@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,227 +0,0 @@
1
- 'use client';
2
-
3
- import {
4
- Children,
5
- isValidElement,
6
- useEffect,
7
- useLayoutEffect,
8
- useMemo,
9
- useRef,
10
- type ReactElement,
11
- type ReactNode,
12
- } from 'react';
13
- import { useSnapCarousel } from '../../hooks/useSnapCarousel';
14
- import { SwipableMobileCarouselDots } from '../SwipableMobileCarouselDots/SwipableMobileCarouselDots';
15
- import { SwipableMobileCarouselSlide } from './SwipableMobileCarouselSlide';
16
- import { CarouselSlideMountContext } from './context';
17
- import styles from './SwipableMobileCarousel.module.css';
18
-
19
- export interface SwipableMobileCarouselIndicatorProps {
20
- count: number;
21
- activeIndex: number;
22
- labels: (string | undefined)[];
23
- onJump: (index: number) => void;
24
- }
25
-
26
- export interface SwipableMobileCarouselProps {
27
- /** Controlled active slide index — the caller owns this (typically via
28
- * useCarouselRouteSync, or plain useState). */
29
- activeIndex: number;
30
- /** Called when a swipe gesture settles on a different index, or when the
31
- * reorder-jump fix re-snaps after the active slide's position changes.
32
- * The caller is responsible for updating `activeIndex` in response. */
33
- onSettle: (index: number) => void;
34
- /** How many slides on each side of the active one stay mounted. Default 1
35
- * matches both sovereign-tasks' and sovereign-shopper's existing "swipe
36
- * never shows a spinner" behavior. Slides outside this window keep their
37
- * DOM slot (so scroll-snap's position-based indexing stays correct) but
38
- * their children are not mounted at all. */
39
- prefetchDistance?: number;
40
- /** Passed straight through to the internal useSnapCarousel. */
41
- settleDebounceMs?: number;
42
- /** Required — labels the scroller region for assistive tech. No generic
43
- * fallback, since one would be wrong for every actual consumer. */
44
- 'aria-label': string;
45
- /** Renders the indicator. Defaults to SwipableMobileCarouselDots. Pass
46
- * `null` to render no indicator at all. */
47
- renderIndicator?: null | ((props: SwipableMobileCarouselIndicatorProps) => ReactNode);
48
- className?: string;
49
- /** Must be SwipableMobileCarouselSlide elements (nullish/boolean children
50
- * are safely skipped for conditional slides). A dev-mode warning is
51
- * logged for any other child type — see resolveSlides below. */
52
- children: ReactNode;
53
- }
54
-
55
- interface ResolvedSlide {
56
- key: string;
57
- label: string | undefined;
58
- element: ReactElement;
59
- }
60
-
61
- function describeChild(child: unknown): string {
62
- if (isValidElement(child)) {
63
- const type = child.type;
64
- if (typeof type === 'string') return `<${type}>`;
65
- if (typeof type === 'function') {
66
- const named = type as { displayName?: string; name?: string };
67
- return `<${named.displayName ?? named.name ?? 'Component'}>`;
68
- }
69
- return '<unknown>';
70
- }
71
- if (typeof child === 'string') return `string "${child}"`;
72
- return String(child);
73
- }
74
-
75
- function resolveSlides(children: ReactNode): ResolvedSlide[] {
76
- const slides: ResolvedSlide[] = [];
77
- Children.forEach(children, (child, index) => {
78
- if (child === null || child === undefined || child === false || child === true) return;
79
- if (!isValidElement(child) || child.type !== SwipableMobileCarouselSlide) {
80
- if (process.env.NODE_ENV !== 'production') {
81
- console.error(
82
- '[SwipableMobileCarousel] Every child must be a <SwipableMobileCarouselSlide>. ' +
83
- `Found ${describeChild(child)} at position ${index}. A non-Slide child shifts every ` +
84
- "subsequent slide's index, desyncing scroll-snap position from activeIndex.",
85
- );
86
- }
87
- return;
88
- }
89
- const slideProps = child.props as { slideKey: string; label?: string };
90
- if (process.env.NODE_ENV !== 'production' && !slideProps.label) {
91
- console.warn(
92
- `[SwipableMobileCarousel] SwipableMobileCarouselSlide "${slideProps.slideKey}" has no ` +
93
- 'label — it will show as "Slide N of count" in the default dots indicator.',
94
- );
95
- }
96
- slides.push({ key: slideProps.slideKey, label: slideProps.label, element: child });
97
- });
98
- return slides;
99
- }
100
-
101
- /**
102
- * SwipableMobileCarousel — a compound component for swiping between full-
103
- * width slides (each an independent route/view on mobile), wrapping
104
- * useSnapCarousel. This library's first compound component: every other
105
- * component here is flat/prop-based, but slide content is large, arbitrary,
106
- * per-plugin subtrees that need a header-known/body-loading split an
107
- * array-of-objects prop would only express with worse JSX ergonomics.
108
- *
109
- * Owns rendering and mount-window mechanics only — it has no opinion on
110
- * where slide data lives. Do NOT: (a) aggregate cross-slide data inside a
111
- * SwipableMobileCarouselSlideBody (that recomputes on every slide render
112
- * regardless of which slide is active — belongs in the parent, which
113
- * already knows every slide exists); (b) mount a detail overlay (Sheet,
114
- * Dialog) inside a Slide's children — mount it as a sibling of
115
- * SwipableMobileCarousel instead, controlled by the same state that would
116
- * otherwise drive a routed page's overlay. sovereign-tasks' current
117
- * hand-rolled carousel does both and is measurably laggier than
118
- * sovereign-shopper's equivalent, which keeps its overlay in the routed pane.
119
- */
120
- export function SwipableMobileCarousel({
121
- activeIndex,
122
- onSettle,
123
- prefetchDistance = 1,
124
- settleDebounceMs = 120,
125
- 'aria-label': ariaLabel,
126
- renderIndicator,
127
- className,
128
- children,
129
- }: SwipableMobileCarouselProps) {
130
- const slides = useMemo(() => resolveSlides(children), [children]);
131
- const count = slides.length;
132
- const clampedActiveIndex = count === 0 ? 0 : Math.max(0, Math.min(count - 1, activeIndex));
133
-
134
- const { scrollRef, scrollToIndex } = useSnapCarousel({
135
- itemCount: count,
136
- onSettle,
137
- debounceMs: settleDebounceMs,
138
- });
139
-
140
- // Initial scroll position, once — subsequent activeIndex changes come
141
- // either from the user's own swipe (already reflected in DOM scroll
142
- // position; re-syncing to the same index below is a harmless no-op) or an
143
- // external navigation, which the effect below scrolls to explicitly.
144
- const initialActiveIndexRef = useRef(clampedActiveIndex);
145
- useLayoutEffect(() => {
146
- scrollToIndex(initialActiveIndexRef.current, 'instant');
147
- // Runs once on mount only, matching both existing plugins' identical pattern.
148
- }, []);
149
-
150
- const didMountActiveIndexSyncRef = useRef(false);
151
- useEffect(() => {
152
- if (!didMountActiveIndexSyncRef.current) {
153
- didMountActiveIndexSyncRef.current = true;
154
- return;
155
- }
156
- scrollToIndex(clampedActiveIndex, 'smooth');
157
- }, [clampedActiveIndex, scrollToIndex]);
158
-
159
- // Reorder-jump fix: scroll-snap position tracks DOM order, not slide
160
- // identity. If the previously-active slide's key still exists but moved
161
- // (a caller re-sorted their slide array while mounted), re-snap to its
162
- // new position and report it via onSettle so the caller's activeIndex
163
- // stays in sync — otherwise scroll position silently desyncs from slide
164
- // identity. Runs every commit (no dependency array) since it needs to
165
- // notice any children change, not just a specific prop.
166
- const prevKeysRef = useRef<string[] | null>(null);
167
- useLayoutEffect(() => {
168
- const currentKeys = slides.map((s) => s.key);
169
- const prevKeys = prevKeysRef.current;
170
- if (prevKeys) {
171
- const sameOrder =
172
- prevKeys.length === currentKeys.length && prevKeys.every((k, i) => k === currentKeys[i]);
173
- if (!sameOrder) {
174
- const activeKey = prevKeys[clampedActiveIndex];
175
- if (activeKey !== undefined) {
176
- const newIndex = currentKeys.indexOf(activeKey);
177
- if (newIndex !== -1 && newIndex !== clampedActiveIndex) {
178
- scrollToIndex(newIndex, 'instant');
179
- onSettle(newIndex);
180
- }
181
- }
182
- }
183
- }
184
- prevKeysRef.current = currentKeys;
185
- });
186
-
187
- function handleJump(index: number) {
188
- // scrollToIndex sets useSnapCarousel's own dedupe ref synchronously, so
189
- // the natural scroll-settle detection will NOT re-report this index —
190
- // onSettle must be called directly here, same pairing as the
191
- // reorder-jump fix above.
192
- scrollToIndex(index, 'smooth');
193
- onSettle(index);
194
- }
195
-
196
- const labels = slides.map((s) => s.label);
197
- const indicator =
198
- renderIndicator === null ? null : renderIndicator ? (
199
- renderIndicator({ count, activeIndex: clampedActiveIndex, labels, onJump: handleJump })
200
- ) : (
201
- <SwipableMobileCarouselDots
202
- className={styles.dots}
203
- count={count}
204
- activeIndex={clampedActiveIndex}
205
- labels={labels}
206
- aria-label={ariaLabel}
207
- onJump={handleJump}
208
- />
209
- );
210
-
211
- return (
212
- <div className={[styles.wrap, className].filter(Boolean).join(' ')}>
213
- <div className={styles.scroller} ref={scrollRef} role="region" aria-label={ariaLabel}>
214
- {slides.map((slide, i) => (
215
- <div className={styles.slide} key={slide.key}>
216
- <CarouselSlideMountContext.Provider
217
- value={{ isMounted: Math.abs(i - clampedActiveIndex) <= prefetchDistance }}
218
- >
219
- {slide.element}
220
- </CarouselSlideMountContext.Provider>
221
- </div>
222
- ))}
223
- </div>
224
- {indicator}
225
- </div>
226
- );
227
- }
@@ -1,35 +0,0 @@
1
- 'use client';
2
-
3
- import { useContext, type ReactNode } from 'react';
4
- import { CarouselSlideMountContext } from './context';
5
-
6
- export interface SwipableMobileCarouselSlideProps {
7
- /** Stable identity for this slide, independent of its position among
8
- * siblings — required. This is what makes SwipableMobileCarousel's
9
- * reorder-jump fix possible: a plain array index can't distinguish "this
10
- * slide moved to position 2" from "this slide was removed and a
11
- * different one is now at position 2." Reuse whatever id the caller
12
- * already keys their `.map()` on (e.g. a list's own id). */
13
- slideKey: string;
14
- /** Accessible label surfaced to the default dots indicator (e.g.
15
- * "Groceries"). Falls back to "Slide N of count" if omitted — omitting it
16
- * logs a dev-mode warning, since every real slide usually has a title
17
- * available synchronously already. */
18
- label?: string;
19
- /** SwipableMobileCarouselSlideHeader/Body/Footer, in any order/subset. */
20
- children: ReactNode;
21
- }
22
-
23
- /**
24
- * SwipableMobileCarouselSlide — a single slide of a SwipableMobileCarousel.
25
- * Renders its children only while within the carousel's mount window (the
26
- * active slide ± its configured prefetchDistance); outside that window it
27
- * renders nothing, matching both sovereign-tasks and sovereign-shopper's
28
- * existing "never fetch/render a non-neighbor slide" behavior, now
29
- * centralized instead of hand-rolled per plugin.
30
- */
31
- export function SwipableMobileCarouselSlide({ children }: SwipableMobileCarouselSlideProps) {
32
- const ctx = useContext(CarouselSlideMountContext);
33
- if (!ctx?.isMounted) return null;
34
- return <>{children}</>;
35
- }
@@ -1,42 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import styles from './SwipableMobileCarouselSlideParts.module.css';
3
-
4
- export interface SwipableMobileCarouselSlideBodyProps {
5
- children: ReactNode;
6
- /** While true, renders `loadingFallback` INSTEAD OF children — scoped to
7
- * just this region, not the whole slide. This is what fixes the
8
- * "whole slide blanks out, title included, until its own fetch resolves"
9
- * bug: a caller renders `<SwipableMobileCarouselSlideHeader>` from
10
- * already-known metadata unconditionally, and gates only this component's
11
- * `loading` on the slower fetch — the natural way to compose
12
- * Header/Body/Footer as siblings already produces that behavior, instead
13
- * of gating the entire slide behind one boolean. */
14
- loading?: boolean;
15
- loadingFallback?: ReactNode;
16
- className?: string;
17
- }
18
-
19
- const defaultLoadingFallback = <div className={styles.loading}>Loading…</div>;
20
-
21
- /**
22
- * SwipableMobileCarouselSlideBody — the scrollable region of a slide.
23
- *
24
- * Deliberately does not set `touch-action: pan-y` on its scroll container
25
- * (see SwipableMobileCarouselSlideParts.module.css's `.body` rule) — that
26
- * would intersect-to-empty against the carousel's own horizontal
27
- * touch-action handling (docs/architecture-rules.md's touch-action
28
- * intersection rule), breaking both the vertical scroll here and the
29
- * horizontal swipe between slides.
30
- */
31
- export function SwipableMobileCarouselSlideBody({
32
- children,
33
- loading = false,
34
- loadingFallback,
35
- className,
36
- }: SwipableMobileCarouselSlideBodyProps) {
37
- return (
38
- <div className={[styles.body, className].filter(Boolean).join(' ')}>
39
- {loading ? (loadingFallback ?? defaultLoadingFallback) : children}
40
- </div>
41
- );
42
- }
@@ -1,18 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import styles from './SwipableMobileCarouselSlideParts.module.css';
3
-
4
- export interface SwipableMobileCarouselSlideFooterProps {
5
- children: ReactNode;
6
- className?: string;
7
- }
8
-
9
- /**
10
- * SwipableMobileCarouselSlideFooter — always renders its children, no
11
- * loading concept. See SwipableMobileCarouselSlideHeader's doc comment.
12
- */
13
- export function SwipableMobileCarouselSlideFooter({
14
- children,
15
- className,
16
- }: SwipableMobileCarouselSlideFooterProps) {
17
- return <div className={[styles.footer, className].filter(Boolean).join(' ')}>{children}</div>;
18
- }
@@ -1,21 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import styles from './SwipableMobileCarouselSlideParts.module.css';
3
-
4
- export interface SwipableMobileCarouselSlideHeaderProps {
5
- children: ReactNode;
6
- className?: string;
7
- }
8
-
9
- /**
10
- * SwipableMobileCarouselSlideHeader — always renders its children, no
11
- * loading concept. Meant for content already known synchronously (a list's
12
- * title, color, item count from data the caller already has) so it can
13
- * render immediately even while SwipableMobileCarouselSlideBody's own
14
- * content is still loading — see that component's doc comment.
15
- */
16
- export function SwipableMobileCarouselSlideHeader({
17
- children,
18
- className,
19
- }: SwipableMobileCarouselSlideHeaderProps) {
20
- return <div className={[styles.header, className].filter(Boolean).join(' ')}>{children}</div>;
21
- }
@@ -1,29 +0,0 @@
1
- .header,
2
- .footer {
3
- flex: 0 0 auto;
4
- }
5
-
6
- .body {
7
- flex: 1 1 auto;
8
- min-height: 0; /* allow shrinking inside the slide's flex column, so it can scroll instead of overflowing */
9
- overflow-y: auto;
10
- overflow-x: hidden;
11
- /* Deliberately does NOT set touch-action: pan-y here. touch-action's
12
- effective value is the INTERSECTION of this element's and every
13
- ancestor's value (docs/architecture-rules.md) — the ancestor .scroller
14
- (SwipableMobileCarousel.module.css) needs the horizontal swipe gesture,
15
- so pan-y here ∩ that horizontal handling would resolve to neither axis
16
- working natively. Relying on the browser's default touch-action (auto)
17
- here lets native gesture arbitration between the two nested scrollers
18
- sort out which axis wins per-gesture — don't "fix" perceived nested-
19
- scroll jank by adding pan-y; it silently breaks horizontal swipe instead. */
20
- }
21
-
22
- .loading {
23
- display: flex;
24
- align-items: center;
25
- justify-content: center;
26
- height: 100%;
27
- color: var(--sv-color-text-subtle);
28
- font-size: var(--sv-font-size-sm);
29
- }
@@ -1,133 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { act, cleanup, fireEvent, render, screen } from '@testing-library/react';
4
- import { SwipableMobileCarousel } from '../SwipableMobileCarousel';
5
- import { SwipableMobileCarouselSlide } from '../SwipableMobileCarouselSlide';
6
- import { SwipableMobileCarouselSlideHeader } from '../SwipableMobileCarouselSlideHeader';
7
- import { SwipableMobileCarouselSlideBody } from '../SwipableMobileCarouselSlideBody';
8
-
9
- // Same jsdom scroll polyfill/fake-timer setup as useSnapCarousel.test.tsx,
10
- // since this component wraps that hook directly.
11
- beforeEach(() => {
12
- vi.useFakeTimers();
13
- if (!Element.prototype.scrollTo) {
14
- Element.prototype.scrollTo = vi.fn();
15
- }
16
- });
17
-
18
- afterEach(() => {
19
- vi.runOnlyPendingTimers();
20
- vi.useRealTimers();
21
- cleanup();
22
- });
23
-
24
- function setLayout(el: HTMLElement, clientWidth: number, scrollLeft: number) {
25
- Object.defineProperty(el, 'clientWidth', { value: clientWidth, configurable: true });
26
- Object.defineProperty(el, 'scrollLeft', { value: scrollLeft, configurable: true });
27
- }
28
-
29
- const KEYS = ['a', 'b', 'c', 'd', 'e'];
30
-
31
- function FiveSlides({
32
- activeIndex,
33
- onSettle,
34
- }: {
35
- activeIndex: number;
36
- onSettle: (i: number) => void;
37
- }) {
38
- return (
39
- <SwipableMobileCarousel activeIndex={activeIndex} onSettle={onSettle} aria-label="Test slides">
40
- {KEYS.map((key) => (
41
- <SwipableMobileCarouselSlide key={key} slideKey={key} label={key}>
42
- <SwipableMobileCarouselSlideHeader>{`header-${key}`}</SwipableMobileCarouselSlideHeader>
43
- <SwipableMobileCarouselSlideBody>{`body-${key}`}</SwipableMobileCarouselSlideBody>
44
- </SwipableMobileCarouselSlide>
45
- ))}
46
- </SwipableMobileCarousel>
47
- );
48
- }
49
-
50
- describe('SwipableMobileCarousel', () => {
51
- it('only mounts the active slide and its immediate neighbors (default prefetchDistance=1)', () => {
52
- render(<FiveSlides activeIndex={2} onSettle={() => {}} />);
53
- // active (c) and neighbors (b, d) are mounted
54
- expect(screen.getByText('header-b')).toBeDefined();
55
- expect(screen.getByText('header-c')).toBeDefined();
56
- expect(screen.getByText('header-d')).toBeDefined();
57
- // out-of-window slides (a, e) render nothing at all
58
- expect(screen.queryByText('header-a')).toBeNull();
59
- expect(screen.queryByText('body-a')).toBeNull();
60
- expect(screen.queryByText('header-e')).toBeNull();
61
- expect(screen.queryByText('body-e')).toBeNull();
62
- });
63
-
64
- it("SlideBody's loading prop only hides that region, not the Header", () => {
65
- render(
66
- <SwipableMobileCarousel activeIndex={0} onSettle={() => {}} aria-label="Test slides">
67
- <SwipableMobileCarouselSlide slideKey="only" label="Only">
68
- <SwipableMobileCarouselSlideHeader>the-title</SwipableMobileCarouselSlideHeader>
69
- <SwipableMobileCarouselSlideBody loading>tasks-content</SwipableMobileCarouselSlideBody>
70
- </SwipableMobileCarouselSlide>
71
- </SwipableMobileCarousel>,
72
- );
73
- expect(screen.getByText('the-title')).toBeDefined();
74
- expect(screen.queryByText('tasks-content')).toBeNull();
75
- expect(screen.getByText('Loading…')).toBeDefined();
76
- });
77
-
78
- it('calls onSettle with the new index after a swipe settles', () => {
79
- const onSettle = vi.fn();
80
- render(<FiveSlides activeIndex={0} onSettle={onSettle} />);
81
- const scroller = screen.getByRole('region', { name: 'Test slides' });
82
- setLayout(scroller, 300, 300); // scrollLeft 300 / width 300 -> index 1
83
- fireEvent.scroll(scroller);
84
- act(() => void vi.advanceTimersByTime(120));
85
- expect(onSettle).toHaveBeenCalledWith(1);
86
- });
87
-
88
- it('clicking a dot calls onSettle directly with that index', () => {
89
- const onSettle = vi.fn();
90
- render(<FiveSlides activeIndex={0} onSettle={onSettle} />);
91
- const dots = screen.getAllByRole('tab');
92
- const fourthDot = dots[3];
93
- if (!fourthDot) throw new Error('expected a 4th dot');
94
- setLayout(screen.getByRole('region', { name: 'Test slides' }), 300, 0);
95
- fireEvent.click(fourthDot);
96
- expect(onSettle).toHaveBeenCalledWith(3);
97
- });
98
-
99
- it('re-snaps and reports the new index when the active slide moves position (reorder-jump fix)', () => {
100
- function Reorderable({ order, onSettle }: { order: string[]; onSettle: (i: number) => void }) {
101
- return (
102
- <SwipableMobileCarousel activeIndex={1} onSettle={onSettle} aria-label="Test slides">
103
- {order.map((key) => (
104
- <SwipableMobileCarouselSlide key={key} slideKey={key} label={key}>
105
- <SwipableMobileCarouselSlideHeader>{`header-${key}`}</SwipableMobileCarouselSlideHeader>
106
- </SwipableMobileCarouselSlide>
107
- ))}
108
- </SwipableMobileCarousel>
109
- );
110
- }
111
- const onSettle = vi.fn();
112
- const { rerender } = render(<Reorderable order={['a', 'b', 'c']} onSettle={onSettle} />);
113
- const scroller = screen.getByRole('region', { name: 'Test slides' });
114
- setLayout(scroller, 300, 0);
115
- const spy = vi.spyOn(scroller, 'scrollTo');
116
-
117
- // 'b' (index 1, active) moves to index 0.
118
- rerender(<Reorderable order={['b', 'a', 'c']} onSettle={onSettle} />);
119
-
120
- expect(onSettle).toHaveBeenCalledWith(0);
121
- expect(spy).toHaveBeenCalledWith({ left: 0, behavior: 'instant' });
122
- });
123
-
124
- it('does not re-snap when slide order is unchanged', () => {
125
- function Reorderable({ onSettle }: { onSettle: (i: number) => void }) {
126
- return <FiveSlides activeIndex={2} onSettle={onSettle} />;
127
- }
128
- const onSettle = vi.fn();
129
- const { rerender } = render(<Reorderable onSettle={onSettle} />);
130
- rerender(<Reorderable onSettle={onSettle} />);
131
- expect(onSettle).not.toHaveBeenCalled();
132
- });
133
- });
@@ -1,61 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { cleanup, render } from '@testing-library/react';
4
- import { SwipableMobileCarousel } from '../SwipableMobileCarousel';
5
- import { SwipableMobileCarouselSlide } from '../SwipableMobileCarouselSlide';
6
-
7
- beforeEach(() => {
8
- if (!Element.prototype.scrollTo) {
9
- Element.prototype.scrollTo = vi.fn();
10
- }
11
- });
12
-
13
- afterEach(() => {
14
- cleanup();
15
- vi.restoreAllMocks();
16
- });
17
-
18
- function renderWithStrayChild() {
19
- return render(
20
- <SwipableMobileCarousel activeIndex={0} onSettle={() => {}} aria-label="Test slides">
21
- <SwipableMobileCarouselSlide slideKey="a" label="A">
22
- content
23
- </SwipableMobileCarouselSlide>
24
- {/* stray non-Slide child — shifts index math for anything after it */}
25
- <div>oops</div>
26
- <SwipableMobileCarouselSlide slideKey="b" label="B">
27
- content
28
- </SwipableMobileCarouselSlide>
29
- </SwipableMobileCarousel>,
30
- );
31
- }
32
-
33
- describe('SwipableMobileCarousel dev-mode child-type guard', () => {
34
- it('warns via console.error in development, mentioning the offending child', () => {
35
- const originalEnv = process.env.NODE_ENV;
36
- vi.stubEnv('NODE_ENV', 'development');
37
- const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
38
-
39
- expect(() => renderWithStrayChild()).not.toThrow();
40
-
41
- expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('<div>'));
42
- vi.stubEnv('NODE_ENV', originalEnv ?? 'test');
43
- });
44
-
45
- it('does not call console.error in production', () => {
46
- const originalEnv = process.env.NODE_ENV;
47
- vi.stubEnv('NODE_ENV', 'production');
48
- const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
49
-
50
- expect(() => renderWithStrayChild()).not.toThrow();
51
-
52
- expect(errorSpy).not.toHaveBeenCalled();
53
- vi.stubEnv('NODE_ENV', originalEnv ?? 'test');
54
- });
55
-
56
- it('never throws, even with a stray child (a miscounted slide degrades, it does not crash)', () => {
57
- vi.stubEnv('NODE_ENV', 'development');
58
- vi.spyOn(console, 'error').mockImplementation(() => {});
59
- expect(() => renderWithStrayChild()).not.toThrow();
60
- });
61
- });
@@ -1,13 +0,0 @@
1
- 'use client';
2
-
3
- import { createContext } from 'react';
4
-
5
- export interface CarouselSlideMountContextValue {
6
- /** Whether this slide is within the carousel's mount window (the active
7
- * slide ± its configured prefetchDistance). Kept out of the main .tsx
8
- * file for React Fast Refresh hygiene (a file exporting only components
9
- * refreshes more reliably than one mixing components and plain values). */
10
- isMounted: boolean;
11
- }
12
-
13
- export const CarouselSlideMountContext = createContext<CarouselSlideMountContextValue | null>(null);
@@ -1,49 +0,0 @@
1
- .dots {
2
- display: flex;
3
- align-items: center;
4
- justify-content: center;
5
- gap: var(--sv-space-2);
6
- }
7
-
8
- .dot {
9
- /* A 6px visible dot is too small a hit target on its own — the button's
10
- real box is larger (20px) with the dot itself painted by ::before and
11
- centered inside, so tap area grows without changing the visible dot
12
- size or the row's gap-based spacing math. */
13
- position: relative;
14
- width: 20px;
15
- height: 20px;
16
- padding: 0;
17
- border: none;
18
- background: transparent;
19
- cursor: pointer;
20
- }
21
-
22
- .dot::before {
23
- content: '';
24
- position: absolute;
25
- top: 50%;
26
- left: 50%;
27
- width: 6px;
28
- height: 6px;
29
- border-radius: 50%;
30
- background: var(--sv-color-border-strong);
31
- transform: translate(-50%, -50%);
32
- transition: background 0.15s ease;
33
- }
34
-
35
- .dot:focus-visible {
36
- outline: 2px solid var(--sv-color-focus-ring);
37
- outline-offset: 2px;
38
- border-radius: 50%;
39
- }
40
-
41
- .dotActive::before {
42
- background: var(--sv-color-text-primary);
43
- }
44
-
45
- @media (hover: hover) {
46
- .dot:not(.dotActive):hover::before {
47
- background: var(--sv-color-text-muted);
48
- }
49
- }