@sovereignfs/ui 0.54.0 → 0.89.1

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 (473) hide show
  1. package/LICENSE +373 -661
  2. package/NOTICE +8 -0
  3. package/README.md +4 -6
  4. package/dist/Accordion.module.css +1 -1
  5. package/dist/Alert.module.css +1 -1
  6. package/dist/AppsLauncher.module.css +102 -0
  7. package/dist/Avatar.module.css +1 -1
  8. package/dist/Badge.module.css +30 -7
  9. package/dist/BalanceChip.module.css +1 -1
  10. package/dist/Button.module.css +23 -2
  11. package/dist/Card.module.css +7 -1
  12. package/dist/CardTile.module.css +187 -0
  13. package/dist/CheckableListRow.module.css +8 -0
  14. package/dist/Checkbox.module.css +8 -0
  15. package/dist/CodeTextarea.module.css +7 -1
  16. package/dist/Collapsible.module.css +1 -1
  17. package/dist/ColorPicker.module.css +138 -0
  18. package/dist/Combobox.module.css +8 -2
  19. package/dist/Command.module.css +7 -1
  20. package/dist/ConfirmDialog.module.css +8 -2
  21. package/dist/ConsentPrompt.module.css +21 -0
  22. package/dist/DatePicker.module.css +7 -1
  23. package/dist/Dialog.module.css +130 -21
  24. package/dist/DragHandleRow.module.css +6 -0
  25. package/dist/Drawer.module.css +36 -7
  26. package/dist/FileDropzone.module.css +25 -1
  27. package/dist/Header.module.css +68 -0
  28. package/dist/HeaderFooterLayout.module.css +21 -0
  29. package/dist/IconPicker.module.css +15 -5
  30. package/dist/Input.module.css +7 -1
  31. package/dist/Kbd.module.css +1 -1
  32. package/dist/LegalLinks.module.css +9 -2
  33. package/dist/Markdown.module.css +29 -0
  34. package/dist/Menu.module.css +1 -0
  35. package/dist/Message.module.css +10 -1
  36. package/dist/MessageScroller.module.css +12 -1
  37. package/dist/MobileAppsDrawer.module.css +19 -14
  38. package/dist/MobileFooter.module.css +7 -1
  39. package/dist/MobileHeader.module.css +14 -1
  40. package/dist/NavList.module.css +139 -0
  41. package/dist/NavTabs.module.css +8 -2
  42. package/dist/NotificationsPanel.module.css +268 -0
  43. package/dist/OverlayHeader.module.css +1 -1
  44. package/dist/PageContainer.module.css +62 -0
  45. package/dist/PageHeader.module.css +54 -0
  46. package/dist/PageLayout.module.css +51 -0
  47. package/dist/Popover.module.css +1 -1
  48. package/dist/QrCode.module.css +17 -0
  49. package/dist/QuantityStepper.module.css +5 -3
  50. package/dist/RadioGroup.module.css +6 -0
  51. package/dist/Resizable.module.css +3 -3
  52. package/dist/RootLayout.module.css +12 -0
  53. package/dist/SegmentedControl.module.css +7 -1
  54. package/dist/Select.module.css +7 -1
  55. package/dist/Sheet.module.css +20 -2
  56. package/dist/SplitPane.module.css +5 -5
  57. package/dist/StatusBadge.module.css +1 -1
  58. package/dist/StepStrip.module.css +55 -0
  59. package/dist/SuggestionInput.module.css +14 -3
  60. package/dist/SwipableMobileCarousel.module.css +12 -3
  61. package/dist/SwipableMobileCarouselDots.module.css +21 -0
  62. package/dist/SwipeStack.module.css +101 -0
  63. package/dist/SystemBanner.module.css +16 -0
  64. package/dist/Table.module.css +2 -2
  65. package/dist/Tabs.module.css +7 -1
  66. package/dist/TagInput.module.css +8 -2
  67. package/dist/Textarea.module.css +15 -1
  68. package/dist/ThreeColumnLayout.module.css +35 -0
  69. package/dist/Toast.module.css +67 -3
  70. package/dist/Toggle.module.css +7 -0
  71. package/dist/Tooltip.module.css +7 -1
  72. package/dist/UserMenu.module.css +95 -0
  73. package/dist/fonts/OFL.txt +93 -0
  74. package/dist/fonts/hanken-grotesk-cyrillic-ext-wght-normal.woff2 +0 -0
  75. package/dist/fonts/hanken-grotesk-latin-ext-wght-normal.woff2 +0 -0
  76. package/dist/fonts/hanken-grotesk-latin-wght-normal.woff2 +0 -0
  77. package/dist/fonts/hanken-grotesk-vietnamese-wght-normal.woff2 +0 -0
  78. package/dist/index.d.ts +1156 -76
  79. package/dist/index.js +4223 -1513
  80. package/dist/tokens/fonts.css +53 -0
  81. package/dist/tokens/primitives.css +23 -12
  82. package/dist/tokens/semantic.css +32 -0
  83. package/dist/tokens/theme-presets.css +33 -0
  84. package/dist/tokens.css +2 -1
  85. package/package.json +46 -19
  86. package/src/__tests__/motion.test.tsx +0 -105
  87. package/src/components/Accordion/Accordion.module.css +0 -3
  88. package/src/components/Accordion/Accordion.stories.tsx +0 -110
  89. package/src/components/Accordion/Accordion.tsx +0 -53
  90. package/src/components/Accordion/__tests__/Accordion.test.tsx +0 -61
  91. package/src/components/Alert/Alert.module.css +0 -62
  92. package/src/components/Alert/Alert.stories.tsx +0 -96
  93. package/src/components/Alert/Alert.tsx +0 -58
  94. package/src/components/Alert/__tests__/Alert.test.tsx +0 -75
  95. package/src/components/AspectRatio/AspectRatio.module.css +0 -15
  96. package/src/components/AspectRatio/AspectRatio.stories.tsx +0 -78
  97. package/src/components/AspectRatio/AspectRatio.tsx +0 -21
  98. package/src/components/AspectRatio/__tests__/AspectRatio.test.tsx +0 -27
  99. package/src/components/Avatar/Avatar.module.css +0 -38
  100. package/src/components/Avatar/Avatar.tsx +0 -42
  101. package/src/components/Badge/Badge.module.css +0 -154
  102. package/src/components/Badge/Badge.stories.tsx +0 -226
  103. package/src/components/Badge/Badge.tsx +0 -81
  104. package/src/components/Badge/__tests__/Badge.test.tsx +0 -88
  105. package/src/components/BalanceChip/BalanceChip.module.css +0 -32
  106. package/src/components/BalanceChip/BalanceChip.stories.tsx +0 -45
  107. package/src/components/BalanceChip/BalanceChip.tsx +0 -33
  108. package/src/components/Breadcrumb/Breadcrumb.module.css +0 -49
  109. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +0 -47
  110. package/src/components/Breadcrumb/Breadcrumb.tsx +0 -57
  111. package/src/components/Breadcrumb/__tests__/Breadcrumb.test.tsx +0 -52
  112. package/src/components/Button/Button.module.css +0 -153
  113. package/src/components/Button/Button.stories.tsx +0 -83
  114. package/src/components/Button/Button.tsx +0 -52
  115. package/src/components/Button/__tests__/Button.test.tsx +0 -66
  116. package/src/components/ButtonGroup/ButtonGroup.module.css +0 -29
  117. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +0 -57
  118. package/src/components/ButtonGroup/ButtonGroup.tsx +0 -27
  119. package/src/components/ButtonGroup/__tests__/ButtonGroup.test.tsx +0 -29
  120. package/src/components/Calendar/Calendar.module.css +0 -126
  121. package/src/components/Calendar/Calendar.tsx +0 -213
  122. package/src/components/Calendar/__tests__/Calendar.test.tsx +0 -98
  123. package/src/components/Calendar/dateUtils.ts +0 -97
  124. package/src/components/Card/Card.module.css +0 -42
  125. package/src/components/Card/Card.tsx +0 -34
  126. package/src/components/CheckableListRow/CheckableListRow.module.css +0 -95
  127. package/src/components/CheckableListRow/CheckableListRow.stories.tsx +0 -99
  128. package/src/components/CheckableListRow/CheckableListRow.tsx +0 -89
  129. package/src/components/Checkbox/Checkbox.module.css +0 -111
  130. package/src/components/Checkbox/Checkbox.tsx +0 -78
  131. package/src/components/CodeTextarea/CodeTextarea.module.css +0 -53
  132. package/src/components/CodeTextarea/CodeTextarea.stories.tsx +0 -77
  133. package/src/components/CodeTextarea/CodeTextarea.tsx +0 -36
  134. package/src/components/Collapsible/Collapsible.module.css +0 -70
  135. package/src/components/Collapsible/Collapsible.stories.tsx +0 -62
  136. package/src/components/Collapsible/Collapsible.tsx +0 -66
  137. package/src/components/Collapsible/__tests__/Collapsible.test.tsx +0 -71
  138. package/src/components/Combobox/Combobox.module.css +0 -122
  139. package/src/components/Combobox/Combobox.stories.tsx +0 -79
  140. package/src/components/Combobox/Combobox.tsx +0 -186
  141. package/src/components/Combobox/__tests__/Combobox.test.tsx +0 -158
  142. package/src/components/Command/Command.module.css +0 -80
  143. package/src/components/Command/Command.stories.tsx +0 -104
  144. package/src/components/Command/Command.tsx +0 -168
  145. package/src/components/Command/__tests__/Command.test.tsx +0 -162
  146. package/src/components/ConfirmDialog/ConfirmDialog.module.css +0 -113
  147. package/src/components/ConfirmDialog/ConfirmDialog.tsx +0 -124
  148. package/src/components/ConfirmDialog/__tests__/ConfirmDialog.test.tsx +0 -146
  149. package/src/components/ContextMenu/ContextMenu.stories.tsx +0 -81
  150. package/src/components/ContextMenu/ContextMenu.tsx +0 -100
  151. package/src/components/ContextMenu/__tests__/ContextMenu.test.tsx +0 -87
  152. package/src/components/CurrencyInput/CurrencyInput.stories.tsx +0 -50
  153. package/src/components/CurrencyInput/CurrencyInput.tsx +0 -60
  154. package/src/components/DataTable/DataTable.module.css +0 -28
  155. package/src/components/DataTable/DataTable.stories.tsx +0 -74
  156. package/src/components/DataTable/DataTable.tsx +0 -154
  157. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -123
  158. package/src/components/DatePicker/DatePicker.module.css +0 -61
  159. package/src/components/DatePicker/DatePicker.tsx +0 -103
  160. package/src/components/DatePicker/__tests__/DatePicker.test.tsx +0 -89
  161. package/src/components/DeviceOnlyGate/DeviceOnlyGate.tsx +0 -58
  162. package/src/components/DeviceOnlyGate/__tests__/DeviceOnlyGate.test.tsx +0 -45
  163. package/src/components/DeviceStorageKeyGate/DeviceStorageKeyGate.tsx +0 -100
  164. package/src/components/DeviceStorageKeyGate/__tests__/DeviceStorageKeyGate.test.tsx +0 -119
  165. package/src/components/Dialog/Dialog.module.css +0 -226
  166. package/src/components/Dialog/Dialog.stories.tsx +0 -147
  167. package/src/components/Dialog/Dialog.tsx +0 -160
  168. package/src/components/Dialog/__tests__/Dialog.test.tsx +0 -137
  169. package/src/components/DragHandleRow/DragHandleRow.module.css +0 -57
  170. package/src/components/DragHandleRow/DragHandleRow.tsx +0 -61
  171. package/src/components/Drawer/Drawer.module.css +0 -92
  172. package/src/components/Drawer/Drawer.stories.tsx +0 -132
  173. package/src/components/Drawer/Drawer.tsx +0 -176
  174. package/src/components/Drawer/__tests__/Drawer.test.tsx +0 -199
  175. package/src/components/EmptyState/EmptyState.module.css +0 -27
  176. package/src/components/EmptyState/EmptyState.tsx +0 -27
  177. package/src/components/FileDropzone/FileDropzone.module.css +0 -63
  178. package/src/components/FileDropzone/FileDropzone.tsx +0 -109
  179. package/src/components/FileDropzone/__tests__/FileDropzone.test.tsx +0 -67
  180. package/src/components/FormField/FormField.module.css +0 -33
  181. package/src/components/FormField/FormField.tsx +0 -78
  182. package/src/components/FormField/__tests__/FormField.test.tsx +0 -83
  183. package/src/components/HoverCard/HoverCard.module.css +0 -3
  184. package/src/components/HoverCard/HoverCard.stories.tsx +0 -66
  185. package/src/components/HoverCard/HoverCard.tsx +0 -111
  186. package/src/components/HoverCard/__tests__/HoverCard.test.tsx +0 -99
  187. package/src/components/Icon/Icon.module.css +0 -27
  188. package/src/components/Icon/Icon.stories.tsx +0 -95
  189. package/src/components/Icon/Icon.tsx +0 -43
  190. package/src/components/Icon/__tests__/Icon.test.tsx +0 -40
  191. package/src/components/Icon/icons/activity.tsx +0 -20
  192. package/src/components/Icon/icons/alert-triangle.tsx +0 -22
  193. package/src/components/Icon/icons/apple.tsx +0 -21
  194. package/src/components/Icon/icons/banana.tsx +0 -21
  195. package/src/components/Icon/icons/beef.tsx +0 -22
  196. package/src/components/Icon/icons/beer.tsx +0 -24
  197. package/src/components/Icon/icons/bell.tsx +0 -21
  198. package/src/components/Icon/icons/calendar.tsx +0 -23
  199. package/src/components/Icon/icons/candy.tsx +0 -24
  200. package/src/components/Icon/icons/carrot.tsx +0 -22
  201. package/src/components/Icon/icons/check.tsx +0 -20
  202. package/src/components/Icon/icons/chevron-down.tsx +0 -20
  203. package/src/components/Icon/icons/chevron-left.tsx +0 -20
  204. package/src/components/Icon/icons/chevron-right.tsx +0 -20
  205. package/src/components/Icon/icons/chevron-up.tsx +0 -20
  206. package/src/components/Icon/icons/circle-check.tsx +0 -21
  207. package/src/components/Icon/icons/circle-x.tsx +0 -22
  208. package/src/components/Icon/icons/coffee.tsx +0 -23
  209. package/src/components/Icon/icons/cookie.tsx +0 -25
  210. package/src/components/Icon/icons/croissant.tsx +0 -24
  211. package/src/components/Icon/icons/cup-soda.tsx +0 -23
  212. package/src/components/Icon/icons/drumstick.tsx +0 -21
  213. package/src/components/Icon/icons/egg.tsx +0 -20
  214. package/src/components/Icon/icons/ellipsis-vertical.tsx +0 -22
  215. package/src/components/Icon/icons/external-link.tsx +0 -22
  216. package/src/components/Icon/icons/eye-off.tsx +0 -23
  217. package/src/components/Icon/icons/eye.tsx +0 -21
  218. package/src/components/Icon/icons/file.tsx +0 -21
  219. package/src/components/Icon/icons/fish.tsx +0 -25
  220. package/src/components/Icon/icons/grid-2x2.tsx +0 -22
  221. package/src/components/Icon/icons/house.tsx +0 -21
  222. package/src/components/Icon/icons/index.ts +0 -234
  223. package/src/components/Icon/icons/info.tsx +0 -22
  224. package/src/components/Icon/icons/lock.tsx +0 -21
  225. package/src/components/Icon/icons/log-out.tsx +0 -22
  226. package/src/components/Icon/icons/mail.tsx +0 -21
  227. package/src/components/Icon/icons/menu.tsx +0 -22
  228. package/src/components/Icon/icons/milk.tsx +0 -22
  229. package/src/components/Icon/icons/package.tsx +0 -23
  230. package/src/components/Icon/icons/pencil.tsx +0 -21
  231. package/src/components/Icon/icons/pizza.tsx +0 -24
  232. package/src/components/Icon/icons/plus.tsx +0 -21
  233. package/src/components/Icon/icons/rotate-ccw.tsx +0 -21
  234. package/src/components/Icon/icons/salad.tsx +0 -24
  235. package/src/components/Icon/icons/search.tsx +0 -21
  236. package/src/components/Icon/icons/settings.tsx +0 -21
  237. package/src/components/Icon/icons/shield.tsx +0 -20
  238. package/src/components/Icon/icons/shopping-basket.tsx +0 -26
  239. package/src/components/Icon/icons/sliders-horizontal.tsx +0 -28
  240. package/src/components/Icon/icons/smartphone.tsx +0 -21
  241. package/src/components/Icon/icons/snowflake.tsx +0 -31
  242. package/src/components/Icon/icons/spray-can.tsx +0 -29
  243. package/src/components/Icon/icons/trash-2.tsx +0 -24
  244. package/src/components/Icon/icons/upload.tsx +0 -22
  245. package/src/components/Icon/icons/user.tsx +0 -21
  246. package/src/components/Icon/icons/wine.tsx +0 -23
  247. package/src/components/Icon/icons/x.tsx +0 -21
  248. package/src/components/IconPicker/IconPicker.module.css +0 -63
  249. package/src/components/IconPicker/IconPicker.stories.tsx +0 -84
  250. package/src/components/IconPicker/IconPicker.tsx +0 -90
  251. package/src/components/Input/Input.module.css +0 -52
  252. package/src/components/Input/Input.stories.tsx +0 -86
  253. package/src/components/Input/Input.tsx +0 -14
  254. package/src/components/Input/__tests__/Input.test.tsx +0 -22
  255. package/src/components/Item/Item.module.css +0 -70
  256. package/src/components/Item/Item.stories.tsx +0 -62
  257. package/src/components/Item/Item.tsx +0 -54
  258. package/src/components/Item/__tests__/Item.test.tsx +0 -39
  259. package/src/components/Kbd/Kbd.module.css +0 -14
  260. package/src/components/Kbd/Kbd.stories.tsx +0 -32
  261. package/src/components/Kbd/Kbd.tsx +0 -12
  262. package/src/components/Kbd/__tests__/Kbd.test.tsx +0 -14
  263. package/src/components/Label/Label.module.css +0 -11
  264. package/src/components/Label/Label.stories.tsx +0 -40
  265. package/src/components/Label/Label.tsx +0 -24
  266. package/src/components/Label/__tests__/Label.test.tsx +0 -32
  267. package/src/components/LegalLinks/LegalLinks.module.css +0 -24
  268. package/src/components/LegalLinks/LegalLinks.stories.tsx +0 -22
  269. package/src/components/LegalLinks/LegalLinks.tsx +0 -40
  270. package/src/components/Markdown/Markdown.module.css +0 -49
  271. package/src/components/Markdown/Markdown.stories.tsx +0 -30
  272. package/src/components/Markdown/Markdown.tsx +0 -168
  273. package/src/components/Marker/Marker.module.css +0 -33
  274. package/src/components/Marker/Marker.stories.tsx +0 -39
  275. package/src/components/Marker/Marker.tsx +0 -34
  276. package/src/components/Marker/__tests__/Marker.test.tsx +0 -23
  277. package/src/components/MemberMultiSelect/MemberMultiSelect.module.css +0 -27
  278. package/src/components/MemberMultiSelect/MemberMultiSelect.stories.tsx +0 -74
  279. package/src/components/MemberMultiSelect/MemberMultiSelect.tsx +0 -67
  280. package/src/components/Menu/Menu.module.css +0 -89
  281. package/src/components/Menu/Menu.tsx +0 -159
  282. package/src/components/Menu/__tests__/Menu.test.tsx +0 -197
  283. package/src/components/Menubar/Menubar.stories.tsx +0 -52
  284. package/src/components/Menubar/Menubar.tsx +0 -42
  285. package/src/components/Menubar/__tests__/Menubar.test.tsx +0 -45
  286. package/src/components/Message/Message.module.css +0 -99
  287. package/src/components/Message/Message.stories.tsx +0 -79
  288. package/src/components/Message/Message.tsx +0 -41
  289. package/src/components/Message/__tests__/Message.test.tsx +0 -46
  290. package/src/components/MessageScroller/MessageScroller.module.css +0 -54
  291. package/src/components/MessageScroller/MessageScroller.stories.tsx +0 -84
  292. package/src/components/MessageScroller/MessageScroller.tsx +0 -72
  293. package/src/components/MessageScroller/__tests__/MessageScroller.test.tsx +0 -105
  294. package/src/components/MobileAppsDrawer/MobileAppsDrawer.module.css +0 -81
  295. package/src/components/MobileAppsDrawer/MobileAppsDrawer.tsx +0 -78
  296. package/src/components/MobileAppsDrawer/__tests__/MobileAppsDrawer.test.tsx +0 -80
  297. package/src/components/MobileFooter/MobileFooter.module.css +0 -73
  298. package/src/components/MobileFooter/MobileFooter.stories.tsx +0 -47
  299. package/src/components/MobileFooter/MobileFooter.tsx +0 -109
  300. package/src/components/MobileFooter/__tests__/MobileFooter.test.tsx +0 -71
  301. package/src/components/MobileHeader/MobileHeader.module.css +0 -63
  302. package/src/components/MobileHeader/MobileHeader.stories.tsx +0 -57
  303. package/src/components/MobileHeader/MobileHeader.tsx +0 -77
  304. package/src/components/MobileHeader/__tests__/MobileHeader.test.tsx +0 -58
  305. package/src/components/NavTabs/NavTabs.module.css +0 -50
  306. package/src/components/NavTabs/NavTabs.tsx +0 -61
  307. package/src/components/NavigationMenu/NavigationMenu.module.css +0 -53
  308. package/src/components/NavigationMenu/NavigationMenu.stories.tsx +0 -58
  309. package/src/components/NavigationMenu/NavigationMenu.tsx +0 -125
  310. package/src/components/NavigationMenu/__tests__/NavigationMenu.test.tsx +0 -93
  311. package/src/components/OfflineGate/OfflineGate.tsx +0 -44
  312. package/src/components/OfflineGate/__tests__/OfflineGate.test.tsx +0 -66
  313. package/src/components/OverlayHeader/OverlayHeader.module.css +0 -98
  314. package/src/components/OverlayHeader/OverlayHeader.tsx +0 -62
  315. package/src/components/OverlayHeader/__tests__/OverlayHeader.test.tsx +0 -51
  316. package/src/components/PageContainer/PageContainer.module.css +0 -20
  317. package/src/components/PageContainer/PageContainer.tsx +0 -31
  318. package/src/components/PageContainer/__tests__/PageContainer.test.tsx +0 -37
  319. package/src/components/PageHeader/PageHeader.module.css +0 -32
  320. package/src/components/PageHeader/PageHeader.tsx +0 -35
  321. package/src/components/Pagination/Pagination.module.css +0 -98
  322. package/src/components/Pagination/Pagination.stories.tsx +0 -49
  323. package/src/components/Pagination/Pagination.tsx +0 -87
  324. package/src/components/Pagination/__tests__/Pagination.test.tsx +0 -56
  325. package/src/components/Popover/Popover.module.css +0 -74
  326. package/src/components/Popover/Popover.stories.tsx +0 -357
  327. package/src/components/Popover/Popover.tsx +0 -208
  328. package/src/components/Popover/__tests__/Popover.test.tsx +0 -98
  329. package/src/components/Progress/Progress.module.css +0 -20
  330. package/src/components/Progress/Progress.stories.tsx +0 -40
  331. package/src/components/Progress/Progress.tsx +0 -35
  332. package/src/components/Progress/__tests__/Progress.test.tsx +0 -31
  333. package/src/components/QuantityStepper/QuantityStepper.module.css +0 -67
  334. package/src/components/QuantityStepper/QuantityStepper.stories.tsx +0 -79
  335. package/src/components/QuantityStepper/QuantityStepper.tsx +0 -107
  336. package/src/components/RadioGroup/RadioGroup.module.css +0 -88
  337. package/src/components/RadioGroup/RadioGroup.stories.tsx +0 -69
  338. package/src/components/RadioGroup/RadioGroup.tsx +0 -99
  339. package/src/components/RadioGroup/__tests__/RadioGroup.test.tsx +0 -59
  340. package/src/components/Resizable/Resizable.module.css +0 -70
  341. package/src/components/Resizable/Resizable.stories.tsx +0 -82
  342. package/src/components/Resizable/Resizable.tsx +0 -313
  343. package/src/components/Resizable/__tests__/Resizable.test.tsx +0 -128
  344. package/src/components/ResponsiveSurface/ResponsiveSurface.tsx +0 -24
  345. package/src/components/ResponsiveSurface/__tests__/ResponsiveSurface.test.tsx +0 -73
  346. package/src/components/ScrollArea/ScrollArea.module.css +0 -20
  347. package/src/components/ScrollArea/ScrollArea.stories.tsx +0 -57
  348. package/src/components/ScrollArea/ScrollArea.tsx +0 -27
  349. package/src/components/ScrollArea/__tests__/ScrollArea.test.tsx +0 -39
  350. package/src/components/SegmentedControl/SegmentedControl.module.css +0 -55
  351. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +0 -118
  352. package/src/components/SegmentedControl/SegmentedControl.tsx +0 -56
  353. package/src/components/SegmentedControl/__tests__/SegmentedControl.test.tsx +0 -63
  354. package/src/components/Select/Select.module.css +0 -82
  355. package/src/components/Select/Select.stories.tsx +0 -115
  356. package/src/components/Select/Select.tsx +0 -48
  357. package/src/components/Select/__tests__/Select.test.tsx +0 -59
  358. package/src/components/Sheet/Sheet.module.css +0 -55
  359. package/src/components/Sheet/Sheet.tsx +0 -109
  360. package/src/components/Sheet/__tests__/Sheet.test.tsx +0 -99
  361. package/src/components/Slider/Slider.module.css +0 -95
  362. package/src/components/Slider/Slider.stories.tsx +0 -64
  363. package/src/components/Slider/Slider.tsx +0 -77
  364. package/src/components/Slider/__tests__/Slider.test.tsx +0 -45
  365. package/src/components/Spinner/Spinner.module.css +0 -39
  366. package/src/components/Spinner/Spinner.tsx +0 -23
  367. package/src/components/SplitMethodSelector/SplitMethodSelector.stories.tsx +0 -33
  368. package/src/components/SplitMethodSelector/SplitMethodSelector.tsx +0 -43
  369. package/src/components/SplitPane/SplitPane.module.css +0 -85
  370. package/src/components/SplitPane/SplitPane.stories.tsx +0 -160
  371. package/src/components/SplitPane/SplitPane.tsx +0 -149
  372. package/src/components/SplitPane/__tests__/SplitPane.test.tsx +0 -51
  373. package/src/components/StatusBadge/StatusBadge.module.css +0 -59
  374. package/src/components/StatusBadge/StatusBadge.stories.tsx +0 -74
  375. package/src/components/StatusBadge/StatusBadge.tsx +0 -65
  376. package/src/components/SuggestionInput/SuggestionInput.module.css +0 -103
  377. package/src/components/SuggestionInput/SuggestionInput.stories.tsx +0 -144
  378. package/src/components/SuggestionInput/SuggestionInput.tsx +0 -207
  379. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.module.css +0 -55
  380. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.tsx +0 -227
  381. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlide.tsx +0 -35
  382. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody.tsx +0 -42
  383. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter.tsx +0 -18
  384. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader.tsx +0 -21
  385. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideParts.module.css +0 -29
  386. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarousel.test.tsx +0 -133
  387. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarouselDevGuard.test.tsx +0 -61
  388. package/src/components/SwipableMobileCarousel/context.ts +0 -13
  389. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.module.css +0 -49
  390. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.tsx +0 -62
  391. package/src/components/SwipableMobileCarouselDots/__tests__/SwipableMobileCarouselDots.test.tsx +0 -63
  392. package/src/components/SystemBanner/SystemBanner.module.css +0 -69
  393. package/src/components/SystemBanner/SystemBanner.stories.tsx +0 -86
  394. package/src/components/SystemBanner/SystemBanner.tsx +0 -50
  395. package/src/components/SystemBanner/__tests__/SystemBanner.test.tsx +0 -50
  396. package/src/components/Table/Table.module.css +0 -45
  397. package/src/components/Table/Table.stories.tsx +0 -125
  398. package/src/components/Table/Table.tsx +0 -51
  399. package/src/components/Table/__tests__/Table.test.tsx +0 -50
  400. package/src/components/Tabs/Tabs.module.css +0 -56
  401. package/src/components/Tabs/Tabs.stories.tsx +0 -100
  402. package/src/components/Tabs/Tabs.tsx +0 -46
  403. package/src/components/Tabs/__tests__/Tabs.test.tsx +0 -45
  404. package/src/components/TagInput/TagInput.module.css +0 -141
  405. package/src/components/TagInput/TagInput.stories.tsx +0 -109
  406. package/src/components/TagInput/TagInput.tsx +0 -174
  407. package/src/components/TagInput/__tests__/TagInput.test.tsx +0 -69
  408. package/src/components/Textarea/Textarea.module.css +0 -39
  409. package/src/components/Textarea/Textarea.tsx +0 -15
  410. package/src/components/Textarea/__tests__/Textarea.test.tsx +0 -29
  411. package/src/components/Toast/Toast.module.css +0 -132
  412. package/src/components/Toast/Toast.stories.tsx +0 -191
  413. package/src/components/Toast/Toast.tsx +0 -139
  414. package/src/components/Toggle/Toggle.module.css +0 -57
  415. package/src/components/Toggle/Toggle.stories.tsx +0 -95
  416. package/src/components/Toggle/Toggle.tsx +0 -39
  417. package/src/components/Toggle/__tests__/Toggle.test.tsx +0 -47
  418. package/src/components/Tooltip/Tooltip.module.css +0 -56
  419. package/src/components/Tooltip/Tooltip.tsx +0 -30
  420. package/src/components/Typography/Typography.module.css +0 -47
  421. package/src/components/Typography/Typography.stories.tsx +0 -62
  422. package/src/components/Typography/Typography.tsx +0 -30
  423. package/src/components/Typography/__tests__/Typography.test.tsx +0 -34
  424. package/src/css-modules.d.ts +0 -4
  425. package/src/hooks/__tests__/useCarouselRouteSync.test.tsx +0 -126
  426. package/src/hooks/__tests__/useDoubleTap.test.tsx +0 -117
  427. package/src/hooks/__tests__/useIsMobile.test.tsx +0 -80
  428. package/src/hooks/__tests__/useIsOffline.test.tsx +0 -53
  429. package/src/hooks/__tests__/useLongPress.test.tsx +0 -158
  430. package/src/hooks/__tests__/useOfflineTileState.test.tsx +0 -69
  431. package/src/hooks/__tests__/useResponsiveLayout.test.tsx +0 -87
  432. package/src/hooks/__tests__/useSnapCarousel.test.tsx +0 -93
  433. package/src/hooks/__tests__/useSwipeReveal.test.tsx +0 -110
  434. package/src/hooks/index.ts +0 -24
  435. package/src/hooks/useCarouselRouteSync.ts +0 -92
  436. package/src/hooks/useCommitOnEnterOrBlur.ts +0 -39
  437. package/src/hooks/useDoubleTap.ts +0 -91
  438. package/src/hooks/useIsMobile.ts +0 -33
  439. package/src/hooks/useIsOffline.ts +0 -41
  440. package/src/hooks/useLongPress.ts +0 -185
  441. package/src/hooks/useOfflineTileState.ts +0 -45
  442. package/src/hooks/useResponsiveLayout.ts +0 -36
  443. package/src/hooks/useSnapCarousel.ts +0 -79
  444. package/src/hooks/useSwipeReveal.ts +0 -107
  445. package/src/index.ts +0 -251
  446. package/src/motion.ts +0 -78
  447. package/src/overlay-shell.ts +0 -94
  448. package/src/scroll-lock.ts +0 -22
  449. package/src/stories/Avatar.stories.tsx +0 -44
  450. package/src/stories/Card.stories.tsx +0 -35
  451. package/src/stories/Checkbox.stories.tsx +0 -45
  452. package/src/stories/DesignSystemOverview.stories.tsx +0 -3187
  453. package/src/stories/DeviceOnlyGate.stories.tsx +0 -35
  454. package/src/stories/DeviceStorageKeyGate.stories.tsx +0 -57
  455. package/src/stories/DragHandleRow.stories.tsx +0 -41
  456. package/src/stories/EmptyState.stories.tsx +0 -33
  457. package/src/stories/FileDropzone.stories.tsx +0 -69
  458. package/src/stories/FormField.stories.tsx +0 -47
  459. package/src/stories/InteractionHooks.stories.tsx +0 -925
  460. package/src/stories/MobilePatterns.stories.tsx +0 -1536
  461. package/src/stories/NavTabs.stories.tsx +0 -53
  462. package/src/stories/OfflineGate.stories.tsx +0 -42
  463. package/src/stories/PageContainer.stories.tsx +0 -37
  464. package/src/stories/PageHeader.stories.tsx +0 -42
  465. package/src/stories/ResponsiveSurface.stories.tsx +0 -47
  466. package/src/stories/Spinner.stories.tsx +0 -25
  467. package/src/stories/SwipableMobileCarousel.stories.tsx +0 -304
  468. package/src/stories/Textarea.stories.tsx +0 -51
  469. package/src/stories/TokenGallery.stories.tsx +0 -602
  470. package/src/stories/Tooltip.stories.tsx +0 -59
  471. package/src/tokens/primitives.css +0 -157
  472. package/src/tokens/semantic.css +0 -130
  473. package/src/tokens.css +0 -5
@@ -1,53 +0,0 @@
1
- .nav {
2
- min-width: 0;
3
- }
4
-
5
- .list {
6
- display: flex;
7
- align-items: center;
8
- gap: var(--sv-space-1);
9
- margin: 0;
10
- padding: 0;
11
- list-style: none;
12
- }
13
-
14
- .link,
15
- .trigger {
16
- display: inline-flex;
17
- align-items: center;
18
- height: 36px;
19
- padding: 0 var(--sv-space-3);
20
- border: none;
21
- border-radius: var(--sv-radius-md);
22
- background: transparent;
23
- color: var(--sv-color-text-primary);
24
- font-family: var(--sv-font-family);
25
- font-size: var(--sv-font-size-sm);
26
- font-weight: var(--sv-font-weight-medium);
27
- text-decoration: none;
28
- cursor: pointer;
29
- }
30
-
31
- @media (hover: hover) {
32
- .link:hover,
33
- .trigger:hover {
34
- background: var(--sv-color-surface-sunken);
35
- }
36
- }
37
-
38
- .link:focus-visible,
39
- .trigger:focus-visible {
40
- outline: 2px solid var(--sv-color-focus-ring);
41
- outline-offset: 2px;
42
- }
43
-
44
- .triggerOpen {
45
- background: var(--sv-color-surface-sunken);
46
- }
47
-
48
- @media (pointer: coarse) {
49
- .link,
50
- .trigger {
51
- min-height: var(--sv-touch-target-min, 44px);
52
- }
53
- }
@@ -1,58 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { NavigationMenu } from './NavigationMenu';
3
-
4
- const meta = {
5
- title: 'Components/NavigationMenu',
6
- component: NavigationMenu,
7
- parameters: {
8
- layout: 'padded',
9
- docs: {
10
- description: {
11
- component:
12
- 'Top-level nav bar where some items open a flyout panel. Desktop-oriented by design — a hover-triggered flyout bar has no mobile equivalent. Once one flyout is open, hovering a sibling switches directly to it; ArrowLeft/ArrowRight move focus between triggers.',
13
- },
14
- },
15
- },
16
- args: { 'aria-label': 'Main' },
17
- } satisfies Meta<typeof NavigationMenu>;
18
-
19
- export default meta;
20
- type Story = StoryObj<typeof meta>;
21
-
22
- // ---------------------------------------------------------------------------
23
-
24
- const FlyoutContent = ({ links }: { links: string[] }) => (
25
- <div style={{ padding: 'var(--sv-space-3)', display: 'flex', flexDirection: 'column', gap: 4 }}>
26
- {links.map((link) => (
27
- <a
28
- key={link}
29
- href={`/${link.toLowerCase().replace(/\s+/g, '-')}`}
30
- style={{
31
- fontSize: 14,
32
- color: 'var(--sv-color-text-primary)',
33
- textDecoration: 'none',
34
- padding: 'var(--sv-space-1) var(--sv-space-2)',
35
- }}
36
- >
37
- {link}
38
- </a>
39
- ))}
40
- </div>
41
- );
42
-
43
- export const Default: Story = {
44
- args: {
45
- items: [
46
- { label: 'Home', href: '/home' },
47
- {
48
- label: 'Products',
49
- content: <FlyoutContent links={['Tasks', 'Ledger', 'Shopper', 'Wallet']} />,
50
- },
51
- {
52
- label: 'Company',
53
- content: <FlyoutContent links={['About', 'Blog', 'Careers']} />,
54
- },
55
- { label: 'Docs', href: '/docs' },
56
- ],
57
- },
58
- };
@@ -1,125 +0,0 @@
1
- 'use client';
2
-
3
- import { useRef, useState } from 'react';
4
- import type { ReactNode, KeyboardEvent as ReactKeyboardEvent } from 'react';
5
- import { Popover } from '../Popover/Popover';
6
- import styles from './NavigationMenu.module.css';
7
-
8
- export interface NavigationMenuItem {
9
- label: string;
10
- /** A plain link with no flyout — mutually exclusive with `content`. */
11
- href?: string;
12
- /** Flyout panel content shown when this item is triggered. Pass a
13
- * function instead of a plain node when the content needs to close its
14
- * own flyout after an action (e.g. `Menubar`'s menu items) — it receives
15
- * a `close` callback. */
16
- content?: ReactNode | ((close: () => void) => ReactNode);
17
- }
18
-
19
- export interface NavigationMenuProps {
20
- items: NavigationMenuItem[];
21
- /** Renders a plain-link item's anchor. Defaults to `<a href>`, which
22
- * causes a full page reload — pass Next's `<Link>` (or equivalent) to
23
- * keep navigation client-side. */
24
- renderLink?: (href: string, children: ReactNode) => ReactNode;
25
- 'aria-label'?: string;
26
- }
27
-
28
- /**
29
- * NavigationMenu — top-level nav bar where some items open a flyout panel.
30
- *
31
- * Desktop-oriented by design — a hover-triggered flyout bar has no mobile
32
- * equivalent (Research 0004); it renders as-is on touch rather than
33
- * attempting a redesign no consumer has asked for yet.
34
- *
35
- * Each flyout is its own `Popover` instance rather than one shared
36
- * positioned panel, reusing its collision detection per item. Once one
37
- * flyout is open, moving the pointer to a sibling trigger switches directly
38
- * to that one — standard menu-bar behavior — and ArrowLeft/ArrowRight move
39
- * focus between top-level triggers (a roving-tabindex bar, per the
40
- * WAI-ARIA menu pattern), Escape closes.
41
- */
42
- export function NavigationMenu({
43
- items,
44
- renderLink,
45
- 'aria-label': ariaLabel,
46
- }: NavigationMenuProps) {
47
- const [openIndex, setOpenIndex] = useState<number | null>(null);
48
- const triggerRefs = useRef<(HTMLButtonElement | null)[]>([]);
49
-
50
- function handleKeyDown(e: ReactKeyboardEvent, index: number) {
51
- if (e.key === 'Escape') {
52
- setOpenIndex(null);
53
- triggerRefs.current[index]?.focus();
54
- return;
55
- }
56
- if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
57
- e.preventDefault();
58
- const direction = e.key === 'ArrowRight' ? 1 : -1;
59
- const nextIndex = (index + direction + items.length) % items.length;
60
- triggerRefs.current[nextIndex]?.focus();
61
- }
62
- }
63
-
64
- return (
65
- <nav aria-label={ariaLabel} className={styles.nav}>
66
- <ul className={styles.list}>
67
- {items.map((item, index) => {
68
- if (!item.content) {
69
- const linkChildren = item.label;
70
- return (
71
- <li key={item.label}>
72
- {item.href && renderLink ? (
73
- renderLink(item.href, linkChildren)
74
- ) : (
75
- <a href={item.href} className={styles.link}>
76
- {linkChildren}
77
- </a>
78
- )}
79
- </li>
80
- );
81
- }
82
-
83
- const isOpen = openIndex === index;
84
- return (
85
- <li key={item.label}>
86
- <Popover
87
- aria-label={item.label}
88
- open={isOpen}
89
- onClose={() => setOpenIndex((current) => (current === index ? null : current))}
90
- trigger={
91
- <button
92
- ref={(el) => {
93
- triggerRefs.current[index] = el;
94
- }}
95
- type="button"
96
- className={[styles.trigger, isOpen ? styles.triggerOpen : '']
97
- .filter(Boolean)
98
- .join(' ')}
99
- aria-expanded={isOpen}
100
- onClick={() => setOpenIndex((current) => (current === index ? null : index))}
101
- onMouseEnter={() => {
102
- // Once a sibling is already open, hovering another
103
- // trigger switches directly to it — standard menu-bar
104
- // behavior. Otherwise hovering alone does not open
105
- // one; that stays an explicit click, since a nav bar
106
- // (unlike HoverCard) isn't a "preview" surface.
107
- setOpenIndex((current) => (current !== null ? index : current));
108
- }}
109
- onKeyDown={(e) => handleKeyDown(e, index)}
110
- >
111
- {item.label}
112
- </button>
113
- }
114
- >
115
- {typeof item.content === 'function'
116
- ? item.content(() => setOpenIndex(null))
117
- : item.content}
118
- </Popover>
119
- </li>
120
- );
121
- })}
122
- </ul>
123
- </nav>
124
- );
125
- }
@@ -1,93 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import { cleanup, render, screen, fireEvent } from '@testing-library/react';
4
- import { NavigationMenu } from '../NavigationMenu';
5
-
6
- afterEach(cleanup);
7
-
8
- const items = [
9
- { label: 'Home', href: '/home' },
10
- { label: 'Products', content: <div>Products flyout</div> },
11
- { label: 'Company', content: <div>Company flyout</div> },
12
- ];
13
-
14
- describe('NavigationMenu', () => {
15
- it('renders a plain link for an item with no content', () => {
16
- render(<NavigationMenu items={items} aria-label="Main" />);
17
- const link = screen.getByRole('link', { name: 'Home' });
18
- expect(link.getAttribute('href')).toBe('/home');
19
- });
20
-
21
- it('renders a toggle trigger for an item with content, collapsed by default', () => {
22
- render(<NavigationMenu items={items} aria-label="Main" />);
23
- expect(screen.getByRole('button', { name: 'Products' }).getAttribute('aria-expanded')).toBe(
24
- 'false',
25
- );
26
- });
27
-
28
- it('opens a flyout on trigger click', () => {
29
- render(<NavigationMenu items={items} aria-label="Main" />);
30
- fireEvent.click(screen.getByRole('button', { name: 'Products' }));
31
- expect(screen.getByText('Products flyout')).toBeDefined();
32
- });
33
-
34
- it('closes on a second click of the same trigger', () => {
35
- render(<NavigationMenu items={items} aria-label="Main" />);
36
- const trigger = screen.getByRole('button', { name: 'Products' });
37
- fireEvent.click(trigger);
38
- fireEvent.click(trigger);
39
- expect(screen.queryByText('Products flyout')).toBeNull();
40
- });
41
-
42
- it('switches directly to a sibling on hover once one flyout is already open', () => {
43
- render(<NavigationMenu items={items} aria-label="Main" />);
44
- fireEvent.click(screen.getByRole('button', { name: 'Products' }));
45
- expect(screen.getByText('Products flyout')).toBeDefined();
46
-
47
- fireEvent.mouseEnter(screen.getByRole('button', { name: 'Company' }));
48
- expect(screen.getByText('Company flyout')).toBeDefined();
49
- expect(screen.queryByText('Products flyout')).toBeNull();
50
- });
51
-
52
- it('does not open a flyout on hover alone when nothing else is open', () => {
53
- render(<NavigationMenu items={items} aria-label="Main" />);
54
- fireEvent.mouseEnter(screen.getByRole('button', { name: 'Products' }));
55
- expect(screen.queryByText('Products flyout')).toBeNull();
56
- });
57
-
58
- it('ArrowRight/ArrowLeft move focus between top-level triggers', () => {
59
- render(<NavigationMenu items={items} aria-label="Main" />);
60
- const products = screen.getByRole('button', { name: 'Products' });
61
- const company = screen.getByRole('button', { name: 'Company' });
62
- products.focus();
63
- fireEvent.keyDown(products, { key: 'ArrowRight' });
64
- expect(document.activeElement).toBe(company);
65
- fireEvent.keyDown(company, { key: 'ArrowLeft' });
66
- expect(document.activeElement).toBe(products);
67
- });
68
-
69
- it('Escape closes the open flyout and returns focus to its trigger', () => {
70
- render(<NavigationMenu items={items} aria-label="Main" />);
71
- const trigger = screen.getByRole('button', { name: 'Products' });
72
- fireEvent.click(trigger);
73
- fireEvent.keyDown(trigger, { key: 'Escape' });
74
- expect(screen.queryByText('Products flyout')).toBeNull();
75
- expect(document.activeElement).toBe(trigger);
76
- });
77
-
78
- it('uses a caller-supplied renderLink for plain links instead of a bare <a>', () => {
79
- render(
80
- <NavigationMenu
81
- items={items}
82
- aria-label="Main"
83
- renderLink={(href, children) => (
84
- <button type="button" data-href={href}>
85
- {children}
86
- </button>
87
- )}
88
- />,
89
- );
90
- expect(screen.queryByRole('link', { name: 'Home' })).toBeNull();
91
- expect(screen.getByRole('button', { name: 'Home' })).toHaveProperty('dataset.href', '/home');
92
- });
93
- });
@@ -1,44 +0,0 @@
1
- 'use client';
2
-
3
- import type { ReactNode } from 'react';
4
- import { useIsOffline } from '../../hooks/useIsOffline';
5
- import { EmptyState } from '../EmptyState/EmptyState';
6
-
7
- export interface OfflineGateProps {
8
- children: ReactNode;
9
- /** Defaults to a generic "this section" phrasing — pass the surface's own name. */
10
- surfaceName?: string;
11
- className?: string;
12
- }
13
-
14
- /**
15
- * OfflineGate — blocks administrative/settings surfaces from rendering
16
- * (possibly stale) cached content while the device has no network, showing an
17
- * explanatory empty state instead (research 0012, epic task 2.32).
18
- *
19
- * Distinct from `OfflineBanner`: the banner is an informational overlay that
20
- * coexists with normal content everywhere in the shell. This is a hard block
21
- * for surfaces where operating against stale data is actively wrong — e.g. a
22
- * Console user list or an Account billing page reflects a point-in-time
23
- * snapshot the moment it's server-rendered, and any cached copy replayed
24
- * later has no way to signal that it may already be stale. `OfflineGate`
25
- * doesn't try to tell staleness apart from freshness; it removes the
26
- * question by not rendering the content at all while offline.
27
- *
28
- * `children` is rendered unconditionally while online, so this adds no cost
29
- * to the common case — it only decides what to show, never how the wrapped
30
- * content itself is fetched or cached.
31
- */
32
- export function OfflineGate({ children, surfaceName, className }: OfflineGateProps) {
33
- const isOffline = useIsOffline();
34
- if (!isOffline) return <>{children}</>;
35
-
36
- return (
37
- <EmptyState
38
- icon="alert-triangle"
39
- heading="You're offline"
40
- description={`${surfaceName ?? 'This section'} needs a connection — reconnect to continue.`}
41
- className={className}
42
- />
43
- );
44
- }
@@ -1,66 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { act, cleanup, render, screen } from '@testing-library/react';
4
- import { OfflineGate } from '../OfflineGate';
5
-
6
- describe('OfflineGate', () => {
7
- beforeEach(() => {
8
- vi.stubGlobal('navigator', { ...window.navigator, onLine: true });
9
- });
10
- afterEach(() => {
11
- vi.unstubAllGlobals();
12
- cleanup();
13
- });
14
-
15
- it('renders children unchanged while online', () => {
16
- render(
17
- <OfflineGate>
18
- <p>Live content</p>
19
- </OfflineGate>,
20
- );
21
- expect(screen.getByText('Live content')).toBeDefined();
22
- });
23
-
24
- it('replaces children with an explanatory empty state while offline', () => {
25
- vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
26
- render(
27
- <OfflineGate>
28
- <p>Live content</p>
29
- </OfflineGate>,
30
- );
31
- expect(screen.queryByText('Live content')).toBeNull();
32
- expect(screen.getByText("You're offline")).toBeDefined();
33
- });
34
-
35
- it('names the surface in the offline message when provided', () => {
36
- vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
37
- render(
38
- <OfflineGate surfaceName="Console">
39
- <p>Live content</p>
40
- </OfflineGate>,
41
- );
42
- expect(screen.getByText(/Console needs a connection/)).toBeDefined();
43
- });
44
-
45
- it('falls back to generic phrasing with no surface name', () => {
46
- vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
47
- render(
48
- <OfflineGate>
49
- <p>Live content</p>
50
- </OfflineGate>,
51
- );
52
- expect(screen.getByText(/This section needs a connection/)).toBeDefined();
53
- });
54
-
55
- it('swaps back to children on reconnect', () => {
56
- vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
57
- render(
58
- <OfflineGate>
59
- <p>Live content</p>
60
- </OfflineGate>,
61
- );
62
- expect(screen.getByText("You're offline")).toBeDefined();
63
- act(() => window.dispatchEvent(new Event('online')));
64
- expect(screen.getByText('Live content')).toBeDefined();
65
- });
66
- });
@@ -1,98 +0,0 @@
1
- /* OverlayHeader — shared fixed secondary header for Dialog's mobile mode,
2
- * Sheet, and Drawer. Not itself pinned via position — the consumer renders it
3
- * as a flex-shrink: 0 sibling before its own scrolling content region (see
4
- * the component's own doc comment). */
5
-
6
- .header {
7
- flex-shrink: 0;
8
- background: var(--sv-color-surface);
9
- border-bottom: 1px solid var(--sv-color-border);
10
- }
11
-
12
- .row {
13
- display: flex;
14
- align-items: center;
15
- gap: var(--sv-space-2);
16
- padding: var(--sv-space-3) var(--sv-space-4);
17
- }
18
-
19
- .backButton {
20
- display: inline-flex;
21
- align-items: center;
22
- justify-content: center;
23
- width: var(--sv-touch-target-min, 44px);
24
- height: var(--sv-touch-target-min, 44px);
25
- flex-shrink: 0;
26
- /* Pull the touch-target padding back so the chevron glyph still sits close
27
- to the title, matching the visual (not hit-area) spacing of .row's own
28
- gap — otherwise a 44px box reads as a large empty gap before the title. */
29
- margin-left: calc(-1 * (var(--sv-touch-target-min, 44px) - var(--sv-icon-size-md)) / 2);
30
- margin-right: calc(
31
- -1 * (var(--sv-touch-target-min, 44px) - var(--sv-icon-size-md)) / 2 + var(--sv-space-1)
32
- );
33
- border: none;
34
- border-radius: var(--sv-radius-md);
35
- background: transparent;
36
- color: var(--sv-color-text-muted);
37
- cursor: pointer;
38
- }
39
-
40
- @media (hover: hover) {
41
- .backButton:hover {
42
- background: var(--sv-color-surface-sunken);
43
- color: var(--sv-color-text-primary);
44
- }
45
- }
46
-
47
- .backButton:focus-visible {
48
- outline: 2px solid var(--sv-color-focus-ring);
49
- outline-offset: -2px;
50
- }
51
-
52
- .title {
53
- flex: 1;
54
- min-width: 0;
55
- overflow: hidden;
56
- text-overflow: ellipsis;
57
- white-space: nowrap;
58
- font-size: var(--sv-font-size-xl);
59
- font-weight: var(--sv-font-weight-semibold);
60
- color: var(--sv-color-text-primary);
61
- }
62
-
63
- .action {
64
- flex-shrink: 0;
65
- }
66
-
67
- .closeButton {
68
- display: inline-flex;
69
- align-items: center;
70
- justify-content: center;
71
- width: var(--sv-touch-target-min, 44px);
72
- height: var(--sv-touch-target-min, 44px);
73
- flex-shrink: 0;
74
- /* Pull the touch-target padding back so the × sits flush with the row's own
75
- edge padding, same reasoning as .backButton above. */
76
- margin-right: calc(-1 * (var(--sv-touch-target-min, 44px) - var(--sv-icon-size-sm)) / 2);
77
- border: none;
78
- border-radius: var(--sv-radius-md);
79
- background: transparent;
80
- color: var(--sv-color-text-muted);
81
- cursor: pointer;
82
- }
83
-
84
- @media (hover: hover) {
85
- .closeButton:hover {
86
- background: var(--sv-color-surface-sunken);
87
- color: var(--sv-color-text-primary);
88
- }
89
- }
90
-
91
- .closeButton:focus-visible {
92
- outline: 2px solid var(--sv-color-focus-ring);
93
- outline-offset: -2px;
94
- }
95
-
96
- .secondRow {
97
- padding: 0 var(--sv-space-2) var(--sv-space-2);
98
- }
@@ -1,62 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import { Icon } from '../Icon/Icon';
3
- import styles from './OverlayHeader.module.css';
4
-
5
- export interface OverlayHeaderProps {
6
- /** Overlay title, shown between the optional back button and the trailing
7
- * slots. Optional — some consumers (e.g. `Dialog`'s mobile bar) need the
8
- * row's close button present even when no title applies. */
9
- title?: string;
10
- /** Always renders a close button; called on click. */
11
- onClose: () => void;
12
- /** When provided, renders a back-chevron button before the title (for
13
- * hierarchical navigation within a single overlay — going back without
14
- * fully closing it). Omit for a flat overlay that only ever closes. */
15
- onBack?: () => void;
16
- /** Trailing slot next to the close button — e.g. a "Save" action. */
17
- action?: ReactNode;
18
- /** A second row below the title row — e.g. a tab strip. */
19
- secondRow?: ReactNode;
20
- className?: string;
21
- }
22
-
23
- /**
24
- * OverlayHeader — the shared fixed secondary header for `Dialog`'s mobile
25
- * mode, `Sheet`, and `Drawer`: title + close (+ optional back button /
26
- * trailing action / tab-strip row). Not itself `position: sticky` or
27
- * `position: fixed` — it stays visually pinned because the consuming overlay
28
- * renders it as a non-scrolling flex sibling before its own scrollable
29
- * content region, the same technique `Dialog`'s `.mobileBar` already used
30
- * before this component existed to generalize it.
31
- *
32
- * Content that needs a fully custom header (e.g. an editable title, or
33
- * controls that aren't a simple title/back/action shape) should not use this
34
- * component — render its own header row instead; `Sheet`'s `title` prop is
35
- * optional specifically to leave that escape hatch open.
36
- */
37
- export function OverlayHeader({
38
- title,
39
- onClose,
40
- onBack,
41
- action,
42
- secondRow,
43
- className,
44
- }: OverlayHeaderProps) {
45
- return (
46
- <div className={[styles.header, className].filter(Boolean).join(' ')}>
47
- <div className={styles.row}>
48
- {onBack && (
49
- <button type="button" className={styles.backButton} aria-label="Back" onClick={onBack}>
50
- <Icon name="chevron-left" size="md" aria-hidden />
51
- </button>
52
- )}
53
- <span className={styles.title}>{title}</span>
54
- {action && <div className={styles.action}>{action}</div>}
55
- <button type="button" className={styles.closeButton} aria-label="Close" onClick={onClose}>
56
- <Icon name="x" size="sm" aria-hidden />
57
- </button>
58
- </div>
59
- {secondRow && <div className={styles.secondRow}>{secondRow}</div>}
60
- </div>
61
- );
62
- }
@@ -1,51 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, describe, expect, it, vi } from 'vitest';
3
- import { cleanup, fireEvent, render, screen } from '@testing-library/react';
4
- import { OverlayHeader } from '../OverlayHeader';
5
-
6
- describe('OverlayHeader', () => {
7
- afterEach(cleanup);
8
-
9
- it('renders the title and calls onClose on the close button', () => {
10
- const onClose = vi.fn();
11
- render(<OverlayHeader title="Account" onClose={onClose} />);
12
- expect(screen.getByText('Account')).toBeTruthy();
13
- fireEvent.click(screen.getByRole('button', { name: 'Close' }));
14
- expect(onClose).toHaveBeenCalledOnce();
15
- });
16
-
17
- it('does not render a back button when onBack is omitted', () => {
18
- render(<OverlayHeader title="Account" onClose={() => {}} />);
19
- expect(screen.queryByRole('button', { name: 'Back' })).toBeNull();
20
- });
21
-
22
- it('renders and wires a back button when onBack is provided', () => {
23
- const onBack = vi.fn();
24
- render(<OverlayHeader title="Account" onClose={() => {}} onBack={onBack} />);
25
- fireEvent.click(screen.getByRole('button', { name: 'Back' }));
26
- expect(onBack).toHaveBeenCalledOnce();
27
- });
28
-
29
- it('renders the trailing action slot', () => {
30
- render(
31
- <OverlayHeader
32
- title="Edit list"
33
- onClose={() => {}}
34
- action={<button type="button">Save</button>}
35
- />,
36
- );
37
- expect(screen.getByRole('button', { name: 'Save' })).toBeTruthy();
38
- });
39
-
40
- it('renders just the close button when title is omitted', () => {
41
- const onClose = vi.fn();
42
- render(<OverlayHeader onClose={onClose} />);
43
- fireEvent.click(screen.getByRole('button', { name: 'Close' }));
44
- expect(onClose).toHaveBeenCalledOnce();
45
- });
46
-
47
- it('renders the second row', () => {
48
- render(<OverlayHeader title="Account" onClose={() => {}} secondRow={<nav>Tab strip</nav>} />);
49
- expect(screen.getByText('Tab strip')).toBeTruthy();
50
- });
51
- });
@@ -1,20 +0,0 @@
1
- .container {
2
- width: 100%;
3
- margin-inline: auto;
4
- }
5
-
6
- .sm {
7
- max-width: 640px;
8
- }
9
-
10
- .md {
11
- max-width: 960px;
12
- }
13
-
14
- .lg {
15
- max-width: 1200px;
16
- }
17
-
18
- .full {
19
- max-width: none;
20
- }