Pārlūkot izejas kodu

Merge branch 'release/1.1.0-alpha.7' into develop

lfabl 2 nedēļas atpakaļ
vecāks
revīzija
4afe63cc79
79 mainītis faili ar 5189 papildinājumiem un 1514 dzēšanām
  1. 12 0
      .agents/AGENTS.md
  2. 7 0
      .editorconfig
  3. 0 1
      .gitattributes
  4. 6 3
      .vscode/settings.json
  5. 583 542
      eslint-local-rules/index.js
  6. 32 4
      eslint.config.mjs
  7. 197 151
      example/src/navigation/index.tsx
  8. 3 0
      example/src/navigation/type.ts
  9. 179 0
      example/src/pages/components/codeEditor/index.tsx
  10. 30 0
      example/src/pages/components/codeEditor/stylesheet.ts
  11. 91 0
      example/src/pages/components/markdownEditor/index.tsx
  12. 27 0
      example/src/pages/components/markdownEditor/stylesheet.ts
  13. 175 0
      example/src/pages/components/systemToolbar/index.tsx
  14. 25 0
      example/src/pages/components/systemToolbar/stylesheet.ts
  15. 0 1
      example/src/pages/components/timeSelector/index.tsx
  16. 243 0
      example/src/pages/components/tooltip/index.tsx
  17. 33 0
      example/src/pages/components/tooltip/stylesheet.ts
  18. 0 3
      example/src/pages/coreFeatures/defaultJSONs/index.tsx
  19. 0 5
      example/src/pages/coreFeatures/localeExamples/index.tsx
  20. 0 5
      example/src/pages/coreFeatures/toolsUsage/index.tsx
  21. 0 4
      example/src/pages/coreFeatures/typesOverride/index.tsx
  22. 116 18
      example/src/variants/locales/default.json
  23. 1 1
      package.json
  24. 5 6
      src/components/button/index.tsx
  25. 37 37
      src/components/button/stylesheet.ts
  26. 4 7
      src/components/checkBox/index.tsx
  27. 436 0
      src/components/codeEditor/index.tsx
  28. 208 0
      src/components/codeEditor/stylesheet.ts
  29. 39 0
      src/components/codeEditor/type.ts
  30. 7 7
      src/components/codeViewer/parser.ts
  31. 40 37
      src/components/codeViewer/stylesheet.ts
  32. 12 7
      src/components/dateSelector/index.tsx
  33. 0 6
      src/components/dateTimePicker/index.tsx
  34. 53 35
      src/components/dateTimeSheet/index.tsx
  35. 1 1
      src/components/embeddedMenu/components/menuButton/index.tsx
  36. 46 31
      src/components/embeddedMenu/index.tsx
  37. 8 8
      src/components/header/index.tsx
  38. 4 1
      src/components/header/type.ts
  39. 0 1
      src/components/highlightButton/index.tsx
  40. 41 6
      src/components/index.ts
  41. 14 9
      src/components/mainHeader/index.tsx
  42. 530 0
      src/components/markdownEditor/index.tsx
  43. 140 0
      src/components/markdownEditor/stylesheet.ts
  44. 34 0
      src/components/markdownEditor/type.ts
  45. 89 86
      src/components/markdownViewer/index.tsx
  46. 0 5
      src/components/markdownViewer/stylesheet.ts
  47. 4 3
      src/components/markdownViewer/type.ts
  48. 32 10
      src/components/markdownViewer/util.ts
  49. 1 1
      src/components/menu/components/menuButton/index.tsx
  50. 24 14
      src/components/menu/index.tsx
  51. 12 7
      src/components/monthSelector/index.tsx
  52. 11 14
      src/components/numericInput/index.tsx
  53. 0 3
      src/components/radioButton/index.tsx
  54. 0 6
      src/components/selectBox/index.tsx
  55. 59 35
      src/components/selectSheet/index.tsx
  56. 1 1
      src/components/siteLogo/index.tsx
  57. 1 1
      src/components/snackBar/index.tsx
  58. 0 3
      src/components/switch/index.tsx
  59. 188 0
      src/components/systemToolbar/index.tsx
  60. 59 0
      src/components/systemToolbar/stylesheet.ts
  61. 43 0
      src/components/systemToolbar/type.ts
  62. 55 42
      src/components/textAreaInput/index.tsx
  63. 88 81
      src/components/textAreaInput/stylesheet.ts
  64. 13 7
      src/components/textAreaInput/type.ts
  65. 62 53
      src/components/textInput/index.tsx
  66. 90 81
      src/components/textInput/stylesheet.ts
  67. 6 0
      src/components/textInput/type.ts
  68. 82 73
      src/components/timeSelector/index.tsx
  69. 1 1
      src/components/toast/index.tsx
  70. 477 0
      src/components/tooltip/index.tsx
  71. 177 0
      src/components/tooltip/stylesheet.ts
  72. 93 0
      src/components/tooltip/type.ts
  73. 12 7
      src/components/yearSelector/index.tsx
  74. 29 29
      src/components/yearSelector/stylesheet.ts
  75. 0 1
      src/helpers/portalize/Host.tsx
  76. 11 2
      src/index.tsx
  77. 49 11
      src/variants/locales/default.json
  78. 1 0
      src/variants/themes/default.json
  79. BIN
      temp_index.tsx.bak

+ 12 - 0
.agents/AGENTS.md

@@ -38,3 +38,15 @@ Always follow these rules by default. Pay "extreme attention" (aşırı dikkat)
 - **Incorrect:** `flex1`, `fullWidth`, `transparentBackground`
 - **Correct:** `container`, `content`, `titleContainer`, `title`, `emptyCheckIcon`
 - For example: The outermost `<View>` in a component is usually `container`. A wrapper for content is `contentContainer`. A view wrapping a title is `titleContainer`. Always look at the semantic purpose of the element in the UI hierarchy.
+
+## Line Endings (CRLF)
+- Always use Windows-style CRLF line endings (`\r\n`) for all text and code files, unless a specific file or environment strictly requires LF (`\n`).
+
+
+## No Inline Comments
+- Never leave inline comments in the code explaining what the style or line does.
+- Remove all inline comments unless they are strictly necessary (e.g., leaving something broken intentionally to fix later).
+- Keep the codebase clean and free of conversational or explanatory comments.
+
+## Communication Language
+- ALWAYS communicate in Turkish (Türkçe konuş) with the user in all responses, explanations, and notes, unless strictly required otherwise.

+ 7 - 0
.editorconfig

@@ -0,0 +1,7 @@
+root = true
+
+[*]
+trim_trailing_whitespace = true
+insert_final_newline = true
+end_of_line = crlf
+charset = utf-8

+ 0 - 1
.gitattributes

@@ -1,3 +1,2 @@
 *.pbxproj -text
-# specific for windows script files
 *.bat text eol=crlf

+ 6 - 3
.vscode/settings.json

@@ -27,14 +27,17 @@
             "pattern": "./src"
         }
     ],
-    "editor.tabSize": 4,
-    "editor.insertSpaces": true,
-    "files.eol": "\n",
+    "editor.unicodeHighlight.invisibleCharacters": false,
+    "editor.unicodeHighlight.ambiguousCharacters": false,
+    "editor.unicodeHighlight.nonBasicASCII": false,
     "files.trimTrailingWhitespace": true,
     "files.insertFinalNewline": true,
     "files.trimFinalNewlines": true,
     "eslint.lintTask.enable": true,
     "eslint.format.enable": true,
+    "editor.insertSpaces": true,
+    "editor.tabSize": 4,
+    "files.eol": "\r\n",
     "[typescript]": {
         "editor.defaultFormatter": "dbaeumer.vscode-eslint"
     },

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 583 - 542
eslint-local-rules/index.js


+ 32 - 4
eslint.config.mjs

@@ -32,12 +32,32 @@ export default tseslint.config(
             "local-rules/no-jsx-parens-in-return": "error",
             "local-rules/no-newline-after-jsx": "error",
             "local-rules/no-static-inline-styles": "error",
+            "local-rules/jsx-no-blank-lines": "error",
+            "local-rules/sort-jsx-props": "error",
+            "local-rules/sort-import-specifiers": "error",
+            "local-rules/ncore-sort-styles": "error",
+            "local-rules/ncore-sort-types": "error",
+            "local-rules/ncore-format-union-types": "error",
+            "local-rules/sort-objects-by-length": "error",
+            "padded-blocks": ["error", "never"],
+            "padding-line-between-statements": [
+                "error",
+                { "blankLine": "never", "prev": "import", "next": "import" }
+            ],
             "@typescript-eslint/no-empty-object-type": [
                 "error",
                 {
                     "allowInterfaces": "with-single-extends"
                 }
             ],
+            "no-multiple-empty-lines": [
+                "error",
+                {
+                    "max": 1,
+                    "maxEOF": 0,
+                    "maxBOF": 0
+                }
+            ],
             "object-property-newline": [
                 "error",
                 {
@@ -194,7 +214,14 @@ export default tseslint.config(
         }
     },
     {
+        plugins: {
+            jsonc,
+            "local-rules": {
+                rules: localRulesPlugin.rules
+            }
+        },
         rules: {
+            "local-rules/sort-translations": "error",
             "jsonc/object-property-newline": [
                 "error",
                 {
@@ -223,6 +250,10 @@ export default tseslint.config(
             "jsonc/indent": [
                 "error",
                 4
+            ],
+            "linebreak-style": [
+                "error",
+                "windows"
             ]
         },
         languageOptions: {
@@ -230,9 +261,6 @@ export default tseslint.config(
         },
         files: [
             "**/*.json"
-        ],
-        plugins: {
-            jsonc
-        }
+        ]
     }
 );

+ 197 - 151
example/src/navigation/index.tsx

@@ -17,8 +17,8 @@ import {
     MainHeader
 } from "ncore-ui-kit";
 import {
-    type LinkingOptions,
     NavigationContainer,
+    type LinkingOptions,
     getStateFromPath,
     useNavigation
 } from "@react-navigation/native";
@@ -33,56 +33,60 @@ import {
     GoalIcon,
     HomeIcon
 } from "lucide-react-native";
-import AvatarPage from "../pages/components/avatar";
-import AvatarGroupPage from "../pages/components/avatarGroup";
-import BottomSheetPage from "../pages/components/bottomSheet";
-import ButtonPage from "../pages/components/button";
-import CheckBoxPage from "../pages/components/checkBox";
-import ChipPage from "../pages/components/chip";
-import CodeViewerPage from "../pages/components/codeViewer";
-import DateSelectorPage from "../pages/components/dateSelector";
-import DateTimePickerPage from "../pages/components/dateTimePicker";
-import DateTimeSheetPage from "../pages/components/dateTimeSheet";
-import DialogPage from "../pages/components/dialog";
-import EmbeddedMenuPage from "../pages/components/embeddedMenu";
-import HeaderPage from "../pages/components/header";
+import NotificationIndicatorPage from "../pages/components/notificationIndicator";
 import HighlightButtonPage from "../pages/components/highlightButton";
-import LoadingPage from "../pages/components/loading";
+import PaletteSwitcherPage from "../pages/components/paletteSwitcher";
+import LocaleExamplesPage from "../pages/coreFeatures/localeExamples";
+import DateTimePickerPage from "../pages/components/dateTimePicker";
 import LocaleSwitcherPage from "../pages/components/localeSwitcher";
-import MainHeaderPage from "../pages/components/mainHeader";
+import MarkdownEditorPage from "../pages/components/markdownEditor";
 import MarkdownViewerPage from "../pages/components/markdownViewer";
-import MenuPage from "../pages/components/menu";
-import ModalPage from "../pages/components/modal";
+import ThemeExamplesPage from "../pages/coreFeatures/themeExamples";
+import DateTimeSheetPage from "../pages/components/dateTimeSheet";
 import MonthSelectorPage from "../pages/components/monthSelector";
-import NotificationIndicatorPage from "../pages/components/notificationIndicator";
-import NumericInputPage from "../pages/components/numericInput";
 import PageContainerPage from "../pages/components/pageContainer";
-import PaletteSwitcherPage from "../pages/components/paletteSwitcher";
+import SystemToolbarPage from "../pages/components/systemToolbar";
+import TextAreaInputPage from "../pages/components/textAreaInput";
+import ThemeSwitcherPage from "../pages/components/themeSwitcher";
+import DefaultJSONsPage from "../pages/coreFeatures/defaultJSONs";
+import DateSelectorPage from "../pages/components/dateSelector";
+import EmbeddedMenuPage from "../pages/components/embeddedMenu";
+import NumericInputPage from "../pages/components/numericInput";
+import TimeSelectorPage from "../pages/components/timeSelector";
+import WebScrollbarPage from "../pages/components/webScrollbar";
+import YearSelectorPage from "../pages/components/yearSelector";
+import AvatarGroupPage from "../pages/components/avatarGroup";
+import BottomSheetPage from "../pages/components/bottomSheet";
 import RadioButtonPage from "../pages/components/radioButton";
-import RowCardPage from "../pages/components/rowCard";
-import SelectBoxPage from "../pages/components/selectBox";
 import SelectSheetPage from "../pages/components/selectSheet";
+import ToolsUsagePage from "../pages/coreFeatures/toolsUsage";
+import CodeEditorPage from "../pages/components/codeEditor";
+import CodeViewerPage from "../pages/components/codeViewer";
+import MainHeaderPage from "../pages/components/mainHeader";
+import SelectBoxPage from "../pages/components/selectBox";
 import SeperatorPage from "../pages/components/seperator";
+import StateCardPage from "../pages/components/stateCard";
+import TextInputPage from "../pages/components/textInput";
+import ImplementationPage from "../pages/implementation";
+import CheckBoxPage from "../pages/components/checkBox";
 import SiteLogoPage from "../pages/components/siteLogo";
 import SnackBarPage from "../pages/components/snackBar";
-import StateCardPage from "../pages/components/stateCard";
+import LoadingPage from "../pages/components/loading";
+import RowCardPage from "../pages/components/rowCard";
 import StickerPage from "../pages/components/sticker";
+import TooltipPage from "../pages/components/tooltip";
+import InstallationPage from "../pages/installation";
+import AvatarPage from "../pages/components/avatar";
+import ButtonPage from "../pages/components/button";
+import DialogPage from "../pages/components/dialog";
+import HeaderPage from "../pages/components/header";
 import SwitchPage from "../pages/components/switch";
-import TextPage from "../pages/components/text";
-import TextAreaInputPage from "../pages/components/textAreaInput";
-import TextInputPage from "../pages/components/textInput";
-import ThemeSwitcherPage from "../pages/components/themeSwitcher";
-import TimeSelectorPage from "../pages/components/timeSelector";
+import ModalPage from "../pages/components/modal";
 import ToastPage from "../pages/components/toast";
-import WebScrollbarPage from "../pages/components/webScrollbar";
-import YearSelectorPage from "../pages/components/yearSelector";
-import DefaultJSONsPage from "../pages/coreFeatures/defaultJSONs";
-import LocaleExamplesPage from "../pages/coreFeatures/localeExamples";
-import ThemeExamplesPage from "../pages/coreFeatures/themeExamples";
-import ToolsUsagePage from "../pages/coreFeatures/toolsUsage";
+import ChipPage from "../pages/components/chip";
+import MenuPage from "../pages/components/menu";
+import TextPage from "../pages/components/text";
 import Home from "../pages/home";
-import ImplementationPage from "../pages/implementation";
-import InstallationPage from "../pages/installation";
 
 const RootStack = createNativeStackNavigator();
 const ComponentsStack = createNativeStackNavigator();
@@ -168,6 +172,10 @@ const ComponentsNav = () => {
             component={CodeViewerPage}
             name="CodeViewer"
         />
+        <ComponentsStack.Screen
+            component={CodeEditorPage}
+            name="CodeEditor"
+        />
         <ComponentsStack.Screen
             component={ChipPage}
             name="Chip"
@@ -216,6 +224,10 @@ const ComponentsNav = () => {
             component={MarkdownViewerPage}
             name="MarkdownViewer"
         />
+        <ComponentsStack.Screen
+            component={MarkdownEditorPage}
+            name="MarkdownEditor"
+        />
         <ComponentsStack.Screen
             component={MenuPage}
             name="Menu"
@@ -284,6 +296,10 @@ const ComponentsNav = () => {
             component={SwitchPage}
             name="Switch"
         />
+        <ComponentsStack.Screen
+            component={SystemToolbarPage}
+            name="SystemToolbar"
+        />
         <ComponentsStack.Screen
             component={TextPage}
             name="Text"
@@ -308,6 +324,10 @@ const ComponentsNav = () => {
             component={ToastPage}
             name="Toast"
         />
+        <ComponentsStack.Screen
+            component={TooltipPage}
+            name="Tooltip"
+        />
         <ComponentsStack.Screen
             component={WebScrollbarPage}
             name="WebScrollbar"
@@ -392,32 +412,18 @@ const RootNav = () => {
 
         NCoreUIKitEmbeddedMenu.load({
             isCollapse: currentMenuStatus === "true" ? true : false,
-            isWorkWithSafeAreaView: false,
-            siteLogoProps: {
-                isShowIcon: false,
-                title: localize("menu")
-            },
             buttons: [
                 {
-                    redirectMain: "Home",
-                    isUseLocalize: true,
-                    title: "home",
                     icon: ({
                         color
                     }) => <RenderHomeIcon
                         color={color}
-                    />
+                    />,
+                    redirectMain: "Home",
+                    isUseLocalize: true,
+                    title: "home"
                 },
                 {
-                    redirectMain: "GettingStarted",
-                    isCollapsible: true,
-                    title: "gettingStarted",
-                    isUseLocalize: true,
-                    icon: ({
-                        color
-                    }) => <RenderGettingStartedIcon
-                        color={color}
-                    />,
                     subButtons: [
                         {
                             redirectMain: "GettingStarted",
@@ -431,18 +437,18 @@ const RootNav = () => {
                             title: "implementation",
                             isUseLocalize: true
                         }
-                    ]
-                },
-                {
-                    redirectMain: "CoreFeatures",
-                    isCollapsible: true,
-                    title: "coreFeatures",
-                    isUseLocalize: true,
+                    ],
                     icon: ({
                         color
-                    }) => <RenderCoreFeaturesIcon
+                    }) => <RenderGettingStartedIcon
                         color={color}
                     />,
+                    redirectMain: "GettingStarted",
+                    title: "gettingStarted",
+                    isCollapsible: true,
+                    isUseLocalize: true
+                },
+                {
                     subButtons: [
                         {
                             redirectMain: "CoreFeatures",
@@ -457,8 +463,8 @@ const RootNav = () => {
                             isUseLocalize: true
                         },
                         {
-                            redirectMain: "CoreFeatures",
                             redirectSub: "LocaleExamples",
+                            redirectMain: "CoreFeatures",
                             title: "localeExamples",
                             isUseLocalize: true
                         },
@@ -474,18 +480,18 @@ const RootNav = () => {
                             title: "defaultJSONs",
                             isUseLocalize: true
                         }
-                    ]
-                },
-                {
-                    redirectMain: "Components",
-                    isUseLocalize: true,
-                    isCollapsible: true,
-                    title: "components",
+                    ],
                     icon: ({
                         color
-                    }) => <RenderComponentIcon
+                    }) => <RenderCoreFeaturesIcon
                         color={color}
                     />,
+                    redirectMain: "CoreFeatures",
+                    title: "coreFeatures",
+                    isCollapsible: true,
+                    isUseLocalize: true
+                },
+                {
                     subButtons: [
                         {
                             redirectMain: "Components",
@@ -498,8 +504,8 @@ const RootNav = () => {
                             title: "Button"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "HighlightButton",
+                            redirectMain: "Components",
                             title: "HighlightButton"
                         },
                         {
@@ -508,13 +514,13 @@ const RootNav = () => {
                             title: "TextInput"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "TextAreaInput",
+                            redirectMain: "Components",
                             title: "TextAreaInput"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "NumericInput",
+                            redirectMain: "Components",
                             title: "NumericInput"
                         },
                         {
@@ -543,33 +549,33 @@ const RootNav = () => {
                             title: "Switch"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "DateTimePicker",
+                            redirectMain: "Components",
                             title: "DateTimePicker"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "DateTimeSheet",
+                            redirectMain: "Components",
                             title: "DateTimeSheet"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "DateSelector",
+                            redirectMain: "Components",
                             title: "DateSelector"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "TimeSelector",
+                            redirectMain: "Components",
                             title: "TimeSelector"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "MonthSelector",
+                            redirectMain: "Components",
                             title: "MonthSelector"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "YearSelector",
+                            redirectMain: "Components",
                             title: "YearSelector"
                         },
                         {
@@ -587,6 +593,18 @@ const RootNav = () => {
                             redirectSub: "CodeViewer",
                             title: "CodeViewer"
                         },
+                        {
+                            redirectMain: "Components",
+                            redirectSub: "CodeEditor",
+                            title: "CodeEditor",
+                            isUseLocalize: true
+                        },
+                        {
+                            redirectSub: "SystemToolbar",
+                            redirectMain: "Components",
+                            title: "SystemToolbar",
+                            isUseLocalize: true
+                        },
                         {
                             redirectMain: "Components",
                             redirectSub: "Chip",
@@ -632,21 +650,31 @@ const RootNav = () => {
                             redirectSub: "Toast",
                             title: "Toast"
                         },
+                        {
+                            redirectMain: "Components",
+                            redirectSub: "Tooltip",
+                            title: "Tooltip"
+                        },
                         {
                             redirectMain: "Components",
                             redirectSub: "Loading",
                             title: "Loading"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "NotificationIndicator",
-                            title: "NotificationIndicator"
+                            title: "NotificationIndicator",
+                            redirectMain: "Components"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "MarkdownViewer",
+                            redirectMain: "Components",
                             title: "MarkdownViewer"
                         },
+                        {
+                            redirectSub: "MarkdownEditor",
+                            redirectMain: "Components",
+                            title: "MarkdownEditor"
+                        },
                         {
                             redirectMain: "Components",
                             redirectSub: "Seperator",
@@ -658,13 +686,13 @@ const RootNav = () => {
                             title: "SiteLogo"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "WebScrollbar",
+                            redirectMain: "Components",
                             title: "WebScrollbar"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "PageContainer",
+                            redirectMain: "Components",
                             title: "PageContainer"
                         },
                         {
@@ -683,28 +711,42 @@ const RootNav = () => {
                             title: "Menu"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "EmbeddedMenu",
+                            redirectMain: "Components",
                             title: "EmbeddedMenu"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "ThemeSwitcher",
+                            redirectMain: "Components",
                             title: "ThemeSwitcher"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "PaletteSwitcher",
+                            redirectMain: "Components",
                             title: "PaletteSwitcher"
                         },
                         {
-                            redirectMain: "Components",
                             redirectSub: "LocaleSwitcher",
+                            redirectMain: "Components",
                             title: "LocaleSwitcher"
                         }
-                    ]
+                    ],
+                    redirectMain: "Components",
+                    icon: ({
+                        color
+                    }) => <RenderComponentIcon
+                        color={color}
+                    />,
+                    isCollapsible: true,
+                    isUseLocalize: true,
+                    title: "components"
                 }
             ],
+            isWorkWithSafeAreaView: false,
+            siteLogoProps: {
+                title: localize("menu"),
+                isShowIcon: false
+            },
             isAutoClosed: true,
             id: "main-menu"
         });
@@ -749,21 +791,19 @@ const RootNav = () => {
     };
 
     return <MainHeader
-        isWorkWithSeperator={true}
         siteLogoProps={{
             imageUrl: activeTheme.indexOf("dark") !== -1 ? "http://ncore.nibgat.space/assets/images/darklogo.png" : "http://ncore.nibgat.space/assets/images/ncorelogo.png",
+            subTitle: "Design System - UI Kit",
             onPress: () => {
                 navigation.navigate("Home");
             },
             imageProps: {
                 resizeMode: "stretch"
             },
-            subTitle: "Design System - UI Kit",
             title: "NİBGAT® | NCore",
             isWorkWithAction: true,
             isWorkWithFlex1: true
         }}
-        isWorkWithSticky={true}
         renderRight={() => {
             return <View
                 style={[
@@ -778,6 +818,8 @@ const RootNav = () => {
                 <ThemeSwitcher/>
             </View>;
         }}
+        isWorkWithSeperator={true}
+        isWorkWithSticky={true}
         glassEffect={5}
     >
         <NCoreUIKitEmbeddedMenu.Render
@@ -814,86 +856,90 @@ const RootNav = () => {
 const Navigation = () => {
     return <NavigationContainer
         documentTitle={{
-            formatter: (options, route) => `NCore - Design System | UI Kit - ${options?.title ?? route?.name ?? "Home"}`
+            formatter: (options, route) => `${options?.title ?? route?.name ?? "Home"} || NCore - Design System | UI Kit`
         }}
         linking={{
-            prefixes: [
-                "http://localhost:3000",
-                "https://ncore.nibgat.space"
-            ],
             config: {
                 screens: {
-                    Home: "home",
-                    GettingStarted: {
-                        path: "gettingstarted",
-                        screens: {
-                            Installation: "installation",
-                            Implementation: "implementation"
-                        }
-                    },
-                    CoreFeatures: {
-                        path: "corefeatures",
-                        screens: {
-                            ToolsUsage: "toolsusage",
-                            ThemeExamples: "themeexamples",
-                            LocaleExamples: "localeexamples",
-                            TypesOverride: "typesoverride",
-                            DefaultJSONs: "defaultjsons"
-                        }
-                    },
                     Components: {
-                        path: "components",
                         screens: {
-                            Avatar: "avatar",
-                            AvatarGroup: "avatargroup",
-                            BottomSheet: "bottomsheet",
-                            Button: "button",
-                            CheckBox: "checkbox",
-                            Chip: "chip",
-                            CodeViewer: "codeviewer",
-                            DateSelector: "dateselector",
-                            DateTimePicker: "datetimepicker",
-                            DateTimeSheet: "datetimesheet",
-                            Dialog: "dialog",
-                            EmbeddedMenu: "embeddedmenu",
-                            Header: "header",
+                            NotificationIndicator: "notificationindicator",
                             HighlightButton: "highlightbutton",
-                            Loading: "loading",
+                            PaletteSwitcher: "paletteswitcher",
+                            DateTimePicker: "datetimepicker",
                             LocaleSwitcher: "localeswitcher",
-                            MainHeader: "mainheader",
+                            MarkdownEditor: "markdowneditor",
                             MarkdownViewer: "markdownviewer",
-                            Menu: "menu",
-                            Modal: "modal",
+                            DateTimeSheet: "datetimesheet",
                             MonthSelector: "monthselector",
-                            NotificationIndicator: "notificationindicator",
-                            NumericInput: "numericinput",
                             PageContainer: "pagecontainer",
-                            PaletteSwitcher: "paletteswitcher",
+                            SystemToolbar: "systemtoolber",
+                            TextAreaInput: "textareainput",
+                            ThemeSwitcher: "themeswitcher",
+                            DateSelector: "dateselector",
+                            EmbeddedMenu: "embeddedmenu",
+                            NumericInput: "numericinput",
+                            TimeSelector: "timeselector",
+                            WebScrollbar: "webscrollbar",
+                            YearSelector: "yearselector",
+                            AvatarGroup: "avatargroup",
+                            BottomSheet: "bottomsheet",
                             RadioButton: "radiobutton",
-                            RowCard: "rowcard",
-                            SelectBox: "selectbox",
                             SelectSheet: "selectsheet",
+                            CodeEditor: "codeeditor",
+                            CodeViewer: "codeviewer",
+                            MainHeader: "mainheader",
+                            SelectBox: "selectbox",
                             Seperator: "seperator",
+                            StateCard: "statecard",
+                            TextInput: "textinput",
+                            CheckBox: "checkbox",
                             SiteLogo: "sitelogo",
                             SnackBar: "snackbar",
-                            StateCard: "statecard",
+                            Loading: "loading",
+                            RowCard: "rowcard",
                             Sticker: "sticker",
+                            Tooltip: "tooltip",
+                            Avatar: "avatar",
+                            Button: "button",
+                            Dialog: "dialog",
+                            Header: "header",
                             Switch: "switch",
-                            Text: "text",
-                            TextAreaInput: "textareainput",
-                            TextInput: "textinput",
-                            ThemeSwitcher: "themeswitcher",
-                            TimeSelector: "timeselector",
+                            Modal: "modal",
                             Toast: "toast",
-                            WebScrollbar: "webscrollbar",
-                            YearSelector: "yearselector"
-                        }
-                    }
+                            Chip: "chip",
+                            Menu: "menu",
+                            Text: "text"
+                        },
+                        path: "components"
+                    },
+                    CoreFeatures: {
+                        screens: {
+                            LocaleExamples: "localeexamples",
+                            ThemeExamples: "themeexamples",
+                            TypesOverride: "typesoverride",
+                            DefaultJSONs: "defaultjsons",
+                            ToolsUsage: "toolsusage"
+                        },
+                        path: "corefeatures"
+                    },
+                    GettingStarted: {
+                        screens: {
+                            Implementation: "implementation",
+                            Installation: "installation"
+                        },
+                        path: "gettingstarted"
+                    },
+                    Home: "home"
                 }
             },
             getStateFromPath: (path, options) => {
                 return getStateFromPath(path.toLowerCase(), options);
-            }
+            },
+            prefixes: [
+                "http://localhost:3000",
+                "https://ncore.nibgat.space"
+            ]
         } as LinkingOptions<RootStackParamList>}
     >
         <RootNav/>

+ 3 - 0
example/src/navigation/type.ts

@@ -21,6 +21,7 @@ export type ComponentsStackParamList = {
     PaletteSwitcher: undefined;
     DateTimePicker: undefined;
     MarkdownViewer: undefined;
+    MarkdownEditor: undefined;
     LocaleSwitcher: undefined;
     DateTimeSheet: undefined;
     TextAreaInput: undefined;
@@ -37,6 +38,7 @@ export type ComponentsStackParamList = {
     RadioButton: undefined;
     SelectSheet: undefined;
     CodeViewer: undefined;
+    CodeEditor: undefined;
     SelectBox: undefined;
     Seperator: undefined;
     StateCard: undefined;
@@ -47,6 +49,7 @@ export type ComponentsStackParamList = {
     Loading: undefined;
     RowCard: undefined;
     Sticker: undefined;
+    Tooltip: undefined;
     Avatar: undefined;
     Button: undefined;
     Dialog: undefined;

+ 179 - 0
example/src/pages/components/codeEditor/index.tsx

@@ -0,0 +1,179 @@
+import {
+    useLayoutEffect,
+    useState
+} from "react";
+import {
+    Platform,
+    View
+} from "react-native";
+import stylesheet from "./stylesheet";
+import {
+    NCoreUIKitLocalize,
+    NCoreUIKitTheme,
+    PageContainer,
+    CodeViewer,
+    CodeEditor,
+    Header,
+    Text
+} from "ncore-ui-kit";
+import {
+    useNavigation
+} from "@react-navigation/native";
+import type RootStackParamList from "../../../navigation/type";
+import type {
+    NativeStackNavigationProp
+} from "@react-navigation/native-stack";
+import {
+    File
+} from "lucide-react-native";
+
+const CodeEditorPage = () => {
+    const {
+        spaces,
+        colors
+    } = NCoreUIKitTheme.useContext();
+
+    const {
+        localize
+    } = NCoreUIKitLocalize.useContext();
+
+    const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
+
+    useLayoutEffect(() => {
+        navigation.setOptions({
+            header: () => <Header
+                title={localize("codeEditor-title")}
+                isWrapSafeareaContext={false}
+                navigation={navigation}
+                isGoBackEnable={true}
+            />,
+            headerShown: true
+        });
+    }, []);
+
+    const [
+        code,
+        setCode
+    ] = useState<string>("const hello = \"world\";\n\nconst greet = async (name) => {\n    console.log(hello, name);\n};\n\ngreet(\"NCore\");");
+
+    return <PageContainer
+        scrollViewProps={{
+            contentContainerStyle: stylesheet.scrollContent
+        }}
+        isWorkWithHeaderSpace={false}
+        scrollViewStyle={[
+            stylesheet.container
+        ]}
+        isScrollable={true}
+    >
+        <View
+            style={[
+                stylesheet.contentContainer
+            ]}
+        >
+            <Text
+                style={stylesheet.marginContainer}
+                variant="bodyMediumSize"
+                color="mid"
+            >
+                {localize("codeEditor-desc")}
+            </Text>
+            <View
+                style={{
+                    marginBottom: spaces.spacingMd
+                }}
+            >
+                <Text
+                    style={{
+                        marginBottom: spaces.spacingSm
+                    }}
+                    variant="headlineSmallSize"
+                >
+                    {localize("usage")}
+                </Text>
+                <CodeViewer
+                    code={"import {\n    CodeEditor\n} from \"ncore-ui-kit\";\n\n<CodeEditor\n    language=\"javascript\"\n    onChangeText={setCode}\n    value={code}\n    isScrollable={true}\n    isToolbarVisible={true}\n    toolbarActions={[\n        {\n            icon: ({ color, size }) => <File color={colors.content.icon[color]} size={size} />,\n            content: () => {\n                // Return your ReactNode options here.\n            }\n        }\n    ]}\n/>"}
+                    language="tsx"
+                />
+            </View>
+            <CodeEditor
+                toolbarActions={[
+                    {
+                        actions: [
+                            {
+                                onPress: () => {
+                                    if (Platform.OS === "web") {
+                                        const input = document.createElement("input");
+
+                                        input.type = "file";
+                                        input.accept = ".js,.ts,.tsx,.json,.txt";
+
+                                        input.onchange = (e) => {
+                                            const file = (e.target as HTMLInputElement).files?.[0];
+
+                                            if (file) {
+                                                const reader = new FileReader();
+
+                                                reader.onload = (ev) => {
+                                                    setCode(ev.target?.result as string);
+                                                };
+
+                                                reader.readAsText(file);
+                                            }
+                                        };
+
+                                        input.click();
+                                    } else {
+                                        // TODO: Will be code it.
+                                    }
+                                },
+                                titleKey: "open"
+                            },
+                            {
+                                onPress: () => {
+                                    if (Platform.OS === "web") {
+                                        const blob = new Blob([
+                                            code
+                                        ], {
+                                            type: "text/plain"
+                                        });
+
+                                        const url = URL.createObjectURL(blob);
+
+                                        const a = document.createElement("a");
+                                        a.href = url;
+                                        a.download = "code.js";
+                                        a.click();
+
+                                        URL.revokeObjectURL(url);
+                                    } else {
+                                        // TODO: Will be code it.
+                                    }
+                                },
+                                titleKey: "save"
+                            }
+                        ],
+                        icon: ({
+                            color,
+                            size
+                        }) => <File
+                            color={colors.content.icon[color]}
+                            size={size}
+                        />,
+                        variant: "filled",
+                        titleKey: "file",
+                        type: "neutral",
+                        size: "medium"
+                    }
+                ]}
+                style={stylesheet.editorScrollable}
+                isToolbarVisible={true}
+                onChangeText={setCode}
+                language="javascript"
+                isScrollable={true}
+                value={code}
+            />
+        </View>
+    </PageContainer>;
+};
+export default CodeEditorPage;

+ 30 - 0
example/src/pages/components/codeEditor/stylesheet.ts

@@ -0,0 +1,30 @@
+import {
+    StyleSheet
+} from "react-native";
+
+const stylesheet = StyleSheet.create({
+    scrollContent: {
+        justifyContent: "center",
+        alignItems: "center"
+    },
+    marginContainer: {
+        marginBottom: 20
+    },
+    editorScrollable: {
+        minHeight: 350,
+        width: "100%",
+        height: 200
+    },
+    contentContainer: {
+        maxWidth: 850,
+        width: "100%"
+    },
+    editor: {
+        minHeight: 350,
+        width: "100%"
+    },
+    container: {
+        flex: 1
+    }
+});
+export default stylesheet;

+ 91 - 0
example/src/pages/components/markdownEditor/index.tsx

@@ -0,0 +1,91 @@
+import {
+    useLayoutEffect
+} from "react";
+import {
+    View
+} from "react-native";
+import stylesheet from "./stylesheet";
+import {
+    NCoreUIKitLocalize,
+    NCoreUIKitTheme,
+    MarkdownEditor,
+    PageContainer,
+    CodeViewer,
+    Header,
+    Text
+} from "ncore-ui-kit";
+import {
+    useNavigation
+} from "@react-navigation/native";
+import type RootStackParamList from "../../../navigation/type";
+import type {
+    NativeStackNavigationProp
+} from "@react-navigation/native-stack";
+
+const MarkdownEditorPage = () => {
+    const {
+        spaces
+    } = NCoreUIKitTheme.useContext();
+
+    const {
+        localize
+    } = NCoreUIKitLocalize.useContext();
+
+    const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
+
+    useLayoutEffect(() => {
+        navigation.setOptions({
+            header: () => <Header
+                title={localize("markdownEditor-title")}
+                isWrapSafeareaContext={false}
+                navigation={navigation}
+                isGoBackEnable={true}
+            />,
+            headerShown: true
+        });
+    }, []);
+
+    return <PageContainer
+        scrollViewProps={{
+            contentContainerStyle: stylesheet.scrollContent
+        }}
+        scrollViewStyle={[stylesheet.container]}
+        isWorkWithHeaderSpace={false}
+        isScrollable={true}
+    >
+        <View
+            style={[stylesheet.contentContainer]}
+        >
+            <Text
+                variant="bodyMediumSize"
+                color="mid"
+                style={stylesheet.marginContainer}
+            >
+                {localize("markdownEditor-desc")}
+            </Text>
+            <View
+                style={{
+                    marginBottom: spaces.spacingMd
+                }}
+            >
+                <Text
+                    variant="headlineSmallSize"
+                    style={{
+                        marginBottom: spaces.spacingSm
+                    }}
+                >
+                    {localize("usage") || "Usage"}
+                </Text>
+                <CodeViewer
+                    code={"import {\n    MarkdownEditor\n} from \"ncore-ui-kit\";\n\n<MarkdownEditor\n    initialValue=\"# Hello\"\n/>"}
+                    language="tsx"
+                />
+            </View>
+            <MarkdownEditor
+                initialValue="# Markdown Editor\n\nThis is a **MarkdownEditor** component from *NCore UI Kit*.\n\n- Write your markdown here."
+                style={stylesheet.editor}
+            />
+        </View>
+    </PageContainer>;
+};
+export default MarkdownEditorPage;

+ 27 - 0
example/src/pages/components/markdownEditor/stylesheet.ts

@@ -0,0 +1,27 @@
+import {
+    StyleSheet
+} from "react-native";
+
+const stylesheet = StyleSheet.create({
+    scrollContent: {
+        justifyContent: "center",
+        alignItems: "center"
+    },
+    contentContainer: {
+        maxWidth: 850,
+        width: "100%"
+    },
+    paddedMarginContainer: {
+        minHeight: 120
+    },
+    marginContainer: {
+        marginBottom: 20
+    },
+    editor: {
+        minHeight: 350
+    },
+    container: {
+        flex: 1
+    }
+});
+export default stylesheet;

+ 175 - 0
example/src/pages/components/systemToolbar/index.tsx

@@ -0,0 +1,175 @@
+import {
+    useLayoutEffect
+} from "react";
+import {
+    View
+} from "react-native";
+import stylesheet from "./stylesheet";
+import {
+    NCoreUIKitLocalize,
+    NCoreUIKitTheme,
+    SystemToolbar,
+    PageContainer,
+    CodeViewer,
+    Header,
+    Text
+} from "ncore-ui-kit";
+import {
+    useNavigation
+} from "@react-navigation/native";
+import type RootStackParamList from "../../../navigation/type";
+import type {
+    NativeStackNavigationProp
+} from "@react-navigation/native-stack";
+import {
+    SettingsIcon,
+    LogOutIcon,
+    UserIcon,
+    MenuIcon,
+    HomeIcon
+} from "lucide-react-native";
+
+const SystemToolbarPage = () => {
+    const {
+        radiuses,
+        borders,
+        spaces,
+        colors
+    } = NCoreUIKitTheme.useContext();
+
+    const {
+        localize
+    } = NCoreUIKitLocalize.useContext();
+
+    const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
+
+    useLayoutEffect(() => {
+        navigation.setOptions({
+            header: () => <Header
+                title={localize("systemToolbar-title")}
+                isWrapSafeareaContext={false}
+                navigation={navigation}
+                isGoBackEnable={true}
+            />,
+            headerShown: true
+        });
+    }, [
+        navigation,
+        localize
+    ]);
+
+    return <PageContainer
+        scrollViewProps={{
+            contentContainerStyle: stylesheet.scrollContent
+        }}
+        isWorkWithHeaderSpace={false}
+        scrollViewStyle={[
+            stylesheet.container
+        ]}
+        isScrollable={true}
+    >
+        <View
+            style={[
+                stylesheet.contentContainer
+            ]}
+        >
+            <Text
+                style={stylesheet.marginContainer}
+                variant="bodyMediumSize"
+                color="mid"
+            >
+                {localize("systemToolbar-desc")}
+            </Text>
+            <View
+                style={[
+                    stylesheet.previewContainer,
+                    {
+                        borderColor: colors.content.border.subtle,
+                        marginBottom: spaces.spacingMd,
+                        borderRadius: radiuses.form,
+                        borderWidth: borders.line,
+                        padding: spaces.spacingMd
+                    }
+                ]}
+            >
+                <SystemToolbar
+                    actions={[
+                        {
+                            onPress: () => console.log("Settings pressed"),
+                            icon: ({
+                                color,
+                                size
+                            }) => <SettingsIcon
+                                color={colors.content.icon[color]}
+                                size={size}
+                            />,
+                            titleKey: "menu-settings"
+                        },
+                        {
+                            content: [
+                                {
+                                    icon: ({
+                                        color,
+                                        size
+                                    }) => <HomeIcon
+                                        color={colors.content.icon[color]}
+                                        size={size}
+                                    />,
+                                    onPress: () => console.log("Home"),
+                                    titleKey: "menu-home"
+                                },
+                                {
+                                    icon: ({
+                                        color,
+                                        size
+                                    }) => <LogOutIcon
+                                        color={colors.content.icon[color]}
+                                        size={size}
+                                    />,
+                                    onPress: () => console.log("Logout"),
+                                    titleKey: "close"
+                                }
+                            ],
+                            icon: ({
+                                color,
+                                size
+                            }) => <UserIcon
+                                color={colors.content.icon[color]}
+                                size={size}
+                            />,
+                            titleKey: "avatar-title"
+                        }
+                    ]}
+                    icon={({
+                        color,
+                        size
+                    }) => <MenuIcon
+                        color={colors.content.icon[color]}
+                        size={size}
+                    />}
+                    titleKey="menu-title"
+                />
+            </View>
+            <View
+                style={{
+                    marginBottom: spaces.spacingMd
+                }}
+            >
+                <Text
+                    style={{
+                        marginBottom: spaces.spacingSm
+                    }}
+                    variant="headlineSmallSize"
+                >
+                    {localize("usage")}
+                </Text>
+                <CodeViewer
+                    code={"import {\n    SystemToolbar\n} from \"ncore-ui-kit\";\nimport {\n    Settings,\n    User,\n    LogOut,\n    Menu,\n    Home\n} from \"lucide-react-native\";\n\n<SystemToolbar\n    titleKey=\"menu\"\n    icon={({ color, size }) => <Menu color={colors.content.icon[color]} size={size} />}\n    actions={[\n        {\n            titleKey: \"menu-settings\",\n            icon: ({ color, size }) => <Settings color={colors.content.icon[color]} size={size} />,\n            onPress: () => console.log(\"Settings pressed\")\n        }\n    ]}\n/>"}
+                    language="tsx"
+                />
+            </View>
+        </View>
+    </PageContainer>;
+};
+
+export default SystemToolbarPage;

+ 25 - 0
example/src/pages/components/systemToolbar/stylesheet.ts

@@ -0,0 +1,25 @@
+import {
+    StyleSheet
+} from "react-native";
+
+const stylesheet = StyleSheet.create({
+    previewContainer: {
+        justifyContent: "center",
+        alignItems: "center",
+        minHeight: 120,
+        zIndex: 99
+    },
+    marginContainer: {
+        marginBottom: 20
+    },
+    contentContainer: {
+        flex: 1
+    },
+    scrollContent: {
+        flexGrow: 1
+    },
+    container: {
+        flex: 1
+    }
+});
+export default stylesheet;

+ 0 - 1
example/src/pages/components/timeSelector/index.tsx

@@ -79,7 +79,6 @@ const TimeSelectorPage = () => {
             >
                 {localize("components-timeSelector")}
             </Text>
-
             <TimeSelector
                 setIsSheetContentReady={setIsSheetContentReady}
                 selectMultipleObject={() => {}}

+ 243 - 0
example/src/pages/components/tooltip/index.tsx

@@ -0,0 +1,243 @@
+import {
+    useLayoutEffect,
+    useState
+} from "react";
+import {
+    View
+} from "react-native";
+import stylesheet from "./stylesheet";
+import {
+    NCoreUIKitLocalize,
+    NCoreUIKitTheme,
+    PageContainer,
+    CodeViewer,
+    SelectBox,
+    Tooltip,
+    Header,
+    Button,
+    Text
+} from "ncore-ui-kit";
+import {
+    useNavigation
+} from "@react-navigation/native";
+import type RootStackParamList from "../../../navigation/type";
+import type {
+    NativeStackNavigationProp
+} from "@react-navigation/native-stack";
+import type {
+    TooltipLocation,
+    ITooltipProps
+} from "ncore-ui-kit";
+
+const TOOLTIP_TYPES: Array<ITooltipProps["type"]> = [
+    "neutral",
+    "primary",
+    "danger",
+    "warning",
+    "success",
+    "info"
+];
+
+const TOOLTIP_TYPES_DATA = TOOLTIP_TYPES.map(item => ({
+    __title: item as string,
+    __key: item as string
+}));
+
+const TOOLTIP_LOCATIONS: Array<TooltipLocation> = [
+    {
+        horizontal: "center",
+        vertical: "top"
+    },
+    {
+        horizontal: "center",
+        vertical: "bottom"
+    },
+    {
+        horizontal: "left",
+        vertical: "center"
+    },
+    {
+        horizontal: "right",
+        vertical: "center"
+    }
+];
+
+const TOOLTIP_LOCATIONS_DATA = [
+    {
+        __title: "Top",
+        __key: "0"
+    },
+    {
+        __title: "Bottom",
+        __key: "1"
+    },
+    {
+        __title: "Left",
+        __key: "2"
+    },
+    {
+        __title: "Right",
+        __key: "3"
+    }
+];
+
+const TooltipPage = () => {
+    const {
+        radiuses,
+        borders,
+        colors,
+        spaces
+    } = NCoreUIKitTheme.useContext();
+
+    const {
+        localize
+    } = NCoreUIKitLocalize.useContext();
+
+    const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
+
+    const [
+        typeIndex,
+        setTypeIndex
+    ] = useState<number>(0);
+
+    const [
+        locationIndex,
+        setLocationIndex
+    ] = useState<number>(0);
+
+    useLayoutEffect(() => {
+        navigation.setOptions({
+            header: () => <Header
+                isWrapSafeareaContext={false}
+                title={localize("tooltip")}
+                navigation={navigation}
+                isGoBackEnable={true}
+            />,
+            headerShown: true
+        });
+    }, []);
+
+    return <PageContainer
+        scrollViewProps={{
+            contentContainerStyle: stylesheet.scrollContent
+        }}
+        scrollViewStyle={[
+            stylesheet.container
+        ]}
+        isWorkWithHeaderSpace={false}
+        isScrollable={true}
+    >
+        <View
+            style={[
+                stylesheet.contentContainer
+            ]}
+        >
+            <Text
+                style={stylesheet.descText}
+                variant="bodyMediumSize"
+                color="mid"
+            >
+                {localize("tooltip-desc")}
+            </Text>
+            <View
+                style={[
+                    stylesheet.previewContainer,
+                    {
+                        borderColor: colors.content.border.subtle,
+                        marginBottom: spaces.spacingMd,
+                        borderRadius: radiuses.form,
+                        borderWidth: borders.line,
+                        padding: spaces.spacingMd,
+                        paddingVertical: spaces.spacingLg
+                    }
+                ]}
+            >
+                <Tooltip
+                    subTitle={localize("example-tooltip-subtitle")}
+                    location={TOOLTIP_LOCATIONS[locationIndex]}
+                    title={localize("example-tooltip-title")}
+                    type={TOOLTIP_TYPES[typeIndex]}
+                >
+                    <Button
+                        title={localize("hover-or-press-me")}
+                        onPress={() => {}}
+                    />
+                </Tooltip>
+            </View>
+            <View
+                style={{
+                    marginBottom: spaces.spacingMd
+                }}
+            >
+                <Text
+                    style={{
+                        marginBottom: spaces.spacingSm
+                    }}
+                    variant="headlineSmallSize"
+                >
+                    {localize("usage")}
+                </Text>
+                <CodeViewer
+                    code={"import {\n    Tooltip,\n    Button\n} from \"ncore-ui-kit\";\n\n<Tooltip\n    location={{\n        horizontal: \"center\",\n        vertical: \"top\"\n    }}\n    title=\"Tooltip Title\"\n    subTitle=\"Tooltip Subtitle\"\n    type=\"primary\"\n>\n    <Button\n        title=\"Hover Me\"\n        onPress={() => {}}\n    />\n</Tooltip>"}
+                    language="tsx"
+                />
+            </View>
+            <View
+                style={[
+                    stylesheet.rowContainer,
+                    {
+                        gap: spaces.spacingMd
+                    }
+                ]}
+            >
+                <SelectBox
+                    onChange={(selectedItems) => {
+                        if (selectedItems.length > 0) {
+                            const index = TOOLTIP_TYPES.indexOf(selectedItems[0]!.__key as ITooltipProps["type"]);
+                            if (index !== -1) setTypeIndex(index);
+                        }
+                    }}
+                    initialSelectedItems={
+                        TOOLTIP_TYPES_DATA[typeIndex]
+                            ? [
+                                TOOLTIP_TYPES_DATA[typeIndex]!
+                            ]
+                            : []
+                    }
+                    titleExtractor={(item) => item.__title}
+                    keyExtractor={(item) => item.__key}
+                    title={localize("change-type")}
+                    data={TOOLTIP_TYPES_DATA}
+                    spreadBehaviour="free"
+                />
+                <SelectBox
+                    initialSelectedItems={
+                        TOOLTIP_LOCATIONS_DATA[locationIndex]
+                            ? [
+                                {
+                                    ...TOOLTIP_LOCATIONS_DATA[locationIndex]!,
+                                    __title: localize(TOOLTIP_LOCATIONS_DATA[locationIndex]!.__title.toLowerCase() as keyof NCoreUIKit.Translation)
+                                }
+                            ]
+                            : []
+                    }
+                    onChange={(selectedItems) => {
+                        if (selectedItems.length > 0) {
+                            const index = parseInt(selectedItems[0]!.__key);
+                            if (!isNaN(index)) setLocationIndex(index);
+                        }
+                    }}
+                    data={TOOLTIP_LOCATIONS_DATA.map(item => ({
+                        ...item,
+                        __title: localize(item.__title.toLowerCase() as keyof NCoreUIKit.Translation)
+                    }))}
+                    titleExtractor={(item) => item.__title}
+                    title={localize("change-location")}
+                    keyExtractor={(item) => item.__key}
+                    spreadBehaviour="free"
+                />
+            </View>
+        </View>
+    </PageContainer>;
+};
+export default TooltipPage;

+ 33 - 0
example/src/pages/components/tooltip/stylesheet.ts

@@ -0,0 +1,33 @@
+import {
+    StyleSheet
+} from "react-native";
+
+const stylesheet = StyleSheet.create({
+    rowContainer: {
+        justifyContent: "space-between",
+        alignItems: "center",
+        flexDirection: "row",
+        flexWrap: "wrap",
+        width: "100%"
+    },
+    previewContainer: {
+        justifyContent: "center",
+        alignItems: "center",
+        minHeight: 120
+    },
+    scrollContent: {
+        justifyContent: "center",
+        alignItems: "center"
+    },
+    contentContainer: {
+        width: "100%",
+        maxWidth: 850
+    },
+    descText: {
+        marginBottom: 20
+    },
+    container: {
+        flex: 1
+    }
+});
+export default stylesheet;

+ 0 - 3
example/src/pages/coreFeatures/defaultJSONs/index.tsx

@@ -93,7 +93,6 @@ const DefaultJSONs = () => {
         >
             {localize("defaultJSONs-desc")}
         </Text>
-
         <Text
             variant="titleMediumSize"
             color="high"
@@ -121,7 +120,6 @@ const DefaultJSONs = () => {
                 language="json"
             />
         </View>
-
         <Text
             variant="titleMediumSize"
             color="high"
@@ -150,7 +148,6 @@ const DefaultJSONs = () => {
                 language="json"
             />
         </View>
-
         <View
             style={[
                 stylesheet.rowSpaceBetween,

+ 0 - 5
example/src/pages/coreFeatures/localeExamples/index.tsx

@@ -89,7 +89,6 @@ const LocaleExamples = () => {
         >
             <LocaleSwitcher/>
         </View>
-
         <View
             style={[
                 stylesheet.borderedCard,
@@ -109,7 +108,6 @@ const LocaleExamples = () => {
             >
                 {localize("localeExamples-localizedTexts")}
             </Text>
-
             <Text
                 color="mid"
                 style={{
@@ -123,7 +121,6 @@ const LocaleExamples = () => {
                     {activeLocale}
                 </Text>
             </Text>
-
             <View
                 style={[
                     stylesheet.borderedCard2,
@@ -178,7 +175,6 @@ const LocaleExamples = () => {
                 </View>
             </View>
         </View>
-
         <View
             style={[
                 stylesheet.rowSpaceBetween,
@@ -204,7 +200,6 @@ const LocaleExamples = () => {
                 }}
                 title={localize("themeExamples-title")}
             />
-
             <Button
                 icon={({
                     color,

+ 0 - 5
example/src/pages/coreFeatures/toolsUsage/index.tsx

@@ -139,7 +139,6 @@ const MyComponent = () => {
         >
             {localize("toolsUsage-desc")}
         </Text>
-
         <Text
             variant="titleMediumSize"
             color="high"
@@ -167,7 +166,6 @@ const MyComponent = () => {
                 language="tsx"
             />
         </View>
-
         <Text
             variant="titleMediumSize"
             color="high"
@@ -195,7 +193,6 @@ const MyComponent = () => {
                 language="tsx"
             />
         </View>
-
         <Text
             variant="titleMediumSize"
             color="high"
@@ -223,7 +220,6 @@ const MyComponent = () => {
                 language="tsx"
             />
         </View>
-
         <View
             style={[
                 stylesheet.rowSpaceBetween,
@@ -249,7 +245,6 @@ const MyComponent = () => {
                     });
                 }}
             />
-
             <Button
                 icon={({
                     color,

+ 0 - 4
example/src/pages/coreFeatures/typesOverride/index.tsx

@@ -118,7 +118,6 @@ const TypesOverride = () => {
         >
             {localize("typesOverride-desc")}
         </Text>
-
         <Text
             variant="titleMediumSize"
             color="high"
@@ -146,7 +145,6 @@ const TypesOverride = () => {
                 language="tsx"
             />
         </View>
-
         <Text
             variant="titleMediumSize"
             color="high"
@@ -174,7 +172,6 @@ const TypesOverride = () => {
                 language="json"
             />
         </View>
-
         <View
             style={[
                 stylesheet.rowSpaceBetween,
@@ -200,7 +197,6 @@ const TypesOverride = () => {
                     });
                 }}
             />
-
             <Button
                 icon={({
                     color,

+ 116 - 18
example/src/variants/locales/default.json

@@ -5,16 +5,21 @@
             "typesOverride-globalDtsDesc": "TypeScript projelerinde NCore UI Kit kütüphanesini kullanırken, temanızdaki veya dil dosyanızdaki özel anahtarları TypeScript'e tanıtmak için global.d.ts kullanmanız gerekir.",
             "toolsUsage-ncoreThemeDesc": "Tema değerlerine dinamik olarak erişim sağlar, prop drilling gerektirmez. Renkleri ve boşlukları global olarak kullanabilirsiniz.",
             "installation-peerDepsDesc": "Aşağıdaki paketlerin projenizde kurulu olması gereklidir. Geliştirme ortamınıza uygun olan komut ile (yarn/npm) kurabilirsiniz.",
+            "defaultJSONs-desc": "Projenizde NCore UI Kit'i başlatırken kendi temanızı ve dil dosyanızı nasıl tanımlayacağınızı gösteren örnek yapı taşları.",
             "pageContainer-desc": "Sayfa içeriklerini sararak tema boşluklarına, güvenli alanlara ve kaydırma yapılarına uygun hale getiren temel bileşen.",
             "typesOverride-tsconfigDesc": "Projenizin tsconfig.json dosyasında global.d.ts dosyanızı typeRoots veya include içerisine eklemeyi unutmayın.",
             "stateCard-desc": "Boş durum, hata durumu veya başarılı işlem gibi uygulama anlarını kullanıcıya gösteren bilgilendirici kart bileşeni.",
             "toolsUsage-ncoreToastDesc": "Kullanıcıyı bir işlemin sonucu hakkında bilgilendirmek için interaktif toast mesajları göstermeyi sağlar.",
+            "defaultJSONs-themeDesc": "Uygulamanızın renk paletlerini, tipografisini ve boşluk değerlerini belirleyen tema konfigürasyonu örneği.",
             "installation-desc": "NCore UI Kit kurulumu, temel kullanımı ve geliştirme ortamınıza nasıl entegre edeceğiniz hakkında bilgiler.",
             "typesOverride-desc": "Kendi projelerinizde NCore UI Kit tiplerini (tema, dil vb.) global.d.ts ile nasıl ezebileceğinizin örneği.",
+            "tooltip-desc": "Bir bileşenin üzerine gelindiğinde veya basılı tutulduğunda ekstra bilgi sağlayan küçük bir bilgi kutucuğudur.",
             "webScrollbar-desc": "Web platformlarında tarayıcının varsayılan kaydırma çubuğunu özel temalı bir çubukla değiştiren bileşen.",
+            "defaultJSONs-localeDesc": "Uygulamanızın desteklediği dilleri ve çevirileri barındıran yerelleştirme konfigürasyonu örneği.",
             "markdownViewer-desc": "Markdown formatındaki zengin metinleri ayrıştırıp biçimlendirilmiş olarak gösteren içerik bileşeni.",
             "implementation-desc": "Projelerinizde NCore UI Kit'i kurduktan sonra en dış katmandan nasıl uygulayacağınıza dair örnek.",
             "modal-desc": "Mevcut sayfanın üzerine binen ve kullanıcıyı belirli bir göreve odaklayan kalıcı (modal) pencere bileşeni.",
+            "systemToolbar-desc": "Kullanıcıya iç içe menüler ve çeşitli aksiyonları kompakt bir şekilde sunan araç çubuğu bileşeni.",
             "notificationIndicator-desc": "Okunmamış bildirim veya mesaj sayılarını görsel olarak belirten ufak belirteç bileşeni.",
             "paletteSwitcher-desc": "Kullanıcının uygulamanın renk paletini ve görünümünü özelleştirmesine olanak tanıyan bileşen.",
             "selectSheet-desc": "Ekranın altından açılarak bir liste içerisinden pratik seçim yapılmasını sağlayan sayfa bileşeni.",
@@ -31,22 +36,27 @@
             "header-desc": "Sayfaların en üstünde yer alan, başlık ve navigasyon eylemlerini barındıran üst alan bileşeni.",
             "loading-desc": "Arka planda devam eden asenkron bir işlemin veya veri yüklemesinin durumunu gösteren bileşen.",
             "chip-desc": "Küçük bilgi parçalarını, etiketleri veya durumları göstermek için kullanılan kompakt bileşen.",
+            "markdownEditor-desc": "Markdown formatındaki zengin metinleri düzenlemek için kullanılan içerik bileşeni.",
             "snackBar-desc": "Ekranın alt kısmında geçici olarak beliren ve kısa durum mesajları sunan uyarı bileşeni.",
             "toolsUsage-codeViewerDesc": "Kodu uygulamanızda güzel bir şekilde render etmek ve panoya kopyalamak için.",
             "checkBox-desc": "Birden fazla seçenek arasından bağımsız seçimler yapmayı sağlayan onay kutusu bileşeni.",
             "embeddedMenu-desc": "Sayfa içine gömülü (inline) olarak çalışan ve bağlamsal menü öğeleri sunan bileşen.",
             "numericInput-desc": "Sadece sayısal verilerin veya miktarların girilmesini sağlayan özel girdi bileşeni.",
+            "selected-end-time-cannot-before-from-start-time": "Seçilen bitiş saati, başlangıç saatinden önce olamaz.",
+            "selected-start-time-cannot-after-then-end-time": "Seçilen başlangıç saati, bitiş saatinden sonra olamaz.",
             "seperator-desc": "Bileşenler veya içerikler arasında görsel bir ayrım çizgisi oluşturan boşluk bileşeni.",
             "textInput-desc": "Kullanıcıdan kısa metin veya veri girmesini talep eden standart form girdi bileşeni.",
             "monthSelector-desc": "Bir yıl içerisinden belirli bir ayı veya ayları seçmek için kullanılan bileşen.",
             "sticker-desc": "Eğlenceli görseller veya ikonlar eklemek için kullanılan dinamik yapıştırma bileşeni.",
             "toast-desc": "Ekranın üst kısmında anlık olarak belirip kaybolan sistem mesajlarını gösteren bileşen.",
+            "codeEditor-desc": "Yazılım geliştiriciler için syntax highlighting özellikli kod düzenleme bileşeni.",
             "timeSelector-desc": "Belirli bir zamanı (saat, dakika) seçmek için optimize edilmiş arayüz bileşeni.",
             "rowCard-desc": "Bilgileri veya görselleri yatay bir satır düzeni içinde sunan bilgi kartı bileşeni.",
             "selectBox-desc": "Açılır liste içerisinden tekil veya çoklu seçim yapmayı sağlayan seçici bileşeni.",
             "themeExamples-desc": "Farklı tema, palet ve tipografi kullanımları ve canlı olarak değiştirilmesi.",
             "highlightButton-desc": "Önemli eylemleri vurgulamak için kullanılan dikkat çekici buton bileşeni.",
             "bottomSheet-desc": "Ekranın altından açılan ve ek içerikler sunan kaydırılabilir panel bileşeni.",
+            "minimum-selection-number-of-days-required-not-provided": "Gerekli minimum gün seçimi sağlanmadı.",
             "button-desc": "Kullanıcı etkileşimlerini tetiklemek için kullanılan temel tıklanabilir bileşen.",
             "toolsUsage-codeThemeComment": "Mevcut tema renklerine, boşluklarına ve aktif tercihlere erişin",
             "localeExamples-desc": "Diller arası geçiş ve localize fonksiyonu ile dinamik metin kullanımı.",
@@ -57,16 +67,25 @@
             "toolsUsage-desc": "NCore UI Kit hook'ları olan useTheme, useLocale ve useToast kullanımı.",
             "siteLogo-desc": "Markayı veya uygulamayı temsil eden ana logo görselini işleyen bileşen.",
             "codeViewer-desc": "Kod bloklarını görüntülemek ve kopyalamak için kullanılan bileşen.",
+            "maximum-selection-number-of-days-limit-exceeds": "Maksimum gün seçim sınırı aşıldı.",
             "avatarGroup-desc": "Birden fazla avatarı bir arada gruplayarak gösteren bileşen.",
             "avatar-desc": "Kullanıcı veya varlıkları temsil eden profil görseli bileşeni.",
+            "maximum-selection-limit-has-been-reached": "Maksimum seçim limitine ulaşıldı.",
             "toolsUsage-codeLocaleComment": "Mevcut çevirilere ve aktif dile erişin",
+            "code-copy-error-to-clipboard": "Kod panoya kopyalanırken hata oluştu.",
+            "minimum-a-item-selection-required": "En az bir öğe seçimi zorunludur.",
+            "start-date-select-is-required": "Başlangıç tarihi seçimi zorunludur.",
+            "code-copy-success-to-clipboard": "Kod başarıyla panoya kopyalandı.",
             "markdownViewer-title": "Markdown Görüntüleyici (Markdown Viewer)",
             "typesOverride-tsconfigIntegration": "tsconfig.json Entegrasyonu",
+            "end-date-select-is-required": "Bitiş tarihi seçimi zorunludur.",
+            "markdownEditor-title": "Markdown Düzenleyici (Markdown Editor)",
             "bottomSheet-toggleSwipeClose": "Kaydırarak Kapatmayı Aç/Kapat",
             "highlightButton-toggleCustomPadding": "Özel Boşluğu Aç/Kapat",
             "notificationIndicator-toggleShowCount": "Sayıyı Göster/Gizle",
             "themeExamples-headlineLarge": "Büyük Başlık (Headline Large)",
             "localeExamples-localizedTexts": "Yerelleştirilmiş Metinler",
+            "systemToolbar-title": "Sistem Araç Çubuğu (System Toolbar)",
             "themeExamples-titleLarge": "Büyük Alt Başlık (Title Large)",
             "dateTimePicker-changePickerType": "Seçici Türünü Değiştir",
             "themeExamples-displayLarge": "Büyük Ekran (Display Large)",
@@ -105,6 +124,7 @@
             "avatarGroup-toggleLoading": "Yükleniyoru Aç/Kapat",
             "bottomSheet-toggleShowHandle": "Tutamacı Aç/Kapat",
             "checkBox-toggleFlip": "Tersine Çevirmeyi Aç/Kapat",
+            "codeEditor-title": "Kod Düzenleyici (Code Editor)",
             "dateTimePicker-changeVariant": "Varyantı Değiştir",
             "highlightButton-changeSpread": "Yayılımı Değiştir",
             "notificationIndicator-changeType": "Türü Değiştir",
@@ -120,6 +140,7 @@
             "textAreaInput-placeholder": "Bir şeyler yazın...",
             "webScrollbar-item": "Kaydırılabilir İçerik Öğesi",
             "components-paletteSwitcher": "Palet Değiştirici",
+            "defaultJSONs-title": "Varsayılan JSON Dosyaları",
             "dialog-enterContentText": "İçerik Metnini Girin",
             "numericInput-changeVariant": "Varyantı Değiştir",
             "rowCard-toggleDisabled": "Devre Dışıyı Aç/Kapat",
@@ -158,6 +179,8 @@
             "components-localeSwitcher": "Dil Değiştirici",
             "components-pageContainer": "Sayfa Konteyneri",
             "components-themeSwitcher": "Tema Değiştirici",
+            "components-tooltip": "Bilgi Balonu (Tooltip)",
+            "example-tooltip-subtitle": "Örnek Alt Başlık",
             "highlightButton-toggleIcon": "İkonu Aç/Kapat",
             "rowCard-toggleLeftIcon": "Sol İkonu Aç/Kapat",
             "switch-changeIconDir": "İkon Yönünü Değiştir",
@@ -181,6 +204,7 @@
             "numericInput-exampleTitle": "Sayısal Değer",
             "numericInput-placeholder": "Bir sayı girin",
             "rowCard-exampleSubTitle": "Kart Alt Başlık",
+            "select-an-option": "Bir seçenek belirleyin",
             "siteLogo-enterSubTitle": "Alt Başlık Girin",
             "toolsUsage-codeViewer": "Kod Görüntüleyici",
             "typesOverride-globalTypes": "Global Tipler",
@@ -190,6 +214,7 @@
             "dialog-changeVariant": "Varyantı Değiştir",
             "dialog-openDialog": "İletişim Kutusunu Aç",
             "enter-image-url": "Resim Bağlantısı Girin",
+            "hover-or-press-me": "Üzerime Gel veya Bas",
             "installation-installationTitle": "Kurulum",
             "numericInput-toggleIcon": "İkonu Aç/Kapat",
             "rowCard-enterSubTitle": "Alt Başlık Girin",
@@ -237,6 +262,7 @@
             "components-monthSelector": "Ay Seçici",
             "components-yearSelector": "Yıl Seçici",
             "date-time-picker": "Tarih Saat Seçici",
+            "example-tooltip-title": "Örnek Başlık",
             "loading-changeSize": "Boyutu Değiştir",
             "loading-title": "Yükleniyor (Loading)",
             "localeExamples-title": "Dil Örnekleri",
@@ -270,15 +296,19 @@
             "webScrollbar-title": "Web Scrollbar",
             "change-spread": "Yayılımı Değiştir",
             "chip-changeSize": "Boyutu Değiştir",
+            "defaultJSONs": "Varsayılan JSONlar",
             "open-bottom-sheet": "Alt Paneli Aç",
             "rowCard-enterTitle": "Başlık Girin",
+            "select-any-date": "Bir tarih seçin",
             "stateCard-exampleValue": "$ 12,000",
             "sticker-enterTitle": "Başlık Girin",
             "switch-subTitleLabel": "Alt Başlık",
             "textAreaInput-title": "Metin Alanı",
             "textAreaInput-titleLabel": "Başlık",
             "avatarGroup-title": "Avatar Grubu",
+            "change-location": "Konum Değiştir",
             "checkBox-enterText": "Metin Girin",
+            "clean-selection": "Seçimi Temizle",
             "enter-sub-text": "Alt Metin Girin",
             "numericInput-titleLabel": "Başlık",
             "radioButton-title": "Radyo Butonu",
@@ -287,6 +317,7 @@
             "themeExamples-primary": "Birincil",
             "themeExamples-success": "Başarılı",
             "toggle-portal": "Portalı Aç/Kapat",
+            "change-language": "Dili Değiştir",
             "change-status": "Durumu Değiştir",
             "chip-changeType": "Türü Değiştir",
             "coreFeatures": "Temel Özellikler",
@@ -294,8 +325,8 @@
             "radioButton-titleLabel": "Başlık",
             "selectBox-placeholder": "Seçiniz",
             "switch-title": "Anahtar (Switch)",
-            "change-language": "Dili Değiştir",
             "avatar-enterText": "Metin Girin",
+            "codeViewer": "Kod Görüntüleyici",
             "dialog-enterText": "Metin Girin",
             "dialog-title": "İletişim Kutusu",
             "installation-title": "Başlarken",
@@ -307,7 +338,6 @@
             "themeExamples-danger": "Tehlike",
             "toolsUsage": "Araç Kullanımları",
             "typesOverride": "Tip Değiştirme",
-            "codeViewer": "Kod Görüntüleyici",
             "bottomSheet-title": "Alt Panel",
             "change-size": "Boyutu Değiştir",
             "menu-openMenu": "Menu OpenMenu",
@@ -325,6 +355,7 @@
             "image-url": "Resim Bağlantısı",
             "seperator-titleLabel": "Metin",
             "siteLogo-titleLabel": "Başlık",
+            "start-time": "Başlangıç Saati",
             "stateCard-valueLabel": "Değer",
             "toggle-icon": "İkonu Aç/Kapat",
             "avatar-group": "Avatar Grubu",
@@ -336,8 +367,10 @@
             "sticker-exampleTitle": "Yeni",
             "sticker-titleLabel": "Başlık",
             "avatar-titleLabel": "Başlık",
+            "clean-all": "Tümünü Temizle",
             "dialog-titleLabel": "Başlık",
             "gettingStarted": "Başlarken",
+            "is-optional": "İsteğe Bağlı",
             "switch-titleLabel": "Başlık",
             "themeExamples-info": "Bilgi",
             "bottomSheet-close": "Kapat",
@@ -346,33 +379,49 @@
             "chip-titleLabel": "Başlık",
             "dialog": "İletişim Kutusu",
             "enter-text": "Metin Girin",
+            "go-to-today": "Bugüne Git",
             "check-box": "Onay Kutusu",
-            "menu-title": "Menu Title",
+            "components": "Bileşenler",
             "enter-code": "Kodu Girin",
+            "menu-title": "Menu Title",
+            "select-all": "Tümünü Seç",
+            "end-time": "Bitiş Saati",
             "installation": "Kurulum",
             "sub-title": "Alt Başlık",
             "avatar-title": "Avatar",
+            "codeViewer-code": "Kod",
             "menu-home": "Menu Home",
             "text": "Text ( Metin )",
-            "codeViewer-code": "Kod",
+            "preview": "Önizleme",
             "chip-title": "Çip",
             "content": "İçerik",
             "home": "Ana Sayfa",
             "usage": "Kullanım",
             "avatar": "Avatar",
             "button": "Button",
+            "monthly": "Aylık",
+            "tooltip": "İpucu",
             "version": "Sürüm",
+            "yearly": "Yıllık",
+            "cancel": "İptal",
+            "daily": "Günlük",
             "next": "Sonraki",
             "title": "Başlık",
             "close": "Kapat",
+            "save": "Kaydet",
+            "bottom": "Alt",
+            "file": "Dosya",
+            "live": "Canlı",
+            "search": "Ara",
+            "menu": "Menü",
             "right": "Sağ",
+            "write": "Yaz",
             "chip": "Çip",
             "left": "Sol",
-            "defaultJSONs-title": "Varsayılan JSON Dosyaları",
-            "defaultJSONs-desc": "Projenizde NCore UI Kit'i başlatırken kendi temanızı ve dil dosyanızı nasıl tanımlayacağınızı gösteren örnek yapı taşları.",
-            "defaultJSONs-themeDesc": "Uygulamanızın renk paletlerini, tipografisini ve boşluk değerlerini belirleyen tema konfigürasyonu örneği.",
-            "defaultJSONs-localeDesc": "Uygulamanızın desteklediği dilleri ve çevirileri barındıran yerelleştirme konfigürasyonu örneği.",
-            "defaultJSONs": "Varsayılan JSONlar"
+            "ok": "Tamam",
+            "open": "Aç",
+            "or": "Veya",
+            "top": "Üst"
         },
         "locale": "tr-TR",
         "isRTL": false
@@ -383,6 +432,9 @@
             "installation-peerDepsDesc": "The following packages must be installed in your project. You can install them using the appropriate command (yarn/npm) for your development environment.",
             "toolsUsage-ncoreThemeDesc": "Provides access to theme values dynamically without needing prop drilling. You can consume colors, spaces, radiuses globally.",
             "typesOverride-globalDtsDesc": "When using NCore UI Kit in TypeScript projects, you must use global.d.ts to introduce your custom keys to TypeScript.",
+            "defaultJSONs-desc": "Example building blocks showing how to define your own theme and language file when initializing NCore UI Kit in your project.",
+            "defaultJSONs-themeDesc": "Example of a theme configuration that determines your application's color palettes, typography, and spacing values.",
+            "defaultJSONs-localeDesc": "Example of a localization configuration that holds the languages and translations supported by your application.",
             "pageContainer-desc": "A foundational component that wraps page content to comply with theme spacing, safe areas, and scrolling structures.",
             "installation-desc": "Information on how to install NCore UI Kit, basic usage, and how to integrate it into your development environment.",
             "toolsUsage-ncoreToastDesc": "Gives the ability to throw interactive toast messages globally to inform the user about an action result.",
@@ -401,16 +453,19 @@
             "dialog-desc": "A pop-up window component used to draw the user's attention, get confirmation, or provide information.",
             "markdownViewer-desc": "A content component that parses and displays rich text in Markdown format as formatted output.",
             "paletteSwitcher-desc": "A component that allows the user to customize the application's color palette and appearance.",
+            "systemToolbar-desc": "A toolbar component providing nested menus and various actions to the user in a compact layout.",
             "toast-desc": "A component that shows system messages appearing and disappearing momentarily at the top of the screen.",
             "localeSwitcher-desc": "A control component that allows instant switching between the application's language options.",
             "dateTimeSheet-desc": "A sheet component that opens from the bottom of the screen to allow date and time selection.",
             "radioButton-desc": "A button component used to select exactly one option from a set of mutually exclusive choices.",
+            "tooltip-desc": "A small informational box that provides extra details when hovering or long-pressing a component.",
             "typesOverride-tsconfigDesc": "Don't forget to add your global.d.ts to typeRoots or include in your tsconfig.json.",
             "numericInput-desc": "A specialized input component that only allows numerical data or quantities to be entered.",
             "modal-desc": "A modal window component that overlays the current page and focuses the user on a specific task.",
             "text-desc": "The core typography component that handles all text in the application according to theme rules.",
             "yearSelector-desc": "A specialized time interface component focused solely on selecting the year from a list.",
             "themeSwitcher-desc": "A component that allows switching between light and dark themes, or the system theme.",
+            "minimum-selection-number-of-days-required-not-provided": "Minimum number of days required is not provided.",
             "themeExamples-desc": "Usage of different themes, palettes, and typography, and switching them dynamically.",
             "header-desc": "A top-area component located at the top of pages, containing title and navigation actions.",
             "seperator-desc": "A spacing component that creates a visual dividing line between components or content.",
@@ -422,22 +477,33 @@
             "textInput-desc": "A standard form input component that requests the user to enter short text or data.",
             "siteLogo-desc": "A component that renders the main logo image representing the brand or application.",
             "timeSelector-desc": "An interface component optimized for selecting a specific time (hour, minute).",
+            "maximum-selection-number-of-days-limit-exceeds": "Maximum number of days selection limit exceeded.",
             "menu-desc": "A general-purpose menu component that presents various options and links to the user.",
+            "selected-end-time-cannot-before-from-start-time": "Selected end time cannot be before start time.",
             "chip-desc": "A compact component used to display small pieces of information, tags, or statuses.",
+            "markdownEditor-desc": "A content component that allows you to edit rich text in Markdown format.",
             "localeExamples-desc": "Switching between locales and dynamic text usage with localize function.",
+            "selected-start-time-cannot-after-then-end-time": "Selected start time cannot be after end time.",
             "highlightButton-desc": "An eye-catching button component used to highlight important actions.",
             "toolsUsage-codeViewerDesc": "To render code beautifully in your app and copy it to clipboard.",
             "toolsUsage-codeLocaleComment": "Access current localization translations and active language",
+            "codeEditor-desc": "Code editing component with syntax highlighting for software developers.",
+            "code-copy-error-to-clipboard": "An error occurred while copying the code to the clipboard.",
             "monthSelector-desc": "A component used to select a specific month or months within a year.",
             "toolsUsage-codeThemeComment": "Access current theme colors, spaces, and active preferences",
             "dateSelector-desc": "An interface component that allows users to select a specific date.",
+            "maximum-selection-limit-has-been-reached": "Maximum selection limit has been reached.",
             "sticker-desc": "A dynamic sticker component used for adding playful visuals or icons.",
             "switch-desc": "A toggle switch component used to change binary (on/off) preferences.",
             "avatarGroup-desc": "A component that groups and displays multiple avatars together.",
+            "minimum-a-item-selection-required": "A minimum of one item selection is required.",
             "toolsUsage-desc": "Usage of NCore UI Kit hooks useTheme, useLocale, and useToast.",
             "button-desc": "A basic clickable component used to trigger user interactions.",
             "avatar-desc": "A profile image component representing users or entities.",
+            "code-copy-success-to-clipboard": "Code successfully copied to clipboard.",
             "codeViewer-desc": "A component used to display and copy code blocks.",
+            "start-date-select-is-required": "Start date selection is required.",
+            "end-date-select-is-required": "End date selection is required.",
             "typesOverride-tsconfigIntegration": "tsconfig.json Integration",
             "highlightButton-toggleCustomPadding": "Toggle Custom Padding",
             "notificationIndicator-toggleShowCount": "Toggle Show Count",
@@ -493,6 +559,7 @@
             "bottom-sheet-content": "Bottom Sheet Content",
             "components-localeSwitcher": "Locale Switcher",
             "dateTimePicker-changeSpread": "Change Spread",
+            "example-tooltip-subtitle": "Example Subtitle",
             "ncore-design-system": "NCore | Design System",
             "numericInput-changeVariant": "Change Variant",
             "rowCard-toggleRightIcon": "Toggle Right Icon",
@@ -546,6 +613,7 @@
             "components-yearSelector": "Year Selector",
             "dateTimePicker-changeType": "Change Type",
             "dateTimePicker-title": "Date Time Picker",
+            "defaultJSONs-title": "Default JSON Files",
             "embeddedMenu-title": "EmbeddedMenu Title",
             "enter-content-text": "Enter Content Text",
             "numericInput-toggleClean": "Toggle Clean",
@@ -558,6 +626,7 @@
             "checkBox-enterSubText": "Enter Sub Text",
             "highlightButton-enterText": "Enter Text",
             "localeExamples-title": "Locale Examples",
+            "markdownEditor-title": "Markdown Editor",
             "markdownViewer-title": "Markdown Viewer",
             "radioButton-exampleTitle": "Radio Title",
             "rowCard-enterSubTitle": "Enter Subtitle",
@@ -576,8 +645,10 @@
             "components-selectSheet": "Select Sheet",
             "dialog-changeVariant": "Change Variant",
             "embeddedMenu-home": "EmbeddedMenu Home",
+            "example-tooltip-title": "Example Title",
             "header-enterTitle": "Header EnterTitle",
             "header-titleLabel": "Header TitleLabel",
+            "hover-or-press-me": "Hover or Press Me",
             "implementation-title": "Implementation",
             "markdownViewer-contentLabel": "Content",
             "numericInput-changeType": "Change Type",
@@ -594,6 +665,7 @@
             "radioButton-subTitleLabel": "Subtitle",
             "radioButton-toggleFlip": "Toggle Flip",
             "selectBox-toggleClean": "Toggle Clean",
+            "systemToolbar-title": "System Toolbar",
             "textInput-toggleClean": "Toggle Clean",
             "themeExamples-bodyLarge": "Body Large",
             "themeExamples-title": "Theme Examples",
@@ -601,6 +673,7 @@
             "chip-toggleLoading": "Toggle Loading",
             "date-time-picker": "Date Time Picker",
             "mainHeader-title": "MainHeader Title",
+            "select-an-option": "Select an option",
             "switch-changeSpread": "Change Spread",
             "switch-toggleActive": "Toggle Active",
             "themeExamples-switchers": "Switchers",
@@ -619,12 +692,16 @@
             "textInput-enterTitle": "Enter Title",
             "textInput-toggleIcon": "Toggle Icon",
             "webScrollbar-title": "Web Scrollbar",
+            "change-language": "Change Language",
+            "change-location": "Change Location",
             "checkBox-changeType": "Change Type",
             "checkBox-toggleFlip": "Toggle Flip",
             "chip-changeSpread": "Change Spread",
+            "clean-selection": "Clean Selection",
             "enter-image-url": "Enter Image URL",
             "getting-started": "Getting Started",
             "rowCard-exampleTitle": "Card Title",
+            "select-any-date": "Select any date",
             "selectBox-placeholder": "Select...",
             "seperator-enterTitle": "Enter Text",
             "siteLogo-enterTitle": "Enter Title",
@@ -635,7 +712,6 @@
             "toggle-closable": "Toggle Closable",
             "toggle-disabled": "Toggle Disabled",
             "ui-kit-library": "UI Kit - Library",
-            "change-language": "Change Language",
             "avatarGroup-title": "Avatar Group",
             "bottomSheet-title": "Bottom Sheet",
             "gettingStarted": "Getting Started",
@@ -660,6 +736,7 @@
             "themeExamples-success": "Success",
             "themeExamples-warning": "Warning",
             "toggle-loading": "Toggle Loading",
+            "codeEditor-title": "Code Editor",
             "components-snackBar": "SnackBar",
             "radioButton-titleLabel": "Title",
             "siteLogo-exampleTitle": "NİBGAT",
@@ -677,7 +754,9 @@
             "menu-settings": "Menu Settings",
             "themeExamples-danger": "Danger",
             "toggle-portal": "Toggle Portal",
+            "components-tooltip": "Tooltip",
             "coreFeatures": "Core Features",
+            "defaultJSONs": "Default JSONs",
             "selectBox-title": "Select Box",
             "selectBox-titleLabel": "Title",
             "stateCard-title": "State Card",
@@ -706,53 +785,72 @@
             "change-size": "Change Size",
             "change-type": "Change Type",
             "dialog-titleLabel": "Title",
+            "go-to-today": "Go To Today",
             "hello-world": "Hello World",
             "open-dialog": "Open Dialog",
             "switch-titleLabel": "Title",
             "themeExamples-info": "Info",
             "toggle-flip": "Toggle Flip",
             "toggle-icon": "Toggle Icon",
+            "codeViewer": "Code Viewer",
             "components-modal": "Modal",
             "components-toast": "Toast",
             "rowCard-title": "Row Card",
             "toolsUsage": "Tools Usage",
-            "codeViewer": "Code Viewer",
             "chip-titleLabel": "Title",
+            "components": "Components",
+            "enter-code": "Enter Code",
             "enter-text": "Enter Text",
             "loading-title": "Loading",
             "menu-title": "Menu Title",
+            "select-all": "Select All",
+            "start-time": "Start Time",
             "sticker-title": "Sticker",
-            "enter-code": "Enter Code",
             "codeViewer-code": "Code",
+            "is-optional": "Optional",
             "avatar-title": "Avatar",
             "check-box": "Check Box",
+            "clean-all": "Clean All",
             "dialog-title": "Dialog",
             "image-url": "Image URL",
             "menu-home": "Menu Home",
             "sub-title": "Sub Title",
             "switch-title": "Switch",
+            "end-time": "End Time",
             "chip-title": "Chip",
             "content": "Content",
+            "monthly": "Monthly",
+            "preview": "Preview",
+            "tooltip": "Tooltip",
             "version": "Version",
             "home": "Home Page",
             "avatar": "Avatar",
+            "bottom": "Bottom",
             "button": "Button",
+            "cancel": "Cancel",
             "dialog": "Dialog",
+            "search": "Search",
+            "yearly": "Yearly",
             "close": "Close",
+            "daily": "Daily",
             "right": "Right",
             "title": "Title",
             "usage": "Usage",
+            "write": "Write",
             "chip": "Chip",
+            "file": "File",
             "left": "Left",
+            "live": "Live",
+            "menu": "Menu",
             "next": "Next",
+            "open": "Open",
+            "save": "Save",
             "text": "Text",
-            "defaultJSONs-title": "Default JSON Files",
-            "defaultJSONs-desc": "Example building blocks showing how to define your own theme and language file when initializing NCore UI Kit in your project.",
-            "defaultJSONs-themeDesc": "Example of a theme configuration that determines your application's color palettes, typography, and spacing values.",
-            "defaultJSONs-localeDesc": "Example of a localization configuration that holds the languages and translations supported by your application.",
-            "defaultJSONs": "Default JSONs"
+            "top": "Top",
+            "ok": "OK",
+            "or": "Or"
         },
         "locale": "en-US",
         "isRTL": false
     }
-]
+]

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
     "name": "ncore-ui-kit",
-    "version": "1.1.0-alpha.6",
+    "version": "1.1.0-alpha.7",
     "description": "NİBGAT® | NCore - UI Kit for React-Native Mobile Apps.",
     "main": "./lib/module/index.js",
     "types": "./lib/typescript/src/index.d.ts",

+ 5 - 6
src/components/button/index.tsx

@@ -28,12 +28,12 @@ const Button: FC<IButtonProps> = ({
     displayBehaviourWhileLoading = "disabled",
     verticalLocationForStretchFix = "start",
     spreadBehaviour = "baseline",
-    isCustomPadding = false,
     icon: IconComponentProp,
+    isCustomPadding = false,
     iconDirection = "left",
     isFixVerticalStretch,
-    variant = "filled",
     isDisabled = false,
+    variant = "filled",
     customBorderColor,
     type = "primary",
     customIconColor,
@@ -46,8 +46,8 @@ const Button: FC<IButtonProps> = ({
     isLoading,
     iconSize,
     onPress,
-    title,
     style,
+    title,
     ...props
 }) => {
     const {
@@ -86,14 +86,14 @@ const Button: FC<IButtonProps> = ({
         spreadBehaviour,
         currentVariant,
         iconDirection,
-        currentType,
         currentSize,
+        currentType,
         customColor,
         isDisabled,
         isLoading,
         radiuses,
-        variant,
         borders,
+        variant,
         colors,
         spaces,
         title,
@@ -220,7 +220,6 @@ const Button: FC<IButtonProps> = ({
         {renderIcon("left")}
         {renderTitle()}
         {renderIcon("right")}
-
         {renderOverlay()}
     </TouchableOpacity>;
 };

+ 37 - 37
src/components/button/stylesheet.ts

@@ -21,20 +21,20 @@ import type {
 } from "../../types";
 
 export const BUTTON_SIZES: Record<ButtonSize, ButtonMeasuresKeys> = {
-    small: {
-        paddingHorizontal: "spacingMd",
-        paddingVertical: "spacingSm",
-        fontSize: "labelSmallSize"
+    large: {
+        paddingHorizontal: "spacingXl",
+        paddingVertical: "spacingLg",
+        fontSize: "labelLargeSize"
     },
     medium: {
         paddingHorizontal: "spacingLg",
         paddingVertical: "spacingMd",
         fontSize: "labelMediumSize"
     },
-    large: {
-        paddingHorizontal: "spacingXl",
-        paddingVertical: "spacingLg",
-        fontSize: "labelLargeSize"
+    small: {
+        paddingHorizontal: "spacingMd",
+        paddingVertical: "spacingSm",
+        fontSize: "labelSmallSize"
     }
 };
 
@@ -48,9 +48,9 @@ export const BUTTON_VARIANT_STYLES: Record<
         containerColor: "transparent" | "type";
     }
 > = {
-    filled: {
-        borderColor: "container",
-        containerColor: "type",
+    ghost: {
+        containerColor: "transparent",
+        borderColor: "transparent",
         titleColor: "type",
         iconColor: "type"
     },
@@ -60,9 +60,9 @@ export const BUTTON_VARIANT_STYLES: Record<
         titleColor: "type",
         iconColor: "type"
     },
-    ghost: {
-        containerColor: "transparent",
-        borderColor: "transparent",
+    filled: {
+        borderColor: "container",
+        containerColor: "type",
         titleColor: "type",
         iconColor: "type"
     }
@@ -83,12 +83,6 @@ export const BUTTON_TYPE_STYLES: Record<
         titleColor: "onPrimary",
         iconColor: "onPrimary"
     },
-    danger: {
-        containerColor: "danger",
-        borderColor: "danger",
-        titleColor: "danger",
-        iconColor: "danger"
-    },
     success: {
         containerColor: "success",
         borderColor: "success",
@@ -101,17 +95,23 @@ export const BUTTON_TYPE_STYLES: Record<
         titleColor: "warning",
         iconColor: "warning"
     },
-    info: {
-        containerColor: "info",
-        borderColor: "info",
-        titleColor: "info",
-        iconColor: "info"
+    danger: {
+        containerColor: "danger",
+        borderColor: "danger",
+        titleColor: "danger",
+        iconColor: "danger"
     },
     neutral: {
         containerColor: "subtle",
         borderColor: "subtle",
         titleColor: "mid",
         iconColor: "mid"
+    },
+    info: {
+        containerColor: "info",
+        borderColor: "info",
+        titleColor: "info",
+        iconColor: "info"
     }
 };
 
@@ -154,11 +154,6 @@ const stylesheet = StyleSheet.create({
         position: "relative",
         display: "flex"
     },
-    title: {
-        textAlign: "center",
-        margin: 0
-    },
-    loading: {},
     overlay: {
         position: "absolute",
         display: "none",
@@ -166,7 +161,12 @@ const stylesheet = StyleSheet.create({
         right: 0,
         left: 0,
         top: 0
-    }
+    },
+    title: {
+        textAlign: "center",
+        margin: 0
+    },
+    loading: {}
 });
 
 export const useStyles = ({
@@ -174,18 +174,18 @@ export const useStyles = ({
     displayBehaviourWhileLoading,
     isFixVerticalStretch,
     customBorderColor,
-    spreadBehaviour,
     isCustomPadding,
+    spreadBehaviour,
     currentVariant,
     iconDirection,
-    currentType,
     currentSize,
+    currentType,
     customColor,
     isDisabled,
     isLoading,
     radiuses,
-    variant,
     borders,
+    variant,
     colors,
     spaces,
     title,
@@ -204,12 +204,12 @@ export const useStyles = ({
             borderRadius: radiuses.actions,
             borderWidth: borders.line
         } as Mutable<ViewStyle>,
+        overlay: {
+            borderRadius: radiuses.actions - 2
+        } as Mutable<ViewStyle>,
         title: {
         } as Mutable<TextStyle>,
         loading: {
-        } as Mutable<ViewStyle>,
-        overlay: {
-            borderRadius: radiuses.actions - 2
         } as Mutable<ViewStyle>
     };
 

+ 4 - 7
src/components/checkBox/index.tsx

@@ -17,8 +17,8 @@ import {
 } from "../../core/hooks";
 import type ITextProps from "../text/type";
 import {
-    Check,
-    Minus
+    Check as CheckIcon,
+    Minus as MinusIcon
 } from "lucide-react-native";
 import Loading from "../loading";
 import Text from "../text";
@@ -166,13 +166,13 @@ const CheckBox: FC<ICheckBoxProps> = ({
         const selectedColor = indicatorIconProps.customColor ? indicatorIconProps.customColor : colors.content.border[indicatorIconProps.color];
 
         if(isChecked === "partially") {
-            return <Minus
+            return <MinusIcon
                 color={selectedColor}
                 size={16}
             />;
         }
 
-        return <Check
+        return <CheckIcon
             color={selectedColor}
             size={16}
         />;
@@ -194,7 +194,6 @@ const CheckBox: FC<ICheckBoxProps> = ({
             ]}
         >
             {renderCheckIcon()}
-
             {renderOverlay()}
         </View>;
     };
@@ -260,9 +259,7 @@ const CheckBox: FC<ICheckBoxProps> = ({
         })}
     >
         {isFlip ? null : renderCheckIndicator()}
-
         {renderContent()}
-
         {isFlip ? renderCheckIndicator() : null}
     </TouchableOpacity>;
 };

+ 436 - 0
src/components/codeEditor/index.tsx

@@ -0,0 +1,436 @@
+import {
+    useCallback,
+    useEffect,
+    useState,
+    useMemo,
+    useRef
+} from "react";
+import {
+    type TextInputKeyPressEvent,
+    Text as NativeText,
+    ScrollView,
+    TextInput,
+    Platform,
+    View
+} from "react-native";
+import type ICodeEditorProps from "./type";
+import stylesheet, {
+    useStyles
+} from "./stylesheet";
+import {
+    NCoreUIKitTheme
+} from "../../core/hooks";
+import type {
+    TokenType
+} from "../codeViewer/type";
+import {
+    splitTokensIntoLines,
+    parseCode
+} from "../codeViewer/parser";
+import SystemToolbar from "../systemToolbar";
+
+const CodeEditor = ({
+    isLineNumberVisible = true,
+    isToolbarVisible = false,
+    toolbarActions = [],
+    containerStyle,
+    onChangeText,
+    language,
+    style,
+    value,
+    ...props
+}: ICodeEditorProps) => {
+    const {
+        typography,
+        radiuses,
+        borders,
+        colors,
+        spaces
+    } = NCoreUIKitTheme.useContext();
+
+    const inputRef = useRef<TextInput>(null);
+
+    const [
+        selection,
+        setSelection
+    ] = useState<{ start: number; end: number; }>({
+        start: 0,
+        end: 0
+    });
+
+    const tokens = useMemo(() => parseCode(value, language), [
+        language,
+        value
+    ]);
+
+    const lines = useMemo(() => {
+        return splitTokensIntoLines(tokens);
+    }, [tokens]);
+
+    const {
+        toolbarContainer: toolbarContainerDynamicStyle,
+        editorContainer: editorContainerDynamicStyle,
+        languageText: languageTextDynamicStyle,
+        editorInput: editorInputDynamicStyle,
+        container: containerDynamicStyle,
+        lineRow: lineRowDynamicStyle,
+        gutter: gutterDynamicStyle,
+        text: textDynamicStyle
+    } = useStyles({
+        hasLanguage: !!language,
+        isLineNumberVisible,
+        isToolbarVisible,
+        typography,
+        radiuses,
+        borders,
+        colors,
+        spaces
+    });
+
+    const getTokenColor = (type: TokenType) => {
+        return colors.code[type as keyof typeof colors.code] || colors.code.default;
+    };
+
+    const handleKeyPress = (e: TextInputKeyPressEvent) => {
+        if (e.nativeEvent.key === "Tab") {
+            e.preventDefault();
+
+            const before = value.substring(0, selection.start);
+            const after = value.substring(selection.end);
+
+            const newText = before + "    " + after;
+            onChangeText?.(newText);
+        }
+    };
+
+    useEffect(() => {
+        if (Platform.OS === "web" && inputRef.current) {
+            const node = inputRef.current as unknown as HTMLTextAreaElement;
+            const handleKeyDown = (e: KeyboardEvent) => {
+                const target = e.target as HTMLTextAreaElement;
+                const start = target.selectionStart;
+                const end = target.selectionEnd;
+
+                const before = value.substring(0, start);
+                const after = value.substring(end);
+
+                const updateText = (newText: string, newCursorPos: number) => {
+                    e.preventDefault();
+                    onChangeText?.(newText);
+                    setTimeout(() => {
+                        if (inputRef.current) {
+                            const currentTarget = inputRef.current as unknown as HTMLTextAreaElement;
+                            currentTarget.selectionStart = newCursorPos;
+                            currentTarget.selectionEnd = newCursorPos;
+                            setSelection({
+                                start: newCursorPos,
+                                end: newCursorPos
+                            });
+                        }
+                    }, 0);
+                };
+
+                if (e.key === "Tab") {
+                    updateText(before + "    " + after, start + 4);
+                    return;
+                }
+
+                const pairs: Record<string, string> = {
+                    "\"": "\"",
+                    "'": "'",
+                    "(": ")",
+                    "[": "]",
+                    "{": "}",
+                    "`": "`"
+                };
+
+                const prevChar = before.charAt(before.length - 1);
+                const nextChar = after.charAt(0);
+
+                if (pairs[e.key]) {
+                    if (start !== end) {
+                        const selectedText = value.substring(start, end);
+                        updateText(before + e.key + selectedText + pairs[e.key] + after, end + 1);
+                        return;
+                    }
+
+                    if ([
+                        "\"",
+                        "'",
+                        "`"
+                    ].includes(e.key) && nextChar === e.key) {
+                        updateText(value, start + 1);
+                        return;
+                    }
+
+                    if ([
+                        "\"",
+                        "'",
+                        "`"
+                    ].includes(e.key) && /[a-zA-Z0-9]/.test(prevChar)) {
+                        return;
+                    }
+
+                    if (nextChar === "" || /[\s\]})]/ .test(nextChar)) {
+                        updateText(before + e.key + pairs[e.key] + after, start + 1);
+                        return;
+                    }
+                }
+
+                if ([
+                    ")",
+                    "}",
+                    "]"
+                ].includes(e.key) && start === end && nextChar === e.key) {
+                    updateText(value, start + 1);
+                    return;
+                }
+
+                if (e.key === "Backspace" && start === end && start > 0) {
+                    if (
+                        (prevChar === "{" && nextChar === "}") ||
+                        (prevChar === "[" && nextChar === "]") ||
+                        (prevChar === "(" && nextChar === ")") ||
+                        (prevChar === "\"" && nextChar === "\"") ||
+                        (prevChar === "'" && nextChar === "'") ||
+                        (prevChar === "`" && nextChar === "`")
+                    ) {
+                        updateText(before.slice(0, -1) + after.slice(1), start - 1);
+                        return;
+                    }
+                }
+
+                if (e.key === "Enter" && start === end) {
+                    const currentLineText = before.split("\n").pop() || "";
+                    const match = currentLineText.match(/^(\s*)/);
+                    const currentIndentation = match?.[1] || "";
+
+                    if (prevChar === "{" && nextChar === "}") {
+                        updateText(
+                            before + "\n" + currentIndentation + "    \n" + currentIndentation + after,
+                            start + 1 + currentIndentation.length + 4
+                        );
+                        return;
+                    } else if (currentIndentation.length > 0) {
+                        updateText(
+                            before + "\n" + currentIndentation + after,
+                            start + 1 + currentIndentation.length
+                        );
+                        return;
+                    }
+                }
+            };
+
+            node.addEventListener?.("keydown", handleKeyDown);
+            return () => {
+                node.removeEventListener?.("keydown", handleKeyDown);
+            };
+        }
+    }, [
+        value,
+        onChangeText
+    ]);
+
+    const renderBackground = useCallback(() => {
+        return <View>
+            {
+                language ?
+                    <NativeText
+                        style={[
+                            stylesheet.content,
+                            textDynamicStyle,
+                            languageTextDynamicStyle
+                        ]}
+                        selectable={false}
+                    >
+                        // {language}
+                    </NativeText>
+                :
+                    null
+            }
+            {lines.map((lineTokens, index) => {
+                return <View
+                    style={[
+                        stylesheet.lineRow,
+                        lineRowDynamicStyle
+                    ]}
+                    key={`line-${index}`}
+                >
+                    {
+                        isLineNumberVisible ?
+                            <View
+                                style={[
+                                    stylesheet.gutter,
+                                    gutterDynamicStyle,
+                                    {
+                                        borderRightColor: colors.content.border.subtle
+                                    }
+                                ]}
+                            >
+                                <NativeText
+                                    style={[
+                                        stylesheet.lineNumber,
+                                        {
+                                            color: colors.content.text.low
+                                        }
+                                    ]}
+                                    selectable={false}
+                                >
+                                    {index + 1}
+                                </NativeText>
+                            </View>
+                        :
+                            null
+                    }
+                    <NativeText
+                        style={[
+                            stylesheet.content,
+                            textDynamicStyle,
+                            {
+                                color: colors.content.text.high
+                            }
+                        ]}
+                    >
+                        {lineTokens.map((token, tIndex) => {
+                            return <NativeText
+                                style={{
+                                    color: getTokenColor(token.type)
+                                }}
+                                key={`token-${index}-${tIndex}`}
+                            >
+                                {token.value}
+                            </NativeText>;
+                        })}
+                    </NativeText>
+                </View>;
+            })}
+            {
+                lines.length === 0 ?
+                    <View
+                        style={[
+                            stylesheet.lineRow,
+                            lineRowDynamicStyle
+                        ]}
+                    >
+                        {
+                            isLineNumberVisible ?
+                                <View
+                                    style={[
+                                        stylesheet.gutter,
+                                        gutterDynamicStyle,
+                                        {
+                                            borderRightColor: colors.content.border.subtle
+                                        }
+                                    ]}
+                                >
+                                    <NativeText
+                                        style={[
+                                            stylesheet.lineNumber,
+                                            {
+                                                color: colors.content.text.low
+                                            }
+                                        ]}
+                                        selectable={false}
+                                    >
+                                        1
+                                    </NativeText>
+                                </View>
+                            :
+                                null
+                        }
+                        <NativeText
+                            style={[
+                                stylesheet.content,
+                                textDynamicStyle,
+                                {
+                                    color: colors.content.text.high
+                                }
+                            ]}
+                        >
+                        </NativeText>
+                    </View>
+                :
+                    null
+            }
+        </View>;
+    }, [
+        languageTextDynamicStyle,
+        isLineNumberVisible,
+        lineRowDynamicStyle,
+        gutterDynamicStyle,
+        textDynamicStyle,
+        language,
+        colors,
+        lines
+    ]);
+
+    return <View
+        style={[
+            stylesheet.container,
+            containerDynamicStyle,
+            containerStyle
+        ]}
+    >
+        {
+            isToolbarVisible ?
+                <View
+                    style={[
+                        stylesheet.toolbarContainer,
+                        toolbarContainerDynamicStyle
+                    ]}
+                >
+                    {toolbarActions.map((action, index) => <SystemToolbar
+                        key={`toolbar-action-${index}`}
+                        {...action}
+                    />)}
+                </View>
+            :
+                null
+        }
+        <View
+            style={[
+                editorContainerDynamicStyle
+            ]}
+        >
+            <ScrollView
+                showsHorizontalScrollIndicator={true}
+                contentContainerStyle={[
+                    stylesheet.scrollContent
+                ]}
+                style={[
+                    stylesheet.scrollView
+                ]}
+                horizontal={true}
+            >
+                <View
+                    style={[
+                        stylesheet.scrollContent
+                    ]}
+                >
+                    {renderBackground()}
+                    <TextInput
+                        {...props}
+                        onSelectionChange={(e) => {
+                            setSelection(e.nativeEvent.selection);
+                            props.onSelectionChange?.(e);
+                        }}
+                        style={[
+                            stylesheet.editorInput,
+                            editorInputDynamicStyle,
+                            style
+                        ]}
+                        onChangeText={onChangeText}
+                        onKeyPress={handleKeyPress}
+                        autoCapitalize="none"
+                        autoCorrect={false}
+                        spellCheck={false}
+                        multiline={true}
+                        ref={inputRef}
+                        value={value}
+                    />
+                </View>
+            </ScrollView>
+        </View>
+    </View>;
+};
+export default CodeEditor;

+ 208 - 0
src/components/codeEditor/stylesheet.ts

@@ -0,0 +1,208 @@
+import {
+    type TextStyle,
+    type ViewStyle,
+    StyleSheet,
+    Platform
+} from "react-native";
+import type {
+    ICodeEditorDynamicStyleProps
+} from "./type";
+import {
+    webStyle
+} from "../../utils";
+
+const stylesheet = StyleSheet.create({
+    editorInput: {
+        fontFamily: Platform.OS === "web" ? "Consolas, 'Courier New', monospace" : "monospace",
+        backgroundColor: "transparent",
+        textAlignVertical: "top",
+        position: "absolute",
+        color: "transparent",
+        fontWeight: "400",
+        letterSpacing: 0,
+        borderWidth: 0,
+        lineHeight: 24,
+        fontSize: 14,
+        padding: 0,
+        margin: 0,
+        bottom: 0,
+        right: 0,
+        left: 0,
+        top: 0,
+        ...webStyle({
+            fontVariantLigatures: "none",
+            caretColor: "inherit",
+            outline: "none",
+            resize: "none"
+        })
+    },
+    content: {
+        fontFamily: Platform.OS === "web" ? "Consolas, 'Courier New', monospace" : "monospace",
+        fontWeight: "400",
+        letterSpacing: 0,
+        ...webStyle({
+            whiteSpace: Platform.OS === "web" ? "pre" : "pre-wrap",
+            fontVariantLigatures: "none"
+        })
+    },
+    codeText: {
+        fontFamily: Platform.OS === "web" ? "Consolas, 'Courier New', monospace" : "monospace",
+        fontWeight: "400",
+        letterSpacing: 0,
+        fontSize: 14,
+        ...webStyle({
+            fontVariantLigatures: "none"
+        })
+    },
+    lineNumber: {
+        fontFamily: Platform.OS === "web" ? "monospace" : "System",
+        textAlign: "right",
+        marginRight: 4,
+        lineHeight: 24,
+        fontSize: 12,
+        ...webStyle({
+            userSelect: "none"
+        })
+    },
+    toolbarContainer: {
+        justifyContent: "flex-start",
+        borderBottomWidth: 0,
+        alignItems: "center",
+        flexDirection: "row",
+        position: "relative",
+        paddingVertical: 4,
+        flexWrap: "wrap",
+        zIndex: 1
+    },
+    gutter: {
+        justifyContent: "flex-end",
+        alignItems: "flex-start",
+        flexDirection: "row",
+        borderRightWidth: 1,
+        ...webStyle({
+            userSelect: "none"
+        })
+    },
+    lineRow: {
+        alignItems: "flex-start",
+        flexDirection: "row",
+        minHeight: 24
+    },
+    container: {
+        flexDirection: "column",
+        position: "relative",
+        width: "100%"
+    },
+    editorContainer: {
+        position: "relative",
+        zIndex: 0
+    },
+    scrollContent: {
+        minWidth: "100%",
+        flexGrow: 1
+    },
+    text: {
+        lineHeight: 24
+    },
+    scrollView: {
+        flex: 1
+    }
+});
+
+export const useStyles = ({
+    isLineNumberVisible = true,
+    isToolbarVisible = false,
+    hasLanguage = false,
+    spreadBehaviour,
+    typography,
+    radiuses,
+    borders,
+    colors,
+    spaces
+}: ICodeEditorDynamicStyleProps) => {
+    let gutterPaddingRight = 6;
+    let gutterMarginRight = 8;
+    let gutterWidth = 32;
+
+    if (!isLineNumberVisible) {
+        gutterPaddingRight = 0;
+        gutterMarginRight = 0;
+        gutterWidth = 0;
+    }
+
+    const languageMarginLeft = spaces.spacingSm;
+    const lineHeight = (typography.bodyMediumSize?.lineHeight as number) || 24;
+
+    const styles = {
+        container: {
+            alignSelf: spreadBehaviour === "stretch" ? "stretch" : (spreadBehaviour === "baseline" ? "baseline" : "auto"),
+            width: spreadBehaviour === "baseline" ? "auto" : "100%",
+            marginVertical: spaces.spacingSm
+        } as ViewStyle,
+        editorInput: {
+            ...typography.bodyMediumSize,
+            paddingLeft: (isLineNumberVisible ? (gutterWidth + gutterMarginRight) : spaces.spacingSm),
+            fontFamily: Platform.OS === "web" ? "Consolas, 'Courier New', monospace" : "monospace",
+            paddingTop: hasLanguage ? (lineHeight + spaces.spacingSm) : 0,
+            paddingRight: spaces.spacingMd,
+            ...webStyle({
+                caretColor: colors.content.text.high
+            })
+        } as TextStyle,
+        text: {
+            ...typography.bodyMediumSize,
+            fontFamily: Platform.OS === "web" ? "Consolas, 'Courier New', monospace" : "monospace"
+        } as TextStyle,
+        editorContainer: {
+            paddingTop: isToolbarVisible ? spaces.spacingXs : spaces.spacingMd,
+            borderTopRightRadius: isToolbarVisible ? 0 : radiuses.form,
+            borderTopLeftRadius: isToolbarVisible ? 0 : radiuses.form,
+            backgroundColor: colors.content.container.subtle,
+            borderColor: colors.content.border.subtle,
+            borderBottomRightRadius: radiuses.form,
+            borderBottomLeftRadius: radiuses.form,
+            paddingHorizontal: spaces.spacingMd,
+            paddingBottom: spaces.spacingMd,
+            borderWidth: borders.line,
+            borderTopWidth: isToolbarVisible ? 0 : borders.line
+        } as ViewStyle,
+        lineRow: {
+            marginLeft: !isLineNumberVisible ? spaces.spacingSm : 0,
+            minHeight: lineHeight,
+            height: lineHeight
+        } as ViewStyle,
+        toolbarContainer: {
+            backgroundColor: colors.content.container.subtle,
+            borderColor: colors.content.border.subtle,
+            borderTopRightRadius: radiuses.form,
+            paddingHorizontal: spaces.spacingMd,
+            borderTopLeftRadius: radiuses.form,
+            paddingBottom: spaces.spacingXs,
+            borderRightWidth: borders.line,
+            borderLeftWidth: borders.line,
+            borderTopWidth: borders.line,
+            paddingTop: spaces.spacingMd,
+            gap: spaces.spacingXs
+        } as ViewStyle,
+        toolbarActionBtn: {
+            paddingHorizontal: spaces.spacingMd,
+            paddingVertical: spaces.spacingSm
+        } as ViewStyle,
+        gutter: {
+            paddingRight: gutterPaddingRight,
+            marginRight: gutterMarginRight,
+            width: gutterWidth
+        } as ViewStyle,
+        languageText: {
+            marginBottom: spaces.spacingSm,
+            color: colors.content.text.low,
+            marginLeft: languageMarginLeft,
+            ...webStyle({
+                userSelect: "none"
+            })
+        } as TextStyle
+    };
+
+    return styles;
+};
+export default stylesheet;

+ 39 - 0
src/components/codeEditor/type.ts

@@ -0,0 +1,39 @@
+import {
+    type TextInputProps,
+    type StyleProp,
+    type ViewStyle
+} from "react-native";
+
+export type CodeEditorSpreadBehaviour = "baseline" | "stretch" | "free";
+
+export interface ICodeEditorDynamicStyleProps {
+    typography: NCoreUIKit.ActivePalette["typography"];
+    radiuses: NCoreUIKit.ActivePalette["radiuses"];
+    borders: NCoreUIKit.ActivePalette["borders"];
+    spreadBehaviour?: CodeEditorSpreadBehaviour;
+    spaces: NCoreUIKit.ActivePalette["spaces"];
+    colors: NCoreUIKit.ActivePalette["colors"];
+    isLineNumberVisible?: boolean;
+    isToolbarVisible?: boolean;
+    hasLanguage?: boolean;
+}
+
+import type ISystemToolbarProps from "../systemToolbar/type";
+
+interface ICodeEditorProps extends Omit<TextInputProps, "style" | "value" | "onChangeText"> {
+    toolbarContainerStyle?: StyleProp<ViewStyle>;
+    toolbarActions?: Array<ISystemToolbarProps>;
+    spreadBehaviour?: CodeEditorSpreadBehaviour;
+    onChangeText?: (text: string) => void;
+    isLineNumberVisible?: boolean;
+    isToolbarVisible?: boolean;
+    containerStyle?: ViewStyle;
+    isScrollable?: boolean;
+    style?: ViewStyle;
+    language?: string;
+    value: string;
+}
+
+export type {
+    ICodeEditorProps as default
+};

+ 7 - 7
src/components/codeViewer/parser.ts

@@ -595,8 +595,8 @@ const getTokenRegex = (language?: string): RegExp => {
         "(?<keyword>" + keywordsRegexStr + ")|" +
         "(?<htmlTag>(?<=<\\/?)[a-z][a-zA-Z0-9-]*\\b)|" +
         "(?<component>\\b[A-Z][a-zA-Z0-9_$]*\\b)|" +
-        "(?<function>\\b[a-zA-Z_$][a-zA-Z0-9_$]*(?=\\s*\\())|" +
-        "(?<property>\\b[a-zA-Z_$][a-zA-Z0-9_$]*(?=\\s*=))|" +
+        "(?<function>\\b[a-zA-Z_$][a-zA-Z0-9_$]*(?=\\s*\\()|\\b[a-zA-Z_$][a-zA-Z0-9_$]*(?=\\s*[:=]\\s*(?:async\\s+)?(?:\\([^)]*\\)|[a-zA-Z_$][a-zA-Z0-9_$]*)\\s*=>)|\\b[a-zA-Z_$][a-zA-Z0-9_$]*(?=\\s*[:=]\\s*function\\b))|" +
+        "(?<property>\\b[a-zA-Z_$][a-zA-Z0-9_$]*(?=\\s*[:=]))|" +
         "(?<variable>\\b[a-zA-Z_$][a-zA-Z0-9_$]*\\b)|" +
         "(?<number>\\b\\d+(?:\\.\\d+)?\\b)|" +
         "(?<arrow>=>)|" +
@@ -675,9 +675,9 @@ export const splitTokensIntoLines = (tokens: Token[]): Token[][] => {
             currentLine.push(token);
         }
     });
-    if (currentLine.length > 0) {
-        lines.push(currentLine);
-    }
+
+    lines.push(currentLine);
+
     return lines;
 };
 
@@ -687,12 +687,12 @@ export const getLineIndentation = (lineTokens: Token[]): number => {
         if (token.type === "text") {
             const match = token.value.match(/^(\s+)/);
 
-            if (match) {
+            if(match) {
                 const matchLen = (match[1] as string).length;
 
                 indentation += matchLen;
 
-                if (matchLen !== token.value.length) {
+                if(matchLen !== token.value.length) {
                     break;
                 }
             } else if (token.value.length > 0) {

+ 40 - 37
src/components/codeViewer/stylesheet.ts

@@ -12,21 +12,14 @@ import {
 } from "../../utils";
 
 const stylesheet = StyleSheet.create({
-    container: {
+    gutter: {
+        justifyContent: "flex-end",
         alignItems: "flex-start",
         flexDirection: "row",
-        borderRadius: 10,
-        borderWidth: 1
-    },
-    scrollContent: {
-        flexGrow: 1
-    },
-    scrollView: {
-        flex: 1
-    },
-    stickyActionContainer: {
-        alignSelf: "flex-start",
-        zIndex: 1
+        borderRightWidth: 1,
+        ...webStyle({
+            userSelect: "none"
+        })
     },
     content: {
         fontFamily: Platform.OS === "web" ? "monospace" : "System",
@@ -34,23 +27,10 @@ const stylesheet = StyleSheet.create({
             whiteSpace: Platform.OS === "web" ? "pre" : "pre-wrap"
         })
     },
-    lineRow: {
-        alignItems: "flex-start",
-        flexDirection: "row",
-        minHeight: 24
-    },
-    gutter: {
-        justifyContent: "flex-end",
-        flexDirection: "row",
-        alignItems: "center",
-        borderRightWidth: 1,
-        ...webStyle({
-            userSelect: "none"
-        })
-    },
     lineNumber: {
         textAlign: "right",
         marginRight: 4,
+        lineHeight: 24,
         fontSize: 12,
         ...webStyle({
             userSelect: "none"
@@ -59,12 +39,35 @@ const stylesheet = StyleSheet.create({
     foldIcon: {
         justifyContent: "center",
         alignItems: "center",
+        marginTop: 5,
         height: 14,
         width: 14
     },
+    container: {
+        alignItems: "flex-start",
+        flexDirection: "row",
+        borderRadius: 10,
+        borderWidth: 1
+    },
+    lineRow: {
+        alignItems: "flex-start",
+        flexDirection: "row",
+        minHeight: 24
+    },
     foldIconPlaceholder: {
+        marginTop: 5,
         height: 14,
         width: 14
+    },
+    stickyActionContainer: {
+        alignSelf: "flex-start",
+        zIndex: 1
+    },
+    scrollContent: {
+        flexGrow: 1
+    },
+    scrollView: {
+        flex: 1
     }
 });
 
@@ -99,16 +102,6 @@ export const useStyles = ({
     const languageMarginLeft = spaces.spacingSm;
 
     const styles = {
-        container: {
-            backgroundColor: colors.content.container.subtle,
-            borderColor: colors.content.border.subtle,
-            marginVertical: spaces.spacingSm,
-            padding: spaces.spacingMd
-        } as ViewStyle,
-        text: {
-            ...typography.bodyMediumSize,
-            lineHeight: 24
-        } as TextStyle,
         languageText: {
             color: colors.content.text.low,
             marginBottom: spaces.spacingSm,
@@ -117,11 +110,21 @@ export const useStyles = ({
                 userSelect: "none"
             })
         } as TextStyle,
+        container: {
+            backgroundColor: colors.content.container.subtle,
+            borderColor: colors.content.border.subtle,
+            marginVertical: spaces.spacingSm,
+            padding: spaces.spacingMd
+        } as ViewStyle,
         gutter: {
             paddingRight: gutterPaddingRight,
             marginRight: gutterMarginRight,
             width: gutterWidth
         } as ViewStyle,
+        text: {
+            ...typography.bodyMediumSize,
+            lineHeight: 24
+        } as TextStyle,
         lineRow: {
             marginLeft: !isGutterVisible ? spaces.spacingSm : 0
         } as ViewStyle

+ 12 - 7
src/components/dateSelector/index.tsx

@@ -329,16 +329,21 @@ const DateSelector = ({
             >
                 {dayItem.dayNumber}
             </Text>
-            {isShowTodayIndicator && dayItem.isToday ? <View
-                style={[
-                    stylesheet.todayIndicator,
-                    selectionStyle,
-                    todayIndicatorDynamicStyle,
+            {
+                isShowTodayIndicator && dayItem.isToday ?
+                    <View
+                        style={[
+                            stylesheet.todayIndicator,
+                            selectionStyle,
+                            todayIndicatorDynamicStyle,
                     dayItem.isSelected ? {
                         borderColor: colors.content.border.subtle
                     } : null
-                ]}
-            /> : null}
+                        ]}
+                    />
+                :
+                    null
+            }
         </TouchableOpacity>;
     };
 

+ 0 - 6
src/components/dateTimePicker/index.tsx

@@ -901,7 +901,6 @@ const DateTimePicker = ({
         ]}
     >
         {renderTitle()}
-
         <TouchableOpacity
             disabled={isDisabled}
             style={[
@@ -916,17 +915,12 @@ const DateTimePicker = ({
             }}
         >
             {renderOverlay()}
-
             {renderIcon()}
-
             {renderContent()}
-
             {renderCleanButton()}
             {renderRightIcon()}
         </TouchableOpacity>
-
         {renderHintText()}
-
         <DateTimeSheet
             isTimeSelectWorksWithCenterWhenTimePicker={isTimeSelectWorksWithCenterWhenTimePicker}
             multipleSelectMinimumRequiredDayCount={multipleSelectMinimumRequiredDayCount}

+ 53 - 35
src/components/dateTimeSheet/index.tsx

@@ -254,10 +254,15 @@ const DateTimeSheet = ({
                     loadingContainerDynamicStyle
                 ]}
             >
-                {LoadingIconComponentProp ? <LoadingIconComponentProp
-                    color="emphasized"
-                    size={20}
-                /> : <Loading/>}
+                {
+                    LoadingIconComponentProp ?
+                        <LoadingIconComponentProp
+                            color="emphasized"
+                            size={20}
+                        />
+                    :
+                        <Loading/>
+                }
             </View>;
         }
 
@@ -270,21 +275,24 @@ const DateTimeSheet = ({
             {renderCalenderChangerTool()}
             {renderDateCalendar()}
             {
-                pickerType === "date" ? null : <TimeSelector
-                    isTimeSelectWorksWithCenterWhenTimePicker={isTimeSelectWorksWithCenterWhenTimePicker}
-                    multipleSelectMinimumRequireMS={multipleSelectMinimumRequireMS}
-                    multipleSelectMaximumMS={multipleSelectMaximumMS}
-                    setIsSheetContentReady={setIsSheetContentReady}
-                    selectMultipleObject={selectMultipleObject}
-                    isWorkWithSeconds={isWorkWithSeconds}
-                    selectObject={selectObject}
-                    pickerType={pickerType}
-                    dateRange={dateRange}
-                    maxDate={maxDate}
-                    minDate={minDate}
-                    variant={variant}
-                    date={date}
-                />
+                pickerType === "date" ?
+                    null
+                :
+                    <TimeSelector
+                        isTimeSelectWorksWithCenterWhenTimePicker={isTimeSelectWorksWithCenterWhenTimePicker}
+                        multipleSelectMinimumRequireMS={multipleSelectMinimumRequireMS}
+                        multipleSelectMaximumMS={multipleSelectMaximumMS}
+                        setIsSheetContentReady={setIsSheetContentReady}
+                        selectMultipleObject={selectMultipleObject}
+                        isWorkWithSeconds={isWorkWithSeconds}
+                        selectObject={selectObject}
+                        pickerType={pickerType}
+                        dateRange={dateRange}
+                        maxDate={maxDate}
+                        minDate={minDate}
+                        variant={variant}
+                        date={date}
+                    />
             }
         </View>;
     };
@@ -318,14 +326,19 @@ const DateTimeSheet = ({
                 toolsContainerDynamicStyle
             ]}
         >
-            {!minChoice ? <CheckBox
-                isChecked={isAnySelected ? "checked" : null}
-                title={localize("clean-selection")}
-                spreadBehaviour="free"
-                onPress={() => {
-                    clean();
-                }}
-            /> : null}
+            {
+                !minChoice ?
+                    <CheckBox
+                        isChecked={isAnySelected ? "checked" : null}
+                        title={localize("clean-selection")}
+                        spreadBehaviour="free"
+                        onPress={() => {
+                            clean();
+                        }}
+                    />
+                :
+                    null
+            }
             <Button
                 onPress={() => {
                     if(monthCalendarRef.current) monthCalendarRef.current.changeCurrentYear(new Date());
@@ -346,14 +359,19 @@ const DateTimeSheet = ({
                 headerContainerDynamicStyle
             ]}
         >
-            {title ? <Text
-                variant="titleMediumSize"
-                style={[
-                    headerTitleDynamicStyle
-                ]}
-            >
-                {title}
-            </Text> : null}
+            {
+                title ?
+                    <Text
+                        variant="titleMediumSize"
+                        style={[
+                            headerTitleDynamicStyle
+                        ]}
+                    >
+                        {title}
+                    </Text>
+                :
+                    null
+            }
             {renderTools()}
         </View>;
     };

+ 1 - 1
src/components/embeddedMenu/components/menuButton/index.tsx

@@ -277,7 +277,7 @@ const EmbeddedMenuButton: FC<IEmbeddedMenuButton> = ({
                         />;
                     })}
                 </Animated.View>
-                :
+            :
                 null
         }
     </View>;

+ 46 - 31
src/components/embeddedMenu/index.tsx

@@ -33,8 +33,8 @@ import type {
     RefForwardingComponent
 } from "../../types";
 import {
-    PanelLeftClose,
-    PanelLeftOpen
+    PanelLeftClose as PanelLeftCloseIcon,
+    PanelLeftOpen as PanelLeftOpenIcon
 } from "lucide-react-native";
 import {
     SafeAreaView
@@ -256,7 +256,7 @@ const Menu: RefForwardingComponent<IEmbeddedMenuRef, IEmbeddedMenuProps> = ({
                 color,
                 size
             }) => {
-                return <PanelLeftOpen
+                return <PanelLeftOpenIcon
                     color={colors.content.icon[color]}
                     size={size * 2}
                 />;
@@ -288,7 +288,7 @@ const Menu: RefForwardingComponent<IEmbeddedMenuRef, IEmbeddedMenuProps> = ({
                 color,
                 size
             }) => {
-                return <PanelLeftClose
+                return <PanelLeftCloseIcon
                     color={colors.content.icon[color]}
                     size={size * 2}
                 />;
@@ -328,27 +328,37 @@ const Menu: RefForwardingComponent<IEmbeddedMenuRef, IEmbeddedMenuProps> = ({
                     headerContentContainerDynamicStyle
                 ]}
             >
-                {isShowSiteLogo ? renderSiteLogo ? renderSiteLogo() : <SiteLogo
-                    customLocalize={customLocalize}
-                    customTheme={customTheme}
-                    {...siteLogoProps}
-                    title={isActive ? siteLogoProps?.title : undefined}
-                    size={isActive ? siteLogoProps?.size : "small"}
-                    style={[
-                        siteLogoProps?.style,
-                        siteLogoDynamicStyle
-                    ]}
-                /> : <View
-                    style={stylesheet.emptyLogo}
-                />}
+                {
+                    isShowSiteLogo ?
+                        renderSiteLogo ? renderSiteLogo() : <SiteLogo
+                            customLocalize={customLocalize}
+                            customTheme={customTheme}
+                            {...siteLogoProps}
+                            title={isActive ? siteLogoProps?.title : undefined}
+                            size={isActive ? siteLogoProps?.size : "small"}
+                            style={[
+                                siteLogoProps?.style,
+                                siteLogoDynamicStyle
+                            ]}
+                        />
+                    :
+                        <View
+                            style={stylesheet.emptyLogo}
+                        />
+                }
                 {renderToggleCollapseForExpended()}
             </View>
-            {renderHeaderSeperator ? renderHeaderSeperator() : <Seperator
-                style={[
-                    stylesheet.seperator,
-                    seperatorDynamicStyle
-                ]}
-            />}
+            {
+                renderHeaderSeperator ?
+                    renderHeaderSeperator()
+                :
+                    <Seperator
+                        style={[
+                            stylesheet.seperator,
+                            seperatorDynamicStyle
+                        ]}
+                    />
+            }
         </View>;
     };
 
@@ -392,14 +402,19 @@ const Menu: RefForwardingComponent<IEmbeddedMenuRef, IEmbeddedMenuProps> = ({
     const renderSafeAreaContext = () => {
         if(!isWorkWithSafeAreaView) {
             return <Fragment>
-                {isWorkWithHeaderSpace && (configs.headerSpace || headerSpace) ? <View
-                    style={[
-                        stylesheet.headerSpacer,
-                        {
-                            height: headerSpace ? headerSpace : configs.headerSpace
-                        }
-                    ]}
-                /> : null}
+                {
+                    isWorkWithHeaderSpace && (configs.headerSpace || headerSpace) ?
+                        <View
+                            style={[
+                                stylesheet.headerSpacer,
+                                {
+                                    height: headerSpace ? headerSpace : configs.headerSpace
+                                }
+                            ]}
+                        />
+                    :
+                        null
+                }
                 {renderHeader()}
                 <ScrollView
                     showsHorizontalScrollIndicator={false}

+ 8 - 8
src/components/header/index.tsx

@@ -16,12 +16,12 @@ import stylesheet, {
 import {
     NCoreUIKitTheme
 } from "../../core/hooks";
-import {
-    ChevronLeftIcon
-} from "lucide-react-native";
 import {
     SafeAreaView
 } from "react-native-safe-area-context";
+import {
+    ChevronLeftIcon
+} from "lucide-react-native";
 import Button from "../button";
 import Text from "../text";
 
@@ -106,7 +106,7 @@ const Header = <T extends NavigationType>({
             </View>;
         }
 
-        if(!isGoBackEnable || !navigation) {
+        if(!isGoBackEnable || !navigation || !navigation.canGoBack()) {
             if(leftContainerWidth === null) setLeftContainerWidth(0);
             return <View/>;
         }
@@ -122,10 +122,6 @@ const Header = <T extends NavigationType>({
             ]}
         >
             <Button
-                spreadBehaviour="free"
-                variant="ghost"
-                type="neutral"
-                size="small"
                 icon={({
                     color,
                     size
@@ -140,6 +136,10 @@ const Header = <T extends NavigationType>({
                         (navigation as unknown as { goBack: () => void }).goBack();
                     }
                 }}
+                spreadBehaviour="free"
+                variant="ghost"
+                type="neutral"
+                size="small"
             />
         </View>;
     };

+ 4 - 1
src/components/header/type.ts

@@ -18,7 +18,10 @@ export type HeaderDynamicStyleType = {
     headerSpace?: number;
 };
 
-export type NavigationType = unknown;
+export type NavigationType = {
+    canGoBack: () => boolean;
+    goBack: () => void;
+};
 
 export type ActionItem = IButtonProps;
 

+ 0 - 1
src/components/highlightButton/index.tsx

@@ -196,7 +196,6 @@ const HighlightButton: FC<IHighlightButtonProps> = ({
         {renderIcon("left")}
         {renderTitle()}
         {renderIcon("right")}
-
         {renderOverlay()}
     </TouchableOpacity>;
 };

+ 41 - 6
src/components/index.ts

@@ -31,8 +31,8 @@ export {
 } from "./dialog";
 
 export type {
-    default as IDialogProps,
     DialogDynamicStyleType,
+    default as IDialogProps,
     DialogContentJustify,
     DialogVariant,
     IDialogRef
@@ -95,9 +95,9 @@ export {
 
 export type {
     CheckBoxDisplayBehaviourWhileLoading,
-    default as ICheckBoxProps,
     CheckBoxDynamicStyleType,
     CheckBoxTypeConstantType,
+    default as ICheckBoxProps,
     CheckBoxSpreadBehaviour,
     CheckBoxTypes,
     CheckBoxType
@@ -173,9 +173,9 @@ export type {
 } from "./dateTimeSheet/type";
 
 export type {
-    default as IDateTimePickerProps,
     DateTimePickerDateRangeResponse,
     DateTimePickerDynamicStyleType,
+    default as IDateTimePickerProps,
     DateTimePickerSpreadBehaviour,
     DateTimePickerPickerType,
     DateTimePickerDateRange,
@@ -256,9 +256,9 @@ export {
 
 export type {
     ChipDisplayBehaviourWhileLoading,
-    default as IChipProps,
     ChipDynamicStyleType,
     ChipTypeConstantType,
+    default as IChipProps,
     ChipSpreadBehaviour,
     ChipSizeType,
     ChipTypes,
@@ -296,9 +296,9 @@ export {
 export type {
     AvatarTitleAbbreviationTypes,
     AvatarStatusIndicatorType,
-    default as IAvatarProps,
     AvatarDynamicStyleType,
     AvatarSizeConstantType,
+    default as IAvatarProps,
     AvatarMeasuresKeys,
     AvatarMeasures,
     AvatarSizeType
@@ -310,9 +310,9 @@ export {
 
 export type {
     AvatarGroupTitleAbbreviationTypes,
-    default as IAvatarGroupProps,
     AvatarGroupDynamicStyleType,
     AvatarGroupSizeConstantType,
+    default as IAvatarGroupProps,
     AvatarGroupMeasuresKeys,
     AvatarGroupAvatarsType,
     AvatarGroupSizeType
@@ -420,3 +420,38 @@ export type {
     default as IYearSelectorProps,
     IYearSelectorRef
 } from "./yearSelector/type";
+
+export {
+    default as MarkdownEditor
+} from "./markdownEditor";
+
+export type {
+    default as IMarkdownEditorProps,
+    MarkdownDynamicStyles,
+    MarkdownEditorMode
+} from "./markdownEditor/type";
+
+export {
+    default as CodeEditor
+} from "./codeEditor";
+
+export type {
+    default as ICodeEditorProps
+} from "./codeEditor/type";
+
+export {
+    default as Tooltip
+} from "./tooltip";
+
+export type {
+    default as ITooltipProps,
+    TooltipLocation
+} from "./tooltip/type";
+
+export {
+    default as SystemToolbar
+} from "./systemToolbar";
+
+export type {
+    default as ISystemToolbarProps
+} from "./systemToolbar/type";

+ 14 - 9
src/components/mainHeader/index.tsx

@@ -158,15 +158,20 @@ const MainHeader = ({
             ]}
         >
             {isWorkWithSafeAreaView ? renderSafeAreaView() : renderContentContainer()}
-            {isWorkWithSticky && isWorkWithStickySpace ? <View
-                style={[
-                    stylesheet.stickySpacer,
-                    {
-                        backgroundColor: customBackgroundColor ? colors.project[customBackgroundColor] : colors.content.container[backgroundColor],
-                        height: contentHeight
-                    }
-                ]}
-            /> : null}
+            {
+                isWorkWithSticky && isWorkWithStickySpace ?
+                    <View
+                        style={[
+                            stylesheet.stickySpacer,
+                            {
+                                backgroundColor: customBackgroundColor ? colors.project[customBackgroundColor] : colors.content.container[backgroundColor],
+                                height: contentHeight
+                            }
+                        ]}
+                    />
+                :
+                    null
+            }
             {children}
         </View>;
     };

+ 530 - 0
src/components/markdownEditor/index.tsx

@@ -0,0 +1,530 @@
+import {
+    useState,
+    useRef,
+    type FC
+} from "react";
+import {
+    TouchableOpacity,
+    ScrollView,
+    TextInput,
+    View
+} from "react-native";
+import type {
+    MarkdownEditorMode
+} from "./type";
+import type IMarkdownEditorProps from "./type";
+import stylesheet, {
+    useStyles
+} from "./stylesheet";
+import {
+    NCoreUIKitLocalize,
+    NCoreUIKitTheme
+} from "../../core/hooks";
+import type {
+    TextMarkdownTypes,
+    MarkdownKeys
+} from "../markdownViewer/type";
+import {
+    ChevronsDown as ChevronsDownIcon,
+    ChevronDown as ChevronDownIcon,
+    AlignCenter as AlignCenterIcon,
+    AlignRight as AlignRightIcon,
+    AlignLeft as AlignLeftIcon,
+    Italic as ItalicIcon,
+    Quote as QuoteIcon,
+    Image as ImageIcon,
+    Bold as BoldIcon,
+    Link as LinkIcon,
+    Code as CodeIcon,
+    List as ListIcon
+} from "lucide-react-native";
+import MarkdownViewer from "../markdownViewer";
+import {
+    DEFAULT_VARIANTS
+} from "../markdownViewer/constant";
+import Text from "../text";
+import {
+    webStyle
+} from "../../utils";
+
+const MarkdownEditor: FC<IMarkdownEditorProps> = ({
+    spreadBehaviour = "stretch",
+    isViewerResizable = true,
+    isEditorResizable = true,
+    toolbarContainerStyle,
+    defaultMode = "live",
+    initialValue = "",
+    onChangeText,
+    variants,
+    style,
+    ...props
+}) => {
+    const {
+        radiuses,
+        borders,
+        colors,
+        spaces
+    } = NCoreUIKitTheme.useContext();
+
+    const {
+        localize
+    } = NCoreUIKitLocalize.useContext();
+
+    const [
+        text,
+        setText
+    ] = useState<string>(initialValue);
+
+    const [
+        mode,
+        setMode
+    ] = useState<MarkdownEditorMode>(defaultMode);
+
+    const [
+        selection,
+        setSelection
+    ] = useState<{ end: number; start: number } | null>(null);
+
+    const [
+        isAutoScrollEnabled,
+        setIsAutoScrollEnabled
+    ] = useState<boolean>(true);
+
+    const previewScrollRef = useRef<ScrollView>(null);
+
+    const dynamicStyles = useStyles({
+        spreadBehaviour,
+        radiuses,
+        borders,
+        colors,
+        spaces
+    });
+
+    const handleAction = (prefix: string, suffix: string, placeholder: string) => {
+        let newText = "";
+
+        if (selection && selection.start !== selection.end) {
+            const before = text.substring(0, selection.start);
+            const selected = text.substring(selection.start, selection.end);
+            const after = text.substring(selection.end);
+
+            const hasPrefix = prefix !== "" && selected.startsWith(prefix);
+            const hasSuffix = suffix !== "" && selected.endsWith(suffix);
+
+            const hasOuterPrefix = prefix !== "" && before.endsWith(prefix);
+            const hasOuterSuffix = suffix !== "" && after.startsWith(suffix);
+
+            if (
+                (prefix === "" || hasPrefix) &&
+                (suffix === "" || hasSuffix) &&
+                (prefix !== "" || suffix !== "")
+            ) {
+                const stripped = selected.substring(prefix.length, selected.length - suffix.length);
+                newText = before + stripped + after;
+            } else if (
+                (prefix === "" || hasOuterPrefix) &&
+                (suffix === "" || hasOuterSuffix) &&
+                (prefix !== "" || suffix !== "")
+            ) {
+                const newBefore = before.substring(0, before.length - prefix.length);
+                const newAfter = after.substring(suffix.length);
+                newText = newBefore + selected + newAfter;
+            } else {
+                newText = before + prefix + selected + suffix + after;
+            }
+        } else {
+            const insertPos = selection ? selection.start : text.length;
+            const before = text.substring(0, insertPos);
+            const after = text.substring(insertPos);
+            newText = before + prefix + placeholder + suffix + after;
+        }
+
+        setText(newText);
+        onChangeText?.(newText);
+    };
+
+    const handleTypographySelect = (syntax: string) => {
+        let prefix = syntax;
+        let suffix = "";
+
+        if (syntax === "<p>") {
+            prefix = "<p>";
+            suffix = "</p>";
+        }
+
+        if (selection && selection.start !== selection.end) {
+            const before = text.substring(0, selection.start);
+            const selected = text.substring(selection.start, selection.end);
+            const after = text.substring(selection.end);
+
+            const prependNewline = before.length > 0 && !before.endsWith("\n");
+            const finalPrefix = (prependNewline ? "\n" : "") + prefix;
+
+            const appendNewline = after.length > 0 && !after.startsWith("\n");
+            const finalSuffix = suffix + (appendNewline ? "\n" : "");
+
+            const newText = before + finalPrefix + selected + finalSuffix + after;
+
+            setText(newText);
+            onChangeText?.(newText);
+        } else {
+            const insertPos = selection ? selection.start : text.length;
+            const before = text.substring(0, insertPos);
+            const after = text.substring(insertPos);
+
+            const prependNewline = before.length > 0 && !before.endsWith("\n");
+            const finalPrefix = (prependNewline ? "\n" : "") + prefix;
+
+            const newText = before + finalPrefix + suffix + after;
+
+            setText(newText);
+            onChangeText?.(newText);
+        }
+    };
+
+    const renderToolbar = () => {
+        const activeVariants = {
+            ...DEFAULT_VARIANTS,
+            ...variants
+        };
+
+        const textSyntaxKeys: TextMarkdownTypes[] = [
+            "# ",
+            "## ",
+            "### ",
+            "#### ",
+            "##### ",
+            "###### ",
+            "<p>"
+        ];
+        const typographyKeysToRender = textSyntaxKeys.map(syntax => ({
+            syntax,
+            typographyKey: activeVariants[syntax as MarkdownKeys]
+        })).filter(item => item.typographyKey);
+
+        return <View
+            style={[
+                stylesheet.toolbarContainer,
+                dynamicStyles.toolbarContainer,
+                toolbarContainerStyle
+            ]}
+        >
+            <TouchableOpacity
+                onPress={() => handleAction("**", "**", "bold")}
+                style={[
+                    stylesheet.toolbarAction,
+                    dynamicStyles.toolbarAction
+                ]}
+            >
+                <BoldIcon
+                    color={colors.content.icon.mid}
+                    size={18}
+                />
+            </TouchableOpacity>
+            <TouchableOpacity
+                onPress={() => handleAction("__", "__", "italic")}
+                style={[
+                    stylesheet.toolbarAction,
+                    dynamicStyles.toolbarAction
+                ]}
+            >
+                <ItalicIcon
+                    color={colors.content.icon.mid}
+                    size={18}
+                />
+            </TouchableOpacity>
+            <View
+                style={[
+                    stylesheet.toolbarSeparator,
+                    dynamicStyles.toolbarSeparator
+                ]}
+            />
+            <TouchableOpacity
+                onPress={() => handleAction("<link href=\"https://nibgat.com\">\n", "\n</link>", "title")}
+                style={[
+                    stylesheet.toolbarAction,
+                    dynamicStyles.toolbarAction
+                ]}
+            >
+                <LinkIcon
+                    color={colors.content.icon.mid}
+                    size={18}
+                />
+            </TouchableOpacity>
+            <TouchableOpacity
+                onPress={() => handleAction("[", "](https://nibgat.com/assets/images/logo.png)", "alt")}
+                style={[
+                    stylesheet.toolbarAction,
+                    dynamicStyles.toolbarAction
+                ]}
+            >
+                <ImageIcon
+                    color={colors.content.icon.mid}
+                    size={18}
+                />
+            </TouchableOpacity>
+            <TouchableOpacity
+                onPress={() => handleAction("```\n", "\n```", "code")}
+                style={[
+                    stylesheet.toolbarAction,
+                    dynamicStyles.toolbarAction
+                ]}
+            >
+                <CodeIcon
+                    color={colors.content.icon.mid}
+                    size={18}
+                />
+            </TouchableOpacity>
+            <TouchableOpacity
+                onPress={() => handleAction("\n* ", "", "list item")}
+                style={[
+                    stylesheet.toolbarAction,
+                    dynamicStyles.toolbarAction
+                ]}
+            >
+                <ListIcon
+                    color={colors.content.icon.mid}
+                    size={18}
+                />
+            </TouchableOpacity>
+            <TouchableOpacity
+                onPress={() => handleAction("\n<<\n", "\n>>\n", "quote")}
+                style={[
+                    stylesheet.toolbarAction,
+                    dynamicStyles.toolbarAction
+                ]}
+            >
+                <QuoteIcon
+                    color={colors.content.icon.mid}
+                    size={18}
+                />
+            </TouchableOpacity>
+            <View
+                style={[
+                    stylesheet.toolbarSeparator,
+                    dynamicStyles.toolbarSeparator
+                ]}
+            />
+            <TouchableOpacity
+                onPress={() => handleAction("<left>\n", "\n</left>", "content")}
+                style={[
+                    stylesheet.toolbarAction,
+                    dynamicStyles.toolbarAction
+                ]}
+            >
+                <AlignLeftIcon
+                    color={colors.content.icon.mid}
+                    size={18}
+                />
+            </TouchableOpacity>
+            <TouchableOpacity
+                onPress={() => handleAction("<center>\n", "\n</center>", "content")}
+                style={[
+                    stylesheet.toolbarAction,
+                    dynamicStyles.toolbarAction
+                ]}
+            >
+                <AlignCenterIcon
+                    color={colors.content.icon.mid}
+                    size={18}
+                />
+            </TouchableOpacity>
+            <TouchableOpacity
+                onPress={() => handleAction("<right>\n", "\n</right>", "content")}
+                style={[
+                    stylesheet.toolbarAction,
+                    dynamicStyles.toolbarAction
+                ]}
+            >
+                <AlignRightIcon
+                    color={colors.content.icon.mid}
+                    size={18}
+                />
+            </TouchableOpacity>
+            <View
+                style={[
+                    stylesheet.toolbarSeparator,
+                    dynamicStyles.toolbarSeparator
+                ]}
+            />
+            <ScrollView
+                horizontal
+                showsHorizontalScrollIndicator={false}
+                style={stylesheet.typographyScroll}
+            >
+                {typographyKeysToRender.map((item) => {
+                    return <TouchableOpacity
+                        key={item.typographyKey}
+                        style={[
+                            stylesheet.typographyPill,
+                            dynamicStyles.typographyPill
+                        ]}
+                        onPress={() => handleTypographySelect(item.syntax)}
+                    >
+                        <Text
+                            color="mid"
+                        >
+                            {localize(`typography-${item.typographyKey}` as Parameters<typeof localize>[0])}
+                        </Text>
+                    </TouchableOpacity>;
+                })}
+            </ScrollView>
+            <View
+                style={stylesheet.switchContainer}
+            >
+                <TouchableOpacity
+                    onPress={() => setIsAutoScrollEnabled(!isAutoScrollEnabled)}
+                    style={[
+                        stylesheet.toolbarAction,
+                        dynamicStyles.toolbarAction,
+                        {
+                            backgroundColor: isAutoScrollEnabled ? colors.content.container.primary : "transparent"
+                        }
+                    ]}
+                >
+                    {
+                        isAutoScrollEnabled ?
+                            <ChevronsDownIcon
+                                color={colors.content.text.constrastHigh}
+                                size={18}
+                            />
+                        :
+                            <ChevronDownIcon
+                                color={colors.content.icon.mid}
+                                size={18}
+                            />
+                    }
+                </TouchableOpacity>
+            </View>
+        </View>;
+    };
+
+    return <View
+        style={[
+            stylesheet.container,
+            dynamicStyles.container,
+            style
+        ]}
+    >
+        <View
+            style={[
+                stylesheet.tabsContainer,
+                dynamicStyles.tabsContainer
+            ]}
+        >
+            <TouchableOpacity
+                style={[
+                    stylesheet.tabButton,
+                    mode === "live" ? dynamicStyles.tabButtonActive : dynamicStyles.tabButtonInactive
+                ]}
+                onPress={() => setMode("live")}
+            >
+                <Text
+                    customColor={mode === "live" ? colors.content.text.emphasized : undefined}
+                    color={mode === "live" ? undefined : "mid"}
+                >
+                    {localize("live")}
+                </Text>
+            </TouchableOpacity>
+            <TouchableOpacity
+                style={[
+                    stylesheet.tabButton,
+                    mode === "write" ? dynamicStyles.tabButtonActive : dynamicStyles.tabButtonInactive
+                ]}
+                onPress={() => setMode("write")}
+            >
+                <Text
+                    customColor={mode === "write" ? colors.content.text.emphasized : undefined}
+                    color={mode === "write" ? undefined : "mid"}
+                >
+                    {localize("write")}
+                </Text>
+            </TouchableOpacity>
+            <TouchableOpacity
+                style={[
+                    stylesheet.tabButton,
+                    mode === "preview" ? dynamicStyles.tabButtonActive : dynamicStyles.tabButtonInactive
+                ]}
+                onPress={() => setMode("preview")}
+            >
+                <Text
+                    customColor={mode === "preview" ? colors.content.text.emphasized : undefined}
+                    color={mode === "preview" ? undefined : "mid"}
+                >
+                    {localize("preview")}
+                </Text>
+            </TouchableOpacity>
+        </View>
+        {
+            (mode === "live" || mode === "preview") &&
+                <View
+                    style={[
+                        stylesheet.previewContainer,
+                        dynamicStyles.previewContainer,
+                        mode === "live" ? {
+                            marginBottom: 10,
+                            minHeight: 100,
+                            height: 250,
+                            overflow: "hidden",
+                            ...(isViewerResizable ? webStyle({
+                                resize: "vertical"
+                            }) : {})
+                        } : {}
+                    ]}
+                >
+                    {
+                        mode === "live" ?
+                            <ScrollView
+                                ref={previewScrollRef}
+                                onContentSizeChange={() => {
+                                    if (isAutoScrollEnabled) {
+                                        previewScrollRef.current?.scrollToEnd({
+                                            animated: true
+                                        });
+                                    }
+                                }}
+                            >
+                                <MarkdownViewer
+                                    variants={variants}
+                                    content={text}
+                                />
+                            </ScrollView>
+                        :
+                            <MarkdownViewer
+                                variants={variants}
+                                content={text}
+                            />
+                    }
+                </View>
+        }
+        {
+            (mode === "live" || mode === "write") &&
+                <View>
+                    {renderToolbar()}
+                    <TextInput
+                        {...props}
+                        multiline={true}
+                        value={text}
+                        placeholderTextColor={colors.content.text.mid}
+                        onSelectionChange={(e) => {
+                            setSelection(e.nativeEvent.selection);
+                            props.onSelectionChange?.(e);
+                        }}
+                        onChangeText={(val) => {
+                            setText(val);
+                            onChangeText?.(val);
+                        }}
+                        style={[
+                            stylesheet.editorInput,
+                            dynamicStyles.editorInput,
+                            isEditorResizable ? webStyle({
+                                resize: "vertical"
+                            }) : {},
+                            style
+                        ]}
+                    />
+                </View>
+        }
+    </View>;
+};
+export default MarkdownEditor;

+ 140 - 0
src/components/markdownEditor/stylesheet.ts

@@ -0,0 +1,140 @@
+import {
+    type ViewStyle,
+    StyleSheet
+} from "react-native";
+import type {
+    MarkdownDynamicStyles
+} from "./type";
+import type {
+    Mutable
+} from "../../types";
+
+const stylesheet = StyleSheet.create({
+    typographyScroll: {
+        paddingHorizontal: 8,
+        flexDirection: "row"
+    },
+    toolbarContainer: {
+        borderBottomWidth: 0,
+        paddingHorizontal: 8,
+        flexDirection: "row",
+        alignItems: "center",
+        paddingVertical: 4,
+        flexWrap: "wrap"
+    },
+    toolbarSeparator: {
+        marginHorizontal: 6,
+        height: 18
+    },
+    previewContainer: {
+        minHeight: 150
+    },
+    typographyPill: {
+        justifyContent: "center",
+        paddingHorizontal: 10,
+        alignItems: "center",
+        paddingVertical: 4,
+        marginRight: 6,
+        borderWidth: 0
+    },
+    toolbarAction: {
+        justifyContent: "center",
+        alignItems: "center",
+        marginHorizontal: 2,
+        padding: 6
+    },
+    tabsContainer: {
+        flexDirection: "row"
+    },
+    switchContainer: {
+        justifyContent: "center",
+        marginLeft: "auto",
+        paddingRight: 8
+    },
+    editorInput: {
+        textAlignVertical: "top",
+        minHeight: 100,
+        height: 250
+    },
+    tabButton: {
+        paddingHorizontal: 16,
+        paddingVertical: 10
+    },
+    container: {
+        width: "100%"
+    }
+});
+
+export const useStyles = ({
+    spreadBehaviour,
+    radiuses,
+    borders,
+    colors,
+    spaces
+}: MarkdownDynamicStyles) => {
+    const styles = {
+        container: {
+            alignSelf: "auto"
+        } as Mutable<ViewStyle>,
+        tabButtonInactive: {
+            borderBottomColor: "transparent"
+        },
+        toolbarContainer: {
+            backgroundColor: colors.content.container.subtle,
+            borderColor: colors.content.border.subtle,
+            borderTopRightRadius: radiuses.form,
+            borderTopLeftRadius: radiuses.form,
+            borderWidth: borders.line
+        },
+        toolbarSeparator: {
+            backgroundColor: colors.content.border.subtle,
+            width: borders.line
+        },
+        toolbarAction: {
+            borderRadius: radiuses.actions
+        },
+        previewContainer: {
+            backgroundColor: colors.content.container.default,
+            borderColor: colors.content.border.subtle,
+            borderRadius: radiuses.form,
+            borderWidth: borders.line,
+            padding: spaces.spacingMd
+        },
+        tabButtonActive: {
+            borderBottomColor: colors.content.container.primary
+        },
+        tabButton: {
+            borderBottomWidth: borders.indicator
+        },
+        typographyPill: {
+            backgroundColor: colors.content.container.subtle,
+            borderColor: colors.content.border.subtle,
+            borderRadius: radiuses.chip
+        },
+        tabsContainer: {
+            borderBottomColor: colors.content.border.subtle,
+            borderBottomWidth: borders.line,
+            marginBottom: spaces.spacingSm
+        },
+        editorInput: {
+            backgroundColor: colors.content.container.default,
+            borderColor: colors.content.border.subtle,
+            borderBottomRightRadius: radiuses.form,
+            borderBottomLeftRadius: radiuses.form,
+            color: colors.content.text.high,
+            borderWidth: borders.line,
+            padding: spaces.spacingMd
+        }
+    };
+
+    if (spreadBehaviour === "baseline") {
+        styles.container.alignSelf = spreadBehaviour;
+        styles.container.width = "auto";
+    } else if (spreadBehaviour === "stretch") {
+        styles.container.alignSelf = spreadBehaviour;
+        styles.container.width = "100%";
+    }
+
+    return styles;
+};
+export default stylesheet;

+ 34 - 0
src/components/markdownEditor/type.ts

@@ -0,0 +1,34 @@
+import type {
+    TextInputProps,
+    StyleProp,
+    ViewStyle
+} from "react-native";
+import type {
+    MarkdownKeys
+} from "../markdownViewer/type";
+
+export type MarkdownEditorMode = "live" | "write" | "preview";
+
+export type MarkdownEditorSpreadBehaviour = "baseline" | "stretch" | "free";
+
+export type MarkdownDynamicStyles = {
+    spreadBehaviour?: MarkdownEditorSpreadBehaviour;
+    radiuses: NCoreUIKit.ActivePalette["radiuses"];
+    borders: NCoreUIKit.ActivePalette["borders"];
+    colors: NCoreUIKit.ActivePalette["colors"];
+    spaces: NCoreUIKit.ActivePalette["spaces"];
+};
+
+interface IMarkdownEditorProps extends TextInputProps {
+    variants?: Partial<Record<MarkdownKeys, keyof NCoreUIKit.Typography>>;
+    spreadBehaviour?: MarkdownEditorSpreadBehaviour;
+    toolbarContainerStyle?: StyleProp<ViewStyle>;
+    defaultMode?: MarkdownEditorMode;
+    isViewerResizable?: boolean;
+    isEditorResizable?: boolean;
+    initialValue?: string;
+};
+
+export type {
+    IMarkdownEditorProps as default
+};

+ 89 - 86
src/components/markdownViewer/index.tsx

@@ -1,5 +1,4 @@
 import {
-    useEffect,
     useState,
     type FC
 } from "react";
@@ -7,14 +6,15 @@ import {
     type DimensionValue,
     Text as NativeText,
     TouchableOpacity,
+    type ImageProps,
     Linking,
     Image,
     View
 } from "react-native";
 import type IMarkdownViewerProps from "./type";
 import type {
-    MarkdownObject,
-    TextMarkdownTypes
+    TextMarkdownTypes,
+    MarkdownObject
 } from "./type";
 import stylesheet, {
     useStyles
@@ -29,11 +29,74 @@ import type ITextProps from "../text/type";
 import {
     Quote as QuoteIcon
 } from "lucide-react-native";
+import CodeViewer from "../codeViewer";
 import Text from "../text";
 
+const MarkdownImage: FC<{
+    containerWidth: number | null;
+    imageProps?: ImageProps;
+    node: MarkdownObject;
+}> = ({
+    containerWidth,
+    imageProps,
+    node
+}) => {
+    const [imgSize,
+        setImgSize] = useState<{
+        height: number | string;
+        width: number | string;
+        isSetted: boolean;
+    }>({
+        isSetted: false,
+        width: "100%",
+        height: 0
+    });
+
+    const targetWidth = node.size ? node.size[0] : imgSize.width;
+    const targetHeight = node.size ? node.size[1] : imgSize.height;
+
+    const currentWidth = typeof targetWidth === "number" || (typeof targetWidth === "string" && targetWidth.indexOf("%") === -1) || !containerWidth
+        ? targetWidth
+        : (containerWidth * Number((targetWidth as string).split("%")[0])) / 100;
+
+    const currentHeight = typeof targetHeight === "number" || (typeof targetHeight === "string" && targetHeight.indexOf("%") === -1) || !containerWidth
+        ? targetHeight
+        : (containerWidth * Number((targetHeight as string).split("%")[0])) / 100;
+
+    return <Image
+        {...imageProps}
+        alt={node.content}
+        source={{
+            uri: node.url
+        }}
+        resizeMode={node.resizeMode ? node.resizeMode : "contain"}
+        onLoad={(event) => {
+            if (!node.size) {
+                const nativeEvent = event.nativeEvent as unknown as {
+                    source?: { height: number; width: number };
+                    height?: number;
+                    width?: number;
+                };
+                const height = nativeEvent.source?.height || nativeEvent.height || 0;
+                const width = nativeEvent.source?.width || nativeEvent.width || 0;
+                setImgSize({
+                    isSetted: true,
+                    height,
+                    width
+                });
+            }
+        }}
+        style={{
+            ...stylesheet.image,
+            height: currentHeight as DimensionValue,
+            width: currentWidth as DimensionValue,
+            ...imageProps?.style
+        }}
+    />;
+};
+
 const MarkdownViewer: FC<IMarkdownViewerProps> = ({
     blockquoteIconSize = "titleLargeSize",
-    codeTextColor = "emphasized",
     blockquoteIconColor = "mid",
     blockquoteTextColor = "mid",
     blockquoteContainerProps,
@@ -55,11 +118,11 @@ const MarkdownViewer: FC<IMarkdownViewerProps> = ({
     enterTextProps,
     boldTextProps,
     listIconProps,
-    codeTextProps,
     listTextProps,
     italicStyle,
     imageProps,
     boldStyle,
+    variants,
     content,
     style,
     ...props
@@ -78,8 +141,7 @@ const MarkdownViewer: FC<IMarkdownViewerProps> = ({
 
     const {
         blockquoteContainer: blockquoteContainerDynamicStyle,
-        blockquoteIcon: blockquoteIconDynamicStyle,
-        codeContainer: codeContainerDynamicStyle
+        blockquoteIcon: blockquoteIconDynamicStyle
     } = useStyles({
         radiuses,
         colors,
@@ -150,7 +212,7 @@ const MarkdownViewer: FC<IMarkdownViewerProps> = ({
         node: MarkdownObject
     }) => {
         let textProps: ITextProps = {
-            variant: node.variant
+            variant: (variants as Record<string, keyof NCoreUIKit.Typography>)?.[node.nativeType] || node.variant
         };
 
         if(customTextStyles && customTextStyles[node.nativeType as TextMarkdownTypes]) {
@@ -187,7 +249,7 @@ const MarkdownViewer: FC<IMarkdownViewerProps> = ({
             style={[
                 stylesheet.enter,
                 {
-                    height: typography[node.variant as keyof NCoreUIKit.Typography].fontSize
+                    height: typography[((variants as Record<string, keyof NCoreUIKit.Typography>)?.[node.nativeType] || node.variant) as keyof NCoreUIKit.Typography].fontSize
                 },
                 enterTextProps?.style
             ]}
@@ -217,7 +279,7 @@ const MarkdownViewer: FC<IMarkdownViewerProps> = ({
             />
             <Text
                 color={blockquoteTextColor}
-                variant={node.variant}
+                variant={(variants as Record<string, keyof NCoreUIKit.Typography>)?.[node.nativeType] || node.variant}
                 style={{
                     ...stylesheet.blockquoteText,
                     ...blockquoteTextStyle
@@ -228,72 +290,16 @@ const MarkdownViewer: FC<IMarkdownViewerProps> = ({
         </View>;
     };
 
-    const renderImage = ({
+    const renderImageComponent = ({
         node
     }: {
         node: MarkdownObject
     }) => {
-        const [
-            imgSize,
-            setImgSize
-        ] = useState<{
-            height: number | string;
-            width: number | string;
-            isSetted: boolean;
-        }>({
-            isSetted: false,
-            width: "100%",
-            height: 0
-        });
-
-        useEffect(() => {
-            if(!imgSize.isSetted && node.size) {
-                setImgSize({
-                    height: node.size[1] as number | string,
-                    width: node.size[0] as number | string,
-                    isSetted: true
-                });
-            }
-        }, [
-            imgSize
-        ]);
-
-        const currentWidth = typeof imgSize.width === "number" || imgSize.width.indexOf("%") === -1 || !containerWidth
-            ? imgSize.width
-            : (containerWidth * Number(imgSize.width.split("%")[0])) / 100;
-
-        const currentHeight = typeof imgSize.height === "number" || imgSize.height.indexOf("%") === -1 || !containerWidth
-            ? imgSize.height
-            : (containerWidth * Number(imgSize.height.split("%")[0])) / 100;
-
-        return <Image
-            {...imageProps}
-            alt={node.content}
+        return <MarkdownImage
+            node={node}
+            imageProps={imageProps}
+            containerWidth={containerWidth}
             key={node.key}
-            source={{
-                uri: node.url
-            }}
-            resizeMode={node.resizeMode ? node.resizeMode : "contain"}
-            onLoad={(event) => {
-                if(!node.size) {
-                    const {
-                        height,
-                        width
-                    } = event.nativeEvent.source;
-
-                    setImgSize({
-                        isSetted: true,
-                        height,
-                        width
-                    });
-                }
-            }}
-            style={{
-                ...stylesheet.image,
-                height: currentHeight as DimensionValue,
-                width: currentWidth as DimensionValue,
-                ...imageProps?.style
-            }}
         />;
     };
 
@@ -307,18 +313,21 @@ const MarkdownViewer: FC<IMarkdownViewerProps> = ({
             key={node.key}
             style={[
                 stylesheet.listContainer,
-                listContainerProps?.style
+                listContainerProps?.style,
+                {
+                    paddingLeft: (node.indent || 0) * 8
+                }
             ]}
         >
             <Text
                 {...listIconProps}
-                variant={node.variant}
+                variant={(variants as Record<string, keyof NCoreUIKit.Typography>)?.[node.nativeType] || node.variant}
             >
                 •{" "}
             </Text>
             <Text
                 {...listTextProps}
-                variant={node.variant}
+                variant={(variants as Record<string, keyof NCoreUIKit.Typography>)?.[node.nativeType] || node.variant}
             >
                 {renderInlineStyles(node.content)}
             </Text>
@@ -333,18 +342,12 @@ const MarkdownViewer: FC<IMarkdownViewerProps> = ({
         return <View
             {...codeContainerProps}
             key={node.key}
-            style={[
-                codeContainerDynamicStyle,
-                codeContainerProps?.style
-            ]}
+            style={codeContainerProps?.style}
         >
-            <Text
-                {...codeTextProps}
-                variant={node.variant}
-                color={codeTextColor}
-            >
-                {node.content}
-            </Text>
+            <CodeViewer
+                language={node.language}
+                code={node.content}
+            />
         </View>;
     };
 
@@ -489,7 +492,7 @@ const MarkdownViewer: FC<IMarkdownViewerProps> = ({
                     });
                 }
                 case "image": {
-                    return renderImage({
+                    return renderImageComponent({
                         node
                     });
                 }

+ 0 - 5
src/components/markdownViewer/stylesheet.ts

@@ -59,11 +59,6 @@ export const useStyles = ({
         },
         blockquoteIcon: {
             marginBottom: spaces.spacingXs
-        },
-        codeContainer: {
-            backgroundColor: colors.content.container.mid,
-            borderRadius: radiuses.form,
-            padding: spaces.spacingMd
         }
     };
 

+ 4 - 3
src/components/markdownViewer/type.ts

@@ -21,6 +21,8 @@ export type MarkdownObject = {
     nativeType: MarkdownKeys | "image" | "center" | "right" | "left" | "link";
     variant?: keyof NCoreUIKit.Typography;
     size?: Array<number | string>;
+    language?: string;
+    indent?: number;
     content: string;
     url?: string;
     key: number;
@@ -45,11 +47,11 @@ export type ListTypes = "* " | "- ";
 export type MarkdownKeys = TextMarkdownTypes | EnterMarkdownTypes | CodeMarkdownTypes | BlockquoteTypes | ListTypes;
 
 interface IMarkdownViewerProps extends ViewProps {
+    variants?: Partial<Record<MarkdownKeys, keyof NCoreUIKit.Typography>>;
     blockquoteIconStyle?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
     blockquoteTextColor?: keyof NCoreUIKit.TextContentColors;
     blockquoteIconColor?: keyof NCoreUIKit.IconContentColors;
     style?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
-    codeTextColor?: keyof NCoreUIKit.TextContentColors;
     blockquoteIconSize?: keyof NCoreUIKit.Typography;
     linkContainerProps?: TouchableOpacityProps;
     centerMarkdownProps?: IMarkdownViewerProps;
@@ -65,7 +67,6 @@ interface IMarkdownViewerProps extends ViewProps {
     listContainerProps?: ViewProps;
     italicTextProps?: TextProps;
     enterTextProps?: ITextProps;
-    codeTextProps?: ITextProps;
     listTextProps?: ITextProps;
     listIconProps?: ITextProps;
     boldTextProps?: TextProps;
@@ -78,8 +79,8 @@ interface IMarkdownViewerProps extends ViewProps {
         TextMarkdownTypes,
         ITextProps["style"]
     >;
-    italicStyle?: TextStyle;
     boldStyle?: TextStyle;
+    italicStyle?: TextStyle;
     content: string;
 };
 export type {

+ 32 - 10
src/components/markdownViewer/util.ts

@@ -49,12 +49,17 @@ export const textMarkdown = ({
     index: number;
     line: string;
 }): MarkdownObject => {
+    let content = line.replace(type, "");
+    if (type === "<p>") {
+        content = content.replace("</p>", "");
+    }
+
     return {
-        content: line.replace(type, ""),
         variant: DEFAULT_VARIANTS[type],
         nativeType: type,
         type: "text",
-        key: index
+        key: index,
+        content
     };
 };
 
@@ -101,7 +106,11 @@ export const codeMarkdown = ({
 
         const codeContent = lines.slice(index + 1, endIndex).join("\n");
 
+        const languageMatch = lines[index]?.match(/^```(.*)/);
+        const language = languageMatch && languageMatch[1] ? languageMatch[1].trim() : "";
+
         return {
+            language: language !== "" ? language : undefined,
             variant: DEFAULT_VARIANTS["```"],
             content: codeContent,
             nativeType: "```",
@@ -292,19 +301,22 @@ export const blockquoteMarkdown = ({
 
 export const listMarkdown = ({
     isStarList,
+    indent,
     index,
     line
 }: {
     isStarList: boolean;
+    indent: number;
     index: number;
     line: string;
 }): MarkdownObject => {
     return {
         variant: DEFAULT_VARIANTS[isStarList ? "* " : "- "],
         nativeType: isStarList ? "* " : "- ",
-        content: line.substring(2),
+        content: line,
         type: "list",
-        key: index
+        key: index,
+        indent
     };
 };
 
@@ -358,6 +370,12 @@ export const parseMarkdown = (rawText: string): Array<MarkdownObject> => {
             line
         });
 
+        if (line.startsWith("<p>")) return textMarkdown({
+            type: "<p>",
+            index,
+            line
+        });
+
         if (line.startsWith("<br/>") || line === "") return enterMarkdown({
             index,
             line
@@ -434,13 +452,17 @@ export const parseMarkdown = (rawText: string): Array<MarkdownObject> => {
             line
         });
 
-        const isStarList = line.startsWith("* ");
+        const listMatch = line.match(/^(\s*)(?:\*|-)\s(.*)/);
 
-        if (isStarList || line.startsWith("- ")) return listMarkdown({
-            isStarList,
-            index,
-            line
-        });
+        if (listMatch) {
+            const isStarList = line.trim().startsWith("*");
+            return listMarkdown({
+                indent: listMatch[1]?.length ?? 0,
+                line: listMatch[2] ?? "",
+                isStarList,
+                index
+            });
+        }
 
         return {
             variant: DEFAULT_VARIANTS["<p>"],

+ 1 - 1
src/components/menu/components/menuButton/index.tsx

@@ -259,7 +259,7 @@ const MenuButton: FC<IMenuButton> = ({
                         />;
                     })}
                 </Animated.View>
-                :
+            :
                 null
         }
     </View>;

+ 24 - 14
src/components/menu/index.tsx

@@ -290,20 +290,30 @@ const Menu: RefForwardingComponent<IMenuRef, IMenuProps> = ({
                 headerContainerDynamicStyle
             ]}
         >
-            {renderSiteLogo ? renderSiteLogo() : <SiteLogo
-                customLocalize={customLocalize}
-                customTheme={customTheme}
-                {...siteLogoProps}
-            />}
-            {renderHeaderSeperator ? renderHeaderSeperator() : <Seperator
-                {...seperatorProps}
-                length="100%"
-                style={[
-                    seperatorProps?.style,
-                    stylesheet.seperator,
-                    seperatorDynamicStyle
-                ]}
-            />}
+            {
+                renderSiteLogo ?
+                    renderSiteLogo()
+                :
+                    <SiteLogo
+                        customLocalize={customLocalize}
+                        customTheme={customTheme}
+                        {...siteLogoProps}
+                    />
+            }
+            {
+                renderHeaderSeperator ?
+                    renderHeaderSeperator()
+                :
+                    <Seperator
+                        {...seperatorProps}
+                        length="100%"
+                        style={[
+                            seperatorProps?.style,
+                            stylesheet.seperator,
+                            seperatorDynamicStyle
+                        ]}
+                    />
+            }
         </View>;
     };
 

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

@@ -359,16 +359,21 @@ const MonthSelector = ({
             >
                 {monthItem.title}
             </Text>
-            {isShowTodayIndicator && monthItem.isToday ? <View
-                style={[
-                    stylesheet.todayIndicator,
-                    selectionStyle,
-                    todayIndicatorDynamicStyle,
+            {
+                isShowTodayIndicator && monthItem.isToday ?
+                    <View
+                        style={[
+                            stylesheet.todayIndicator,
+                            selectionStyle,
+                            todayIndicatorDynamicStyle,
                     monthItem.isSelected ? {
                         borderColor: colors.content.border.subtle
                     } : null
-                ]}
-            /> : null}
+                        ]}
+                    />
+                :
+                    null
+            }
         </TouchableOpacity>;
     };
 

+ 11 - 14
src/components/numericInput/index.tsx

@@ -396,15 +396,17 @@ const NumericInput: RefForwardingComponent<INumericInputRef, ITextInputProps> =
                 hideTextIconContainerDynamicStyle
             ]}
         >
-            {hideValue ?
-                <EyeIcon
-                    color={colors.content.icon[iconProps.color]}
-                    size={20}
-                /> :
-                <EyeClosedIcon
-                    color={colors.content.icon[iconProps.color]}
-                    size={20}
-                />
+            {
+                hideValue ?
+                    <EyeIcon
+                        color={colors.content.icon[iconProps.color]}
+                        size={20}
+                    />
+                :
+                    <EyeClosedIcon
+                        color={colors.content.icon[iconProps.color]}
+                        size={20}
+                    />
             }
         </TouchableOpacity>;
     };
@@ -594,7 +596,6 @@ const NumericInput: RefForwardingComponent<INumericInputRef, ITextInputProps> =
         })}
     >
         {renderTitle()}
-
         <View
             style={[
                 contentContainerStyle,
@@ -603,16 +604,12 @@ const NumericInput: RefForwardingComponent<INumericInputRef, ITextInputProps> =
             ]}
         >
             {renderIcon()}
-
             {renderInput()}
-
             {renderCleanButton()}
             {renderHideTextIcon()}
             {renderRightIcon()}
-
             {renderOverlay()}
         </View>
-
         {renderHintText()}
     </TouchableOpacity>;
 };

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

@@ -190,7 +190,6 @@ const RadioButton: FC<IRadioButtonProps> = ({
             ]}
         >
             {renderIndicator()}
-
             {renderOverlay()}
         </View>;
     };
@@ -256,9 +255,7 @@ const RadioButton: FC<IRadioButtonProps> = ({
         })}
     >
         {isFlip ? null : renderIndicatorContainer()}
-
         {renderContent()}
-
         {isFlip ? renderIndicatorContainer() : null}
     </TouchableOpacity>;
 };

+ 0 - 6
src/components/selectBox/index.tsx

@@ -801,7 +801,6 @@ function SelectBox<T>({
         ]}
     >
         {renderTitle()}
-
         <TouchableOpacity
             disabled={isDisabled}
             style={[
@@ -816,17 +815,12 @@ function SelectBox<T>({
             }}
         >
             {renderOverlay()}
-
             {renderIcon()}
-
             {renderContent()}
-
             {renderCleanButton()}
             {renderRightIcon()}
         </TouchableOpacity>
-
         {renderHintText()}
-
         <SelectSheet
             LoadingIconComponentProp={LoadingIconComponentProp}
             customLocalize={customSelectSheetLocalize}

+ 59 - 35
src/components/selectSheet/index.tsx

@@ -97,10 +97,15 @@ function SelectSheet<T>({
                     loadingContainerDynamicStyle
                 ]}
             >
-                {LoadingIconComponentProp ? <LoadingIconComponentProp
-                    color="emphasized"
-                    size={20}
-                /> : <Loading/>}
+                {
+                    LoadingIconComponentProp ?
+                        <LoadingIconComponentProp
+                            color="emphasized"
+                            size={20}
+                        />
+                    :
+                        <Loading/>
+                }
             </View>;
         }
 
@@ -183,21 +188,30 @@ function SelectSheet<T>({
                                 checkIconContainerDynamicStyle
                             ]}
                         >
-                            {isSelected ?
-                                <CheckIcon
-                                    color={colors.content.icon.emphasized}
-                                    size={24}
-                                /> : null}
+                            {
+                                isSelected ?
+                                    <CheckIcon
+                                        color={colors.content.icon.emphasized}
+                                        size={24}
+                                    />
+                                :
+                                    null
+                            }
                         </View>
-                        {isDisabled ? <View
-                            style={[
-                                stylesheet.disabledOverlay,
-                                {
-                                    backgroundColor: colors.system.disabled.content,
-                                    borderRadius: radiuses.actions
-                                }
-                            ]}
-                        /> : null}
+                        {
+                            isDisabled ?
+                                <View
+                                    style={[
+                                        stylesheet.disabledOverlay,
+                                        {
+                                            backgroundColor: colors.system.disabled.content,
+                                            borderRadius: radiuses.actions
+                                        }
+                                    ]}
+                                />
+                            :
+                                null
+                        }
                     </TouchableOpacity>;
                 })
             }
@@ -239,23 +253,33 @@ function SelectSheet<T>({
                 toolsContainerDynamicStyle
             ]}
         >
-            {!minChoice ? <CheckBox
-                isChecked={mainSelectedItems.length === 0 ? "checked" : null}
-                title={localize("clean-all")}
-                spreadBehaviour="free"
-                onPress={() => {
-                    cleanAll();
-                }}
-            /> : null}
-            {maxChoice === -1 ? <CheckBox
-                isChecked={data.length === mainSelectedItems.length ? "checked" : mainSelectedItems.length ? "partially" : null}
-                title={localize("select-all")}
-                spreadBehaviour="free"
-                isFlip={!minChoice}
-                onPress={() => {
-                    selectAll();
-                }}
-            /> : null}
+            {
+                !minChoice ?
+                    <CheckBox
+                        isChecked={mainSelectedItems.length === 0 ? "checked" : null}
+                        title={localize("clean-all")}
+                        spreadBehaviour="free"
+                        onPress={() => {
+                            cleanAll();
+                        }}
+                    />
+                :
+                    null
+            }
+            {
+                maxChoice === -1 ?
+                    <CheckBox
+                        isChecked={data.length === mainSelectedItems.length ? "checked" : mainSelectedItems.length ? "partially" : null}
+                        title={localize("select-all")}
+                        spreadBehaviour="free"
+                        isFlip={!minChoice}
+                        onPress={() => {
+                            selectAll();
+                        }}
+                    />
+                :
+                    null
+            }
         </View>;
     };
 

+ 1 - 1
src/components/siteLogo/index.tsx

@@ -227,7 +227,7 @@ const SiteLogo = ({
                     >
                         {subTitleKey ? subTitleKey : subTitle}
                     </Text>
-                    :
+                :
                     null
             }
         </View>;

+ 1 - 1
src/components/snackBar/index.tsx

@@ -278,7 +278,7 @@ const SnackBar: FC<ISnackBarProps> = ({
                     >
                         {subTitle}
                     </Text>
-                    :
+                :
                     null
             }
         </View>;

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

@@ -211,7 +211,6 @@ const Switch: FC<ISwitchProps> = ({
             ]}
         >
             {renderIndicator()}
-
             {renderOverlay()}
         </View>;
     };
@@ -277,9 +276,7 @@ const Switch: FC<ISwitchProps> = ({
         })}
     >
         {isFlip ? null : renderIndicatorContainer()}
-
         {renderContent()}
-
         {isFlip ? renderIndicatorContainer() : null}
     </TouchableOpacity>;
 };

+ 188 - 0
src/components/systemToolbar/index.tsx

@@ -0,0 +1,188 @@
+import {
+    useMemo,
+    type FC
+} from "react";
+import {
+    Pressable,
+    View
+} from "react-native";
+import type ISystemToolbarProps from "./type";
+import {
+    type ISystemToolbarAction
+} from "./type";
+import stylesheet, {
+    useStyles
+} from "./stylesheet";
+import {
+    NCoreUIKitLocalize,
+    NCoreUIKitTheme
+} from "../../core/hooks";
+import Tooltip from "../tooltip";
+import Button from "../button";
+import Text from "../text";
+
+const ActionItem: FC<{ action: ISystemToolbarAction }> = ({
+    action
+}) => {
+    const {
+        localize
+    } = NCoreUIKitLocalize.useContext();
+
+    const {
+        borders,
+        colors,
+        spaces
+    } = NCoreUIKitTheme.useContext();
+
+    const {
+        tooltipContainer: tooltipContainerDynamicStyle,
+        childCaret: childCaretDynamicStyle,
+        actionItem: actionItemDynamicStyle
+    } = useStyles({
+        borders,
+        colors,
+        spaces
+    });
+
+    const pressableStyle = useMemo(() => {
+        return [
+            stylesheet.systemToolbarAction,
+            actionItemDynamicStyle,
+            action.style
+        ];
+    }, [
+        actionItemDynamicStyle,
+        action.style
+    ]);
+
+    const titleText = action.titleKey ? localize(action.titleKey) : undefined;
+    const ActionIcon = action.icon;
+
+    const btn = <Pressable
+        onPress={action.onPress}
+        style={pressableStyle}
+    >
+        {
+            ActionIcon ?
+                <ActionIcon
+                    color="mid"
+                    size={16}
+                />
+            :
+                null
+        }
+        {
+            titleText ?
+                <Text
+                    variant="labelMediumSize"
+                    style={action.titleProps}
+                >
+                    {titleText}
+                </Text>
+            :
+                null
+        }
+    </Pressable>;
+
+    if (!action.content || action.content.length === 0) {
+        return btn;
+    }
+
+    return <Tooltip
+        content={<View
+            style={stylesheet.systemToolbarContent}
+        >
+            {action.content.map((childAction, index) => <ActionItem
+                key={`system-toolbar-child-action-${index}`}
+                action={childAction}
+            />)}
+        </View>}
+        containerStyle={tooltipContainerDynamicStyle}
+        caretStyle={childCaretDynamicStyle}
+        location={{
+            horizontal: "right",
+            vertical: "center"
+        }}
+        triggerMode="hover"
+        sizing="content"
+    >
+        {btn}
+    </Tooltip>;
+};
+
+const SystemToolbar: FC<ISystemToolbarProps> = ({
+    variant = "filled",
+    type = "neutral",
+    size = "medium",
+    titleKey,
+    actions,
+    style,
+    title,
+    icon
+}) => {
+    const {
+        localize
+    } = NCoreUIKitLocalize.useContext();
+
+    const {
+        borders,
+        colors,
+        spaces
+    } = NCoreUIKitTheme.useContext();
+
+    const {
+        tooltipContainer: tooltipContainerDynamicStyle,
+        triggerBtn: triggerBtnDynamicStyle,
+        rootCaret: rootCaretDynamicStyle
+    } = useStyles({
+        borders,
+        colors,
+        spaces
+    });
+
+    const mainTitle = titleKey ? localize(titleKey) : title;
+
+    const triggerBtn = <Button
+        onPress={() => {
+            // Dropdown triggers typically don't have a main action unless specified.
+            // Wait, we don't have onPress on the root SystemToolbar based on user request.
+        }}
+        customColor={colors.content.container.default}
+        style={[
+            style,
+            triggerBtnDynamicStyle
+        ]}
+        isCustomPadding={true}
+        variant={variant}
+        title={mainTitle}
+        size={size}
+        type={type}
+        icon={icon}
+    />;
+
+    if (!actions || actions.length === 0) {
+        return triggerBtn;
+    }
+
+    return <Tooltip
+        content={<View
+            style={stylesheet.systemToolbarContent}
+        >
+            {actions.map((action, index) => <ActionItem
+                key={`system-toolbar-action-${index}`}
+                action={action}
+            />)}
+        </View>}
+        containerStyle={tooltipContainerDynamicStyle}
+        caretStyle={rootCaretDynamicStyle}
+        location={{
+            horizontal: "center",
+            vertical: "bottom"
+        }}
+        triggerMode="hover"
+        sizing="content"
+    >
+        {triggerBtn}
+    </Tooltip>;
+};
+export default SystemToolbar;

+ 59 - 0
src/components/systemToolbar/stylesheet.ts

@@ -0,0 +1,59 @@
+import {
+    type ViewStyle,
+    StyleSheet
+} from "react-native";
+import type {
+    SystemToolbarDynamicStyleType
+} from "./type";
+import type {
+    Mutable
+} from "../../types";
+
+const stylesheet = StyleSheet.create({
+    systemToolbarAction: {
+        justifyContent: "flex-start",
+        flexDirection: "row",
+        alignItems: "center"
+    },
+    systemToolbarContent: {
+        minWidth: 100,
+        gap: 2
+    }
+});
+
+export const useStyles = ({
+    borders,
+    colors,
+    spaces
+}: SystemToolbarDynamicStyleType) => {
+    const styles = {
+        tooltipContainer: {
+            backgroundColor: colors.content.container.default,
+            borderColor: colors.content.border.default,
+            borderWidth: borders.line
+        } as Mutable<ViewStyle>,
+        childCaret: {
+            backgroundColor: colors.content.container.default,
+            borderColor: colors.content.border.default,
+            borderBottomWidth: borders.line,
+            borderLeftWidth: borders.line
+        } as Mutable<ViewStyle>,
+        rootCaret: {
+            backgroundColor: colors.content.container.default,
+            borderColor: colors.content.border.default,
+            borderLeftWidth: borders.line,
+            borderTopWidth: borders.line
+        } as Mutable<ViewStyle>,
+        actionItem: {
+            paddingHorizontal: spaces.spacingSm,
+            paddingVertical: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        triggerBtn: {
+            paddingHorizontal: spaces.spacingMd,
+            paddingVertical: spaces.spacingSm
+        } as Mutable<ViewStyle>
+    };
+
+    return styles;
+};
+export default stylesheet;

+ 43 - 0
src/components/systemToolbar/type.ts

@@ -0,0 +1,43 @@
+import {
+    type StyleProp,
+    type TextStyle,
+    type ViewStyle
+} from "react-native";
+import {
+    type NCoreUIKitIcon
+} from "../../types";
+import {
+    type ButtonVariant,
+    type ButtonSize,
+    type ButtonType
+} from "../button/type";
+
+export interface SystemToolbarDynamicStyleType {
+    borders: NCoreUIKit.ActivePalette["borders"];
+    colors: NCoreUIKit.ActivePalette["colors"];
+    spaces: NCoreUIKit.ActivePalette["spaces"];
+}
+
+export interface ISystemToolbarAction {
+    titleKey?: keyof NCoreUIKit.Translation;
+    titleProps?: StyleProp<TextStyle>;
+    content?: ISystemToolbarAction[];
+    style?: StyleProp<ViewStyle>;
+    icon?: NCoreUIKitIcon;
+    onPress?: () => void;
+}
+
+export interface ISystemToolbarProps {
+    titleKey?: keyof NCoreUIKit.Translation;
+    actions: ISystemToolbarAction[];
+    style?: StyleProp<ViewStyle>;
+    variant?: ButtonVariant;
+    icon?: NCoreUIKitIcon;
+    size?: ButtonSize;
+    type?: ButtonType;
+    title?: string;
+}
+
+export type {
+    ISystemToolbarProps as default
+};

+ 55 - 42
src/components/textAreaInput/index.tsx

@@ -54,8 +54,8 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
     rightIcon: RightIconComponentProp,
     hintTextIcon: HintTextIconProp,
     spreadBehaviour = "baseline",
-    isShowLengthLimiter = true,
     isShowHintTextIcon = false,
+    isShowLengthLimiter = true,
     isUpdateOnRealtime = false,
     icon: IconComponentProp,
     hintTextContainerStyle,
@@ -63,27 +63,31 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
     contentContainerStyle,
     subTitle = "Optional",
     onFocus: onFocusProp,
-    isRequired = false,
     isDisabled = false,
+    isRequired = false,
     onBlur: onBlurProp,
-    type = "default",
+    customBorderColor,
+    customTitleColor,
     rightIconOnPress,
+    type = "default",
+    customIconColor,
     maxHeight = 350,
     minHeight = 250,
+    cleanIconStyle,
     customLocalize,
-    rightIconStyle,
     isShowSubTitle,
-    cleanIconStyle,
-    onChangeText,
+    rightIconStyle,
     initialValue,
+    onChangeText,
+    customColor,
     customTheme,
-    placeholder,
     iconOnPress,
+    placeholder,
+    inputStyle,
     isOptional,
     validation,
-    inputStyle,
-    maxLength,
     iconStyle,
+    maxLength,
     hintText,
     style,
     title,
@@ -122,25 +126,27 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
 
     const {
         lengthLimiterContainer: lengthLimiterContainerDynamicStyle,
-        titleContainer: titleContainerDynamicStyle,
         inputContainer: inputContainerDynamicStyle,
+        titleContainer: titleContainerDynamicStyle,
         hintTextIcon: hintTextIconDynamicStyle,
         cleanButton: cleanButtonDynamicStyle,
-        rightIcon: rightIconDynamicStyle,
         container: containerDynamicStyle,
+        rightIcon: rightIconDynamicStyle,
         hintText: hintTextDynamicStyle,
         required: requiredDynamicStyle,
         subTitle: subTitleDynamicStyle,
         content: contentDynamicStyle,
         overlay: overlayDynamicStyle,
-        title: titleDynamicStyle,
         input: inputDynamicStyle,
+        title: titleDynamicStyle,
         icon: iconDynamicStyle
     } = useStyles({
         icon: IconComponentProp ? true : false,
+        customBorderColor,
         spreadBehaviour,
         inlineSpaces,
         currentType,
+        customColor,
         isDisabled,
         typography,
         isFocused,
@@ -156,9 +162,13 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
 
     useEffect(() => {
         if(initialValue) {
-            inputRef.current?.setNativeProps({
-                text: initialValue
-            });
+            if (Platform.OS !== "web") {
+                inputRef.current?.setNativeProps({
+                    text: initialValue
+                });
+            } else if (inputRef.current) {
+                (inputRef.current as unknown as { value: string }).value = initialValue;
+            }
         }
     }, []);
 
@@ -208,9 +218,13 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
     const updateValue = (text: string) => {
         setValue(text);
 
-        inputRef.current?.setNativeProps({
-            text: text
-        });
+        if (Platform.OS !== "web") {
+            inputRef.current?.setNativeProps({
+                text: text
+            });
+        } else if (inputRef.current) {
+            (inputRef.current as unknown as { value: string }).value = text;
+        }
     };
 
     const onFocus = () => {
@@ -241,11 +255,6 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
         }
 
         return <TouchableOpacity
-            style={[
-                cleanIconStyle,
-                stylesheet.cleanButton,
-                cleanButtonDynamicStyle
-            ]}
             onPress={() => {
                 if(inputRef.current) inputRef.current?.clear();
 
@@ -255,6 +264,11 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
 
                 setValue("");
             }}
+            style={[
+                cleanIconStyle,
+                stylesheet.cleanButton,
+                cleanButtonDynamicStyle
+            ]}
         >
             <CircleXIcon
                 color={colors.content.icon[currentType.iconColor]}
@@ -277,6 +291,7 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
             ]}
         >
             <IconComponentProp
+                customColor={customIconColor}
                 color={iconProps.color}
                 size={iconProps.size}
             />
@@ -315,11 +330,11 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
         if(HintTextIconProp) {
             return <HintTextIconProp
                 color={isDisabled ? "disabled" : currentType.hintTextIconColor}
-                size={20}
                 style={[
                     stylesheet.hintTextIcon,
                     hintTextIconDynamicStyle
                 ]}
+                size={20}
             />;
         }
 
@@ -332,12 +347,12 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
         }
 
         return <CurrentHintIcon
-            color={hintIconColor}
-            size={20}
             style={[
                 stylesheet.hintTextIcon,
                 hintTextIconDynamicStyle
             ]}
+            color={hintIconColor}
+            size={20}
         />;
     };
 
@@ -370,11 +385,11 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
         }
 
         return <Text
-            color="danger"
             style={[
                 stylesheet.required,
                 requiredDynamicStyle
             ]}
+            color="danger"
         >
             *
         </Text>;
@@ -386,6 +401,7 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
         }
 
         return <Text
+            customColor={customTitleColor}
             variant="labelLargeSize"
             color={titleProps.color}
             style={[
@@ -411,6 +427,7 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
             {renderRequired()}
             <Text
                 {...titleProps}
+                customColor={customTitleColor}
                 variant={titleProps.variant}
                 color={titleProps.color}
                 style={[
@@ -451,15 +468,6 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
             <NativeTextInput
                 {...props}
                 placeholderTextColor={colors.content.text[currentType.placeholderColor]}
-                underlineColorAndroid="rgba(255,255,255,0)"
-                placeholder={placeholder}
-                allowFontScaling={false}
-                editable={!isDisabled}
-                maxLength={maxLength}
-                multiline={true}
-                onFocus={onFocus}
-                onBlur={onBlur}
-                ref={inputRef}
                 onEndEditing={(t) => {
                     const text = t.nativeEvent.text;
 
@@ -492,11 +500,21 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
                         }
                     }
                 }}
+                value={isUpdateOnRealtime ? value : undefined}
+                underlineColorAndroid="rgba(255,255,255,0)"
+                placeholder={placeholder}
+                allowFontScaling={false}
+                editable={!isDisabled}
+                maxLength={maxLength}
                 style={[
                     inputStyle,
                     stylesheet.input,
                     inputDynamicStyle
                 ]}
+                onFocus={onFocus}
+                multiline={true}
+                onBlur={onBlur}
+                ref={inputRef}
             />
             {renderLengthLimiter()}
         </View>;
@@ -504,11 +522,11 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
 
     const renderOverlay = () => {
         return <View
-            pointerEvents="none"
             style={[
                 stylesheet.overlay,
                 overlayDynamicStyle
             ]}
+            pointerEvents="none"
         />;
     };
 
@@ -536,7 +554,6 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
         })}
     >
         {renderTitle()}
-
         <View
             style={[
                 contentContainerStyle,
@@ -545,15 +562,11 @@ const TextAreaInput: RefForwardingComponent<ITextAreaInputRef, ITextAreaInputPro
             ]}
         >
             {renderOverlay()}
-
             {renderIcon()}
-
             {renderInput()}
-
             {renderCleanButton()}
             {renderRightIcon()}
         </View>
-
         {renderHintText()}
     </View>;
 };

+ 88 - 81
src/components/textAreaInput/stylesheet.ts

@@ -27,16 +27,16 @@ export const TEXT_AREA_INPUT_TYPE_STYLES: Record<
         inputColor: "mid",
         iconColor: "mid"
     },
-    danger: {
-        placeholderColor: "dangerLow",
-        hintTextIconColor: "danger",
-        focusBorderColor: "danger",
-        containerColor: "danger",
-        hintTextColor: "danger",
-        borderColor: "danger",
-        titleColor: "danger",
-        inputColor: "danger",
-        iconColor: "danger"
+    question: {
+        focusBorderColor: "emphasized",
+        borderColor: "emphasized",
+        hintTextIconColor: "mid",
+        placeholderColor: "low",
+        containerColor: "mid",
+        hintTextColor: "mid",
+        titleColor: "mid",
+        inputColor: "mid",
+        iconColor: "mid"
     },
     success: {
         placeholderColor: "successLow",
@@ -60,6 +60,17 @@ export const TEXT_AREA_INPUT_TYPE_STYLES: Record<
         inputColor: "warning",
         iconColor: "warning"
     },
+    danger: {
+        placeholderColor: "dangerLow",
+        hintTextIconColor: "danger",
+        focusBorderColor: "danger",
+        containerColor: "danger",
+        hintTextColor: "danger",
+        borderColor: "danger",
+        titleColor: "danger",
+        inputColor: "danger",
+        iconColor: "danger"
+    },
     info: {
         placeholderColor: "infoLow",
         hintTextIconColor: "info",
@@ -70,17 +81,6 @@ export const TEXT_AREA_INPUT_TYPE_STYLES: Record<
         titleColor: "info",
         inputColor: "info",
         iconColor: "info"
-    },
-    question: {
-        focusBorderColor: "emphasized",
-        borderColor: "emphasized",
-        hintTextIconColor: "mid",
-        placeholderColor: "low",
-        containerColor: "mid",
-        hintTextColor: "mid",
-        titleColor: "mid",
-        inputColor: "mid",
-        iconColor: "mid"
     }
 };
 
@@ -95,20 +95,6 @@ export const getTextAreaInputType = ({
 };
 
 const stylesheet = StyleSheet.create({
-    container: {
-        flexDirection: "column",
-        boxSizing: "border-box",
-        display: "flex"
-    },
-    content: {
-        alignItems: "flex-start",
-        boxSizing: "border-box",
-        flexDirection: "row",
-        borderStyle: "solid",
-        position: "relative",
-        display: "flex",
-        minWidth: 250
-    },
     input: {
         backgroundColor: "transparent",
         borderColor: "transparent",
@@ -121,6 +107,19 @@ const stylesheet = StyleSheet.create({
         minHeight: 55,
         zIndex: 99
     },
+    lengthLimiterContainer: {
+        justifyContent: "flex-end",
+        flexDirection: "row"
+    },
+    content: {
+        alignItems: "flex-start",
+        boxSizing: "border-box",
+        flexDirection: "row",
+        borderStyle: "solid",
+        position: "relative",
+        display: "flex",
+        minWidth: 250
+    },
     cleanButton: {
         justifyContent: "center",
         alignSelf: "flex-start",
@@ -136,12 +135,6 @@ const stylesheet = StyleSheet.create({
         zIndex: 99,
         height: 18
     },
-    titleContainer: {
-        flexDirection: "row",
-        alignItems: "center"
-    },
-    title: {
-    },
     icon: {
         justifyContent: "center",
         alignContent: "center",
@@ -149,17 +142,32 @@ const stylesheet = StyleSheet.create({
         display: "flex",
         zIndex: 99
     },
-    required: {
+    rightIcon: {
+        justifyContent: "center",
+        alignItems: "center",
+        alignSelf: "center",
+        display: "flex",
+        zIndex: 99
     },
-    hintTextIcon: {
+    container: {
+        flexDirection: "column",
+        boxSizing: "border-box",
+        alignSelf: "auto",
+        display: "flex"
+    },
+    inputContainer: {
+        flexDirection: "column",
+        flex: 1
+    },
+    titleContainer: {
+        flexDirection: "row",
+        alignItems: "center"
     },
     hintText: {
         flexDirection: "row",
         alignItems: "center",
         display: "flex"
     },
-    subTitle: {
-    },
     overlay: {
         position: "absolute",
         zIndex: 98,
@@ -168,29 +176,24 @@ const stylesheet = StyleSheet.create({
         left: 0,
         top: 0
     },
-    rightIcon: {
-        justifyContent: "center",
-        alignItems: "center",
-        alignSelf: "center",
-        display: "flex",
-        zIndex: 99
+    hintTextIcon: {
     },
-    lengthLimiterContainer: {
-        justifyContent: "flex-end",
-        flexDirection: "row"
+    required: {
     },
-    inputContainer: {
-        flexDirection: "column",
-        flex: 1
+    subTitle: {
+    },
+    title: {
     }
 });
 
 export const useStyles = ({
+    customBorderColor,
     spreadBehaviour,
     inlineSpaces,
     currentType,
-    typography,
+    customColor,
     isDisabled,
+    typography,
     isFocused,
     maxHeight,
     minHeight,
@@ -203,9 +206,6 @@ export const useStyles = ({
     const styleType = type === "danger" ? "error" : type === "question" ? "neutral" : type;
 
     const styles = {
-        container: {
-            alignSelf: "auto"
-        } as Mutable<ViewStyle>,
         content: {
             backgroundColor: colors.content.container[currentType.containerColor],
             borderColor: colors.content.container[currentType.containerColor],
@@ -222,44 +222,43 @@ export const useStyles = ({
             minHeight: minHeight,
             maxHeight: maxHeight
         } as Mutable<TextStyle>,
-        cleanButton: {
-            marginLeft: spaces.spacingSm
+        required: {
+            marginRight: inlineSpaces.required
         } as Mutable<ViewStyle>,
-        hintTextIconContainer: {
-            marginLeft: spaces.spacingSm
+        subTitle: {
+            marginLeft: inlineSpaces.subTitle
+        } as Mutable<TextStyle>,
+        overlay: {
+            borderRadius: radiuses.form - 1
         } as Mutable<ViewStyle>,
         titleContainer: {
             marginBottom: spaces.spacingSm
         } as Mutable<ViewStyle>,
-        title: {
-
-        } as Mutable<TextStyle>,
         icon: {
             marginRight: spaces.spacingSm
         } as Mutable<ViewStyle>,
-        required: {
-            marginRight: inlineSpaces.required
-        } as Mutable<ViewStyle>,
         hintTextIcon: {
             marginRight: spaces.spacingXs
         } as Mutable<ViewStyle>,
-        hintText: {
-            marginTop: spaces.spacingSm
-        } as Mutable<TextStyle>,
-        subTitle: {
-            marginLeft: inlineSpaces.subTitle
-        } as Mutable<TextStyle>,
-        overlay: {
-            borderRadius: radiuses.form - 1
+        cleanButton: {
+            marginLeft: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        hintTextIconContainer: {
+            marginLeft: spaces.spacingSm
         } as Mutable<ViewStyle>,
         rightIcon: {
             marginLeft: spaces.spacingSm
         } as Mutable<ViewStyle>,
+        hintText: {
+            marginTop: spaces.spacingSm
+        } as Mutable<TextStyle>,
         lengthLimiterContainer: {
-
         } as Mutable<ViewStyle>,
+        container: {
+        } as Mutable<ViewStyle>,
+        title: {
+        } as Mutable<TextStyle>,
         inputContainer: {
-
         } as Mutable<ViewStyle>
     };
 
@@ -284,6 +283,10 @@ export const useStyles = ({
         styles.container.width = "100%";
     }
 
+    if(customBorderColor) {
+        styles.container.borderColor = customBorderColor;
+    }
+
     if(isFocused && !isDisabled) {
         if(type === "question" || type === "default") {
             styles.content.borderColor = colors.content.border.emphasized;
@@ -292,6 +295,10 @@ export const useStyles = ({
         }
     }
 
+    if(customColor) {
+        styles.container.backgroundColor = customColor;
+    }
+
     return styles;
 };
 export default stylesheet;

+ 13 - 7
src/components/textAreaInput/type.ts

@@ -28,7 +28,9 @@ export type TextAreaInputDynamicStyleType = {
     colors: NCoreUIKit.ActivePalette["colors"];
     currentType: TextAreaInputTypes;
     borders: NCoreUIKit.Borders;
+    customBorderColor?: string;
     type: TextAreaInputType;
+    customColor?: string;
     isDisabled?: boolean;
     maxHeight?: number;
     minHeight?: number;
@@ -62,31 +64,36 @@ interface ITextAreaInputProps extends TextInputProps {
         paletteKey?: keyof NCoreUIKit.PaletteKey;
         themeKey?: keyof NCoreUIKit.ThemeKey;
     };
+    spreadBehaviour?: TextAreaInputSpreadBehaviour;
     customLocalize?: {
         activeLocale?: keyof NCoreUIKit.LocaleKey;
     };
-    spreadBehaviour?: TextAreaInputSpreadBehaviour;
+    hintTextContainerStyle?: StyleProp<ViewStyle>;
+    contentContainerStyle?: StyleProp<ViewStyle>;
     onChangeText?: (value: string) => void;
     validation?: (text: string) => boolean;
     isAutoKeyboardDismissOnBlur?: boolean;
-    hintTextContainerStyle?: ViewStyle;
-    contentContainerStyle?: ViewStyle;
+    cleanIconStyle?: StyleProp<ViewStyle>;
+    rightIconStyle?: StyleProp<ViewStyle>;
     inputStyle?: StyleProp<TextStyle>;
+    iconStyle?: StyleProp<ViewStyle>;
     isShowLengthLimiter?: boolean;
     rightIconOnPress?: () => void;
     hintTextIcon?: NCoreUIKitIcon;
     isShowHintTextIcon?: boolean;
     isUpdateOnRealtime?: boolean;
-    cleanIconStyle?: ViewStyle;
-    rightIconStyle?: ViewStyle;
+    style?: StyleProp<ViewStyle>;
+    customBorderColor?: string;
     rightIcon?: NCoreUIKitIcon;
+    customTitleColor?: string;
+    customIconColor?: string;
     isShowSubTitle?: boolean;
     isCleanEnabled?: boolean;
     iconOnPress?: () => void;
     type?: TextAreaInputType;
     initialValue?: string;
-    iconStyle?: ViewStyle;
     icon?: NCoreUIKitIcon;
+    customColor?: string;
     placeholder?: string;
     isRequired?: boolean;
     isDisabled?: boolean;
@@ -97,7 +104,6 @@ interface ITextAreaInputProps extends TextInputProps {
     maxHeight?: number;
     hintText?: string;
     subTitle?: string;
-    style?: ViewStyle;
     title?: string;
     id?: string;
 };

+ 62 - 53
src/components/textInput/index.tsx

@@ -63,25 +63,29 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
     contentContainerStyle,
     subTitle = "Optional",
     onFocus: onFocusProp,
-    isRequired = false,
     isDisabled = false,
+    isRequired = false,
     onBlur: onBlurProp,
+    customBorderColor,
     hideTextIconStyle,
-    variant = "text",
-    type = "default",
+    customTitleColor,
     rightIconOnPress,
+    type = "default",
+    variant = "text",
+    customIconColor,
+    cleanIconStyle,
     customLocalize,
-    rightIconStyle,
     isShowSubTitle,
-    cleanIconStyle,
-    onChangeText,
+    rightIconStyle,
     initialValue,
+    onChangeText,
+    customColor,
     customTheme,
-    placeholder,
     iconOnPress,
+    placeholder,
+    inputStyle,
     isOptional,
     validation,
-    inputStyle,
     iconStyle,
     hintText,
     style,
@@ -129,28 +133,30 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
         titleContainer: titleContainerDynamicStyle,
         hintTextIcon: hintTextIconDynamicStyle,
         cleanButton: cleanButtonDynamicStyle,
-        rightIcon: rightIconDynamicStyle,
         container: containerDynamicStyle,
+        rightIcon: rightIconDynamicStyle,
         hintText: hintTextDynamicStyle,
         required: requiredDynamicStyle,
         subTitle: subTitleDynamicStyle,
         content: contentDynamicStyle,
         overlay: overlayDynamicStyle,
-        title: titleDynamicStyle,
         input: inputDynamicStyle,
+        title: titleDynamicStyle,
         icon: iconDynamicStyle
     } = useStyles({
         icon: IconComponentProp ? true : false,
+        customBorderColor,
         spreadBehaviour,
         inlineSpaces,
         currentType,
+        customColor,
         isDisabled,
         typography,
         isFocused,
         radiuses,
         borders,
-        spaces,
         colors,
+        spaces,
         title,
         type
     });
@@ -201,9 +207,13 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
     const updateValue = (text: string) => {
         setValue(text);
 
-        inputRef.current?.setNativeProps({
-            text: text
-        });
+        if (Platform.OS !== "web") {
+            inputRef.current?.setNativeProps({
+                text: text
+            });
+        } else if (inputRef.current) {
+            (inputRef.current as unknown as { value: string }).value = text;
+        }
     };
 
     const onFocus = () => {
@@ -242,11 +252,6 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
         }
 
         return <TouchableOpacity
-            style={[
-                cleanIconStyle,
-                stylesheet.cleanButton,
-                cleanButtonDynamicStyle
-            ]}
             onPress={() => {
                 if(inputRef.current) inputRef.current.clear();
 
@@ -256,6 +261,11 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
 
                 setValue("");
             }}
+            style={[
+                cleanIconStyle,
+                stylesheet.cleanButton,
+                cleanButtonDynamicStyle
+            ]}
         >
             <CircleXIcon
                 color={colors.content.icon[currentType.iconColor]}
@@ -278,6 +288,7 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
             ]}
         >
             <IconComponentProp
+                customColor={customIconColor}
                 color={iconProps.color}
                 size={iconProps.size}
             />
@@ -322,22 +333,24 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
         }
 
         return <TouchableOpacity
-            onPress={toggleValueVisibility}
             style={[
                 hideTextIconStyle,
                 stylesheet.hideTextIconContainer,
                 hideTextIconContainerDynamicStyle
             ]}
+            onPress={toggleValueVisibility}
         >
-            {hideValue ?
-                <EyeIcon
-                    color={colors.content.icon[iconProps.color]}
-                    size={20}
-                /> :
-                <EyeClosedIcon
-                    color={colors.content.icon[iconProps.color]}
-                    size={20}
-                />
+            {
+                hideValue ?
+                    <EyeIcon
+                        color={colors.content.icon[iconProps.color]}
+                        size={20}
+                    />
+                :
+                    <EyeClosedIcon
+                        color={colors.content.icon[iconProps.color]}
+                        size={20}
+                    />
             }
         </TouchableOpacity>;
     };
@@ -350,11 +363,11 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
         if(HintTextIconProp) {
             return <HintTextIconProp
                 color={isDisabled ? "disabled" : currentType.hintTextIconColor}
-                size={20}
                 style={[
                     stylesheet.hintTextIcon,
                     hintTextIconDynamicStyle
                 ]}
+                size={20}
             />;
         }
 
@@ -367,12 +380,12 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
         }
 
         return <CurrentHintIcon
-            color={hintIconColor}
-            size={20}
             style={[
                 stylesheet.hintTextIcon,
                 hintTextIconDynamicStyle
             ]}
+            color={hintIconColor}
+            size={20}
         />;
     };
 
@@ -405,11 +418,11 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
         }
 
         return <Text
-            color="danger"
             style={[
                 stylesheet.required,
                 requiredDynamicStyle
             ]}
+            color="danger"
         >
             *
         </Text>;
@@ -421,12 +434,13 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
         }
 
         return <Text
-            variant="labelLargeSize"
-            color={titleProps.color}
+            customColor={customTitleColor}
             style={[
                 stylesheet.subTitle,
                 subTitleDynamicStyle
             ]}
+            variant="labelLargeSize"
+            color={titleProps.color}
         >
             ( {isOptional ? localize("is-optional") : subTitle} )
         </Text>;
@@ -463,15 +477,6 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
         return <NativeTextInput
             {...props}
             placeholderTextColor={colors.content.text[currentType.placeholderColor]}
-            secureTextEntry={variant === "hidden" && hideValue}
-            underlineColorAndroid="rgba(255,255,255,0)"
-            placeholder={placeholder}
-            allowFontScaling={false}
-            editable={!isDisabled}
-            multiline={false}
-            onFocus={onFocus}
-            onBlur={onBlur}
-            ref={inputRef}
             onChangeText={(text) => {
                 const inputValue = text.replace(/\n/g, "");
 
@@ -495,11 +500,20 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
                     if(onChangeText) onChangeText(inputValue);
                 }
             }}
+            secureTextEntry={variant === "hidden" && hideValue}
+            underlineColorAndroid="rgba(255,255,255,0)"
+            placeholder={placeholder}
+            allowFontScaling={false}
+            editable={!isDisabled}
             style={[
                 inputStyle,
                 stylesheet.input,
                 inputDynamicStyle
             ]}
+            multiline={false}
+            onFocus={onFocus}
+            onBlur={onBlur}
+            ref={inputRef}
         />;
     };
 
@@ -513,15 +527,15 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
     };
 
     return <TouchableOpacity
-        disabled={isDisabled}
+        onPress={() => {
+            if(!isDisabled) inputRef.current?.focus();
+        }}
         style={[
             style,
             stylesheet.container,
             containerDynamicStyle
         ]}
-        onPress={() => {
-            if(!isDisabled) inputRef.current?.focus();
-        }}
+        disabled={isDisabled}
         {...Platform.select({
             web: {
                 dataSet: {
@@ -532,7 +546,6 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
         })}
     >
         {renderTitle()}
-
         <View
             style={[
                 contentContainerStyle,
@@ -541,16 +554,12 @@ const TextInput: RefForwardingComponent<ITextInputRef, ITextInputProps> = ({
             ]}
         >
             {renderIcon()}
-
             {renderInput()}
-
             {renderCleanButton()}
             {renderHideTextIcon()}
             {renderRightIcon()}
-
             {renderOverlay()}
         </View>
-
         {renderHintText()}
     </TouchableOpacity>;
 };

+ 90 - 81
src/components/textInput/stylesheet.ts

@@ -27,16 +27,16 @@ export const TEXT_INPUT_TYPE_STYLES: Record<
         inputColor: "mid",
         iconColor: "mid"
     },
-    danger: {
-        placeholderColor: "dangerLow",
-        hintTextIconColor: "danger",
-        focusBorderColor: "danger",
-        containerColor: "danger",
-        hintTextColor: "danger",
-        borderColor: "danger",
-        titleColor: "danger",
-        inputColor: "danger",
-        iconColor: "danger"
+    question: {
+        focusBorderColor: "emphasized",
+        borderColor: "emphasized",
+        hintTextIconColor: "mid",
+        placeholderColor: "low",
+        containerColor: "mid",
+        hintTextColor: "mid",
+        titleColor: "mid",
+        inputColor: "mid",
+        iconColor: "mid"
     },
     success: {
         placeholderColor: "successLow",
@@ -60,6 +60,17 @@ export const TEXT_INPUT_TYPE_STYLES: Record<
         inputColor: "warning",
         iconColor: "warning"
     },
+    danger: {
+        placeholderColor: "dangerLow",
+        hintTextIconColor: "danger",
+        focusBorderColor: "danger",
+        containerColor: "danger",
+        hintTextColor: "danger",
+        borderColor: "danger",
+        titleColor: "danger",
+        inputColor: "danger",
+        iconColor: "danger"
+    },
     info: {
         placeholderColor: "infoLow",
         hintTextIconColor: "info",
@@ -70,17 +81,6 @@ export const TEXT_INPUT_TYPE_STYLES: Record<
         titleColor: "info",
         inputColor: "info",
         iconColor: "info"
-    },
-    question: {
-        focusBorderColor: "emphasized",
-        borderColor: "emphasized",
-        hintTextIconColor: "mid",
-        placeholderColor: "low",
-        containerColor: "mid",
-        hintTextColor: "mid",
-        titleColor: "mid",
-        inputColor: "mid",
-        iconColor: "mid"
     }
 };
 
@@ -95,20 +95,6 @@ export const getTextInputType = ({
 };
 
 const stylesheet = StyleSheet.create({
-    container: {
-        flexDirection: "column",
-        boxSizing: "border-box",
-        display: "flex"
-    },
-    content: {
-        boxSizing: "border-box",
-        flexDirection: "row",
-        borderStyle: "solid",
-        alignItems: "center",
-        position: "relative",
-        display: "flex",
-        minWidth: 250
-    },
     input: {
         backgroundColor: "transparent",
         textAlignVertical: "center",
@@ -122,6 +108,14 @@ const stylesheet = StyleSheet.create({
         zIndex: 99,
         flex: 1
     },
+    hideTextIconContainer: {
+        justifyContent: "center",
+        alignItems: "center",
+        alignSelf: "center",
+        display: "flex",
+        zIndex: 99,
+        height: 18
+    },
     cleanButton: {
         justifyContent: "center",
         alignItems: "center",
@@ -129,19 +123,12 @@ const stylesheet = StyleSheet.create({
         display: "flex",
         zIndex: 99
     },
-    hideTextIconContainer: {
+    rightIcon: {
         justifyContent: "center",
         alignItems: "center",
         alignSelf: "center",
         display: "flex",
-        zIndex: 99,
-        height: 18
-    },
-    titleContainer: {
-        flexDirection: "row",
-        alignItems: "center"
-    },
-    title: {
+        zIndex: 99
     },
     icon: {
         justifyContent: "center",
@@ -150,40 +137,52 @@ const stylesheet = StyleSheet.create({
         display: "flex",
         zIndex: 99
     },
-    required: {
+    content: {
+        boxSizing: "border-box",
+        flexDirection: "row",
+        borderStyle: "solid",
+        alignItems: "center",
+        position: "relative",
+        display: "flex",
+        minWidth: 250
     },
-    hintTextIcon: {
+    container: {
+        flexDirection: "column",
+        boxSizing: "border-box",
+        alignSelf: "auto",
+        display: "flex"
     },
     hintText: {
         flexDirection: "row",
         alignItems: "center",
         display: "flex"
     },
-    subTitle: {
+    titleContainer: {
+        flexDirection: "row",
+        alignItems: "center"
     },
     overlay: {
         position: "absolute",
-        zIndex: 98,
-        bottom: 0,
-        right: 0,
-        left: 0,
-        top: 0
+        zIndex: 98
     },
-    rightIcon: {
-        justifyContent: "center",
-        alignItems: "center",
-        alignSelf: "center",
-        display: "flex",
-        zIndex: 99
+    hintTextIcon: {
+    },
+    required: {
+    },
+    subTitle: {
+    },
+    title: {
     }
 });
 
 export const useStyles = ({
+    customBorderColor,
     spreadBehaviour,
     inlineSpaces,
     currentType,
-    typography,
+    customColor,
     isDisabled,
+    typography,
     isFocused,
     radiuses,
     borders,
@@ -194,9 +193,6 @@ export const useStyles = ({
     const styleType = type === "danger" ? "error" : type === "question" ? "neutral" : type;
 
     const styles = {
-        container: {
-            alignSelf: "auto"
-        } as Mutable<ViewStyle>,
         content: {
             backgroundColor: colors.content.container[currentType.containerColor],
             borderColor: colors.content.container[currentType.containerColor],
@@ -211,39 +207,44 @@ export const useStyles = ({
             ...typography.labelLargeSize,
             color: colors.content.text[currentType.inputColor]
         } as Mutable<TextStyle>,
-        cleanButton: {
-            marginLeft: spaces.spacingSm
+        overlay: {
+            borderRadius: radiuses.actions - 1,
+            bottom: -borders.line,
+            right: -borders.line,
+            left: -borders.line,
+            top: -borders.line
         } as Mutable<ViewStyle>,
-        hideTextIconContainer: {
-            marginLeft: spaces.spacingSm
+        required: {
+            marginRight: inlineSpaces.required
         } as Mutable<ViewStyle>,
+        subTitle: {
+            marginLeft: inlineSpaces.subTitle
+        } as Mutable<TextStyle>,
         titleContainer: {
             marginBottom: spaces.spacingSm
         } as Mutable<ViewStyle>,
-        title: {
-
-        } as Mutable<TextStyle>,
+        hintTextIcon: {
+            marginRight: spaces.spacingXs
+        } as Mutable<ViewStyle>,
         icon: {
             marginRight: spaces.spacingSm
         } as Mutable<ViewStyle>,
-        required: {
-            marginRight: inlineSpaces.required
+        hideTextIconContainer: {
+            marginLeft: spaces.spacingSm
         } as Mutable<ViewStyle>,
-        hintTextIcon: {
-            marginRight: spaces.spacingXs
+        cleanButton: {
+            marginLeft: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        rightIcon: {
+            marginLeft: spaces.spacingSm
         } as Mutable<ViewStyle>,
         hintText: {
             marginTop: spaces.spacingSm
         } as Mutable<TextStyle>,
-        subTitle: {
-            marginLeft: inlineSpaces.subTitle
-        } as Mutable<TextStyle>,
-        overlay: {
-            borderRadius: radiuses.actions - 1
+        container: {
         } as Mutable<ViewStyle>,
-        rightIcon: {
-            marginLeft: spaces.spacingSm
-        } as Mutable<ViewStyle>
+        title: {
+        } as Mutable<TextStyle>
     };
 
     if(isDisabled) {
@@ -267,6 +268,10 @@ export const useStyles = ({
         styles.container.width = "100%";
     }
 
+    if(customBorderColor) {
+        styles.container.borderColor = customBorderColor;
+    }
+
     if(isFocused && !isDisabled) {
         if(type === "question" || type === "default") {
             styles.content.borderColor = colors.content.border.emphasized;
@@ -275,6 +280,10 @@ export const useStyles = ({
         }
     }
 
+    if(customColor) {
+        styles.container.backgroundColor = customColor;
+    }
+
     return styles;
 };
 export default stylesheet;

+ 6 - 0
src/components/textInput/type.ts

@@ -28,6 +28,8 @@ export type TextInputDynamicStyleType = {
     colors: NCoreUIKit.ActivePalette["colors"];
     currentType: TextInputTypes;
     borders: NCoreUIKit.Borders;
+    customBorderColor?: string;
+    customColor?: string;
     isDisabled?: boolean;
     type: TextInputType;
     isFocused: boolean;
@@ -77,16 +79,20 @@ interface ITextInputProps extends TextInputProps {
     rightIconOnPress?: () => void;
     hintTextIcon?: NCoreUIKitIcon;
     isShowHintTextIcon?: boolean;
+    customBorderColor?: string;
     cleanIconStyle?: ViewStyle;
     rightIconStyle?: ViewStyle;
     rightIcon?: NCoreUIKitIcon;
     variant?: TextInputVariant;
+    customTitleColor?: string;
+    customIconColor?: string;
     isShowSubTitle?: boolean;
     isCleanEnabled?: boolean;
     iconOnPress?: () => void;
     initialValue?: string;
     iconStyle?: ViewStyle;
     icon?: NCoreUIKitIcon;
+    customColor?: string;
     placeholder?: string;
     isRequired?: boolean;
     isDisabled?: boolean;

+ 82 - 73
src/components/timeSelector/index.tsx

@@ -233,31 +233,34 @@ const TimeSelector = ({
                         rangeType="start"
                     />
                     {
-                        isWorkWithSeconds ? <Fragment>
-                            <Text
-                                variant="titleMediumSize"
-                                style={{
-                                    ...stylesheet.colonText,
-                                    ...colonTextDynamicStyle
-                                }}
-                            >
-                                :
-                            </Text>
-                            <TimeInput
-                                initialValue={dateRange?.start?.getSeconds().toString().padStart(2, "0")}
-                                isWorkWith24HoursFormat={isWorkWith24HoursFormat}
-                                selectMultipleObject={selectMultipleObject}
-                                setDateRangeValue={setDateRangeValue}
-                                rangeValidation={rangeValidation}
-                                setDateValue={setDateValue}
-                                selectObject={selectObject}
-                                timeType="seconds"
-                                variant={variant}
-                                maxDate={maxDate}
-                                minDate={minDate}
-                                rangeType="start"
-                            />
-                        </Fragment> : null
+                        isWorkWithSeconds ?
+                            <Fragment>
+                                <Text
+                                    variant="titleMediumSize"
+                                    style={{
+                                        ...stylesheet.colonText,
+                                        ...colonTextDynamicStyle
+                                    }}
+                                >
+                                    :
+                                </Text>
+                                <TimeInput
+                                    initialValue={dateRange?.start?.getSeconds().toString().padStart(2, "0")}
+                                    isWorkWith24HoursFormat={isWorkWith24HoursFormat}
+                                    selectMultipleObject={selectMultipleObject}
+                                    setDateRangeValue={setDateRangeValue}
+                                    rangeValidation={rangeValidation}
+                                    setDateValue={setDateValue}
+                                    selectObject={selectObject}
+                                    timeType="seconds"
+                                    variant={variant}
+                                    maxDate={maxDate}
+                                    minDate={minDate}
+                                    rangeType="start"
+                                />
+                            </Fragment>
+                        :
+                            null
                     }
                 </View>
                 <Text
@@ -313,31 +316,34 @@ const TimeSelector = ({
                         rangeType="end"
                     />
                     {
-                        isWorkWithSeconds ? <Fragment>
-                            <Text
-                                variant="titleMediumSize"
-                                style={{
-                                    ...stylesheet.colonText,
-                                    ...colonTextDynamicStyle
-                                }}
-                            >
-                                :
-                            </Text>
-                            <TimeInput
-                                initialValue={dateRange?.end?.getSeconds().toString().padStart(2, "0")}
-                                isWorkWith24HoursFormat={isWorkWith24HoursFormat}
-                                selectMultipleObject={selectMultipleObject}
-                                setDateRangeValue={setDateRangeValue}
-                                rangeValidation={rangeValidation}
-                                setDateValue={setDateValue}
-                                selectObject={selectObject}
-                                timeType="seconds"
-                                variant={variant}
-                                maxDate={maxDate}
-                                minDate={minDate}
-                                rangeType="end"
-                            />
-                        </Fragment> : null
+                        isWorkWithSeconds ?
+                            <Fragment>
+                                <Text
+                                    variant="titleMediumSize"
+                                    style={{
+                                        ...stylesheet.colonText,
+                                        ...colonTextDynamicStyle
+                                    }}
+                                >
+                                    :
+                                </Text>
+                                <TimeInput
+                                    initialValue={dateRange?.end?.getSeconds().toString().padStart(2, "0")}
+                                    isWorkWith24HoursFormat={isWorkWith24HoursFormat}
+                                    selectMultipleObject={selectMultipleObject}
+                                    setDateRangeValue={setDateRangeValue}
+                                    rangeValidation={rangeValidation}
+                                    setDateValue={setDateValue}
+                                    selectObject={selectObject}
+                                    timeType="seconds"
+                                    variant={variant}
+                                    maxDate={maxDate}
+                                    minDate={minDate}
+                                    rangeType="end"
+                                />
+                            </Fragment>
+                        :
+                            null
                     }
                 </View>
             </View>;
@@ -393,29 +399,32 @@ const TimeSelector = ({
                     minDate={minDate}
                 />
                 {
-                    isWorkWithSeconds ? <Fragment>
-                        <Text
-                            variant="titleMediumSize"
-                            style={{
-                                ...stylesheet.colonText,
-                                ...colonTextDynamicStyle
-                            }}
-                        >
-                            :
-                        </Text>
-                        <TimeInput
-                            initialValue={date?.getSeconds().toString().padStart(2, "0")}
-                            isWorkWith24HoursFormat={isWorkWith24HoursFormat}
-                            selectMultipleObject={selectMultipleObject}
-                            setDateRangeValue={setDateRangeValue}
-                            setDateValue={setDateValue}
-                            selectObject={selectObject}
-                            timeType="seconds"
-                            variant={variant}
-                            maxDate={maxDate}
-                            minDate={minDate}
-                        />
-                    </Fragment> : null
+                    isWorkWithSeconds ?
+                        <Fragment>
+                            <Text
+                                variant="titleMediumSize"
+                                style={{
+                                    ...stylesheet.colonText,
+                                    ...colonTextDynamicStyle
+                                }}
+                            >
+                                :
+                            </Text>
+                            <TimeInput
+                                initialValue={date?.getSeconds().toString().padStart(2, "0")}
+                                isWorkWith24HoursFormat={isWorkWith24HoursFormat}
+                                selectMultipleObject={selectMultipleObject}
+                                setDateRangeValue={setDateRangeValue}
+                                setDateValue={setDateValue}
+                                selectObject={selectObject}
+                                timeType="seconds"
+                                variant={variant}
+                                maxDate={maxDate}
+                                minDate={minDate}
+                            />
+                        </Fragment>
+                    :
+                        null
                 }
             </View>
         </View>;

+ 1 - 1
src/components/toast/index.tsx

@@ -186,7 +186,7 @@ const Toast: FC<IToastProps> = ({
                     >
                         {subTitle}
                     </Text>
-                    :
+                :
                     null
             }
         </View>;

+ 477 - 0
src/components/tooltip/index.tsx

@@ -0,0 +1,477 @@
+import {
+    useEffect,
+    useState,
+    type FC,
+    useRef
+} from "react";
+import {
+    type ViewStyle,
+    Pressable,
+    Animated,
+    Platform,
+    Easing,
+    View
+} from "react-native";
+import type ITooltipProps from "./type";
+import stylesheet, {
+    getTooltipType,
+    useStyles
+} from "./stylesheet";
+import {
+    NCoreUIKitTheme
+} from "../../core/hooks";
+import {
+    X as XIcon
+} from "lucide-react-native";
+import Button from "../button";
+import Text from "../text";
+
+const Tooltip: FC<ITooltipProps> = ({
+    isCloseOnPressActionButton = true,
+    location = {
+        horizontal: "center",
+        vertical: "top"
+    },
+    isCloseOnPress = false,
+    contentContainerStyle,
+    triggerMode = "hover",
+    sizing = "content",
+    icon: CustomIcon,
+    type = "neutral",
+    containerStyle,
+    customTheme,
+    caretStyle,
+    isVisible,
+    children,
+    onClosed,
+    subTitle,
+    content,
+    onClose,
+    action,
+    height,
+    onOpen,
+    style,
+    title,
+    width
+}) => {
+    const {
+        radiuses,
+        colors,
+        spaces
+    } = NCoreUIKitTheme.useContext(customTheme);
+
+    const [
+        wrapperSize,
+        setWrapperSize
+    ] = useState({
+        height: 0,
+        width: 0
+    });
+
+    const [
+        tooltipSize,
+        setTooltipSize
+    ] = useState({
+        height: 0,
+        width: 0
+    });
+
+    const [
+        isInternalVisible,
+        setIsInternalVisible
+    ] = useState(false);
+
+    const opacityAnim = useRef(new Animated.Value(0)).current;
+    const wrapperRef = useRef<View>(null);
+    const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null);
+
+    const handleHoverIn = () => {
+        if (hoverTimeoutRef.current) {
+            clearTimeout(hoverTimeoutRef.current);
+            hoverTimeoutRef.current = null;
+        }
+        if (isVisible === undefined) {
+            setIsInternalVisible(true);
+        }
+        if (onOpen) onOpen();
+    };
+
+    const handleHoverOut = () => {
+        hoverTimeoutRef.current = setTimeout(() => {
+            if (isVisible === undefined) {
+                setIsInternalVisible(false);
+            }
+            if (onClose) onClose();
+            hoverTimeoutRef.current = null;
+        }, 100);
+    };
+
+    const currentType = getTooltipType({
+        type
+    });
+
+    const {
+        contentContainer: contentContainerDynamicStyle,
+        containerObject: containerObjectDynamicStyle,
+        iconContainer: iconContainerDynamicStyle,
+        container: containerDynamicStyle,
+        subTitle: subTitleDynamicStyle,
+        action: actionDynamicStyle,
+        title: titleDynamicStyle,
+        caret: caretDynamicStyle
+    } = useStyles({
+        currentType,
+        radiuses,
+        colors,
+        spaces,
+        height,
+        sizing,
+        width,
+        type
+    });
+
+    const isShow = isVisible !== undefined ? isVisible : isInternalVisible;
+
+    useEffect(() => {
+        if(isShow) {
+            if(onOpen) onOpen();
+
+            Animated.timing(opacityAnim, {
+                useNativeDriver: Platform.OS !== "web",
+                easing: Easing.bezier(0, 0, 0, 1),
+                duration: 250,
+                toValue: 1
+            }).start();
+        } else {
+            Animated.timing(opacityAnim, {
+                useNativeDriver: Platform.OS !== "web",
+                easing: Easing.bezier(0, 0, 0, 1),
+                duration: 250,
+                toValue: 0
+            }).start(({
+                finished
+            }) => {
+                if(finished && onClosed) {
+                    onClosed();
+                }
+            });
+        }
+    }, [
+        isShow
+    ]);
+
+    useEffect(() => {
+        if (Platform.OS === "web" && triggerMode === "click" && isShow) {
+            const handleClickOutside = (event: Event) => {
+                const target = event.target as Node;
+                const node = wrapperRef.current as unknown as HTMLElement;
+
+                if (node && node.contains && !node.contains(target)) {
+                    if (isVisible === undefined) {
+                        setIsInternalVisible(false);
+                    }
+
+                    if (onClose) onClose();
+                }
+            };
+
+            document.addEventListener("mousedown", handleClickOutside);
+
+            return () => {
+                document.removeEventListener("mousedown", handleClickOutside);
+            };
+        }
+
+        return undefined;
+    }, [
+        isShow,
+        triggerMode,
+        isVisible,
+        onClose
+    ]);
+
+    const handleClose = () => {
+        if(isVisible === undefined) {
+            setIsInternalVisible(false);
+        }
+        if(onClose) onClose();
+    };
+
+    const handleToggle = () => {
+        if(isVisible === undefined) {
+            setIsInternalVisible(!isInternalVisible);
+        }
+
+        if(!isShow && onOpen) {
+            onOpen();
+        } else if (isShow && onClose) {
+            onClose();
+        }
+    };
+
+    const renderIcon = () => {
+        if(!CustomIcon) {
+            return null;
+        }
+
+        return <View
+            style={[
+                stylesheet.iconContainer,
+                iconContainerDynamicStyle
+            ]}
+        >
+            <CustomIcon
+                color={currentType.iconColor}
+                size={16}
+            />
+        </View>;
+    };
+
+    const renderContent = () => {
+        if(content) {
+            if(typeof content === "function") {
+                return content();
+            }
+
+            return content;
+        }
+
+        return <View
+            style={[
+                stylesheet.contentContainer,
+                contentContainerDynamicStyle,
+                contentContainerStyle
+            ]}
+        >
+            {
+                title ?
+                    <Text
+                        color={currentType.titleColor}
+                        variant="labelMediumSize"
+                        style={{
+                            ...stylesheet.title,
+                            ...titleDynamicStyle
+                        }}
+                        numberOfLines={3}
+                    >
+                        {title}
+                    </Text>
+                :
+                    null
+            }
+            {
+                subTitle ?
+                    <Text
+                        color={currentType.subTitleColor}
+                        style={{
+                            ...stylesheet.subTitle,
+                            ...subTitleDynamicStyle
+                        }}
+                        variant="labelSmallSize"
+                        numberOfLines={2}
+                    >
+                        {subTitle}
+                    </Text>
+                :
+                    null
+            }
+        </View>;
+    };
+
+    const renderAction = () => {
+        if(!action) {
+            return null;
+        }
+
+        return <Button
+            icon={() => {
+                if(action.title) {
+                    return null;
+                }
+
+                return <XIcon
+                    color={colors.content.text[currentType.actionColor]}
+                    size={16}
+                />;
+            }}
+            onPress={() => {
+                if(isCloseOnPressActionButton) handleClose();
+
+                if(action.onPress) {
+                    action.onPress({
+                        closeAnimation: handleClose
+                    });
+                }
+            }}
+            title={action.title ? action.title : undefined}
+            style={{
+                ...action.style,
+                ...actionDynamicStyle
+            }}
+            spreadBehaviour="free"
+            isCustomPadding={true}
+            variant="ghost"
+            size="small"
+            type={type}
+        />;
+    };
+
+    const getTooltipStyle = (): ViewStyle => {
+        const _style: ViewStyle = {};
+
+        if(tooltipSize.width > 0 && wrapperSize.width > 0) {
+            if(location.vertical === "top") {
+                _style.bottom = wrapperSize.height + 8;
+            } else if (location.vertical === "bottom") {
+                _style.top = wrapperSize.height + 8;
+            } else {
+                _style.top = (wrapperSize.height - tooltipSize.height) / 2;
+            }
+
+            if(location.horizontal === "left") {
+                _style.right = wrapperSize.width + 8;
+            } else if (location.horizontal === "right") {
+                _style.left = wrapperSize.width + 8;
+            } else {
+                _style.left = (wrapperSize.width - tooltipSize.width) / 2;
+            }
+        } else {
+            _style.opacity = 0;
+        }
+
+        return _style;
+    };
+
+    const getCaretStyle = (): ViewStyle => {
+        const _style: ViewStyle = {};
+
+        if(location.vertical === "top") {
+            _style.bottom = -4;
+        } else if (location.vertical === "bottom") {
+            _style.top = -4;
+        } else {
+            _style.top = (tooltipSize.height - 12) / 2;
+        }
+
+        if(location.horizontal === "left") {
+            _style.right = -4;
+        } else if (location.horizontal === "right") {
+            _style.left = -4;
+        } else {
+            _style.left = (tooltipSize.width - 12) / 2;
+        }
+
+        if (location.vertical === "top" && location.horizontal === "right") {
+            _style.left = 12;
+        } else if (location.vertical === "top" && location.horizontal === "left") {
+            _style.right = 12;
+        } else if (location.vertical === "bottom" && location.horizontal === "right") {
+            _style.left = 12;
+        } else if (location.vertical === "bottom" && location.horizontal === "left") {
+            _style.right = 12;
+        }
+
+        return _style;
+    };
+
+    return <View
+        onLayout={(e) => {
+            const {
+                height,
+                width
+            } = e.nativeEvent.layout;
+
+            setWrapperSize(prev => {
+                if (prev.height === height && prev.width === width) {
+                    return prev;
+                }
+                return {
+                    height,
+                    width
+                };
+            });
+        }}
+        style={[
+            stylesheet.wrapper,
+            style
+        ]}
+        ref={wrapperRef}
+    >
+        <Pressable
+            onPointerLeave={triggerMode === "hover" ? handleHoverOut : undefined}
+            onPointerEnter={triggerMode === "hover" ? handleHoverIn : undefined}
+            onPress={() => {
+                if(!isCloseOnPress) {
+                    handleToggle();
+                } else if(isShow) {
+                    handleClose();
+                } else {
+                    handleToggle();
+                }
+            }}
+        >
+            <View>
+                {children}
+            </View>
+        </Pressable>
+        {
+            isShow || opacityAnim !== undefined ?
+                <Animated.View
+                    onLayout={(e) => {
+                        const {
+                            height,
+                            width
+                        } = e.nativeEvent.layout;
+
+                        setTooltipSize(prev => {
+                            if (prev.height === height && prev.width === width) {
+                                return prev;
+                            }
+                            return {
+                                height,
+                                width
+                            };
+                        });
+                    }}
+                    pointerEvents={isShow ? "auto" : "none"}
+                    style={[
+                        stylesheet.container,
+                        containerDynamicStyle,
+                        getTooltipStyle(),
+                        {
+                            opacity: opacityAnim
+                        },
+                        containerStyle
+                    ]}
+                >
+                    <View
+                        onPointerLeave={triggerMode === "hover" ? handleHoverOut : undefined}
+                        onPointerEnter={triggerMode === "hover" ? handleHoverIn : undefined}
+                        style={stylesheet.hoverWrapper}
+                    >
+                        <View
+                            style={[
+                                stylesheet.caret,
+                                caretDynamicStyle,
+                                getCaretStyle(),
+                                caretStyle
+                            ]}
+                        />
+                        <View
+                            style={[
+                                stylesheet.containerObject,
+                                containerObjectDynamicStyle
+                            ]}
+                        >
+                            {renderIcon()}
+                            {renderContent()}
+                            {renderAction()}
+                        </View>
+                    </View>
+                </Animated.View>
+            :
+                null
+        }
+    </View>;
+};
+export default Tooltip;

+ 177 - 0
src/components/tooltip/stylesheet.ts

@@ -0,0 +1,177 @@
+import {
+    type TextStyle,
+    type ViewStyle,
+    StyleSheet,
+    Platform
+} from "react-native";
+import type {
+    TooltipTypeConstantType,
+    TooltipDynamicStyleType,
+    TooltipTypes,
+    TooltipType
+} from "./type";
+import type {
+    Mutable
+} from "../../types";
+import {
+    windowWidth
+} from "../../utils";
+
+export const TOOLTIP_TYPE_STYLES: Record<
+    TooltipType,
+    {
+        containerColor: keyof NCoreUIKit.ContainerContentColors;
+        subTitleColor: keyof NCoreUIKit.TextContentColors;
+        actionColor: keyof NCoreUIKit.TextContentColors;
+        titleColor: keyof NCoreUIKit.TextContentColors;
+        iconColor: keyof NCoreUIKit.IconContentColors;
+    }
+> = {
+    success: {
+        subTitleColor: "successLow",
+        containerColor: "success",
+        actionColor: "success",
+        titleColor: "success",
+        iconColor: "success"
+    },
+    warning: {
+        subTitleColor: "warningLow",
+        containerColor: "warning",
+        actionColor: "warning",
+        titleColor: "warning",
+        iconColor: "warning"
+    },
+    danger: {
+        subTitleColor: "dangerLow",
+        containerColor: "danger",
+        actionColor: "danger",
+        titleColor: "danger",
+        iconColor: "danger"
+    },
+    primary: {
+        subTitleColor: "onPrimary",
+        containerColor: "primary",
+        actionColor: "onPrimary",
+        iconColor: "emphasized",
+        titleColor: "onPrimary"
+    },
+    info: {
+        subTitleColor: "infoLow",
+        containerColor: "info",
+        actionColor: "info",
+        titleColor: "info",
+        iconColor: "info"
+    },
+    neutral: {
+        containerColor: "mid",
+        subTitleColor: "low",
+        actionColor: "mid",
+        titleColor: "mid",
+        iconColor: "mid"
+    }
+};
+
+export const getTooltipType = ({
+    type
+}: TooltipTypeConstantType): TooltipTypes => {
+    const currentType = TOOLTIP_TYPE_STYLES[type];
+
+    return currentType;
+};
+
+const stylesheet = StyleSheet.create({
+    caret: {
+        transform: [
+            {
+                rotate: "45deg"
+            }
+        ],
+        position: "absolute",
+        height: 12,
+        width: 12
+    },
+    contentContainer: {
+        justifyContent: "center",
+        alignItems: "flex-start",
+        flexDirection: "column",
+        flexShrink: 1
+    },
+    wrapper: {
+        justifyContent: "center",
+        alignSelf: "flex-start",
+        position: "relative",
+        alignItems: "center"
+    },
+    iconContainer: {
+        justifyContent: "center",
+        alignItems: "center"
+    },
+    containerObject: {
+        flexDirection: "row",
+        alignItems: "center"
+    },
+    container: {
+        position: "absolute",
+        zIndex: 99998
+    },
+    subTitle: {
+        textAlign: "left"
+    },
+    title: {
+        textAlign: "left"
+    },
+    hoverWrapper: {
+        flex: 1
+    }
+});
+
+export const useStyles = ({
+    currentType,
+    radiuses,
+    colors,
+    height,
+    sizing,
+    spaces,
+    width
+}: TooltipDynamicStyleType) => {
+    const isFixed = sizing === "fixed";
+
+    const styles = {
+        container: {
+            width: isFixed ? width : (Platform.OS === "web" ? "max-content" : undefined),
+            backgroundColor: colors.content.container[currentType.containerColor],
+            maxWidth: isFixed ? undefined : windowWidth - (spaces.spacingMd * 2),
+            height: isFixed ? height : undefined,
+            minWidth: isFixed ? undefined : 50,
+            borderRadius: radiuses.md
+        } as Mutable<ViewStyle>,
+        action: {
+            paddingBottom: spaces.spacingSm,
+            paddingRight: spaces.spacingSm,
+            paddingLeft: spaces.spacingMd,
+            paddingTop: spaces.spacingSm,
+            marginLeft: spaces.spacingMd
+        } as Mutable<ViewStyle>,
+        containerObject: {
+            paddingHorizontal: spaces.spacingMd,
+            paddingVertical: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        iconContainer: {
+            paddingRight: spaces.spacingSm,
+            marginRight: spaces.spacingSm
+        } as Mutable<ViewStyle>,
+        caret: {
+            backgroundColor: colors.content.container[currentType.containerColor]
+        } as Mutable<ViewStyle>,
+        subTitle: {
+            marginTop: spaces.spacingXs
+        } as Mutable<TextStyle>,
+        contentContainer: {
+        } as Mutable<ViewStyle>,
+        title: {
+        } as Mutable<TextStyle>
+    };
+
+    return styles;
+};
+export default stylesheet;

+ 93 - 0
src/components/tooltip/type.ts

@@ -0,0 +1,93 @@
+import {
+    type ReactNode
+} from "react";
+import {
+    type StyleProp,
+    type ViewStyle
+} from "react-native";
+import type {
+    NCoreUIKitIcon
+} from "../../types";
+
+export type TooltipDynamicStyleType = {
+    radiuses: NCoreUIKit.ActivePalette["radiuses"];
+    spaces: NCoreUIKit.ActivePalette["spaces"];
+    colors: NCoreUIKit.ActivePalette["colors"];
+    sizing?: "content" | "fixed";
+    currentType: TooltipTypes;
+    type: TooltipType;
+    height?: number;
+    width?: number;
+};
+
+export type TooltipTypes = {
+    containerColor: keyof NCoreUIKit.ContainerContentColors;
+    subTitleColor: keyof NCoreUIKit.TextContentColors;
+    actionColor: keyof NCoreUIKit.TextContentColors;
+    titleColor: keyof NCoreUIKit.TextContentColors;
+    iconColor: keyof NCoreUIKit.IconContentColors;
+};
+
+export type TooltipTypeConstantType = {
+    type: TooltipType;
+};
+
+export type TooltipType = "primary" | "danger" | "warning" | "neutral" | "success" | "info";
+
+export type TooltipLocation = {
+    horizontal: "left" | "center" | "right";
+    vertical: "top" | "center" | "bottom";
+};
+
+export type TooltipInternalProps = {
+    contentContainerStyle?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
+    containerStyle?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
+    caretStyle?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
+    customTheme?: {
+        gapPropagation?: keyof NCoreUIKit.GapPropagationKey;
+        sharpness?: keyof NCoreUIKit.SharpnessKey;
+        paletteKey?: keyof NCoreUIKit.PaletteKey;
+        themeKey?: keyof NCoreUIKit.ThemeKey;
+    };
+    style?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
+    content?: ReactNode | (() => ReactNode);
+    isCloseOnPressActionButton?: boolean;
+    action?: {
+        onPress: (props: {
+            closeAnimation: () => void;
+        }) => void;
+        icon?: NCoreUIKitIcon;
+        style?: ViewStyle;
+        title?: string;
+    };
+    triggerMode?: "hover" | "click";
+    location?: TooltipLocation;
+    isCloseOnPress?: boolean;
+    icon?: NCoreUIKitIcon;
+    onClosed?: () => void;
+    children?: ReactNode;
+    onClose?: () => void;
+    isVisible?: boolean;
+    onOpen?: () => void;
+    type?: TooltipType;
+    subTitle?: string;
+    title?: string;
+};
+
+export type TooltipSizingProps = |
+    {
+        sizing?: "content";
+        height?: never;
+        width?: never;
+    } |
+    {
+        sizing: "fixed";
+        height: number;
+        width: number;
+    };
+
+type ITooltipProps = TooltipInternalProps & TooltipSizingProps;
+
+export type {
+    ITooltipProps as default
+};

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

@@ -351,16 +351,21 @@ const YearSelector = ({
             >
                 {yearItem.title}
             </Text>
-            {isShowTodayIndicator && yearItem.isToday ? <View
-                style={[
-                    stylesheet.todayIndicator,
-                    selectionStyle,
-                    todayIndicatorDynamicStyle,
+            {
+                isShowTodayIndicator && yearItem.isToday ?
+                    <View
+                        style={[
+                            stylesheet.todayIndicator,
+                            selectionStyle,
+                            todayIndicatorDynamicStyle,
                     yearItem.isSelected ? {
                         borderColor: colors.content.border.subtle
                     } : null
-                ]}
-            /> : null}
+                        ]}
+                    />
+                :
+                    null
+            }
         </TouchableOpacity>;
     };
 

+ 29 - 29
src/components/yearSelector/stylesheet.ts

@@ -10,32 +10,21 @@ import type {
 } from "../../types";
 
 const stylesheet = StyleSheet.create({
-    container: {
-        flex: 1
-    },
-    contentContainer: {
-        justifyContent: "space-between",
-        flexDirection: "column",
-        alignItems: "center"
-    },
-    columnContainer: {
-        justifyContent: "center",
-        flexDirection: "column",
-        alignItems: "center",
-        flexShrink: 1,
-        flex: 1
-    },
     day: {
+        borderColor: "transparent",
         justifyContent: "center",
         alignItems: "center",
         position: "relative",
-        flexShrink: 1,
         width: "100%",
-        flex: 1
+        flex: 1,
+        flexShrink: 1
     },
-    todayIndicator: {
-        position: "absolute",
-        zIndex: 999
+    columnContainer: {
+        justifyContent: "center",
+        flexDirection: "column",
+        alignItems: "center",
+        flex: 1,
+        flexShrink: 1
     },
     nextPrevToolContainer: {
         justifyContent: "space-between",
@@ -43,8 +32,20 @@ const stylesheet = StyleSheet.create({
         alignItems: "center",
         flex: 1
     },
+    contentContainer: {
+        justifyContent: "space-between",
+        flexDirection: "column",
+        alignItems: "center"
+    },
+    todayIndicator: {
+        position: "absolute",
+        zIndex: 999
+    },
     rowContainer: {
         flexDirection: "row"
+    },
+    container: {
+        flex: 1
     }
 });
 
@@ -55,15 +56,6 @@ export const useStyles = ({
     colors
 }: YearSelectorDynamicStyle) => {
     const styles = {
-        day: {
-            borderBottomRightRadius: radiuses.full,
-            borderBottomLeftRadius: radiuses.full,
-            borderTopRightRadius: radiuses.full,
-            borderTopLeftRadius: radiuses.full,
-            borderColor: "transparent",
-            borderWidth: borders.line,
-            padding: spaces.spacingSm
-        } as Mutable<ViewStyle>,
         todayIndicator: {
             borderColor: colors.content.border.default,
             borderBottomRightRadius: radiuses.full,
@@ -76,6 +68,14 @@ export const useStyles = ({
             left: spaces.spacingXs,
             top: spaces.spacingXs
         } as Mutable<ViewStyle>,
+        day: {
+            borderBottomRightRadius: radiuses.full,
+            borderBottomLeftRadius: radiuses.full,
+            borderTopRightRadius: radiuses.full,
+            borderTopLeftRadius: radiuses.full,
+            borderWidth: borders.line,
+            padding: spaces.spacingSm
+        } as Mutable<ViewStyle>,
         nextPrevToolContainer: {
             marginBottom: spaces.spacingMd
         } as Mutable<ViewStyle>,

+ 0 - 1
src/helpers/portalize/Host.tsx

@@ -114,7 +114,6 @@ export const Host = ({
         >
             {children}
         </View>
-
         <Manager
             ref={managerRef}
             name={name}

+ 11 - 2
src/index.tsx

@@ -21,12 +21,14 @@ export {
     PaletteSwitcher,
     DateTimePicker,
     LocaleSwitcher,
+    MarkdownEditor,
     MarkdownViewer,
     DateTimeSheet,
     MonthSelector,
     PageContainer,
     TextAreaInput,
     ThemeSwitcher,
+    SystemToolbar,
     WebScrollbar,
     DateSelector,
     EmbeddedMenu,
@@ -37,6 +39,7 @@ export {
     BottomSheet,
     RadioButton,
     SelectSheet,
+    CodeEditor,
     CodeViewer,
     MainHeader,
     MenuButton,
@@ -50,8 +53,9 @@ export {
     Loading,
     RowCard,
     Sticker,
-    Avatar,
+    Tooltip,
     Button,
+    Avatar,
     Dialog,
     Header,
     Switch,
@@ -70,9 +74,9 @@ export type {
     DateTimePickerDynamicStyleType,
     DateTimePickerSpreadBehaviour,
     AvatarTitleAbbreviationTypes,
+    INotificationIndicatorProps,
     AvatarGroupDynamicStyleType,
     AvatarGroupSizeConstantType,
-    INotificationIndicatorProps,
     AvatarStatusIndicatorType,
     CheckBoxDynamicStyleType,
     CheckBoxTypeConstantType,
@@ -94,6 +98,7 @@ export type {
     IDateTimePickerProps,
     ILocaleSwitcherProps,
     IMarkdownViewerProps,
+    IMarkdownEditorProps,
     AvatarGroupSizeType,
     ChipSpreadBehaviour,
     DateTimePickerTypes,
@@ -102,6 +107,7 @@ export type {
     IPageContainerProps,
     ITextAreaInputProps,
     IThemeSwitcherProps,
+    ISystemToolbarProps,
     AvatarMeasuresKeys,
     DateTimePickerType,
     EnterMarkdownTypes,
@@ -118,6 +124,7 @@ export type {
     ISelectSheetProps,
     ITextAreaInputRef,
     TextMarkdownTypes,
+    ICodeEditorProps,
     IEmbeddedMenuRef,
     DateCalendarType,
     IDateSelectorRef,
@@ -125,6 +132,7 @@ export type {
     IMainHeaderProps,
     IMenuButtonProps,
     ValidTitleFormat,
+    TooltipLocation,
     BlockquoteTypes,
     IBottomSheetRef,
     ISelectBoxProps,
@@ -137,6 +145,7 @@ export type {
     ISiteLogoProps,
     ISnackBarProps,
     MarkdownObject,
+    ITooltipProps,
     CheckBoxTypes,
     DialogVariant,
     ILoadingProps,

+ 49 - 11
src/variants/locales/default.json

@@ -6,10 +6,10 @@
             "selected-start-and-end-times-cannot-be-less-than-x-times-apart": "Seçilen başlangıç ve bitiş zamanı {{0}} aralığından az olamaz.",
             "selected-start-and-end-times-cannot-exceed-x-intervals": "Seçilen başlangıç ve bitiş zamanı {{0}} aralığından çok olamaz.",
             "minimum-selection-number-of-days-required-not-provided": "Minimum seçilmesi gereken gün sayısını karşılamıyor.",
-            "selected-start-time-cannot-after-then-end-time": "Seçilen başlangıç zamanı, başlangıç zamanından sonra olamaz.",
             "selected-start-date-cannot-after-then-end-date": "Seçilen başlangıç tarihi, başlangıç tarihinden sonra olamaz.",
-            "selected-end-time-cannot-before-from-start-time": "Seçilen bitiş zamanı, başlangıç zamanından önce olamaz.",
+            "selected-start-time-cannot-after-then-end-time": "Seçilen başlangıç zamanı, başlangıç zamanından sonra olamaz.",
             "selected-end-date-cannot-before-from-start-date": "Seçilen bitiş tarihi, başlangıç tarihinden önce olamaz.",
+            "selected-end-time-cannot-before-from-start-time": "Seçilen bitiş zamanı, başlangıç zamanından önce olamaz.",
             "maximum-selection-number-of-days-limit-exceeds": "Maksimum seçilebilen gün sınırını aşıyor.",
             "maximum-selection-limit-has-been-reached": "Maksimum seçim limitine ulaşıldı.",
             "minimum-a-item-selection-required": "Minimum 1 öğe seçimi gereklidir.",
@@ -18,27 +18,46 @@
             "end-date-select-is-required": "Bitiş tarihi seçimi zorunlu.",
             "code-copy-error-to-clipboard": "❌ Kod kopyalanamadı.",
             "copy-success-to-clipboard": "✅ Başarıyla kopyalandı.",
-            "copy-error-to-clipboard": "❌ Kopyalama başarısız.",
             "selected-options-with-count": "{{0}} seçim yapıldı",
+            "copy-error-to-clipboard": "❌ Kopyalama başarısız.",
+            "typography-headlineMediumSize": "H-M",
+            "typography-displayMediumSize": "D-M",
+            "typography-headlineLargeSize": "H-L",
+            "typography-headlineSmallSize": "H-S",
             "select-any-date": "Bir tarih seçin",
+            "typography-displayLargeSize": "D-L",
+            "typography-displaySmallSize": "D-S",
             "clean-selection": "Seçimi Temizle",
+            "typography-labelMediumSize": "L-M",
+            "typography-labelLargeSize": "L-L",
+            "typography-labelSmallSize": "L-S",
+            "typography-titleMediumSize": "H2",
             "select-an-option": "Seçim yapın",
+            "typography-bodyMediumSize": "H5",
+            "typography-titleLargeSize": "H1",
+            "typography-titleSmallSize": "H3",
             "start-time": "Başlangıç Zamanı",
+            "typography-bodyLargeSize": "H4",
+            "typography-bodySmallSize": "H6",
             "clean-all": "Tümünü Temizle",
-            "is-optional": "Opsiyonel",
-            "select-all": "Tümünü Seç",
             "components": "Bileşenler",
             "end-time": "Bitiş Zamanı",
+            "is-optional": "Opsiyonel",
+            "select-all": "Tümünü Seç",
             "go-to-today": "Bugün",
+            "preview": "Önizleme",
             "home": "Ana Sayfa",
             "monthly": "Aylık",
             "yearly": "Yıllık",
             "cancel": "İptal",
             "daily": "Günlük",
+            "live": "Canlı",
             "search": "Ara",
             "menu": "Menü",
+            "write": "Yaz",
             "ok": "Tamam",
-            "or": "ya da"
+            "or": "ya da",
+            "open": "Aç"
         },
         "rruleConfig": {
             "dayNames": [
@@ -118,10 +137,10 @@
             "selected-start-and-end-times-cannot-be-less-than-x-times-apart": "Selected start and end times cannot be less than {{0}}.",
             "selected-start-and-end-times-cannot-exceed-x-intervals": "selected start and end times cannot exceed {{0}} intervals.",
             "maximum-selection-number-of-days-limit-exceeds": "It exceeds the maximum number of days that can be selected.",
-            "selected-end-time-cannot-before-from-start-time": "Selected end time cannot before from start time.",
             "selected-end-date-cannot-before-from-start-date": "Selected end date cannot before from start date.",
-            "selected-start-time-cannot-after-then-end-time": "Selected start time cannot after then end time.",
+            "selected-end-time-cannot-before-from-start-time": "Selected end time cannot before from start time.",
             "selected-start-date-cannot-after-then-end-date": "Selected start date cannot after then end date.",
+            "selected-start-time-cannot-after-then-end-time": "Selected start time cannot after then end time.",
             "maximum-selection-limit-has-been-reached": "Maximum selection limit has been reached.",
             "minimum-a-item-selection-required": "Minimum 1 item selection required.",
             "start-date-select-is-required": "Start date select is required.",
@@ -132,22 +151,41 @@
             "selected-options-with-count": "{{0}} items selected",
             "copy-error-to-clipboard": "❌ Copy unsuccessful.",
             "select-an-option": "Select an option",
+            "typography-headlineMediumSize": "H-M",
+            "typography-displayMediumSize": "D-M",
+            "typography-headlineLargeSize": "H-L",
+            "typography-headlineSmallSize": "H-S",
             "clean-selection": "Clean Selection",
             "select-any-date": "Select any date",
-            "start-time": "Start Time",
-            "select-all": "Select All",
+            "typography-displayLargeSize": "D-L",
+            "typography-displaySmallSize": "D-S",
+            "typography-labelMediumSize": "L-M",
+            "typography-labelLargeSize": "L-L",
+            "typography-labelSmallSize": "L-S",
+            "typography-titleMediumSize": "H2",
+            "typography-bodyMediumSize": "H5",
+            "typography-titleLargeSize": "H1",
+            "typography-titleSmallSize": "H3",
+            "typography-bodyLargeSize": "H4",
+            "typography-bodySmallSize": "H6",
             "components": "Components",
-            "is-optional": "Optional",
+            "select-all": "Select All",
+            "start-time": "Start Time",
             "go-to-today": "Go Today",
+            "is-optional": "Optional",
             "clean-all": "Clean All",
             "end-time": "End Time",
             "monthly": "Monthly",
+            "preview": "Preview",
             "cancel": "Cancel",
             "search": "Search",
             "yearly": "Yearly",
             "daily": "Daily",
+            "write": "Write",
             "home": "Home",
+            "live": "Live",
             "menu": "Menu",
+            "open": "Open",
             "ok": "Okey",
             "or": "or"
         },

+ 1 - 0
src/variants/themes/default.json

@@ -64,6 +64,7 @@
             "scrollBarTrack": 6,
             "scrollBarThumb": 4,
             "seperator": 0.5,
+            "indicator": 4,
             "subtract": 3,
             "line": 2
         },

BIN
temp_index.tsx.bak


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels