react-native-molecules 0.5.0-beta.0

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 (355) hide show
  1. package/components/Accordion/Accordion.tsx +89 -0
  2. package/components/Accordion/AccordionItem.tsx +94 -0
  3. package/components/Accordion/AccordionItemContent.tsx +17 -0
  4. package/components/Accordion/AccordionItemHeader.tsx +122 -0
  5. package/components/Accordion/index.tsx +36 -0
  6. package/components/Accordion/utils.ts +62 -0
  7. package/components/ActivityIndicator/ActivityIndicator.ios.tsx +1 -0
  8. package/components/ActivityIndicator/ActivityIndicator.tsx +200 -0
  9. package/components/ActivityIndicator/AnimatedSpinner.tsx +121 -0
  10. package/components/ActivityIndicator/index.tsx +17 -0
  11. package/components/Appbar/AppbarActions.tsx +13 -0
  12. package/components/Appbar/AppbarBase.tsx +60 -0
  13. package/components/Appbar/AppbarCenterAligned.tsx +13 -0
  14. package/components/Appbar/AppbarLarge.tsx +13 -0
  15. package/components/Appbar/AppbarLeft.tsx +26 -0
  16. package/components/Appbar/AppbarMedium.tsx +13 -0
  17. package/components/Appbar/AppbarRight.tsx +40 -0
  18. package/components/Appbar/AppbarSmall.tsx +13 -0
  19. package/components/Appbar/AppbarTitle.tsx +49 -0
  20. package/components/Appbar/index.tsx +46 -0
  21. package/components/Appbar/types.ts +19 -0
  22. package/components/Appbar/utils.ts +127 -0
  23. package/components/Avatar/Avatar.tsx +189 -0
  24. package/components/Avatar/index.tsx +11 -0
  25. package/components/Avatar/utils.ts +35 -0
  26. package/components/Backdrop/Backdrop.tsx +18 -0
  27. package/components/Backdrop/index.tsx +11 -0
  28. package/components/Backdrop/types.ts +3 -0
  29. package/components/Backdrop/utils.ts +21 -0
  30. package/components/Badge/Badge.tsx +29 -0
  31. package/components/Badge/index.tsx +11 -0
  32. package/components/Badge/utils.ts +38 -0
  33. package/components/Button/Button.tsx +349 -0
  34. package/components/Button/index.tsx +11 -0
  35. package/components/Button/types.ts +5 -0
  36. package/components/Button/utils.ts +416 -0
  37. package/components/Card/Card.tsx +160 -0
  38. package/components/Card/CardActions.tsx +18 -0
  39. package/components/Card/CardContent.tsx +29 -0
  40. package/components/Card/CardHeader.tsx +31 -0
  41. package/components/Card/CardHeadline.tsx +15 -0
  42. package/components/Card/CardMedia.tsx +36 -0
  43. package/components/Card/CardSubhead.tsx +15 -0
  44. package/components/Card/CardText.tsx +13 -0
  45. package/components/Card/CardTypography.tsx +113 -0
  46. package/components/Card/index.tsx +38 -0
  47. package/components/Card/types.ts +1 -0
  48. package/components/Card/utils.ts +23 -0
  49. package/components/Checkbox/Checkbox.tsx +123 -0
  50. package/components/Checkbox/CheckboxBase.ios.tsx +86 -0
  51. package/components/Checkbox/CheckboxBase.tsx +216 -0
  52. package/components/Checkbox/index.tsx +11 -0
  53. package/components/Checkbox/types.ts +72 -0
  54. package/components/Checkbox/utils.ts +210 -0
  55. package/components/Chip/Chip.tsx +416 -0
  56. package/components/Chip/index.tsx +51 -0
  57. package/components/Chip/utils.ts +100 -0
  58. package/components/DatePickerDocked/DatePickerDocked.tsx +30 -0
  59. package/components/DatePickerDocked/DatePickerDockedHeader.tsx +129 -0
  60. package/components/DatePickerDocked/index.tsx +21 -0
  61. package/components/DatePickerDocked/types.ts +11 -0
  62. package/components/DatePickerDocked/utils.ts +155 -0
  63. package/components/DatePickerInline/AutoSizer.tsx +46 -0
  64. package/components/DatePickerInline/DatePickerContext.tsx +21 -0
  65. package/components/DatePickerInline/DatePickerInline.tsx +82 -0
  66. package/components/DatePickerInline/DatePickerInlineBase.tsx +181 -0
  67. package/components/DatePickerInline/DatePickerInlineHeader.tsx +108 -0
  68. package/components/DatePickerInline/Day.tsx +88 -0
  69. package/components/DatePickerInline/DayName.tsx +17 -0
  70. package/components/DatePickerInline/DayNames.tsx +32 -0
  71. package/components/DatePickerInline/DayRange.tsx +48 -0
  72. package/components/DatePickerInline/HeaderItem.tsx +111 -0
  73. package/components/DatePickerInline/Month.tsx +233 -0
  74. package/components/DatePickerInline/MonthPicker.tsx +174 -0
  75. package/components/DatePickerInline/Swiper.native.tsx +172 -0
  76. package/components/DatePickerInline/Swiper.tsx +172 -0
  77. package/components/DatePickerInline/SwiperUtils.ts +40 -0
  78. package/components/DatePickerInline/Week.tsx +67 -0
  79. package/components/DatePickerInline/YearPicker.tsx +139 -0
  80. package/components/DatePickerInline/dateUtils.tsx +334 -0
  81. package/components/DatePickerInline/index.tsx +41 -0
  82. package/components/DatePickerInline/types.ts +104 -0
  83. package/components/DatePickerInline/utils.ts +367 -0
  84. package/components/DatePickerInput/DatePickerInput.tsx +139 -0
  85. package/components/DatePickerInput/DatePickerInputModal.tsx +48 -0
  86. package/components/DatePickerInput/DatePickerInputWithoutModal.tsx +77 -0
  87. package/components/DatePickerInput/DateRangeInput.tsx +88 -0
  88. package/components/DatePickerInput/index.tsx +14 -0
  89. package/components/DatePickerInput/inputUtils.ts +138 -0
  90. package/components/DatePickerInput/types.ts +28 -0
  91. package/components/DatePickerInput/utils.ts +16 -0
  92. package/components/DatePickerModal/AnimatedCrossView.tsx +94 -0
  93. package/components/DatePickerModal/CalendarEdit.tsx +139 -0
  94. package/components/DatePickerModal/DatePickerModal.tsx +85 -0
  95. package/components/DatePickerModal/DatePickerModalContent.tsx +155 -0
  96. package/components/DatePickerModal/DatePickerModalContentHeader.tsx +213 -0
  97. package/components/DatePickerModal/DatePickerModalHeader.tsx +74 -0
  98. package/components/DatePickerModal/DatePickerModalHeaderBackground.tsx +13 -0
  99. package/components/DatePickerModal/index.tsx +20 -0
  100. package/components/DatePickerModal/types.ts +92 -0
  101. package/components/DatePickerModal/utils.ts +121 -0
  102. package/components/DateTimePicker/DateTimePicker.tsx +172 -0
  103. package/components/DateTimePicker/index.tsx +14 -0
  104. package/components/DateTimePicker/utils.ts +13 -0
  105. package/components/Dialog/Dialog.tsx +66 -0
  106. package/components/Dialog/DialogActions.tsx +89 -0
  107. package/components/Dialog/DialogContent.tsx +37 -0
  108. package/components/Dialog/DialogIcon.tsx +69 -0
  109. package/components/Dialog/DialogTitle.tsx +68 -0
  110. package/components/Dialog/index.tsx +37 -0
  111. package/components/Dialog/utils.ts +80 -0
  112. package/components/Drawer/Collapsible/DrawerCollapsible.tsx +22 -0
  113. package/components/Drawer/Collapsible/DrawerCollapsibleItem.tsx +38 -0
  114. package/components/Drawer/Collapsible/DrawerCollapsibleItemContent.tsx +16 -0
  115. package/components/Drawer/Collapsible/DrawerCollapsibleItemHeader.tsx +48 -0
  116. package/components/Drawer/Collapsible/index.tsx +23 -0
  117. package/components/Drawer/Collapsible/utils.ts +49 -0
  118. package/components/Drawer/Drawer.tsx +43 -0
  119. package/components/Drawer/DrawerContent.tsx +35 -0
  120. package/components/Drawer/DrawerFooter.tsx +27 -0
  121. package/components/Drawer/DrawerHeader.tsx +27 -0
  122. package/components/Drawer/DrawerItem.tsx +206 -0
  123. package/components/Drawer/DrawerItemGroup.tsx +82 -0
  124. package/components/Drawer/index.tsx +47 -0
  125. package/components/Drawer/types.ts +3 -0
  126. package/components/Drawer/utils.ts +8 -0
  127. package/components/ElementGroup/ElementGroup.tsx +139 -0
  128. package/components/ElementGroup/index.tsx +11 -0
  129. package/components/ElementGroup/utils.ts +25 -0
  130. package/components/FAB/FAB.tsx +176 -0
  131. package/components/FAB/index.tsx +12 -0
  132. package/components/FAB/types.ts +1 -0
  133. package/components/FAB/utils.ts +221 -0
  134. package/components/FilePicker/FilePicker.tsx +133 -0
  135. package/components/FilePicker/index.tsx +11 -0
  136. package/components/FilePicker/utils.ts +13 -0
  137. package/components/HelperText/HelperText.tsx +139 -0
  138. package/components/HelperText/index.tsx +11 -0
  139. package/components/HelperText/utils.ts +29 -0
  140. package/components/HorizontalDivider/HorizontalDivider.tsx +101 -0
  141. package/components/HorizontalDivider/index.tsx +13 -0
  142. package/components/Icon/CrossFadeIcon.tsx +116 -0
  143. package/components/Icon/Icon.tsx +41 -0
  144. package/components/Icon/iconFactory.tsx +23 -0
  145. package/components/Icon/index.tsx +11 -0
  146. package/components/Icon/types.ts +35 -0
  147. package/components/IconButton/IconButton.tsx +218 -0
  148. package/components/IconButton/index.tsx +11 -0
  149. package/components/IconButton/types.ts +1 -0
  150. package/components/IconButton/utils.ts +325 -0
  151. package/components/If/index.tsx +13 -0
  152. package/components/InputAddon/InputAddon.tsx +27 -0
  153. package/components/InputAddon/index.tsx +11 -0
  154. package/components/InputAddon/utils.ts +33 -0
  155. package/components/Link/Link.tsx +48 -0
  156. package/components/Link/index.tsx +11 -0
  157. package/components/Link/utils.ts +37 -0
  158. package/components/ListItem/ListItem.tsx +136 -0
  159. package/components/ListItem/ListItemDescription.tsx +25 -0
  160. package/components/ListItem/ListItemTitle.tsx +25 -0
  161. package/components/ListItem/index.tsx +18 -0
  162. package/components/ListItem/utils.ts +113 -0
  163. package/components/Menu/Menu.tsx +69 -0
  164. package/components/Menu/MenuDivider.tsx +13 -0
  165. package/components/Menu/MenuItem.tsx +128 -0
  166. package/components/Menu/index.tsx +19 -0
  167. package/components/Menu/utils.ts +92 -0
  168. package/components/Modal/Modal.tsx +261 -0
  169. package/components/Modal/index.tsx +11 -0
  170. package/components/Modal/utils.ts +45 -0
  171. package/components/NavigationRail/NavigationRail.tsx +32 -0
  172. package/components/NavigationRail/NavigationRailContent.tsx +25 -0
  173. package/components/NavigationRail/NavigationRailFooter.tsx +18 -0
  174. package/components/NavigationRail/NavigationRailHeader.tsx +18 -0
  175. package/components/NavigationRail/NavigationRailItem.tsx +226 -0
  176. package/components/NavigationRail/index.tsx +35 -0
  177. package/components/NavigationRail/utils.ts +170 -0
  178. package/components/NavigationStack/NavigationStack.tsx +85 -0
  179. package/components/NavigationStack/NavigationStackItem.tsx +60 -0
  180. package/components/NavigationStack/index.tsx +20 -0
  181. package/components/NavigationStack/utils.tsx +16 -0
  182. package/components/Popover/Popover.native.tsx +185 -0
  183. package/components/Popover/Popover.tsx +198 -0
  184. package/components/Popover/common.ts +459 -0
  185. package/components/Popover/index.ts +2 -0
  186. package/components/Portal/Portal.tsx +13 -0
  187. package/components/Portal/index.tsx +12 -0
  188. package/components/RadioButton/RadioButton.tsx +138 -0
  189. package/components/RadioButton/RadioButtonAndroid.tsx +188 -0
  190. package/components/RadioButton/RadioButtonGroup.tsx +98 -0
  191. package/components/RadioButton/RadioButtonIOS.tsx +106 -0
  192. package/components/RadioButton/RadioButtonItem.tsx +232 -0
  193. package/components/RadioButton/index.ts +27 -0
  194. package/components/RadioButton/utils.ts +164 -0
  195. package/components/Rating/Rating.tsx +149 -0
  196. package/components/Rating/RatingItem.tsx +125 -0
  197. package/components/Rating/index.tsx +13 -0
  198. package/components/Rating/utils.ts +38 -0
  199. package/components/Select/Select.tsx +1038 -0
  200. package/components/Select/index.ts +14 -0
  201. package/components/Select/types.ts +115 -0
  202. package/components/StateLayer/StateLayer.tsx +12 -0
  203. package/components/StateLayer/index.tsx +11 -0
  204. package/components/StateLayer/utils.ts +17 -0
  205. package/components/Surface/BackgroundContextWrapper.tsx +27 -0
  206. package/components/Surface/Surface.android.tsx +62 -0
  207. package/components/Surface/Surface.ios.tsx +123 -0
  208. package/components/Surface/Surface.tsx +48 -0
  209. package/components/Surface/index.tsx +12 -0
  210. package/components/Surface/utils.ts +106 -0
  211. package/components/Switch/Switch.ios.tsx +67 -0
  212. package/components/Switch/Switch.tsx +278 -0
  213. package/components/Switch/index.tsx +11 -0
  214. package/components/Switch/utils.ts +283 -0
  215. package/components/Tabs/TabItem.tsx +150 -0
  216. package/components/Tabs/TabLabel.tsx +84 -0
  217. package/components/Tabs/Tabs.tsx +398 -0
  218. package/components/Tabs/index.tsx +21 -0
  219. package/components/Tabs/utils.ts +126 -0
  220. package/components/Text/Text.tsx +23 -0
  221. package/components/Text/index.tsx +2 -0
  222. package/components/Text/textFactory.tsx +33 -0
  223. package/components/TextInput/InputLabel.tsx +181 -0
  224. package/components/TextInput/TextInput.tsx +693 -0
  225. package/components/TextInput/index.tsx +16 -0
  226. package/components/TextInput/types.ts +96 -0
  227. package/components/TextInput/utils.ts +544 -0
  228. package/components/TextInputWithMask/TextInputMask.tsx +57 -0
  229. package/components/TextInputWithMask/index.tsx +11 -0
  230. package/components/TextInputWithMask/utils.ts +56 -0
  231. package/components/TimePicker/AmPmSwitcher.tsx +99 -0
  232. package/components/TimePicker/AnalogClock.tsx +165 -0
  233. package/components/TimePicker/AnalogClockHours.tsx +163 -0
  234. package/components/TimePicker/AnalogClockMinutes.tsx +68 -0
  235. package/components/TimePicker/AnimatedClockSwitcher.tsx +72 -0
  236. package/components/TimePicker/DisplayModeContext.tsx +6 -0
  237. package/components/TimePicker/TimeInput.tsx +112 -0
  238. package/components/TimePicker/TimeInputs.tsx +148 -0
  239. package/components/TimePicker/TimePicker.tsx +130 -0
  240. package/components/TimePicker/index.tsx +19 -0
  241. package/components/TimePicker/timeUtils.ts +159 -0
  242. package/components/TimePicker/utils.ts +285 -0
  243. package/components/TimePickerField/TimePickerField.tsx +152 -0
  244. package/components/TimePickerField/index.tsx +14 -0
  245. package/components/TimePickerField/sanitizeTime.ts +85 -0
  246. package/components/TimePickerField/utils.ts +95 -0
  247. package/components/TimePickerModal/TimePickerModal.tsx +115 -0
  248. package/components/TimePickerModal/index.tsx +14 -0
  249. package/components/TimePickerModal/utils.ts +48 -0
  250. package/components/Tooltip/Tooltip.tsx +137 -0
  251. package/components/Tooltip/TooltipContent.tsx +12 -0
  252. package/components/Tooltip/TooltipTrigger.tsx +94 -0
  253. package/components/Tooltip/index.tsx +20 -0
  254. package/components/Tooltip/utils.ts +21 -0
  255. package/components/TouchableRipple/TouchableRipple.native.tsx +105 -0
  256. package/components/TouchableRipple/TouchableRipple.tsx +286 -0
  257. package/components/TouchableRipple/index.tsx +14 -0
  258. package/components/TouchableRipple/utils.ts +15 -0
  259. package/components/VerticalDivider/VerticalDivider.tsx +99 -0
  260. package/components/VerticalDivider/index.tsx +13 -0
  261. package/context-bridge/index.tsx +87 -0
  262. package/core/componentsRegistry.ts +164 -0
  263. package/core/index.tsx +2 -0
  264. package/fast-context/index.tsx +190 -0
  265. package/hocs/index.tsx +5 -0
  266. package/hocs/typedMemo.tsx +5 -0
  267. package/hocs/withKeyboardAccessibility.tsx +231 -0
  268. package/hocs/withPortal.tsx +16 -0
  269. package/hooks/createPsuedoHook.tsx +50 -0
  270. package/hooks/index.tsx +29 -0
  271. package/hooks/useActionState.native.tsx +22 -0
  272. package/hooks/useActionState.tsx +34 -0
  273. package/hooks/useActive.tsx +5 -0
  274. package/hooks/useBreakpoints.tsx +7 -0
  275. package/hooks/useColorMode.tsx +17 -0
  276. package/hooks/useContrastColor.ts +15 -0
  277. package/hooks/useControlledValue.tsx +68 -0
  278. package/hooks/useFilePicker.tsx +48 -0
  279. package/hooks/useFocus.tsx +5 -0
  280. package/hooks/useHandleNumberFormat.tsx +106 -0
  281. package/hooks/useHover.tsx +5 -0
  282. package/hooks/useKeyboardDismissable.ts +66 -0
  283. package/hooks/useLatest.tsx +9 -0
  284. package/hooks/useMediaQuery.tsx +64 -0
  285. package/hooks/useMergedRefs.ts +14 -0
  286. package/hooks/usePrevious.ts +13 -0
  287. package/hooks/useQueryFilter.tsx +35 -0
  288. package/hooks/useSearchable.tsx +74 -0
  289. package/hooks/useSubcomponents.tsx +59 -0
  290. package/hooks/useTheme.ts +3 -0
  291. package/hooks/useToggle.tsx +24 -0
  292. package/package.json +114 -0
  293. package/shortcuts-manager/EventsManager.tsx +121 -0
  294. package/shortcuts-manager/ShortcutsManager/ShortcutsManager.native.tsx +9 -0
  295. package/shortcuts-manager/ShortcutsManager/ShortcutsManager.tsx +58 -0
  296. package/shortcuts-manager/ShortcutsManager/index.tsx +2 -0
  297. package/shortcuts-manager/ShortcutsManager/utils.tsx +30 -0
  298. package/shortcuts-manager/index.tsx +6 -0
  299. package/shortcuts-manager/types.ts +24 -0
  300. package/shortcuts-manager/useIsKeyPressed/index.tsx +1 -0
  301. package/shortcuts-manager/useIsKeyPressed/useIsKeyPress.tsx +9 -0
  302. package/shortcuts-manager/useSetScopes/index.tsx +1 -0
  303. package/shortcuts-manager/useSetScopes/useSetScopes.native.tsx +9 -0
  304. package/shortcuts-manager/useSetScopes/useSetScopes.tsx +25 -0
  305. package/shortcuts-manager/useShortcut/index.tsx +2 -0
  306. package/shortcuts-manager/useShortcut/types.ts +3 -0
  307. package/shortcuts-manager/useShortcut/useShortcut.native.tsx +9 -0
  308. package/shortcuts-manager/useShortcut/useShortcut.tsx +61 -0
  309. package/shortcuts-manager/utils.ts +105 -0
  310. package/styles/index.ts +4 -0
  311. package/styles/overlay.ts +69 -0
  312. package/styles/shadow.ts +21 -0
  313. package/styles/themes/DarkTheme.tsx +98 -0
  314. package/styles/themes/LightTheme.tsx +212 -0
  315. package/styles/themes/tokens.ts +248 -0
  316. package/styles/utils.ts +11 -0
  317. package/types/index.ts +129 -0
  318. package/types/theme.ts +159 -0
  319. package/utils/DocumentPicker/documentPicker.native.ts +10 -0
  320. package/utils/DocumentPicker/documentPicker.ts +76 -0
  321. package/utils/DocumentPicker/index.ts +2 -0
  322. package/utils/DocumentPicker/types.ts +28 -0
  323. package/utils/addEventListener.tsx +51 -0
  324. package/utils/backgroundContext.ts +9 -0
  325. package/utils/color.ts +22 -0
  326. package/utils/compare/index.ts +54 -0
  327. package/utils/composeEventHandlers.ts +9 -0
  328. package/utils/createNumberMask/createNumberMask.ts +98 -0
  329. package/utils/createNumberMask/index.ts +5 -0
  330. package/utils/createSyntheticEvent.ts +31 -0
  331. package/utils/date-fns.ts +7 -0
  332. package/utils/dateTimePicker.ts +5 -0
  333. package/utils/escapeRegex.ts +9 -0
  334. package/utils/extractTextStyles.ts +52 -0
  335. package/utils/formatNumberWithMask/formatNumberWithMask.ts +26 -0
  336. package/utils/formatNumberWithMask/formatWithMask.ts +119 -0
  337. package/utils/formatNumberWithMask/index.ts +6 -0
  338. package/utils/getCursorStyle/getCursorStyle.native.ts +1 -0
  339. package/utils/getCursorStyle/getCursorStyle.ts +1 -0
  340. package/utils/getCursorStyle/index.ts +1 -0
  341. package/utils/getOS/getOS.native.ts +7 -0
  342. package/utils/getOS/getOS.ts +24 -0
  343. package/utils/getOS/index.ts +1 -0
  344. package/utils/getyearRange.ts +5 -0
  345. package/utils/index.ts +20 -0
  346. package/utils/lodash.ts +50 -0
  347. package/utils/mergeRefs.ts +13 -0
  348. package/utils/normalizeBorderRadiuses.ts +24 -0
  349. package/utils/normalizeSpacings.ts +110 -0
  350. package/utils/normalizeToNumberString/index.ts +4 -0
  351. package/utils/normalizeToNumberString/normalizeToNumberString.ts +48 -0
  352. package/utils/repository.ts +103 -0
  353. package/utils/resolveColorMode.ts +9 -0
  354. package/utils/resolveStateVariant.ts +26 -0
  355. package/utils/tokenStylesParser.ts +7 -0
@@ -0,0 +1,190 @@
1
+ import {
2
+ type Context,
3
+ createContext,
4
+ type ReactNode,
5
+ type RefObject,
6
+ useCallback,
7
+ useContext,
8
+ useEffect,
9
+ useMemo,
10
+ useRef,
11
+ } from 'react';
12
+ import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector';
13
+
14
+ import typedMemo from '../hocs/typedMemo';
15
+ import { usePrevious } from '../hooks';
16
+ import { shallowCompare } from '../utils';
17
+
18
+ type StoreDataType = Record<string, any>;
19
+
20
+ type SelectorOutputType<IStore, SelectorOutput> = (store: IStore) => SelectorOutput;
21
+
22
+ type UseStoreDataReturnType<T> = {
23
+ get: () => T;
24
+ set: (value: (prev: T) => Partial<T>) => void;
25
+ store: RefObject<T>;
26
+ subscribe: (callback: () => void) => () => void;
27
+ };
28
+
29
+ const useStoreData = <IStore extends StoreDataType>(
30
+ value: IStore,
31
+ defaultValue: IStore | null,
32
+ watch: boolean = false,
33
+ ): UseStoreDataReturnType<IStore> => {
34
+ const store = useRef<IStore>({ ...defaultValue, ...(value as IStore) });
35
+ const watchRef = useRef(watch);
36
+
37
+ const get = useCallback(() => store.current, [store]);
38
+
39
+ const subscribers = useRef(new Set<() => void>());
40
+
41
+ const set = useCallback(
42
+ (callback: (prev: IStore) => Partial<IStore>) => {
43
+ store.current = { ...store.current, ...callback(store.current) };
44
+ subscribers.current.forEach(subscriber => subscriber());
45
+ },
46
+ [store],
47
+ );
48
+
49
+ const subscribe = useCallback((callback: () => void) => {
50
+ subscribers.current.add(callback);
51
+
52
+ return () => subscribers.current.delete(callback);
53
+ }, []);
54
+
55
+ /** The effect is required to trigger the updates on the consumers */
56
+ useEffect(() => {
57
+ if (!watchRef.current) return;
58
+ set(prev => ({ ...prev, ...value }));
59
+ }, [set, value]);
60
+
61
+ /**
62
+ * Cases:
63
+ * 1. when the value updates, we want the data to be updated immediately
64
+ * 2. the data stored in store.current may not be current with regards to the parent and the parent must have dropped the references related to the data.
65
+ * 3. because store.current is a ref, on watch and change, if we update store.current, no side-effect introduced.
66
+ */
67
+ if (usePrevious(value).current !== value && watchRef.current) {
68
+ store.current = { ...store.current, ...value };
69
+ }
70
+
71
+ return useMemo(
72
+ () => ({
73
+ get,
74
+ set,
75
+ subscribe,
76
+ store,
77
+ }),
78
+ [get, set, subscribe],
79
+ );
80
+ };
81
+
82
+ export const createFastContext = <T extends StoreDataType = {}>(
83
+ defaultValue: T | null = null,
84
+ watch: boolean = false,
85
+ ) => {
86
+ const context = createContext<UseStoreDataReturnType<T> | null>(null);
87
+
88
+ return {
89
+ /**
90
+ * using the value from here will never cause a rerender as context is based on refs.
91
+ */
92
+ useStoreRef: createUseRefContext(context),
93
+
94
+ /**
95
+ *
96
+ * the value is memoized and thus changing the value will have no effect.
97
+ * use key prop to unmount and remount if necessary. alternatively use set from the context to update the value.
98
+ *
99
+ */
100
+ Provider: createProvider<T>(
101
+ context as Context<UseStoreDataReturnType<T>>,
102
+ defaultValue,
103
+ watch,
104
+ ),
105
+
106
+ /**
107
+ *
108
+ * @param selector
109
+ * @param equalityCheck
110
+ * @returns tuple, first item is return value of the selector and the second item is setter
111
+ *
112
+ */
113
+ useContext: <SelectorOutput,>(
114
+ selector: SelectorOutputType<T, SelectorOutput>,
115
+ equalityCheck = shallowCompare,
116
+ ) => useStore(context as Context<UseStoreDataReturnType<T>>, selector, equalityCheck),
117
+
118
+ /**
119
+ *
120
+ * @param selector
121
+ * @param equalityCheck
122
+ * @returns return value of the selector
123
+ *
124
+ */
125
+ useContextValue: <SelectorOutput,>(
126
+ selector: SelectorOutputType<T, SelectorOutput>,
127
+ equalityCheck = shallowCompare,
128
+ ) => useStoreValue(context as Context<UseStoreDataReturnType<T>>, selector, equalityCheck),
129
+ /**
130
+ * context of the store. Useful for ContextBridge
131
+ */
132
+ Context: context,
133
+ };
134
+ };
135
+
136
+ export const createProvider = <T extends Record<string, any> = {}>(
137
+ StoreContext: Context<UseStoreDataReturnType<T>>,
138
+ defaultValue: T | null,
139
+ watch: boolean,
140
+ ) =>
141
+ typedMemo(({ value, children }: { value: T; children: ReactNode }) => {
142
+ return (
143
+ <StoreContext.Provider value={useStoreData<T>(value, defaultValue, watch) as any}>
144
+ {children}
145
+ </StoreContext.Provider>
146
+ );
147
+ });
148
+
149
+ export const createUseRefContext = <T,>(_Context: Context<UseStoreDataReturnType<T> | null>) => {
150
+ return () => {
151
+ const value = useContext<UseStoreDataReturnType<T> | null>(_Context);
152
+ if (value === null)
153
+ throw 'Fast Context requires the value to be wrapped in a Provider with a value.';
154
+
155
+ return value;
156
+ };
157
+ };
158
+
159
+ export const useStore = <IStore extends StoreDataType, SelectorOutput>(
160
+ _Context: Context<UseStoreDataReturnType<IStore>>,
161
+ selector: SelectorOutputType<IStore, SelectorOutput>,
162
+ equalityFn = Object.is,
163
+ ): [SelectorOutput, (value: (prev: IStore) => Partial<IStore>) => void] => {
164
+ const store = useContext(_Context);
165
+ if (!store) {
166
+ throw new Error('Store not found');
167
+ }
168
+
169
+ const state = useSyncExternalStoreWithSelector(
170
+ store.subscribe,
171
+ () => {
172
+ return store.get();
173
+ },
174
+ undefined,
175
+ snapshot => {
176
+ return selector(snapshot);
177
+ },
178
+ equalityFn,
179
+ );
180
+
181
+ return [state, store.set];
182
+ };
183
+
184
+ export const useStoreValue = <IStore extends StoreDataType, SelectorOutput>(
185
+ _Context: Context<UseStoreDataReturnType<IStore>>,
186
+ selector: SelectorOutputType<IStore, SelectorOutput>,
187
+ equalityFn = Object.is,
188
+ ) => {
189
+ return useStore(_Context, selector, equalityFn)[0];
190
+ };
package/hocs/index.tsx ADDED
@@ -0,0 +1,5 @@
1
+ export { default as typedMemo } from './typedMemo';
2
+ export {
3
+ useCurrentIndexStore,
4
+ default as withKeyboardAccessibility,
5
+ } from './withKeyboardAccessibility';
@@ -0,0 +1,5 @@
1
+ import { memo } from 'react';
2
+
3
+ const typedMemo: <T>(c: T) => T = memo;
4
+
5
+ export default typedMemo;
@@ -0,0 +1,231 @@
1
+ import {
2
+ type ComponentType,
3
+ forwardRef,
4
+ Fragment,
5
+ memo,
6
+ type ReactNode,
7
+ type RefObject,
8
+ useCallback,
9
+ useEffect,
10
+ useImperativeHandle,
11
+ useMemo,
12
+ useRef,
13
+ } from 'react';
14
+ import type { FlatList } from 'react-native';
15
+ import type { SectionList } from 'react-native';
16
+ import { Platform } from 'react-native';
17
+
18
+ import { createFastContext } from '../fast-context';
19
+ import useLatest from '../hooks/useLatest';
20
+
21
+ export type Store = {
22
+ currentIndex: number | null;
23
+ };
24
+
25
+ const defaultValue = { currentIndex: null };
26
+
27
+ const {
28
+ useStoreRef,
29
+ Provider,
30
+ useContext: useFastContext,
31
+ useContextValue,
32
+ } = createFastContext<Store>();
33
+
34
+ const withKeyboardAccessibility = <P extends Record<string, any>>(
35
+ Component: ComponentType<P>,
36
+ key: string = 'records',
37
+ isFlat: boolean = false,
38
+ ) =>
39
+ // @ts-expect-error // TODO - fix ts issues
40
+ forwardRef(({ enableKeyboardNavigation, onCancel, ...props }: P, ref: any) => {
41
+ const componentRef = useRef<FlatList | SectionList>(null);
42
+ const records = props[key] as any[];
43
+
44
+ const recordsIndexMap = useMemo(() => {
45
+ if (!records) return {};
46
+
47
+ const flattenRecords = isFlat
48
+ ? records
49
+ : records.reduce((acc, item, sectionIndex) => {
50
+ return acc.concat(
51
+ (item.data || []).map((t: any) => ({ ...t, sectionIndex })),
52
+ );
53
+ }, [] as any[]);
54
+
55
+ return flattenRecords.reduce((acc: Record<number, any>, item: any, i: number) => {
56
+ acc[i] = item;
57
+
58
+ return acc;
59
+ }, {} as Record<number, any>);
60
+ }, [records]);
61
+
62
+ const length = useMemo(() => {
63
+ if (!isFlat) {
64
+ return records.reduce((acc, item) => {
65
+ acc += item.data.length;
66
+ return acc;
67
+ }, 0);
68
+ }
69
+
70
+ return records.length;
71
+ }, [records]);
72
+
73
+ const onSelectItem = useCallback(
74
+ (index: number) => {
75
+ const selectItem = recordsIndexMap[index];
76
+
77
+ if (!selectItem) return props.onSelectionChange?.(props.selection);
78
+
79
+ props.onSelectionChange?.(
80
+ props.multiple ? [...props.selection, selectItem] : selectItem,
81
+ );
82
+ },
83
+ [props, recordsIndexMap],
84
+ );
85
+
86
+ useImperativeHandle(ref, () => componentRef.current);
87
+
88
+ const Wrapper =
89
+ enableKeyboardNavigation && Platform.OS === 'web' ? AccessibilityWrapper : Fragment;
90
+
91
+ const accessibilityWrapperProps =
92
+ enableKeyboardNavigation && Platform.OS === 'web'
93
+ ? {
94
+ listRef: componentRef as any,
95
+ listLength: length,
96
+ onSelectItem: onSelectItem,
97
+ isFlat,
98
+ onCancel,
99
+ }
100
+ : {};
101
+
102
+ return (
103
+ <Provider value={defaultValue}>
104
+ <Wrapper
105
+ {...(accessibilityWrapperProps as Omit<AccessibilityWrapperProps, 'children'>)}>
106
+ <Component {...(props as P)} ref={componentRef} />
107
+ </Wrapper>
108
+ </Provider>
109
+ );
110
+ });
111
+
112
+ type AccessibilityWrapperProps = {
113
+ children: ReactNode;
114
+ listRef: RefObject<FlatList> | RefObject<SectionList>;
115
+ listLength: number;
116
+ onSelectItem: (index: number) => void;
117
+ isFlat: boolean;
118
+ onCancel?: () => void;
119
+ };
120
+
121
+ const withPreventDefault =
122
+ (func: (e: KeyboardEvent) => void, preventDefault = true) =>
123
+ (e: KeyboardEvent) => {
124
+ if (preventDefault) e.preventDefault();
125
+ func(e);
126
+ };
127
+
128
+ const AccessibilityWrapper = memo(
129
+ ({
130
+ children,
131
+ listRef,
132
+ listLength,
133
+ onSelectItem,
134
+ isFlat,
135
+ onCancel,
136
+ }: AccessibilityWrapperProps) => {
137
+ const [currentIndex, setStore] = useFastContext(state => state.currentIndex);
138
+
139
+ // use the ref here to avoid recreation of the keyToFunctionMap function
140
+ const { store: currentIndexRef } = useStoreRef();
141
+
142
+ const keyToFunctionMap = useMemo(
143
+ () => ({
144
+ ArrowUp: withPreventDefault(() =>
145
+ setStore(prev => ({
146
+ currentIndex:
147
+ prev.currentIndex === null || prev.currentIndex === 0
148
+ ? listLength - 1
149
+ : prev.currentIndex - 1,
150
+ })),
151
+ ),
152
+ ArrowDown: withPreventDefault(() =>
153
+ setStore(prev => ({
154
+ currentIndex:
155
+ prev.currentIndex === null || prev.currentIndex === listLength - 1
156
+ ? 0
157
+ : prev.currentIndex + 1,
158
+ })),
159
+ ),
160
+ Enter: withPreventDefault(e => {
161
+ if (currentIndexRef.current.currentIndex === null) return;
162
+ e.preventDefault();
163
+ onSelectItem(currentIndexRef.current.currentIndex);
164
+ }, false),
165
+ Escape: withPreventDefault(e => {
166
+ if (currentIndexRef.current.currentIndex === null) onCancel?.();
167
+ e.preventDefault();
168
+ setStore(() => ({
169
+ currentIndex: null,
170
+ }));
171
+ }, false),
172
+ }),
173
+ [currentIndexRef, listLength, onCancel, onSelectItem, setStore],
174
+ );
175
+
176
+ const onKeyPress = useCallback(
177
+ (e: KeyboardEvent) => {
178
+ const keyFunction = keyToFunctionMap[e.key as keyof typeof keyToFunctionMap];
179
+
180
+ if (!keyFunction) return;
181
+
182
+ keyFunction(e);
183
+ },
184
+ [keyToFunctionMap],
185
+ );
186
+
187
+ const listLengthLatest = useLatest(listLength);
188
+ useEffect(() => {
189
+ if (listRef && !!listRef.current) {
190
+ if (
191
+ currentIndex === null ||
192
+ currentIndex < 0 ||
193
+ currentIndex > listLengthLatest.current - 1
194
+ )
195
+ return;
196
+
197
+ if (isFlat) {
198
+ (listRef as RefObject<FlatList>).current?.scrollToIndex?.({
199
+ index: currentIndex || 0,
200
+ animated: false,
201
+ });
202
+ } else {
203
+ (listRef as RefObject<SectionList>).current?.scrollToLocation({
204
+ animated: false,
205
+ sectionIndex: 0,
206
+ itemIndex: currentIndex,
207
+ });
208
+ }
209
+ }
210
+ }, [currentIndex, isFlat, listRef, listLengthLatest]);
211
+
212
+ useEffect(() => {
213
+ const controller = new AbortController();
214
+ window.addEventListener('keydown', onKeyPress, {
215
+ capture: true,
216
+ signal: controller.signal,
217
+ } as AddEventListenerOptions);
218
+
219
+ return () => {
220
+ controller.abort();
221
+ };
222
+ }, [onKeyPress]);
223
+
224
+ return <>{children}</>;
225
+ },
226
+ );
227
+
228
+ export const useCurrentIndexStore = useFastContext;
229
+ export const useCurrentIndexStoreValue = useContextValue;
230
+
231
+ export default withKeyboardAccessibility;
@@ -0,0 +1,16 @@
1
+ import { type ComponentType } from 'react';
2
+
3
+ import { Portal } from '../components/Portal';
4
+
5
+ const withPortal =
6
+ <T,>(Component: ComponentType<T>) =>
7
+ (props: T) => {
8
+ return (
9
+ <Portal name={'withPortal' + (Component.displayName ?? '')}>
10
+ {/* @ts-ignore */}
11
+ <Component {...(props as T)} />
12
+ </Portal>
13
+ );
14
+ };
15
+
16
+ export default withPortal;
@@ -0,0 +1,50 @@
1
+ import * as React from 'react';
2
+ import { Platform } from 'react-native';
3
+
4
+ export default function createPseudoHook<T>({ events }: { events: string[] }) {
5
+ return function (ref: React.RefObject<T>, listen: boolean = true) {
6
+ if (Platform.OS !== 'web') {
7
+ return false;
8
+ }
9
+
10
+ const [isActive, setActive] = React.useState(false);
11
+
12
+ React.useEffect(() => {
13
+ const [eventIn, eventOut] = events;
14
+
15
+ const node = ref?.current;
16
+ if (!node || !listen) {
17
+ return;
18
+ }
19
+ const resolve = (value: boolean) => {
20
+ setActive(value);
21
+ };
22
+
23
+ // @ts-ignore
24
+ const onStart = resolve.bind(this, true);
25
+ // @ts-ignore
26
+ const onEnd = resolve.bind(this, false);
27
+
28
+ // @ts-ignore
29
+ node.addEventListener(eventIn, onStart);
30
+ // @ts-ignore
31
+ node.addEventListener(eventOut, onEnd);
32
+
33
+ // Special case for useActive to respond when the user drags out of the view and releases.
34
+ if (eventOut === 'mouseup') {
35
+ document.addEventListener(eventOut, onEnd, false);
36
+ }
37
+ return () => {
38
+ document.removeEventListener(eventOut, onEnd, false);
39
+ // @ts-ignore
40
+ node.removeEventListener(eventIn, onStart);
41
+ // @ts-ignore
42
+ node.removeEventListener(eventOut, onEnd);
43
+ };
44
+ // we only take initial value of listen
45
+ // eslint-disable-next-line
46
+ }, [ref]);
47
+
48
+ return isActive;
49
+ };
50
+ }
@@ -0,0 +1,29 @@
1
+ // export { usePortal } from '@gorhom/portal';
2
+
3
+ export * from './useActionState';
4
+ export * from './useActive';
5
+ export { default as useBreakpoints } from './useBreakpoints';
6
+ export { default as useColorMode } from './useColorMode';
7
+ export { useContrastColor } from './useContrastColor';
8
+ export { default as useControlledValue } from './useControlledValue';
9
+ export * from './useFocus';
10
+ export {
11
+ type NumberMaskConfig,
12
+ default as useHandleNumberFormat,
13
+ type UseHandleNumberFormatProps,
14
+ } from './useHandleNumberFormat';
15
+ export * from './useHover';
16
+ export * from './useKeyboardDismissable';
17
+ export { default as useLatest } from './useLatest';
18
+ export { useMediaQuery } from './useMediaQuery';
19
+ export { useMergedRefs } from './useMergedRefs';
20
+ export { default as usePrevious } from './usePrevious';
21
+ export * from './useQueryFilter';
22
+ export {
23
+ default as useSearchable,
24
+ type UseSearchableProps,
25
+ useSearchInputProps,
26
+ } from './useSearchable';
27
+ export { default as useSubcomponents, type UseSubcomponentsProps } from './useSubcomponents';
28
+ export * from './useTheme';
29
+ export { default as useToggle } from './useToggle';
@@ -0,0 +1,22 @@
1
+ import { type RefObject, useRef } from 'react';
2
+
3
+ export type UseActionStateProps = {
4
+ pressed?: boolean;
5
+ hovered?: boolean;
6
+ focused?: boolean;
7
+ actionsToListen?: ('pressed' | 'hovered' | 'focused')[];
8
+ };
9
+
10
+ export const useActionState = (
11
+ props: UseActionStateProps & { ref?: RefObject<any> | React.ForwardedRef<any> } = {},
12
+ ) => {
13
+ const ref = useRef(null);
14
+ const actionsRef = (props.ref ?? ref) as RefObject<any>;
15
+
16
+ return {
17
+ actionsRef,
18
+ hovered: false,
19
+ pressed: false,
20
+ focused: false,
21
+ };
22
+ };
@@ -0,0 +1,34 @@
1
+ import { type RefObject, useRef } from 'react';
2
+
3
+ import { useActive } from './useActive';
4
+ import { useFocus } from './useFocus';
5
+ import { useHover } from './useHover';
6
+
7
+ export type UseActionStateProps = {
8
+ pressed?: boolean;
9
+ hovered?: boolean;
10
+ focused?: boolean;
11
+ actionsToListen?: ('press' | 'hover' | 'focus')[];
12
+ };
13
+
14
+ export const useActionState = (
15
+ props: UseActionStateProps & { ref?: RefObject<any> | React.ForwardedRef<any> } = {},
16
+ ) => {
17
+ const ref = useRef(null);
18
+ const actionsRef = (
19
+ (props.ref as any)?.current === undefined ? ref : props.ref
20
+ ) as RefObject<any>;
21
+ const hovered =
22
+ useHover(actionsRef, props.actionsToListen?.includes('hover')) || !!props.hovered;
23
+ const pressed =
24
+ useActive(actionsRef, props.actionsToListen?.includes('press')) || !!props.pressed;
25
+ const focused =
26
+ useFocus(actionsRef, props.actionsToListen?.includes('focus')) || !!props.focused;
27
+
28
+ return {
29
+ actionsRef,
30
+ hovered,
31
+ pressed,
32
+ focused,
33
+ };
34
+ };
@@ -0,0 +1,5 @@
1
+ import createPseudoHook from './createPsuedoHook';
2
+
3
+ export const useActive = createPseudoHook({
4
+ events: ['mousedown', 'mouseup'],
5
+ });
@@ -0,0 +1,7 @@
1
+ import { useTheme } from './useTheme';
2
+
3
+ const useBreakpoints = () => {
4
+ return useTheme().grid.breakpoints;
5
+ };
6
+
7
+ export default useBreakpoints;
@@ -0,0 +1,17 @@
1
+ import { useMemo } from 'react';
2
+ import { UnistylesRuntime, useUnistyles } from 'react-native-unistyles';
3
+
4
+ import { type ColorMode, resolveColorMode } from '../utils/resolveColorMode';
5
+
6
+ const useColorMode = () => {
7
+ const themeName = useUnistyles().theme.dark ? 'dark' : 'light';
8
+ return useMemo(
9
+ () => ({
10
+ colorMode: resolveColorMode(themeName as ColorMode),
11
+ setColorMode: UnistylesRuntime.setTheme,
12
+ }),
13
+ [themeName],
14
+ );
15
+ };
16
+
17
+ export default useColorMode;
@@ -0,0 +1,15 @@
1
+ import { useMemo } from 'react';
2
+ import { useUnistyles } from 'react-native-unistyles';
3
+
4
+ import { resolveContrastColor } from '../utils/color';
5
+
6
+ export const useContrastColor = (bgColor: string, lightColor?: string, darkColor?: string) => {
7
+ const isDarkMode = useUnistyles().theme.dark;
8
+
9
+ return useMemo(
10
+ () => resolveContrastColor(bgColor, lightColor, darkColor, isDarkMode),
11
+ [bgColor, lightColor, darkColor, isDarkMode],
12
+ );
13
+ };
14
+
15
+ export default useContrastColor;