@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,41 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import styles from './Message.module.css';
3
-
4
- export type MessageSender = 'user' | 'assistant' | 'tool';
5
-
6
- export interface MessageProps {
7
- /** Matches the three roles Sovereign Harness stores per RFC 0040:
8
- * user, assistant, and tool messages. Named `sender`, not `role`, to
9
- * avoid colliding with the ARIA `role` attribute in JSX tooling. */
10
- sender: MessageSender;
11
- children?: ReactNode;
12
- /** Shows a "thinking" indicator instead of children — before the first
13
- * token of a streaming response arrives. Once content starts streaming
14
- * in, pass it as children and stop passing `pending`. */
15
- pending?: boolean;
16
- /** Rendered in a small row below the bubble — e.g. "Forget this" (RFC
17
- * 0040's per-message memory action), "Copy", "Regenerate". */
18
- actions?: ReactNode;
19
- className?: string;
20
- }
21
-
22
- /** Message — a single chat turn. Content is caller-controlled `ReactNode`
23
- * (markdown rendering, if any, is the consumer's choice, not baked in here). */
24
- export function Message({ sender, children, pending, actions, className }: MessageProps) {
25
- return (
26
- <div className={[styles.row, styles[sender], className].filter(Boolean).join(' ')}>
27
- <div className={styles.bubble}>
28
- {pending ? (
29
- <span className={styles.typingDots} aria-label="Thinking">
30
- <span className={styles.dot} />
31
- <span className={styles.dot} />
32
- <span className={styles.dot} />
33
- </span>
34
- ) : (
35
- children
36
- )}
37
- </div>
38
- {actions && !pending && <div className={styles.actions}>{actions}</div>}
39
- </div>
40
- );
41
- }
@@ -1,46 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import { cleanup, render, screen } from '@testing-library/react';
4
- import { Message } from '../Message';
5
-
6
- afterEach(cleanup);
7
-
8
- describe('Message', () => {
9
- it('renders children content', () => {
10
- render(<Message sender="user">Hello there</Message>);
11
- expect(screen.getByText('Hello there')).toBeDefined();
12
- });
13
-
14
- it('shows a "Thinking" indicator instead of children when pending', () => {
15
- render(
16
- <Message sender="assistant" pending>
17
- Not shown yet
18
- </Message>,
19
- );
20
- expect(screen.getByLabelText('Thinking')).toBeDefined();
21
- expect(screen.queryByText('Not shown yet')).toBeNull();
22
- });
23
-
24
- it('renders actions below the bubble when given and not pending', () => {
25
- render(
26
- <Message sender="assistant" actions={<button type="button">Forget this</button>}>
27
- Your task is due Thursday.
28
- </Message>,
29
- );
30
- expect(screen.getByRole('button', { name: 'Forget this' })).toBeDefined();
31
- });
32
-
33
- it('hides actions while pending', () => {
34
- render(
35
- <Message sender="assistant" pending actions={<button type="button">Forget this</button>}>
36
- content
37
- </Message>,
38
- );
39
- expect(screen.queryByRole('button', { name: 'Forget this' })).toBeNull();
40
- });
41
-
42
- it.each(['user', 'assistant', 'tool'] as const)('renders the %s sender', (sender) => {
43
- render(<Message sender={sender}>content</Message>);
44
- expect(screen.getByText('content')).toBeDefined();
45
- });
46
- });
@@ -1,54 +0,0 @@
1
- .root {
2
- position: relative;
3
- height: 100%;
4
- min-height: 0;
5
- }
6
-
7
- .scrollContainer {
8
- height: 100%;
9
- overflow-y: auto;
10
- overscroll-behavior: contain;
11
- display: flex;
12
- flex-direction: column;
13
- gap: var(--sv-space-3);
14
- padding: var(--sv-space-3);
15
- scrollbar-width: thin;
16
- scrollbar-color: var(--sv-color-border-strong) transparent;
17
- }
18
-
19
- .scrollContainer::-webkit-scrollbar {
20
- width: 8px;
21
- }
22
-
23
- .scrollContainer::-webkit-scrollbar-thumb {
24
- background: var(--sv-color-border-strong);
25
- border-radius: var(--sv-radius-full);
26
- }
27
-
28
- .jumpButton {
29
- position: absolute;
30
- bottom: var(--sv-space-3);
31
- left: 50%;
32
- transform: translateX(-50%);
33
- padding: var(--sv-space-1) var(--sv-space-3);
34
- border: 1px solid var(--sv-color-border);
35
- border-radius: var(--sv-radius-full);
36
- background: var(--sv-color-surface-raised);
37
- box-shadow: var(--sv-shadow-popover);
38
- color: var(--sv-color-text-primary);
39
- font-family: var(--sv-font-family);
40
- font-size: var(--sv-font-size-caption);
41
- font-weight: var(--sv-font-weight-medium);
42
- cursor: pointer;
43
- }
44
-
45
- .jumpButton:focus-visible {
46
- outline: 2px solid var(--sv-color-focus-ring);
47
- outline-offset: 2px;
48
- }
49
-
50
- @media (hover: hover) {
51
- .jumpButton:hover {
52
- background: var(--sv-color-surface-sunken);
53
- }
54
- }
@@ -1,84 +0,0 @@
1
- import { useState } from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react-vite';
3
- import { MessageScroller } from './MessageScroller';
4
- import { Message } from '../Message/Message';
5
- import { Button } from '../Button/Button';
6
-
7
- const meta = {
8
- title: 'Components/MessageScroller',
9
- component: MessageScroller,
10
- parameters: {
11
- layout: 'fullscreen',
12
- docs: {
13
- description: {
14
- component:
15
- 'Auto-scrolling chat container. Scrolls to the newest message while the user is near the bottom; if they\'ve scrolled up, new content shows a "New messages" button instead of yanking them back down.',
16
- },
17
- },
18
- },
19
- args: { children: null },
20
- } satisfies Meta<typeof MessageScroller>;
21
-
22
- export default meta;
23
- type Story = StoryObj<typeof meta>;
24
-
25
- // ---------------------------------------------------------------------------
26
-
27
- const SEED_MESSAGES = [
28
- { sender: 'user' as const, text: 'What tasks do I have due this week?' },
29
- {
30
- sender: 'assistant' as const,
31
- text: 'You have 3 tasks due this week: review the Q3 report, reply to the design feedback thread, and renew the domain registration.',
32
- },
33
- { sender: 'user' as const, text: 'Can you summarize the Q3 report task?' },
34
- {
35
- sender: 'assistant' as const,
36
- text: 'It\'s tagged "high priority" and due Thursday — created from your Notes plugin two days ago.',
37
- },
38
- ];
39
-
40
- export const Interactive: Story = {
41
- render: () => {
42
- const [messages, setMessages] = useState(SEED_MESSAGES);
43
- return (
44
- <div style={{ height: 420, display: 'flex', flexDirection: 'column', maxWidth: 480 }}>
45
- <div style={{ flex: 1, minHeight: 0, border: '1px solid var(--sv-color-border)' }}>
46
- <MessageScroller>
47
- {messages.map((m, i) => (
48
- <Message key={i} sender={m.sender}>
49
- {m.text}
50
- </Message>
51
- ))}
52
- </MessageScroller>
53
- </div>
54
- <div style={{ padding: 'var(--sv-space-3)' }}>
55
- <Button
56
- size="sm"
57
- onClick={() =>
58
- setMessages((prev) => [
59
- ...prev,
60
- { sender: 'assistant', text: `New message #${prev.length + 1}` },
61
- ])
62
- }
63
- >
64
- Add message
65
- </Button>
66
- </div>
67
- </div>
68
- );
69
- },
70
- };
71
-
72
- export const LongHistory: Story = {
73
- render: () => (
74
- <div style={{ height: 420, maxWidth: 480, border: '1px solid var(--sv-color-border)' }}>
75
- <MessageScroller>
76
- {Array.from({ length: 30 }, (_, i) => (
77
- <Message key={i} sender={i % 2 === 0 ? 'user' : 'assistant'}>
78
- Message {i + 1}
79
- </Message>
80
- ))}
81
- </MessageScroller>
82
- </div>
83
- ),
84
- };
@@ -1,72 +0,0 @@
1
- 'use client';
2
-
3
- import { useEffect, useRef, useState } from 'react';
4
- import type { ReactNode, UIEvent } from 'react';
5
- import styles from './MessageScroller.module.css';
6
-
7
- export interface MessageScrollerProps {
8
- children: ReactNode;
9
- className?: string;
10
- }
11
-
12
- const NEAR_BOTTOM_THRESHOLD_PX = 80;
13
-
14
- /**
15
- * MessageScroller — auto-scrolling chat container.
16
- *
17
- * Scrolls to the newest message automatically, but only while the user is
18
- * already near the bottom. If they've scrolled up to read history, new
19
- * content does not yank them back down — a "New messages" button appears
20
- * instead, matching the pattern every chat product (Slack, Discord,
21
- * ChatGPT) already uses.
22
- */
23
- export function MessageScroller({ children, className }: MessageScrollerProps) {
24
- const containerRef = useRef<HTMLDivElement>(null);
25
- // A ref, not state: reading the user's scroll position must not itself
26
- // retrigger the auto-scroll effect below, or scrolling back near the
27
- // bottom manually would immediately snap the container the rest of the
28
- // way — fighting the user's own scroll input.
29
- const isNearBottomRef = useRef(true);
30
- const [hasNewMessages, setHasNewMessages] = useState(false);
31
-
32
- useEffect(() => {
33
- const el = containerRef.current;
34
- if (!el) return;
35
- if (isNearBottomRef.current) {
36
- el.scrollTop = el.scrollHeight;
37
- setHasNewMessages(false);
38
- } else {
39
- setHasNewMessages(true);
40
- }
41
- }, [children]);
42
-
43
- function handleScroll(event: UIEvent<HTMLDivElement>) {
44
- const el = event.currentTarget;
45
- const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
46
- isNearBottomRef.current = distanceFromBottom < NEAR_BOTTOM_THRESHOLD_PX;
47
- if (isNearBottomRef.current) {
48
- setHasNewMessages(false);
49
- }
50
- }
51
-
52
- function scrollToBottom() {
53
- const el = containerRef.current;
54
- if (!el) return;
55
- el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' });
56
- isNearBottomRef.current = true;
57
- setHasNewMessages(false);
58
- }
59
-
60
- return (
61
- <div className={[styles.root, className].filter(Boolean).join(' ')}>
62
- <div className={styles.scrollContainer} ref={containerRef} onScroll={handleScroll}>
63
- {children}
64
- </div>
65
- {hasNewMessages && (
66
- <button type="button" className={styles.jumpButton} onClick={scrollToBottom}>
67
- New messages ↓
68
- </button>
69
- )}
70
- </div>
71
- );
72
- }
@@ -1,105 +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 { MessageScroller } from '../MessageScroller';
5
-
6
- afterEach(cleanup);
7
-
8
- /** jsdom doesn't implement layout, so scrollHeight/clientHeight are always 0
9
- * unless stubbed. Mirrors the common pattern for testing scroll behavior. */
10
- function stubScrollMetrics(
11
- el: HTMLElement,
12
- {
13
- scrollHeight,
14
- clientHeight,
15
- scrollTop,
16
- }: {
17
- scrollHeight: number;
18
- clientHeight: number;
19
- scrollTop: number;
20
- },
21
- ) {
22
- Object.defineProperty(el, 'scrollHeight', { value: scrollHeight, configurable: true });
23
- Object.defineProperty(el, 'clientHeight', { value: clientHeight, configurable: true });
24
- Object.defineProperty(el, 'scrollTop', { value: scrollTop, writable: true, configurable: true });
25
- }
26
-
27
- describe('MessageScroller', () => {
28
- it('auto-scrolls to the bottom when near-bottom and children change', () => {
29
- const { container, rerender } = render(
30
- <MessageScroller>
31
- <div>message 1</div>
32
- </MessageScroller>,
33
- );
34
- const scrollEl = container.querySelector('[class*="scrollContainer"]') as HTMLElement;
35
- stubScrollMetrics(scrollEl, { scrollHeight: 500, clientHeight: 200, scrollTop: 0 });
36
-
37
- rerender(
38
- <MessageScroller>
39
- <div>message 1</div>
40
- <div>message 2</div>
41
- </MessageScroller>,
42
- );
43
-
44
- expect(scrollEl.scrollTop).toBe(500);
45
- expect(screen.queryByText('New messages ↓')).toBeNull();
46
- });
47
-
48
- it('shows a "New messages" button instead of auto-scrolling when scrolled up', () => {
49
- const { container, rerender } = render(
50
- <MessageScroller>
51
- <div>message 1</div>
52
- </MessageScroller>,
53
- );
54
- const scrollEl = container.querySelector('[class*="scrollContainer"]') as HTMLElement;
55
- // Simulate the user having scrolled up, far from the bottom.
56
- stubScrollMetrics(scrollEl, { scrollHeight: 500, clientHeight: 200, scrollTop: 0 });
57
- fireEvent.scroll(scrollEl);
58
-
59
- rerender(
60
- <MessageScroller>
61
- <div>message 1</div>
62
- <div>message 2</div>
63
- </MessageScroller>,
64
- );
65
-
66
- expect(screen.getByText('New messages ↓')).toBeDefined();
67
- });
68
-
69
- it('scrolling back near the bottom does not force scrollTop (no fighting the user)', () => {
70
- const { container } = render(
71
- <MessageScroller>
72
- <div>message 1</div>
73
- </MessageScroller>,
74
- );
75
- const scrollEl = container.querySelector('[class*="scrollContainer"]') as HTMLElement;
76
- stubScrollMetrics(scrollEl, { scrollHeight: 500, clientHeight: 200, scrollTop: 450 });
77
- fireEvent.scroll(scrollEl);
78
-
79
- expect(scrollEl.scrollTop).toBe(450);
80
- });
81
-
82
- it('clicking the jump button scrolls to bottom and hides the button', () => {
83
- const { container, rerender } = render(
84
- <MessageScroller>
85
- <div>message 1</div>
86
- </MessageScroller>,
87
- );
88
- const scrollEl = container.querySelector('[class*="scrollContainer"]') as HTMLElement;
89
- stubScrollMetrics(scrollEl, { scrollHeight: 500, clientHeight: 200, scrollTop: 0 });
90
- fireEvent.scroll(scrollEl);
91
- rerender(
92
- <MessageScroller>
93
- <div>message 1</div>
94
- <div>message 2</div>
95
- </MessageScroller>,
96
- );
97
- expect(screen.getByText('New messages ↓')).toBeDefined();
98
-
99
- scrollEl.scrollTo = vi.fn();
100
- fireEvent.click(screen.getByText('New messages ↓'));
101
-
102
- expect(scrollEl.scrollTo).toHaveBeenCalledWith({ top: 500, behavior: 'smooth' });
103
- expect(screen.queryByText('New messages ↓')).toBeNull();
104
- });
105
- });
@@ -1,81 +0,0 @@
1
- /* Matches the runtime shell's own Apps drawer grid exactly
2
- (runtime/app/(platform)/_components/MobileNav.module.css's .drawerGrid/
3
- .drawerGridItem/.drawerGridIcon/.drawerGridName) — this component is
4
- meant to replace that hand-rolled markup for any consumer building its
5
- own Apps-style launcher. No header row — see the component's own doc
6
- comment for why. */
7
-
8
- .grid {
9
- list-style: none;
10
- margin: 0;
11
- /* Drawer's own grab handle already reserves a 44px touch target above this
12
- — no extra top padding needed beyond a touch of breathing room. Bottom
13
- gets noticeably more: with no header row to separate the grid from the
14
- handle, a tight top/bottom balance read as top-heavy (grid crowding the
15
- handle isn't the issue; the *last* row crowding the panel's bottom
16
- edge/safe-area is). Drawer's own panel already adds
17
- env(safe-area-inset-bottom) below everything, so this is on top of that,
18
- not instead of it. */
19
- padding: var(--sv-space-1) var(--sv-space-4) var(--sv-space-10);
20
- display: grid;
21
- grid-template-columns: repeat(3, 1fr);
22
- row-gap: var(--sv-space-5);
23
- }
24
-
25
- .gridItem {
26
- display: flex;
27
- flex-direction: column;
28
- align-items: center;
29
- gap: var(--sv-space-2);
30
- padding: var(--sv-space-1);
31
- border: none;
32
- background: none;
33
- text-decoration: none;
34
- color: var(--sv-color-text-primary);
35
- font: inherit;
36
- cursor: pointer;
37
- width: 100%;
38
- }
39
-
40
- @media (hover: hover) {
41
- .gridItem:hover .gridIcon {
42
- background: var(--sv-color-border);
43
- }
44
- }
45
-
46
- .gridItem:focus-visible {
47
- outline: 2px solid var(--sv-color-focus-ring);
48
- outline-offset: 2px;
49
- border-radius: var(--sv-radius-md);
50
- }
51
-
52
- /* color: text-primary, not text-muted — the reference's own drawerGridIcon
53
- uses text-muted only as its monogram-fallback text color for <img>-less
54
- plugin icons (raster <img> icons don't inherit CSS color at all, so that
55
- value never actually painted a real icon). Every tile here renders a real
56
- stroke icon via the Icon component (currentColor), which does inherit —
57
- matching the reference's own explicit override for that exact case
58
- (.drawerGridIconSettings, used by its Console tile) rather than the
59
- fallback default. */
60
- .gridIcon {
61
- display: flex;
62
- align-items: center;
63
- justify-content: center;
64
- width: 56px;
65
- height: 56px;
66
- border-radius: 14px;
67
- background: var(--sv-color-surface-sunken);
68
- font-size: var(--sv-font-size-sm);
69
- font-weight: var(--sv-font-weight-semibold);
70
- color: var(--sv-color-text-primary);
71
- transition: background 0.1s;
72
- }
73
-
74
- .gridName {
75
- font-size: var(--sv-font-size-sm);
76
- text-align: center;
77
- color: var(--sv-color-text-primary);
78
- line-height: 1.3;
79
- word-break: break-word;
80
- max-width: 80px;
81
- }
@@ -1,78 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import { Drawer } from '../Drawer/Drawer';
3
- import styles from './MobileAppsDrawer.module.css';
4
-
5
- export interface MobileAppsDrawerItem {
6
- /** Stable identity for this tile — used as the React key. */
7
- key: string;
8
- icon: ReactNode;
9
- label: string;
10
- /** Renders an `<a>` when set; otherwise a `<button>` calling `onClick`. */
11
- href?: string;
12
- onClick?: () => void;
13
- }
14
-
15
- export interface MobileAppsDrawerProps {
16
- open: boolean;
17
- onClose: () => void;
18
- /** Accessible name for the drawer panel — required since there's no
19
- * visible title to fall back to (Drawer's grab handle plus swipe-down /
20
- * scrim-tap already cover dismissal, so no header row is rendered). */
21
- 'aria-label': string;
22
- /** The grid tiles — supplied by the consumer (e.g. installed plugins,
23
- * a plugin's own sections). MobileAppsDrawer owns only the drawer
24
- * chrome/grid layout, never the item list itself. */
25
- items: MobileAppsDrawerItem[];
26
- }
27
-
28
- function DrawerGridTile({ icon, label, href, onClick }: Omit<MobileAppsDrawerItem, 'key'>) {
29
- const content = (
30
- <>
31
- <span className={styles.gridIcon} aria-hidden="true">
32
- {icon}
33
- </span>
34
- <span className={styles.gridName}>{label}</span>
35
- </>
36
- );
37
- if (href) {
38
- return (
39
- <a href={href} className={styles.gridItem} onClick={onClick}>
40
- {content}
41
- </a>
42
- );
43
- }
44
- return (
45
- <button type="button" className={styles.gridItem} onClick={onClick}>
46
- {content}
47
- </button>
48
- );
49
- }
50
-
51
- /**
52
- * The mobile "Apps" drawer: a bottom sheet with a 3-column grid of icon
53
- * tiles — same tile size (56px, radius 14px) and grid layout as the runtime
54
- * shell's own Apps drawer (MobileNav's Drawer content), generalized so the
55
- * tile list comes from the consumer (the shell passes installed plugins; a
56
- * plugin composing its own MobileFooter launcher passes whatever its own
57
- * "apps" are, e.g. a section index) rather than being hardcoded to plugins
58
- * specifically. No header row (title/close button) — Drawer's own grab
59
- * handle plus swipe-down/scrim-tap dismissal are enough, and a header ate
60
- * into the limited vertical space a launcher grid needs most.
61
- */
62
- export function MobileAppsDrawer({ open, onClose, items, ...rest }: MobileAppsDrawerProps) {
63
- const ariaLabel = rest['aria-label'];
64
-
65
- return (
66
- <Drawer open={open} onClose={onClose} aria-label={ariaLabel}>
67
- <nav aria-label={ariaLabel}>
68
- <ul className={styles.grid}>
69
- {items.map(({ key, ...item }) => (
70
- <li key={key}>
71
- <DrawerGridTile key={key} {...item} />
72
- </li>
73
- ))}
74
- </ul>
75
- </nav>
76
- </Drawer>
77
- );
78
- }
@@ -1,80 +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 { MobileAppsDrawer } from '../MobileAppsDrawer';
5
-
6
- // Drawer's exit animation reads prefers-reduced-motion via matchMedia, which
7
- // jsdom does not implement — see Drawer's own test for the full rationale.
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
- function installPointerCapture() {
24
- if (!Element.prototype.setPointerCapture) {
25
- Element.prototype.setPointerCapture = () => {};
26
- }
27
- if (!Element.prototype.releasePointerCapture) {
28
- Element.prototype.releasePointerCapture = () => {};
29
- }
30
- }
31
-
32
- const items = [
33
- { key: 'home', icon: <span>icon</span>, label: 'Home', href: '/home' },
34
- { key: 'notes', icon: <span>icon</span>, label: 'Notes', onClick: vi.fn() },
35
- ];
36
-
37
- describe('MobileAppsDrawer', () => {
38
- beforeEach(() => {
39
- installMatchMedia();
40
- installPointerCapture();
41
- });
42
- afterEach(() => {
43
- vi.unstubAllGlobals();
44
- cleanup();
45
- });
46
-
47
- it('renders nothing when closed', () => {
48
- render(
49
- <MobileAppsDrawer open={false} onClose={() => {}} aria-label="Sections" items={items} />,
50
- );
51
- expect(screen.queryByRole('dialog')).toBeNull();
52
- });
53
-
54
- it('renders every item when open, with no header title or close button', () => {
55
- render(<MobileAppsDrawer open onClose={() => {}} aria-label="Sections" items={items} />);
56
-
57
- expect(screen.getByRole('dialog', { name: 'Sections' })).toBeDefined();
58
- expect(screen.getByText('Home')).toBeDefined();
59
- expect(screen.getByText('Notes')).toBeDefined();
60
- expect(screen.queryByRole('button', { name: 'Close' })).toBeNull();
61
- });
62
-
63
- it('renders an href item as a link and an onClick item as a button', () => {
64
- render(<MobileAppsDrawer open onClose={() => {}} aria-label="Sections" items={items} />);
65
-
66
- const link = screen.getByText('Home').closest('a');
67
- expect(link).not.toBeNull();
68
- expect(link?.getAttribute('href')).toBe('/home');
69
-
70
- const button = screen.getByText('Notes').closest('button');
71
- expect(button).not.toBeNull();
72
- });
73
-
74
- it('calls the item onClick handler when pressed', () => {
75
- render(<MobileAppsDrawer open onClose={() => {}} aria-label="Sections" items={items} />);
76
-
77
- fireEvent.click(screen.getByText('Notes'));
78
- expect(items[1]?.onClick).toHaveBeenCalledTimes(1);
79
- });
80
- });