@sovereignfs/ui 0.41.0 → 0.54.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 (256) hide show
  1. package/dist/Accordion.module.css +3 -0
  2. package/dist/Alert.module.css +62 -0
  3. package/dist/AspectRatio.module.css +15 -0
  4. package/dist/Badge.module.css +75 -9
  5. package/dist/Breadcrumb.module.css +49 -0
  6. package/dist/Button.module.css +12 -3
  7. package/dist/ButtonGroup.module.css +29 -0
  8. package/dist/Card.module.css +6 -0
  9. package/dist/Checkbox.module.css +3 -1
  10. package/dist/Collapsible.module.css +70 -0
  11. package/dist/Combobox.module.css +122 -0
  12. package/dist/Command.module.css +80 -0
  13. package/dist/ConfirmDialog.module.css +5 -1
  14. package/dist/DataTable.module.css +28 -0
  15. package/dist/DatePicker.module.css +6 -2
  16. package/dist/Dialog.module.css +3 -0
  17. package/dist/HoverCard.module.css +3 -0
  18. package/dist/Input.module.css +6 -1
  19. package/dist/Item.module.css +70 -0
  20. package/dist/Kbd.module.css +14 -0
  21. package/dist/Label.module.css +11 -0
  22. package/dist/LegalLinks.module.css +24 -0
  23. package/dist/Markdown.module.css +49 -0
  24. package/dist/Marker.module.css +33 -0
  25. package/dist/Menu.module.css +8 -1
  26. package/dist/Message.module.css +99 -0
  27. package/dist/MessageScroller.module.css +54 -0
  28. package/dist/MobileAppsDrawer.module.css +81 -0
  29. package/dist/MobileFooter.module.css +73 -0
  30. package/dist/MobileHeader.module.css +63 -0
  31. package/dist/NavigationMenu.module.css +53 -0
  32. package/dist/PageContainer.module.css +20 -0
  33. package/dist/Pagination.module.css +98 -0
  34. package/dist/Progress.module.css +20 -0
  35. package/dist/RadioGroup.module.css +88 -0
  36. package/dist/Resizable.module.css +70 -0
  37. package/dist/ScrollArea.module.css +20 -0
  38. package/dist/Select.module.css +7 -3
  39. package/dist/Slider.module.css +95 -0
  40. package/dist/SwipableMobileCarousel.module.css +55 -0
  41. package/dist/SwipableMobileCarouselDots.module.css +49 -0
  42. package/dist/SwipableMobileCarouselSlideParts.module.css +29 -0
  43. package/dist/Table.module.css +45 -0
  44. package/dist/Tabs.module.css +6 -1
  45. package/dist/Toggle.module.css +6 -1
  46. package/dist/Typography.module.css +47 -0
  47. package/dist/index.d.ts +1268 -8
  48. package/dist/index.js +3046 -975
  49. package/dist/tokens/primitives.css +47 -8
  50. package/package.json +13 -9
  51. package/src/components/Accordion/Accordion.module.css +3 -0
  52. package/src/components/Accordion/Accordion.stories.tsx +110 -0
  53. package/src/components/Accordion/Accordion.tsx +53 -0
  54. package/src/components/Accordion/__tests__/Accordion.test.tsx +61 -0
  55. package/src/components/Alert/Alert.module.css +62 -0
  56. package/src/components/Alert/Alert.stories.tsx +96 -0
  57. package/src/components/Alert/Alert.tsx +58 -0
  58. package/src/components/Alert/__tests__/Alert.test.tsx +75 -0
  59. package/src/components/AspectRatio/AspectRatio.module.css +15 -0
  60. package/src/components/AspectRatio/AspectRatio.stories.tsx +78 -0
  61. package/src/components/AspectRatio/AspectRatio.tsx +21 -0
  62. package/src/components/AspectRatio/__tests__/AspectRatio.test.tsx +27 -0
  63. package/src/components/Badge/Badge.module.css +75 -9
  64. package/src/components/Badge/Badge.stories.tsx +109 -1
  65. package/src/components/Badge/Badge.tsx +31 -9
  66. package/src/components/Badge/__tests__/Badge.test.tsx +26 -2
  67. package/src/components/Breadcrumb/Breadcrumb.module.css +49 -0
  68. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +47 -0
  69. package/src/components/Breadcrumb/Breadcrumb.tsx +57 -0
  70. package/src/components/Breadcrumb/__tests__/Breadcrumb.test.tsx +52 -0
  71. package/src/components/Button/Button.module.css +12 -3
  72. package/src/components/Button/Button.stories.tsx +3 -2
  73. package/src/components/Button/Button.tsx +1 -1
  74. package/src/components/Button/__tests__/Button.test.tsx +10 -0
  75. package/src/components/ButtonGroup/ButtonGroup.module.css +29 -0
  76. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +57 -0
  77. package/src/components/ButtonGroup/ButtonGroup.tsx +27 -0
  78. package/src/components/ButtonGroup/__tests__/ButtonGroup.test.tsx +29 -0
  79. package/src/components/Card/Card.module.css +6 -0
  80. package/src/components/Checkbox/Checkbox.module.css +3 -1
  81. package/src/components/Collapsible/Collapsible.module.css +70 -0
  82. package/src/components/Collapsible/Collapsible.stories.tsx +62 -0
  83. package/src/components/Collapsible/Collapsible.tsx +66 -0
  84. package/src/components/Collapsible/__tests__/Collapsible.test.tsx +71 -0
  85. package/src/components/Combobox/Combobox.module.css +122 -0
  86. package/src/components/Combobox/Combobox.stories.tsx +79 -0
  87. package/src/components/Combobox/Combobox.tsx +186 -0
  88. package/src/components/Combobox/__tests__/Combobox.test.tsx +158 -0
  89. package/src/components/Command/Command.module.css +80 -0
  90. package/src/components/Command/Command.stories.tsx +104 -0
  91. package/src/components/Command/Command.tsx +168 -0
  92. package/src/components/Command/__tests__/Command.test.tsx +162 -0
  93. package/src/components/ConfirmDialog/ConfirmDialog.module.css +5 -1
  94. package/src/components/ContextMenu/ContextMenu.stories.tsx +81 -0
  95. package/src/components/ContextMenu/ContextMenu.tsx +100 -0
  96. package/src/components/ContextMenu/__tests__/ContextMenu.test.tsx +87 -0
  97. package/src/components/DataTable/DataTable.module.css +28 -0
  98. package/src/components/DataTable/DataTable.stories.tsx +74 -0
  99. package/src/components/DataTable/DataTable.tsx +154 -0
  100. package/src/components/DataTable/__tests__/DataTable.test.tsx +123 -0
  101. package/src/components/DatePicker/DatePicker.module.css +6 -2
  102. package/src/components/DeviceOnlyGate/DeviceOnlyGate.tsx +58 -0
  103. package/src/components/DeviceOnlyGate/__tests__/DeviceOnlyGate.test.tsx +45 -0
  104. package/src/components/DeviceStorageKeyGate/DeviceStorageKeyGate.tsx +100 -0
  105. package/src/components/DeviceStorageKeyGate/__tests__/DeviceStorageKeyGate.test.tsx +119 -0
  106. package/src/components/Dialog/Dialog.module.css +3 -0
  107. package/src/components/Dialog/Dialog.tsx +8 -59
  108. package/src/components/Drawer/Drawer.stories.tsx +44 -0
  109. package/src/components/Drawer/Drawer.tsx +18 -56
  110. package/src/components/Drawer/__tests__/Drawer.test.tsx +22 -0
  111. package/src/components/HoverCard/HoverCard.module.css +3 -0
  112. package/src/components/HoverCard/HoverCard.stories.tsx +66 -0
  113. package/src/components/HoverCard/HoverCard.tsx +111 -0
  114. package/src/components/HoverCard/__tests__/HoverCard.test.tsx +99 -0
  115. package/src/components/Icon/icons/circle-check.tsx +21 -0
  116. package/src/components/Icon/icons/circle-x.tsx +22 -0
  117. package/src/components/Icon/icons/index.ts +16 -0
  118. package/src/components/Icon/icons/menu.tsx +22 -0
  119. package/src/components/Icon/icons/smartphone.tsx +21 -0
  120. package/src/components/Input/Input.module.css +6 -1
  121. package/src/components/Item/Item.module.css +70 -0
  122. package/src/components/Item/Item.stories.tsx +62 -0
  123. package/src/components/Item/Item.tsx +54 -0
  124. package/src/components/Item/__tests__/Item.test.tsx +39 -0
  125. package/src/components/Kbd/Kbd.module.css +14 -0
  126. package/src/components/Kbd/Kbd.stories.tsx +32 -0
  127. package/src/components/Kbd/Kbd.tsx +12 -0
  128. package/src/components/Kbd/__tests__/Kbd.test.tsx +14 -0
  129. package/src/components/Label/Label.module.css +11 -0
  130. package/src/components/Label/Label.stories.tsx +40 -0
  131. package/src/components/Label/Label.tsx +24 -0
  132. package/src/components/Label/__tests__/Label.test.tsx +32 -0
  133. package/src/components/LegalLinks/LegalLinks.module.css +24 -0
  134. package/src/components/LegalLinks/LegalLinks.stories.tsx +22 -0
  135. package/src/components/LegalLinks/LegalLinks.tsx +40 -0
  136. package/src/components/Markdown/Markdown.module.css +49 -0
  137. package/src/components/Markdown/Markdown.stories.tsx +30 -0
  138. package/src/components/Markdown/Markdown.tsx +168 -0
  139. package/src/components/Marker/Marker.module.css +33 -0
  140. package/src/components/Marker/Marker.stories.tsx +39 -0
  141. package/src/components/Marker/Marker.tsx +34 -0
  142. package/src/components/Marker/__tests__/Marker.test.tsx +23 -0
  143. package/src/components/Menu/Menu.module.css +8 -1
  144. package/src/components/Menu/Menu.tsx +30 -8
  145. package/src/components/Menubar/Menubar.stories.tsx +52 -0
  146. package/src/components/Menubar/Menubar.tsx +42 -0
  147. package/src/components/Menubar/__tests__/Menubar.test.tsx +45 -0
  148. package/src/components/Message/Message.module.css +99 -0
  149. package/src/components/Message/Message.stories.tsx +79 -0
  150. package/src/components/Message/Message.tsx +41 -0
  151. package/src/components/Message/__tests__/Message.test.tsx +46 -0
  152. package/src/components/MessageScroller/MessageScroller.module.css +54 -0
  153. package/src/components/MessageScroller/MessageScroller.stories.tsx +84 -0
  154. package/src/components/MessageScroller/MessageScroller.tsx +72 -0
  155. package/src/components/MessageScroller/__tests__/MessageScroller.test.tsx +105 -0
  156. package/src/components/MobileAppsDrawer/MobileAppsDrawer.module.css +81 -0
  157. package/src/components/MobileAppsDrawer/MobileAppsDrawer.tsx +78 -0
  158. package/src/components/MobileAppsDrawer/__tests__/MobileAppsDrawer.test.tsx +80 -0
  159. package/src/components/MobileFooter/MobileFooter.module.css +73 -0
  160. package/src/components/MobileFooter/MobileFooter.stories.tsx +47 -0
  161. package/src/components/MobileFooter/MobileFooter.tsx +109 -0
  162. package/src/components/MobileFooter/__tests__/MobileFooter.test.tsx +71 -0
  163. package/src/components/MobileHeader/MobileHeader.module.css +63 -0
  164. package/src/components/MobileHeader/MobileHeader.stories.tsx +57 -0
  165. package/src/components/MobileHeader/MobileHeader.tsx +77 -0
  166. package/src/components/MobileHeader/__tests__/MobileHeader.test.tsx +58 -0
  167. package/src/components/NavTabs/NavTabs.tsx +39 -11
  168. package/src/components/NavigationMenu/NavigationMenu.module.css +53 -0
  169. package/src/components/NavigationMenu/NavigationMenu.stories.tsx +58 -0
  170. package/src/components/NavigationMenu/NavigationMenu.tsx +125 -0
  171. package/src/components/NavigationMenu/__tests__/NavigationMenu.test.tsx +93 -0
  172. package/src/components/OfflineGate/OfflineGate.tsx +44 -0
  173. package/src/components/OfflineGate/__tests__/OfflineGate.test.tsx +66 -0
  174. package/src/components/PageContainer/PageContainer.module.css +20 -0
  175. package/src/components/PageContainer/PageContainer.tsx +31 -0
  176. package/src/components/PageContainer/__tests__/PageContainer.test.tsx +37 -0
  177. package/src/components/PageHeader/PageHeader.tsx +16 -2
  178. package/src/components/Pagination/Pagination.module.css +98 -0
  179. package/src/components/Pagination/Pagination.stories.tsx +49 -0
  180. package/src/components/Pagination/Pagination.tsx +87 -0
  181. package/src/components/Pagination/__tests__/Pagination.test.tsx +56 -0
  182. package/src/components/Progress/Progress.module.css +20 -0
  183. package/src/components/Progress/Progress.stories.tsx +40 -0
  184. package/src/components/Progress/Progress.tsx +35 -0
  185. package/src/components/Progress/__tests__/Progress.test.tsx +31 -0
  186. package/src/components/RadioGroup/RadioGroup.module.css +88 -0
  187. package/src/components/RadioGroup/RadioGroup.stories.tsx +69 -0
  188. package/src/components/RadioGroup/RadioGroup.tsx +99 -0
  189. package/src/components/RadioGroup/__tests__/RadioGroup.test.tsx +59 -0
  190. package/src/components/Resizable/Resizable.module.css +70 -0
  191. package/src/components/Resizable/Resizable.stories.tsx +82 -0
  192. package/src/components/Resizable/Resizable.tsx +313 -0
  193. package/src/components/Resizable/__tests__/Resizable.test.tsx +128 -0
  194. package/src/components/ResponsiveSurface/ResponsiveSurface.tsx +24 -0
  195. package/src/components/ResponsiveSurface/__tests__/ResponsiveSurface.test.tsx +73 -0
  196. package/src/components/ScrollArea/ScrollArea.module.css +20 -0
  197. package/src/components/ScrollArea/ScrollArea.stories.tsx +57 -0
  198. package/src/components/ScrollArea/ScrollArea.tsx +27 -0
  199. package/src/components/ScrollArea/__tests__/ScrollArea.test.tsx +39 -0
  200. package/src/components/Select/Select.module.css +7 -3
  201. package/src/components/Sheet/Sheet.tsx +9 -51
  202. package/src/components/Slider/Slider.module.css +95 -0
  203. package/src/components/Slider/Slider.stories.tsx +64 -0
  204. package/src/components/Slider/Slider.tsx +77 -0
  205. package/src/components/Slider/__tests__/Slider.test.tsx +45 -0
  206. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.module.css +55 -0
  207. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.tsx +227 -0
  208. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlide.tsx +35 -0
  209. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody.tsx +42 -0
  210. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter.tsx +18 -0
  211. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader.tsx +21 -0
  212. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideParts.module.css +29 -0
  213. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarousel.test.tsx +133 -0
  214. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarouselDevGuard.test.tsx +61 -0
  215. package/src/components/SwipableMobileCarousel/context.ts +13 -0
  216. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.module.css +49 -0
  217. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.tsx +62 -0
  218. package/src/components/SwipableMobileCarouselDots/__tests__/SwipableMobileCarouselDots.test.tsx +63 -0
  219. package/src/components/Table/Table.module.css +45 -0
  220. package/src/components/Table/Table.stories.tsx +125 -0
  221. package/src/components/Table/Table.tsx +51 -0
  222. package/src/components/Table/__tests__/Table.test.tsx +50 -0
  223. package/src/components/Tabs/Tabs.module.css +6 -1
  224. package/src/components/Toggle/Toggle.module.css +6 -1
  225. package/src/components/Typography/Typography.module.css +47 -0
  226. package/src/components/Typography/Typography.stories.tsx +62 -0
  227. package/src/components/Typography/Typography.tsx +30 -0
  228. package/src/components/Typography/__tests__/Typography.test.tsx +34 -0
  229. package/src/hooks/__tests__/useCarouselRouteSync.test.tsx +126 -0
  230. package/src/hooks/__tests__/useIsOffline.test.tsx +53 -0
  231. package/src/hooks/__tests__/useOfflineTileState.test.tsx +69 -0
  232. package/src/hooks/__tests__/useResponsiveLayout.test.tsx +87 -0
  233. package/src/hooks/__tests__/useSnapCarousel.test.tsx +93 -0
  234. package/src/hooks/__tests__/useSwipeReveal.test.tsx +110 -0
  235. package/src/hooks/index.ts +18 -0
  236. package/src/hooks/useCarouselRouteSync.ts +92 -0
  237. package/src/hooks/useIsOffline.ts +41 -0
  238. package/src/hooks/useOfflineTileState.ts +45 -0
  239. package/src/hooks/useResponsiveLayout.ts +36 -0
  240. package/src/hooks/useSnapCarousel.ts +79 -0
  241. package/src/hooks/useSwipeReveal.ts +107 -0
  242. package/src/index.ts +141 -3
  243. package/src/overlay-shell.ts +94 -0
  244. package/src/stories/DesignSystemOverview.stories.tsx +936 -3
  245. package/src/stories/DeviceOnlyGate.stories.tsx +35 -0
  246. package/src/stories/DeviceStorageKeyGate.stories.tsx +57 -0
  247. package/src/stories/InteractionHooks.stories.tsx +483 -0
  248. package/src/stories/MobilePatterns.stories.tsx +255 -4
  249. package/src/stories/NavTabs.stories.tsx +18 -0
  250. package/src/stories/OfflineGate.stories.tsx +42 -0
  251. package/src/stories/PageContainer.stories.tsx +37 -0
  252. package/src/stories/PageHeader.stories.tsx +11 -0
  253. package/src/stories/ResponsiveSurface.stories.tsx +47 -0
  254. package/src/stories/SwipableMobileCarousel.stories.tsx +304 -0
  255. package/src/stories/TokenGallery.stories.tsx +177 -16
  256. package/src/tokens/primitives.css +47 -8
@@ -0,0 +1,107 @@
1
+ 'use client';
2
+
3
+ import { useRef } from 'react';
4
+ import type { PointerEvent as ReactPointerEvent, RefObject } from 'react';
5
+
6
+ export interface UseSwipeRevealOptions {
7
+ /** Max reveal distance in px — the row translates by `-revealWidth` when open. */
8
+ revealWidth: number;
9
+ /** Whether the reveal is currently open. Controlled by the caller so a
10
+ * list of rows can coordinate "only one open at a time" — this hook has
11
+ * no open state of its own. */
12
+ open: boolean;
13
+ /** Called when a drag releases past the halfway point — the caller should
14
+ * set `open` to true. */
15
+ onOpen: () => void;
16
+ /** Called when a drag releases before the halfway point — the caller
17
+ * should set `open` to false. */
18
+ onClose: () => void;
19
+ /** Skip entirely (hooks can't be called conditionally). */
20
+ disabled?: boolean;
21
+ }
22
+
23
+ export interface UseSwipeRevealHandlers {
24
+ onPointerDown: (e: ReactPointerEvent) => void;
25
+ onPointerMove: (e: ReactPointerEvent) => void;
26
+ onPointerUp: (e: ReactPointerEvent) => void;
27
+ onPointerCancel: (e: ReactPointerEvent) => void;
28
+ }
29
+
30
+ export interface UseSwipeRevealResult {
31
+ /** Attach to the swipeable row element — the hook writes a live transform
32
+ * to it directly during the drag (not via React state) so the row tracks
33
+ * the finger at 60fps with no re-render per pointermove. */
34
+ rowRef: RefObject<HTMLDivElement | null>;
35
+ /** Spread onto the row's pointer event handlers. */
36
+ handlers: UseSwipeRevealHandlers;
37
+ }
38
+
39
+ /**
40
+ * useSwipeReveal — horizontal swipe-to-reveal (e.g. Done/Delete actions
41
+ * behind a list row), extracted from `sovereign-tasks`'s `TaskItem`/
42
+ * `ListSidebar`, which independently hand-rolled the identical gesture twice
43
+ * with only `revealWidth` differing (RFC 0079, epic task 9.20).
44
+ *
45
+ * Axis-locks on the first 8px of movement (so a vertical scroll or the
46
+ * carousel's own horizontal swipe-between-slides gesture isn't hijacked by a
47
+ * diagonal drag) and only resolves to open/closed on release, past the
48
+ * halfway point of `revealWidth`.
49
+ */
50
+ export function useSwipeReveal({
51
+ revealWidth,
52
+ open,
53
+ onOpen,
54
+ onClose,
55
+ disabled = false,
56
+ }: UseSwipeRevealOptions): UseSwipeRevealResult {
57
+ const rowRef = useRef<HTMLDivElement>(null);
58
+ const dragState = useRef<{
59
+ startX: number;
60
+ startY: number;
61
+ locked: 'horizontal' | 'vertical' | null;
62
+ } | null>(null);
63
+
64
+ function onPointerDown(e: ReactPointerEvent) {
65
+ if (disabled) return;
66
+ e.currentTarget.setPointerCapture(e.pointerId);
67
+ dragState.current = { startX: e.clientX, startY: e.clientY, locked: null };
68
+ }
69
+
70
+ function onPointerMove(e: ReactPointerEvent) {
71
+ const state = dragState.current;
72
+ if (!state) return;
73
+ const dx = e.clientX - state.startX;
74
+ const dy = e.clientY - state.startY;
75
+ if (!state.locked) {
76
+ if (Math.abs(dx) < 8 && Math.abs(dy) < 8) return;
77
+ state.locked = Math.abs(dx) > Math.abs(dy) ? 'horizontal' : 'vertical';
78
+ }
79
+ if (state.locked !== 'horizontal') return;
80
+ e.preventDefault();
81
+ const base = open ? -revealWidth : 0;
82
+ const next = Math.min(0, Math.max(-revealWidth, base + dx));
83
+ if (rowRef.current) rowRef.current.style.transform = `translateX(${next}px)`;
84
+ }
85
+
86
+ function releaseDrag(e: ReactPointerEvent) {
87
+ const state = dragState.current;
88
+ dragState.current = null;
89
+ if (!state || state.locked !== 'horizontal') return;
90
+ const dx = e.clientX - state.startX;
91
+ const base = open ? -revealWidth : 0;
92
+ const finalX = Math.min(0, Math.max(-revealWidth, base + dx));
93
+ if (rowRef.current) rowRef.current.style.transform = '';
94
+ if (finalX < -revealWidth / 2) onOpen();
95
+ else onClose();
96
+ }
97
+
98
+ return {
99
+ rowRef,
100
+ handlers: {
101
+ onPointerDown,
102
+ onPointerMove,
103
+ onPointerUp: releaseDrag,
104
+ onPointerCancel: releaseDrag,
105
+ },
106
+ };
107
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,7 @@
1
+ export { LegalLinks } from './components/LegalLinks/LegalLinks';
2
+ export type { LegalLinksProps } from './components/LegalLinks/LegalLinks';
3
+ export { Markdown } from './components/Markdown/Markdown';
4
+ export type { MarkdownProps } from './components/Markdown/Markdown';
1
5
  export { Badge } from './components/Badge/Badge';
2
6
  export type { BadgeProps, BadgeVariant, BadgeStatus } from './components/Badge/Badge';
3
7
  export { Icon } from './components/Icon/Icon';
@@ -41,7 +45,7 @@ export { Sheet } from './components/Sheet/Sheet';
41
45
  export type { SheetProps } from './components/Sheet/Sheet';
42
46
  export { ConfirmDialog } from './components/ConfirmDialog/ConfirmDialog';
43
47
  export type { ConfirmDialogProps } from './components/ConfirmDialog/ConfirmDialog';
44
- export { Menu } from './components/Menu/Menu';
48
+ export { Menu, MenuEntries } from './components/Menu/Menu';
45
49
  export type {
46
50
  MenuProps,
47
51
  MenuItem,
@@ -57,18 +61,115 @@ export { FormField } from './components/FormField/FormField';
57
61
  export type { FormFieldProps, FormFieldRenderProps } from './components/FormField/FormField';
58
62
  export { PageHeader } from './components/PageHeader/PageHeader';
59
63
  export type { PageHeaderProps } from './components/PageHeader/PageHeader';
64
+ export { PageContainer } from './components/PageContainer/PageContainer';
65
+ export type { PageContainerProps } from './components/PageContainer/PageContainer';
66
+ export { MobileHeader } from './components/MobileHeader/MobileHeader';
67
+ export type { MobileHeaderProps } from './components/MobileHeader/MobileHeader';
68
+ export { MobileFooter } from './components/MobileFooter/MobileFooter';
69
+ export type { MobileFooterProps, FooterIcon } from './components/MobileFooter/MobileFooter';
70
+ export { MobileAppsDrawer } from './components/MobileAppsDrawer/MobileAppsDrawer';
71
+ export type {
72
+ MobileAppsDrawerProps,
73
+ MobileAppsDrawerItem,
74
+ } from './components/MobileAppsDrawer/MobileAppsDrawer';
60
75
  export { EmptyState } from './components/EmptyState/EmptyState';
61
76
  export type { EmptyStateProps } from './components/EmptyState/EmptyState';
77
+ export { OfflineGate } from './components/OfflineGate/OfflineGate';
78
+ export type { OfflineGateProps } from './components/OfflineGate/OfflineGate';
79
+ export { DeviceOnlyGate } from './components/DeviceOnlyGate/DeviceOnlyGate';
80
+ export type { DeviceOnlyGateProps } from './components/DeviceOnlyGate/DeviceOnlyGate';
81
+ export { DeviceStorageKeyGate } from './components/DeviceStorageKeyGate/DeviceStorageKeyGate';
82
+ export type {
83
+ DeviceStorageKeyGateProps,
84
+ DeviceStorageKeyGateStatus,
85
+ } from './components/DeviceStorageKeyGate/DeviceStorageKeyGate';
62
86
  export { Spinner } from './components/Spinner/Spinner';
63
87
  export type { SpinnerProps } from './components/Spinner/Spinner';
64
88
  export { Avatar } from './components/Avatar/Avatar';
65
89
  export type { AvatarProps } from './components/Avatar/Avatar';
66
90
  export { NavTabs } from './components/NavTabs/NavTabs';
67
- export type { NavTabsProps, NavTabItem } from './components/NavTabs/NavTabs';
91
+ export type { NavTabsProps, NavTabItem, NavTabLinkProps } from './components/NavTabs/NavTabs';
68
92
  export { Tooltip } from './components/Tooltip/Tooltip';
69
93
  export type { TooltipProps } from './components/Tooltip/Tooltip';
70
94
  export { Checkbox } from './components/Checkbox/Checkbox';
71
95
  export type { CheckboxProps } from './components/Checkbox/Checkbox';
96
+ export { RadioGroup } from './components/RadioGroup/RadioGroup';
97
+ export type { RadioGroupProps, RadioGroupItem } from './components/RadioGroup/RadioGroup';
98
+ export { Slider } from './components/Slider/Slider';
99
+ export type { SliderProps } from './components/Slider/Slider';
100
+ export { Progress } from './components/Progress/Progress';
101
+ export type { ProgressProps } from './components/Progress/Progress';
102
+ export {
103
+ Table,
104
+ TableHead,
105
+ TableBody,
106
+ TableRow,
107
+ TableHeaderCell,
108
+ TableCell,
109
+ } from './components/Table/Table';
110
+ export type { TableProps } from './components/Table/Table';
111
+ export { Alert } from './components/Alert/Alert';
112
+ export type { AlertProps, AlertVariant } from './components/Alert/Alert';
113
+ export { Breadcrumb } from './components/Breadcrumb/Breadcrumb';
114
+ export type { BreadcrumbProps, BreadcrumbItem } from './components/Breadcrumb/Breadcrumb';
115
+ export { Pagination } from './components/Pagination/Pagination';
116
+ export type { PaginationProps } from './components/Pagination/Pagination';
117
+ export { Kbd } from './components/Kbd/Kbd';
118
+ export type { KbdProps } from './components/Kbd/Kbd';
119
+ export { Collapsible } from './components/Collapsible/Collapsible';
120
+ export type { CollapsibleProps } from './components/Collapsible/Collapsible';
121
+ export { Accordion } from './components/Accordion/Accordion';
122
+ export type { AccordionProps, AccordionItem } from './components/Accordion/Accordion';
123
+ export { AspectRatio } from './components/AspectRatio/AspectRatio';
124
+ export type { AspectRatioProps } from './components/AspectRatio/AspectRatio';
125
+ export { ButtonGroup } from './components/ButtonGroup/ButtonGroup';
126
+ export type { ButtonGroupProps } from './components/ButtonGroup/ButtonGroup';
127
+ export { Item } from './components/Item/Item';
128
+ export type { ItemProps } from './components/Item/Item';
129
+ export { Label } from './components/Label/Label';
130
+ export type { LabelProps } from './components/Label/Label';
131
+ export { ScrollArea } from './components/ScrollArea/ScrollArea';
132
+ export type { ScrollAreaProps } from './components/ScrollArea/ScrollArea';
133
+ export { Typography } from './components/Typography/Typography';
134
+ export type { TypographyProps, TypographyVariant } from './components/Typography/Typography';
135
+ export { Marker } from './components/Marker/Marker';
136
+ export type { MarkerProps } from './components/Marker/Marker';
137
+ export { Message } from './components/Message/Message';
138
+ export type { MessageProps, MessageSender } from './components/Message/Message';
139
+ export { MessageScroller } from './components/MessageScroller/MessageScroller';
140
+ export type { MessageScrollerProps } from './components/MessageScroller/MessageScroller';
141
+ export { HoverCard } from './components/HoverCard/HoverCard';
142
+ export type { HoverCardProps } from './components/HoverCard/HoverCard';
143
+ export { ContextMenu } from './components/ContextMenu/ContextMenu';
144
+ export type { ContextMenuProps } from './components/ContextMenu/ContextMenu';
145
+ export { NavigationMenu } from './components/NavigationMenu/NavigationMenu';
146
+ export type {
147
+ NavigationMenuProps,
148
+ NavigationMenuItem,
149
+ } from './components/NavigationMenu/NavigationMenu';
150
+ export { Menubar } from './components/Menubar/Menubar';
151
+ export type { MenubarProps, MenubarMenu } from './components/Menubar/Menubar';
152
+ export { Command } from './components/Command/Command';
153
+ export type { CommandProps, CommandItem } from './components/Command/Command';
154
+ export {
155
+ ResizablePanelGroup,
156
+ ResizablePanel,
157
+ ResizableHandle,
158
+ } from './components/Resizable/Resizable';
159
+ export type {
160
+ ResizablePanelGroupProps,
161
+ ResizablePanelProps,
162
+ ResizableHandleProps,
163
+ ResizableDirection,
164
+ } from './components/Resizable/Resizable';
165
+ export { DataTable } from './components/DataTable/DataTable';
166
+ export type {
167
+ DataTableProps,
168
+ DataTableColumn,
169
+ SortDirection,
170
+ } from './components/DataTable/DataTable';
171
+ export { Combobox } from './components/Combobox/Combobox';
172
+ export type { ComboboxProps, ComboboxOption } from './components/Combobox/Combobox';
72
173
  export { DragHandleRow } from './components/DragHandleRow/DragHandleRow';
73
174
  export type { DragHandleRowProps } from './components/DragHandleRow/DragHandleRow';
74
175
  export { FileDropzone } from './components/FileDropzone/FileDropzone';
@@ -107,7 +208,44 @@ export {
107
208
  useDoubleTapHandler,
108
209
  useSingleOrDoubleTap,
109
210
  useIsMobile,
211
+ useIsOffline,
212
+ useOfflineTileState,
110
213
  useCommitOnEnterOrBlur,
214
+ useSwipeReveal,
215
+ useSnapCarousel,
216
+ useResponsiveLayout,
217
+ useCarouselRouteSync,
111
218
  } from './hooks';
219
+ export type { OfflineTileState } from './hooks';
112
220
  export { MOBILE_BREAKPOINT_PX } from './hooks';
113
- export type { UseLongPressOptions, LongPressHandlers, CommitOnEnterOrBlurHandlers } from './hooks';
221
+ export type {
222
+ UseLongPressOptions,
223
+ LongPressHandlers,
224
+ CommitOnEnterOrBlurHandlers,
225
+ UseSwipeRevealOptions,
226
+ UseSwipeRevealHandlers,
227
+ UseSwipeRevealResult,
228
+ UseSnapCarouselOptions,
229
+ UseSnapCarouselResult,
230
+ UseResponsiveLayoutOptions,
231
+ UseResponsiveLayoutResult,
232
+ UseCarouselRouteSyncOptions,
233
+ UseCarouselRouteSyncResult,
234
+ } from './hooks';
235
+ export { ResponsiveSurface } from './components/ResponsiveSurface/ResponsiveSurface';
236
+ export type { ResponsiveSurfaceProps } from './components/ResponsiveSurface/ResponsiveSurface';
237
+ export { SwipableMobileCarouselDots } from './components/SwipableMobileCarouselDots/SwipableMobileCarouselDots';
238
+ export type { SwipableMobileCarouselDotsProps } from './components/SwipableMobileCarouselDots/SwipableMobileCarouselDots';
239
+ export { SwipableMobileCarousel } from './components/SwipableMobileCarousel/SwipableMobileCarousel';
240
+ export type {
241
+ SwipableMobileCarouselProps,
242
+ SwipableMobileCarouselIndicatorProps,
243
+ } from './components/SwipableMobileCarousel/SwipableMobileCarousel';
244
+ export { SwipableMobileCarouselSlide } from './components/SwipableMobileCarousel/SwipableMobileCarouselSlide';
245
+ export type { SwipableMobileCarouselSlideProps } from './components/SwipableMobileCarousel/SwipableMobileCarouselSlide';
246
+ export { SwipableMobileCarouselSlideHeader } from './components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader';
247
+ export type { SwipableMobileCarouselSlideHeaderProps } from './components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader';
248
+ export { SwipableMobileCarouselSlideBody } from './components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody';
249
+ export type { SwipableMobileCarouselSlideBodyProps } from './components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody';
250
+ export { SwipableMobileCarouselSlideFooter } from './components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter';
251
+ export type { SwipableMobileCarouselSlideFooterProps } from './components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter';
@@ -0,0 +1,94 @@
1
+ 'use client';
2
+
3
+ import { type RefObject, useEffect, useRef } from 'react';
4
+ import { lockBodyScroll, unlockBodyScroll } from './scroll-lock';
5
+
6
+ // Internal to the design system — not exported from `index.ts`. Shared by
7
+ // Dialog, Drawer, and Sheet, which independently implemented identical
8
+ // scrim/focus-trap/Escape/scroll-lock logic before this consolidation
9
+ // (RFC 0079, epic task 9.19). ConfirmDialog is deliberately not migrated
10
+ // here — it stays on the native `<dialog>` element, which already provides
11
+ // equivalent focus-trap/backdrop semantics more reliably for its use case.
12
+
13
+ export const OVERLAY_FOCUSABLE_SELECTOR =
14
+ 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
15
+
16
+ /**
17
+ * Locks document scroll for the whole mounted lifetime of an overlay
18
+ * (including its exit animation), not just while `open` — so the background
19
+ * can't scroll while the panel is still visibly sliding/fading away.
20
+ * Ref-counted via `scroll-lock.ts` so nested overlays (e.g. a confirmation
21
+ * dialog inside an overlay-shell plugin) don't release the lock while a
22
+ * sibling is still open.
23
+ */
24
+ export function useOverlayScrollLock(mounted: boolean): void {
25
+ useEffect(() => {
26
+ if (!mounted) return;
27
+ lockBodyScroll();
28
+ return unlockBodyScroll;
29
+ }, [mounted]);
30
+ }
31
+
32
+ /**
33
+ * Captures the element focused before the overlay opened, moves focus into
34
+ * the panel when `active` becomes true, and restores the original focus on
35
+ * cleanup. Callers pass whichever prop should trigger the capture — `open`
36
+ * for Dialog/Drawer, `mounted` for Sheet (which restores focus on unmount
37
+ * rather than on the raw `open` transition).
38
+ */
39
+ export function useOverlayFocusCapture(
40
+ panelRef: RefObject<HTMLElement | null>,
41
+ active: boolean,
42
+ ): void {
43
+ const previouslyFocused = useRef<HTMLElement | null>(null);
44
+ useEffect(() => {
45
+ if (!active) return;
46
+ previouslyFocused.current = document.activeElement as HTMLElement | null;
47
+ const panel = panelRef.current;
48
+ const first = panel?.querySelector<HTMLElement>(OVERLAY_FOCUSABLE_SELECTOR);
49
+ (first ?? panel)?.focus();
50
+ return () => previouslyFocused.current?.focus();
51
+ }, [active, panelRef]);
52
+ }
53
+
54
+ /**
55
+ * Escape-to-close plus a Tab focus trap cycling within the panel. Attached
56
+ * at `document` level so no keyboard listener is needed on the overlay's own
57
+ * element (which would trigger `jsx-a11y/no-noninteractive-element-interactions`).
58
+ */
59
+ export function useOverlayKeyboardTrap(
60
+ panelRef: RefObject<HTMLElement | null>,
61
+ open: boolean,
62
+ onClose: () => void,
63
+ ): void {
64
+ useEffect(() => {
65
+ if (!open) return;
66
+ function handleKeyDown(e: KeyboardEvent) {
67
+ if (e.key === 'Escape') {
68
+ e.stopPropagation();
69
+ onClose();
70
+ return;
71
+ }
72
+ if (e.key !== 'Tab') return;
73
+ const panel = panelRef.current;
74
+ if (!panel) return;
75
+ const focusable = [...panel.querySelectorAll<HTMLElement>(OVERLAY_FOCUSABLE_SELECTOR)];
76
+ const first = focusable[0];
77
+ const last = focusable.at(-1);
78
+ if (!first || !last) {
79
+ e.preventDefault();
80
+ return;
81
+ }
82
+ const active = document.activeElement;
83
+ if (e.shiftKey && active === first) {
84
+ e.preventDefault();
85
+ last.focus();
86
+ } else if (!e.shiftKey && active === last) {
87
+ e.preventDefault();
88
+ first.focus();
89
+ }
90
+ }
91
+ document.addEventListener('keydown', handleKeyDown);
92
+ return () => document.removeEventListener('keydown', handleKeyDown);
93
+ }, [open, onClose, panelRef]);
94
+ }