@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,160 +0,0 @@
1
- 'use client';
2
-
3
- import { createContext, type ReactNode, useContext, useEffect, useRef, useState } from 'react';
4
- import { useMountTransition, usePrefersReducedMotion } from '../../motion';
5
- import {
6
- useOverlayFocusCapture,
7
- useOverlayKeyboardTrap,
8
- useOverlayScrollLock,
9
- } from '../../overlay-shell';
10
- import { OverlayHeader } from '../OverlayHeader/OverlayHeader';
11
- import styles from './Dialog.module.css';
12
-
13
- // Matches --sv-motion-duration-base (Dialog.module.css) — kept as a plain JS
14
- // constant rather than read from the CSS custom property so the unmount timer
15
- // and the CSS transition duration can't silently drift apart at build time;
16
- // change both together if this value ever changes.
17
- const MOTION_DURATION_MS = 250;
18
-
19
- // undefined (the default, outside any Provider) means "no Dialog ancestor" —
20
- // distinct from a real setter function, so useOverlaySecondRow can silently
21
- // no-op when called outside a Dialog instead of throwing.
22
- const OverlaySecondRowContext = createContext<((node: ReactNode | null) => void) | undefined>(
23
- undefined,
24
- );
25
-
26
- /**
27
- * Lets content deep inside a `Dialog` (e.g. a plugin's own route layout,
28
- * rendered several levels below wherever the `Dialog` itself is
29
- * instantiated) supply the second-row content of the Dialog's mobile
30
- * `OverlayHeader` — typically a tab strip. Solves the "double header"
31
- * problem: without this, a plugin's own tab strip has no way to reach the
32
- * Dialog's header and ends up rendered a second time, as its own sticky bar,
33
- * inside the scrolling content area.
34
- *
35
- * A no-op when there is no enclosing `Dialog` (e.g. the same plugin layout
36
- * also rendered on a plain, non-overlay route) — safe to call unconditionally.
37
- * Returns whether an enclosing `Dialog` actually received the content, so a
38
- * caller that also renders its own inline header/tab-strip copy for the
39
- * no-Dialog case can hide that copy on mobile specifically when this
40
- * returned `true` (the Dialog's own header is showing it instead there).
41
- *
42
- * ```tsx
43
- * function AccountLayout({ children }) {
44
- * const insideOverlay = useOverlaySecondRow(<nav>...tab strip...</nav>);
45
- * return <div>{children}</div>;
46
- * }
47
- * ```
48
- */
49
- export function useOverlaySecondRow(node: ReactNode | null): boolean {
50
- const setSecondRow = useContext(OverlaySecondRowContext);
51
- useEffect(() => {
52
- if (!setSecondRow) return;
53
- setSecondRow(node);
54
- return () => setSecondRow(null);
55
- }, [setSecondRow, node]);
56
- return setSecondRow !== undefined;
57
- }
58
-
59
- export type DialogSize = 'sm' | 'md' | 'lg' | 'full';
60
-
61
- export interface DialogProps {
62
- /** Whether the dialog is shown. When false, nothing renders. */
63
- open: boolean;
64
- /** Called on Esc, scrim click, or the close button. */
65
- onClose: () => void;
66
- /** Panel size on desktop. Mobile always renders as a full-screen sheet. */
67
- size?: DialogSize;
68
- /** Accessible name for the dialog (sets `aria-label` on the panel). */
69
- 'aria-label'?: string;
70
- /** On mobile: shown in the top bar alongside the close button so the title
71
- * and dismiss affordance occupy the same row instead of stacking. */
72
- title?: string;
73
- children: ReactNode;
74
- }
75
-
76
- /**
77
- * Dialog — a modal surface (scrim + panel) for overlay-shell plugins and any
78
- * plugin that needs a dismissable layer. Router-agnostic: the caller decides
79
- * what `onClose` does (the runtime's `@modal` slot wires it to `router.back()`).
80
- *
81
- * Behaviour: Esc and scrim-click dismiss; focus moves into the panel on open and
82
- * is restored to the previously-focused element on close; Tab is trapped within
83
- * the panel. Styling references `--sv-*` tokens only; on mobile the panel becomes
84
- * a full-screen sheet regardless of `size`.
85
- *
86
- * Animated open/close: fade + scale on desktop, slide-up on mobile (matching
87
- * the "feels like a page push" framing of the mobile sheet). The `open`/
88
- * `onClose` API is unchanged — closing still stays mounted internally for the
89
- * exit transition before actually unmounting; `prefers-reduced-motion: reduce`
90
- * collapses both to near-instant.
91
- */
92
- export function Dialog({
93
- open,
94
- onClose,
95
- size = 'lg',
96
- 'aria-label': ariaLabel,
97
- title,
98
- children,
99
- }: DialogProps) {
100
- const panelRef = useRef<HTMLDivElement>(null);
101
- const reducedMotion = usePrefersReducedMotion();
102
- const { mounted, phase } = useMountTransition(open, reducedMotion ? 0 : MOTION_DURATION_MS);
103
- const [secondRow, setSecondRow] = useState<ReactNode | null>(null);
104
-
105
- useOverlayScrollLock(mounted);
106
- useOverlayFocusCapture(panelRef, open);
107
- useOverlayKeyboardTrap(panelRef, open, onClose);
108
-
109
- if (!mounted) return null;
110
- const isOpenPhase = phase === 'open';
111
-
112
- return (
113
- // role="presentation" removes the scrim from the AT (it is purely visual).
114
- // e.target check lets clicks inside the panel bubble without triggering dismiss.
115
- <div
116
- className={[styles.scrim, isOpenPhase ? styles.scrimOpen : ''].filter(Boolean).join(' ')}
117
- role="presentation"
118
- onClick={(e) => {
119
- if (e.target === e.currentTarget) onClose();
120
- }}
121
- onKeyDown={(e) => {
122
- if (e.key === 'Escape') onClose();
123
- }}
124
- >
125
- <div
126
- ref={panelRef}
127
- role="dialog"
128
- aria-modal="true"
129
- aria-label={ariaLabel ?? title}
130
- tabIndex={-1}
131
- className={[styles.panel, styles[size], isOpenPhase ? styles.panelOpen : '']
132
- .filter(Boolean)
133
- .join(' ')}
134
- >
135
- {/* Mobile: shared OverlayHeader (title + close in one row, hidden on
136
- desktop via CSS — see .mobileHeader). secondRow is populated by a
137
- descendant's useOverlaySecondRow call, e.g. a plugin's own tab
138
- strip — see that hook's doc comment for why. */}
139
- <OverlayHeader
140
- title={title}
141
- onClose={onClose}
142
- secondRow={secondRow}
143
- className={styles.mobileHeader}
144
- />
145
- {/* Desktop: absolute close button (hidden on mobile via CSS). */}
146
- <button type="button" className={styles.close} aria-label="Close" onClick={onClose}>
147
- ×
148
- </button>
149
- {/* The panel is a fixed-size box; only this region scrolls, so the
150
- panel never resizes with its content and the close button stays
151
- pinned. */}
152
- <div className={styles.content}>
153
- <OverlaySecondRowContext.Provider value={setSecondRow}>
154
- {children}
155
- </OverlaySecondRowContext.Provider>
156
- </div>
157
- </div>
158
- </div>
159
- );
160
- }
@@ -1,137 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { cleanup, fireEvent, render, screen } from '@testing-library/react';
4
- import { Dialog, useOverlaySecondRow } from '../Dialog';
5
-
6
- // Dialog's exit animation reads prefers-reduced-motion via matchMedia, which
7
- // jsdom does not implement. `matches: false` (motion enabled) exercises the
8
- // normal animated path; the actual reduced-motion behaviour is covered by
9
- // motion.ts's own tests.
10
- function installMatchMedia() {
11
- vi.stubGlobal(
12
- 'matchMedia',
13
- vi.fn().mockImplementation((query: string) => ({
14
- matches: false,
15
- media: query,
16
- addEventListener: vi.fn(),
17
- removeEventListener: vi.fn(),
18
- addListener: vi.fn(),
19
- removeListener: vi.fn(),
20
- dispatchEvent: vi.fn(),
21
- })),
22
- );
23
- }
24
-
25
- describe('Dialog', () => {
26
- beforeEach(installMatchMedia);
27
- afterEach(() => {
28
- vi.unstubAllGlobals();
29
- cleanup();
30
- });
31
-
32
- it('renders nothing when closed', () => {
33
- render(
34
- <Dialog open={false} onClose={() => {}}>
35
- Body
36
- </Dialog>,
37
- );
38
- expect(screen.queryByRole('dialog')).toBeNull();
39
- });
40
-
41
- it('renders the panel with its accessible name when open', () => {
42
- render(
43
- <Dialog open onClose={() => {}} aria-label="Settings">
44
- Body
45
- </Dialog>,
46
- );
47
- const dialog = screen.getByRole('dialog', { name: 'Settings' });
48
- expect(dialog.getAttribute('aria-modal')).toBe('true');
49
- });
50
-
51
- it('calls onClose on Escape', () => {
52
- const onClose = vi.fn();
53
- render(
54
- <Dialog open onClose={onClose}>
55
- Body
56
- </Dialog>,
57
- );
58
- // Keyboard handler is registered on document (not the dialog element) so
59
- // screen readers and keyboard users can dismiss from anywhere in the page.
60
- fireEvent.keyDown(document, { key: 'Escape' });
61
- expect(onClose).toHaveBeenCalledOnce();
62
- });
63
-
64
- it('calls onClose on scrim click but not on panel click', () => {
65
- const onClose = vi.fn();
66
- render(
67
- <Dialog open onClose={onClose} aria-label="Panel">
68
- Body
69
- </Dialog>,
70
- );
71
- fireEvent.click(screen.getByRole('dialog')); // panel — should not close
72
- expect(onClose).not.toHaveBeenCalled();
73
- const closeButtons = screen.getAllByRole('button', { name: 'Close' });
74
- expect(closeButtons.length).toBeGreaterThan(0);
75
- fireEvent.click(closeButtons[0] as HTMLElement);
76
- expect(onClose).toHaveBeenCalledOnce();
77
- });
78
-
79
- it('applies the size class', () => {
80
- render(
81
- <Dialog open onClose={() => {}} size="full" aria-label="Big">
82
- Body
83
- </Dialog>,
84
- );
85
- expect(screen.getByRole('dialog').className).toContain('full');
86
- });
87
-
88
- it('supports the sm size', () => {
89
- render(
90
- <Dialog open onClose={() => {}} size="sm" aria-label="Small">
91
- Body
92
- </Dialog>,
93
- );
94
- expect(screen.getByRole('dialog').className).toContain('sm');
95
- });
96
-
97
- it('renders a descendant-supplied secondRow via useOverlaySecondRow', () => {
98
- function TabStrip() {
99
- useOverlaySecondRow(<nav>Tab strip</nav>);
100
- return null;
101
- }
102
- render(
103
- <Dialog open onClose={() => {}} title="Account" aria-label="Account">
104
- <TabStrip />
105
- </Dialog>,
106
- );
107
- expect(screen.getByText('Tab strip')).toBeTruthy();
108
- });
109
-
110
- it('removes the secondRow when the supplying descendant unmounts', () => {
111
- function TabStrip() {
112
- useOverlaySecondRow(<nav>Tab strip</nav>);
113
- return null;
114
- }
115
- function Harness({ showTabs }: { showTabs: boolean }) {
116
- return (
117
- <Dialog open onClose={() => {}} title="Account" aria-label="Account">
118
- {showTabs && <TabStrip />}
119
- </Dialog>
120
- );
121
- }
122
- const { rerender } = render(<Harness showTabs />);
123
- expect(screen.getByText('Tab strip')).toBeTruthy();
124
- rerender(<Harness showTabs={false} />);
125
- expect(screen.queryByText('Tab strip')).toBeNull();
126
- });
127
-
128
- it('is a no-op when called outside a Dialog', () => {
129
- function Standalone() {
130
- useOverlaySecondRow(<nav>Tab strip</nav>);
131
- return <span>Standalone content</span>;
132
- }
133
- render(<Standalone />);
134
- expect(screen.getByText('Standalone content')).toBeTruthy();
135
- expect(screen.queryByText('Tab strip')).toBeNull();
136
- });
137
- });
@@ -1,57 +0,0 @@
1
- .row {
2
- display: flex;
3
- align-items: flex-start;
4
- gap: var(--sv-space-1);
5
- position: relative;
6
- }
7
-
8
- /* Hover-reveal only where hover genuinely exists — on touch the handle would
9
- otherwise never become visible (tap-generated hover doesn't count as a
10
- sustained hover state, and :not(:hover) is always true with no hover
11
- capability at all), so it stays visible by default there. */
12
- @media (hover: hover) {
13
- .row:not(:hover) .handle,
14
- .row:not(:focus-within) .handle {
15
- opacity: 0;
16
- }
17
- }
18
-
19
- .handle {
20
- flex-shrink: 0;
21
- display: flex;
22
- align-items: center;
23
- justify-content: center;
24
- width: 24px;
25
- height: 24px;
26
- margin-top: 2px;
27
- border: none;
28
- background: none;
29
- padding: 0;
30
- border-radius: var(--sv-radius-sm);
31
- color: var(--sv-color-text-muted);
32
- cursor: grab;
33
- opacity: 1;
34
- transition: opacity 0.1s ease;
35
- }
36
-
37
- .handle:focus-visible {
38
- outline: 2px solid var(--sv-color-focus-ring);
39
- outline-offset: 2px;
40
- }
41
-
42
- .handle:active {
43
- cursor: grabbing;
44
- }
45
-
46
- .icon {
47
- pointer-events: none;
48
- }
49
-
50
- .content {
51
- flex: 1;
52
- min-width: 0;
53
- }
54
-
55
- .dragging {
56
- opacity: 0.5;
57
- }
@@ -1,61 +0,0 @@
1
- import type { HTMLAttributes, ReactNode } from 'react';
2
- import styles from './DragHandleRow.module.css';
3
-
4
- export interface DragHandleRowProps extends HTMLAttributes<HTMLDivElement> {
5
- children: ReactNode;
6
- /** Pass drag-listener and drag-control props from dnd-kit here. */
7
- handleProps?: HTMLAttributes<HTMLButtonElement>;
8
- isDragging?: boolean;
9
- }
10
-
11
- /**
12
- * A row wrapper that surfaces a drag handle on the left.
13
- * Consumers attach dnd-kit's useSortable listeners to `handleProps`.
14
- */
15
- export function DragHandleRow({
16
- children,
17
- handleProps,
18
- isDragging,
19
- className,
20
- ...rest
21
- }: DragHandleRowProps) {
22
- return (
23
- <div
24
- {...rest}
25
- className={[styles.row, isDragging ? styles.dragging : '', className]
26
- .filter(Boolean)
27
- .join(' ')}
28
- >
29
- <button
30
- type="button"
31
- aria-label="Drag to reorder"
32
- className={styles.handle}
33
- tabIndex={-1}
34
- {...handleProps}
35
- >
36
- <DragIcon />
37
- </button>
38
- <div className={styles.content}>{children}</div>
39
- </div>
40
- );
41
- }
42
-
43
- function DragIcon() {
44
- return (
45
- <svg
46
- width="14"
47
- height="14"
48
- viewBox="0 0 14 14"
49
- fill="none"
50
- aria-hidden="true"
51
- className={styles.icon}
52
- >
53
- {/* Two columns of three dots */}
54
- {[3, 7, 11].map((cy) =>
55
- [4, 10].map((cx) => (
56
- <circle key={`${cx}-${cy}`} cx={cx} cy={cy} r={1.2} fill="currentColor" />
57
- )),
58
- )}
59
- </svg>
60
- );
61
- }
@@ -1,92 +0,0 @@
1
- /* Drawer — bottom-sheet surface (RFC 0013). Shares scrim/shadow tokens with
2
- * Dialog but slides up from the bottom instead of centering. The panel has no
3
- * fixed height — it sizes to content, capped at 80dvh so some page context
4
- * remains visible above. Safe-area-aware: bottom padding clears the home
5
- * indicator in standalone/fullscreen mode. */
6
-
7
- .scrim {
8
- position: fixed;
9
- inset: 0;
10
- /* When the shell declares --sv-shell-footer-height (mobile nav bar), stop the
11
- scrim above the footer so the panel never hides behind it. */
12
- bottom: var(--sv-shell-footer-height, 0);
13
- z-index: 100;
14
- display: flex;
15
- align-items: flex-end;
16
- background: var(--sv-color-scrim);
17
- /* Entrance/exit fade — same two-phase-mount pattern as Dialog (see motion.ts
18
- and Drawer.tsx). */
19
- opacity: 0;
20
- transition: opacity var(--sv-motion-duration-base) var(--sv-motion-ease-out);
21
- }
22
-
23
- .scrimOpen {
24
- opacity: 1;
25
- }
26
-
27
- .panel {
28
- width: 100%;
29
- max-height: 80dvh;
30
- overflow-y: auto;
31
- overscroll-behavior: contain;
32
- background: var(--sv-color-surface-raised);
33
- border-top: 1px solid var(--sv-color-border);
34
- border-radius: var(--sv-radius-3xl) var(--sv-radius-3xl) 0 0;
35
- box-shadow: var(--sv-shadow-overlay);
36
- /* Pull content above the home indicator / bottom bar in standalone mode. */
37
- padding-bottom: env(safe-area-inset-bottom);
38
- outline: none;
39
- /* Slide up from below the viewport. Always a bottom sheet, so unlike Dialog
40
- there's no desktop-vs-mobile fork here. */
41
- transform: translateY(100%);
42
- transition: transform var(--sv-motion-duration-base) var(--sv-motion-ease-out);
43
- }
44
-
45
- .panelOpen {
46
- transform: translateY(0);
47
- }
48
-
49
- /* 'half' snapHeight — a fixed height instead of the default content-sized cap
50
- * above. Per the design-system's "half screen or less" convention for
51
- * Drawer; content taller than this belongs in Sheet instead. */
52
- .panelHalf {
53
- height: 50dvh;
54
- max-height: 50dvh;
55
- }
56
-
57
- /* See Dialog.module.css's identical rule for why 0.01ms rather than 0. */
58
- @media (prefers-reduced-motion: reduce) {
59
- .scrim,
60
- .panel {
61
- transition-duration: 0.01ms;
62
- }
63
- }
64
-
65
- /* Grab handle — the sole drag-initiation region for swipe-down-to-dismiss
66
- * (see Drawer.tsx's doc comment for why not the whole panel). The visual bar
67
- * (::before) stays the small, established 36x4px size; only the hit area
68
- * grows to a comfortable touch target. */
69
- .handle {
70
- display: flex;
71
- align-items: center;
72
- justify-content: center;
73
- width: 100%;
74
- height: var(--sv-touch-target-min, 44px);
75
- flex-shrink: 0;
76
- cursor: grab;
77
- /* JS-driven drag — the browser must not treat a press here as a
78
- scroll/pan gesture that would fight it. */
79
- touch-action: none;
80
- }
81
-
82
- .handle:active {
83
- cursor: grabbing;
84
- }
85
-
86
- .handle::before {
87
- content: '';
88
- width: 36px;
89
- height: 4px;
90
- border-radius: var(--sv-radius-full);
91
- background: var(--sv-color-border-strong);
92
- }
@@ -1,132 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { expect, userEvent, within } from 'storybook/test';
3
- import { useState } from 'react';
4
- import { Button } from '../Button/Button';
5
- import { Icon } from '../Icon/Icon';
6
- import { Drawer } from './Drawer';
7
-
8
- function DrawerDemo({ label = 'Navigation' }: { label?: string }) {
9
- const [open, setOpen] = useState(false);
10
- return (
11
- <>
12
- <Button onClick={() => setOpen(true)}>Open drawer</Button>
13
- <Drawer open={open} onClose={() => setOpen(false)} aria-label={label}>
14
- <ul style={{ listStyle: 'none', margin: 0, padding: '8px 0' }}>
15
- {(['house', 'grid-2x2', 'settings', 'user'] as const).map((icon) => (
16
- <li key={icon}>
17
- <button
18
- onClick={() => setOpen(false)}
19
- style={{
20
- display: 'flex',
21
- alignItems: 'center',
22
- gap: 12,
23
- width: '100%',
24
- padding: '12px 20px',
25
- background: 'none',
26
- border: 'none',
27
- cursor: 'pointer',
28
- fontSize: 15,
29
- color: 'var(--sv-color-text-primary)',
30
- fontFamily: 'system-ui',
31
- }}
32
- >
33
- <Icon name={icon} size="md" aria-hidden />
34
- {icon.replace(/-/g, ' ')}
35
- </button>
36
- </li>
37
- ))}
38
- </ul>
39
- </Drawer>
40
- </>
41
- );
42
- }
43
-
44
- const meta = {
45
- title: 'Components/Drawer',
46
- component: Drawer,
47
- parameters: {
48
- layout: 'centered',
49
- docs: {
50
- description: {
51
- component:
52
- 'Dismissable bottom-sheet panel. Used by the mobile shell for plugin navigation. Supports Esc, scrim-click, focus trap. Respects `env(safe-area-inset-bottom)`. Use the viewport addon at 375px to see the intended mobile context.',
53
- },
54
- },
55
- viewport: { defaultViewport: 'mobile' },
56
- },
57
- } satisfies Meta<typeof Drawer>;
58
-
59
- export default meta;
60
- type Story = StoryObj<typeof meta>;
61
-
62
- // ---------------------------------------------------------------------------
63
-
64
- export const Default: Story = {
65
- args: { open: false, onClose: () => {}, children: null },
66
- render: (_args) => <DrawerDemo />,
67
- };
68
-
69
- export const Closed: Story = {
70
- args: { open: false, onClose: () => {}, children: null },
71
- render: (_args) => (
72
- <Drawer open={false} onClose={() => {}} aria-label="Closed drawer">
73
- <p>Never seen</p>
74
- </Drawer>
75
- ),
76
- };
77
-
78
- function DrawerWithTitleDemo() {
79
- const [open, setOpen] = useState(false);
80
- return (
81
- <>
82
- <Button onClick={() => setOpen(true)}>Open drawer</Button>
83
- <Drawer open={open} onClose={() => setOpen(false)} title="Apps">
84
- <ul style={{ listStyle: 'none', margin: 0, padding: '8px 0' }}>
85
- {(['house', 'grid-2x2', 'settings', 'user'] as const).map((icon) => (
86
- <li key={icon}>
87
- <button
88
- onClick={() => setOpen(false)}
89
- style={{
90
- display: 'flex',
91
- alignItems: 'center',
92
- gap: 12,
93
- width: '100%',
94
- padding: '12px 20px',
95
- background: 'none',
96
- border: 'none',
97
- cursor: 'pointer',
98
- fontSize: 15,
99
- color: 'var(--sv-color-text-primary)',
100
- fontFamily: 'system-ui',
101
- }}
102
- >
103
- <Icon name={icon} size="md" aria-hidden />
104
- {icon.replace(/-/g, ' ')}
105
- </button>
106
- </li>
107
- ))}
108
- </ul>
109
- </Drawer>
110
- </>
111
- );
112
- }
113
-
114
- /** Opt-in `title` prop renders a built-in `OverlayHeader` (title + close)
115
- * below the grab handle — hidden by default (see the `Default` story), for
116
- * consumers that want one instead of building their own header markup. */
117
- export const WithTitle: Story = {
118
- args: { open: false, onClose: () => {}, children: null },
119
- render: (_args) => <DrawerWithTitleDemo />,
120
- };
121
-
122
- /** Play function opens the drawer and asserts its list items are visible. */
123
- export const OpenViaInteraction: Story = {
124
- args: { open: false, onClose: () => {}, children: null },
125
- render: (_args) => <DrawerDemo label="Navigation menu" />,
126
- play: async ({ canvasElement }) => {
127
- const canvas = within(canvasElement);
128
- await userEvent.click(canvas.getByRole('button', { name: /open drawer/i }));
129
- const drawer = canvas.getByRole('navigation');
130
- await expect(drawer).toBeVisible();
131
- },
132
- };