@duro-app/ui 5.12.0 → 5.14.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 (270) hide show
  1. package/README.md +49 -0
  2. package/dist/Table-DnaoH-h5.js +1806 -0
  3. package/dist/Table-DnaoH-h5.js.map +1 -0
  4. package/dist/components/AppShell/native.css.d.ts +53 -0
  5. package/dist/components/AppShell/native.css.d.ts.map +1 -0
  6. package/dist/components/Button/Button.d.ts.map +1 -1
  7. package/dist/components/ColorMode/ColorMode.d.ts +2 -1
  8. package/dist/components/ColorMode/ColorMode.d.ts.map +1 -1
  9. package/dist/components/ColorMode/storage.d.ts +4 -0
  10. package/dist/components/ColorMode/storage.d.ts.map +1 -0
  11. package/dist/components/ColorMode/styles.css.d.ts +4 -0
  12. package/dist/components/ColorMode/styles.css.d.ts.map +1 -1
  13. package/dist/components/ColorMode/useSystemScheme.d.ts +7 -0
  14. package/dist/components/ColorMode/useSystemScheme.d.ts.map +1 -0
  15. package/dist/components/Combobox/Combobox.d.ts +7 -2
  16. package/dist/components/Combobox/Combobox.d.ts.map +1 -1
  17. package/dist/components/Combobox/comboboxState.d.ts +29 -0
  18. package/dist/components/Combobox/comboboxState.d.ts.map +1 -0
  19. package/dist/components/Combobox/native.css.d.ts +27 -0
  20. package/dist/components/Combobox/native.css.d.ts.map +1 -0
  21. package/dist/components/Combobox/useComboboxRoot.d.ts +6 -10
  22. package/dist/components/Combobox/useComboboxRoot.d.ts.map +1 -1
  23. package/dist/components/Drawer/Drawer.d.ts +12 -37
  24. package/dist/components/Drawer/Drawer.d.ts.map +1 -1
  25. package/dist/components/Drawer/Drawer.meta.d.ts.map +1 -1
  26. package/dist/components/Drawer/DrawerScroll.stories.d.ts.map +1 -1
  27. package/dist/components/Drawer/DrawerSnap.stories.d.ts +22 -0
  28. package/dist/components/Drawer/DrawerSnap.stories.d.ts.map +1 -0
  29. package/dist/components/Drawer/native.css.d.ts +59 -0
  30. package/dist/components/Drawer/native.css.d.ts.map +1 -0
  31. package/dist/components/Drawer/parts.css.d.ts +96 -0
  32. package/dist/components/Drawer/parts.css.d.ts.map +1 -0
  33. package/dist/components/Drawer/parts.d.ts +56 -0
  34. package/dist/components/Drawer/parts.d.ts.map +1 -0
  35. package/dist/components/Drawer/sheetPhysics.d.ts +56 -0
  36. package/dist/components/Drawer/sheetPhysics.d.ts.map +1 -0
  37. package/dist/components/Drawer/styles.css.d.ts +16 -57
  38. package/dist/components/Drawer/styles.css.d.ts.map +1 -1
  39. package/dist/components/Drawer/touchInput.d.ts +35 -0
  40. package/dist/components/Drawer/touchInput.d.ts.map +1 -0
  41. package/dist/components/Drawer/useDrawerRoot.d.ts +33 -0
  42. package/dist/components/Drawer/useDrawerRoot.d.ts.map +1 -0
  43. package/dist/components/Drawer/useSheetHeights.d.ts +7 -0
  44. package/dist/components/Drawer/useSheetHeights.d.ts.map +1 -0
  45. package/dist/components/Drawer/useSwipeDismiss.d.ts +13 -2
  46. package/dist/components/Drawer/useSwipeDismiss.d.ts.map +1 -1
  47. package/dist/components/Form/FormSubmitContext.d.ts +8 -0
  48. package/dist/components/Form/FormSubmitContext.d.ts.map +1 -0
  49. package/dist/components/Listbox/native.css.d.ts +84 -0
  50. package/dist/components/Listbox/native.css.d.ts.map +1 -0
  51. package/dist/components/Menu/Menu.d.ts +7 -1
  52. package/dist/components/Menu/Menu.d.ts.map +1 -1
  53. package/dist/components/Menu/native.css.d.ts +14 -0
  54. package/dist/components/Menu/native.css.d.ts.map +1 -0
  55. package/dist/components/Menu/useMenuOpen.d.ts +16 -0
  56. package/dist/components/Menu/useMenuOpen.d.ts.map +1 -0
  57. package/dist/components/Menu/useMenuRoot.d.ts +3 -6
  58. package/dist/components/Menu/useMenuRoot.d.ts.map +1 -1
  59. package/dist/components/Popover/native.css.d.ts +11 -0
  60. package/dist/components/Popover/native.css.d.ts.map +1 -0
  61. package/dist/components/Select/Select.d.ts +9 -2
  62. package/dist/components/Select/Select.d.ts.map +1 -1
  63. package/dist/components/Select/Select.stories.d.ts +11 -0
  64. package/dist/components/Select/Select.stories.d.ts.map +1 -1
  65. package/dist/components/Select/native.css.d.ts +11 -0
  66. package/dist/components/Select/native.css.d.ts.map +1 -0
  67. package/dist/components/Select/selectState.d.ts +21 -0
  68. package/dist/components/Select/selectState.d.ts.map +1 -0
  69. package/dist/components/Select/styles.css.d.ts +10 -0
  70. package/dist/components/Select/styles.css.d.ts.map +1 -1
  71. package/dist/components/Select/useSelectRoot.d.ts +6 -8
  72. package/dist/components/Select/useSelectRoot.d.ts.map +1 -1
  73. package/dist/components/SideNav/Chevron.d.ts +4 -0
  74. package/dist/components/SideNav/Chevron.d.ts.map +1 -0
  75. package/dist/components/SideNav/SideNav.d.ts.map +1 -1
  76. package/dist/components/SideNav/styles.css.d.ts +6 -0
  77. package/dist/components/SideNav/styles.css.d.ts.map +1 -1
  78. package/dist/components/SideNav/types.d.ts +6 -0
  79. package/dist/components/SideNav/types.d.ts.map +1 -0
  80. package/dist/components/SplitPane/SplitPane.d.ts +38 -0
  81. package/dist/components/SplitPane/SplitPane.d.ts.map +1 -0
  82. package/dist/components/SplitPane/SplitPane.meta.d.ts +3 -0
  83. package/dist/components/SplitPane/SplitPane.meta.d.ts.map +1 -0
  84. package/dist/components/SplitPane/SplitPane.stories.d.ts +17 -0
  85. package/dist/components/SplitPane/SplitPane.stories.d.ts.map +1 -0
  86. package/dist/components/SplitPane/styles.css.d.ts +78 -0
  87. package/dist/components/SplitPane/styles.css.d.ts.map +1 -0
  88. package/dist/components/Tabs/TabLayout.d.ts +7 -0
  89. package/dist/components/Tabs/TabLayout.d.ts.map +1 -0
  90. package/dist/components/Tabs/Tabs.d.ts.map +1 -1
  91. package/dist/components/Tabs/indicator.d.ts +28 -0
  92. package/dist/components/Tabs/indicator.d.ts.map +1 -0
  93. package/dist/components/Tabs/styles.css.d.ts +4 -0
  94. package/dist/components/Tabs/styles.css.d.ts.map +1 -1
  95. package/dist/components/Tabs/useTabIndicator.d.ts +4 -0
  96. package/dist/components/Tabs/useTabIndicator.d.ts.map +1 -0
  97. package/dist/components/Tabs/useTabKeys.d.ts +13 -0
  98. package/dist/components/Tabs/useTabKeys.d.ts.map +1 -0
  99. package/dist/components/Tag/RemoveGlyph.d.ts +4 -0
  100. package/dist/components/Tag/RemoveGlyph.d.ts.map +1 -0
  101. package/dist/components/Tag/Tag.d.ts +2 -24
  102. package/dist/components/Tag/Tag.d.ts.map +1 -1
  103. package/dist/components/Tag/styles.css.d.ts +8 -0
  104. package/dist/components/Tag/styles.css.d.ts.map +1 -1
  105. package/dist/components/Tag/types.d.ts +39 -0
  106. package/dist/components/Tag/types.d.ts.map +1 -0
  107. package/dist/components/ThemeProvider/ThemeOverrides.stories.d.ts +13 -0
  108. package/dist/components/ThemeProvider/ThemeOverrides.stories.d.ts.map +1 -0
  109. package/dist/components/ThemeProvider/ThemeProvider.d.ts +9 -2
  110. package/dist/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  111. package/dist/components/ThemeProvider/overrideRule.d.ts +7 -0
  112. package/dist/components/ThemeProvider/overrideRule.d.ts.map +1 -0
  113. package/dist/components/ThemeProvider/overrides.d.ts +16 -0
  114. package/dist/components/ThemeProvider/overrides.d.ts.map +1 -0
  115. package/dist/components/Toast/ToastProvider.d.ts +2 -21
  116. package/dist/components/Toast/ToastProvider.d.ts.map +1 -1
  117. package/dist/components/Toast/native.css.d.ts +81 -0
  118. package/dist/components/Toast/native.css.d.ts.map +1 -0
  119. package/dist/components/Toast/store.d.ts +47 -0
  120. package/dist/components/Toast/store.d.ts.map +1 -0
  121. package/dist/components/Tooltip/TooltipHint.d.ts +9 -0
  122. package/dist/components/Tooltip/TooltipHint.d.ts.map +1 -0
  123. package/dist/components/Tree/Tree.d.ts.map +1 -1
  124. package/dist/components/Tree/styles.css.d.ts +6 -0
  125. package/dist/components/Tree/styles.css.d.ts.map +1 -1
  126. package/dist/components/Tree/useTreeKeyboard.d.ts +19 -0
  127. package/dist/components/Tree/useTreeKeyboard.d.ts.map +1 -0
  128. package/dist/components/VirtualList/VirtualList.d.ts +33 -0
  129. package/dist/components/VirtualList/VirtualList.d.ts.map +1 -0
  130. package/dist/components/VirtualList/VirtualList.meta.d.ts +3 -0
  131. package/dist/components/VirtualList/VirtualList.meta.d.ts.map +1 -0
  132. package/dist/components/VirtualList/VirtualList.stories.d.ts +15 -0
  133. package/dist/components/VirtualList/VirtualList.stories.d.ts.map +1 -0
  134. package/dist/components/VirtualList/styles.css.d.ts +28 -0
  135. package/dist/components/VirtualList/styles.css.d.ts.map +1 -0
  136. package/dist/index.css +1 -1
  137. package/dist/index.d.ts +4 -2
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/index.js +5090 -4381
  140. package/dist/index.js.map +1 -1
  141. package/dist/shared/ButtonHost.d.ts +11 -0
  142. package/dist/shared/ButtonHost.d.ts.map +1 -0
  143. package/dist/shared/pressableChild.d.ts +14 -0
  144. package/dist/shared/pressableChild.d.ts.map +1 -0
  145. package/dist/shared/textOf.d.ts +7 -0
  146. package/dist/shared/textOf.d.ts.map +1 -0
  147. package/dist/table.js +1 -1
  148. package/package.json +3 -2
  149. package/src/components/AppShell/AppShell.meta.ts +1 -1
  150. package/src/components/AppShell/AppShell.native.tsx +174 -0
  151. package/src/components/AppShell/native.css.ts +56 -0
  152. package/src/components/Button/Button.tsx +15 -4
  153. package/src/components/ColorMode/ColorMode.meta.ts +1 -1
  154. package/src/components/ColorMode/ColorMode.tsx +16 -37
  155. package/src/components/ColorMode/storage.native.ts +8 -0
  156. package/src/components/ColorMode/storage.ts +19 -0
  157. package/src/components/ColorMode/styles.css.ts +6 -0
  158. package/src/components/ColorMode/useSystemScheme.native.ts +6 -0
  159. package/src/components/ColorMode/useSystemScheme.ts +19 -0
  160. package/src/components/Combobox/Combobox.meta.ts +1 -1
  161. package/src/components/Combobox/Combobox.native.tsx +295 -0
  162. package/src/components/Combobox/Combobox.tsx +14 -8
  163. package/src/components/Combobox/comboboxState.ts +107 -0
  164. package/src/components/Combobox/native.css.ts +33 -0
  165. package/src/components/Combobox/useComboboxRoot.ts +17 -91
  166. package/src/components/Drawer/Drawer.meta.ts +2 -1
  167. package/src/components/Drawer/Drawer.native.tsx +491 -0
  168. package/src/components/Drawer/Drawer.tsx +65 -143
  169. package/src/components/Drawer/DrawerScroll.stories.tsx +4 -54
  170. package/src/components/Drawer/DrawerSnap.stories.tsx +225 -0
  171. package/src/components/Drawer/native.css.ts +62 -0
  172. package/src/components/Drawer/parts.css.ts +125 -0
  173. package/src/components/Drawer/parts.tsx +110 -0
  174. package/src/components/Drawer/sheetPhysics.ts +103 -0
  175. package/src/components/Drawer/styles.css.ts +18 -73
  176. package/src/components/Drawer/touchInput.ts +81 -0
  177. package/src/components/Drawer/useDrawerRoot.ts +90 -0
  178. package/src/components/Drawer/useSheetHeights.ts +42 -0
  179. package/src/components/Drawer/useSwipeDismiss.ts +146 -23
  180. package/src/components/Form/Form.meta.ts +1 -1
  181. package/src/components/Form/Form.native.tsx +120 -0
  182. package/src/components/Form/FormSubmitContext.ts +12 -0
  183. package/src/components/Listbox/Listbox.meta.ts +1 -1
  184. package/src/components/Listbox/Listbox.native.tsx +153 -0
  185. package/src/components/Listbox/native.css.ts +91 -0
  186. package/src/components/Menu/Menu.meta.ts +1 -1
  187. package/src/components/Menu/Menu.native.tsx +268 -0
  188. package/src/components/Menu/Menu.tsx +11 -2
  189. package/src/components/Menu/native.css.ts +18 -0
  190. package/src/components/Menu/useMenuOpen.ts +33 -0
  191. package/src/components/Menu/useMenuRoot.ts +7 -26
  192. package/src/components/Popover/Popover.meta.ts +1 -1
  193. package/src/components/Popover/Popover.native.tsx +205 -0
  194. package/src/components/Popover/native.css.ts +13 -0
  195. package/src/components/ScrollArea/ScrollArea.meta.ts +1 -1
  196. package/src/components/ScrollArea/ScrollArea.native.tsx +61 -0
  197. package/src/components/Select/Select.meta.ts +1 -1
  198. package/src/components/Select/Select.native.tsx +224 -0
  199. package/src/components/Select/Select.stories.tsx +49 -1
  200. package/src/components/Select/Select.tsx +20 -3
  201. package/src/components/Select/native.css.ts +13 -0
  202. package/src/components/Select/selectState.ts +36 -0
  203. package/src/components/Select/styles.css.ts +11 -0
  204. package/src/components/Select/useSelectRoot.ts +9 -30
  205. package/src/components/SideNav/Chevron.native.tsx +20 -0
  206. package/src/components/SideNav/Chevron.tsx +20 -0
  207. package/src/components/SideNav/SideNav.meta.ts +1 -1
  208. package/src/components/SideNav/SideNav.tsx +57 -41
  209. package/src/components/SideNav/styles.css.ts +8 -0
  210. package/src/components/SideNav/types.ts +6 -0
  211. package/src/components/SplitPane/SplitPane.meta.ts +40 -0
  212. package/src/components/SplitPane/SplitPane.native.tsx +47 -0
  213. package/src/components/SplitPane/SplitPane.stories.tsx +148 -0
  214. package/src/components/SplitPane/SplitPane.tsx +218 -0
  215. package/src/components/SplitPane/styles.css.ts +81 -0
  216. package/src/components/Tabs/TabLayout.native.tsx +9 -0
  217. package/src/components/Tabs/TabLayout.tsx +6 -0
  218. package/src/components/Tabs/Tabs.meta.ts +1 -1
  219. package/src/components/Tabs/Tabs.tsx +38 -136
  220. package/src/components/Tabs/indicator.ts +36 -0
  221. package/src/components/Tabs/styles.css.ts +7 -0
  222. package/src/components/Tabs/useTabIndicator.native.ts +35 -0
  223. package/src/components/Tabs/useTabIndicator.ts +49 -0
  224. package/src/components/Tabs/useTabKeys.native.ts +2 -0
  225. package/src/components/Tabs/useTabKeys.ts +99 -0
  226. package/src/components/Tag/RemoveGlyph.native.tsx +17 -0
  227. package/src/components/Tag/RemoveGlyph.tsx +10 -0
  228. package/src/components/Tag/Tag.meta.ts +1 -1
  229. package/src/components/Tag/Tag.native.tsx +70 -0
  230. package/src/components/Tag/Tag.tsx +9 -37
  231. package/src/components/Tag/styles.css.ts +9 -0
  232. package/src/components/Tag/types.ts +43 -0
  233. package/src/components/ThemeProvider/ThemeOverrides.stories.tsx +113 -0
  234. package/src/components/ThemeProvider/ThemeProvider.meta.ts +1 -1
  235. package/src/components/ThemeProvider/ThemeProvider.native.tsx +36 -7
  236. package/src/components/ThemeProvider/ThemeProvider.tsx +42 -6
  237. package/src/components/ThemeProvider/overrideRule.ts +39 -0
  238. package/src/components/ThemeProvider/overrides.ts +27 -0
  239. package/src/components/Toast/Toast.meta.ts +1 -1
  240. package/src/components/Toast/ToastProvider.native.tsx +226 -0
  241. package/src/components/Toast/ToastProvider.tsx +22 -84
  242. package/src/components/Toast/native.css.ts +78 -0
  243. package/src/components/Toast/store.ts +96 -0
  244. package/src/components/Toggle/Toggle.tsx +3 -3
  245. package/src/components/Tooltip/Tooltip.meta.ts +1 -1
  246. package/src/components/Tooltip/Tooltip.native.tsx +36 -0
  247. package/src/components/Tooltip/TooltipHint.ts +13 -0
  248. package/src/components/Tree/Tree.meta.ts +1 -1
  249. package/src/components/Tree/Tree.tsx +23 -135
  250. package/src/components/Tree/styles.css.ts +6 -0
  251. package/src/components/Tree/useTreeKeyboard.native.ts +5 -0
  252. package/src/components/Tree/useTreeKeyboard.ts +152 -0
  253. package/src/components/VirtualList/VirtualList.meta.ts +39 -0
  254. package/src/components/VirtualList/VirtualList.stories.tsx +95 -0
  255. package/src/components/VirtualList/VirtualList.tsx +103 -0
  256. package/src/components/VirtualList/styles.css.ts +31 -0
  257. package/src/form.native.ts +7 -0
  258. package/src/hooks/useContainerBelow.native.ts +30 -0
  259. package/src/index.native.ts +48 -0
  260. package/src/index.ts +9 -1
  261. package/src/shared/ButtonHost.native.tsx +70 -0
  262. package/src/shared/ButtonHost.tsx +12 -0
  263. package/src/shared/focusInput.native.ts +18 -0
  264. package/src/shared/portal/AnchoredOverlay.native.tsx +117 -0
  265. package/src/shared/pressableChild.ts +33 -0
  266. package/src/shared/textOf.ts +13 -0
  267. package/src/shared/useKeyboardHeight.native.ts +18 -0
  268. package/src/shared/useScreenReaderEnabled.native.ts +19 -0
  269. package/dist/Table-ColfpgKV.js +0 -1552
  270. package/dist/Table-ColfpgKV.js.map +0 -1
@@ -47,10 +47,50 @@ export {
47
47
  export {List, type ListSelectionMode} from './components/List/List'
48
48
  export {RadioGroup} from './components/RadioGroup/RadioGroup'
49
49
  export {Toggle, type ToggleSize} from './components/Toggle/Toggle'
50
+ export {Tag, type TagVariant} from './components/Tag/Tag'
51
+ export {SideNav} from './components/SideNav/SideNav'
52
+ export {Tabs} from './components/Tabs/Tabs'
53
+ export {Tree} from './components/Tree/Tree'
54
+ // 5.14: pickers open a bottom sheet (a Drawer at the medium and large detents)
55
+ export {Select} from './components/Select/Select'
56
+ export {Combobox} from './components/Combobox/Combobox'
57
+ export {Listbox} from './components/Listbox/Listbox'
58
+ // The platform's own scroll indicator: Scrollbar and Thumb draw nothing.
59
+ export {ScrollArea} from './components/ScrollArea/ScrollArea'
60
+ export type {ListboxAnchorProps, ListboxMaxHeight} from './components/Listbox/Listbox'
61
+ // Always stacked on native: a phone is below every collapseBelow.
62
+ export {SplitPane} from './components/SplitPane/SplitPane'
63
+ // Always the phone shape on native: the bar on top, the rail in a left Drawer.
64
+ export {
65
+ AppShell,
66
+ type AppShellCollapse,
67
+ type AppShellRailState,
68
+ } from './components/AppShell/AppShell'
50
69
 
51
70
  // Overlays (5.12: rendered in an OverlayModal on native)
52
71
  export {ConfirmDialog} from './components/ConfirmDialog/ConfirmDialog'
53
72
  export {Dialog, type DialogSize} from './components/Dialog/Dialog'
73
+ // 5.13: the panel follows the finger on the UI thread (Gesture Handler + Reanimated)
74
+ export {
75
+ Drawer,
76
+ type DrawerAnchor,
77
+ type DrawerSize,
78
+ type SnapPoint,
79
+ } from './components/Drawer/Drawer'
80
+ export {Menu, type MenuTriggerVariant} from './components/Menu/Menu'
81
+ export {Popover, type PopoverHandle} from './components/Popover/Popover'
82
+ // Touch has no hover: a Tooltip's text is its trigger's accessibility hint.
83
+ export {Tooltip} from './components/Tooltip/Tooltip'
84
+ // Drawn through the portal host, above every open overlay and the keyboard.
85
+ export {
86
+ ToastProvider,
87
+ useToast,
88
+ type ToastVariant,
89
+ type ToastOptions,
90
+ type ToastAction,
91
+ type ToastContextValue,
92
+ type ToastProviderProps,
93
+ } from './components/Toast'
54
94
 
55
95
  // Layout primitives
56
96
  export {PageShell, type PageShellMaxWidth, type PageShellPadding} from './components/PageShell'
@@ -64,9 +104,17 @@ export type {GridTrack} from './shared/length'
64
104
  // no display:contents / portal mount; applies the theme to a flex container).
65
105
  export {
66
106
  ThemeProvider,
107
+ type ColorOverrides,
67
108
  usePortalMount,
68
109
  useResolvedColors,
69
110
  type ThemeName,
70
111
  } from './components/ThemeProvider/ThemeProvider'
112
+ // 'system' follows RN Appearance; persistence is the app's (preference + onPreferenceChange).
113
+ export {
114
+ ColorModeProvider,
115
+ ColorModeToggle,
116
+ useColorMode,
117
+ type ColorModePreference,
118
+ } from './components/ColorMode'
71
119
  // Where toasts draw on native: mount one inside a natively presented route.
72
120
  export {PortalHost} from './shared/portal/PortalHost'
package/src/index.ts CHANGED
@@ -49,7 +49,12 @@ export {
49
49
  } from './components/DragDrop/DragDrop'
50
50
  export {Dialog, type DialogSize} from './components/Dialog/Dialog'
51
51
  export {DetailPanel, type DetailPanelSize} from './components/DetailPanel/DetailPanel'
52
- export {Drawer, type DrawerAnchor, type DrawerSize} from './components/Drawer/Drawer'
52
+ export {
53
+ Drawer,
54
+ type DrawerAnchor,
55
+ type DrawerSize,
56
+ type SnapPoint,
57
+ } from './components/Drawer/Drawer'
53
58
  export {EmptyState} from './components/EmptyState/EmptyState'
54
59
  export {Heading, type HeadingVariant} from './components/Heading/Heading'
55
60
  export {List, type ListSelectionMode} from './components/List/List'
@@ -115,9 +120,12 @@ export {
115
120
  type TimelineRowProps,
116
121
  } from './components/Timeline/Timeline'
117
122
  export {Tree} from './components/Tree/Tree'
123
+ export {SplitPane} from './components/SplitPane/SplitPane'
124
+ export {VirtualList, type VirtualListProps} from './components/VirtualList/VirtualList'
118
125
  export {Textarea, type TextareaVariant} from './components/Textarea/Textarea'
119
126
  export {
120
127
  ThemeProvider,
128
+ type ColorOverrides,
121
129
  usePortalMount,
122
130
  type ThemeName,
123
131
  } from './components/ThemeProvider/ThemeProvider'
@@ -0,0 +1,70 @@
1
+ import {Children, type ComponentProps, type ReactNode, type Ref} from 'react'
2
+ import {Pressable} from 'react-native'
3
+ import {html} from 'react-strict-dom'
4
+ import {useTooltipHint} from '../components/Tooltip/TooltipHint'
5
+
6
+ export type ButtonHostProps = ComponentProps<typeof html.button>
7
+
8
+ /**
9
+ * The host element of Button and Toggle on native. Inside a Tooltip it is an
10
+ * RN Pressable, which carries the Tooltip's text as its own accessibility hint
11
+ * (plan N0, Decision 5: RSD drops `accessibilityHint` on html.*); the visual
12
+ * styles move to a div inside it. Elsewhere it is RSD's button, as before.
13
+ *
14
+ * holds-until: react-strict-dom maps aria-description to accessibilityHint
15
+ * (https://github.com/react/react-strict-dom/issues/524); then html.button
16
+ * carries the hint itself and this swap goes.
17
+ */
18
+ export function ButtonHost(props: ButtonHostProps) {
19
+ const hint = useTooltipHint()
20
+ const content = textInSpans(props.children)
21
+ if (!hint) {
22
+ return (
23
+ <html.button {...props} style={props.style}>
24
+ {content}
25
+ </html.button>
26
+ )
27
+ }
28
+ const {
29
+ ref,
30
+ style,
31
+ disabled,
32
+ onClick,
33
+ 'aria-label': label,
34
+ 'aria-pressed': pressed,
35
+ 'aria-expanded': expanded,
36
+ } = props
37
+ return (
38
+ <Pressable
39
+ ref={ref as Ref<never>}
40
+ onPress={disabled ? undefined : () => onClick?.(undefined as never)}
41
+ disabled={disabled}
42
+ accessibilityRole="button"
43
+ accessibilityLabel={label ?? undefined}
44
+ accessibilityHint={hint}
45
+ accessibilityState={{
46
+ disabled: !!disabled,
47
+ ...(pressed !== undefined ? {checked: !!pressed} : {}),
48
+ ...(expanded !== undefined ? {expanded: !!expanded} : {}),
49
+ }}
50
+ >
51
+ <html.div style={style}>{content}</html.div>
52
+ </Pressable>
53
+ )
54
+ }
55
+
56
+ /**
57
+ * A label beside an icon (`<Icon/> Menu`): RSD wraps a button's text only
58
+ * when it is the sole child, and React Native refuses bare text in a view.
59
+ */
60
+ function textInSpans(children: ReactNode): ReactNode {
61
+ const items = Children.toArray(children)
62
+ if (items.length < 2) return children
63
+ return items.map((child, i) =>
64
+ typeof child === 'string' || typeof child === 'number' ? (
65
+ <html.span key={i}>{child}</html.span>
66
+ ) : (
67
+ child
68
+ ),
69
+ )
70
+ }
@@ -0,0 +1,12 @@
1
+ import type {ComponentProps} from 'react'
2
+ import {html} from 'react-strict-dom'
3
+
4
+ export type ButtonHostProps = ComponentProps<typeof html.button>
5
+
6
+ /**
7
+ * The host element of Button and Toggle. On the web it is the <button>
8
+ * itself, with no component in between (a wrapper changed what a Form's
9
+ * submit focuses); the native variant (ButtonHost.native.tsx) can swap in an
10
+ * RN Pressable to carry a Tooltip's accessibility hint.
11
+ */
12
+ export const ButtonHost: typeof html.button = html.button
@@ -0,0 +1,18 @@
1
+ interface StrictInputRef {
2
+ getNativeRef?: () => {focus?: () => void} | null
3
+ focus?: () => void
4
+ }
5
+
6
+ /**
7
+ * Focus an html.input on native. react-strict-dom 0.0.55 hands out a copy of
8
+ * the TextInput instance, whose `focus()` does nothing (#506); the copy keeps
9
+ * TextInput's own `getNativeRef()`, which returns the real host.
10
+ *
11
+ * holds-until: react-strict-dom releases #515 (focus() on the ref itself).
12
+ */
13
+ export function focusInput(input: unknown): void {
14
+ const ref = input as StrictInputRef | null
15
+ const host = ref?.getNativeRef?.()
16
+ if (host?.focus) host.focus()
17
+ else ref?.focus?.()
18
+ }
@@ -0,0 +1,117 @@
1
+ import {type ReactNode, type RefObject, useEffect, useState} from 'react'
2
+ import {
3
+ type LayoutChangeEvent,
4
+ Pressable,
5
+ StyleSheet,
6
+ useWindowDimensions,
7
+ View,
8
+ } from 'react-native'
9
+ import {SPACING_PX} from '@duro-app/tokens/keys'
10
+ import {
11
+ computePopoverPosition,
12
+ type PopoverAlign,
13
+ type PopoverRect,
14
+ type PopoverSide,
15
+ type PopoverSize,
16
+ } from '../../components/Popover/position'
17
+ import {OverlayModal} from './OverlayModal'
18
+
19
+ interface Measurable {
20
+ measureInWindow?: (cb: (x: number, y: number, width: number, height: number) => void) => void
21
+ }
22
+
23
+ interface AnchoredOverlayProps {
24
+ visible: boolean
25
+ /** The trigger's host: it is measured in window coordinates when the overlay opens */
26
+ anchorRef: RefObject<unknown>
27
+ side: PopoverSide
28
+ align: PopoverAlign
29
+ /** A backdrop press or Android's back button */
30
+ onRequestClose: () => void
31
+ /** The Modal has been presented: move accessibility focus in */
32
+ onShow?: () => void
33
+ /** iOS: the Modal has finished dismissing */
34
+ onDismiss?: () => void
35
+ children: ReactNode
36
+ }
37
+
38
+ /**
39
+ * A popup placed against its trigger on native (plan N0, Decision 3): the
40
+ * trigger is measured with `measureInWindow`, the popup with `onLayout`, and
41
+ * `computePopoverPosition` places it exactly as on the web. The OverlayModal
42
+ * is transparent and translucent, so its coordinates are window coordinates.
43
+ * Until both are measured the popup is laid out but not shown.
44
+ */
45
+ export function AnchoredOverlay({
46
+ visible,
47
+ anchorRef,
48
+ side,
49
+ align,
50
+ onRequestClose,
51
+ onShow,
52
+ onDismiss,
53
+ children,
54
+ }: AnchoredOverlayProps) {
55
+ const window = useWindowDimensions()
56
+ const [anchor, setAnchor] = useState<PopoverRect | null>(null)
57
+ const [size, setSize] = useState<PopoverSize | null>(null)
58
+
59
+ useEffect(() => {
60
+ if (!visible) {
61
+ setAnchor(null)
62
+ setSize(null)
63
+ return
64
+ }
65
+ const host = anchorRef.current as Measurable | null
66
+ host?.measureInWindow?.((left, top, width, height) => setAnchor({top, left, width, height}))
67
+ }, [visible, anchorRef, window.width, window.height])
68
+
69
+ const onLayout = (e: LayoutChangeEvent) => {
70
+ const {width, height} = e.nativeEvent.layout
71
+ setSize((prev) => (prev?.width === width && prev.height === height ? prev : {width, height}))
72
+ }
73
+
74
+ const position =
75
+ anchor && size
76
+ ? computePopoverPosition({
77
+ anchor,
78
+ popup: size,
79
+ viewport: {width: window.width, height: window.height},
80
+ side,
81
+ align,
82
+ offset: SPACING_PX.xs,
83
+ })
84
+ : null
85
+
86
+ return (
87
+ <OverlayModal
88
+ visible={visible}
89
+ onRequestClose={onRequestClose}
90
+ onShow={onShow}
91
+ onDismiss={onDismiss}
92
+ >
93
+ <Pressable
94
+ style={StyleSheet.absoluteFill}
95
+ onPress={onRequestClose}
96
+ accessible={false}
97
+ importantForAccessibility="no"
98
+ />
99
+ <View
100
+ onLayout={onLayout}
101
+ style={[
102
+ layout.popup,
103
+ {maxWidth: window.width - 2 * SPACING_PX.sm},
104
+ position ? {top: position.top, left: position.left} : layout.unplaced,
105
+ ]}
106
+ >
107
+ {children}
108
+ </View>
109
+ </OverlayModal>
110
+ )
111
+ }
112
+
113
+ // Layout-only: where the popup sits, and hidden until it has been placed.
114
+ const layout = StyleSheet.create({
115
+ popup: {position: 'absolute'},
116
+ unplaced: {top: 0, left: 0, opacity: 0},
117
+ })
@@ -0,0 +1,33 @@
1
+ import {
2
+ Children,
3
+ cloneElement,
4
+ isValidElement,
5
+ type ReactElement,
6
+ type ReactNode,
7
+ type Ref,
8
+ } from 'react'
9
+ import {mergeRefs} from './mergeRefs'
10
+
11
+ interface PressableChildProps {
12
+ onClick?: () => void
13
+ ref?: Ref<unknown>
14
+ }
15
+
16
+ /**
17
+ * Native overlay triggers and closes: native presses do not bubble to a
18
+ * wrapper as web clicks do, so the one child (a Button) gets the handler
19
+ * itself, after its own. `ref` also receives the child's host, where focus
20
+ * returns when the overlay closes.
21
+ */
22
+ export function withPress(children: ReactNode, onPress: () => void, ref?: Ref<unknown>) {
23
+ const child = Children.only(children)
24
+ if (!isValidElement<PressableChildProps>(child)) return null
25
+ const own = child.props.onClick
26
+ return cloneElement(child as ReactElement<PressableChildProps>, {
27
+ ...(ref ? {ref: mergeRefs(child.props.ref, ref)} : {}),
28
+ onClick: () => {
29
+ own?.()
30
+ onPress()
31
+ },
32
+ })
33
+ }
@@ -0,0 +1,13 @@
1
+ import {isValidElement, type ReactNode} from 'react'
2
+
3
+ /**
4
+ * The text a React node would render, read from its props: a native picker's
5
+ * option label, where there is no DOM `textContent` to read it from.
6
+ */
7
+ export function textOf(node: ReactNode): string {
8
+ if (node == null || typeof node === 'boolean') return ''
9
+ if (typeof node === 'string' || typeof node === 'number') return String(node)
10
+ if (Array.isArray(node)) return node.map(textOf).join('')
11
+ if (isValidElement<{children?: ReactNode}>(node)) return textOf(node.props.children)
12
+ return ''
13
+ }
@@ -0,0 +1,18 @@
1
+ import {useEffect, useState} from 'react'
2
+ import {Keyboard, Platform} from 'react-native'
3
+
4
+ /** The on-screen keyboard's height while it is shown, else 0. */
5
+ export function useKeyboardHeight(): number {
6
+ const [height, setHeight] = useState(0)
7
+ useEffect(() => {
8
+ // iOS announces the keyboard before it moves, Android only after.
9
+ const show = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow'
10
+ const hide = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide'
11
+ const subs = [
12
+ Keyboard.addListener(show, (e) => setHeight(e.endCoordinates.height)),
13
+ Keyboard.addListener(hide, () => setHeight(0)),
14
+ ]
15
+ return () => subs.forEach((s) => s.remove())
16
+ }, [])
17
+ return height
18
+ }
@@ -0,0 +1,19 @@
1
+ import {useEffect, useState} from 'react'
2
+ import {AccessibilityInfo} from 'react-native'
3
+
4
+ /** Whether VoiceOver or TalkBack is on, following changes while mounted. */
5
+ export function useScreenReaderEnabled(): boolean {
6
+ const [enabled, setEnabled] = useState(false)
7
+ useEffect(() => {
8
+ let live = true
9
+ void AccessibilityInfo.isScreenReaderEnabled().then((on) => {
10
+ if (live) setEnabled(on)
11
+ })
12
+ const sub = AccessibilityInfo.addEventListener('screenReaderChanged', setEnabled)
13
+ return () => {
14
+ live = false
15
+ sub.remove()
16
+ }
17
+ }, [])
18
+ return enabled
19
+ }