@korsolutions/ui 0.0.37 → 0.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/dist/module/components/alert-dialog/alert-dialog.js +41 -0
  2. package/dist/module/components/alert-dialog/alert-dialog.js.map +1 -0
  3. package/dist/module/components/alert-dialog/async-alert-dialog.js +117 -0
  4. package/dist/module/components/alert-dialog/async-alert-dialog.js.map +1 -0
  5. package/dist/module/components/alert-dialog/index.js +6 -0
  6. package/dist/module/components/alert-dialog/index.js.map +1 -0
  7. package/dist/module/components/alert-dialog/variants/default.js +93 -0
  8. package/dist/module/components/alert-dialog/variants/default.js.map +1 -0
  9. package/dist/module/components/alert-dialog/variants/index.js +7 -0
  10. package/dist/module/components/alert-dialog/variants/index.js.map +1 -0
  11. package/dist/module/components/autocomplete/autocomplete.js +31 -0
  12. package/dist/module/components/autocomplete/autocomplete.js.map +1 -0
  13. package/dist/module/components/autocomplete/variants/default.js +88 -0
  14. package/dist/module/components/autocomplete/variants/default.js.map +1 -0
  15. package/dist/module/components/autocomplete/variants/index.js +7 -0
  16. package/dist/module/components/autocomplete/variants/index.js.map +1 -0
  17. package/dist/module/components/index.js +2 -0
  18. package/dist/module/components/index.js.map +1 -1
  19. package/dist/module/components/input/numeric-input.js +7 -6
  20. package/dist/module/components/input/numeric-input.js.map +1 -1
  21. package/dist/module/index.js +2 -1
  22. package/dist/module/index.js.map +1 -1
  23. package/dist/module/primitives/alert-dialog/alert-dialog-action.js +34 -0
  24. package/dist/module/primitives/alert-dialog/alert-dialog-action.js.map +1 -0
  25. package/dist/module/primitives/alert-dialog/alert-dialog-cancel.js +34 -0
  26. package/dist/module/primitives/alert-dialog/alert-dialog-cancel.js.map +1 -0
  27. package/dist/module/primitives/alert-dialog/alert-dialog-content.js +23 -0
  28. package/dist/module/primitives/alert-dialog/alert-dialog-content.js.map +1 -0
  29. package/dist/module/primitives/alert-dialog/alert-dialog-description.js +23 -0
  30. package/dist/module/primitives/alert-dialog/alert-dialog-description.js.map +1 -0
  31. package/dist/module/primitives/alert-dialog/alert-dialog-footer.js +23 -0
  32. package/dist/module/primitives/alert-dialog/alert-dialog-footer.js.map +1 -0
  33. package/dist/module/primitives/alert-dialog/alert-dialog-overlay.js +26 -0
  34. package/dist/module/primitives/alert-dialog/alert-dialog-overlay.js.map +1 -0
  35. package/dist/module/primitives/alert-dialog/alert-dialog-portal.js +20 -0
  36. package/dist/module/primitives/alert-dialog/alert-dialog-portal.js.map +1 -0
  37. package/dist/module/primitives/alert-dialog/alert-dialog-root.js +22 -0
  38. package/dist/module/primitives/alert-dialog/alert-dialog-root.js.map +1 -0
  39. package/dist/module/primitives/alert-dialog/alert-dialog-title.js +23 -0
  40. package/dist/module/primitives/alert-dialog/alert-dialog-title.js.map +1 -0
  41. package/dist/module/primitives/alert-dialog/alert-dialog-trigger.js +28 -0
  42. package/dist/module/primitives/alert-dialog/alert-dialog-trigger.js.map +1 -0
  43. package/dist/module/primitives/alert-dialog/context.js +12 -0
  44. package/dist/module/primitives/alert-dialog/context.js.map +1 -0
  45. package/dist/module/primitives/alert-dialog/index.js +26 -0
  46. package/dist/module/primitives/alert-dialog/index.js.map +1 -0
  47. package/dist/module/primitives/alert-dialog/types.js +4 -0
  48. package/dist/module/primitives/alert-dialog/types.js.map +1 -0
  49. package/dist/module/primitives/autocomplete/autocomplete-content.js +33 -0
  50. package/dist/module/primitives/autocomplete/autocomplete-content.js.map +1 -0
  51. package/dist/module/primitives/autocomplete/autocomplete-empty.js +17 -0
  52. package/dist/module/primitives/autocomplete/autocomplete-empty.js.map +1 -0
  53. package/dist/module/primitives/autocomplete/autocomplete-input.js +73 -0
  54. package/dist/module/primitives/autocomplete/autocomplete-input.js.map +1 -0
  55. package/dist/module/primitives/autocomplete/autocomplete-option.js +54 -0
  56. package/dist/module/primitives/autocomplete/autocomplete-option.js.map +1 -0
  57. package/dist/module/primitives/autocomplete/autocomplete-overlay.js +20 -0
  58. package/dist/module/primitives/autocomplete/autocomplete-overlay.js.map +1 -0
  59. package/dist/module/primitives/autocomplete/autocomplete-portal.js +25 -0
  60. package/dist/module/primitives/autocomplete/autocomplete-portal.js.map +1 -0
  61. package/dist/module/primitives/autocomplete/autocomplete-root.js +69 -0
  62. package/dist/module/primitives/autocomplete/autocomplete-root.js.map +1 -0
  63. package/dist/module/primitives/autocomplete/context.js +12 -0
  64. package/dist/module/primitives/autocomplete/context.js.map +1 -0
  65. package/dist/module/primitives/autocomplete/index.js +20 -0
  66. package/dist/module/primitives/autocomplete/index.js.map +1 -0
  67. package/dist/module/primitives/autocomplete/types.js +4 -0
  68. package/dist/module/primitives/autocomplete/types.js.map +1 -0
  69. package/dist/module/primitives/dropdown-menu/dropdown-menu-divider.js +2 -2
  70. package/dist/module/primitives/dropdown-menu/dropdown-menu-divider.js.map +1 -1
  71. package/dist/module/primitives/dropdown-menu/dropdown-menu-trigger.js +3 -7
  72. package/dist/module/primitives/dropdown-menu/dropdown-menu-trigger.js.map +1 -1
  73. package/dist/module/primitives/index.js +2 -0
  74. package/dist/module/primitives/index.js.map +1 -1
  75. package/dist/module/primitives/input/input.js +3 -4
  76. package/dist/module/primitives/input/input.js.map +1 -1
  77. package/dist/module/primitives/popover/popover-portal.js +1 -1
  78. package/dist/module/primitives/popover/popover-portal.js.map +1 -1
  79. package/dist/module/primitives/popover/popover-trigger.js +3 -7
  80. package/dist/module/primitives/popover/popover-trigger.js.map +1 -1
  81. package/dist/module/primitives/portal/portal.js +4 -35
  82. package/dist/module/primitives/portal/portal.js.map +1 -1
  83. package/dist/module/primitives/select/context.js.map +1 -1
  84. package/dist/module/primitives/select/select-content.js +16 -5
  85. package/dist/module/primitives/select/select-content.js.map +1 -1
  86. package/dist/module/primitives/select/select-root.js +7 -3
  87. package/dist/module/primitives/select/select-root.js.map +1 -1
  88. package/dist/module/primitives/select/select-trigger.js +16 -11
  89. package/dist/module/primitives/select/select-trigger.js.map +1 -1
  90. package/dist/module/utils/normalize-layout.js +17 -0
  91. package/dist/module/utils/normalize-layout.js.map +1 -1
  92. package/dist/typescript/src/components/alert-dialog/alert-dialog.d.ts +15 -0
  93. package/dist/typescript/src/components/alert-dialog/alert-dialog.d.ts.map +1 -0
  94. package/dist/typescript/src/components/alert-dialog/async-alert-dialog.d.ts +19 -0
  95. package/dist/typescript/src/components/alert-dialog/async-alert-dialog.d.ts.map +1 -0
  96. package/dist/typescript/src/components/alert-dialog/index.d.ts +4 -0
  97. package/dist/typescript/src/components/alert-dialog/index.d.ts.map +1 -0
  98. package/dist/typescript/src/components/alert-dialog/variants/default.d.ts +3 -0
  99. package/dist/typescript/src/components/alert-dialog/variants/default.d.ts.map +1 -0
  100. package/dist/typescript/src/components/alert-dialog/variants/index.d.ts +4 -0
  101. package/dist/typescript/src/components/alert-dialog/variants/index.d.ts.map +1 -0
  102. package/dist/typescript/src/components/autocomplete/autocomplete.d.ts +11 -0
  103. package/dist/typescript/src/components/autocomplete/autocomplete.d.ts.map +1 -0
  104. package/dist/typescript/src/components/autocomplete/variants/default.d.ts +3 -0
  105. package/dist/typescript/src/components/autocomplete/variants/default.d.ts.map +1 -0
  106. package/dist/typescript/src/components/autocomplete/variants/index.d.ts +5 -0
  107. package/dist/typescript/src/components/autocomplete/variants/index.d.ts.map +1 -0
  108. package/dist/typescript/src/components/index.d.ts +2 -0
  109. package/dist/typescript/src/components/index.d.ts.map +1 -1
  110. package/dist/typescript/src/components/input/numeric-input.d.ts +2 -1
  111. package/dist/typescript/src/components/input/numeric-input.d.ts.map +1 -1
  112. package/dist/typescript/src/index.d.ts.map +1 -1
  113. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-action.d.ts +8 -0
  114. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-action.d.ts.map +1 -0
  115. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-cancel.d.ts +8 -0
  116. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-cancel.d.ts.map +1 -0
  117. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-content.d.ts +8 -0
  118. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-content.d.ts.map +1 -0
  119. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-description.d.ts +8 -0
  120. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-description.d.ts.map +1 -0
  121. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-footer.d.ts +8 -0
  122. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-footer.d.ts.map +1 -0
  123. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-overlay.d.ts +7 -0
  124. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-overlay.d.ts.map +1 -0
  125. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-portal.d.ts +7 -0
  126. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-portal.d.ts.map +1 -0
  127. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-root.d.ts +8 -0
  128. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-root.d.ts.map +1 -0
  129. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-title.d.ts +8 -0
  130. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-title.d.ts.map +1 -0
  131. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-trigger.d.ts +8 -0
  132. package/dist/typescript/src/primitives/alert-dialog/alert-dialog-trigger.d.ts.map +1 -0
  133. package/dist/typescript/src/primitives/alert-dialog/context.d.ts +10 -0
  134. package/dist/typescript/src/primitives/alert-dialog/context.d.ts.map +1 -0
  135. package/dist/typescript/src/primitives/alert-dialog/index.d.ts +33 -0
  136. package/dist/typescript/src/primitives/alert-dialog/index.d.ts.map +1 -0
  137. package/dist/typescript/src/primitives/alert-dialog/types.d.ts +13 -0
  138. package/dist/typescript/src/primitives/alert-dialog/types.d.ts.map +1 -0
  139. package/dist/typescript/src/primitives/autocomplete/autocomplete-content.d.ts +8 -0
  140. package/dist/typescript/src/primitives/autocomplete/autocomplete-content.d.ts.map +1 -0
  141. package/dist/typescript/src/primitives/autocomplete/autocomplete-empty.d.ts +9 -0
  142. package/dist/typescript/src/primitives/autocomplete/autocomplete-empty.d.ts.map +1 -0
  143. package/dist/typescript/src/primitives/autocomplete/autocomplete-input.d.ts +7 -0
  144. package/dist/typescript/src/primitives/autocomplete/autocomplete-input.d.ts.map +1 -0
  145. package/dist/typescript/src/primitives/autocomplete/autocomplete-option.d.ts +11 -0
  146. package/dist/typescript/src/primitives/autocomplete/autocomplete-option.d.ts.map +1 -0
  147. package/dist/typescript/src/primitives/autocomplete/autocomplete-overlay.d.ts +10 -0
  148. package/dist/typescript/src/primitives/autocomplete/autocomplete-overlay.d.ts.map +1 -0
  149. package/dist/typescript/src/primitives/autocomplete/autocomplete-portal.d.ts +6 -0
  150. package/dist/typescript/src/primitives/autocomplete/autocomplete-portal.d.ts.map +1 -0
  151. package/dist/typescript/src/primitives/autocomplete/autocomplete-root.d.ts +24 -0
  152. package/dist/typescript/src/primitives/autocomplete/autocomplete-root.d.ts.map +1 -0
  153. package/dist/typescript/src/primitives/autocomplete/context.d.ts +30 -0
  154. package/dist/typescript/src/primitives/autocomplete/context.d.ts.map +1 -0
  155. package/dist/typescript/src/primitives/autocomplete/index.d.ts +25 -0
  156. package/dist/typescript/src/primitives/autocomplete/index.d.ts.map +1 -0
  157. package/dist/typescript/src/primitives/autocomplete/types.d.ts +21 -0
  158. package/dist/typescript/src/primitives/autocomplete/types.d.ts.map +1 -0
  159. package/dist/typescript/src/primitives/dropdown-menu/dropdown-menu-divider.d.ts.map +1 -1
  160. package/dist/typescript/src/primitives/dropdown-menu/dropdown-menu-trigger.d.ts.map +1 -1
  161. package/dist/typescript/src/primitives/index.d.ts +2 -0
  162. package/dist/typescript/src/primitives/index.d.ts.map +1 -1
  163. package/dist/typescript/src/primitives/input/input.d.ts +1 -2
  164. package/dist/typescript/src/primitives/input/input.d.ts.map +1 -1
  165. package/dist/typescript/src/primitives/popover/popover-trigger.d.ts.map +1 -1
  166. package/dist/typescript/src/primitives/portal/portal.constants.d.ts +6 -2
  167. package/dist/typescript/src/primitives/portal/portal.constants.d.ts.map +1 -1
  168. package/dist/typescript/src/primitives/portal/portal.d.ts +2 -5
  169. package/dist/typescript/src/primitives/portal/portal.d.ts.map +1 -1
  170. package/dist/typescript/src/primitives/select/context.d.ts +5 -2
  171. package/dist/typescript/src/primitives/select/context.d.ts.map +1 -1
  172. package/dist/typescript/src/primitives/select/select-content.d.ts.map +1 -1
  173. package/dist/typescript/src/primitives/select/select-root.d.ts.map +1 -1
  174. package/dist/typescript/src/primitives/select/select-trigger.d.ts +0 -5
  175. package/dist/typescript/src/primitives/select/select-trigger.d.ts.map +1 -1
  176. package/dist/typescript/src/types/element.types.d.ts +10 -3
  177. package/dist/typescript/src/types/element.types.d.ts.map +1 -1
  178. package/dist/typescript/src/utils/normalize-layout.d.ts +3 -1
  179. package/dist/typescript/src/utils/normalize-layout.d.ts.map +1 -1
  180. package/package.json +8 -5
  181. package/scripts/build.sh +2 -2
  182. package/src/components/alert-dialog/alert-dialog.tsx +38 -0
  183. package/src/components/alert-dialog/async-alert-dialog.tsx +121 -0
  184. package/src/components/alert-dialog/index.ts +3 -0
  185. package/src/components/alert-dialog/variants/default.tsx +82 -0
  186. package/src/components/alert-dialog/variants/index.ts +5 -0
  187. package/src/components/autocomplete/autocomplete.tsx +34 -0
  188. package/src/components/autocomplete/variants/default.tsx +84 -0
  189. package/src/components/autocomplete/variants/index.ts +5 -0
  190. package/src/components/index.ts +2 -0
  191. package/src/components/input/numeric-input.tsx +8 -6
  192. package/src/index.tsx +2 -0
  193. package/src/primitives/alert-dialog/alert-dialog-action.tsx +27 -0
  194. package/src/primitives/alert-dialog/alert-dialog-cancel.tsx +27 -0
  195. package/src/primitives/alert-dialog/alert-dialog-content.tsx +21 -0
  196. package/src/primitives/alert-dialog/alert-dialog-description.tsx +21 -0
  197. package/src/primitives/alert-dialog/alert-dialog-footer.tsx +21 -0
  198. package/src/primitives/alert-dialog/alert-dialog-overlay.tsx +25 -0
  199. package/src/primitives/alert-dialog/alert-dialog-portal.tsx +20 -0
  200. package/src/primitives/alert-dialog/alert-dialog-root.tsx +25 -0
  201. package/src/primitives/alert-dialog/alert-dialog-title.tsx +21 -0
  202. package/src/primitives/alert-dialog/alert-dialog-trigger.tsx +27 -0
  203. package/src/primitives/alert-dialog/context.ts +18 -0
  204. package/src/primitives/alert-dialog/index.ts +34 -0
  205. package/src/primitives/alert-dialog/types.ts +13 -0
  206. package/src/primitives/autocomplete/autocomplete-content.tsx +38 -0
  207. package/src/primitives/autocomplete/autocomplete-empty.tsx +19 -0
  208. package/src/primitives/autocomplete/autocomplete-input.tsx +85 -0
  209. package/src/primitives/autocomplete/autocomplete-option.tsx +66 -0
  210. package/src/primitives/autocomplete/autocomplete-overlay.tsx +29 -0
  211. package/src/primitives/autocomplete/autocomplete-portal.tsx +27 -0
  212. package/src/primitives/autocomplete/autocomplete-root.tsx +111 -0
  213. package/src/primitives/autocomplete/context.ts +45 -0
  214. package/src/primitives/autocomplete/index.ts +27 -0
  215. package/src/primitives/autocomplete/types.ts +23 -0
  216. package/src/primitives/dropdown-menu/dropdown-menu-divider.tsx +2 -2
  217. package/src/primitives/dropdown-menu/dropdown-menu-trigger.tsx +3 -7
  218. package/src/primitives/index.ts +2 -0
  219. package/src/primitives/input/input.tsx +3 -6
  220. package/src/primitives/popover/popover-portal.tsx +1 -1
  221. package/src/primitives/popover/popover-trigger.tsx +3 -7
  222. package/src/primitives/portal/portal.constants.tsx +2 -2
  223. package/src/primitives/portal/portal.tsx +4 -36
  224. package/src/primitives/select/context.ts +5 -2
  225. package/src/primitives/select/select-content.tsx +16 -9
  226. package/src/primitives/select/select-root.tsx +7 -3
  227. package/src/primitives/select/select-trigger.tsx +19 -21
  228. package/src/types/element.types.ts +10 -3
  229. package/src/utils/normalize-layout.ts +22 -1
@@ -0,0 +1,45 @@
1
+ import type { LayoutPosition } from "@/hooks";
2
+ import { createContext, type Dispatch, useContext } from "react";
3
+ import type { LayoutRectangle } from "react-native";
4
+ import type { AutocompleteOption, AutocompleteState, AutocompleteStyles } from "./types";
5
+
6
+ export interface AutocompleteContext {
7
+ value?: string;
8
+ onChange?: (value: string) => void;
9
+ placeholder?: string;
10
+
11
+ inputValue?: string;
12
+ setInputValue?: (value: string) => void;
13
+
14
+ isOpen: boolean;
15
+ setIsOpen: Dispatch<React.SetStateAction<boolean>>;
16
+ inputPosition: LayoutPosition;
17
+ setInputPosition: Dispatch<React.SetStateAction<LayoutPosition>>;
18
+ contentLayout: LayoutRectangle;
19
+ setContentLayout: Dispatch<React.SetStateAction<LayoutRectangle>>;
20
+
21
+ options: Array<AutocompleteOption>;
22
+ setOptions: Dispatch<React.SetStateAction<Array<AutocompleteOption>>>;
23
+
24
+ openOnFocus: boolean;
25
+
26
+ blurInput: () => void;
27
+ setBlurInput: Dispatch<React.SetStateAction<() => void>>;
28
+ setInputDisplayValueSetter: Dispatch<React.SetStateAction<(value: string) => void>>;
29
+ setInputDisplayValue: (value: string) => void;
30
+
31
+ isDisabled: boolean;
32
+
33
+ state: AutocompleteState;
34
+ styles: AutocompleteStyles | null;
35
+ }
36
+
37
+ export const AutocompleteContext = createContext<AutocompleteContext | undefined>(undefined);
38
+
39
+ export const useAutocomplete = () => {
40
+ const context = useContext(AutocompleteContext);
41
+ if (!context) {
42
+ throw new Error("useAutocomplete must be used within an AutocompleteProvider");
43
+ }
44
+ return context;
45
+ };
@@ -0,0 +1,27 @@
1
+ export type { AutocompleteContentProps } from "./autocomplete-content";
2
+ export type { AutocompleteEmptyProps } from "./autocomplete-empty";
3
+ export type { AutocompleteInputProps } from "./autocomplete-input";
4
+ export type { AutocompleteOptionProps } from "./autocomplete-option";
5
+ export type { AutocompleteOverlayProps } from "./autocomplete-overlay";
6
+ export type { AutocompletePortalProps } from "./autocomplete-portal";
7
+ export type { AutocompleteRootBaseProps, AutocompleteRootProps } from "./autocomplete-root";
8
+ export { useAutocomplete } from "./context";
9
+ export type { AutocompleteOption, AutocompleteOptionState, AutocompleteState, AutocompleteStyles } from "./types";
10
+
11
+ import { AutocompleteContent } from "./autocomplete-content";
12
+ import { AutocompleteEmpty } from "./autocomplete-empty";
13
+ import { AutocompleteInput } from "./autocomplete-input";
14
+ import { AutocompleteOption } from "./autocomplete-option";
15
+ import { AutocompleteOverlay } from "./autocomplete-overlay";
16
+ import { AutocompletePortal } from "./autocomplete-portal";
17
+ import { AutocompleteRoot } from "./autocomplete-root";
18
+
19
+ export const AutocompletePrimitive = {
20
+ Root: AutocompleteRoot,
21
+ Input: AutocompleteInput,
22
+ Portal: AutocompletePortal,
23
+ Overlay: AutocompleteOverlay,
24
+ Content: AutocompleteContent,
25
+ Option: AutocompleteOption,
26
+ Empty: AutocompleteEmpty,
27
+ };
@@ -0,0 +1,23 @@
1
+ import type { AutocompleteContentProps } from "./autocomplete-content";
2
+ import type { AutocompleteEmptyProps } from "./autocomplete-empty";
3
+ import type { AutocompleteInputProps } from "./autocomplete-input";
4
+ import type { AutocompleteOptionProps } from "./autocomplete-option";
5
+ import type { AutocompleteOverlayProps } from "./autocomplete-overlay";
6
+ import type { AutocompleteRootProps } from "./autocomplete-root";
7
+
8
+ export type AutocompleteState = "default" | "focused" | "disabled";
9
+ export type AutocompleteOptionState = AutocompleteState | "hovered" | "selected";
10
+
11
+ export interface AutocompleteStyles {
12
+ root?: Partial<Record<AutocompleteState, AutocompleteRootProps["style"]>>;
13
+ input?: Partial<Record<AutocompleteState, AutocompleteInputProps["style"]>>;
14
+ overlay?: Partial<Record<AutocompleteState, AutocompleteOverlayProps["style"]>>;
15
+ content?: Partial<Record<AutocompleteState, AutocompleteContentProps["style"]>>;
16
+ option?: Partial<Record<AutocompleteOptionState, AutocompleteOptionProps["style"]>>;
17
+ empty?: Partial<Record<AutocompleteState, AutocompleteEmptyProps["style"]>>;
18
+ }
19
+
20
+ export interface AutocompleteOption {
21
+ value: string;
22
+ label: string;
23
+ }
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { type StyleProp, View, type ViewStyle } from "react-native";
2
+ import { type StyleProp, StyleSheet, View, type ViewStyle } from "react-native";
3
3
  import { useDropdownMenu } from "./context";
4
4
 
5
5
  export interface DropdownMenuDividerProps {
@@ -11,7 +11,7 @@ export interface DropdownMenuDividerProps {
11
11
  export function DropdownMenuDivider(props: DropdownMenuDividerProps) {
12
12
  const menu = useDropdownMenu();
13
13
 
14
- const composedStyle = [menu.styles?.divider, props.style];
14
+ const composedStyle = StyleSheet.flatten([menu.styles?.divider, props.style]);
15
15
 
16
16
  const Component = props.render ?? View;
17
17
  return <Component {...props} style={composedStyle} />;
@@ -1,4 +1,5 @@
1
1
  import type { ViewRef } from "@/types/element.types";
2
+ import { measureLayoutPosition } from "@/utils/normalize-layout";
2
3
  import React, { forwardRef, useImperativeHandle, useRef } from "react";
3
4
  import { type PressableProps } from "react-native";
4
5
  import { useDropdownMenu } from "./context";
@@ -18,13 +19,8 @@ export const DropdownMenuTrigger = forwardRef<DropdownMenuTriggerRef, DropdownMe
18
19
 
19
20
  const onTriggerPress = async () => {
20
21
  if (!dropdownMenu.isOpen) {
21
- triggerRef.current?.measureInWindow((pageX, pageY, width, height) => {
22
- dropdownMenu.setTriggerPosition({
23
- height,
24
- width,
25
- pageX,
26
- pageY,
27
- });
22
+ measureLayoutPosition(triggerRef.current, (layout) => {
23
+ dropdownMenu.setTriggerPosition(layout);
28
24
  dropdownMenu.setIsOpen(true);
29
25
  });
30
26
  } else {
@@ -2,6 +2,7 @@ export * from "./field";
2
2
  export * from "./input";
3
3
  export * from "./button";
4
4
  export * from "./select";
5
+ export * from "./autocomplete";
5
6
  export * from "./card";
6
7
  export * from "./empty";
7
8
  export * from "./avatar";
@@ -14,3 +15,4 @@ export * from "./portal";
14
15
  export * from "./calendar";
15
16
  export * from "./tabs";
16
17
  export * from "./checkbox";
18
+ export * from "./alert-dialog";
@@ -1,6 +1,6 @@
1
1
  import type { TextInputRef } from "@/types/element.types";
2
2
  import { forwardRef, useState } from "react";
3
- import { TextInput, type TextInputProps } from "react-native";
3
+ import { StyleSheet, TextInput, type TextInputProps } from "react-native";
4
4
  import { useFieldOptional } from "../field/context";
5
5
  import type { InputState, InputStyles } from "./types";
6
6
 
@@ -11,8 +11,6 @@ export type InputPrimitiveBaseProps = Omit<TextInputProps, "onChange"> & {
11
11
  };
12
12
 
13
13
  export interface InputPrimitiveProps extends InputPrimitiveBaseProps {
14
- render?: (props: InputPrimitiveProps) => React.ReactNode;
15
-
16
14
  styles?: InputStyles;
17
15
  }
18
16
 
@@ -31,16 +29,15 @@ export const InputPrimitive = forwardRef<TextInputRef, InputPrimitiveProps>((pro
31
29
  const state = calculateState(props, isFocused);
32
30
  const field = useFieldOptional();
33
31
 
34
- const composedStyles = [props.styles?.default?.style, props.styles?.[state]?.style, props.style];
32
+ const composedStyles = StyleSheet.flatten([props.styles?.default?.style, props.styles?.[state]?.style, props.style]);
35
33
  const composedProps = {
36
34
  ...props.styles?.default,
37
35
  ...props.styles?.[state],
38
36
  ...props,
39
37
  };
40
- const Component = props.render ?? TextInput;
41
38
 
42
39
  return (
43
- <Component
40
+ <TextInput
44
41
  {...composedProps}
45
42
  ref={ref}
46
43
  id={field?.id}
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { Portal } from "../portal";
3
- import { usePopover, PopoverContext } from "./context";
3
+ import { PopoverContext, usePopover } from "./context";
4
4
 
5
5
  export interface PopoverPortalProps {
6
6
  children?: React.ReactNode;
@@ -1,4 +1,5 @@
1
1
  import type { ViewRef } from "@/types/element.types";
2
+ import { measureLayoutPosition } from "@/utils/normalize-layout";
2
3
  import React, { forwardRef, useImperativeHandle, useRef } from "react";
3
4
  import { type PressableProps } from "react-native";
4
5
  import { usePopover } from "./context";
@@ -18,13 +19,8 @@ export const PopoverTrigger = forwardRef<PopoverTriggerRef, PopoverTriggerProps>
18
19
 
19
20
  const onTriggerPress = async () => {
20
21
  if (!popover.isOpen) {
21
- triggerRef.current?.measureInWindow((pageX, pageY, width, height) => {
22
- popover.setTriggerPosition({
23
- height,
24
- width,
25
- pageX,
26
- pageY,
27
- });
22
+ measureLayoutPosition(triggerRef.current, (layout) => {
23
+ popover.setTriggerPosition(layout);
28
24
  popover.setIsOpen(true);
29
25
  });
30
26
  } else {
@@ -3,8 +3,8 @@ export const DEFAULT_PORTAL_HOST = "__KOR_PORTAL_HOST__";
3
3
  export interface PortalHostProps {
4
4
  name?: string;
5
5
  container?: {
6
- ios?: React.ComponentType<React.PropsWithChildren>;
7
- android?: React.ComponentType<React.PropsWithChildren>;
6
+ ios?: React.ComponentType<{ children: React.ReactNode }>;
7
+ android?: React.ComponentType<{ children: React.ReactNode }>;
8
8
  };
9
9
  }
10
10
 
@@ -1,4 +1,4 @@
1
- import { useEffect, useState, useSyncExternalStore } from "react";
1
+ import { useEffect, useSyncExternalStore } from "react";
2
2
  import { Platform, View } from "react-native";
3
3
  import { DEFAULT_PORTAL_HOST, type PortalHostProps, type PortalProps } from "./portal.constants";
4
4
 
@@ -48,7 +48,7 @@ function removePortal(hostName: string, name: string) {
48
48
  emit();
49
49
  }
50
50
 
51
- function NativePortalHost({ name = DEFAULT_PORTAL_HOST, container }: PortalHostProps) {
51
+ export function PortalHost({ name = DEFAULT_PORTAL_HOST, container }: PortalHostProps) {
52
52
  const map = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
53
53
  const portalMap = map.get(name) ?? new Map<string, React.ReactNode>();
54
54
  if (portalMap.size === 0) return null;
@@ -69,23 +69,13 @@ function NativePortalHost({ name = DEFAULT_PORTAL_HOST, container }: PortalHostP
69
69
  }}
70
70
  />
71
71
  ),
72
- ios: container?.ios,
73
- android: container?.android,
72
+ ...container,
74
73
  });
75
74
 
76
75
  return <Container>{Array.from(portalMap.values())}</Container>;
77
76
  }
78
77
 
79
- function WebPortalHost() {
80
- return <></>;
81
- }
82
-
83
- export const PortalHost = Platform.select({
84
- default: NativePortalHost,
85
- web: WebPortalHost,
86
- });
87
-
88
- function NativePortal({ name, hostName = DEFAULT_PORTAL_HOST, children }: PortalProps) {
78
+ export function Portal({ name, hostName = DEFAULT_PORTAL_HOST, children }: PortalProps) {
89
79
  useEffect(() => {
90
80
  updatePortal(hostName, name, children);
91
81
  }, [hostName, name, children]);
@@ -98,25 +88,3 @@ function NativePortal({ name, hostName = DEFAULT_PORTAL_HOST, children }: Portal
98
88
 
99
89
  return <></>;
100
90
  }
101
-
102
- function WebPortal({ name, hostName = DEFAULT_PORTAL_HOST, children }: PortalProps) {
103
- const [] = useState(() => {
104
- let container = document.getElementById(hostName);
105
-
106
- if (!container) {
107
- container = document.createElement("div");
108
- container.id = hostName;
109
- document.body.appendChild(container);
110
- }
111
- return container;
112
- });
113
-
114
- const createPortal = require("react-dom").createPortal as typeof import("react-dom").createPortal;
115
-
116
- return <>{createPortal(children, document.body, name)}</>;
117
- }
118
-
119
- export const Portal = Platform.select({
120
- default: NativePortal,
121
- web: WebPortal,
122
- });
@@ -1,3 +1,4 @@
1
+ import type { LayoutPosition } from "@/hooks";
1
2
  import { createContext, type Dispatch, useContext } from "react";
2
3
  import type { LayoutRectangle } from "react-native";
3
4
  import type { SelectOption, SelectState, SelectStyles } from "./types";
@@ -9,8 +10,10 @@ export interface SelectContext {
9
10
 
10
11
  isOpen: boolean;
11
12
  setIsOpen: Dispatch<React.SetStateAction<boolean>>;
12
- triggerLayout: LayoutRectangle | null;
13
- setTriggerLayout: Dispatch<React.SetStateAction<LayoutRectangle | null>>;
13
+ triggerPosition: LayoutPosition;
14
+ setTriggerPosition: Dispatch<React.SetStateAction<LayoutPosition>>;
15
+ contentLayout: LayoutRectangle;
16
+ setContentLayout: Dispatch<React.SetStateAction<LayoutRectangle>>;
14
17
  options: Array<SelectOption>;
15
18
  setOptions: Dispatch<React.SetStateAction<Array<SelectOption>>>;
16
19
 
@@ -1,3 +1,4 @@
1
+ import { useRelativePosition } from "@/hooks/use-relative-position";
1
2
  import { calculateComposedStyles } from "@/utils/calculate-styles";
2
3
  import React from "react";
3
4
  import { type StyleProp, View, type ViewStyle } from "react-native";
@@ -15,18 +16,24 @@ export function SelectContent(props: SelectContentProps) {
15
16
  const select = useSelect();
16
17
  const composedStyles = calculateComposedStyles(select.styles, select.state, "content", props.style);
17
18
 
19
+ const positionStyle = useRelativePosition({
20
+ align: "start",
21
+ avoidCollisions: true,
22
+ triggerPosition: select.triggerPosition,
23
+ contentLayout: select.contentLayout,
24
+ alignOffset: 0,
25
+ side: "bottom",
26
+ sideOffset: 0,
27
+ });
28
+
18
29
  const Component = props.render ?? View;
19
30
  return (
20
31
  <Component
21
- style={[
22
- composedStyles,
23
- {
24
- position: "absolute",
25
- top: select.triggerLayout?.y! + select.triggerLayout?.height!,
26
- left: select.triggerLayout?.x!,
27
- width: select.triggerLayout?.width!,
28
- },
29
- ]}
32
+ style={[positionStyle, composedStyles, { width: select.triggerPosition.width }]}
33
+ onLayout={(e) => {
34
+ select.setContentLayout(e.nativeEvent.layout);
35
+ }}
36
+ pointerEvents="box-none"
30
37
  >
31
38
  {props.children}
32
39
  </Component>
@@ -1,3 +1,4 @@
1
+ import { DEFAULT_LAYOUT, DEFAULT_POSITION, type LayoutPosition } from "@/hooks";
1
2
  import { calculateComposedStyles } from "@/utils/calculate-styles";
2
3
  import React, { useState } from "react";
3
4
  import { type LayoutRectangle, type StyleProp, View, type ViewStyle } from "react-native";
@@ -34,7 +35,8 @@ const calculateState = (props: SelectRootProps): SelectState => {
34
35
 
35
36
  export function SelectRoot(props: SelectRootProps) {
36
37
  const [isOpen, setIsOpen] = useState(false);
37
- const [triggerLayout, setTriggerLayout] = useState<LayoutRectangle | null>(null);
38
+ const [contentLayout, setContentLayout] = useState<LayoutRectangle>(DEFAULT_LAYOUT);
39
+ const [triggerPosition, setTriggerPosition] = useState<LayoutPosition>(DEFAULT_POSITION);
38
40
  const [options, setOptions] = useState<Array<SelectOption>>([]);
39
41
 
40
42
  const state = calculateState(props);
@@ -49,8 +51,10 @@ export function SelectRoot(props: SelectRootProps) {
49
51
  placeholder: props.placeholder,
50
52
  isOpen,
51
53
  setIsOpen,
52
- triggerLayout,
53
- setTriggerLayout,
54
+ triggerPosition,
55
+ setTriggerPosition,
56
+ contentLayout,
57
+ setContentLayout,
54
58
  options,
55
59
  setOptions,
56
60
  state,
@@ -1,38 +1,36 @@
1
+ import type { ViewRef } from "@/types/element.types";
1
2
  import { calculateComposedStyles } from "@/utils/calculate-styles";
2
- import { normalizeLayout } from "@/utils/normalize-layout";
3
- import React from "react";
3
+ import { measureLayoutPosition } from "@/utils/normalize-layout";
4
+ import React, { useRef } from "react";
4
5
  import { Pressable, type StyleProp, type ViewStyle } from "react-native";
5
6
  import { useSelect } from "./context";
6
7
 
7
- interface SelectTriggerInjectionProps {
8
- onPress?: () => void;
9
- }
10
-
11
8
  export interface SelectTriggerProps {
12
9
  children?: React.ReactNode;
13
10
 
14
11
  style?: StyleProp<ViewStyle>;
15
-
16
- render?: (props: SelectTriggerInjectionProps) => React.ReactElement;
17
12
  }
18
13
 
19
14
  export function SelectTrigger(props: SelectTriggerProps) {
20
15
  const select = useSelect();
16
+ const triggerRef = useRef<ViewRef>(null);
17
+
21
18
  const composedStyles = calculateComposedStyles(select.styles, select.state, "trigger", props.style);
22
- const Component = props.render ?? Pressable;
19
+
20
+ const onTriggerPress = () => {
21
+ if (!select.isOpen) {
22
+ measureLayoutPosition(triggerRef.current, (layout) => {
23
+ select.setTriggerPosition(layout);
24
+ select.setIsOpen(true);
25
+ });
26
+ } else {
27
+ select.setIsOpen(false);
28
+ }
29
+ };
30
+
23
31
  return (
24
- <Component
25
- onPress={() => {
26
- select.setIsOpen((prev) => !prev);
27
- }}
28
- onLayout={(e) => {
29
- const layout = normalizeLayout(e.nativeEvent.layout);
30
- select.setTriggerLayout(layout);
31
- }}
32
- disabled={select.isDisabled}
33
- style={composedStyles}
34
- >
32
+ <Pressable ref={triggerRef} onPress={onTriggerPress} disabled={select.isDisabled} style={composedStyles}>
35
33
  {props.children}
36
- </Component>
34
+ </Pressable>
37
35
  );
38
36
  }
@@ -1,4 +1,11 @@
1
- import type { TextInput, View } from "react-native";
1
+ import type { HostInstance } from "react-native";
2
2
 
3
- export type ViewRef = React.ComponentRef<View>;
4
- export type TextInputRef = React.ComponentRef<TextInput>;
3
+ export type ViewRef = HostInstance;
4
+ export type TextInputRef = HostInstance & {
5
+ focus: () => void;
6
+ blur: () => void;
7
+ clear: () => void;
8
+ isFocused: () => boolean;
9
+ getNativeRef: () => HostInstance;
10
+ setSelection: (start: number, end?: number) => void;
11
+ };
@@ -1,4 +1,6 @@
1
- import type { LayoutRectangle } from "react-native";
1
+ import type { LayoutPosition } from "@/hooks";
2
+ import type { HostInstance, LayoutRectangle } from "react-native";
3
+
2
4
  export const normalizeLayout = (layout: LayoutRectangle) => {
3
5
  const _layout = { ...layout };
4
6
  // Web layout doesn't provide x/y, but left/top
@@ -10,3 +12,22 @@ export const normalizeLayout = (layout: LayoutRectangle) => {
10
12
  }
11
13
  return _layout;
12
14
  };
15
+
16
+ const isValidNumber = (value: unknown): value is number => {
17
+ const isValid = typeof value === "number" && !isNaN(value) && isFinite(value);
18
+ if (!isValid) {
19
+ console.warn(`Expected a valid number but received: ${value}`);
20
+ }
21
+ return isValid;
22
+ };
23
+
24
+ export const measureLayoutPosition = (ref: HostInstance | null, callback: (layout: LayoutPosition) => void) => {
25
+ ref?.measureInWindow((pageX, pageY, width, height) => {
26
+ callback({
27
+ height: isValidNumber(height) ? height : 0,
28
+ width: isValidNumber(width) ? width : 0,
29
+ pageX: isValidNumber(pageX) ? pageX : 0,
30
+ pageY: isValidNumber(pageY) ? pageY : 0,
31
+ });
32
+ });
33
+ };