@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,59 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, describe, expect, it, vi } from 'vitest';
3
- import { cleanup, render, screen, fireEvent } from '@testing-library/react';
4
- import { Select } from '../Select';
5
-
6
- afterEach(cleanup);
7
-
8
- describe('Select', () => {
9
- it('renders a combobox', () => {
10
- render(
11
- <Select aria-label="Role">
12
- <option value="user">User</option>
13
- <option value="admin">Admin</option>
14
- </Select>,
15
- );
16
- expect(screen.getByRole('combobox', { name: 'Role' })).toBeDefined();
17
- });
18
-
19
- it('renders provided options', () => {
20
- render(
21
- <Select aria-label="Role">
22
- <option value="user">User</option>
23
- <option value="admin">Admin</option>
24
- <option value="owner">Owner</option>
25
- </Select>,
26
- );
27
- expect(screen.getAllByRole('option').length).toBe(3);
28
- });
29
-
30
- it('forwards value and onChange', () => {
31
- const onChange = vi.fn();
32
- render(
33
- <Select aria-label="Role" value="user" onChange={onChange}>
34
- <option value="user">User</option>
35
- <option value="admin">Admin</option>
36
- </Select>,
37
- );
38
- fireEvent.change(screen.getByRole('combobox'), { target: { value: 'admin' } });
39
- expect(onChange).toHaveBeenCalled();
40
- });
41
-
42
- it('is disabled when the disabled prop is set', () => {
43
- render(
44
- <Select aria-label="Role" disabled>
45
- <option value="user">User</option>
46
- </Select>,
47
- );
48
- expect((screen.getByRole('combobox') as HTMLSelectElement).disabled).toBe(true);
49
- });
50
-
51
- it('renders a decorative chevron element', () => {
52
- const { container } = render(
53
- <Select aria-label="Role">
54
- <option value="user">User</option>
55
- </Select>,
56
- );
57
- expect(container.querySelector('[aria-hidden]')).toBeDefined();
58
- });
59
- });
@@ -1,55 +0,0 @@
1
- /* Sheet — fills the same rect as a plugin's content area (between the shell's
2
- * sticky header and footer nav — see --sv-shell-header-height /
3
- * --sv-shell-footer-height, set by the shell), sliding in from an edge
4
- * instead of Dialog's centered box or Drawer's partial-height sheet-over-
5
- * scrim. z-index matches Dialog/Drawer's scrim so it layers consistently
6
- * with any other overlay. No scrim of its own — see the component doc
7
- * comment for why. */
8
-
9
- .panel {
10
- position: fixed;
11
- left: 0;
12
- right: 0;
13
- top: var(--sv-shell-header-height, 0);
14
- bottom: var(--sv-shell-footer-height, 0);
15
- z-index: 100;
16
- display: flex;
17
- flex-direction: column;
18
- background: var(--sv-color-surface);
19
- outline: none;
20
- transform: translateY(100%);
21
- transition: transform var(--sv-motion-duration-base) var(--sv-motion-ease-out);
22
- }
23
-
24
- .panelOpen {
25
- transform: translateY(0);
26
- }
27
-
28
- /* Opt-in top variant (slideFrom="top") — a short options/actions menu opened
29
- * from a header button reads more naturally sliding down from that button's
30
- * edge than traveling up from off-screen bottom. :not(.panelOpen) is what
31
- * lets this coexist with .panelOpen above despite equal-looking single-class
32
- * specificity elsewhere in this file: its (0,2,0) beats .panelOpen's (0,1,0)
33
- * while closed/entering/closing, and yields to it (transform: translateY(0),
34
- * same value either direction) once open. */
35
- .panelFromTop:not(.panelOpen) {
36
- transform: translateY(-100%);
37
- }
38
-
39
- /* See Dialog.module.css's identical rule for why 0.01ms rather than 0. */
40
- @media (prefers-reduced-motion: reduce) {
41
- .panel {
42
- transition-duration: 0.01ms;
43
- }
44
- }
45
-
46
- /* Always the scroll container, with or without OverlayHeader present (see
47
- * Sheet.tsx). No opinionated padding here — matches Drawer's convention of
48
- * leaving horizontal/top padding and safe-area-bottom clearance to the
49
- * content itself, since a Sheet's content shape varies far more than a
50
- * fixed-size Dialog's. */
51
- .content {
52
- flex: 1 1 auto;
53
- overflow-y: auto;
54
- overscroll-behavior: contain;
55
- }
@@ -1,109 +0,0 @@
1
- 'use client';
2
-
3
- import { type ReactNode, useRef } 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 './Sheet.module.css';
12
-
13
- export interface SheetProps {
14
- /** Whether the sheet is shown. When false, nothing renders. */
15
- open: boolean;
16
- /** Called on Esc, or the built-in `OverlayHeader`'s close button. There is
17
- * no scrim to tap — a Sheet replaces the content area it fills, not a
18
- * layer floating above it (see the component doc comment). */
19
- onClose: () => void;
20
- /** Accessible name for the sheet. Defaults to `title` when omitted. */
21
- 'aria-label'?: string;
22
- /** Renders a built-in `OverlayHeader` (title + close, optional back button
23
- * and trailing action). Omit when the content supplies its own header —
24
- * e.g. a form whose title doubles as an editable field. */
25
- title?: string;
26
- /** Forwarded to `OverlayHeader` — see its own `onBack` doc. Has no effect
27
- * without `title`. */
28
- onBack?: () => void;
29
- /** Forwarded to `OverlayHeader`'s trailing-action slot. Has no effect
30
- * without `title`. */
31
- headerAction?: ReactNode;
32
- /**
33
- * Which edge the panel slides in from. Defaults to `'bottom'` (detail
34
- * views, forms — content the user is reaching down into). `'top'` suits a
35
- * short options/actions menu opened from a header button near the top of
36
- * the screen, where sliding up from the bottom would travel past empty
37
- * space before reaching content that visually belongs near the trigger.
38
- */
39
- slideFrom?: 'bottom' | 'top';
40
- children: ReactNode;
41
- }
42
-
43
- // Matches --sv-motion-duration-base (Sheet.module.css) — see Dialog.tsx's
44
- // identical constant for why this stays a plain JS number.
45
- const MOTION_DURATION_MS = 250;
46
-
47
- /**
48
- * Sheet — a full-page overlay that replaces a plugin's content area between
49
- * the shell's fixed header and footer (RFC 0013's mobile chrome stays visible
50
- * and interactive around it), sliding in from an edge instead of centering
51
- * like `Dialog`. Promoted from the tasks plugin's `MobileFullPageOverlay`
52
- * (now the reference pattern for this component). Desktop has no equivalent
53
- * presentation — a desktop layout shows the same content inline (columns,
54
- * panes) instead of mounting a `Sheet` at all; this component is for the
55
- * mobile case specifically.
56
- *
57
- * Unlike `Dialog`/`Drawer` there is no scrim: a Sheet visually *replaces* the
58
- * region it covers rather than floating a layer above it, so there is no
59
- * "outside" to tap-dismiss. Behaviour: Esc dismisses; focus moves into the
60
- * panel on open and is restored on close; Tab is trapped within the panel;
61
- * animated open/close via the same two-phase mount as `Dialog`/`Drawer`,
62
- * respecting `prefers-reduced-motion`.
63
- */
64
- export function Sheet({
65
- open,
66
- onClose,
67
- 'aria-label': ariaLabel,
68
- title,
69
- onBack,
70
- headerAction,
71
- slideFrom = 'bottom',
72
- children,
73
- }: SheetProps) {
74
- const panelRef = useRef<HTMLDivElement>(null);
75
- const reducedMotion = usePrefersReducedMotion();
76
- const { mounted, phase } = useMountTransition(open, reducedMotion ? 0 : MOTION_DURATION_MS);
77
-
78
- useOverlayScrollLock(mounted);
79
- useOverlayFocusCapture(panelRef, mounted);
80
- useOverlayKeyboardTrap(panelRef, open, onClose);
81
-
82
- if (!mounted) return null;
83
-
84
- return (
85
- <div
86
- ref={panelRef}
87
- role="dialog"
88
- aria-modal="true"
89
- aria-label={ariaLabel ?? title}
90
- tabIndex={-1}
91
- className={[
92
- styles.panel,
93
- slideFrom === 'top' ? styles.panelFromTop : '',
94
- phase === 'open' ? styles.panelOpen : '',
95
- ]
96
- .filter(Boolean)
97
- .join(' ')}
98
- >
99
- {title && (
100
- <OverlayHeader title={title} onClose={onClose} onBack={onBack} action={headerAction} />
101
- )}
102
- {/* Content is always the scroll container — with or without a header —
103
- so a header's sibling stays fixed and any content-owned internal
104
- sticky positioning (e.g. a form's own sub-header) resolves against
105
- this same scrolling ancestor either way. */}
106
- <div className={styles.content}>{children}</div>
107
- </div>
108
- );
109
- }
@@ -1,99 +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 { Sheet } from '../Sheet';
5
-
6
- // Sheet's exit animation reads prefers-reduced-motion via matchMedia, which
7
- // jsdom does not implement — see Dialog.test.tsx's identical setup.
8
- function installMatchMedia() {
9
- vi.stubGlobal(
10
- 'matchMedia',
11
- vi.fn().mockImplementation((query: string) => ({
12
- matches: false,
13
- media: query,
14
- addEventListener: vi.fn(),
15
- removeEventListener: vi.fn(),
16
- addListener: vi.fn(),
17
- removeListener: vi.fn(),
18
- dispatchEvent: vi.fn(),
19
- })),
20
- );
21
- }
22
-
23
- describe('Sheet', () => {
24
- beforeEach(installMatchMedia);
25
- afterEach(() => {
26
- vi.unstubAllGlobals();
27
- cleanup();
28
- });
29
-
30
- it('renders nothing when closed', () => {
31
- render(
32
- <Sheet open={false} onClose={() => {}}>
33
- Body
34
- </Sheet>,
35
- );
36
- expect(screen.queryByRole('dialog')).toBeNull();
37
- });
38
-
39
- it('renders the panel with its accessible name when open', () => {
40
- render(
41
- <Sheet open onClose={() => {}} aria-label="Task detail">
42
- Body
43
- </Sheet>,
44
- );
45
- const panel = screen.getByRole('dialog', { name: 'Task detail' });
46
- expect(panel.getAttribute('aria-modal')).toBe('true');
47
- });
48
-
49
- it('falls back to title for the accessible name when aria-label is omitted', () => {
50
- render(
51
- <Sheet open onClose={() => {}} title="Edit list">
52
- Body
53
- </Sheet>,
54
- );
55
- expect(screen.getByRole('dialog', { name: 'Edit list' })).toBeTruthy();
56
- });
57
-
58
- it('does not render OverlayHeader when title is omitted (headerless escape hatch)', () => {
59
- render(
60
- <Sheet open onClose={() => {}} aria-label="Custom">
61
- <button type="button">Own close button</button>
62
- </Sheet>,
63
- );
64
- // Only the content's own button — no OverlayHeader close button.
65
- expect(screen.getAllByRole('button')).toHaveLength(1);
66
- });
67
-
68
- it('renders OverlayHeader (title + close) when title is provided', () => {
69
- const onClose = vi.fn();
70
- render(
71
- <Sheet open onClose={onClose} title="Edit list">
72
- Body
73
- </Sheet>,
74
- );
75
- expect(screen.getByText('Edit list')).toBeTruthy();
76
- fireEvent.click(screen.getByRole('button', { name: 'Close' }));
77
- expect(onClose).toHaveBeenCalledOnce();
78
- });
79
-
80
- it('calls onClose on Escape', () => {
81
- const onClose = vi.fn();
82
- render(
83
- <Sheet open onClose={onClose} aria-label="Panel">
84
- Body
85
- </Sheet>,
86
- );
87
- fireEvent.keyDown(document, { key: 'Escape' });
88
- expect(onClose).toHaveBeenCalledOnce();
89
- });
90
-
91
- it('applies the top slide-from variant class', () => {
92
- render(
93
- <Sheet open onClose={() => {}} aria-label="Menu" slideFrom="top">
94
- Body
95
- </Sheet>,
96
- );
97
- expect(screen.getByRole('dialog').className).toMatch(/panelFromTop/);
98
- });
99
- });
@@ -1,95 +0,0 @@
1
- .root {
2
- display: flex;
3
- flex-direction: column;
4
- gap: var(--sv-space-2);
5
- }
6
-
7
- .label {
8
- font-size: var(--sv-font-size-sm);
9
- color: var(--sv-color-text-primary);
10
- }
11
-
12
- .slider {
13
- appearance: none;
14
- width: 100%;
15
- height: 20px;
16
- background: transparent;
17
- cursor: pointer;
18
- margin: 0;
19
- }
20
-
21
- /* Expand the vertical hit area for touch dragging without thickening the
22
- visible track — same rationale as Button/Checkbox's touch-target
23
- expansion, gated to the primary pointer. */
24
- @media (pointer: coarse) {
25
- .slider {
26
- height: var(--sv-touch-target-min, 44px);
27
- }
28
- }
29
-
30
- .slider:disabled {
31
- opacity: 0.5;
32
- cursor: not-allowed;
33
- }
34
-
35
- .slider:focus-visible {
36
- outline: 2px solid var(--sv-color-focus-ring);
37
- outline-offset: 2px;
38
- }
39
-
40
- /* Track — WebKit/Blink. The filled portion is a gradient computed from the
41
- --slider-fill custom property the component sets inline; no JS-measured
42
- pixel math, just a CSS variable driving a hard color stop. */
43
- .slider::-webkit-slider-runnable-track {
44
- height: 4px;
45
- border-radius: var(--sv-radius-full);
46
- background: linear-gradient(
47
- to right,
48
- var(--sv-color-accent) var(--slider-fill),
49
- var(--sv-color-border-strong) var(--slider-fill)
50
- );
51
- }
52
-
53
- .slider::-webkit-slider-thumb {
54
- appearance: none;
55
- width: 16px;
56
- height: 16px;
57
- margin-top: -6px;
58
- border-radius: var(--sv-radius-full);
59
- background: var(--sv-color-accent);
60
- box-shadow: var(--sv-shadow-control);
61
- cursor: pointer;
62
- }
63
-
64
- .slider:disabled::-webkit-slider-thumb {
65
- cursor: not-allowed;
66
- }
67
-
68
- /* Track — Firefox. Separate track/progress pseudo-elements instead of a
69
- gradient — Firefox renders the filled portion natively via
70
- ::-moz-range-progress. */
71
- .slider::-moz-range-track {
72
- height: 4px;
73
- border-radius: var(--sv-radius-full);
74
- background: var(--sv-color-border-strong);
75
- }
76
-
77
- .slider::-moz-range-progress {
78
- height: 4px;
79
- border-radius: var(--sv-radius-full);
80
- background: var(--sv-color-accent);
81
- }
82
-
83
- .slider::-moz-range-thumb {
84
- width: 16px;
85
- height: 16px;
86
- border: none;
87
- border-radius: var(--sv-radius-full);
88
- background: var(--sv-color-accent);
89
- box-shadow: var(--sv-shadow-control);
90
- cursor: pointer;
91
- }
92
-
93
- .slider:disabled::-moz-range-thumb {
94
- cursor: not-allowed;
95
- }
@@ -1,64 +0,0 @@
1
- import { useState } from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react-vite';
3
- import { Slider } from './Slider';
4
-
5
- const meta = {
6
- title: 'Components/Slider',
7
- component: Slider,
8
- parameters: {
9
- layout: 'padded',
10
- docs: {
11
- description: {
12
- component:
13
- 'Single-thumb range input. A native <input type="range"> under custom styling — arrow keys, Home/End, and touch-drag all come from the browser.',
14
- },
15
- },
16
- },
17
- args: {
18
- value: 50,
19
- onChange: () => {},
20
- min: 0,
21
- max: 100,
22
- 'aria-label': 'Value',
23
- },
24
- } satisfies Meta<typeof Slider>;
25
-
26
- export default meta;
27
- type Story = StoryObj<typeof meta>;
28
-
29
- // ---------------------------------------------------------------------------
30
-
31
- export const Default: Story = {
32
- render: (args) => {
33
- const [value, setValue] = useState(args.value);
34
- return <Slider {...args} value={value} onChange={setValue} />;
35
- },
36
- };
37
-
38
- export const WithLabel: Story = {
39
- render: (args) => {
40
- const [value, setValue] = useState(args.value);
41
- return <Slider {...args} label="Volume" value={value} onChange={setValue} />;
42
- },
43
- };
44
-
45
- export const AtMin: Story = {
46
- args: { value: 0 },
47
- };
48
-
49
- export const AtMax: Story = {
50
- args: { value: 100 },
51
- };
52
-
53
- export const SteppedRange: Story = {
54
- render: (_args) => {
55
- const [value, setValue] = useState(5);
56
- return (
57
- <Slider value={value} onChange={setValue} min={0} max={10} step={1} label="Rating (0–10)" />
58
- );
59
- },
60
- };
61
-
62
- export const Disabled: Story = {
63
- args: { disabled: true },
64
- };
@@ -1,77 +0,0 @@
1
- 'use client';
2
-
3
- import { useId } from 'react';
4
- import type { CSSProperties } from 'react';
5
- import styles from './Slider.module.css';
6
-
7
- export interface SliderProps {
8
- value: number;
9
- onChange: (value: number) => void;
10
- min: number;
11
- max: number;
12
- step?: number;
13
- /** Renders a visible label above the track. Omit and pass `aria-label`
14
- * instead for a standalone, unlabeled slider. */
15
- label?: string;
16
- disabled?: boolean;
17
- id?: string;
18
- className?: string;
19
- 'aria-label'?: string;
20
- 'aria-describedby'?: string;
21
- 'aria-invalid'?: boolean;
22
- required?: boolean;
23
- }
24
-
25
- /**
26
- * Slider — single-thumb range input.
27
- *
28
- * A native `<input type="range">` under custom track/thumb styling — arrow
29
- * key (adjust by `step`), Home/End (jump to min/max), and touch-drag
30
- * support all come from the browser, nothing hand-rolled. Dual-thumb/range
31
- * selection is out of scope until a consumer needs it.
32
- */
33
- export function Slider({
34
- value,
35
- onChange,
36
- min,
37
- max,
38
- step,
39
- label,
40
- disabled,
41
- id,
42
- className,
43
- 'aria-label': ariaLabel,
44
- 'aria-describedby': ariaDescribedBy,
45
- 'aria-invalid': ariaInvalid,
46
- required,
47
- }: SliderProps) {
48
- const generatedId = useId();
49
- const inputId = id ?? generatedId;
50
- const fillPercent = max > min ? ((value - min) / (max - min)) * 100 : 0;
51
-
52
- return (
53
- <div className={[styles.root, className].filter(Boolean).join(' ')}>
54
- {label && (
55
- <label htmlFor={inputId} className={styles.label}>
56
- {label}
57
- </label>
58
- )}
59
- <input
60
- id={inputId}
61
- type="range"
62
- min={min}
63
- max={max}
64
- step={step}
65
- value={value}
66
- disabled={disabled}
67
- required={required}
68
- aria-label={label ? undefined : ariaLabel}
69
- aria-describedby={ariaDescribedBy}
70
- aria-invalid={ariaInvalid}
71
- className={styles.slider}
72
- style={{ '--slider-fill': `${fillPercent}%` } as CSSProperties}
73
- onChange={(e) => onChange(Number(e.target.value))}
74
- />
75
- </div>
76
- );
77
- }
@@ -1,45 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, describe, expect, it, vi } from 'vitest';
3
- import { cleanup, render, screen, fireEvent } from '@testing-library/react';
4
- import { Slider } from '../Slider';
5
-
6
- afterEach(cleanup);
7
-
8
- describe('Slider', () => {
9
- it('renders a range input with the given min/max/value', () => {
10
- render(<Slider value={50} onChange={() => {}} min={0} max={100} aria-label="Volume" />);
11
- const input = screen.getByRole('slider') as HTMLInputElement;
12
- expect(input.min).toBe('0');
13
- expect(input.max).toBe('100');
14
- expect(input.value).toBe('50');
15
- });
16
-
17
- it('calls onChange with a number when the value changes', () => {
18
- const onChange = vi.fn();
19
- render(<Slider value={50} onChange={onChange} min={0} max={100} aria-label="Volume" />);
20
- fireEvent.change(screen.getByRole('slider'), { target: { value: '75' } });
21
- expect(onChange).toHaveBeenCalledWith(75);
22
- });
23
-
24
- it('respects a step prop', () => {
25
- render(<Slider value={5} onChange={() => {}} min={0} max={10} step={5} aria-label="Volume" />);
26
- expect((screen.getByRole('slider') as HTMLInputElement).step).toBe('5');
27
- });
28
-
29
- it('renders a visible label and associates it via htmlFor', () => {
30
- render(<Slider value={50} onChange={() => {}} min={0} max={100} label="Volume" />);
31
- expect(screen.getByRole('slider', { name: 'Volume' })).toBeDefined();
32
- });
33
-
34
- it('falls back to aria-label when no visible label is given', () => {
35
- render(<Slider value={50} onChange={() => {}} min={0} max={100} aria-label="Volume" />);
36
- expect(screen.getByRole('slider', { name: 'Volume' })).toBeDefined();
37
- });
38
-
39
- it('disables the input when disabled is set', () => {
40
- render(
41
- <Slider value={50} onChange={() => {}} min={0} max={100} aria-label="Volume" disabled />,
42
- );
43
- expect(screen.getByRole('slider')).toHaveProperty('disabled', true);
44
- });
45
- });
@@ -1,39 +0,0 @@
1
- @keyframes spin {
2
- to {
3
- transform: rotate(360deg);
4
- }
5
- }
6
-
7
- .spinner {
8
- display: inline-block;
9
- border-radius: 50%;
10
- border-style: solid;
11
- border-color: var(--sv-color-border);
12
- border-top-color: var(--sv-color-accent);
13
- animation: spin 0.7s linear infinite;
14
- flex-shrink: 0;
15
- }
16
-
17
- @media (prefers-reduced-motion: reduce) {
18
- .spinner {
19
- animation-play-state: paused;
20
- }
21
- }
22
-
23
- .sm {
24
- width: var(--sv-icon-size-sm);
25
- height: var(--sv-icon-size-sm);
26
- border-width: 2px;
27
- }
28
-
29
- .md {
30
- width: var(--sv-icon-size-md);
31
- height: var(--sv-icon-size-md);
32
- border-width: 2px;
33
- }
34
-
35
- .lg {
36
- width: var(--sv-icon-size-lg);
37
- height: var(--sv-icon-size-lg);
38
- border-width: 3px;
39
- }
@@ -1,23 +0,0 @@
1
- import styles from './Spinner.module.css';
2
-
3
- export interface SpinnerProps {
4
- size?: 'sm' | 'md' | 'lg';
5
- label?: string;
6
- className?: string;
7
- }
8
-
9
- const sizeClass: Record<NonNullable<SpinnerProps['size']>, string> = {
10
- sm: styles.sm as string,
11
- md: styles.md as string,
12
- lg: styles.lg as string,
13
- };
14
-
15
- export function Spinner({ size = 'md', label = 'Loading…', className }: SpinnerProps) {
16
- return (
17
- <span
18
- role="status"
19
- aria-label={label}
20
- className={[styles.spinner, sizeClass[size], className].filter(Boolean).join(' ')}
21
- />
22
- );
23
- }