@sovereignfs/ui 0.83.1 → 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 (556) hide show
  1. package/LICENSE +373 -661
  2. package/NOTICE +8 -0
  3. package/README.md +4 -6
  4. package/dist/AppsLauncher.module.css +6 -0
  5. package/dist/Button.module.css +5 -0
  6. package/dist/Card.module.css +6 -0
  7. package/dist/CardTile.module.css +6 -0
  8. package/dist/CheckableListRow.module.css +8 -0
  9. package/dist/Checkbox.module.css +8 -0
  10. package/dist/CodeTextarea.module.css +6 -0
  11. package/dist/ColorPicker.module.css +6 -0
  12. package/dist/Combobox.module.css +6 -0
  13. package/dist/Command.module.css +6 -0
  14. package/dist/ConfirmDialog.module.css +6 -0
  15. package/dist/DatePicker.module.css +6 -0
  16. package/dist/Dialog.module.css +1 -1
  17. package/dist/DragHandleRow.module.css +6 -0
  18. package/dist/FileDropzone.module.css +25 -1
  19. package/dist/Header.module.css +6 -0
  20. package/dist/IconPicker.module.css +14 -4
  21. package/dist/Input.module.css +6 -0
  22. package/dist/LegalLinks.module.css +9 -2
  23. package/dist/Markdown.module.css +5 -0
  24. package/dist/Message.module.css +9 -0
  25. package/dist/MobileAppsDrawer.module.css +9 -5
  26. package/dist/MobileFooter.module.css +6 -0
  27. package/dist/NavList.module.css +11 -2
  28. package/dist/NavTabs.module.css +7 -1
  29. package/dist/NotificationsPanel.module.css +10 -0
  30. package/dist/QrCode.module.css +17 -0
  31. package/dist/QuantityStepper.module.css +4 -2
  32. package/dist/RadioGroup.module.css +6 -0
  33. package/dist/SegmentedControl.module.css +6 -0
  34. package/dist/Select.module.css +6 -0
  35. package/dist/Sheet.module.css +16 -1
  36. package/dist/SplitPane.module.css +1 -1
  37. package/dist/StepStrip.module.css +5 -3
  38. package/dist/SuggestionInput.module.css +12 -1
  39. package/dist/SwipableMobileCarouselDots.module.css +6 -0
  40. package/dist/SystemBanner.module.css +6 -0
  41. package/dist/Tabs.module.css +6 -0
  42. package/dist/TagInput.module.css +6 -0
  43. package/dist/Textarea.module.css +6 -0
  44. package/dist/Toast.module.css +5 -0
  45. package/dist/Toggle.module.css +7 -0
  46. package/dist/Tooltip.module.css +6 -0
  47. package/dist/UserMenu.module.css +5 -0
  48. package/dist/fonts/OFL.txt +93 -0
  49. package/dist/fonts/hanken-grotesk-cyrillic-ext-wght-normal.woff2 +0 -0
  50. package/dist/fonts/hanken-grotesk-latin-ext-wght-normal.woff2 +0 -0
  51. package/dist/fonts/hanken-grotesk-latin-wght-normal.woff2 +0 -0
  52. package/dist/fonts/hanken-grotesk-vietnamese-wght-normal.woff2 +0 -0
  53. package/dist/index.d.ts +121 -43
  54. package/dist/index.js +1410 -1152
  55. package/dist/tokens/fonts.css +53 -0
  56. package/dist/tokens/primitives.css +12 -12
  57. package/dist/tokens.css +2 -1
  58. package/package.json +24 -13
  59. package/src/__tests__/motion.test.tsx +0 -105
  60. package/src/__tests__/package-json.test.ts +0 -8
  61. package/src/components/Accordion/Accordion.module.css +0 -3
  62. package/src/components/Accordion/Accordion.stories.tsx +0 -110
  63. package/src/components/Accordion/Accordion.tsx +0 -53
  64. package/src/components/Accordion/__tests__/Accordion.test.tsx +0 -61
  65. package/src/components/Alert/Alert.module.css +0 -62
  66. package/src/components/Alert/Alert.stories.tsx +0 -96
  67. package/src/components/Alert/Alert.tsx +0 -58
  68. package/src/components/Alert/__tests__/Alert.test.tsx +0 -75
  69. package/src/components/AppsLauncher/AppsLauncher.module.css +0 -96
  70. package/src/components/AppsLauncher/AppsLauncher.stories.tsx +0 -58
  71. package/src/components/AppsLauncher/AppsLauncher.tsx +0 -117
  72. package/src/components/AppsLauncher/__tests__/AppsLauncher.test.tsx +0 -52
  73. package/src/components/AspectRatio/AspectRatio.module.css +0 -15
  74. package/src/components/AspectRatio/AspectRatio.stories.tsx +0 -78
  75. package/src/components/AspectRatio/AspectRatio.tsx +0 -21
  76. package/src/components/AspectRatio/__tests__/AspectRatio.test.tsx +0 -27
  77. package/src/components/Avatar/Avatar.module.css +0 -38
  78. package/src/components/Avatar/Avatar.tsx +0 -42
  79. package/src/components/Badge/Badge.module.css +0 -177
  80. package/src/components/Badge/Badge.stories.tsx +0 -238
  81. package/src/components/Badge/Badge.tsx +0 -84
  82. package/src/components/Badge/__tests__/Badge.test.tsx +0 -90
  83. package/src/components/BalanceChip/BalanceChip.module.css +0 -32
  84. package/src/components/BalanceChip/BalanceChip.stories.tsx +0 -45
  85. package/src/components/BalanceChip/BalanceChip.tsx +0 -33
  86. package/src/components/Breadcrumb/Breadcrumb.module.css +0 -49
  87. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +0 -47
  88. package/src/components/Breadcrumb/Breadcrumb.tsx +0 -57
  89. package/src/components/Breadcrumb/__tests__/Breadcrumb.test.tsx +0 -52
  90. package/src/components/Button/Button.module.css +0 -169
  91. package/src/components/Button/Button.stories.tsx +0 -83
  92. package/src/components/Button/Button.tsx +0 -52
  93. package/src/components/Button/__tests__/Button.test.tsx +0 -66
  94. package/src/components/ButtonGroup/ButtonGroup.module.css +0 -29
  95. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +0 -57
  96. package/src/components/ButtonGroup/ButtonGroup.tsx +0 -27
  97. package/src/components/ButtonGroup/__tests__/ButtonGroup.test.tsx +0 -29
  98. package/src/components/Calendar/Calendar.module.css +0 -126
  99. package/src/components/Calendar/Calendar.tsx +0 -213
  100. package/src/components/Calendar/__tests__/Calendar.test.tsx +0 -98
  101. package/src/components/Calendar/dateUtils.ts +0 -97
  102. package/src/components/Card/Card.module.css +0 -42
  103. package/src/components/Card/Card.tsx +0 -34
  104. package/src/components/CardTile/CardTile.module.css +0 -181
  105. package/src/components/CardTile/CardTile.stories.tsx +0 -86
  106. package/src/components/CardTile/CardTile.tsx +0 -128
  107. package/src/components/CardTile/__tests__/CardTile.test.tsx +0 -56
  108. package/src/components/CheckableListRow/CheckableListRow.module.css +0 -95
  109. package/src/components/CheckableListRow/CheckableListRow.stories.tsx +0 -99
  110. package/src/components/CheckableListRow/CheckableListRow.tsx +0 -89
  111. package/src/components/Checkbox/Checkbox.module.css +0 -111
  112. package/src/components/Checkbox/Checkbox.tsx +0 -78
  113. package/src/components/CodeTextarea/CodeTextarea.module.css +0 -53
  114. package/src/components/CodeTextarea/CodeTextarea.stories.tsx +0 -77
  115. package/src/components/CodeTextarea/CodeTextarea.tsx +0 -36
  116. package/src/components/Collapsible/Collapsible.module.css +0 -70
  117. package/src/components/Collapsible/Collapsible.stories.tsx +0 -62
  118. package/src/components/Collapsible/Collapsible.tsx +0 -66
  119. package/src/components/Collapsible/__tests__/Collapsible.test.tsx +0 -71
  120. package/src/components/ColorPicker/ColorPicker.module.css +0 -132
  121. package/src/components/ColorPicker/ColorPicker.stories.tsx +0 -80
  122. package/src/components/ColorPicker/ColorPicker.tsx +0 -157
  123. package/src/components/ColorPicker/__tests__/ColorPicker.test.tsx +0 -117
  124. package/src/components/Combobox/Combobox.module.css +0 -122
  125. package/src/components/Combobox/Combobox.stories.tsx +0 -79
  126. package/src/components/Combobox/Combobox.tsx +0 -186
  127. package/src/components/Combobox/__tests__/Combobox.test.tsx +0 -158
  128. package/src/components/Command/Command.module.css +0 -80
  129. package/src/components/Command/Command.stories.tsx +0 -104
  130. package/src/components/Command/Command.tsx +0 -168
  131. package/src/components/Command/__tests__/Command.test.tsx +0 -162
  132. package/src/components/ConfirmDialog/ConfirmDialog.module.css +0 -113
  133. package/src/components/ConfirmDialog/ConfirmDialog.tsx +0 -150
  134. package/src/components/ConfirmDialog/__tests__/ConfirmDialog.test.tsx +0 -214
  135. package/src/components/ConsentPrompt/ConsentPrompt.module.css +0 -21
  136. package/src/components/ConsentPrompt/ConsentPrompt.stories.tsx +0 -31
  137. package/src/components/ConsentPrompt/ConsentPrompt.tsx +0 -66
  138. package/src/components/ContextMenu/ContextMenu.stories.tsx +0 -81
  139. package/src/components/ContextMenu/ContextMenu.tsx +0 -100
  140. package/src/components/ContextMenu/__tests__/ContextMenu.test.tsx +0 -87
  141. package/src/components/CurrencyInput/CurrencyInput.stories.tsx +0 -50
  142. package/src/components/CurrencyInput/CurrencyInput.tsx +0 -60
  143. package/src/components/DataTable/DataTable.module.css +0 -28
  144. package/src/components/DataTable/DataTable.stories.tsx +0 -74
  145. package/src/components/DataTable/DataTable.tsx +0 -154
  146. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -123
  147. package/src/components/DatePicker/DatePicker.module.css +0 -61
  148. package/src/components/DatePicker/DatePicker.tsx +0 -103
  149. package/src/components/DatePicker/__tests__/DatePicker.test.tsx +0 -89
  150. package/src/components/DeviceOnlyGate/DeviceOnlyGate.tsx +0 -58
  151. package/src/components/DeviceOnlyGate/__tests__/DeviceOnlyGate.test.tsx +0 -45
  152. package/src/components/DeviceStorageKeyGate/DeviceStorageKeyGate.tsx +0 -100
  153. package/src/components/DeviceStorageKeyGate/__tests__/DeviceStorageKeyGate.test.tsx +0 -119
  154. package/src/components/Dialog/Dialog.module.css +0 -335
  155. package/src/components/Dialog/Dialog.stories.tsx +0 -324
  156. package/src/components/Dialog/Dialog.tsx +0 -254
  157. package/src/components/Dialog/__tests__/Dialog.test.tsx +0 -318
  158. package/src/components/DragHandleRow/DragHandleRow.module.css +0 -57
  159. package/src/components/DragHandleRow/DragHandleRow.tsx +0 -42
  160. package/src/components/Drawer/Drawer.module.css +0 -121
  161. package/src/components/Drawer/Drawer.stories.tsx +0 -132
  162. package/src/components/Drawer/Drawer.tsx +0 -175
  163. package/src/components/Drawer/__tests__/Drawer.test.tsx +0 -226
  164. package/src/components/EmptyState/EmptyState.module.css +0 -27
  165. package/src/components/EmptyState/EmptyState.tsx +0 -27
  166. package/src/components/FileDropzone/FileDropzone.module.css +0 -63
  167. package/src/components/FileDropzone/FileDropzone.tsx +0 -109
  168. package/src/components/FileDropzone/__tests__/FileDropzone.test.tsx +0 -67
  169. package/src/components/FormField/FormField.module.css +0 -33
  170. package/src/components/FormField/FormField.tsx +0 -78
  171. package/src/components/FormField/__tests__/FormField.test.tsx +0 -83
  172. package/src/components/GripIcon/GripIcon.tsx +0 -27
  173. package/src/components/Header/Header.module.css +0 -62
  174. package/src/components/Header/Header.stories.tsx +0 -452
  175. package/src/components/Header/Header.tsx +0 -102
  176. package/src/components/Header/__tests__/Header.test.tsx +0 -104
  177. package/src/components/HeaderFooterLayout/HeaderFooterLayout.module.css +0 -21
  178. package/src/components/HeaderFooterLayout/HeaderFooterLayout.stories.tsx +0 -111
  179. package/src/components/HeaderFooterLayout/HeaderFooterLayout.tsx +0 -54
  180. package/src/components/HeaderFooterLayout/__tests__/HeaderFooterLayout.test.tsx +0 -58
  181. package/src/components/HoverCard/HoverCard.module.css +0 -3
  182. package/src/components/HoverCard/HoverCard.stories.tsx +0 -66
  183. package/src/components/HoverCard/HoverCard.tsx +0 -111
  184. package/src/components/HoverCard/__tests__/HoverCard.test.tsx +0 -99
  185. package/src/components/Icon/Icon.module.css +0 -27
  186. package/src/components/Icon/Icon.stories.tsx +0 -95
  187. package/src/components/Icon/Icon.tsx +0 -43
  188. package/src/components/Icon/__tests__/Icon.test.tsx +0 -40
  189. package/src/components/Icon/icons/activity.tsx +0 -20
  190. package/src/components/Icon/icons/alert-triangle.tsx +0 -22
  191. package/src/components/Icon/icons/apple.tsx +0 -21
  192. package/src/components/Icon/icons/arrow-left-right.tsx +0 -23
  193. package/src/components/Icon/icons/banana.tsx +0 -21
  194. package/src/components/Icon/icons/beef.tsx +0 -22
  195. package/src/components/Icon/icons/beer.tsx +0 -24
  196. package/src/components/Icon/icons/bell.tsx +0 -21
  197. package/src/components/Icon/icons/bold.tsx +0 -20
  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-chevron-left.tsx +0 -21
  208. package/src/components/Icon/icons/circle-x.tsx +0 -22
  209. package/src/components/Icon/icons/code.tsx +0 -21
  210. package/src/components/Icon/icons/coffee.tsx +0 -23
  211. package/src/components/Icon/icons/cookie.tsx +0 -25
  212. package/src/components/Icon/icons/copy.tsx +0 -21
  213. package/src/components/Icon/icons/credit-card.tsx +0 -21
  214. package/src/components/Icon/icons/croissant.tsx +0 -24
  215. package/src/components/Icon/icons/cup-soda.tsx +0 -23
  216. package/src/components/Icon/icons/database.tsx +0 -22
  217. package/src/components/Icon/icons/download.tsx +0 -22
  218. package/src/components/Icon/icons/drumstick.tsx +0 -21
  219. package/src/components/Icon/icons/egg.tsx +0 -20
  220. package/src/components/Icon/icons/ellipsis-vertical.tsx +0 -22
  221. package/src/components/Icon/icons/external-link.tsx +0 -22
  222. package/src/components/Icon/icons/eye-off.tsx +0 -23
  223. package/src/components/Icon/icons/eye.tsx +0 -21
  224. package/src/components/Icon/icons/file-text.tsx +0 -24
  225. package/src/components/Icon/icons/file.tsx +0 -21
  226. package/src/components/Icon/icons/fish.tsx +0 -25
  227. package/src/components/Icon/icons/folder-closed.tsx +0 -21
  228. package/src/components/Icon/icons/folder-open.tsx +0 -20
  229. package/src/components/Icon/icons/folder.tsx +0 -20
  230. package/src/components/Icon/icons/folders.tsx +0 -21
  231. package/src/components/Icon/icons/grid-2x2.tsx +0 -22
  232. package/src/components/Icon/icons/hat-glasses.tsx +0 -24
  233. package/src/components/Icon/icons/history.tsx +0 -22
  234. package/src/components/Icon/icons/house.tsx +0 -21
  235. package/src/components/Icon/icons/inbox.tsx +0 -21
  236. package/src/components/Icon/icons/index.ts +0 -394
  237. package/src/components/Icon/icons/info.tsx +0 -22
  238. package/src/components/Icon/icons/italic.tsx +0 -22
  239. package/src/components/Icon/icons/layers.tsx +0 -22
  240. package/src/components/Icon/icons/layout-dashboard.tsx +0 -23
  241. package/src/components/Icon/icons/layout-grid.tsx +0 -23
  242. package/src/components/Icon/icons/link.tsx +0 -21
  243. package/src/components/Icon/icons/list-ordered.tsx +0 -25
  244. package/src/components/Icon/icons/list.tsx +0 -25
  245. package/src/components/Icon/icons/lock.tsx +0 -21
  246. package/src/components/Icon/icons/log-out.tsx +0 -22
  247. package/src/components/Icon/icons/luggage.tsx +0 -24
  248. package/src/components/Icon/icons/mail.tsx +0 -21
  249. package/src/components/Icon/icons/map-pin.tsx +0 -21
  250. package/src/components/Icon/icons/menu.tsx +0 -22
  251. package/src/components/Icon/icons/milk.tsx +0 -22
  252. package/src/components/Icon/icons/minus.tsx +0 -20
  253. package/src/components/Icon/icons/package.tsx +0 -23
  254. package/src/components/Icon/icons/paint-bucket.tsx +0 -23
  255. package/src/components/Icon/icons/panel-left.tsx +0 -21
  256. package/src/components/Icon/icons/pencil.tsx +0 -21
  257. package/src/components/Icon/icons/pin.tsx +0 -21
  258. package/src/components/Icon/icons/pizza.tsx +0 -24
  259. package/src/components/Icon/icons/plus.tsx +0 -21
  260. package/src/components/Icon/icons/rectangle-ellipsis.tsx +0 -23
  261. package/src/components/Icon/icons/refresh-cw.tsx +0 -23
  262. package/src/components/Icon/icons/rotate-ccw.tsx +0 -21
  263. package/src/components/Icon/icons/rotate-cw.tsx +0 -21
  264. package/src/components/Icon/icons/route.tsx +0 -22
  265. package/src/components/Icon/icons/salad.tsx +0 -24
  266. package/src/components/Icon/icons/search.tsx +0 -21
  267. package/src/components/Icon/icons/send.tsx +0 -21
  268. package/src/components/Icon/icons/settings.tsx +0 -21
  269. package/src/components/Icon/icons/share-2.tsx +0 -24
  270. package/src/components/Icon/icons/sheet.tsx +0 -24
  271. package/src/components/Icon/icons/shield.tsx +0 -20
  272. package/src/components/Icon/icons/shopping-basket.tsx +0 -26
  273. package/src/components/Icon/icons/sliders-horizontal.tsx +0 -28
  274. package/src/components/Icon/icons/smartphone.tsx +0 -21
  275. package/src/components/Icon/icons/snowflake.tsx +0 -31
  276. package/src/components/Icon/icons/spray-can.tsx +0 -29
  277. package/src/components/Icon/icons/square-kanban.tsx +0 -23
  278. package/src/components/Icon/icons/table.tsx +0 -23
  279. package/src/components/Icon/icons/trash-2.tsx +0 -24
  280. package/src/components/Icon/icons/upload.tsx +0 -22
  281. package/src/components/Icon/icons/user-round-plus.tsx +0 -23
  282. package/src/components/Icon/icons/user.tsx +0 -21
  283. package/src/components/Icon/icons/users.tsx +0 -23
  284. package/src/components/Icon/icons/wine.tsx +0 -23
  285. package/src/components/Icon/icons/x.tsx +0 -21
  286. package/src/components/IconPicker/IconPicker.module.css +0 -63
  287. package/src/components/IconPicker/IconPicker.stories.tsx +0 -84
  288. package/src/components/IconPicker/IconPicker.tsx +0 -90
  289. package/src/components/Input/Input.module.css +0 -52
  290. package/src/components/Input/Input.stories.tsx +0 -86
  291. package/src/components/Input/Input.tsx +0 -20
  292. package/src/components/Input/__tests__/Input.test.tsx +0 -22
  293. package/src/components/Item/Item.module.css +0 -70
  294. package/src/components/Item/Item.stories.tsx +0 -62
  295. package/src/components/Item/Item.tsx +0 -54
  296. package/src/components/Item/__tests__/Item.test.tsx +0 -39
  297. package/src/components/Kbd/Kbd.module.css +0 -14
  298. package/src/components/Kbd/Kbd.stories.tsx +0 -32
  299. package/src/components/Kbd/Kbd.tsx +0 -12
  300. package/src/components/Kbd/__tests__/Kbd.test.tsx +0 -14
  301. package/src/components/Label/Label.module.css +0 -11
  302. package/src/components/Label/Label.stories.tsx +0 -40
  303. package/src/components/Label/Label.tsx +0 -24
  304. package/src/components/Label/__tests__/Label.test.tsx +0 -32
  305. package/src/components/LegalLinks/LegalLinks.module.css +0 -24
  306. package/src/components/LegalLinks/LegalLinks.stories.tsx +0 -22
  307. package/src/components/LegalLinks/LegalLinks.tsx +0 -40
  308. package/src/components/Markdown/Markdown.module.css +0 -73
  309. package/src/components/Markdown/Markdown.stories.tsx +0 -40
  310. package/src/components/Markdown/Markdown.tsx +0 -305
  311. package/src/components/Markdown/__tests__/Markdown.test.tsx +0 -144
  312. package/src/components/Marker/Marker.module.css +0 -33
  313. package/src/components/Marker/Marker.stories.tsx +0 -39
  314. package/src/components/Marker/Marker.tsx +0 -34
  315. package/src/components/Marker/__tests__/Marker.test.tsx +0 -23
  316. package/src/components/MemberMultiSelect/MemberMultiSelect.module.css +0 -27
  317. package/src/components/MemberMultiSelect/MemberMultiSelect.stories.tsx +0 -74
  318. package/src/components/MemberMultiSelect/MemberMultiSelect.tsx +0 -67
  319. package/src/components/Menu/Menu.module.css +0 -90
  320. package/src/components/Menu/Menu.tsx +0 -209
  321. package/src/components/Menu/__tests__/Menu.test.tsx +0 -227
  322. package/src/components/Menubar/Menubar.stories.tsx +0 -52
  323. package/src/components/Menubar/Menubar.tsx +0 -42
  324. package/src/components/Menubar/__tests__/Menubar.test.tsx +0 -45
  325. package/src/components/Message/Message.module.css +0 -99
  326. package/src/components/Message/Message.stories.tsx +0 -79
  327. package/src/components/Message/Message.tsx +0 -41
  328. package/src/components/Message/__tests__/Message.test.tsx +0 -46
  329. package/src/components/MessageScroller/MessageScroller.module.css +0 -65
  330. package/src/components/MessageScroller/MessageScroller.stories.tsx +0 -84
  331. package/src/components/MessageScroller/MessageScroller.tsx +0 -84
  332. package/src/components/MessageScroller/__tests__/MessageScroller.test.tsx +0 -105
  333. package/src/components/MobileAppsDrawer/MobileAppsDrawer.module.css +0 -82
  334. package/src/components/MobileAppsDrawer/MobileAppsDrawer.tsx +0 -78
  335. package/src/components/MobileAppsDrawer/__tests__/MobileAppsDrawer.test.tsx +0 -80
  336. package/src/components/MobileFooter/MobileFooter.module.css +0 -73
  337. package/src/components/MobileFooter/MobileFooter.stories.tsx +0 -47
  338. package/src/components/MobileFooter/MobileFooter.tsx +0 -122
  339. package/src/components/MobileFooter/__tests__/MobileFooter.test.tsx +0 -129
  340. package/src/components/MobileHeader/MobileHeader.module.css +0 -76
  341. package/src/components/MobileHeader/MobileHeader.stories.tsx +0 -57
  342. package/src/components/MobileHeader/MobileHeader.tsx +0 -90
  343. package/src/components/MobileHeader/__tests__/MobileHeader.test.tsx +0 -113
  344. package/src/components/NavList/NavList.module.css +0 -130
  345. package/src/components/NavList/NavList.tsx +0 -136
  346. package/src/components/NavList/__tests__/NavList.test.tsx +0 -109
  347. package/src/components/NavTabs/NavTabs.module.css +0 -50
  348. package/src/components/NavTabs/NavTabs.tsx +0 -61
  349. package/src/components/NavigationMenu/NavigationMenu.module.css +0 -53
  350. package/src/components/NavigationMenu/NavigationMenu.stories.tsx +0 -58
  351. package/src/components/NavigationMenu/NavigationMenu.tsx +0 -125
  352. package/src/components/NavigationMenu/__tests__/NavigationMenu.test.tsx +0 -93
  353. package/src/components/NotificationsPanel/NotificationsPanel.module.css +0 -258
  354. package/src/components/NotificationsPanel/NotificationsPanel.stories.tsx +0 -61
  355. package/src/components/NotificationsPanel/NotificationsPanel.tsx +0 -187
  356. package/src/components/NotificationsPanel/__tests__/NotificationsPanel.test.tsx +0 -78
  357. package/src/components/OfflineGate/OfflineGate.tsx +0 -44
  358. package/src/components/OfflineGate/__tests__/OfflineGate.test.tsx +0 -66
  359. package/src/components/OverlayHeader/OverlayHeader.module.css +0 -98
  360. package/src/components/OverlayHeader/OverlayHeader.tsx +0 -77
  361. package/src/components/OverlayHeader/__tests__/OverlayHeader.test.tsx +0 -69
  362. package/src/components/PageContainer/PageContainer.module.css +0 -82
  363. package/src/components/PageContainer/PageContainer.tsx +0 -64
  364. package/src/components/PageContainer/__tests__/PageContainer.test.tsx +0 -70
  365. package/src/components/PageHeader/PageHeader.module.css +0 -86
  366. package/src/components/PageHeader/PageHeader.tsx +0 -176
  367. package/src/components/PageHeader/__tests__/PageHeader.test.tsx +0 -103
  368. package/src/components/PageLayout/PageLayout.module.css +0 -51
  369. package/src/components/PageLayout/PageLayout.stories.tsx +0 -73
  370. package/src/components/PageLayout/PageLayout.tsx +0 -51
  371. package/src/components/PageLayout/__tests__/PageLayout.test.tsx +0 -34
  372. package/src/components/Pagination/Pagination.module.css +0 -98
  373. package/src/components/Pagination/Pagination.stories.tsx +0 -49
  374. package/src/components/Pagination/Pagination.tsx +0 -87
  375. package/src/components/Pagination/__tests__/Pagination.test.tsx +0 -56
  376. package/src/components/Popover/Popover.module.css +0 -74
  377. package/src/components/Popover/Popover.stories.tsx +0 -357
  378. package/src/components/Popover/Popover.tsx +0 -290
  379. package/src/components/Popover/__tests__/Popover.test.tsx +0 -263
  380. package/src/components/Progress/Progress.module.css +0 -20
  381. package/src/components/Progress/Progress.stories.tsx +0 -40
  382. package/src/components/Progress/Progress.tsx +0 -35
  383. package/src/components/Progress/__tests__/Progress.test.tsx +0 -31
  384. package/src/components/QuantityStepper/QuantityStepper.module.css +0 -67
  385. package/src/components/QuantityStepper/QuantityStepper.stories.tsx +0 -79
  386. package/src/components/QuantityStepper/QuantityStepper.tsx +0 -107
  387. package/src/components/RadioGroup/RadioGroup.module.css +0 -88
  388. package/src/components/RadioGroup/RadioGroup.stories.tsx +0 -69
  389. package/src/components/RadioGroup/RadioGroup.tsx +0 -99
  390. package/src/components/RadioGroup/__tests__/RadioGroup.test.tsx +0 -59
  391. package/src/components/Resizable/Resizable.module.css +0 -70
  392. package/src/components/Resizable/Resizable.stories.tsx +0 -82
  393. package/src/components/Resizable/Resizable.tsx +0 -313
  394. package/src/components/Resizable/__tests__/Resizable.test.tsx +0 -128
  395. package/src/components/ResponsiveSurface/ResponsiveSurface.tsx +0 -24
  396. package/src/components/ResponsiveSurface/__tests__/ResponsiveSurface.test.tsx +0 -73
  397. package/src/components/RootLayout/RootLayout.module.css +0 -12
  398. package/src/components/RootLayout/RootLayout.stories.tsx +0 -125
  399. package/src/components/RootLayout/RootLayout.tsx +0 -185
  400. package/src/components/RootLayout/__tests__/RootLayout.test.tsx +0 -161
  401. package/src/components/ScrollArea/ScrollArea.module.css +0 -20
  402. package/src/components/ScrollArea/ScrollArea.stories.tsx +0 -57
  403. package/src/components/ScrollArea/ScrollArea.tsx +0 -27
  404. package/src/components/ScrollArea/__tests__/ScrollArea.test.tsx +0 -39
  405. package/src/components/SegmentedControl/SegmentedControl.module.css +0 -55
  406. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +0 -118
  407. package/src/components/SegmentedControl/SegmentedControl.tsx +0 -56
  408. package/src/components/SegmentedControl/__tests__/SegmentedControl.test.tsx +0 -63
  409. package/src/components/Select/Select.module.css +0 -82
  410. package/src/components/Select/Select.stories.tsx +0 -115
  411. package/src/components/Select/Select.tsx +0 -48
  412. package/src/components/Select/__tests__/Select.test.tsx +0 -59
  413. package/src/components/Sheet/Sheet.module.css +0 -58
  414. package/src/components/Sheet/Sheet.tsx +0 -109
  415. package/src/components/Sheet/__tests__/Sheet.test.tsx +0 -99
  416. package/src/components/Slider/Slider.module.css +0 -95
  417. package/src/components/Slider/Slider.stories.tsx +0 -64
  418. package/src/components/Slider/Slider.tsx +0 -77
  419. package/src/components/Slider/__tests__/Slider.test.tsx +0 -45
  420. package/src/components/Spinner/Spinner.module.css +0 -39
  421. package/src/components/Spinner/Spinner.tsx +0 -23
  422. package/src/components/SplitMethodSelector/SplitMethodSelector.stories.tsx +0 -33
  423. package/src/components/SplitMethodSelector/SplitMethodSelector.tsx +0 -43
  424. package/src/components/SplitPane/SplitPane.module.css +0 -85
  425. package/src/components/SplitPane/SplitPane.stories.tsx +0 -160
  426. package/src/components/SplitPane/SplitPane.tsx +0 -149
  427. package/src/components/SplitPane/__tests__/SplitPane.test.tsx +0 -51
  428. package/src/components/StatusBadge/StatusBadge.module.css +0 -59
  429. package/src/components/StatusBadge/StatusBadge.stories.tsx +0 -74
  430. package/src/components/StatusBadge/StatusBadge.tsx +0 -65
  431. package/src/components/StepStrip/StepStrip.module.css +0 -53
  432. package/src/components/StepStrip/StepStrip.tsx +0 -74
  433. package/src/components/SuggestionInput/SuggestionInput.module.css +0 -103
  434. package/src/components/SuggestionInput/SuggestionInput.stories.tsx +0 -144
  435. package/src/components/SuggestionInput/SuggestionInput.tsx +0 -207
  436. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.module.css +0 -64
  437. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.tsx +0 -243
  438. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlide.tsx +0 -35
  439. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody.tsx +0 -42
  440. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter.tsx +0 -18
  441. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader.tsx +0 -21
  442. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideParts.module.css +0 -29
  443. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarousel.test.tsx +0 -214
  444. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarouselDevGuard.test.tsx +0 -61
  445. package/src/components/SwipableMobileCarousel/context.ts +0 -13
  446. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.module.css +0 -64
  447. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.tsx +0 -73
  448. package/src/components/SwipableMobileCarouselDots/__tests__/SwipableMobileCarouselDots.test.tsx +0 -63
  449. package/src/components/SwipeStack/SwipeStack.module.css +0 -101
  450. package/src/components/SwipeStack/SwipeStack.tsx +0 -199
  451. package/src/components/SwipeStack/SwipeStackCard.tsx +0 -22
  452. package/src/components/SwipeStack/__tests__/SwipeStack.test.tsx +0 -169
  453. package/src/components/SystemBanner/SystemBanner.module.css +0 -79
  454. package/src/components/SystemBanner/SystemBanner.stories.tsx +0 -86
  455. package/src/components/SystemBanner/SystemBanner.tsx +0 -50
  456. package/src/components/SystemBanner/__tests__/SystemBanner.test.tsx +0 -50
  457. package/src/components/Table/Table.module.css +0 -45
  458. package/src/components/Table/Table.stories.tsx +0 -125
  459. package/src/components/Table/Table.tsx +0 -51
  460. package/src/components/Table/__tests__/Table.test.tsx +0 -50
  461. package/src/components/Tabs/Tabs.module.css +0 -56
  462. package/src/components/Tabs/Tabs.stories.tsx +0 -100
  463. package/src/components/Tabs/Tabs.tsx +0 -46
  464. package/src/components/Tabs/__tests__/Tabs.test.tsx +0 -45
  465. package/src/components/TagInput/TagInput.module.css +0 -141
  466. package/src/components/TagInput/TagInput.stories.tsx +0 -109
  467. package/src/components/TagInput/TagInput.tsx +0 -174
  468. package/src/components/TagInput/__tests__/TagInput.test.tsx +0 -69
  469. package/src/components/Textarea/Textarea.module.css +0 -47
  470. package/src/components/Textarea/Textarea.tsx +0 -38
  471. package/src/components/Textarea/__tests__/Textarea.test.tsx +0 -51
  472. package/src/components/ThreeColumnLayout/ThreeColumnLayout.module.css +0 -35
  473. package/src/components/ThreeColumnLayout/ThreeColumnLayout.stories.tsx +0 -152
  474. package/src/components/ThreeColumnLayout/ThreeColumnLayout.tsx +0 -87
  475. package/src/components/ThreeColumnLayout/__tests__/ThreeColumnLayout.test.tsx +0 -78
  476. package/src/components/Toast/Toast.module.css +0 -191
  477. package/src/components/Toast/Toast.stories.tsx +0 -191
  478. package/src/components/Toast/Toast.tsx +0 -139
  479. package/src/components/Toggle/Toggle.module.css +0 -57
  480. package/src/components/Toggle/Toggle.stories.tsx +0 -95
  481. package/src/components/Toggle/Toggle.tsx +0 -39
  482. package/src/components/Toggle/__tests__/Toggle.test.tsx +0 -47
  483. package/src/components/Tooltip/Tooltip.module.css +0 -56
  484. package/src/components/Tooltip/Tooltip.tsx +0 -30
  485. package/src/components/Typography/Typography.module.css +0 -47
  486. package/src/components/Typography/Typography.stories.tsx +0 -62
  487. package/src/components/Typography/Typography.tsx +0 -30
  488. package/src/components/Typography/__tests__/Typography.test.tsx +0 -34
  489. package/src/components/UserMenu/UserMenu.module.css +0 -90
  490. package/src/components/UserMenu/UserMenu.stories.tsx +0 -49
  491. package/src/components/UserMenu/UserMenu.tsx +0 -132
  492. package/src/components/UserMenu/__tests__/UserMenu.test.tsx +0 -77
  493. package/src/css-modules.d.ts +0 -4
  494. package/src/hooks/__tests__/useCarouselRouteSync.test.tsx +0 -126
  495. package/src/hooks/__tests__/useDoubleTap.test.tsx +0 -117
  496. package/src/hooks/__tests__/useIsMobile.test.tsx +0 -80
  497. package/src/hooks/__tests__/useIsOffline.test.tsx +0 -53
  498. package/src/hooks/__tests__/useLongPress.test.tsx +0 -158
  499. package/src/hooks/__tests__/useOfflineTileState.test.tsx +0 -69
  500. package/src/hooks/__tests__/usePublishShellChromeHeight.test.tsx +0 -118
  501. package/src/hooks/__tests__/useReorderSensors.test.ts +0 -26
  502. package/src/hooks/__tests__/useResponsiveLayout.test.tsx +0 -87
  503. package/src/hooks/__tests__/useSnapCarousel.test.tsx +0 -175
  504. package/src/hooks/__tests__/useSwipeReveal.test.tsx +0 -110
  505. package/src/hooks/__tests__/useSwipeStack.test.tsx +0 -155
  506. package/src/hooks/index.ts +0 -33
  507. package/src/hooks/useCarouselRouteSync.ts +0 -92
  508. package/src/hooks/useCommitOnEnterOrBlur.ts +0 -39
  509. package/src/hooks/useDoubleTap.ts +0 -91
  510. package/src/hooks/useIsMobile.ts +0 -33
  511. package/src/hooks/useIsOffline.ts +0 -41
  512. package/src/hooks/useLongPress.ts +0 -185
  513. package/src/hooks/useOfflineTileState.ts +0 -45
  514. package/src/hooks/usePublishShellChromeHeight.ts +0 -96
  515. package/src/hooks/useReorderSensors.ts +0 -88
  516. package/src/hooks/useResponsiveLayout.ts +0 -36
  517. package/src/hooks/useSnapCarousel.ts +0 -284
  518. package/src/hooks/useSwipeReveal.ts +0 -107
  519. package/src/hooks/useSwipeStack.ts +0 -235
  520. package/src/index.ts +0 -311
  521. package/src/motion.ts +0 -78
  522. package/src/overlay-shell.ts +0 -159
  523. package/src/scroll-lock.ts +0 -22
  524. package/src/stories/Avatar.stories.tsx +0 -44
  525. package/src/stories/Card.stories.tsx +0 -35
  526. package/src/stories/Checkbox.stories.tsx +0 -45
  527. package/src/stories/DesignSystemOverview.stories.tsx +0 -3793
  528. package/src/stories/DeviceOnlyGate.stories.tsx +0 -35
  529. package/src/stories/DeviceStorageKeyGate.stories.tsx +0 -57
  530. package/src/stories/DragHandleRow.stories.tsx +0 -41
  531. package/src/stories/EmptyState.stories.tsx +0 -33
  532. package/src/stories/FileDropzone.stories.tsx +0 -69
  533. package/src/stories/FormField.stories.tsx +0 -47
  534. package/src/stories/GripIcon.stories.tsx +0 -29
  535. package/src/stories/InteractionHooks.stories.tsx +0 -925
  536. package/src/stories/LayoutSystem.stories.tsx +0 -639
  537. package/src/stories/MenuEntries.stories.tsx +0 -86
  538. package/src/stories/MobilePatterns.stories.tsx +0 -1536
  539. package/src/stories/NavList.stories.tsx +0 -147
  540. package/src/stories/NavTabs.stories.tsx +0 -53
  541. package/src/stories/OfflineGate.stories.tsx +0 -42
  542. package/src/stories/PageContainer.stories.tsx +0 -82
  543. package/src/stories/PageHeader.stories.tsx +0 -95
  544. package/src/stories/ResponsiveSurface.stories.tsx +0 -47
  545. package/src/stories/Spinner.stories.tsx +0 -25
  546. package/src/stories/StepStrip.stories.tsx +0 -76
  547. package/src/stories/SwipableMobileCarousel.stories.tsx +0 -362
  548. package/src/stories/SwipeStack.stories.tsx +0 -200
  549. package/src/stories/Textarea.stories.tsx +0 -63
  550. package/src/stories/TokenGallery.stories.tsx +0 -652
  551. package/src/stories/Tooltip.stories.tsx +0 -59
  552. package/src/tokens/primitives.css +0 -168
  553. package/src/tokens/semantic.css +0 -162
  554. package/src/tokens/theme-presets.css +0 -33
  555. package/src/tokens/theme-presets.ts +0 -72
  556. package/src/tokens.css +0 -5
@@ -1,60 +0,0 @@
1
- 'use client';
2
-
3
- import { useState } from 'react';
4
- import { Input, type InputProps } from '../Input/Input';
5
-
6
- export interface CurrencyInputProps extends Omit<
7
- InputProps,
8
- 'value' | 'onChange' | 'type' | 'inputMode'
9
- > {
10
- /** Smallest currency unit (cents) — never a float. Null when the field is empty or unparsable. */
11
- valueCents: number | null;
12
- onValueChange: (cents: number | null) => void;
13
- }
14
-
15
- function centsToText(cents: number): string {
16
- return (cents / 100).toFixed(2);
17
- }
18
-
19
- function textToCents(text: string): number | null {
20
- const trimmed = text.trim();
21
- if (!trimmed) return null;
22
- const parsed = Number(trimmed);
23
- if (!Number.isFinite(parsed)) return null;
24
- return Math.round(parsed * 100);
25
- }
26
-
27
- /**
28
- * CurrencyInput — decimal amount entry that reports its value as integer
29
- * cents, matching Sovereign's "amounts are always smallest-unit integers"
30
- * data-model convention (never a float in application state).
31
- *
32
- * Keeps its own text buffer rather than deriving display text from
33
- * `valueCents` on every keystroke — reformatting mid-type (e.g. "12." → the
34
- * trailing decimal point) would fight the user's cursor. It only
35
- * re-syncs from `valueCents` when the prop changes to something the current
36
- * text doesn't already represent (an external reset/prefill), so typing
37
- * remains uninterrupted while the parsed amount stays in lockstep with the
38
- * parent's state.
39
- */
40
- export function CurrencyInput({ valueCents, onValueChange, ...rest }: CurrencyInputProps) {
41
- const [text, setText] = useState(() => (valueCents != null ? centsToText(valueCents) : ''));
42
-
43
- if (textToCents(text) !== valueCents) {
44
- setText(valueCents != null ? centsToText(valueCents) : '');
45
- }
46
-
47
- return (
48
- <Input
49
- {...rest}
50
- type="text"
51
- inputMode="decimal"
52
- value={text}
53
- onChange={(e) => {
54
- const next = e.currentTarget.value;
55
- setText(next);
56
- onValueChange(textToCents(next));
57
- }}
58
- />
59
- );
60
- }
@@ -1,28 +0,0 @@
1
- .sortButton {
2
- display: inline-flex;
3
- align-items: center;
4
- gap: var(--sv-space-1);
5
- border: none;
6
- background: transparent;
7
- padding: 0;
8
- margin: 0;
9
- color: inherit;
10
- font: inherit;
11
- font-weight: inherit;
12
- cursor: pointer;
13
- }
14
-
15
- .sortButton:focus-visible {
16
- outline: 2px solid var(--sv-color-focus-ring);
17
- outline-offset: 2px;
18
- border-radius: var(--sv-radius-sm);
19
- }
20
-
21
- .sortIcon {
22
- display: inline-flex;
23
- flex-shrink: 0;
24
- width: var(--sv-icon-size-sm);
25
- height: var(--sv-icon-size-sm);
26
- align-items: center;
27
- justify-content: center;
28
- }
@@ -1,74 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { DataTable, type DataTableColumn } from './DataTable';
3
- import { StatusBadge } from '../StatusBadge/StatusBadge';
4
-
5
- interface PluginRow {
6
- id: string;
7
- name: string;
8
- installs: number;
9
- status: 'synced' | 'draft';
10
- }
11
-
12
- const ROWS: PluginRow[] = [
13
- { id: 'tasks', name: 'sovereign-tasks', installs: 482, status: 'synced' },
14
- { id: 'ledger', name: 'sovereign-ledger', installs: 219, status: 'synced' },
15
- { id: 'shopper', name: 'sovereign-shopper', installs: 37, status: 'draft' },
16
- { id: 'healthlog', name: 'sovereign-healthlog', installs: 1204, status: 'synced' },
17
- ];
18
-
19
- const columns: DataTableColumn<PluginRow>[] = [
20
- { key: 'name', header: 'Plugin', sortable: true },
21
- { key: 'installs', header: 'Installs', sortable: true, align: 'end' },
22
- {
23
- key: 'status',
24
- header: 'Status',
25
- render: (row) => <StatusBadge status={row.status} />,
26
- },
27
- ];
28
-
29
- const meta = {
30
- title: 'Components/DataTable',
31
- component: DataTable,
32
- parameters: {
33
- layout: 'padded',
34
- docs: {
35
- description: {
36
- component:
37
- 'Sortable table built on Table. Column-driven: pass columns + data instead of composing TableRow/TableCell by hand. Clicking a sortable header cycles ascending → descending → unsorted.',
38
- },
39
- },
40
- },
41
- args: { columns: [], data: [], getRowKey: (row: PluginRow) => row.id },
42
- } satisfies Meta<typeof DataTable<PluginRow>>;
43
-
44
- export default meta;
45
- type Story = StoryObj<typeof meta>;
46
-
47
- // ---------------------------------------------------------------------------
48
-
49
- export const Default: Story = {
50
- render: () => <DataTable columns={columns} data={ROWS} getRowKey={(row) => row.id} />,
51
- };
52
-
53
- export const DefaultSorted: Story = {
54
- render: () => (
55
- <DataTable
56
- columns={columns}
57
- data={ROWS}
58
- getRowKey={(row) => row.id}
59
- defaultSortKey="installs"
60
- defaultSortDirection="desc"
61
- />
62
- ),
63
- };
64
-
65
- export const Empty: Story = {
66
- render: () => (
67
- <DataTable
68
- columns={columns}
69
- data={[]}
70
- getRowKey={(row) => row.id}
71
- emptyMessage="No plugins installed"
72
- />
73
- ),
74
- };
@@ -1,154 +0,0 @@
1
- 'use client';
2
-
3
- import { useMemo, useState } from 'react';
4
- import type { ReactNode } from 'react';
5
- import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from '../Table/Table';
6
- import { Icon } from '../Icon/Icon';
7
- import { EmptyState } from '../EmptyState/EmptyState';
8
- import styles from './DataTable.module.css';
9
-
10
- export type SortDirection = 'asc' | 'desc';
11
-
12
- export interface DataTableColumn<T> {
13
- key: string;
14
- header: string;
15
- sortable?: boolean;
16
- /** Cell content. Defaults to String(row[key]) when omitted. */
17
- render?: (row: T) => ReactNode;
18
- /** Value compared when sorting by this column. Defaults to row[key].
19
- * Required if `key` isn't a property on T (a computed/joined column). */
20
- sortValue?: (row: T) => string | number;
21
- align?: 'start' | 'end';
22
- }
23
-
24
- export interface DataTableProps<T> {
25
- columns: DataTableColumn<T>[];
26
- data: T[];
27
- getRowKey: (row: T) => string;
28
- /** Initial sort — uncontrolled after mount, like Table itself has no
29
- * externally-controlled state. */
30
- defaultSortKey?: string;
31
- defaultSortDirection?: SortDirection;
32
- emptyMessage?: string;
33
- className?: string;
34
- }
35
-
36
- function compareValues(a: string | number, b: string | number): number {
37
- if (typeof a === 'number' && typeof b === 'number') return a - b;
38
- return String(a).localeCompare(String(b));
39
- }
40
-
41
- /**
42
- * DataTable — sortable table built on Table's own primitives (no
43
- * virtualization or filtering — those stay out of scope, matching Table's
44
- * own "not a data grid" boundary). Column-driven: pass `columns` + `data`
45
- * rather than composing `<TableRow>`/`<TableCell>` by hand.
46
- *
47
- * Sort state is internal (uncontrolled) and click-cycles
48
- * ascending → descending → unsorted for a sortable column, mirroring the
49
- * "toggle → toggle → clear" pattern most sortable tables use rather than
50
- * being permanently stuck in whichever direction was clicked last.
51
- */
52
- export function DataTable<T>({
53
- columns,
54
- data,
55
- getRowKey,
56
- defaultSortKey,
57
- defaultSortDirection = 'asc',
58
- emptyMessage = 'No results.',
59
- className,
60
- }: DataTableProps<T>) {
61
- const [sortKey, setSortKey] = useState<string | undefined>(defaultSortKey);
62
- const [sortDirection, setSortDirection] = useState<SortDirection>(defaultSortDirection);
63
-
64
- const sortColumn = columns.find((c) => c.key === sortKey);
65
-
66
- const sortedData = useMemo(() => {
67
- if (!sortColumn) return data;
68
- const getValue =
69
- sortColumn.sortValue ??
70
- ((row: T) => (row as Record<string, unknown>)[sortColumn.key] as string | number);
71
- const sorted = [...data].sort((a, b) => compareValues(getValue(a), getValue(b)));
72
- return sortDirection === 'asc' ? sorted : sorted.reverse();
73
- }, [data, sortColumn, sortDirection]);
74
-
75
- function handleSort(column: DataTableColumn<T>) {
76
- if (!column.sortable) return;
77
- if (sortKey !== column.key) {
78
- setSortKey(column.key);
79
- setSortDirection('asc');
80
- } else if (sortDirection === 'asc') {
81
- setSortDirection('desc');
82
- } else {
83
- setSortKey(undefined);
84
- setSortDirection('asc');
85
- }
86
- }
87
-
88
- if (data.length === 0) {
89
- return <EmptyState heading={emptyMessage} />;
90
- }
91
-
92
- return (
93
- <Table className={className}>
94
- <TableHead>
95
- <TableRow>
96
- {columns.map((column) => {
97
- const isSorted = sortKey === column.key;
98
- const ariaSort = !column.sortable
99
- ? undefined
100
- : isSorted
101
- ? sortDirection === 'asc'
102
- ? 'ascending'
103
- : 'descending'
104
- : 'none';
105
- return (
106
- <TableHeaderCell
107
- key={column.key}
108
- aria-sort={ariaSort}
109
- style={column.align === 'end' ? { textAlign: 'end' } : undefined}
110
- >
111
- {column.sortable ? (
112
- <button
113
- type="button"
114
- className={styles.sortButton}
115
- onClick={() => handleSort(column)}
116
- >
117
- {column.header}
118
- <span className={styles.sortIcon}>
119
- {isSorted && (
120
- <Icon
121
- name={sortDirection === 'asc' ? 'chevron-up' : 'chevron-down'}
122
- size="sm"
123
- aria-hidden
124
- />
125
- )}
126
- </span>
127
- </button>
128
- ) : (
129
- column.header
130
- )}
131
- </TableHeaderCell>
132
- );
133
- })}
134
- </TableRow>
135
- </TableHead>
136
- <TableBody>
137
- {sortedData.map((row) => (
138
- <TableRow key={getRowKey(row)}>
139
- {columns.map((column) => (
140
- <TableCell
141
- key={column.key}
142
- style={column.align === 'end' ? { textAlign: 'end' } : undefined}
143
- >
144
- {column.render
145
- ? column.render(row)
146
- : String((row as Record<string, unknown>)[column.key] ?? '')}
147
- </TableCell>
148
- ))}
149
- </TableRow>
150
- ))}
151
- </TableBody>
152
- </Table>
153
- );
154
- }
@@ -1,123 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import { cleanup, fireEvent, render, screen, within } from '@testing-library/react';
4
- import { DataTable, type DataTableColumn } from '../DataTable';
5
-
6
- afterEach(cleanup);
7
-
8
- interface Plugin {
9
- id: string;
10
- name: string;
11
- installs: number;
12
- }
13
-
14
- const data: Plugin[] = [
15
- { id: 'a', name: 'Charlie', installs: 12 },
16
- { id: 'b', name: 'Alpha', installs: 30 },
17
- { id: 'c', name: 'Bravo', installs: 5 },
18
- ];
19
-
20
- const columns: DataTableColumn<Plugin>[] = [
21
- { key: 'name', header: 'Name', sortable: true },
22
- { key: 'installs', header: 'Installs', sortable: true, align: 'end' },
23
- ];
24
-
25
- function rowsText() {
26
- return screen
27
- .getAllByRole('row')
28
- .slice(1)
29
- .map((row) => within(row).getAllByRole('cell')[0]?.textContent);
30
- }
31
-
32
- describe('DataTable', () => {
33
- it('renders a row per data item and a header per column', () => {
34
- render(<DataTable columns={columns} data={data} getRowKey={(row) => row.id} />);
35
- expect(screen.getAllByRole('row')).toHaveLength(4); // 1 header + 3 body rows
36
- expect(screen.getByRole('columnheader', { name: 'Name' })).toBeDefined();
37
- expect(screen.getByRole('columnheader', { name: 'Installs' })).toBeDefined();
38
- });
39
-
40
- it('renders cell values from row[key] by default', () => {
41
- render(<DataTable columns={columns} data={data} getRowKey={(row) => row.id} />);
42
- expect(screen.getByText('Charlie')).toBeDefined();
43
- expect(screen.getByText('30')).toBeDefined();
44
- });
45
-
46
- it('uses a custom render function when provided', () => {
47
- const withRender: DataTableColumn<Plugin>[] = [
48
- { key: 'name', header: 'Name' },
49
- { key: 'installs', header: 'Installs', render: (row) => `${row.installs} installs` },
50
- ];
51
- render(<DataTable columns={withRender} data={data} getRowKey={(row) => row.id} />);
52
- expect(screen.getByText('30 installs')).toBeDefined();
53
- });
54
-
55
- it('shows an empty state instead of a table when data is empty', () => {
56
- render(
57
- <DataTable
58
- columns={columns}
59
- data={[]}
60
- getRowKey={(row) => row.id}
61
- emptyMessage="No plugins"
62
- />,
63
- );
64
- expect(screen.queryByRole('table')).toBeNull();
65
- expect(screen.getByText('No plugins')).toBeDefined();
66
- });
67
-
68
- it('non-sortable columns render as plain text, not a button', () => {
69
- const withPlain: DataTableColumn<Plugin>[] = [{ key: 'name', header: 'Name' }];
70
- render(<DataTable columns={withPlain} data={data} getRowKey={(row) => row.id} />);
71
- expect(screen.queryByRole('button', { name: 'Name' })).toBeNull();
72
- expect(screen.getByRole('columnheader', { name: 'Name' }).getAttribute('aria-sort')).toBeNull();
73
- });
74
-
75
- it('clicking a sortable header sorts ascending, then descending, then clears', () => {
76
- render(<DataTable columns={columns} data={data} getRowKey={(row) => row.id} />);
77
- const nameHeader = screen.getByRole('columnheader', { name: 'Name' });
78
- const button = within(nameHeader).getByRole('button');
79
-
80
- fireEvent.click(button);
81
- expect(rowsText()).toEqual(['Alpha', 'Bravo', 'Charlie']);
82
- expect(nameHeader.getAttribute('aria-sort')).toBe('ascending');
83
-
84
- fireEvent.click(button);
85
- expect(rowsText()).toEqual(['Charlie', 'Bravo', 'Alpha']);
86
- expect(nameHeader.getAttribute('aria-sort')).toBe('descending');
87
-
88
- fireEvent.click(button);
89
- expect(rowsText()).toEqual(['Charlie', 'Alpha', 'Bravo']);
90
- expect(nameHeader.getAttribute('aria-sort')).toBe('none');
91
- });
92
-
93
- it('sorts numeric columns numerically, not lexicographically', () => {
94
- render(<DataTable columns={columns} data={data} getRowKey={(row) => row.id} />);
95
- const installsHeader = screen.getByRole('columnheader', { name: 'Installs' });
96
- fireEvent.click(within(installsHeader).getByRole('button'));
97
- expect(rowsText()).toEqual(['Bravo', 'Charlie', 'Alpha']); // 5, 12, 30
98
- });
99
-
100
- it('switching the sort column resets to ascending', () => {
101
- render(<DataTable columns={columns} data={data} getRowKey={(row) => row.id} />);
102
- const nameHeader = screen.getByRole('columnheader', { name: 'Name' });
103
- const installsHeader = screen.getByRole('columnheader', { name: 'Installs' });
104
- fireEvent.click(within(nameHeader).getByRole('button'));
105
- fireEvent.click(within(nameHeader).getByRole('button')); // now descending
106
- fireEvent.click(within(installsHeader).getByRole('button'));
107
- expect(installsHeader.getAttribute('aria-sort')).toBe('ascending');
108
- expect(nameHeader.getAttribute('aria-sort')).toBe('none');
109
- });
110
-
111
- it('respects defaultSortKey/defaultSortDirection', () => {
112
- render(
113
- <DataTable
114
- columns={columns}
115
- data={data}
116
- getRowKey={(row) => row.id}
117
- defaultSortKey="installs"
118
- defaultSortDirection="desc"
119
- />,
120
- );
121
- expect(rowsText()).toEqual(['Alpha', 'Charlie', 'Bravo']); // 30, 12, 5
122
- });
123
- });
@@ -1,61 +0,0 @@
1
- /* DatePicker — trigger styled to match Input's height/border/radius/focus
2
- * ring for visual consistency as a form field. Kept in sync with Input's
3
- * own sizing by hand (36px rendered height via explicit height +
4
- * border-box, not a literal reuse of Input). */
5
-
6
- .trigger {
7
- display: flex;
8
- align-items: center;
9
- justify-content: space-between;
10
- gap: var(--sv-space-2);
11
- width: 100%;
12
- height: 36px;
13
- box-sizing: border-box;
14
- padding: 4px var(--sv-space-3);
15
- font-family: var(--sv-font-family);
16
- font-size: var(--sv-font-size-sm);
17
- line-height: 1.5;
18
- color: var(--sv-color-text-primary);
19
- background-color: var(--sv-color-surface);
20
- border: var(--sv-border-width-hairline) solid var(--sv-color-border-strong);
21
- border-radius: var(--sv-radius-md);
22
- cursor: pointer;
23
- transition:
24
- border-color 0.15s ease,
25
- box-shadow 0.15s ease;
26
- }
27
-
28
- /* Same iOS auto-zoom fix as Input — see its own module.css for why. */
29
- @media (pointer: coarse) {
30
- .trigger {
31
- font-size: var(--sv-font-size-md);
32
- }
33
- }
34
-
35
- .trigger:focus-visible {
36
- outline: none;
37
- border-color: var(--sv-color-accent);
38
- box-shadow: 0 0 0 2px var(--sv-color-focus-ring);
39
- }
40
-
41
- .trigger:disabled {
42
- opacity: 0.5;
43
- cursor: not-allowed;
44
- }
45
-
46
- .triggerValue {
47
- color: var(--sv-color-text-primary);
48
- }
49
-
50
- .triggerPlaceholder {
51
- color: var(--sv-color-text-muted);
52
- }
53
-
54
- .popoverBody {
55
- padding: var(--sv-space-3);
56
- }
57
-
58
- .drawerBody {
59
- padding: var(--sv-space-4);
60
- padding-bottom: max(var(--sv-space-4), env(safe-area-inset-bottom));
61
- }
@@ -1,103 +0,0 @@
1
- 'use client';
2
-
3
- import { useState } from 'react';
4
- import { useIsMobile } from '../../hooks';
5
- import { Calendar } from '../Calendar/Calendar';
6
- import { formatDateShort } from '../Calendar/dateUtils';
7
- import { Drawer } from '../Drawer/Drawer';
8
- import { Icon } from '../Icon/Icon';
9
- import { Popover } from '../Popover/Popover';
10
- import styles from './DatePicker.module.css';
11
-
12
- export interface DatePickerProps {
13
- value: Date | null;
14
- onChange: (date: Date) => void;
15
- minDate?: Date;
16
- maxDate?: Date;
17
- placeholder?: string;
18
- 'aria-label': string;
19
- disabled?: boolean;
20
- }
21
-
22
- // Wide enough for the 7-column Calendar grid (44px touch-target cells) plus
23
- // its own padding, without being so wide it looks odd as a Popover panel.
24
- const POPOVER_WIDTH = 320;
25
-
26
- /**
27
- * DatePicker — a form field pairing a compact trigger with `Calendar`:
28
- * `Popover` on desktop, a bottom-sheet `Drawer` on mobile (the platform's
29
- * standard adaptive-surface pattern, matching `Menu`). Date-only (decision
30
- * D6 in the mobile design-system plan) — time and range selection are future
31
- * scope; recurrence UI stays plugin-side.
32
- *
33
- * Unlike `Menu`, the trigger is built in rather than supplied by the caller
34
- * — a date picker is a form field (consistent with `Input`/`Select`), not an
35
- * arbitrary action-menu trigger.
36
- */
37
- export function DatePicker({
38
- value,
39
- onChange,
40
- minDate,
41
- maxDate,
42
- placeholder = 'Select date',
43
- 'aria-label': ariaLabel,
44
- disabled = false,
45
- }: DatePickerProps) {
46
- const [open, setOpen] = useState(false);
47
- const isMobile = useIsMobile();
48
-
49
- function handleSelect(date: Date) {
50
- onChange(date);
51
- setOpen(false);
52
- }
53
-
54
- const trigger = (
55
- <button
56
- type="button"
57
- className={styles.trigger}
58
- disabled={disabled}
59
- aria-label={ariaLabel}
60
- aria-haspopup="dialog"
61
- aria-expanded={open}
62
- onClick={() => setOpen((o) => !o)}
63
- >
64
- <span className={value ? styles.triggerValue : styles.triggerPlaceholder}>
65
- {value ? formatDateShort(value) : placeholder}
66
- </span>
67
- <Icon name="calendar" size="sm" aria-hidden />
68
- </button>
69
- );
70
-
71
- const calendar = (
72
- <Calendar
73
- value={value}
74
- onChange={handleSelect}
75
- minDate={minDate}
76
- maxDate={maxDate}
77
- aria-label={ariaLabel}
78
- />
79
- );
80
-
81
- if (isMobile) {
82
- return (
83
- <>
84
- {trigger}
85
- <Drawer open={open} onClose={() => setOpen(false)} aria-label={ariaLabel}>
86
- <div className={styles.drawerBody}>{calendar}</div>
87
- </Drawer>
88
- </>
89
- );
90
- }
91
-
92
- return (
93
- <Popover
94
- trigger={trigger}
95
- open={open}
96
- onClose={() => setOpen(false)}
97
- aria-label={ariaLabel}
98
- width={POPOVER_WIDTH}
99
- >
100
- <div className={styles.popoverBody}>{calendar}</div>
101
- </Popover>
102
- );
103
- }
@@ -1,89 +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 { DatePicker } from '../DatePicker';
5
-
6
- let mobile = false;
7
- function installMatchMedia() {
8
- vi.stubGlobal(
9
- 'matchMedia',
10
- vi.fn().mockImplementation((query: string) => ({
11
- // useIsMobile's query is '(max-width: ...)'; Drawer's own
12
- // prefers-reduced-motion check defaults to false — see Menu's
13
- // identical test setup for why.
14
- matches: query.includes('max-width') ? mobile : 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
- const JAN_15_2026 = new Date(2026, 0, 15);
26
-
27
- describe('DatePicker', () => {
28
- beforeEach(() => {
29
- mobile = false;
30
- installMatchMedia();
31
- });
32
- afterEach(() => {
33
- vi.unstubAllGlobals();
34
- cleanup();
35
- });
36
-
37
- it('shows the placeholder when no date is selected', () => {
38
- render(
39
- <DatePicker
40
- value={null}
41
- onChange={() => {}}
42
- placeholder="Pick a date"
43
- aria-label="Due date"
44
- />,
45
- );
46
- expect(screen.getByRole('button', { name: 'Due date' }).textContent).toContain('Pick a date');
47
- });
48
-
49
- it('shows the formatted value when a date is selected', () => {
50
- render(<DatePicker value={JAN_15_2026} onChange={() => {}} aria-label="Due date" />);
51
- expect(screen.getByRole('button', { name: 'Due date' }).textContent).toContain('Jan 15, 2026');
52
- });
53
-
54
- it('opens the calendar as a Popover on desktop', () => {
55
- render(<DatePicker value={null} onChange={() => {}} aria-label="Due date" />);
56
- fireEvent.click(screen.getByRole('button', { name: 'Due date' }));
57
- const panel = screen.getByRole('dialog', { name: 'Due date' });
58
- expect(panel.getAttribute('aria-modal')).toBe('false');
59
- expect(screen.getByRole('grid')).toBeTruthy();
60
- });
61
-
62
- it('opens the calendar as a Drawer on mobile', () => {
63
- mobile = true;
64
- installMatchMedia();
65
- render(<DatePicker value={null} onChange={() => {}} aria-label="Due date" />);
66
- fireEvent.click(screen.getByRole('button', { name: 'Due date' }));
67
- const panel = screen.getByRole('dialog', { name: 'Due date' });
68
- expect(panel.getAttribute('aria-modal')).toBe('true');
69
- expect(screen.getByRole('grid')).toBeTruthy();
70
- });
71
-
72
- it('calls onChange and closes the picker when a date is selected', () => {
73
- const onChange = vi.fn();
74
- render(<DatePicker value={JAN_15_2026} onChange={onChange} aria-label="Due date" />);
75
- fireEvent.click(screen.getByRole('button', { name: 'Due date' }));
76
- fireEvent.click(screen.getByRole('button', { name: /January 20, 2026/ }));
77
- expect(onChange).toHaveBeenCalledOnce();
78
- const called = onChange.mock.calls[0]?.[0] as Date;
79
- expect(called.getDate()).toBe(20);
80
- expect(screen.queryByRole('grid')).toBeNull();
81
- });
82
-
83
- it('disables the trigger when disabled', () => {
84
- render(<DatePicker value={null} onChange={() => {}} aria-label="Due date" disabled />);
85
- expect((screen.getByRole('button', { name: 'Due date' }) as HTMLButtonElement).disabled).toBe(
86
- true,
87
- );
88
- });
89
- });