#1 Release: v1.0.0-pre-alpha.0

已合併
fab 1 周之前 將 8 次代碼提交從 nibgat/develop合併至 nibgat/main
共有 65 個文件被更改,包括 1040 次插入1713 次删除
  1. 2 2
      .github/ISSUE_TEMPLATE/config.yml
  2. 1 0
      .npmignore
  3. 1 1
      .yarnrc.yml
  4. 10 10
      example/mobile/app.json
  5. 3 3
      example/mobile/babel.config.js
  6. 1 1
      example/mobile/index.ts
  7. 12 9
      example/mobile/metro.config.js
  8. 4 32
      example/mobile/package.json
  9. 0 42
      example/mobile/src/index.tsx
  10. 0 61
      example/mobile/src/pages/testSubPage/index.tsx
  11. 5 1
      example/mobile/tsconfig.json
  12. 0 0
      example/src/assets/fonts/Geist-Black.ttf
  13. 0 0
      example/src/assets/fonts/Geist-Bold.ttf
  14. 0 0
      example/src/assets/fonts/Geist-ExtraBold.ttf
  15. 0 0
      example/src/assets/fonts/Geist-ExtraLight.ttf
  16. 0 0
      example/src/assets/fonts/Geist-Light.ttf
  17. 0 0
      example/src/assets/fonts/Geist-Medium.ttf
  18. 0 0
      example/src/assets/fonts/Geist-Regular.ttf
  19. 0 0
      example/src/assets/fonts/Geist-SemiBold.ttf
  20. 0 0
      example/src/assets/fonts/Geist-Thin.ttf
  21. 1 0
      example/src/global.d.ts
  22. 46 0
      example/src/index.tsx
  23. 0 0
      example/src/navigation/index.tsx
  24. 0 0
      example/src/navigation/type.ts
  25. 2 2
      example/src/pages/home/index.tsx
  26. 0 0
      example/src/pages/home/stylesheet.ts
  27. 1 1
      example/src/pages/testSubPage/index.tsx
  28. 0 0
      example/src/pages/testSubPage/stylesheet.ts
  29. 34 0
      example/src/tsconfig.json
  30. 0 2
      example/web/.bundle/config
  31. 0 32
      example/web/App.tsx
  32. 0 13
      example/web/__tests__/App.test.tsx
  33. 2 2
      example/web/app.json
  34. 11 8
      example/web/babel.config.js
  35. 0 9
      example/web/index.js
  36. 14 0
      example/web/index.ts
  37. 50 50
      example/web/ios/nibgatofficialwebsite/Images.xcassets/AppIcon.appiconset/Contents.json
  38. 4 4
      example/web/ios/nibgatofficialwebsite/Images.xcassets/Contents.json
  39. 4 4
      example/web/jest.config.js
  40. 31 2
      example/web/metro.config.js
  41. 2 52
      example/web/package.json
  42. 0 46
      example/web/src/navigation/index.tsx
  43. 0 7
      example/web/src/navigation/type.ts
  44. 0 618
      example/web/src/pages/home/index.tsx
  45. 0 14
      example/web/src/pages/home/stylesheet.ts
  46. 0 10
      example/web/src/pages/testSubPage/stylesheet.ts
  47. 15 6
      example/web/tsconfig.json
  48. 32 15
      example/web/webpack.config.js
  49. 63 22
      package.json
  50. 328 12
      src/components/bottomSheet/index.tsx
  51. 9 0
      src/components/checkBox/index.tsx
  52. 10 0
      src/components/modal/index.tsx
  53. 7 3
      src/components/monthSelector/index.tsx
  54. 9 0
      src/components/numericInput/index.tsx
  55. 9 0
      src/components/radioButton/index.tsx
  56. 63 3
      src/components/snackBar/index.tsx
  57. 9 0
      src/components/switch/index.tsx
  58. 9 0
      src/components/textAreaInput/index.tsx
  59. 9 0
      src/components/textInput/index.tsx
  60. 7 3
      src/components/yearSelector/index.tsx
  61. 75 1
      src/core/index.tsx
  62. 18 0
      src/types/index.ts
  63. 19 4
      tsconfig.json
  64. 33 4
      turbo.json
  65. 75 602
      yarn.lock

+ 2 - 2
.github/ISSUE_TEMPLATE/config.yml

@@ -1,8 +1,8 @@
 blank_issues_enabled: false
 contact_links:
   - name: Feature Request 💡
-    url: https://git.nibgat.space/nibgat-community/ncore-ui-kit-mobile.git/discussions/new?category=ideas
+    url: https://git.nibgat.space/nibgat-community/ncore-ui-kit.git/discussions/new?category=ideas
     about: If you have a feature request, please create a new discussion on GitHub.
   - name: Discussions on GitHub 💬
-    url: https://git.nibgat.space/nibgat-community/ncore-ui-kit-mobile.git/discussions
+    url: https://git.nibgat.space/nibgat-community/ncore-ui-kit.git/discussions
     about: If this library works as promised but you need help, please ask questions there.

+ 1 - 0
.npmignore

@@ -12,3 +12,4 @@ example
 LICENSE
 CODE_OF_CONDUCT.md
 CONTRIBUTING.md
+src

+ 1 - 1
.yarnrc.yml

@@ -1,4 +1,4 @@
 nodeLinker: node-modules
-nmHoistingLimits: workspaces
+nmHoistingLimits: none
 
 yarnPath: .yarn/releases/yarn-4.11.0.cjs

+ 10 - 10
example/mobile/app.json

@@ -1,7 +1,7 @@
 {
     "expo": {
         "name": "NCore | Ui Kit - Mobile Example",
-        "slug": "ncore-ui-kit-mobile-example-mobile",
+        "slug": "ncore-ui-kit-example-mobile",
         "version": "1.0.0",
         "orientation": "portrait",
         "icon": "./assets/icon.png",
@@ -31,15 +31,15 @@
                 "expo-font",
                 {
                     "fonts": [
-                        "./src/assets/fonts/Geist-Black.ttf",
-                        "./src/assets/fonts/Geist-Bold.ttf",
-                        "./src/assets/fonts/Geist-ExtraBold.ttf",
-                        "./src/assets/fonts/Geist-ExtraLight.ttf",
-                        "./src/assets/fonts/Geist-Light.ttf",
-                        "./src/assets/fonts/Geist-Medium.ttf",
-                        "./src/assets/fonts/Geist-Regular.ttf",
-                        "./src/assets/fonts/Geist-SemiBold.ttf",
-                        "./src/assets/fonts/Geist-Thin.ttf"
+                        "../src/assets/fonts/Geist-Black.ttf",
+                        "../src/assets/fonts/Geist-Bold.ttf",
+                        "../src/assets/fonts/Geist-ExtraBold.ttf",
+                        "../src/assets/fonts/Geist-ExtraLight.ttf",
+                        "../src/assets/fonts/Geist-Light.ttf",
+                        "../src/assets/fonts/Geist-Medium.ttf",
+                        "../src/assets/fonts/Geist-Regular.ttf",
+                        "../src/assets/fonts/Geist-SemiBold.ttf",
+                        "../src/assets/fonts/Geist-Thin.ttf"
                     ]
                 }
             ]

+ 3 - 3
example/mobile/babel.config.js

@@ -19,9 +19,9 @@ module.exports = function (api) {
                         ".json"
                     ],
                     alias: {
-                        "ncore-ui-kit-mobile": "../../src",
-                        "react": "./node_modules/react",
-                        "react-native": "./node_modules/react-native"
+                        "ncore-ui-kit": "../../src",
+                        "react": "../../node_modules/react",
+                        "react-native": "../../node_modules/react-native"
                     }
                 }
             ]

+ 1 - 1
example/mobile/index.js → example/mobile/index.ts

@@ -1,6 +1,6 @@
-import App from "./index";
 import {
     registerRootComponent
 } from "expo";
+import App from "../src/index";
 
 registerRootComponent(App);

+ 12 - 9
example/mobile/metro.config.js

@@ -2,25 +2,28 @@
 /* eslint-disable */
 
 const {
-  getDefaultConfig
+    getDefaultConfig
 } = require("expo/metro-config");
 const path = require("path");
 
-const root = path.resolve(__dirname, "..");
-
-const nodeModulesPaths = [path.resolve(__dirname, "node_modules")];
+const root = path.resolve(__dirname, "../..");
+const source = path.resolve(__dirname, "../src");
 
 const config = getDefaultConfig(__dirname);
 
-config.watchFolders = [root];
+config.watchFolders = [
+    root,
+    source
+];
 
 config.resolver.extraNodeModules = {
-  "ncore-ui-kit-mobile": path.resolve(root, "src"),
-  "react": path.resolve(__dirname, "node_modules/react"),
-  "react-native": path.resolve(__dirname, "node_modules/react-native"),
+    "ncore-ui-kit": path.resolve(root, "src"),
+    "node_modules": path.resolve(root, "node_modules")
 };
 
-config.resolver.nodeModulesPaths = nodeModulesPaths;
+config.resolver.nodeModulesPaths = [
+    path.resolve(root, "node_modules")
+];
 
 config.resolver.disableHierarchicalLookup = true;
 

+ 4 - 32
example/mobile/package.json

@@ -1,7 +1,7 @@
 {
-    "name": "ncore-ui-kit-mobile-example-mobile",
-    "version": "1.0.0",
-    "main": "index.js",
+    "name": "ncore-ui-kit-example-mobile",
+    "version": "1.0.0-pre-alpha.0",
+    "main": "index.ts",
     "type": "commonjs",
     "scripts": {
         "start": "expo start",
@@ -9,33 +9,5 @@
         "ios": "expo start --ios",
         "web": "expo start --web"
     },
-    "dependencies": {
-        "@expo/metro-runtime": "~55.0.6",
-        "@react-navigation/elements": "2.9.14",
-        "@react-navigation/native": "7.2.2",
-        "@react-navigation/native-stack": "7.14.11",
-        "expo": "~55.0.4",
-        "expo-font": "~55.0.4",
-        "expo-status-bar": "~55.0.4",
-        "lucide-react-native": "1.8.0",
-        "moment": "https://git.nibgat.space/nibgat-community/moment.git",
-        "ncore-context": "1.0.5",
-        "react": "19.2.6",
-        "react-dom": "19.2.6",
-        "react-native": "0.83.2",
-        "react-native-safe-area-context": "5.7.0",
-        "react-native-screens": "4.24.0",
-        "react-native-svg": "15.15.3",
-        "react-native-web": "~0.21.0",
-        "rrule": "https://git.nibgat.space/nibgat-community/rrule.git"
-    },
-    "private": true,
-    "devDependencies": {
-        "@expo/webpack-config": "^19.0.1",
-        "@react-native/metro-config": "0.84.1",
-        "@types/react-native": "0.73.0",
-        "babel-preset-expo": "56.0.15",
-        "react-native-builder-bob": "0.40.13",
-        "react-native-monorepo-config": "0.3.3"
-    }
+    "private": true
 }

+ 0 - 42
example/mobile/src/index.tsx

@@ -1,42 +0,0 @@
-import Navigation from "./navigation";
-import {
-    useFonts
-} from "expo-font";
-import moment from "moment";
-import {
-    setupNCoreUIKit
-} from "ncore-ui-kit-mobile";
-import "moment/locale/tr";
-
-const NCoreUIKitBase = setupNCoreUIKit({
-    initialSelectedGapPropagation: "spacious",
-    initialSelectedTheme: "light"
-});
-
-moment.locale("tr");
-
-const App = () => {
-    return <Navigation/>;
-};
-
-const ContextAPI = () => {
-    /* eslint-disable @typescript-eslint/no-require-imports */
-    const [loaded] = useFonts({
-        "Geist-ExtraLight": require("./assets/fonts/Geist-ExtraLight.ttf"),
-        "Geist-ExtraBold": require("./assets/fonts/Geist-ExtraBold.ttf"),
-        "Geist-SemiBold": require("./assets/fonts/Geist-SemiBold.ttf"),
-        "Geist-Regular": require("./assets/fonts/Geist-Regular.ttf"),
-        "Geist-Medium": require("./assets/fonts/Geist-Medium.ttf"),
-        "Geist-Black": require("./assets/fonts/Geist-Black.ttf"),
-        "Geist-Light": require("./assets/fonts/Geist-Light.ttf"),
-        "Geist-Bold": require("./assets/fonts/Geist-Bold.ttf"),
-        "Geist-Thin": require("./assets/fonts/Geist-Thin.ttf")
-    });
-
-    if (!loaded) return null;
-
-    return <NCoreUIKitBase.Provider>
-        <App/>
-    </NCoreUIKitBase.Provider>;
-};
-export default ContextAPI;

+ 0 - 61
example/mobile/src/pages/testSubPage/index.tsx

@@ -1,61 +0,0 @@
-import {
-    useRef
-} from "react";
-import {
-    View
-} from "react-native";
-import stylesheet from "./stylesheet";
-import {
-    type IBottomSheetRef,
-    PageContainer,
-    BottomSheet,
-    Button,
-    Text
-} from "ncore-ui-kit-mobile";
-
-const TestSubPage = () => {
-    const bottomSheetRef = useRef<IBottomSheetRef>(null);
-
-    return <PageContainer
-        style={[
-            stylesheet.container
-        ]}
-    >
-        <Text>This is test sub page.</Text>
-        <Button
-            onPress={() => {
-                bottomSheetRef.current?.open();
-            }}
-            type="success"
-            title="Ahmet"
-            variant="filled"
-        />
-        <BottomSheet
-            isCanFullScreenOnSwipe={true}
-            isWorkWithPortal={false}
-            ref={bottomSheetRef}
-            snapPoint={300}
-        >
-            <Button
-                onPress={() => {
-
-                }}
-                title="Git."
-            />
-            <View
-                style={{
-                    backgroundColor: "red",
-                    height: 2400
-                }}
-            />
-            <Text>Deneme 123</Text>
-            <Text>Deneme 123</Text>
-            <Text>Deneme 123</Text>
-            <Text>Deneme 123</Text>
-            <Text>Deneme 123</Text>
-            <Text>Deneme 123</Text>
-            <Text>Deneme 123</Text>
-        </BottomSheet>
-    </PageContainer>;
-};
-export default TestSubPage;

+ 5 - 1
example/mobile/tsconfig.json

@@ -1,5 +1,9 @@
 {
     "extends": "../../tsconfig.json",
     "compilerOptions": {
-    }
+    },
+    "include": [
+        "**/*",
+        "../src/**/*"
+    ]
 }

+ 0 - 0
example/mobile/src/assets/fonts/Geist-Black.ttf → example/src/assets/fonts/Geist-Black.ttf


+ 0 - 0
example/mobile/src/assets/fonts/Geist-Bold.ttf → example/src/assets/fonts/Geist-Bold.ttf


+ 0 - 0
example/mobile/src/assets/fonts/Geist-ExtraBold.ttf → example/src/assets/fonts/Geist-ExtraBold.ttf


+ 0 - 0
example/mobile/src/assets/fonts/Geist-ExtraLight.ttf → example/src/assets/fonts/Geist-ExtraLight.ttf


+ 0 - 0
example/mobile/src/assets/fonts/Geist-Light.ttf → example/src/assets/fonts/Geist-Light.ttf


+ 0 - 0
example/mobile/src/assets/fonts/Geist-Medium.ttf → example/src/assets/fonts/Geist-Medium.ttf


+ 0 - 0
example/mobile/src/assets/fonts/Geist-Regular.ttf → example/src/assets/fonts/Geist-Regular.ttf


+ 0 - 0
example/mobile/src/assets/fonts/Geist-SemiBold.ttf → example/src/assets/fonts/Geist-SemiBold.ttf


+ 0 - 0
example/mobile/src/assets/fonts/Geist-Thin.ttf → example/src/assets/fonts/Geist-Thin.ttf


+ 1 - 0
example/src/global.d.ts

@@ -0,0 +1 @@
+import "../../src/types/index";

+ 46 - 0
example/src/index.tsx

@@ -0,0 +1,46 @@
+import Navigation from "./navigation";
+import {
+    useFonts
+} from "expo-font";
+import moment from "moment";
+import {
+    setupNCoreUIKit
+} from "ncore-ui-kit";
+import "moment/locale/tr";
+
+const NCoreUIKitBase = setupNCoreUIKit({
+    initialSelectedGapPropagation: "spacious",
+    initialSelectedTheme: "light"
+});
+
+moment.locale("tr");
+
+const App = () => {
+    return <Navigation/>;
+};
+
+const isExpo = typeof globalThis !== "undefined" && ("__expo" in globalThis || "Expo" in globalThis);
+
+const ContextAPI = () => {
+    if(isExpo) {
+        /* eslint-disable @typescript-eslint/no-require-imports */
+        const [loaded] = useFonts({
+            "Geist-ExtraLight": require("./assets/fonts/Geist-ExtraLight.ttf"),
+            "Geist-ExtraBold": require("./assets/fonts/Geist-ExtraBold.ttf"),
+            "Geist-SemiBold": require("./assets/fonts/Geist-SemiBold.ttf"),
+            "Geist-Regular": require("./assets/fonts/Geist-Regular.ttf"),
+            "Geist-Medium": require("./assets/fonts/Geist-Medium.ttf"),
+            "Geist-Black": require("./assets/fonts/Geist-Black.ttf"),
+            "Geist-Light": require("./assets/fonts/Geist-Light.ttf"),
+            "Geist-Bold": require("./assets/fonts/Geist-Bold.ttf"),
+            "Geist-Thin": require("./assets/fonts/Geist-Thin.ttf")
+        });
+
+        if (!loaded) return null;
+    }
+
+    return <NCoreUIKitBase.Provider>
+        <App/>
+    </NCoreUIKitBase.Provider>;
+};
+export default ContextAPI;

+ 0 - 0
example/mobile/src/navigation/index.tsx → example/src/navigation/index.tsx


+ 0 - 0
example/mobile/src/navigation/type.ts → example/src/navigation/type.ts


+ 2 - 2
example/mobile/src/pages/home/index.tsx → example/src/pages/home/index.tsx

@@ -27,13 +27,13 @@ import {
     StateCard,
     CheckBox,
     RowCard,
+    Sticker,
     Button,
     Dialog,
     Switch,
     Text,
-    Sticker,
     Chip
-} from "ncore-ui-kit-mobile";
+} from "ncore-ui-kit";
 import {
     useNavigation
 } from "@react-navigation/native";

+ 0 - 0
example/mobile/src/pages/home/stylesheet.ts → example/src/pages/home/stylesheet.ts


+ 1 - 1
example/web/src/pages/testSubPage/index.tsx → example/src/pages/testSubPage/index.tsx

@@ -11,7 +11,7 @@ import {
     BottomSheet,
     Button,
     Text
-} from "ncore-ui-kit-mobile";
+} from "ncore-ui-kit";
 
 const TestSubPage = () => {
     const bottomSheetRef = useRef<IBottomSheetRef>(null);

+ 0 - 0
example/mobile/src/pages/testSubPage/stylesheet.ts → example/src/pages/testSubPage/stylesheet.ts


+ 34 - 0
example/src/tsconfig.json

@@ -0,0 +1,34 @@
+{
+    "extends": [
+        "../../tsconfig.json",
+        "../mobile/tsconfig.json",
+        "../web/tsconfig.json",
+    ],
+    "compilerOptions": {
+        "allowSyntheticDefaultImports": true,
+        "moduleResolution": "bundler",
+        "ignoreDeprecations": "6.0",
+        "preserveSymlinks": true,
+        "esModuleInterop": true,
+        "jsx": "react-native",
+        "target": "esnext",
+        "baseUrl": "."
+    },
+    "references": [
+        {
+            "path": "../../"
+        },
+        {
+            "path": "../mobile"
+        },
+        {
+            "path": "../web"
+        }
+    ],
+    "include": [
+        "**/*.ts",
+        "**/*.tsx",
+        "../../src/**/*",
+        "../../src/types/index.ts"
+    ]
+}

+ 0 - 2
example/web/.bundle/config

@@ -1,2 +0,0 @@
-BUNDLE_PATH: "vendor/bundle"
-BUNDLE_FORCE_RUBY_PLATFORM: 1

+ 0 - 32
example/web/App.tsx

@@ -1,32 +0,0 @@
-import React from 'react';
-import { StyleSheet, View, Pressable } from 'react-native';
-import {
-  setupNCoreUIKit,
-  Button,
-  Text
-} from "ncore-ui-kit-mobile";
-import { EyeClosed } from 'lucide-react-native';
-import Navigation from './src/navigation';
-
-const NCoreUIKitBase = setupNCoreUIKit({
-    initialSelectedGapPropagation: "spacious",
-    initialSelectedTheme: "light"
-});
-
-function App() {
-  return <AppContent />;
-}
-
-function AppContent() {
-  return <NCoreUIKitBase.Provider>
-    <Navigation/>
-  </NCoreUIKitBase.Provider>;
-}
-
-const styles = StyleSheet.create({
-  container: {
-    flex: 1,
-  },
-});
-
-export default App;

+ 0 - 13
example/web/__tests__/App.test.tsx

@@ -1,13 +0,0 @@
-/**
- * @format
- */
-
-import React from 'react';
-import ReactTestRenderer from 'react-test-renderer';
-import App from '../App';
-
-test('renders correctly', async () => {
-  await ReactTestRenderer.act(() => {
-    ReactTestRenderer.create(<App />);
-  });
-});

+ 2 - 2
example/web/app.json

@@ -1,4 +1,4 @@
 {
-  "name": "ncoreuikitwebexample",
-  "displayName": "NİBGAT® | Official Website"
+    "name": "ncoreuikitwebexample",
+    "displayName": "NİBGAT® | Official Website"
 }

+ 11 - 8
example/web/babel.config.js

@@ -1,10 +1,13 @@
 module.exports = {
-  presets: ['module:@react-native/babel-preset'],
-  "plugins": [
-    ["module-resolver", {
-      "alias": {
-        "^react-native$": "react-native-web"
-      }
-    }]
-  ]
+    presets: ["module:@react-native/babel-preset"],
+    "plugins": [
+        [
+            "module-resolver",
+            {
+                "alias": {
+                    "^react-native$": "react-native-web"
+                }
+            }
+        ]
+    ]
 };

+ 0 - 9
example/web/index.js

@@ -1,9 +0,0 @@
-import { AppRegistry } from 'react-native';
-import App from './App';
-import { name as appName } from './app.json';
-
-AppRegistry.registerComponent(appName, () => App);
-AppRegistry.runApplication(appName, {
-  initialProps: {},
-  rootTag: document.getElementById('app-root')
-});

+ 14 - 0
example/web/index.ts

@@ -0,0 +1,14 @@
+import {
+    type RootTag,
+    AppRegistry
+} from "react-native";
+import {
+    name as appName
+} from "./app.json";
+import App from "../src/index";
+
+AppRegistry.registerComponent(appName, () => App);
+AppRegistry.runApplication(appName, {
+    initialProps: {},
+    rootTag: document.getElementById("app-root") as unknown as RootTag
+});

+ 50 - 50
example/web/ios/nibgatofficialwebsite/Images.xcassets/AppIcon.appiconset/Contents.json

@@ -1,53 +1,53 @@
 {
-  "images" : [
-    {
-      "idiom" : "iphone",
-      "scale" : "2x",
-      "size" : "20x20"
-    },
-    {
-      "idiom" : "iphone",
-      "scale" : "3x",
-      "size" : "20x20"
-    },
-    {
-      "idiom" : "iphone",
-      "scale" : "2x",
-      "size" : "29x29"
-    },
-    {
-      "idiom" : "iphone",
-      "scale" : "3x",
-      "size" : "29x29"
-    },
-    {
-      "idiom" : "iphone",
-      "scale" : "2x",
-      "size" : "40x40"
-    },
-    {
-      "idiom" : "iphone",
-      "scale" : "3x",
-      "size" : "40x40"
-    },
-    {
-      "idiom" : "iphone",
-      "scale" : "2x",
-      "size" : "60x60"
-    },
-    {
-      "idiom" : "iphone",
-      "scale" : "3x",
-      "size" : "60x60"
-    },
-    {
-      "idiom" : "ios-marketing",
-      "scale" : "1x",
-      "size" : "1024x1024"
+    "images" : [
+        {
+            "idiom" : "iphone",
+            "scale" : "2x",
+            "size" : "20x20"
+        },
+        {
+            "idiom" : "iphone",
+            "scale" : "3x",
+            "size" : "20x20"
+        },
+        {
+            "idiom" : "iphone",
+            "scale" : "2x",
+            "size" : "29x29"
+        },
+        {
+            "idiom" : "iphone",
+            "scale" : "3x",
+            "size" : "29x29"
+        },
+        {
+            "idiom" : "iphone",
+            "scale" : "2x",
+            "size" : "40x40"
+        },
+        {
+            "idiom" : "iphone",
+            "scale" : "3x",
+            "size" : "40x40"
+        },
+        {
+            "idiom" : "iphone",
+            "scale" : "2x",
+            "size" : "60x60"
+        },
+        {
+            "idiom" : "iphone",
+            "scale" : "3x",
+            "size" : "60x60"
+        },
+        {
+            "idiom" : "ios-marketing",
+            "scale" : "1x",
+            "size" : "1024x1024"
+        }
+    ],
+    "info" : {
+        "author" : "xcode",
+        "version" : 1
     }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  }
 }

+ 4 - 4
example/web/ios/nibgatofficialwebsite/Images.xcassets/Contents.json

@@ -1,6 +1,6 @@
 {
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
+    "info" : {
+        "version" : 1,
+        "author" : "xcode"
+    }
 }

+ 4 - 4
example/web/jest.config.js

@@ -1,6 +1,6 @@
 module.exports = {
-  preset: '@react-native/jest-preset',
-  "moduleNameMapper": {
-    "^react-native$": "react-native-web"
-  }
+    preset: "@react-native/jest-preset",
+    "moduleNameMapper": {
+        "^react-native$": "react-native-web"
+    }
 };

+ 31 - 2
example/web/metro.config.js

@@ -1,4 +1,17 @@
-const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
+/* eslint-disable */
+
+const {
+    getDefaultConfig,
+    mergeConfig
+} = require("@react-native/metro-config");
+const path = require("path");
+
+const root = path.resolve(__dirname, "../..");
+const source = path.resolve(__dirname, "../src");
+
+const nodeModulesPaths = [
+    path.resolve(root, "node_modules")
+];
 
 /**
  * Metro configuration
@@ -6,6 +19,22 @@ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
  *
  * @type {import('@react-native/metro-config').MetroConfig}
  */
-const config = {};
+const config = {
+};
+
+config.watchFolders = [
+    root,
+    source
+];
+
+config.resolver.extraNodeModules = {
+    "ncore-ui-kit": path.resolve(root, "src"),
+    "react": path.resolve(root, "node_modules/react"),
+    "react-native": path.resolve(root, "node_modules/react-native")
+};
+
+config.resolver.nodeModulesPaths = nodeModulesPaths;
+
+config.resolver.disableHierarchicalLookup = true;
 
 module.exports = mergeConfig(getDefaultConfig(__dirname), config);

+ 2 - 52
example/web/package.json

@@ -1,8 +1,8 @@
 {
-    "name": "ncore-ui-kit-mobile-example-web",
+    "name": "ncore-ui-kit-example-web",
     "version": "1.0.0-pre-alpha.0",
+    "main": "index.ts",
     "type": "commonjs",
-    "main": "index.js",
     "private": true,
     "scripts": {
         "android": "react-native run-android",
@@ -12,56 +12,6 @@
         "web": "webpack serve --config ./webpack.config.js",
         "test": "jest"
     },
-    "dependencies": {
-        "@react-native/new-app-screen": "0.85.3",
-        "@react-navigation/elements": "2.9.18",
-        "@react-navigation/native": "7.2.4",
-        "@react-navigation/native-stack": "7.15.1",
-        "lucide-react-native": "1.16.0",
-        "moment": "https://git.nibgat.space/nibgat-community/moment.git",
-        "ncore-context": "1.0.5",
-        "react": "19.2.3",
-        "react-dom": "19.2.3",
-        "react-native": "0.85.3",
-        "react-native-safe-area-context": "5.5.2",
-        "react-native-svg": "15.15.5",
-        "react-native-web": "0.21.2",
-        "rrule": "https://git.nibgat.space/nibgat-community/rrule.git"
-    },
-    "devDependencies": {
-        "@babel/core": "7.25.2",
-        "@babel/plugin-proposal-class-properties": "7.18.6",
-        "@babel/plugin-transform-modules-commonjs": "7.28.6",
-        "@babel/plugin-transform-private-methods": "7.28.6",
-        "@babel/plugin-transform-private-property-in-object": "7.28.6",
-        "@babel/preset-env": "7.25.3",
-        "@babel/preset-typescript": "7.28.5",
-        "@babel/runtime": "7.25.0",
-        "@react-native-community/cli": "20.1.0",
-        "@react-native-community/cli-platform-android": "20.1.0",
-        "@react-native-community/cli-platform-ios": "20.1.0",
-        "@react-native/babel-preset": "0.85.3",
-        "@react-native/eslint-config": "0.85.3",
-        "@react-native/jest-preset": "0.85.3",
-        "@react-native/metro-config": "0.85.3",
-        "@react-native/typescript-config": "0.85.3",
-        "@types/jest": "29.5.13",
-        "@types/react": "19.2.0",
-        "@types/react-test-renderer": "19.1.0",
-        "babel-loader": "10.1.1",
-        "babel-plugin-module-resolver": "5.0.3",
-        "babel-plugin-react-native-web": "0.21.2",
-        "eslint": "8.19.0",
-        "html-webpack-plugin": "5.6.7",
-        "jest": "29.6.3",
-        "prettier": "2.8.8",
-        "react-test-renderer": "19.2.3",
-        "typescript": "5.8.3",
-        "url-loader": "4.1.1",
-        "webpack": "5.107.1",
-        "webpack-cli": "7.0.2",
-        "webpack-dev-server": "5.2.4"
-    },
     "engines": {
         "node": ">= 22.11.0"
     }

+ 0 - 46
example/web/src/navigation/index.tsx

@@ -1,46 +0,0 @@
-import {
-    NavigationContainer
-} from "@react-navigation/native";
-import {
-    createNativeStackNavigator
-} from "@react-navigation/native-stack";
-import Home from "../pages/home";
-import TestSubPage from "../pages/testSubPage";
-
-const RootStack = createNativeStackNavigator();
-
-const RootNav = () => {
-    return <RootStack.Navigator
-        initialRouteName="Home"
-    >
-        <RootStack.Screen
-            name="Home"
-            component={Home}
-        />
-        <RootStack.Screen
-            name="TestSubPage"
-            component={TestSubPage}
-        />
-    </RootStack.Navigator>;
-};
-
-const Navigation = () => {
-    return <NavigationContainer
-        linking={{
-            prefixes: [
-                'http://localhost:3000',
-                'https://nibgat.com.tr',
-                'https://nibgat.com'
-            ],
-            config: {
-                screens: {
-                    Home: '',
-                    TestSubPage: "test"
-                }
-            }
-        }}
-    >
-        <RootNav/>
-    </NavigationContainer>;
-};
-export default Navigation;

+ 0 - 7
example/web/src/navigation/type.ts

@@ -1,7 +0,0 @@
-type RootStackParamList = {
-    TestSubPage: undefined;
-    Home: undefined;
-};
-export type {
-    RootStackParamList as default
-};

+ 0 - 618
example/web/src/pages/home/index.tsx

@@ -1,618 +0,0 @@
-import {
-    Fragment,
-    useState,
-    useRef
-} from "react";
-import {
-    View
-} from "react-native";
-import stylesheet from "./stylesheet";
-import {
-    NCoreUIKitBottomSheet,
-    NotificationIndicator,
-    getNCoreUIKitVersion,
-    type IBottomSheetRef,
-    NCoreUIKitSnackBar,
-    NCoreUIKitDialog,
-    NCoreUIKitToast,
-    NCoreUIKitTheme,
-    DateTimePicker,
-    MarkdownViewer,
-    PageContainer,
-    TextAreaInput,
-    BottomSheet,
-    RadioButton,
-    TextInput,
-    SelectBox,
-    CheckBox,
-    RowCard,
-    Button,
-    Dialog,
-    Switch,
-    Text
-} from "ncore-ui-kit-mobile";
-import {
-    useNavigation
-} from "@react-navigation/native";
-import type {
-    NativeStackNavigationProp
-} from "@react-navigation/native-stack";
-import type RootStackParamList from "../../navigation/type";
-import {
-    ChevronRight as ChevronRightIcon,
-    HomeIcon
-} from "lucide-react-native";
-import moment from "moment";
-
-const X = [
-    {
-        t: "xdfç.öhfdşkhdfşlhkfdşlhkdfşklhjmdfkhl3",
-        p: "ydfguıy8ı*pğ34erdx",
-        n: 90
-    },
-    {
-        t: "3t4uh5ıe6ıo6eıo6eoke6ıoke6ker6kr4ok",
-        p: "y3w46pjbd57ykdr",
-        n: 91
-    },
-    {
-        t: "xr*-0k4wkh-5w40k0*wek95ujk9*",
-        p: "y467o5*3evghe5",
-        n: 92
-    },
-    {
-        t: "x-40*tyg*0w4kyh*w0ko45u*ko0w",
-        p: "y3şçwl78570*fg",
-        n: 93
-    },
-    {
-        t: "*wrüsjh*ü9kws4*h0okdfhdhdfurdkex",
-        p: "yt7ıtot7ot",
-        n: 94
-    },
-    {
-        t: "x2-0*4woy-*w4opyu-*23wou*0wık*0jk",
-        p: "yasfa33",
-        n: 95
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    },
-    {
-        t: "x vmönöpwoı6-pğfş -*235*çda",
-        p: "ydfasdfasf",
-        n: 96
-    }
-];
-
-const Home = () => {
-    const {
-        colors
-    } = NCoreUIKitTheme.useContext();
-
-    const bottomSheetRef = useRef<IBottomSheetRef>(null);
-
-    const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
-
-    const [
-        isCheckboxActive,
-        setIsCheckboxActive
-    ] = useState<"partially" | "checked" | null>("checked");
-
-    const [
-        isDialogActive,
-        setIsDialogActive
-    ] = useState(false);
-
-    const [
-        isRadioActive,
-        setIsRadioActive
-    ] = useState(false);
-
-    const [
-        isSwitchActive,
-        setIsSwitchActive
-    ] = useState(false);
-
-    return <PageContainer
-        scrollViewStyle={stylesheet.container}
-        isScrollable={true}
-        scrollViewProps={{
-            showsHorizontalScrollIndicator: false,
-            showsVerticalScrollIndicator: false,
-            contentContainerStyle: {
-                backgroundColor: colors.content.container.default,
-                ...stylesheet.contentContainer
-            }
-        }}
-        renderOverlays={() => {
-            return <Fragment>
-                <Dialog
-                    isVisible={isDialogActive}
-                    content="etgweı09gı9w0eg"
-                    title="Merhaba Dünya!"
-                    contentJustify="centered"
-                    modalProps={{
-                        isWorkWithPortal: false
-                    }}
-                    onOverlayPress={({
-                        closeAnimation
-                    }) => {
-                        closeAnimation(() => setIsDialogActive(false));
-                    }}
-                    variant="yes-no"
-                    secondaryButtonProps={{
-                        title: "sdfgsdg",
-                        onPress: () => {
-
-                        }
-                    }}
-                    primaryButtonProps={{
-                        onPress: ({
-                            closeAnimation
-                        }) => {
-                            closeAnimation(() => setIsDialogActive(false));
-                        }
-                    }}
-                />
-                <BottomSheet
-                    ref={bottomSheetRef}
-                    renderHeader={() => {
-                        return <View
-                            style={[
-                                {
-                                    backgroundColor: "blue",
-                                    padding: 20
-                                }
-                            ]}
-                        >
-                            <Text>Burası header.</Text>
-                        </View>;
-                    }}
-                    isCanFullScreenOnSwipe={true}
-                    isWorkWithPortal={false}
-                    snapPoint={300}
-                    key="ahmet"
-                >
-                    <Button
-                        title="Open Toast"
-                        variant="filled"
-                        type="warning"
-                        onPress={() => {
-                            NCoreUIKitToast.open({
-                                title: "sdgfsdgsdg",
-                                type: "danger"
-                            });
-                        }}
-                    />
-                    <Button
-                        onPress={() => {
-                            navigation.navigate("TestSubPage");
-                        }}
-                        title="Git."
-                    />
-                    {[
-                        0,
-                        1,
-                        2,
-                        3,
-                        4,
-                        5,
-                        6,
-                        7,
-                        8,
-                        9,
-                        10,
-                        11,
-                        12,
-                        13,
-                        14,
-                        15,
-                        16,
-                        17,
-                        18,
-                        19,
-                        20,
-                        21,
-                        22,
-                        23,
-                        24,
-                        25,
-                        26,
-                        27,
-                        28,
-                        29,
-                        30,
-                        31,
-                        32,
-                        33,
-                        34,
-                        35
-                    ].map((it) => {
-                        return <View
-                            key={`fds-${it}`}
-                            style={{
-                                backgroundColor: `rgb(${it * 10}, ${it > 30 ? it * 5 : "0"}, ${it > 20 ? it * 4 : "0"})`,
-                                height: 150
-                            }}
-                        />;
-                    })}
-                    <Text>Deneme 123</Text>
-                    <Text>Deneme 123</Text>
-                    <Text>Deneme 123</Text>
-                    <Text>Deneme 123</Text>
-                    <Text>Deneme 123</Text>
-                    <Text>Deneme 123</Text>
-                    <Text>Deneme 123</Text>
-                    <Text>Deneme 123</Text>
-                </BottomSheet>
-            </Fragment>;
-        }}
-    >
-        <DateTimePicker
-            minDate={moment().subtract(2, "months").toDate()}
-            maxDate={moment().add(1, "months").toDate()}
-            isWorkWithRealtime={false}
-            spreadBehaviour="free"
-            isCleanEnabled={true}
-            variant="range"
-            initialDateRange={{
-                start: moment().subtract(2, "days").startOf("day").toDate(),
-                end: moment().add(6, "days").endOf("day").toDate()
-            }}
-            initialDate={new Date()}
-        />
-        <MarkdownViewer
-            content={`
-# Merhaba Furkan!.
-
-Nabersin ?
-
-<center>
-<link href="https://www.nibgat.com">
-## Deneme **title** 2
-</link>
-
-\`\`\`
-safasfasfasf
-\`\`\`
-</center>
-iyisindir **umarım.**
-
-\`\`\`
-Ahmet buraya gel.
-
-
-Geldin mi ?
-\`\`\`
-
-<<
-Burası alıntı metnidir.
->>
-
-* Merhaba __madd__e1.
-- Deneme madde2.
-
-[Alt text için deneme](https://static.vecteezy.com/system/resources/thumbnails/060/843/811/small/close-up-of-raindrops-on-leaves-hd-background-luxury-hd-wallpaper-image-trendy-background-illustration-free-photo.jpg)<100%x200>--cover--`}
-        />
-        <NotificationIndicator
-            type="danger"
-            title={53}
-        >
-            <Button
-                size="small"
-                icon={({
-                    color
-                }) => <HomeIcon
-                    color={colors.content.icon[color]}
-                />}
-                onPress={() => {
-
-                }}
-            />
-        </NotificationIndicator>
-        <Switch
-            spreadBehaviour="stretch"
-            isActive={isSwitchActive}
-            title="dsgojksdgpojk"
-            subTitle="SJFAJdfa"
-            isDisabled={false}
-            onPress={() => {
-                setIsSwitchActive(!isSwitchActive);
-            }}
-        />
-        <RowCard
-            title="Merhaba"
-            icon={({
-                color
-            }) => <HomeIcon
-                color={colors.content.icon[color]}
-            />}
-            rightIcon={({
-                color
-            }) => <ChevronRightIcon
-                color={colors.content.icon[color]}
-            />}
-        />
-        <RadioButton
-            isChecked={isRadioActive}
-            title="sadfasfsafasf"
-            isDisabled={false}
-            subTitle="asfgsaf"
-            onPress={() => {
-                setIsRadioActive(!isRadioActive);
-            }}
-        />
-        <CheckBox
-            isChecked={isCheckboxActive}
-            title="sadfasfsafasf"
-            isDisabled={false}
-            subTitle="asfgsaf"
-            onPress={() => {
-                setIsCheckboxActive(isCheckboxActive === "checked" ? null : isCheckboxActive === null ? "partially" : "checked");
-            }}
-        />
-        <TextAreaInput
-            isUpdateOnRealtime={true}
-            spreadBehaviour="stretch"
-            placeholder="efsdg"
-            maxLength={300}
-            title="Merhaba"
-            type="success"
-            isCleanEnabled={true}
-            icon={({
-                color
-            }) => <HomeIcon
-                color={colors.content.icon[color]}
-            />}
-        />
-        <SelectBox
-            keyExtractor={(data, index) => `${data.t}-${index}`}
-            titleExtractor={(data) => data.t}
-            initialSelectedItems={[{
-                __title: X[0]?.t as string,
-                __key: `${X[0]?.t}-0`
-            }]}
-            subTitle="Deneme Subtitle"
-            // isWorkWithRealtime={false}
-            isWorkWithRealtime={false}
-            spreadBehaviour="baseline"
-            isMultipleSelect={true}
-            isShowSubTitle={true}
-            hintText="Test deneme"
-            isCleanEnabled={true}
-            maxChoice={-1}
-            minChoice={0}
-            isSearchable={true}
-            title="Deneme Box"
-            isRequired={true}
-            data={X}
-            onMoreLoad={(props) => {
-                console.log("More Loaded:", props);
-            }}
-        />
-        <TextInput
-            variant="hidden"
-            placeholder="dsagdsag"
-        />
-        <Text>Version: v{getNCoreUIKitVersion()}</Text>
-        <Button
-            onPress={() => {
-                navigation.navigate("TestSubPage");
-            }}
-            title="Open Test Sub Page"
-            variant="filled"
-            spreadBehaviour="stretch"
-        />
-        <Button
-            onPress={() => {
-                bottomSheetRef.current?.open();
-            }}
-            type="success"
-            title="Open Local BottomSheet"
-            variant="filled"
-        />
-        <Button
-            onPress={() => {
-                NCoreUIKitBottomSheet.open({
-                    children: <View>
-                        <Text>Deneme 123</Text>
-                        <Text>Deneme 123</Text>
-                        <Text>Deneme 123</Text>
-                        <Text>Deneme 123</Text>
-                        <Text>Deneme 123</Text>
-                        <Text>Deneme 123</Text>
-                    </View>
-                });
-            }}
-            type="success"
-            title="Open BottomSheet"
-            variant="filled"
-        />
-        <Button
-            onPress={() => {
-                setIsDialogActive(!isDialogActive);
-            }}
-            type="neutral"
-            title="Open Local Dialog"
-            variant="filled"
-        />
-        <Button
-            title="Open Snackbar"
-            variant="filled"
-            type="danger"
-            onPress={() => {
-                NCoreUIKitSnackBar.open({
-                    title: "sdgdsgs",
-                    icon: ({
-                        color
-                    }) => <HomeIcon color={colors.content.icon[color ? color : "default"]}/>
-                });
-            }}
-        />
-        <Button
-            onPress={() => {
-                NCoreUIKitDialog.open({
-                    content: "etgweı09gı9w0eg",
-                    title: "Merhaba Dünya!",
-                    isVisible: true,
-                    onOverlayPress: ({
-                        closeAnimation
-                    }) => {
-                        closeAnimation();
-                    },
-                    variant: "info",
-                    secondaryButtonProps: {
-                        title: "sdfgsdg",
-                        onPress: () => {
-
-                        }
-                    },
-                    primaryButtonProps: {
-                        onPress: ({
-                            closeAnimation
-                        }) => {
-                            closeAnimation();
-                        }
-                    }
-                });
-            }}
-            type="neutral"
-            title="Open Dialog"
-            variant="filled"
-        />
-        <Button
-            title="Open Toast"
-            variant="filled"
-            type="warning"
-            onPress={() => {
-                NCoreUIKitToast.open({
-                    title: "sdgfsdgsdafs sdlşlgkdfşiklh",
-                    subTitle: "tr9uıdgfss 0dgklsd",
-                    isShowAction: true,
-                    icon: ({
-                        color
-                    }) => <HomeIcon color={colors.content.icon[color ? color : "default"]}/>
-                });
-            }}
-        />
-    </PageContainer>;
-};
-export default Home;

+ 0 - 14
example/web/src/pages/home/stylesheet.ts

@@ -1,14 +0,0 @@
-import {
-    StyleSheet
-} from "react-native";
-
-const stylesheet = StyleSheet.create({
-    container: {
-        flex: 1
-    },
-    contentContainer: {
-        justifyContent: "center",
-        alignItems: "center"
-    }
-});
-export default stylesheet;

+ 0 - 10
example/web/src/pages/testSubPage/stylesheet.ts

@@ -1,10 +0,0 @@
-import {
-    StyleSheet
-} from "react-native";
-
-const stylesheet = StyleSheet.create({
-    container: {
-        flex: 1
-    }
-});
-export default stylesheet;

+ 15 - 6
example/web/tsconfig.json

@@ -1,8 +1,17 @@
 {
-  "extends": "@react-native/typescript-config",
-  "compilerOptions": {
-    "types": ["jest"]
-  },
-  "include": ["**/*.ts", "**/*.tsx"],
-  "exclude": ["**/node_modules", "**/Pods"]
+    "extends": "../../tsconfig.json",
+    "compilerOptions": {
+        "types": [
+            "node"
+        ]
+    },
+    "include": [
+        "**/*.ts",
+        "**/*.tsx",
+        "../src/**/*"
+    ],
+    "exclude": [
+        "**/node_modules",
+        "**/Pods"
+    ]
 }

+ 32 - 15
example/web/webpack.config.js

@@ -1,26 +1,33 @@
+/* eslint-disable */
+
 const path = require("path");
 const webpack = require("webpack");
 const HtmlWebpackPlugin = require("html-webpack-plugin");
 
 const appDirectory = path.resolve(__dirname, "./");
+const srcDirectory = path.resolve(__dirname, "../src");
 const rootDirectory = path.resolve(__dirname, "../../");
 
 const babelLoaderConfiguration = {
     test: /\.(tsx|ts|js|jsx)$/,
     include: [
-        path.resolve(appDirectory, "index.js"),
-        path.resolve(appDirectory, "App.tsx"),
-        path.resolve(appDirectory, "src"),
+        path.resolve(appDirectory, "index.ts"),
+        path.resolve(srcDirectory, "index.tsx"),
+        path.resolve(srcDirectory),
 
         path.resolve(rootDirectory, "src"),
 
-        path.resolve(appDirectory, "node_modules/@react-navigation/native-stack"),
-        path.resolve(appDirectory, "node_modules/@react-native/new-app-screen"),
-        path.resolve(appDirectory, "node_modules/@react-navigation/elements"),
-        path.resolve(appDirectory, "node_modules/@react-navigation/native"),
-        path.resolve(appDirectory, "node_modules/react-native-uncompiled"),
-        path.resolve(appDirectory, "node_modules/lucide-react-native"),
-        path.resolve(appDirectory, "node_modules/react-native")
+        path.resolve(rootDirectory, "node_modules/@react-navigation/native-stack"),
+        path.resolve(rootDirectory, "node_modules/@react-native/new-app-screen"),
+        path.resolve(rootDirectory, "node_modules/@react-navigation/elements"),
+        path.resolve(rootDirectory, "node_modules/@react-navigation/native"),
+        path.resolve(rootDirectory, "node_modules/react-native-uncompiled"),
+        path.resolve(rootDirectory, "node_modules/lucide-react-native"),
+        path.resolve(rootDirectory, "node_modules/react-native"),
+
+        path.resolve(rootDirectory, "node_modules/expo-font"),
+        path.resolve(rootDirectory, "node_modules/expo-modules-core"),
+        path.resolve(rootDirectory, "node_modules/expo-asset")
     ],
     use: {
         loader: "babel-loader",
@@ -50,7 +57,7 @@ const imageLoaderConfiguration = {
 
 module.exports = {
     entry: [
-        path.resolve(appDirectory, "index.js")
+        path.resolve(appDirectory, "index.ts")
     ],
     mode: "development",
     devtool: "source-map",
@@ -77,7 +84,7 @@ module.exports = {
             module: /@react-navigation/
         },
         {
-            module: /ncore-ui-kit-mobile/
+            module: /ncore-ui-kit/
         }
     ],
     module: {
@@ -87,7 +94,7 @@ module.exports = {
             {
                 test: /\.(js|mjs|jsx)$/,
                 include: [
-                    path.resolve(appDirectory, "node_modules/@react-navigation")
+                    path.resolve(rootDirectory, "node_modules/@react-navigation")
                 ],
                 type: "javascript/auto",
                 resolve: {
@@ -98,6 +105,13 @@ module.exports = {
                 test: /\.mjs$/,
                 include: /node_modules/,
                 type: "javascript/auto"
+            },
+            {
+                test: /\.(ttf|otf|eot|woff|woff2)$/,
+                type: "asset/resource",
+                generator: {
+                    filename: "../src/assets/fonts/[name][ext]"
+                }
             }
         ]
     },
@@ -108,12 +122,16 @@ module.exports = {
         }),
         new webpack.DefinePlugin({
             __DEV__: JSON.stringify(process.env.NODE_ENV !== "production"),
+
+            "process.env": JSON.stringify({}),
+            "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "development")
         })
     ],
     resolve: {
+        symlinks: false,
         alias: {
             "react-native$": "react-native-web",
-            "ncore-ui-kit-mobile": path.resolve(rootDirectory, "src/index")
+            "ncore-ui-kit": path.resolve(rootDirectory, "src/index")
         },
         extensions: [
             ".web.tsx",
@@ -125,7 +143,6 @@ module.exports = {
             ".mjs"
         ],
         modules: [
-            path.resolve(appDirectory, "node_modules"),
             path.resolve(rootDirectory, "node_modules"),
             "node_modules"
         ]

+ 63 - 22
package.json

@@ -1,6 +1,6 @@
 {
-    "name": "ncore-ui-kit-mobile",
-    "version": "1.0.0-pre-alpha.23",
+    "name": "ncore-ui-kit",
+    "version": "1.0.0-pre-alpha.0",
     "description": "NİBGAT® | NCore - UI Kit for React-Native Mobile Apps.",
     "main": "./lib/module/index.js",
     "types": "./lib/typescript/src/index.d.ts",
@@ -32,12 +32,12 @@
         "!**/.*"
     ],
     "scripts": {
-        "example-mobile": "yarn workspace ncore-ui-kit-mobile-example-mobile",
-        "example-web": "yarn workspace ncore-ui-kit-mobile-example-web",
+        "example-mobile": "yarn workspace ncore-ui-kit-example-mobile",
+        "example-web": "yarn workspace ncore-ui-kit-example-web",
         "clean": "del-cli lib",
         "lint": "eslint . --ext .ts,.tsx --fix",
         "prepare": "bob build && copyfiles -u 1 \"src/variants/**/*.json\" lib/typescript/src/ && node version.mjs",
-        "typecheck": "tsc",
+        "typecheck": "tsc -p tsconfig.build.json",
         "release": "release-it --only-version",
         "build": "yarn clean && yarn lint && yarn typecheck && yarn prepare && npm publish"
     },
@@ -60,26 +60,51 @@
     ],
     "repository": {
         "type": "git",
-        "url": "git+https://git.nibgat.space/nibgat-community/ncore-ui-kit-mobile.git.git"
+        "url": "git+https://git.nibgat.space/nibgat-community/ncore-ui-kit.git.git"
     },
     "author": "nibgat <development@nibgat.com> (https://git.nibgat.space/nibgat-community)",
     "license": "MIT",
     "bugs": {
-        "url": "https://git.nibgat.space/nibgat-community/ncore-ui-kit-mobile.git/issues"
+        "url": "https://git.nibgat.space/nibgat-community/ncore-ui-kit.git/issues"
     },
-    "homepage": "https://git.nibgat.space/nibgat-community/ncore-ui-kit-mobile.git#readme",
+    "homepage": "https://git.nibgat.space/nibgat-community/ncore-ui-kit.git#readme",
     "publishConfig": {
         "registry": "https://registry.npmjs.org/"
     },
     "devDependencies": {
-        "@react-native/babel-preset": "0.83.0",
-        "@react-native/typescript-config": "^0.86.0",
+        "@babel/core": "7.25.2",
+        "@babel/plugin-proposal-class-properties": "7.18.6",
+        "@babel/plugin-transform-modules-commonjs": "7.28.6",
+        "@babel/plugin-transform-private-methods": "7.28.6",
+        "@babel/plugin-transform-private-property-in-object": "7.28.6",
+        "@babel/preset-env": "7.25.3",
+        "@babel/preset-typescript": "7.28.5",
+        "@babel/runtime": "7.25.0",
+        "@expo/metro-runtime": "56.0.15",
+        "@react-native-community/cli": "20.1.0",
+        "@react-native-community/cli-platform-android": "20.1.0",
+        "@react-native-community/cli-platform-ios": "20.1.0",
+        "@react-native/babel-preset": "0.85.3",
+        "@react-native/eslint-config": "0.85.3",
+        "@react-native/jest-preset": "0.85.3",
+        "@react-native/metro-config": "0.85.3",
+        "@react-native/new-app-screen": "0.85.3",
+        "@react-native/typescript-config": "0.85.3",
+        "@react-navigation/elements": "2.9.18",
+        "@react-navigation/native": "7.2.4",
+        "@react-navigation/native-stack": "7.15.1",
         "@release-it/conventional-changelog": "10.0.1",
         "@types/copyfiles": "2",
         "@types/eslint-plugin-jsx-a11y": "6",
-        "@types/react": "19.2.14",
+        "@types/jest": "29.5.13",
+        "@types/node": "25.9.3",
+        "@types/react": "19.2.0",
         "@types/react-native": "0.73.0",
-        "babel-plugin-module-resolver": "5.0.2",
+        "@types/react-test-renderer": "19.1.0",
+        "babel-loader": "10.1.1",
+        "babel-plugin-module-resolver": "5.0.3",
+        "babel-plugin-react-native-web": "0.21.2",
+        "babel-preset-expo": "56.0.15",
         "copyfiles": "2.4.1",
         "del-cli": "6.0.0",
         "eslint": "9.37.0",
@@ -91,20 +116,35 @@
         "eslint-plugin-react": "7.37.5",
         "eslint-plugin-react-hooks": "7.0.0",
         "eslint-plugin-react-native": "5.0.0",
+        "expo": "56.0.11",
+        "expo-font": "56.0.6",
+        "expo-status-bar": "56.0.4",
         "globals": "17.4.0",
+        "html-webpack-plugin": "5.6.7",
+        "jest": "29.6.3",
         "jsonc-eslint-parser": "2.4.1",
-        "react": "19.2.6",
-        "react-native": "0.83.2",
+        "prettier": "2.8.8",
+        "react": "19.2.3",
+        "react-dom": "19.2.3",
+        "react-native": "0.85.3",
         "react-native-builder-bob": "0.40.13",
+        "react-native-monorepo-config": "0.3.3",
+        "react-native-screens": "4.24.0",
+        "react-native-web": "0.21.2",
+        "react-test-renderer": "19.2.3",
         "release-it": "19.0.4",
         "turbo": "2.5.6",
         "typescript": "5.9.3",
-        "typescript-eslint": "8.46.1"
+        "typescript-eslint": "8.46.1",
+        "url-loader": "4.1.1",
+        "webpack": "5.107.1",
+        "webpack-cli": "7.0.2",
+        "webpack-dev-server": "5.2.4"
     },
     "peerDependencies": {
-        "lucide-react-native": ">= 0.577.0",
+        "lucide-react-native": ">= 1.16.0",
         "moment": "*",
-        "ncore-context": ">= 1.0.5",
+        "ncore-context": ">= 1.0.7",
         "react": "*",
         "react-native": "*",
         "react-native-safe-area-context": ">= 5.7.0",
@@ -113,7 +153,8 @@
     },
     "workspaces": [
         "example/mobile",
-        "example/web"
+        "example/web",
+        "example/src"
     ],
     "packageManager": "yarn@4.11.0",
     "react-native-builder-bob": {
@@ -162,11 +203,11 @@
         "version": "0.57.2"
     },
     "dependencies": {
-        "lucide-react-native": "0.577.0",
+        "lucide-react-native": "1.16.0",
         "moment": "https://git.nibgat.space/nibgat-community/moment.git",
-        "ncore-context": "1.0.5",
-        "react-native-safe-area-context": "5.7.0",
-        "react-native-svg": "15.15.3",
+        "ncore-context": "1.0.7",
+        "react-native-safe-area-context": "5.5.2",
+        "react-native-svg": "15.15.5",
         "rrule": "https://git.nibgat.space/nibgat-community/rrule.git"
     }
 }

+ 328 - 12
src/components/bottomSheet/index.tsx

@@ -4,12 +4,14 @@ import {
     forwardRef,
     useEffect,
     useState,
-    useRef
+    useRef,
+    type PointerEvent
 } from "react";
 import {
     type LayoutChangeEvent,
     PanResponder,
     ScrollView,
+    Platform,
     Animated,
     Easing,
     View
@@ -25,15 +27,19 @@ import {
 import {
     useSafeAreaInsets
 } from "react-native-safe-area-context";
-import type {
-    RefForwardingComponent
+import {
+    safeGlobal,
+    webStyle,
+    type RefForwardingComponent,
+    type SafePointerEvent
 } from "../../types";
 import type {
     IModalRef
 } from "../modal/type";
 import {
     windowHeight,
-    uuid
+    uuid,
+    windowWidth
 } from "../../utils";
 import Modal from "../modal";
 
@@ -419,6 +425,7 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
                 return true;
             },
             onPanResponderGrant: (evt) => {
+                console.log("GRANT", evt.nativeEvent);
                 if(!isCanSwipeRef.current) return;
 
                 gestureStartY.current = evt.nativeEvent.pageY;
@@ -743,7 +750,274 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
     const renderView = () => {
         return <Animated.View
             {...props}
-            {...panResponder.panHandlers}
+            {...(Platform.OS === "web" ? {} : panResponder.panHandlers)}
+            onPointerDown={Platform.OS === "web" ? (evt) => {
+                const nativeEvt = evt as unknown as PointerEvent;
+                const startY = nativeEvt.clientY;
+                gestureStartY.current = nativeEvt.clientY;
+
+                const initialT = translateYValue.current;
+                const initialH = heightValue.current;
+                const initialS = scrollOffset.current;
+
+                animatedTranslateY.setOffset(initialT);
+                animatedTranslateY.setValue(0);
+
+                animatedHeight.setOffset(initialH);
+                animatedHeight.setValue(0);
+
+                let lastY = startY;
+                let lastTime = Date.now();
+                let velocityY = 0;
+
+                const handlePointerMove = (moveEvt: SafePointerEvent) => {
+                    if (!isCanSwipeRef.current) return;
+
+                    const dy = moveEvt.clientY - startY;
+                    if (Math.abs(dy) < 5) return;
+
+                    const now = Date.now();
+                    const dt = now - lastTime;
+                    if (dt > 0) {
+                        velocityY = (moveEvt.clientY - lastY) / dt;
+                    }
+                    lastY = moveEvt.clientY;
+                    lastTime = now;
+
+                    const delta = -dy;
+                    const pivot = snapPoint ?? contentHeight.current;
+                    const isAtTavan = heightValue.current >= maxHeight.current - 1;
+                    const hasScroll = scrollViewContentHeight.current > scrollViewLayoutHeight.current;
+                    const isAtTop = scrollOffset.current <= 0;
+                    const isFromTopArea = gestureStartY.current < TOP_GRAB_AREA;
+                    const maxS = Math.max(0, scrollViewContentHeight.current - scrollViewLayoutHeight.current);
+
+                    if (dy > 0 && isAtTavan && hasScroll && !isAtTop && !isFromTopArea) {
+                        const usedForS = Math.max(-dy, -initialS);
+                        scrollOffset.current = initialS + usedForS;
+                        scrollViewRef.current?.scrollTo({
+                            y: scrollOffset.current,
+                            animated: false
+                        });
+                        return;
+                    }
+
+                    if (dy < 0) {
+                        let currentDelta = delta;
+
+                        const effectiveInitialT = Math.max(0, initialT);
+                        const usedForT = Math.min(currentDelta, effectiveInitialT);
+                        animatedTranslateY.setValue(-usedForT);
+                        currentDelta -= usedForT;
+
+                        if (currentDelta > 0) {
+                            if (initialH < pivot) {
+                                const spaceToPivot = pivot - initialH;
+                                const usedForH = Math.min(currentDelta, spaceToPivot);
+                                animatedHeight.setValue(usedForH);
+                                currentDelta -= usedForH;
+                            }
+
+                            const isRestoringHeight = initialH < pivot;
+                            const canScroll = isCanFullScreenOnSwipeRef.current || isWorkAsFullScreenRef.current || !isRestoringHeight;
+
+                            if (currentDelta > 0 && canScroll) {
+                                const remainingScroll = maxS - initialS;
+                                if (remainingScroll > 0) {
+                                    const usedForS = Math.min(currentDelta, remainingScroll);
+                                    scrollOffset.current = initialS + usedForS;
+                                    scrollViewRef.current?.scrollTo({
+                                        y: scrollOffset.current,
+                                        animated: false
+                                    });
+                                    currentDelta -= usedForS;
+                                    animatedHeight.setValue(initialH < pivot ? (pivot - initialH) : 0);
+                                }
+                            }
+
+                            if (currentDelta > 0) {
+                                if (isCanFullScreenOnSwipeRef.current) {
+                                    const totalUsedBefore = initialH < pivot ? (pivot - initialH) : 0;
+                                    animatedHeight.setValue(totalUsedBefore + currentDelta);
+                                } else {
+                                    animatedHeight.setValue(initialH < pivot ? (pivot - initialH) : 0);
+                                }
+                            }
+                        }
+                    } else {
+                        let currentDelta = delta;
+
+                        if (initialH > pivot || initialS > 0) {
+                            if (initialS > 0) {
+                                const usedForS = Math.max(currentDelta, -initialS);
+                                scrollOffset.current = initialS + usedForS;
+                                scrollViewRef.current?.scrollTo({
+                                    y: scrollOffset.current,
+                                    animated: false
+                                });
+                                currentDelta -= usedForS;
+                                animatedHeight.setValue(initialH > pivot ? 0 : pivot - initialH);
+                            }
+
+                            if (currentDelta < 0 && initialH > pivot) {
+                                const distanceToPivot = pivot - initialH;
+                                const usedForH = Math.max(currentDelta, distanceToPivot);
+                                animatedHeight.setValue(usedForH);
+                                currentDelta -= usedForH;
+                            }
+                        }
+
+                        if (currentDelta < 0) {
+                            animatedHeight.setValue(initialH > pivot ? (pivot - initialH) : 0);
+                            animatedTranslateY.setValue(-currentDelta);
+                            scrollOffset.current = 0;
+                            scrollViewRef.current?.scrollTo({
+                                y: 0,
+                                animated: false
+                            });
+                        }
+                    }
+                };
+
+                const handlePointerUp = () => {
+                    safeGlobal.removeEventListener("pointermove", handlePointerMove);
+                    safeGlobal.removeEventListener("pointerup", handlePointerUp);
+
+                    animatedHeight.flattenOffset();
+                    animatedTranslateY.flattenOffset();
+
+                    const currentT = translateYValue.current;
+                    const currentH = heightValue.current;
+                    const pivot = snapPoint ?? contentHeight.current;
+                    const tavan = maxHeight.current;
+
+                    const isAtTavan = currentH >= tavan - 1;
+                    const hasScroll = scrollViewContentHeight.current > scrollViewLayoutHeight.current;
+                    const isAtTop = scrollOffset.current <= 1;
+                    const isFromTopArea = gestureStartY.current < TOP_GRAB_AREA;
+
+                    if (isAtTavan && hasScroll && !isAtTop && !isFromTopArea) {
+                        if (Math.abs(velocityY) > 0.1) {
+                            const momentum = velocityY * -350;
+                            const maxS = Math.max(0, scrollViewContentHeight.current - scrollViewLayoutHeight.current);
+                            const targetOffset = Math.max(0, Math.min(scrollOffset.current + momentum, maxS));
+
+                            const scrollAnim = new Animated.Value(scrollOffset.current);
+                            scrollAnim.addListener(({
+                                value
+                            }) => {
+                                scrollViewRef.current?.scrollTo({
+                                    y: value,
+                                    animated: false
+                                });
+                                scrollOffset.current = value;
+                            });
+
+                            Animated.timing(scrollAnim, {
+                                toValue: targetOffset,
+                                duration: Math.min(Math.abs(momentum) * 2, 600),
+                                easing: Easing.out(Easing.quad),
+                                useNativeDriver: false
+                            }).start(() => {
+                                scrollAnim.removeAllListeners();
+                                checkScrollThreshold();
+                            });
+                        } else {
+                            checkScrollThreshold();
+                        }
+                        return;
+                    }
+
+                    const isFastSwipeDown = velocityY > 0.5;
+                    const isFastSwipeUp = velocityY < -0.5;
+
+                    if (currentT <= Math.max(pivot * 0.2, 60)) {
+                        let toValue = pivot;
+
+                        if (isFastSwipeUp && isCanFullScreenOnSwipeRef.current) {
+                            toValue = tavan;
+                        } else if (isFastSwipeDown) {
+                            toValue = pivot;
+                        } else {
+                            if (!isCanFullScreenOnSwipeRef.current) {
+                                toValue = pivot;
+                            } else {
+                                const totalRange = tavan - pivot;
+                                const distFromPivot = currentH - pivot;
+
+                                if (distFromPivot < totalRange * 0.33) toValue = pivot;
+                                else if (distFromPivot > totalRange * 0.66) toValue = tavan;
+                                else toValue = (tavan - currentH) < (currentH - pivot) ? tavan : pivot;
+                            }
+                        }
+
+                        Animated.spring(animatedHeight, {
+                            toValue,
+                            useNativeDriver: false,
+                            friction: 10,
+                            tension: 40
+                        }).start();
+                        Animated.spring(animatedTranslateY, {
+                            toValue: 0,
+                            useNativeDriver: false,
+                            friction: 10,
+                            tension: 40
+                        }).start();
+                    } else {
+                        if (!isSwipeCloseRef.current) {
+                            Animated.spring(animatedHeight, {
+                                toValue: pivot,
+                                useNativeDriver: false,
+                                friction: 10,
+                                tension: 40
+                            }).start();
+                            Animated.timing(animatedTranslateY, {
+                                toValue: 0,
+                                useNativeDriver: false,
+                                duration: 300
+                            }).start();
+                        } else {
+                            let toValueT = 0;
+                            let isClosing = false;
+
+                            if (isFastSwipeDown) {
+                                toValueT = pivot + 100;
+                                isClosing = true;
+                            } else {
+                                if (currentT > pivot * 0.5) {
+                                    toValueT = pivot + 100;
+                                    isClosing = true;
+                                } else {
+                                    toValueT = 0;
+                                    isClosing = false;
+                                }
+                            }
+
+                            if (onClose) onClose({
+                                id: id.current
+                            });
+
+                            Animated.timing(animatedTranslateY, {
+                                toValue: toValueT,
+                                useNativeDriver: false,
+                                duration: 300
+                            }).start(({
+                                finished
+                            }) => {
+                                if (finished && isClosing) {
+                                    setIsActive(false);
+                                    if (onClosed) onClosed({
+                                        id: id.current
+                                    });
+                                }
+                            });
+                        }
+                    }
+                };
+
+                safeGlobal.addEventListener("pointermove", handlePointerMove);
+                safeGlobal.addEventListener("pointerup", handlePointerUp);
+            } : undefined}
             onLayout={onLayout}
             style={[
                 {
@@ -764,7 +1038,12 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
                         translateY: animatedTranslateY
                     }]
                 },
-                stylesheet.container
+                stylesheet.container,
+                webStyle({
+                    touchAction: "none",
+                    userSelect: "none",
+                    cursor: "grab"
+                })
             ]}
         >
             {renderHeader()}
@@ -786,7 +1065,12 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
                 ref={scrollViewRef}
                 bounces={false}
                 style={[
-                    scrollViewStyle
+                    scrollViewStyle,
+                    webStyle({
+                        maxWidth: windowWidth > 500 ? 500 : undefined,
+                        width: windowWidth > 500 ? 500 : undefined,
+                        alignSelf: "center"
+                    })
                 ]}
             >
                 {children}
@@ -801,6 +1085,20 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
             return null;
         }
 
+        if(Platform.OS === "web") {
+            return <View
+                style={[
+                    webStyle({
+                        maxWidth: windowWidth > 500 ? 500 : undefined,
+                        width: windowWidth > 500 ? 500 : undefined,
+                        alignSelf: "center"
+                    })
+                ]}
+            >
+                {RenderHeaderComponent()}
+            </View>;
+        }
+
         return RenderHeaderComponent();
     };
 
@@ -809,6 +1107,20 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
             return null;
         }
 
+        if(Platform.OS === "web") {
+            return <View
+                style={[
+                    webStyle({
+                        maxWidth: windowWidth > 500 ? 500 : undefined,
+                        width: windowWidth > 500 ? 500 : undefined,
+                        alignSelf: "center"
+                    })
+                ]}
+            >
+                <RenderBottomComponent/>
+            </View>;
+        }
+
         return <RenderBottomComponent/>;
     };
 
@@ -822,9 +1134,8 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
         const handleBorderRadius = Math.ceil(handleHeight / 2);
 
         return <View
-            {...panResponder.panHandlers}
-            onStartShouldSetResponderCapture={() => false}
-            onMoveShouldSetResponderCapture={() => false}
+            onStartShouldSetResponderCapture={() => Platform.OS === "web"}
+            onMoveShouldSetResponderCapture={() => Platform.OS === "web"}
             style={[
                 stylesheet.handleContainer,
                 {
@@ -833,9 +1144,14 @@ const BottomSheet: RefForwardingComponent<IBottomSheetRef, IBottomSheetProps> =
                         : "transparent",
                     height: handleContainerHeight,
                     transform: [{
-                        translateY: -handleContainerHeight
+                        translateY: -handleContainerHeight * (Platform.OS === "web" ? 1.75 : 1)
                     }]
-                }
+                },
+                webStyle({
+                    touchAction: "none !important",
+                    userSelect: "none",
+                    cursor: "grab"
+                })
             ]}
         >
             <View

+ 9 - 0
src/components/checkBox/index.tsx

@@ -3,6 +3,7 @@ import {
 } from "react";
 import {
     TouchableOpacity,
+    Platform,
     View
 } from "react-native";
 import type ICheckBoxProps from "./type";
@@ -253,6 +254,14 @@ const CheckBox: FC<ICheckBoxProps> = ({
                 stylesheet.container,
                 containerDynamicStyle
             ]}
+            {...Platform.select({
+                web: {
+                    dataSet: {
+                        disablePressableDownEffect: "true"
+                    }
+                },
+                default: {}
+            })}
         >
             {isFlip ? null : renderCheckIndicator()}
 

+ 10 - 0
src/components/modal/index.tsx

@@ -8,6 +8,7 @@ import {
 import {
     TouchableWithoutFeedback,
     Animated,
+    Platform,
     Easing,
     View
 } from "react-native";
@@ -167,6 +168,15 @@ const Modal: RefForwardingComponent<IModalRef, IModalProps> = ({
                         backgroundColor: colors.system.scrim
                     }
                 ]}
+                {...Platform.select({
+                    web: {
+                        dataSet: {
+                            disablePressableHoverEffect: "true",
+                            disablePressableDownEffect: "true"
+                        }
+                    },
+                    default: {}
+                })}
             />
         </TouchableWithoutFeedback>;
     };

+ 7 - 3
src/components/monthSelector/index.tsx

@@ -28,8 +28,9 @@ import {
     NCoreUIKitTheme,
     NCoreUIKitToast
 } from "../../core/hooks";
-import type {
-    Mutable
+import {
+    type Mutable,
+    webStyle
 } from "../../types";
 import {
     ChevronRight as ChevronRightIcon,
@@ -426,7 +427,10 @@ const MonthSelector = ({
                 return <View
                     key={`month-row-${mIndex}`}
                     style={[
-                        stylesheet.rowContainer
+                        stylesheet.rowContainer,
+                        webStyle({
+                            width: "100%"
+                        })
                     ]}
                 >
                     {currentMonths.map((monthItem, monthIndex) => {

+ 9 - 0
src/components/numericInput/index.tsx

@@ -8,6 +8,7 @@ import {
     TextInput as NativeTextInput,
     TouchableOpacity,
     Keyboard,
+    Platform,
     View
 } from "react-native";
 import type ITextInputProps from "./type";
@@ -581,6 +582,14 @@ const NumericInput: RefForwardingComponent<INumericInputRef, ITextInputProps> =
         onPress={() => {
             if(!isDisabled) inputRef.current?.focus();
         }}
+        {...Platform.select({
+            web: {
+                dataSet: {
+                    disablePressableDownEffect: "true"
+                }
+            },
+            default: {}
+        })}
     >
         {renderTitle()}
 

+ 9 - 0
src/components/radioButton/index.tsx

@@ -3,6 +3,7 @@ import {
 } from "react";
 import {
     TouchableOpacity,
+    Platform,
     View
 } from "react-native";
 import type IRadioButtonProps from "./type";
@@ -248,6 +249,14 @@ const RadioButton: FC<IRadioButtonProps> = ({
                 stylesheet.container,
                 containerDynamicStyle
             ]}
+            {...Platform.select({
+                web: {
+                    dataSet: {
+                        disablePressableDownEffect: "true"
+                    }
+                },
+                default: {}
+            })}
         >
             {isFlip ? null : renderIndicatorContainer()}
 

+ 63 - 3
src/components/snackBar/index.tsx

@@ -1,4 +1,5 @@
 import {
+    type PointerEvent,
     useEffect,
     useState,
     type FC,
@@ -7,6 +8,7 @@ import {
 import {
     TouchableWithoutFeedback,
     PanResponder,
+    Platform,
     Animated,
     Easing,
     View
@@ -22,17 +24,21 @@ import {
 import {
     useSafeAreaInsets
 } from "react-native-safe-area-context";
+import {
+    safeGlobal,
+    type SafePointerEvent
+} from "../../types";
 import {
     X as XIcon
 } from "lucide-react-native";
 import {
     Portal
 } from "../../helpers/portalize";
-import Button from "../button";
-import Text from "../text";
 import {
     windowHeight
 } from "../../utils";
+import Button from "../button";
+import Text from "../text";
 
 const SnackBar: FC<ISnackBarProps> = ({
     isCloseOnPressActionButton = true,
@@ -331,7 +337,7 @@ const SnackBar: FC<ISnackBarProps> = ({
 
     return <Portal name="snack-bar-system">
         <Animated.View
-            {...panResponder.panHandlers}
+            {...(Platform.OS === "web" ? {} : panResponder.panHandlers)}
             onLayout={(event) => {
                 const _contentHeight = event.nativeEvent.layout.height;
 
@@ -339,6 +345,60 @@ const SnackBar: FC<ISnackBarProps> = ({
 
                 setIsMeasured(true);
             }}
+            onPointerDown={Platform.OS === "web" ? (evt) => {
+                const nativeEvt = evt as unknown as PointerEvent;
+                const startY = nativeEvt.clientY;
+
+                let lastY = startY;
+                let lastTime = Date.now();
+                let velocityY = 0;
+
+                const handlePointerMove = (moveEvt: SafePointerEvent) => {
+                    const dy = moveEvt.clientY - startY;
+
+                    if (dy > 0) return; // sadece yukarı swipe
+
+                    const now = Date.now();
+                    const dt = now - lastTime;
+                    if (dt > 0) velocityY = (moveEvt.clientY - lastY) / dt;
+                    lastY = moveEvt.clientY;
+                    lastTime = now;
+
+                    const op = Math.max(0, 1 + (dy / contentHeight.current));
+                    opacityAnim.setValue(op);
+                    transformAnim.setValue(dy);
+                };
+
+                const handlePointerUp = () => {
+                    safeGlobal.removeEventListener("pointermove", handlePointerMove);
+                    safeGlobal.removeEventListener("pointerup", handlePointerUp);
+
+                    const dy = lastY - startY;
+
+                    if (velocityY < -0.5 || dy < -25) {
+                        closeAnimation();
+                        return;
+                    }
+
+                    Animated.parallel([
+                        Animated.timing(opacityAnim, {
+                            duration: openAnimationDelay,
+                            useNativeDriver: true,
+                            easing: Easing.linear,
+                            toValue: 1
+                        }),
+                        Animated.timing(transformAnim, {
+                            duration: openAnimationDelay,
+                            useNativeDriver: true,
+                            easing: Easing.linear,
+                            toValue: 0
+                        })
+                    ]).start();
+                };
+
+                safeGlobal.addEventListener("pointermove", handlePointerMove);
+                safeGlobal.addEventListener("pointerup", handlePointerUp);
+            } : undefined}
             style={[
                 style,
                 stylesheet.container,

+ 9 - 0
src/components/switch/index.tsx

@@ -6,6 +6,7 @@ import {
 import {
     TouchableOpacity,
     Animated,
+    Platform,
     Easing,
     View
 } from "react-native";
@@ -263,6 +264,14 @@ const Switch: FC<ISwitchProps> = ({
                 stylesheet.container,
                 containerDynamicStyle
             ]}
+            {...Platform.select({
+                web: {
+                    dataSet: {
+                        disablePressableDownEffect: "true"
+                    }
+                },
+                default: {}
+            })}
         >
             {isFlip ? null : renderIndicatorContainer()}
 

+ 9 - 0
src/components/textAreaInput/index.tsx

@@ -9,6 +9,7 @@ import {
     TextInput as NativeTextInput,
     TouchableOpacity,
     Keyboard,
+    Platform,
     View
 } from "react-native";
 import type ITextAreaInputProps from "./type";
@@ -516,6 +517,14 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
         onPress={() => {
             if(!isDisabled) inputRef.current?.focus();
         }}
+        {...Platform.select({
+            web: {
+                dataSet: {
+                    disablePressableDownEffect: "true"
+                }
+            },
+            default: {}
+        })}
     >
         {renderTitle()}
 

+ 9 - 0
src/components/textInput/index.tsx

@@ -8,6 +8,7 @@ import {
     TextInput as NativeTextInput,
     TouchableOpacity,
     Keyboard,
+    Platform,
     View
 } from "react-native";
 import type ITextInputProps from "./type";
@@ -519,6 +520,14 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
         onPress={() => {
             if(!isDisabled) inputRef.current?.focus();
         }}
+        {...Platform.select({
+            web: {
+                dataSet: {
+                    disablePressableDownEffect: "true"
+                }
+            },
+            default: {}
+        })}
     >
         {renderTitle()}
 

+ 7 - 3
src/components/yearSelector/index.tsx

@@ -28,8 +28,9 @@ import {
     NCoreUIKitTheme,
     NCoreUIKitToast
 } from "../../core/hooks";
-import type {
-    Mutable
+import {
+    type Mutable,
+    webStyle
 } from "../../types";
 import {
     ChevronRight as ChevronRightIcon,
@@ -423,7 +424,10 @@ const YearSelector = ({
                 return <View
                     key={`year-row-${yIndex}`}
                     style={[
-                        stylesheet.rowContainer
+                        stylesheet.rowContainer,
+                        webStyle({
+                            width: "100%"
+                        })
                     ]}
                 >
                     {currentYears.map((yearItem, yearIndex) => {

+ 75 - 1
src/core/index.tsx

@@ -1,6 +1,9 @@
 import {
     type ReactNode
 } from "react";
+import {
+    Platform
+} from "react-native";
 import {
     initializeInstances
 } from "./hooks";
@@ -10,8 +13,8 @@ import type {
 import {
     SafeAreaProvider
 } from "react-native-safe-area-context";
-import CoreContext from "../context";
 import packageJSON from "../../package.json";
+import CoreContext from "../context";
 
 export const getNCoreUIKitVersion = () => packageJSON.version;
 
@@ -47,6 +50,77 @@ export const setupNCoreUIKit = (initialState: NCoreUIKitConfig, isCustom: boolea
 
         initializeInstances(NCoreUIKit);
 
+        if (Platform.OS === "web") {
+            const globalRef = globalThis as unknown as { document?: unknown };
+
+            if (globalRef && typeof globalRef.document === "object" && globalRef.document !== null) {
+                const doc = globalRef.document as {
+                    getElementById?: (id: string) => unknown;
+                    createElement?: (tagName: string) => unknown;
+                    head?: unknown;
+                };
+
+                const styleId = "cl-rnw-touchable-fix";
+
+                if (typeof doc.getElementById === "function" && !doc.getElementById(styleId)) {
+                    if (typeof doc.createElement === "function" && doc.head && typeof doc.head === "object") {
+
+                        const style = doc.createElement("style") as {
+                            id?: string;
+                            type?: string;
+                            innerHTML?: string;
+                        };
+
+                        if (style) {
+                            style.id = styleId;
+                            style.type = "text/css";
+                            style.innerHTML = `
+                                html, body, #root {
+                                    touch-action: none;
+                                    overflow: hidden;
+                                }
+
+                                [role="button"],
+                                [data-focusable="true"],
+                                div[tabindex="0"] {
+                                    cursor: pointer !important;
+                                    transition: opacity 0.15s ease-in-out, transform 0.1s ease-in-out !important;
+                                }
+
+                                [role="button"]:not([data-disable-pressable-hover-effect="true"]):hover,
+                                [data-focusable="true"]:not([data-disable-pressable-hover-effect="true"]):hover,
+                                div[tabindex="0"]:not([data-disable-pressable-hover-effect="true"]):hover {
+                                    opacity: 0.8 !important;
+                                }
+
+                                [role="button"]:not([data-disable-pressable-down-effect="true"]):active,
+                                [data-focusable="true"]:not([data-disable-pressable-down-effect="true"]):active,
+                                div[tabindex="0"]:not([data-disable-pressable-down-effect="true"]):active {
+                                    opacity: 0.5 !important;
+                                    transform: translateY(2px) !important;
+                                }
+
+                                input,
+                                textarea,
+                                select,
+                                [role="textinput"],
+                                div[tabindex]:focus {
+                                    outline: none !important;
+                                    box-shadow: none !important;
+                                }
+                            `;
+
+                            const head = doc.head as { appendChild?: (node: unknown) => void };
+
+                            if (typeof head.appendChild === "function") {
+                                head.appendChild(style);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
         return NCoreUIKit;
     }
 };

+ 18 - 0
src/types/index.ts

@@ -1,6 +1,11 @@
 import {
     type ForwardRefRenderFunction
 } from "react";
+import {
+    type StyleProp,
+    type ViewStyle,
+    Platform
+} from "react-native";
 import {
     type INCoreUIKitIconCallbackProps
 } from "./icon";
@@ -55,12 +60,25 @@ export type {
     ThemeType
 };
 
+export const webStyle = (styles: Record<string, unknown>): StyleProp<ViewStyle> => Platform.OS === "web" ? (styles as StyleProp<ViewStyle>) : {};
+
 export type RecursiveRecord = {
   [key: string]: string | RecursiveRecord;
 };
 
 export interface RefForwardingComponent<T, P = object> extends ForwardRefRenderFunction<T, P> {};
 
+export interface SafePointerEvent {
+    clientY: number;
+}
+
+export interface SafeWebWindow {
+    addEventListener: (type: "pointermove" | "pointerup", listener: (evt: SafePointerEvent) => void) => void;
+    removeEventListener: (type: "pointermove" | "pointerup", listener: (evt: SafePointerEvent) => void) => void;
+}
+
+export const safeGlobal = globalThis as unknown as SafeWebWindow;
+
 export type Mutable<T> = {
     -readonly [P in keyof T]: T[P];
 };

+ 19 - 4
tsconfig.json

@@ -2,12 +2,19 @@
     "compilerOptions": {
         "rootDir": ".",
         "paths": {
-            "ncore-ui-kit-mobile": [
+            "ncore-ui-kit": [
                 "./src/index"
             ]
         },
+        "types": [
+            "node"
+        ],
+        "outDir": "lib",
+        "declarationDir": "lib/typescript",
         "allowUnreachableCode": false,
         "allowUnusedLabels": false,
+        "composite": true,
+        "declaration": true,
         "customConditions": [
             "react-native-strict-api"
         ],
@@ -15,11 +22,12 @@
         "forceConsistentCasingInFileNames": true,
         "jsx": "react-jsx",
         "lib": [
-            "ESNext"
+            "ESNext",
+            "dom"
         ],
         "module": "ESNext",
         "moduleResolution": "bundler",
-        "noEmit": true,
+        "noEmit": false,
         "noFallthroughCasesInSwitch": true,
         "noImplicitReturns": true,
         "noImplicitUseStrict": false,
@@ -33,7 +41,14 @@
         "target": "ESNext",
         "verbatimModuleSyntax": true
     },
+    "include": [
+        "src/**/*.json",
+        "src/**/*",
+        "package.json"
+    ],
     "exclude": [
-        "version.mjs"
+        "version.mjs",
+        "lib",
+        "node_modules"
     ]
 }

+ 33 - 4
turbo.json

@@ -23,14 +23,14 @@
                 "example/mobile/android",
                 "!example/mobile/android/.gradle",
                 "!example/mobile/android/build",
-                "!example/mobile/android/app/build",
+                "!example/mobile/android/app/build"
+            ],
+            "outputs": [
                 "example/web/package.json",
                 "example/web/android",
                 "!example/web/android/.gradle",
                 "!example/web/android/build",
                 "!example/web/android/app/build"
-            ],
-            "outputs": [
             ]
         },
         "build:ios": {
@@ -49,13 +49,42 @@
                 "example/mobile/package.json",
                 "example/mobile/ios",
                 "!example/mobile/ios/build",
-                "!example/mobile/ios/Pods",
+                "!example/mobile/ios/Pods"
+            ],
+            "outputs": [
+                "example/web/package.json",
+                "example/web/ios",
+                "!example/web/ios/build",
+                "!example/web/ios/Pods"
+            ]
+        },
+        "build:web": {
+            "inputs": [
+                "package.json",
+                "android",
+                "!android/build",
+                "src/*.ts",
+                "src/*.tsx",
+                "example/web/package.json",
+                "example/web/android",
+                "!example/web/android/.gradle",
+                "!example/web/android/build",
+                "!example/web/android/app/build",
                 "example/web/package.json",
                 "example/web/ios",
                 "!example/web/ios/build",
                 "!example/web/ios/Pods"
             ],
             "outputs": [
+                "example/mobile/package.json",
+                "example/mobile/android",
+                "!example/mobile/android/.gradle",
+                "!example/mobile/android/build",
+                "!example/mobile/android/app/build",
+                "example/mobile/package.json",
+                "example/mobile/ios",
+                "!example/mobile/ios/build",
+                "!example/mobile/ios/Pods"
             ]
         }
     }

文件差異過大導致無法顯示
+ 75 - 602
yarn.lock


部分文件因文件數量過多而無法顯示