@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,159 +0,0 @@
1
- 'use client';
2
-
3
- import type { ReactElement } from 'react';
4
- import { useIsMobile } from '../../hooks';
5
- import { Drawer } from '../Drawer/Drawer';
6
- import { Icon, type IconName } from '../Icon/Icon';
7
- import { Popover } from '../Popover/Popover';
8
- import styles from './Menu.module.css';
9
-
10
- export interface MenuItem {
11
- type?: 'item';
12
- label: string;
13
- onSelect: () => void;
14
- icon?: IconName;
15
- /** Styles the item as a destructive action (e.g. "Delete list"). */
16
- destructive?: boolean;
17
- disabled?: boolean;
18
- /**
19
- * Marks the item as one of a mutually-exclusive set (e.g. the active sort
20
- * order) — renders a leading checkmark and `role="menuitemradio"` instead
21
- * of `role="menuitem"`. Pass this on every item in the group, including
22
- * the unchecked ones, so their labels stay aligned with the checked one's
23
- * reserved checkmark gutter. Omit entirely for plain action items (e.g.
24
- * "Delete list") — they render with no reserved leading space at all.
25
- */
26
- checked?: boolean;
27
- }
28
-
29
- /** A non-interactive section heading above a run of items (e.g. "Sort by"). */
30
- export interface MenuLabel {
31
- type: 'label';
32
- label: string;
33
- }
34
-
35
- /** A visual divider between sections. */
36
- export interface MenuSeparator {
37
- type: 'separator';
38
- }
39
-
40
- export type MenuEntry = MenuItem | MenuLabel | MenuSeparator;
41
-
42
- export interface MenuProps {
43
- /** The element that opens the menu — rendered as-is; the caller wires its
44
- * onClick to flip `open` (same controlled pattern as `Popover`). */
45
- trigger: ReactElement;
46
- open: boolean;
47
- onClose: () => void;
48
- items: MenuEntry[];
49
- 'aria-label': string;
50
- /** Forwarded to `Popover` on desktop. Has no effect on mobile, where the
51
- * menu is always a full-width `Drawer`. */
52
- align?: 'left' | 'right';
53
- }
54
-
55
- /**
56
- * Menu — an adaptive action menu: `Popover` on desktop, a bottom-sheet
57
- * `Drawer` on mobile. Replaces the desktop-Popover/mobile-Drawer fork that
58
- * `⋯` action menus (list options, row actions) otherwise re-derive per
59
- * plugin. Same list of `items` renders in both presentations — only the
60
- * surrounding chrome (floating panel vs. bottom sheet) differs, matching the
61
- * platform's `useIsMobile` breakpoint.
62
- *
63
- * `items` accepts three entry shapes: a plain action (`MenuItem`, `type`
64
- * omitted or `'item'`), a non-interactive section heading (`MenuLabel`,
65
- * `type: 'label'`), and a `MenuSeparator` (`type: 'separator'`) — enough to
66
- * express grouped sections like "Filter" / "Sort by" above a run of
67
- * destructive actions, matching how native OS menus lay out mixed
68
- * action/selection groups.
69
- *
70
- * Selecting an item both closes the menu and calls its `onSelect` — a
71
- * consumer's `onSelect` never needs to call `onClose` itself.
72
- */
73
- /**
74
- * MenuEntries — the `<ul role="menu">` item list itself, factored out of
75
- * `Menu` so other adaptive-surface components (e.g. `ContextMenu`) can
76
- * render the exact same items/destructive/checked/icon markup inside their
77
- * own positioning shell, instead of re-deriving it and risking drift.
78
- */
79
- export function MenuEntries({
80
- items,
81
- onSelect,
82
- }: {
83
- items: MenuEntry[];
84
- /** Called after an item's own onSelect — typically the surface's onClose. */
85
- onSelect: (entry: MenuItem) => void;
86
- }) {
87
- return (
88
- <ul className={styles.list} role="menu">
89
- {items.map((entry, index) => {
90
- // Entries are a static, order-stable list per render — nothing
91
- // reorders — so an index key is safe here.
92
- if (entry.type === 'separator') {
93
- return <li key={index} role="separator" className={styles.separator} />;
94
- }
95
- if (entry.type === 'label') {
96
- return (
97
- <li key={index} role="presentation" className={styles.label}>
98
- {entry.label}
99
- </li>
100
- );
101
- }
102
- const isCheckable = entry.checked !== undefined;
103
- return (
104
- <li key={index} role="none">
105
- <button
106
- role={isCheckable ? 'menuitemradio' : 'menuitem'}
107
- aria-checked={isCheckable ? entry.checked : undefined}
108
- type="button"
109
- className={[styles.item, entry.destructive ? styles.itemDestructive : '']
110
- .filter(Boolean)
111
- .join(' ')}
112
- disabled={entry.disabled}
113
- onClick={() => onSelect(entry)}
114
- >
115
- {isCheckable && (
116
- <span className={styles.check} aria-hidden>
117
- {entry.checked && <Icon name="check" size="sm" aria-hidden />}
118
- </span>
119
- )}
120
- {entry.icon && <Icon name={entry.icon} size="sm" aria-hidden />}
121
- {entry.label}
122
- </button>
123
- </li>
124
- );
125
- })}
126
- </ul>
127
- );
128
- }
129
-
130
- export function Menu({ trigger, open, onClose, items, 'aria-label': ariaLabel, align }: MenuProps) {
131
- const isMobile = useIsMobile();
132
-
133
- const list = (
134
- <MenuEntries
135
- items={items}
136
- onSelect={(entry) => {
137
- onClose();
138
- entry.onSelect();
139
- }}
140
- />
141
- );
142
-
143
- if (isMobile) {
144
- return (
145
- <>
146
- {trigger}
147
- <Drawer open={open} onClose={onClose} aria-label={ariaLabel}>
148
- {list}
149
- </Drawer>
150
- </>
151
- );
152
- }
153
-
154
- return (
155
- <Popover trigger={trigger} open={open} onClose={onClose} aria-label={ariaLabel} align={align}>
156
- {list}
157
- </Popover>
158
- );
159
- }
@@ -1,197 +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 { Menu, type MenuItem } from '../Menu';
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: ...)'; everything else (e.g.
12
- // Drawer's prefers-reduced-motion check) defaults to false so the
13
- // mobile-branch Drawer isn't accidentally forced into the
14
- // reduced-motion path.
15
- matches: query.includes('max-width') ? mobile : false,
16
- media: query,
17
- addEventListener: vi.fn(),
18
- removeEventListener: vi.fn(),
19
- addListener: vi.fn(),
20
- removeListener: vi.fn(),
21
- dispatchEvent: vi.fn(),
22
- })),
23
- );
24
- }
25
-
26
- function installPointerCapture() {
27
- if (!Element.prototype.setPointerCapture) {
28
- Element.prototype.setPointerCapture = () => {};
29
- }
30
- }
31
-
32
- const items: MenuItem[] = [
33
- { label: 'Rename', onSelect: vi.fn() },
34
- { label: 'Delete', onSelect: vi.fn(), destructive: true },
35
- ];
36
-
37
- describe('Menu', () => {
38
- beforeEach(() => {
39
- mobile = false;
40
- installMatchMedia();
41
- installPointerCapture();
42
- });
43
- afterEach(() => {
44
- vi.unstubAllGlobals();
45
- cleanup();
46
- });
47
-
48
- it('renders the trigger regardless of open state', () => {
49
- render(
50
- <Menu
51
- trigger={<button type="button">Open menu</button>}
52
- open={false}
53
- onClose={() => {}}
54
- items={items}
55
- aria-label="List actions"
56
- />,
57
- );
58
- expect(screen.getByRole('button', { name: 'Open menu' })).toBeTruthy();
59
- });
60
-
61
- it('renders as a Popover on desktop', () => {
62
- render(
63
- <Menu
64
- trigger={<button type="button">Open menu</button>}
65
- open
66
- onClose={() => {}}
67
- items={items}
68
- aria-label="List actions"
69
- />,
70
- );
71
- const menu = screen.getByRole('dialog', { name: 'List actions' });
72
- // Popover's own aria-modal is explicitly false (non-modal floating panel).
73
- expect(menu.getAttribute('aria-modal')).toBe('false');
74
- expect(screen.getByRole('menuitem', { name: 'Rename' })).toBeTruthy();
75
- });
76
-
77
- it('renders as a Drawer on mobile', () => {
78
- mobile = true;
79
- installMatchMedia();
80
- render(
81
- <Menu
82
- trigger={<button type="button">Open menu</button>}
83
- open
84
- onClose={() => {}}
85
- items={items}
86
- aria-label="List actions"
87
- />,
88
- );
89
- const menu = screen.getByRole('dialog', { name: 'List actions' });
90
- expect(menu.getAttribute('aria-modal')).toBe('true');
91
- expect(screen.getByRole('menuitem', { name: 'Rename' })).toBeTruthy();
92
- });
93
-
94
- it('calls both onClose and the item onSelect when an item is chosen', () => {
95
- const onClose = vi.fn();
96
- const onSelect = vi.fn();
97
- render(
98
- <Menu
99
- trigger={<button type="button">Open menu</button>}
100
- open
101
- onClose={onClose}
102
- items={[{ label: 'Rename', onSelect }]}
103
- aria-label="List actions"
104
- />,
105
- );
106
- fireEvent.click(screen.getByRole('menuitem', { name: 'Rename' }));
107
- expect(onSelect).toHaveBeenCalledOnce();
108
- expect(onClose).toHaveBeenCalledOnce();
109
- });
110
-
111
- it('disables an item and does not fire onSelect when clicked', () => {
112
- const onSelect = vi.fn();
113
- render(
114
- <Menu
115
- trigger={<button type="button">Open menu</button>}
116
- open
117
- onClose={() => {}}
118
- items={[{ label: 'Archive', onSelect, disabled: true }]}
119
- aria-label="List actions"
120
- />,
121
- );
122
- fireEvent.click(screen.getByRole('menuitem', { name: 'Archive' }));
123
- expect(onSelect).not.toHaveBeenCalled();
124
- });
125
-
126
- it('marks a destructive item distinctly from a default one', () => {
127
- render(
128
- <Menu
129
- trigger={<button type="button">Open menu</button>}
130
- open
131
- onClose={() => {}}
132
- items={items}
133
- aria-label="List actions"
134
- />,
135
- );
136
- const renameClass = screen.getByRole('menuitem', { name: 'Rename' }).className;
137
- const deleteClass = screen.getByRole('menuitem', { name: 'Delete' }).className;
138
- expect(deleteClass).not.toBe(renameClass);
139
- });
140
-
141
- it('renders section labels and separators as non-interactive entries', () => {
142
- render(
143
- <Menu
144
- trigger={<button type="button">Open menu</button>}
145
- open
146
- onClose={() => {}}
147
- items={[
148
- { type: 'label', label: 'Sort by' },
149
- { label: 'Title', onSelect: vi.fn(), checked: true },
150
- { type: 'separator' },
151
- { label: 'Delete list', onSelect: vi.fn(), destructive: true },
152
- ]}
153
- aria-label="List actions"
154
- />,
155
- );
156
- expect(screen.getByText('Sort by').getAttribute('role')).toBe('presentation');
157
- expect(screen.getByRole('separator')).toBeTruthy();
158
- // Only the plain action item is a plain menuitem; the checkable one is a menuitemradio.
159
- expect(screen.getAllByRole('menuitem')).toHaveLength(1);
160
- });
161
-
162
- it('renders a checkable item as menuitemradio with aria-checked', () => {
163
- render(
164
- <Menu
165
- trigger={<button type="button">Open menu</button>}
166
- open
167
- onClose={() => {}}
168
- items={[
169
- { label: 'Manual', onSelect: vi.fn(), checked: false },
170
- { label: 'Title', onSelect: vi.fn(), checked: true },
171
- ]}
172
- aria-label="List actions"
173
- />,
174
- );
175
- const unchecked = screen.getByRole('menuitemradio', { name: 'Manual' });
176
- const checked = screen.getByRole('menuitemradio', { name: 'Title' });
177
- expect(unchecked.getAttribute('aria-checked')).toBe('false');
178
- expect(checked.getAttribute('aria-checked')).toBe('true');
179
- });
180
-
181
- it('closes and selects when a checkable item is clicked', () => {
182
- const onClose = vi.fn();
183
- const onSelect = vi.fn();
184
- render(
185
- <Menu
186
- trigger={<button type="button">Open menu</button>}
187
- open
188
- onClose={onClose}
189
- items={[{ label: 'Title', onSelect, checked: false }]}
190
- aria-label="List actions"
191
- />,
192
- );
193
- fireEvent.click(screen.getByRole('menuitemradio', { name: 'Title' }));
194
- expect(onSelect).toHaveBeenCalledOnce();
195
- expect(onClose).toHaveBeenCalledOnce();
196
- });
197
- });
@@ -1,52 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { Menubar } from './Menubar';
3
-
4
- const meta = {
5
- title: 'Components/Menubar',
6
- component: Menubar,
7
- parameters: {
8
- layout: 'padded',
9
- docs: {
10
- description: {
11
- component:
12
- "Desktop app-style menu bar (File/Edit/View...). A thin composition of NavigationMenu with MenuEntries as each item's flyout content — no positioning or list-rendering logic duplicated.",
13
- },
14
- },
15
- },
16
- } satisfies Meta<typeof Menubar>;
17
-
18
- export default meta;
19
- type Story = StoryObj<typeof meta>;
20
-
21
- // ---------------------------------------------------------------------------
22
-
23
- export const Default: Story = {
24
- args: {
25
- menus: [
26
- {
27
- label: 'File',
28
- items: [
29
- { label: 'New conversation', onSelect: () => {} },
30
- { label: 'Export', onSelect: () => {} },
31
- { type: 'separator' },
32
- { label: 'Close', onSelect: () => {} },
33
- ],
34
- },
35
- {
36
- label: 'Edit',
37
- items: [
38
- { label: 'Undo', onSelect: () => {} },
39
- { label: 'Redo', onSelect: () => {} },
40
- ],
41
- },
42
- {
43
- label: 'View',
44
- items: [
45
- { type: 'label', label: 'Layout' },
46
- { label: 'Compact', checked: false, onSelect: () => {} },
47
- { label: 'Comfortable', checked: true, onSelect: () => {} },
48
- ],
49
- },
50
- ],
51
- },
52
- };
@@ -1,42 +0,0 @@
1
- 'use client';
2
-
3
- import { NavigationMenu } from '../NavigationMenu/NavigationMenu';
4
- import { MenuEntries, type MenuEntry } from '../Menu/Menu';
5
-
6
- export interface MenubarMenu {
7
- label: string;
8
- items: MenuEntry[];
9
- }
10
-
11
- export interface MenubarProps {
12
- menus: MenubarMenu[];
13
- 'aria-label'?: string;
14
- }
15
-
16
- /**
17
- * Menubar — desktop app-style menu bar (File / Edit / View...). A thin
18
- * composition of `NavigationMenu` (top-level triggers, per-item flyout
19
- * positioning, hover-switches-when-one-is-open, arrow-key navigation) with
20
- * `MenuEntries` (the same item list markup `Menu`'s dropdowns use) as each
21
- * item's flyout content — no positioning or list-rendering logic
22
- * duplicated from either.
23
- */
24
- export function Menubar({ menus, 'aria-label': ariaLabel = 'Menu bar' }: MenubarProps) {
25
- return (
26
- <NavigationMenu
27
- aria-label={ariaLabel}
28
- items={menus.map((menu) => ({
29
- label: menu.label,
30
- content: (close: () => void) => (
31
- <MenuEntries
32
- items={menu.items}
33
- onSelect={(entry) => {
34
- close();
35
- entry.onSelect();
36
- }}
37
- />
38
- ),
39
- }))}
40
- />
41
- );
42
- }
@@ -1,45 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, describe, expect, it, vi } from 'vitest';
3
- import { cleanup, render, screen, fireEvent } from '@testing-library/react';
4
- import { Menubar } from '../Menubar';
5
-
6
- afterEach(cleanup);
7
-
8
- describe('Menubar', () => {
9
- it('opens a menu on trigger click, showing its items', () => {
10
- render(<Menubar menus={[{ label: 'File', items: [{ label: 'New', onSelect: () => {} }] }]} />);
11
- fireEvent.click(screen.getByRole('button', { name: 'File' }));
12
- expect(screen.getByRole('menuitem', { name: 'New' })).toBeDefined();
13
- });
14
-
15
- it('selecting an item calls onSelect and closes the menu', () => {
16
- const onSelect = vi.fn();
17
- render(<Menubar menus={[{ label: 'File', items: [{ label: 'New', onSelect }] }]} />);
18
- fireEvent.click(screen.getByRole('button', { name: 'File' }));
19
- fireEvent.click(screen.getByRole('menuitem', { name: 'New' }));
20
- expect(onSelect).toHaveBeenCalled();
21
- expect(screen.queryByRole('menuitem', { name: 'New' })).toBeNull();
22
- });
23
-
24
- it('switches directly between menus on hover once one is open, like a real menu bar', () => {
25
- render(
26
- <Menubar
27
- menus={[
28
- { label: 'File', items: [{ label: 'New', onSelect: () => {} }] },
29
- { label: 'Edit', items: [{ label: 'Undo', onSelect: () => {} }] },
30
- ]}
31
- />,
32
- );
33
- fireEvent.click(screen.getByRole('button', { name: 'File' }));
34
- expect(screen.getByRole('menuitem', { name: 'New' })).toBeDefined();
35
-
36
- fireEvent.mouseEnter(screen.getByRole('button', { name: 'Edit' }));
37
- expect(screen.getByRole('menuitem', { name: 'Undo' })).toBeDefined();
38
- expect(screen.queryByRole('menuitem', { name: 'New' })).toBeNull();
39
- });
40
-
41
- it('defaults to an accessible "Menu bar" label', () => {
42
- render(<Menubar menus={[{ label: 'File', items: [] }]} />);
43
- expect(screen.getByRole('navigation', { name: 'Menu bar' })).toBeDefined();
44
- });
45
- });
@@ -1,99 +0,0 @@
1
- .row {
2
- display: flex;
3
- flex-direction: column;
4
- max-width: 80%;
5
- }
6
-
7
- .user {
8
- align-self: flex-end;
9
- align-items: flex-end;
10
- }
11
-
12
- .assistant,
13
- .tool {
14
- align-self: flex-start;
15
- align-items: flex-start;
16
- }
17
-
18
- .bubble {
19
- padding: var(--sv-space-2) var(--sv-space-3);
20
- border-radius: var(--sv-radius-xl);
21
- font-size: var(--sv-font-size-sm);
22
- line-height: 1.5;
23
- white-space: pre-wrap;
24
- overflow-wrap: break-word;
25
- }
26
-
27
- .user .bubble {
28
- background: var(--sv-color-accent);
29
- color: var(--sv-color-text-on-accent);
30
- border-bottom-right-radius: var(--sv-radius-sm);
31
- }
32
-
33
- .assistant .bubble {
34
- background: var(--sv-color-surface-raised);
35
- border: 1px solid var(--sv-color-border);
36
- color: var(--sv-color-text-primary);
37
- border-bottom-left-radius: var(--sv-radius-sm);
38
- }
39
-
40
- .tool .bubble {
41
- background: var(--sv-color-surface-sunken);
42
- color: var(--sv-color-text-muted);
43
- font-family: var(--sv-font-family-mono);
44
- font-size: var(--sv-font-size-xs);
45
- border-bottom-left-radius: var(--sv-radius-sm);
46
- }
47
-
48
- .actions {
49
- display: flex;
50
- gap: var(--sv-space-2);
51
- margin-top: var(--sv-space-1);
52
- font-size: var(--sv-font-size-caption);
53
- color: var(--sv-color-text-muted);
54
- }
55
-
56
- /* Typing indicator — three dots, staggered pulse. */
57
- .typingDots {
58
- display: inline-flex;
59
- align-items: center;
60
- gap: 3px;
61
- padding: var(--sv-space-1) 0;
62
- }
63
-
64
- .dot {
65
- width: 6px;
66
- height: 6px;
67
- border-radius: var(--sv-radius-full);
68
- background: currentColor;
69
- opacity: 0.4;
70
- animation: typing-pulse 1.2s ease-in-out infinite;
71
- }
72
-
73
- .dot:nth-child(2) {
74
- animation-delay: 0.2s;
75
- }
76
-
77
- .dot:nth-child(3) {
78
- animation-delay: 0.4s;
79
- }
80
-
81
- @keyframes typing-pulse {
82
- 0%,
83
- 80%,
84
- 100% {
85
- opacity: 0.4;
86
- transform: scale(0.85);
87
- }
88
- 40% {
89
- opacity: 1;
90
- transform: scale(1);
91
- }
92
- }
93
-
94
- @media (prefers-reduced-motion: reduce) {
95
- .dot {
96
- animation: none;
97
- opacity: 0.7;
98
- }
99
- }
@@ -1,79 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { Message } from './Message';
3
-
4
- const meta = {
5
- title: 'Components/Message',
6
- component: Message,
7
- parameters: {
8
- layout: 'padded',
9
- docs: {
10
- description: {
11
- component:
12
- "A single chat turn, for the Sovereign Harness assistant (RFC 0040). `sender` is one of user/assistant/tool — matching harness_messages (named `sender`, not `role`, to avoid colliding with the ARIA role attribute). Content is caller-controlled ReactNode; markdown rendering, if any, is the consumer's choice.",
13
- },
14
- },
15
- },
16
- args: { sender: 'assistant', children: 'Your task is due Thursday.' },
17
- } satisfies Meta<typeof Message>;
18
-
19
- export default meta;
20
- type Story = StoryObj<typeof meta>;
21
-
22
- // ---------------------------------------------------------------------------
23
-
24
- export const User: Story = {
25
- args: { sender: 'user', children: 'What tasks do I have due this week?' },
26
- };
27
-
28
- export const Assistant: Story = {
29
- args: { sender: 'assistant' },
30
- };
31
-
32
- export const Tool: Story = {
33
- args: { sender: 'tool', children: 'query_tasks({ dueBefore: "2026-08-01" }) → 3 results' },
34
- };
35
-
36
- export const Pending: Story = {
37
- args: { sender: 'assistant', pending: true },
38
- };
39
-
40
- export const WithActions: Story = {
41
- args: {
42
- sender: 'assistant',
43
- actions: (
44
- <>
45
- <button type="button" style={{ all: 'unset', cursor: 'pointer' }}>
46
- Forget this
47
- </button>
48
- <span>·</span>
49
- <button type="button" style={{ all: 'unset', cursor: 'pointer' }}>
50
- Copy
51
- </button>
52
- </>
53
- ),
54
- },
55
- };
56
-
57
- export const Conversation: Story = {
58
- render: () => (
59
- <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
60
- <Message sender="user">What tasks do I have due this week?</Message>
61
- <Message sender="tool">
62
- query_tasks({'{'} dueBefore: "2026-08-01" {'}'}) → 3 results
63
- </Message>
64
- <Message
65
- sender="assistant"
66
- actions={
67
- <button type="button" style={{ all: 'unset', cursor: 'pointer' }}>
68
- Forget this
69
- </button>
70
- }
71
- >
72
- You have 3 tasks due this week: review the Q3 report, reply to the design feedback thread,
73
- and renew the domain registration.
74
- </Message>
75
- <Message sender="user">Thanks!</Message>
76
- <Message sender="assistant" pending />
77
- </div>
78
- ),
79
- };