@sovereignfs/ui 0.83.1 → 0.89.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (556) hide show
  1. package/LICENSE +373 -661
  2. package/NOTICE +8 -0
  3. package/README.md +4 -6
  4. package/dist/AppsLauncher.module.css +6 -0
  5. package/dist/Button.module.css +5 -0
  6. package/dist/Card.module.css +6 -0
  7. package/dist/CardTile.module.css +6 -0
  8. package/dist/CheckableListRow.module.css +8 -0
  9. package/dist/Checkbox.module.css +8 -0
  10. package/dist/CodeTextarea.module.css +6 -0
  11. package/dist/ColorPicker.module.css +6 -0
  12. package/dist/Combobox.module.css +6 -0
  13. package/dist/Command.module.css +6 -0
  14. package/dist/ConfirmDialog.module.css +6 -0
  15. package/dist/DatePicker.module.css +6 -0
  16. package/dist/Dialog.module.css +1 -1
  17. package/dist/DragHandleRow.module.css +6 -0
  18. package/dist/FileDropzone.module.css +25 -1
  19. package/dist/Header.module.css +6 -0
  20. package/dist/IconPicker.module.css +14 -4
  21. package/dist/Input.module.css +6 -0
  22. package/dist/LegalLinks.module.css +9 -2
  23. package/dist/Markdown.module.css +5 -0
  24. package/dist/Message.module.css +9 -0
  25. package/dist/MobileAppsDrawer.module.css +9 -5
  26. package/dist/MobileFooter.module.css +6 -0
  27. package/dist/NavList.module.css +11 -2
  28. package/dist/NavTabs.module.css +7 -1
  29. package/dist/NotificationsPanel.module.css +10 -0
  30. package/dist/QrCode.module.css +17 -0
  31. package/dist/QuantityStepper.module.css +4 -2
  32. package/dist/RadioGroup.module.css +6 -0
  33. package/dist/SegmentedControl.module.css +6 -0
  34. package/dist/Select.module.css +6 -0
  35. package/dist/Sheet.module.css +16 -1
  36. package/dist/SplitPane.module.css +1 -1
  37. package/dist/StepStrip.module.css +5 -3
  38. package/dist/SuggestionInput.module.css +12 -1
  39. package/dist/SwipableMobileCarouselDots.module.css +6 -0
  40. package/dist/SystemBanner.module.css +6 -0
  41. package/dist/Tabs.module.css +6 -0
  42. package/dist/TagInput.module.css +6 -0
  43. package/dist/Textarea.module.css +6 -0
  44. package/dist/Toast.module.css +5 -0
  45. package/dist/Toggle.module.css +7 -0
  46. package/dist/Tooltip.module.css +6 -0
  47. package/dist/UserMenu.module.css +5 -0
  48. package/dist/fonts/OFL.txt +93 -0
  49. package/dist/fonts/hanken-grotesk-cyrillic-ext-wght-normal.woff2 +0 -0
  50. package/dist/fonts/hanken-grotesk-latin-ext-wght-normal.woff2 +0 -0
  51. package/dist/fonts/hanken-grotesk-latin-wght-normal.woff2 +0 -0
  52. package/dist/fonts/hanken-grotesk-vietnamese-wght-normal.woff2 +0 -0
  53. package/dist/index.d.ts +121 -43
  54. package/dist/index.js +1410 -1152
  55. package/dist/tokens/fonts.css +53 -0
  56. package/dist/tokens/primitives.css +12 -12
  57. package/dist/tokens.css +2 -1
  58. package/package.json +24 -13
  59. package/src/__tests__/motion.test.tsx +0 -105
  60. package/src/__tests__/package-json.test.ts +0 -8
  61. package/src/components/Accordion/Accordion.module.css +0 -3
  62. package/src/components/Accordion/Accordion.stories.tsx +0 -110
  63. package/src/components/Accordion/Accordion.tsx +0 -53
  64. package/src/components/Accordion/__tests__/Accordion.test.tsx +0 -61
  65. package/src/components/Alert/Alert.module.css +0 -62
  66. package/src/components/Alert/Alert.stories.tsx +0 -96
  67. package/src/components/Alert/Alert.tsx +0 -58
  68. package/src/components/Alert/__tests__/Alert.test.tsx +0 -75
  69. package/src/components/AppsLauncher/AppsLauncher.module.css +0 -96
  70. package/src/components/AppsLauncher/AppsLauncher.stories.tsx +0 -58
  71. package/src/components/AppsLauncher/AppsLauncher.tsx +0 -117
  72. package/src/components/AppsLauncher/__tests__/AppsLauncher.test.tsx +0 -52
  73. package/src/components/AspectRatio/AspectRatio.module.css +0 -15
  74. package/src/components/AspectRatio/AspectRatio.stories.tsx +0 -78
  75. package/src/components/AspectRatio/AspectRatio.tsx +0 -21
  76. package/src/components/AspectRatio/__tests__/AspectRatio.test.tsx +0 -27
  77. package/src/components/Avatar/Avatar.module.css +0 -38
  78. package/src/components/Avatar/Avatar.tsx +0 -42
  79. package/src/components/Badge/Badge.module.css +0 -177
  80. package/src/components/Badge/Badge.stories.tsx +0 -238
  81. package/src/components/Badge/Badge.tsx +0 -84
  82. package/src/components/Badge/__tests__/Badge.test.tsx +0 -90
  83. package/src/components/BalanceChip/BalanceChip.module.css +0 -32
  84. package/src/components/BalanceChip/BalanceChip.stories.tsx +0 -45
  85. package/src/components/BalanceChip/BalanceChip.tsx +0 -33
  86. package/src/components/Breadcrumb/Breadcrumb.module.css +0 -49
  87. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +0 -47
  88. package/src/components/Breadcrumb/Breadcrumb.tsx +0 -57
  89. package/src/components/Breadcrumb/__tests__/Breadcrumb.test.tsx +0 -52
  90. package/src/components/Button/Button.module.css +0 -169
  91. package/src/components/Button/Button.stories.tsx +0 -83
  92. package/src/components/Button/Button.tsx +0 -52
  93. package/src/components/Button/__tests__/Button.test.tsx +0 -66
  94. package/src/components/ButtonGroup/ButtonGroup.module.css +0 -29
  95. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +0 -57
  96. package/src/components/ButtonGroup/ButtonGroup.tsx +0 -27
  97. package/src/components/ButtonGroup/__tests__/ButtonGroup.test.tsx +0 -29
  98. package/src/components/Calendar/Calendar.module.css +0 -126
  99. package/src/components/Calendar/Calendar.tsx +0 -213
  100. package/src/components/Calendar/__tests__/Calendar.test.tsx +0 -98
  101. package/src/components/Calendar/dateUtils.ts +0 -97
  102. package/src/components/Card/Card.module.css +0 -42
  103. package/src/components/Card/Card.tsx +0 -34
  104. package/src/components/CardTile/CardTile.module.css +0 -181
  105. package/src/components/CardTile/CardTile.stories.tsx +0 -86
  106. package/src/components/CardTile/CardTile.tsx +0 -128
  107. package/src/components/CardTile/__tests__/CardTile.test.tsx +0 -56
  108. package/src/components/CheckableListRow/CheckableListRow.module.css +0 -95
  109. package/src/components/CheckableListRow/CheckableListRow.stories.tsx +0 -99
  110. package/src/components/CheckableListRow/CheckableListRow.tsx +0 -89
  111. package/src/components/Checkbox/Checkbox.module.css +0 -111
  112. package/src/components/Checkbox/Checkbox.tsx +0 -78
  113. package/src/components/CodeTextarea/CodeTextarea.module.css +0 -53
  114. package/src/components/CodeTextarea/CodeTextarea.stories.tsx +0 -77
  115. package/src/components/CodeTextarea/CodeTextarea.tsx +0 -36
  116. package/src/components/Collapsible/Collapsible.module.css +0 -70
  117. package/src/components/Collapsible/Collapsible.stories.tsx +0 -62
  118. package/src/components/Collapsible/Collapsible.tsx +0 -66
  119. package/src/components/Collapsible/__tests__/Collapsible.test.tsx +0 -71
  120. package/src/components/ColorPicker/ColorPicker.module.css +0 -132
  121. package/src/components/ColorPicker/ColorPicker.stories.tsx +0 -80
  122. package/src/components/ColorPicker/ColorPicker.tsx +0 -157
  123. package/src/components/ColorPicker/__tests__/ColorPicker.test.tsx +0 -117
  124. package/src/components/Combobox/Combobox.module.css +0 -122
  125. package/src/components/Combobox/Combobox.stories.tsx +0 -79
  126. package/src/components/Combobox/Combobox.tsx +0 -186
  127. package/src/components/Combobox/__tests__/Combobox.test.tsx +0 -158
  128. package/src/components/Command/Command.module.css +0 -80
  129. package/src/components/Command/Command.stories.tsx +0 -104
  130. package/src/components/Command/Command.tsx +0 -168
  131. package/src/components/Command/__tests__/Command.test.tsx +0 -162
  132. package/src/components/ConfirmDialog/ConfirmDialog.module.css +0 -113
  133. package/src/components/ConfirmDialog/ConfirmDialog.tsx +0 -150
  134. package/src/components/ConfirmDialog/__tests__/ConfirmDialog.test.tsx +0 -214
  135. package/src/components/ConsentPrompt/ConsentPrompt.module.css +0 -21
  136. package/src/components/ConsentPrompt/ConsentPrompt.stories.tsx +0 -31
  137. package/src/components/ConsentPrompt/ConsentPrompt.tsx +0 -66
  138. package/src/components/ContextMenu/ContextMenu.stories.tsx +0 -81
  139. package/src/components/ContextMenu/ContextMenu.tsx +0 -100
  140. package/src/components/ContextMenu/__tests__/ContextMenu.test.tsx +0 -87
  141. package/src/components/CurrencyInput/CurrencyInput.stories.tsx +0 -50
  142. package/src/components/CurrencyInput/CurrencyInput.tsx +0 -60
  143. package/src/components/DataTable/DataTable.module.css +0 -28
  144. package/src/components/DataTable/DataTable.stories.tsx +0 -74
  145. package/src/components/DataTable/DataTable.tsx +0 -154
  146. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -123
  147. package/src/components/DatePicker/DatePicker.module.css +0 -61
  148. package/src/components/DatePicker/DatePicker.tsx +0 -103
  149. package/src/components/DatePicker/__tests__/DatePicker.test.tsx +0 -89
  150. package/src/components/DeviceOnlyGate/DeviceOnlyGate.tsx +0 -58
  151. package/src/components/DeviceOnlyGate/__tests__/DeviceOnlyGate.test.tsx +0 -45
  152. package/src/components/DeviceStorageKeyGate/DeviceStorageKeyGate.tsx +0 -100
  153. package/src/components/DeviceStorageKeyGate/__tests__/DeviceStorageKeyGate.test.tsx +0 -119
  154. package/src/components/Dialog/Dialog.module.css +0 -335
  155. package/src/components/Dialog/Dialog.stories.tsx +0 -324
  156. package/src/components/Dialog/Dialog.tsx +0 -254
  157. package/src/components/Dialog/__tests__/Dialog.test.tsx +0 -318
  158. package/src/components/DragHandleRow/DragHandleRow.module.css +0 -57
  159. package/src/components/DragHandleRow/DragHandleRow.tsx +0 -42
  160. package/src/components/Drawer/Drawer.module.css +0 -121
  161. package/src/components/Drawer/Drawer.stories.tsx +0 -132
  162. package/src/components/Drawer/Drawer.tsx +0 -175
  163. package/src/components/Drawer/__tests__/Drawer.test.tsx +0 -226
  164. package/src/components/EmptyState/EmptyState.module.css +0 -27
  165. package/src/components/EmptyState/EmptyState.tsx +0 -27
  166. package/src/components/FileDropzone/FileDropzone.module.css +0 -63
  167. package/src/components/FileDropzone/FileDropzone.tsx +0 -109
  168. package/src/components/FileDropzone/__tests__/FileDropzone.test.tsx +0 -67
  169. package/src/components/FormField/FormField.module.css +0 -33
  170. package/src/components/FormField/FormField.tsx +0 -78
  171. package/src/components/FormField/__tests__/FormField.test.tsx +0 -83
  172. package/src/components/GripIcon/GripIcon.tsx +0 -27
  173. package/src/components/Header/Header.module.css +0 -62
  174. package/src/components/Header/Header.stories.tsx +0 -452
  175. package/src/components/Header/Header.tsx +0 -102
  176. package/src/components/Header/__tests__/Header.test.tsx +0 -104
  177. package/src/components/HeaderFooterLayout/HeaderFooterLayout.module.css +0 -21
  178. package/src/components/HeaderFooterLayout/HeaderFooterLayout.stories.tsx +0 -111
  179. package/src/components/HeaderFooterLayout/HeaderFooterLayout.tsx +0 -54
  180. package/src/components/HeaderFooterLayout/__tests__/HeaderFooterLayout.test.tsx +0 -58
  181. package/src/components/HoverCard/HoverCard.module.css +0 -3
  182. package/src/components/HoverCard/HoverCard.stories.tsx +0 -66
  183. package/src/components/HoverCard/HoverCard.tsx +0 -111
  184. package/src/components/HoverCard/__tests__/HoverCard.test.tsx +0 -99
  185. package/src/components/Icon/Icon.module.css +0 -27
  186. package/src/components/Icon/Icon.stories.tsx +0 -95
  187. package/src/components/Icon/Icon.tsx +0 -43
  188. package/src/components/Icon/__tests__/Icon.test.tsx +0 -40
  189. package/src/components/Icon/icons/activity.tsx +0 -20
  190. package/src/components/Icon/icons/alert-triangle.tsx +0 -22
  191. package/src/components/Icon/icons/apple.tsx +0 -21
  192. package/src/components/Icon/icons/arrow-left-right.tsx +0 -23
  193. package/src/components/Icon/icons/banana.tsx +0 -21
  194. package/src/components/Icon/icons/beef.tsx +0 -22
  195. package/src/components/Icon/icons/beer.tsx +0 -24
  196. package/src/components/Icon/icons/bell.tsx +0 -21
  197. package/src/components/Icon/icons/bold.tsx +0 -20
  198. package/src/components/Icon/icons/calendar.tsx +0 -23
  199. package/src/components/Icon/icons/candy.tsx +0 -24
  200. package/src/components/Icon/icons/carrot.tsx +0 -22
  201. package/src/components/Icon/icons/check.tsx +0 -20
  202. package/src/components/Icon/icons/chevron-down.tsx +0 -20
  203. package/src/components/Icon/icons/chevron-left.tsx +0 -20
  204. package/src/components/Icon/icons/chevron-right.tsx +0 -20
  205. package/src/components/Icon/icons/chevron-up.tsx +0 -20
  206. package/src/components/Icon/icons/circle-check.tsx +0 -21
  207. package/src/components/Icon/icons/circle-chevron-left.tsx +0 -21
  208. package/src/components/Icon/icons/circle-x.tsx +0 -22
  209. package/src/components/Icon/icons/code.tsx +0 -21
  210. package/src/components/Icon/icons/coffee.tsx +0 -23
  211. package/src/components/Icon/icons/cookie.tsx +0 -25
  212. package/src/components/Icon/icons/copy.tsx +0 -21
  213. package/src/components/Icon/icons/credit-card.tsx +0 -21
  214. package/src/components/Icon/icons/croissant.tsx +0 -24
  215. package/src/components/Icon/icons/cup-soda.tsx +0 -23
  216. package/src/components/Icon/icons/database.tsx +0 -22
  217. package/src/components/Icon/icons/download.tsx +0 -22
  218. package/src/components/Icon/icons/drumstick.tsx +0 -21
  219. package/src/components/Icon/icons/egg.tsx +0 -20
  220. package/src/components/Icon/icons/ellipsis-vertical.tsx +0 -22
  221. package/src/components/Icon/icons/external-link.tsx +0 -22
  222. package/src/components/Icon/icons/eye-off.tsx +0 -23
  223. package/src/components/Icon/icons/eye.tsx +0 -21
  224. package/src/components/Icon/icons/file-text.tsx +0 -24
  225. package/src/components/Icon/icons/file.tsx +0 -21
  226. package/src/components/Icon/icons/fish.tsx +0 -25
  227. package/src/components/Icon/icons/folder-closed.tsx +0 -21
  228. package/src/components/Icon/icons/folder-open.tsx +0 -20
  229. package/src/components/Icon/icons/folder.tsx +0 -20
  230. package/src/components/Icon/icons/folders.tsx +0 -21
  231. package/src/components/Icon/icons/grid-2x2.tsx +0 -22
  232. package/src/components/Icon/icons/hat-glasses.tsx +0 -24
  233. package/src/components/Icon/icons/history.tsx +0 -22
  234. package/src/components/Icon/icons/house.tsx +0 -21
  235. package/src/components/Icon/icons/inbox.tsx +0 -21
  236. package/src/components/Icon/icons/index.ts +0 -394
  237. package/src/components/Icon/icons/info.tsx +0 -22
  238. package/src/components/Icon/icons/italic.tsx +0 -22
  239. package/src/components/Icon/icons/layers.tsx +0 -22
  240. package/src/components/Icon/icons/layout-dashboard.tsx +0 -23
  241. package/src/components/Icon/icons/layout-grid.tsx +0 -23
  242. package/src/components/Icon/icons/link.tsx +0 -21
  243. package/src/components/Icon/icons/list-ordered.tsx +0 -25
  244. package/src/components/Icon/icons/list.tsx +0 -25
  245. package/src/components/Icon/icons/lock.tsx +0 -21
  246. package/src/components/Icon/icons/log-out.tsx +0 -22
  247. package/src/components/Icon/icons/luggage.tsx +0 -24
  248. package/src/components/Icon/icons/mail.tsx +0 -21
  249. package/src/components/Icon/icons/map-pin.tsx +0 -21
  250. package/src/components/Icon/icons/menu.tsx +0 -22
  251. package/src/components/Icon/icons/milk.tsx +0 -22
  252. package/src/components/Icon/icons/minus.tsx +0 -20
  253. package/src/components/Icon/icons/package.tsx +0 -23
  254. package/src/components/Icon/icons/paint-bucket.tsx +0 -23
  255. package/src/components/Icon/icons/panel-left.tsx +0 -21
  256. package/src/components/Icon/icons/pencil.tsx +0 -21
  257. package/src/components/Icon/icons/pin.tsx +0 -21
  258. package/src/components/Icon/icons/pizza.tsx +0 -24
  259. package/src/components/Icon/icons/plus.tsx +0 -21
  260. package/src/components/Icon/icons/rectangle-ellipsis.tsx +0 -23
  261. package/src/components/Icon/icons/refresh-cw.tsx +0 -23
  262. package/src/components/Icon/icons/rotate-ccw.tsx +0 -21
  263. package/src/components/Icon/icons/rotate-cw.tsx +0 -21
  264. package/src/components/Icon/icons/route.tsx +0 -22
  265. package/src/components/Icon/icons/salad.tsx +0 -24
  266. package/src/components/Icon/icons/search.tsx +0 -21
  267. package/src/components/Icon/icons/send.tsx +0 -21
  268. package/src/components/Icon/icons/settings.tsx +0 -21
  269. package/src/components/Icon/icons/share-2.tsx +0 -24
  270. package/src/components/Icon/icons/sheet.tsx +0 -24
  271. package/src/components/Icon/icons/shield.tsx +0 -20
  272. package/src/components/Icon/icons/shopping-basket.tsx +0 -26
  273. package/src/components/Icon/icons/sliders-horizontal.tsx +0 -28
  274. package/src/components/Icon/icons/smartphone.tsx +0 -21
  275. package/src/components/Icon/icons/snowflake.tsx +0 -31
  276. package/src/components/Icon/icons/spray-can.tsx +0 -29
  277. package/src/components/Icon/icons/square-kanban.tsx +0 -23
  278. package/src/components/Icon/icons/table.tsx +0 -23
  279. package/src/components/Icon/icons/trash-2.tsx +0 -24
  280. package/src/components/Icon/icons/upload.tsx +0 -22
  281. package/src/components/Icon/icons/user-round-plus.tsx +0 -23
  282. package/src/components/Icon/icons/user.tsx +0 -21
  283. package/src/components/Icon/icons/users.tsx +0 -23
  284. package/src/components/Icon/icons/wine.tsx +0 -23
  285. package/src/components/Icon/icons/x.tsx +0 -21
  286. package/src/components/IconPicker/IconPicker.module.css +0 -63
  287. package/src/components/IconPicker/IconPicker.stories.tsx +0 -84
  288. package/src/components/IconPicker/IconPicker.tsx +0 -90
  289. package/src/components/Input/Input.module.css +0 -52
  290. package/src/components/Input/Input.stories.tsx +0 -86
  291. package/src/components/Input/Input.tsx +0 -20
  292. package/src/components/Input/__tests__/Input.test.tsx +0 -22
  293. package/src/components/Item/Item.module.css +0 -70
  294. package/src/components/Item/Item.stories.tsx +0 -62
  295. package/src/components/Item/Item.tsx +0 -54
  296. package/src/components/Item/__tests__/Item.test.tsx +0 -39
  297. package/src/components/Kbd/Kbd.module.css +0 -14
  298. package/src/components/Kbd/Kbd.stories.tsx +0 -32
  299. package/src/components/Kbd/Kbd.tsx +0 -12
  300. package/src/components/Kbd/__tests__/Kbd.test.tsx +0 -14
  301. package/src/components/Label/Label.module.css +0 -11
  302. package/src/components/Label/Label.stories.tsx +0 -40
  303. package/src/components/Label/Label.tsx +0 -24
  304. package/src/components/Label/__tests__/Label.test.tsx +0 -32
  305. package/src/components/LegalLinks/LegalLinks.module.css +0 -24
  306. package/src/components/LegalLinks/LegalLinks.stories.tsx +0 -22
  307. package/src/components/LegalLinks/LegalLinks.tsx +0 -40
  308. package/src/components/Markdown/Markdown.module.css +0 -73
  309. package/src/components/Markdown/Markdown.stories.tsx +0 -40
  310. package/src/components/Markdown/Markdown.tsx +0 -305
  311. package/src/components/Markdown/__tests__/Markdown.test.tsx +0 -144
  312. package/src/components/Marker/Marker.module.css +0 -33
  313. package/src/components/Marker/Marker.stories.tsx +0 -39
  314. package/src/components/Marker/Marker.tsx +0 -34
  315. package/src/components/Marker/__tests__/Marker.test.tsx +0 -23
  316. package/src/components/MemberMultiSelect/MemberMultiSelect.module.css +0 -27
  317. package/src/components/MemberMultiSelect/MemberMultiSelect.stories.tsx +0 -74
  318. package/src/components/MemberMultiSelect/MemberMultiSelect.tsx +0 -67
  319. package/src/components/Menu/Menu.module.css +0 -90
  320. package/src/components/Menu/Menu.tsx +0 -209
  321. package/src/components/Menu/__tests__/Menu.test.tsx +0 -227
  322. package/src/components/Menubar/Menubar.stories.tsx +0 -52
  323. package/src/components/Menubar/Menubar.tsx +0 -42
  324. package/src/components/Menubar/__tests__/Menubar.test.tsx +0 -45
  325. package/src/components/Message/Message.module.css +0 -99
  326. package/src/components/Message/Message.stories.tsx +0 -79
  327. package/src/components/Message/Message.tsx +0 -41
  328. package/src/components/Message/__tests__/Message.test.tsx +0 -46
  329. package/src/components/MessageScroller/MessageScroller.module.css +0 -65
  330. package/src/components/MessageScroller/MessageScroller.stories.tsx +0 -84
  331. package/src/components/MessageScroller/MessageScroller.tsx +0 -84
  332. package/src/components/MessageScroller/__tests__/MessageScroller.test.tsx +0 -105
  333. package/src/components/MobileAppsDrawer/MobileAppsDrawer.module.css +0 -82
  334. package/src/components/MobileAppsDrawer/MobileAppsDrawer.tsx +0 -78
  335. package/src/components/MobileAppsDrawer/__tests__/MobileAppsDrawer.test.tsx +0 -80
  336. package/src/components/MobileFooter/MobileFooter.module.css +0 -73
  337. package/src/components/MobileFooter/MobileFooter.stories.tsx +0 -47
  338. package/src/components/MobileFooter/MobileFooter.tsx +0 -122
  339. package/src/components/MobileFooter/__tests__/MobileFooter.test.tsx +0 -129
  340. package/src/components/MobileHeader/MobileHeader.module.css +0 -76
  341. package/src/components/MobileHeader/MobileHeader.stories.tsx +0 -57
  342. package/src/components/MobileHeader/MobileHeader.tsx +0 -90
  343. package/src/components/MobileHeader/__tests__/MobileHeader.test.tsx +0 -113
  344. package/src/components/NavList/NavList.module.css +0 -130
  345. package/src/components/NavList/NavList.tsx +0 -136
  346. package/src/components/NavList/__tests__/NavList.test.tsx +0 -109
  347. package/src/components/NavTabs/NavTabs.module.css +0 -50
  348. package/src/components/NavTabs/NavTabs.tsx +0 -61
  349. package/src/components/NavigationMenu/NavigationMenu.module.css +0 -53
  350. package/src/components/NavigationMenu/NavigationMenu.stories.tsx +0 -58
  351. package/src/components/NavigationMenu/NavigationMenu.tsx +0 -125
  352. package/src/components/NavigationMenu/__tests__/NavigationMenu.test.tsx +0 -93
  353. package/src/components/NotificationsPanel/NotificationsPanel.module.css +0 -258
  354. package/src/components/NotificationsPanel/NotificationsPanel.stories.tsx +0 -61
  355. package/src/components/NotificationsPanel/NotificationsPanel.tsx +0 -187
  356. package/src/components/NotificationsPanel/__tests__/NotificationsPanel.test.tsx +0 -78
  357. package/src/components/OfflineGate/OfflineGate.tsx +0 -44
  358. package/src/components/OfflineGate/__tests__/OfflineGate.test.tsx +0 -66
  359. package/src/components/OverlayHeader/OverlayHeader.module.css +0 -98
  360. package/src/components/OverlayHeader/OverlayHeader.tsx +0 -77
  361. package/src/components/OverlayHeader/__tests__/OverlayHeader.test.tsx +0 -69
  362. package/src/components/PageContainer/PageContainer.module.css +0 -82
  363. package/src/components/PageContainer/PageContainer.tsx +0 -64
  364. package/src/components/PageContainer/__tests__/PageContainer.test.tsx +0 -70
  365. package/src/components/PageHeader/PageHeader.module.css +0 -86
  366. package/src/components/PageHeader/PageHeader.tsx +0 -176
  367. package/src/components/PageHeader/__tests__/PageHeader.test.tsx +0 -103
  368. package/src/components/PageLayout/PageLayout.module.css +0 -51
  369. package/src/components/PageLayout/PageLayout.stories.tsx +0 -73
  370. package/src/components/PageLayout/PageLayout.tsx +0 -51
  371. package/src/components/PageLayout/__tests__/PageLayout.test.tsx +0 -34
  372. package/src/components/Pagination/Pagination.module.css +0 -98
  373. package/src/components/Pagination/Pagination.stories.tsx +0 -49
  374. package/src/components/Pagination/Pagination.tsx +0 -87
  375. package/src/components/Pagination/__tests__/Pagination.test.tsx +0 -56
  376. package/src/components/Popover/Popover.module.css +0 -74
  377. package/src/components/Popover/Popover.stories.tsx +0 -357
  378. package/src/components/Popover/Popover.tsx +0 -290
  379. package/src/components/Popover/__tests__/Popover.test.tsx +0 -263
  380. package/src/components/Progress/Progress.module.css +0 -20
  381. package/src/components/Progress/Progress.stories.tsx +0 -40
  382. package/src/components/Progress/Progress.tsx +0 -35
  383. package/src/components/Progress/__tests__/Progress.test.tsx +0 -31
  384. package/src/components/QuantityStepper/QuantityStepper.module.css +0 -67
  385. package/src/components/QuantityStepper/QuantityStepper.stories.tsx +0 -79
  386. package/src/components/QuantityStepper/QuantityStepper.tsx +0 -107
  387. package/src/components/RadioGroup/RadioGroup.module.css +0 -88
  388. package/src/components/RadioGroup/RadioGroup.stories.tsx +0 -69
  389. package/src/components/RadioGroup/RadioGroup.tsx +0 -99
  390. package/src/components/RadioGroup/__tests__/RadioGroup.test.tsx +0 -59
  391. package/src/components/Resizable/Resizable.module.css +0 -70
  392. package/src/components/Resizable/Resizable.stories.tsx +0 -82
  393. package/src/components/Resizable/Resizable.tsx +0 -313
  394. package/src/components/Resizable/__tests__/Resizable.test.tsx +0 -128
  395. package/src/components/ResponsiveSurface/ResponsiveSurface.tsx +0 -24
  396. package/src/components/ResponsiveSurface/__tests__/ResponsiveSurface.test.tsx +0 -73
  397. package/src/components/RootLayout/RootLayout.module.css +0 -12
  398. package/src/components/RootLayout/RootLayout.stories.tsx +0 -125
  399. package/src/components/RootLayout/RootLayout.tsx +0 -185
  400. package/src/components/RootLayout/__tests__/RootLayout.test.tsx +0 -161
  401. package/src/components/ScrollArea/ScrollArea.module.css +0 -20
  402. package/src/components/ScrollArea/ScrollArea.stories.tsx +0 -57
  403. package/src/components/ScrollArea/ScrollArea.tsx +0 -27
  404. package/src/components/ScrollArea/__tests__/ScrollArea.test.tsx +0 -39
  405. package/src/components/SegmentedControl/SegmentedControl.module.css +0 -55
  406. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +0 -118
  407. package/src/components/SegmentedControl/SegmentedControl.tsx +0 -56
  408. package/src/components/SegmentedControl/__tests__/SegmentedControl.test.tsx +0 -63
  409. package/src/components/Select/Select.module.css +0 -82
  410. package/src/components/Select/Select.stories.tsx +0 -115
  411. package/src/components/Select/Select.tsx +0 -48
  412. package/src/components/Select/__tests__/Select.test.tsx +0 -59
  413. package/src/components/Sheet/Sheet.module.css +0 -58
  414. package/src/components/Sheet/Sheet.tsx +0 -109
  415. package/src/components/Sheet/__tests__/Sheet.test.tsx +0 -99
  416. package/src/components/Slider/Slider.module.css +0 -95
  417. package/src/components/Slider/Slider.stories.tsx +0 -64
  418. package/src/components/Slider/Slider.tsx +0 -77
  419. package/src/components/Slider/__tests__/Slider.test.tsx +0 -45
  420. package/src/components/Spinner/Spinner.module.css +0 -39
  421. package/src/components/Spinner/Spinner.tsx +0 -23
  422. package/src/components/SplitMethodSelector/SplitMethodSelector.stories.tsx +0 -33
  423. package/src/components/SplitMethodSelector/SplitMethodSelector.tsx +0 -43
  424. package/src/components/SplitPane/SplitPane.module.css +0 -85
  425. package/src/components/SplitPane/SplitPane.stories.tsx +0 -160
  426. package/src/components/SplitPane/SplitPane.tsx +0 -149
  427. package/src/components/SplitPane/__tests__/SplitPane.test.tsx +0 -51
  428. package/src/components/StatusBadge/StatusBadge.module.css +0 -59
  429. package/src/components/StatusBadge/StatusBadge.stories.tsx +0 -74
  430. package/src/components/StatusBadge/StatusBadge.tsx +0 -65
  431. package/src/components/StepStrip/StepStrip.module.css +0 -53
  432. package/src/components/StepStrip/StepStrip.tsx +0 -74
  433. package/src/components/SuggestionInput/SuggestionInput.module.css +0 -103
  434. package/src/components/SuggestionInput/SuggestionInput.stories.tsx +0 -144
  435. package/src/components/SuggestionInput/SuggestionInput.tsx +0 -207
  436. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.module.css +0 -64
  437. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.tsx +0 -243
  438. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlide.tsx +0 -35
  439. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody.tsx +0 -42
  440. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter.tsx +0 -18
  441. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader.tsx +0 -21
  442. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideParts.module.css +0 -29
  443. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarousel.test.tsx +0 -214
  444. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarouselDevGuard.test.tsx +0 -61
  445. package/src/components/SwipableMobileCarousel/context.ts +0 -13
  446. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.module.css +0 -64
  447. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.tsx +0 -73
  448. package/src/components/SwipableMobileCarouselDots/__tests__/SwipableMobileCarouselDots.test.tsx +0 -63
  449. package/src/components/SwipeStack/SwipeStack.module.css +0 -101
  450. package/src/components/SwipeStack/SwipeStack.tsx +0 -199
  451. package/src/components/SwipeStack/SwipeStackCard.tsx +0 -22
  452. package/src/components/SwipeStack/__tests__/SwipeStack.test.tsx +0 -169
  453. package/src/components/SystemBanner/SystemBanner.module.css +0 -79
  454. package/src/components/SystemBanner/SystemBanner.stories.tsx +0 -86
  455. package/src/components/SystemBanner/SystemBanner.tsx +0 -50
  456. package/src/components/SystemBanner/__tests__/SystemBanner.test.tsx +0 -50
  457. package/src/components/Table/Table.module.css +0 -45
  458. package/src/components/Table/Table.stories.tsx +0 -125
  459. package/src/components/Table/Table.tsx +0 -51
  460. package/src/components/Table/__tests__/Table.test.tsx +0 -50
  461. package/src/components/Tabs/Tabs.module.css +0 -56
  462. package/src/components/Tabs/Tabs.stories.tsx +0 -100
  463. package/src/components/Tabs/Tabs.tsx +0 -46
  464. package/src/components/Tabs/__tests__/Tabs.test.tsx +0 -45
  465. package/src/components/TagInput/TagInput.module.css +0 -141
  466. package/src/components/TagInput/TagInput.stories.tsx +0 -109
  467. package/src/components/TagInput/TagInput.tsx +0 -174
  468. package/src/components/TagInput/__tests__/TagInput.test.tsx +0 -69
  469. package/src/components/Textarea/Textarea.module.css +0 -47
  470. package/src/components/Textarea/Textarea.tsx +0 -38
  471. package/src/components/Textarea/__tests__/Textarea.test.tsx +0 -51
  472. package/src/components/ThreeColumnLayout/ThreeColumnLayout.module.css +0 -35
  473. package/src/components/ThreeColumnLayout/ThreeColumnLayout.stories.tsx +0 -152
  474. package/src/components/ThreeColumnLayout/ThreeColumnLayout.tsx +0 -87
  475. package/src/components/ThreeColumnLayout/__tests__/ThreeColumnLayout.test.tsx +0 -78
  476. package/src/components/Toast/Toast.module.css +0 -191
  477. package/src/components/Toast/Toast.stories.tsx +0 -191
  478. package/src/components/Toast/Toast.tsx +0 -139
  479. package/src/components/Toggle/Toggle.module.css +0 -57
  480. package/src/components/Toggle/Toggle.stories.tsx +0 -95
  481. package/src/components/Toggle/Toggle.tsx +0 -39
  482. package/src/components/Toggle/__tests__/Toggle.test.tsx +0 -47
  483. package/src/components/Tooltip/Tooltip.module.css +0 -56
  484. package/src/components/Tooltip/Tooltip.tsx +0 -30
  485. package/src/components/Typography/Typography.module.css +0 -47
  486. package/src/components/Typography/Typography.stories.tsx +0 -62
  487. package/src/components/Typography/Typography.tsx +0 -30
  488. package/src/components/Typography/__tests__/Typography.test.tsx +0 -34
  489. package/src/components/UserMenu/UserMenu.module.css +0 -90
  490. package/src/components/UserMenu/UserMenu.stories.tsx +0 -49
  491. package/src/components/UserMenu/UserMenu.tsx +0 -132
  492. package/src/components/UserMenu/__tests__/UserMenu.test.tsx +0 -77
  493. package/src/css-modules.d.ts +0 -4
  494. package/src/hooks/__tests__/useCarouselRouteSync.test.tsx +0 -126
  495. package/src/hooks/__tests__/useDoubleTap.test.tsx +0 -117
  496. package/src/hooks/__tests__/useIsMobile.test.tsx +0 -80
  497. package/src/hooks/__tests__/useIsOffline.test.tsx +0 -53
  498. package/src/hooks/__tests__/useLongPress.test.tsx +0 -158
  499. package/src/hooks/__tests__/useOfflineTileState.test.tsx +0 -69
  500. package/src/hooks/__tests__/usePublishShellChromeHeight.test.tsx +0 -118
  501. package/src/hooks/__tests__/useReorderSensors.test.ts +0 -26
  502. package/src/hooks/__tests__/useResponsiveLayout.test.tsx +0 -87
  503. package/src/hooks/__tests__/useSnapCarousel.test.tsx +0 -175
  504. package/src/hooks/__tests__/useSwipeReveal.test.tsx +0 -110
  505. package/src/hooks/__tests__/useSwipeStack.test.tsx +0 -155
  506. package/src/hooks/index.ts +0 -33
  507. package/src/hooks/useCarouselRouteSync.ts +0 -92
  508. package/src/hooks/useCommitOnEnterOrBlur.ts +0 -39
  509. package/src/hooks/useDoubleTap.ts +0 -91
  510. package/src/hooks/useIsMobile.ts +0 -33
  511. package/src/hooks/useIsOffline.ts +0 -41
  512. package/src/hooks/useLongPress.ts +0 -185
  513. package/src/hooks/useOfflineTileState.ts +0 -45
  514. package/src/hooks/usePublishShellChromeHeight.ts +0 -96
  515. package/src/hooks/useReorderSensors.ts +0 -88
  516. package/src/hooks/useResponsiveLayout.ts +0 -36
  517. package/src/hooks/useSnapCarousel.ts +0 -284
  518. package/src/hooks/useSwipeReveal.ts +0 -107
  519. package/src/hooks/useSwipeStack.ts +0 -235
  520. package/src/index.ts +0 -311
  521. package/src/motion.ts +0 -78
  522. package/src/overlay-shell.ts +0 -159
  523. package/src/scroll-lock.ts +0 -22
  524. package/src/stories/Avatar.stories.tsx +0 -44
  525. package/src/stories/Card.stories.tsx +0 -35
  526. package/src/stories/Checkbox.stories.tsx +0 -45
  527. package/src/stories/DesignSystemOverview.stories.tsx +0 -3793
  528. package/src/stories/DeviceOnlyGate.stories.tsx +0 -35
  529. package/src/stories/DeviceStorageKeyGate.stories.tsx +0 -57
  530. package/src/stories/DragHandleRow.stories.tsx +0 -41
  531. package/src/stories/EmptyState.stories.tsx +0 -33
  532. package/src/stories/FileDropzone.stories.tsx +0 -69
  533. package/src/stories/FormField.stories.tsx +0 -47
  534. package/src/stories/GripIcon.stories.tsx +0 -29
  535. package/src/stories/InteractionHooks.stories.tsx +0 -925
  536. package/src/stories/LayoutSystem.stories.tsx +0 -639
  537. package/src/stories/MenuEntries.stories.tsx +0 -86
  538. package/src/stories/MobilePatterns.stories.tsx +0 -1536
  539. package/src/stories/NavList.stories.tsx +0 -147
  540. package/src/stories/NavTabs.stories.tsx +0 -53
  541. package/src/stories/OfflineGate.stories.tsx +0 -42
  542. package/src/stories/PageContainer.stories.tsx +0 -82
  543. package/src/stories/PageHeader.stories.tsx +0 -95
  544. package/src/stories/ResponsiveSurface.stories.tsx +0 -47
  545. package/src/stories/Spinner.stories.tsx +0 -25
  546. package/src/stories/StepStrip.stories.tsx +0 -76
  547. package/src/stories/SwipableMobileCarousel.stories.tsx +0 -362
  548. package/src/stories/SwipeStack.stories.tsx +0 -200
  549. package/src/stories/Textarea.stories.tsx +0 -63
  550. package/src/stories/TokenGallery.stories.tsx +0 -652
  551. package/src/stories/Tooltip.stories.tsx +0 -59
  552. package/src/tokens/primitives.css +0 -168
  553. package/src/tokens/semantic.css +0 -162
  554. package/src/tokens/theme-presets.css +0 -33
  555. package/src/tokens/theme-presets.ts +0 -72
  556. package/src/tokens.css +0 -5
@@ -1,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: var(--sv-border-width-hairline) 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
- };
@@ -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,65 +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
- /* Bottom-anchors a conversation that doesn't fill the container: this
29
- leading item claims all leftover main-axis space, pushing the real
30
- messages down to the bottom edge. Once messages overflow, it has no
31
- free space left to grow into and collapses to 0 — normal top-to-bottom
32
- scrolling is unaffected either way, since `justify-content` never
33
- changes from its default `flex-start`. */
34
- .spacer {
35
- flex: 1 0 0%;
36
- min-height: 0;
37
- }
38
-
39
- .jumpButton {
40
- position: absolute;
41
- bottom: var(--sv-space-3);
42
- left: 50%;
43
- transform: translateX(-50%);
44
- padding: var(--sv-space-1) var(--sv-space-3);
45
- border: var(--sv-border-width-hairline) solid var(--sv-color-border);
46
- border-radius: var(--sv-radius-full);
47
- background: var(--sv-color-surface-raised);
48
- box-shadow: var(--sv-shadow-popover);
49
- color: var(--sv-color-text-primary);
50
- font-family: var(--sv-font-family);
51
- font-size: var(--sv-font-size-caption);
52
- font-weight: var(--sv-font-weight-medium);
53
- cursor: pointer;
54
- }
55
-
56
- .jumpButton:focus-visible {
57
- outline: 2px solid var(--sv-color-focus-ring);
58
- outline-offset: 2px;
59
- }
60
-
61
- @media (hover: hover) {
62
- .jumpButton:hover {
63
- background: var(--sv-color-surface-sunken);
64
- }
65
- }
@@ -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,84 +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
- * A short conversation is bottom-anchored, not left floating at the top of
24
- * the container with empty space below it — a leading flex-grow spacer
25
- * absorbs the leftover space and collapses to nothing once messages
26
- * overflow. Deliberately not `justify-content: flex-end` on the scroll
27
- * container itself: Chromium miscomputes `scrollHeight` as equal to
28
- * `clientHeight` for an overflowing flex-end-packed column, which makes the
29
- * container look fully scrolled to the bottom and permanently hides the
30
- * start of a long conversation (confirmed live before choosing this
31
- * approach). The spacer keeps `justify-content` at its default, so overflow
32
- * scrolling is unaffected.
33
- */
34
- export function MessageScroller({ children, className }: MessageScrollerProps) {
35
- const containerRef = useRef<HTMLDivElement>(null);
36
- // A ref, not state: reading the user's scroll position must not itself
37
- // retrigger the auto-scroll effect below, or scrolling back near the
38
- // bottom manually would immediately snap the container the rest of the
39
- // way — fighting the user's own scroll input.
40
- const isNearBottomRef = useRef(true);
41
- const [hasNewMessages, setHasNewMessages] = useState(false);
42
-
43
- useEffect(() => {
44
- const el = containerRef.current;
45
- if (!el) return;
46
- if (isNearBottomRef.current) {
47
- el.scrollTop = el.scrollHeight;
48
- setHasNewMessages(false);
49
- } else {
50
- setHasNewMessages(true);
51
- }
52
- }, [children]);
53
-
54
- function handleScroll(event: UIEvent<HTMLDivElement>) {
55
- const el = event.currentTarget;
56
- const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
57
- isNearBottomRef.current = distanceFromBottom < NEAR_BOTTOM_THRESHOLD_PX;
58
- if (isNearBottomRef.current) {
59
- setHasNewMessages(false);
60
- }
61
- }
62
-
63
- function scrollToBottom() {
64
- const el = containerRef.current;
65
- if (!el) return;
66
- el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' });
67
- isNearBottomRef.current = true;
68
- setHasNewMessages(false);
69
- }
70
-
71
- return (
72
- <div className={[styles.root, className].filter(Boolean).join(' ')}>
73
- <div className={styles.scrollContainer} ref={containerRef} onScroll={handleScroll}>
74
- <div className={styles.spacer} aria-hidden="true" />
75
- {children}
76
- </div>
77
- {hasNewMessages && (
78
- <button type="button" className={styles.jumpButton} onClick={scrollToBottom}>
79
- New messages ↓
80
- </button>
81
- )}
82
- </div>
83
- );
84
- }
@@ -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
- });