@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,117 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { act, cleanup, fireEvent, render } from '@testing-library/react';
4
- import { useDoubleTapHandler, useSingleOrDoubleTap } from '../useDoubleTap';
5
-
6
- // A minimal harness: the hook returns a handler bound to onClick. Real
7
- // double-clicks report detail===2; two separate taps report detail===1 each.
8
- function DoubleTapHarness({ onDouble }: { onDouble: () => void }) {
9
- const handle = useDoubleTapHandler<React.MouseEvent>(() => onDouble());
10
- return (
11
- <button data-testid="btn" onClick={handle}>
12
- tap
13
- </button>
14
- );
15
- }
16
-
17
- function SingleOrDoubleHarness({
18
- onSingle,
19
- onDouble,
20
- }: {
21
- onSingle: () => void;
22
- onDouble: () => void;
23
- }) {
24
- const handle = useSingleOrDoubleTap<React.MouseEvent>(
25
- () => onSingle(),
26
- () => onDouble(),
27
- );
28
- return (
29
- <button data-testid="btn" onClick={handle}>
30
- tap
31
- </button>
32
- );
33
- }
34
-
35
- describe('useDoubleTapHandler', () => {
36
- beforeEach(() => vi.useFakeTimers());
37
- afterEach(() => {
38
- vi.useRealTimers();
39
- cleanup();
40
- });
41
-
42
- it('fires immediately on a native double-click (detail === 2)', () => {
43
- const onDouble = vi.fn();
44
- const { getByTestId } = render(<DoubleTapHarness onDouble={onDouble} />);
45
- fireEvent.click(getByTestId('btn'), { detail: 2 });
46
- expect(onDouble).toHaveBeenCalledOnce();
47
- });
48
-
49
- it('fires on two touch taps within the window', () => {
50
- const onDouble = vi.fn();
51
- const { getByTestId } = render(<DoubleTapHarness onDouble={onDouble} />);
52
- const btn = getByTestId('btn');
53
- fireEvent.click(btn, { detail: 1 });
54
- act(() => void vi.advanceTimersByTime(100));
55
- fireEvent.click(btn, { detail: 1 });
56
- expect(onDouble).toHaveBeenCalledOnce();
57
- });
58
-
59
- it('does not fire on a single tap', () => {
60
- const onDouble = vi.fn();
61
- const { getByTestId } = render(<DoubleTapHarness onDouble={onDouble} />);
62
- fireEvent.click(getByTestId('btn'), { detail: 1 });
63
- act(() => void vi.advanceTimersByTime(1000));
64
- expect(onDouble).not.toHaveBeenCalled();
65
- });
66
- });
67
-
68
- describe('useSingleOrDoubleTap', () => {
69
- beforeEach(() => vi.useFakeTimers());
70
- afterEach(() => {
71
- vi.useRealTimers();
72
- cleanup();
73
- });
74
-
75
- it('defers the single action until the double-tap window closes', () => {
76
- const onSingle = vi.fn();
77
- const onDouble = vi.fn();
78
- const { getByTestId } = render(
79
- <SingleOrDoubleHarness onSingle={onSingle} onDouble={onDouble} />,
80
- );
81
- fireEvent.click(getByTestId('btn'), { detail: 1 });
82
- // Single must NOT have fired yet — this deferral is the whole point.
83
- expect(onSingle).not.toHaveBeenCalled();
84
- act(() => void vi.advanceTimersByTime(350));
85
- expect(onSingle).toHaveBeenCalledOnce();
86
- expect(onDouble).not.toHaveBeenCalled();
87
- });
88
-
89
- it('fires double (and never single) when a second tap arrives in time', () => {
90
- const onSingle = vi.fn();
91
- const onDouble = vi.fn();
92
- const { getByTestId } = render(
93
- <SingleOrDoubleHarness onSingle={onSingle} onDouble={onDouble} />,
94
- );
95
- const btn = getByTestId('btn');
96
- fireEvent.click(btn, { detail: 1 });
97
- act(() => void vi.advanceTimersByTime(100));
98
- fireEvent.click(btn, { detail: 1 });
99
- act(() => void vi.advanceTimersByTime(500));
100
- expect(onDouble).toHaveBeenCalledOnce();
101
- expect(onSingle).not.toHaveBeenCalled();
102
- });
103
-
104
- it('fires double on a native double-click and cancels the pending single', () => {
105
- const onSingle = vi.fn();
106
- const onDouble = vi.fn();
107
- const { getByTestId } = render(
108
- <SingleOrDoubleHarness onSingle={onSingle} onDouble={onDouble} />,
109
- );
110
- const btn = getByTestId('btn');
111
- fireEvent.click(btn, { detail: 1 });
112
- fireEvent.click(btn, { detail: 2 });
113
- act(() => void vi.advanceTimersByTime(500));
114
- expect(onDouble).toHaveBeenCalledOnce();
115
- expect(onSingle).not.toHaveBeenCalled();
116
- });
117
- });
@@ -1,80 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { act, cleanup, render } from '@testing-library/react';
4
- import { MOBILE_BREAKPOINT_PX, useIsMobile } from '../useIsMobile';
5
-
6
- // Capture the registered change listener so a test can drive a viewport change.
7
- let changeHandler: ((e: MediaQueryListEvent) => void) | null = null;
8
- let matches = false;
9
- let lastQuery = '';
10
-
11
- function installMatchMedia() {
12
- changeHandler = null;
13
- vi.stubGlobal(
14
- 'matchMedia',
15
- vi.fn().mockImplementation((query: string) => {
16
- lastQuery = query;
17
- return {
18
- matches,
19
- media: query,
20
- addEventListener: (_: string, cb: (e: MediaQueryListEvent) => void) => {
21
- changeHandler = cb;
22
- },
23
- removeEventListener: vi.fn(),
24
- addListener: vi.fn(),
25
- removeListener: vi.fn(),
26
- dispatchEvent: vi.fn(),
27
- };
28
- }),
29
- );
30
- }
31
-
32
- function Harness({ breakpoint }: { breakpoint?: number }) {
33
- const isMobile = useIsMobile(breakpoint);
34
- return <span data-testid="out">{String(isMobile)}</span>;
35
- }
36
-
37
- describe('useIsMobile', () => {
38
- beforeEach(() => {
39
- matches = false;
40
- installMatchMedia();
41
- });
42
- afterEach(() => {
43
- vi.unstubAllGlobals();
44
- cleanup();
45
- });
46
-
47
- it('exports the canonical 768px breakpoint', () => {
48
- expect(MOBILE_BREAKPOINT_PX).toBe(768);
49
- });
50
-
51
- it('defaults to the canonical breakpoint in its query', () => {
52
- matches = true;
53
- installMatchMedia();
54
- render(<Harness />);
55
- expect(lastQuery).toBe('(max-width: 768px)');
56
- });
57
-
58
- it('reflects the initial matchMedia result after mount', () => {
59
- matches = true;
60
- installMatchMedia();
61
- const { getByTestId } = render(<Harness />);
62
- expect(getByTestId('out').textContent).toBe('true');
63
- });
64
-
65
- it('updates when the viewport crosses the breakpoint', () => {
66
- matches = false;
67
- installMatchMedia();
68
- const { getByTestId } = render(<Harness />);
69
- expect(getByTestId('out').textContent).toBe('false');
70
- act(() => changeHandler?.({ matches: true } as MediaQueryListEvent));
71
- expect(getByTestId('out').textContent).toBe('true');
72
- });
73
-
74
- it('honours a custom breakpoint override', () => {
75
- matches = false;
76
- installMatchMedia();
77
- render(<Harness breakpoint={640} />);
78
- expect(lastQuery).toBe('(max-width: 640px)');
79
- });
80
- });
@@ -1,53 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { act, cleanup, render } from '@testing-library/react';
4
- import { useIsOffline } from '../useIsOffline';
5
-
6
- function Harness() {
7
- const isOffline = useIsOffline();
8
- return <span data-testid="out">{String(isOffline)}</span>;
9
- }
10
-
11
- describe('useIsOffline', () => {
12
- beforeEach(() => {
13
- vi.stubGlobal('navigator', { ...window.navigator, onLine: true });
14
- });
15
- afterEach(() => {
16
- vi.unstubAllGlobals();
17
- cleanup();
18
- });
19
-
20
- it('reflects navigator.onLine after mount', () => {
21
- vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
22
- const { getByTestId } = render(<Harness />);
23
- expect(getByTestId('out').textContent).toBe('true');
24
- });
25
-
26
- it('does not report offline when navigator.onLine is true', () => {
27
- const { getByTestId } = render(<Harness />);
28
- expect(getByTestId('out').textContent).toBe('false');
29
- });
30
-
31
- it('flips on the offline event', () => {
32
- const { getByTestId } = render(<Harness />);
33
- expect(getByTestId('out').textContent).toBe('false');
34
- act(() => window.dispatchEvent(new Event('offline')));
35
- expect(getByTestId('out').textContent).toBe('true');
36
- });
37
-
38
- it('flips back on the online event', () => {
39
- vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
40
- const { getByTestId } = render(<Harness />);
41
- expect(getByTestId('out').textContent).toBe('true');
42
- act(() => window.dispatchEvent(new Event('online')));
43
- expect(getByTestId('out').textContent).toBe('false');
44
- });
45
-
46
- it('removes its listeners on unmount', () => {
47
- const removeSpy = vi.spyOn(window, 'removeEventListener');
48
- const { unmount } = render(<Harness />);
49
- unmount();
50
- expect(removeSpy).toHaveBeenCalledWith('offline', expect.any(Function));
51
- expect(removeSpy).toHaveBeenCalledWith('online', expect.any(Function));
52
- });
53
- });
@@ -1,158 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { act, cleanup, fireEvent, render } from '@testing-library/react';
4
- import { useLongPress, type UseLongPressOptions } from '../useLongPress';
5
-
6
- // Configurable matchMedia mock — usePrefersCoarsePointer reads
7
- // '(pointer: coarse)', and the SSR-safe hooks read it on mount. Default to a
8
- // coarse (touch) device so the suppression styles are exercised; individual
9
- // tests override `coarse` where they assert the desktop path.
10
- let coarse = true;
11
- function installMatchMedia() {
12
- vi.stubGlobal(
13
- 'matchMedia',
14
- vi.fn().mockImplementation((query: string) => ({
15
- matches: query.includes('pointer: coarse') ? coarse : false,
16
- media: query,
17
- addEventListener: vi.fn(),
18
- removeEventListener: vi.fn(),
19
- addListener: vi.fn(),
20
- removeListener: vi.fn(),
21
- dispatchEvent: vi.fn(),
22
- })),
23
- );
24
- }
25
-
26
- // A tiny harness component: spreads the hook's handlers onto a div so we can
27
- // fire real pointer events at it via Testing Library.
28
- function Harness(props: UseLongPressOptions & { testId?: string }) {
29
- const { testId = 'target', ...options } = props;
30
- const handlers = useLongPress(options);
31
- return (
32
- <div data-testid={testId} {...handlers}>
33
- target
34
- </div>
35
- );
36
- }
37
-
38
- function pointer(type: 'touch' | 'mouse', x = 0, y = 0) {
39
- return { pointerType: type, clientX: x, clientY: y };
40
- }
41
-
42
- describe('useLongPress', () => {
43
- beforeEach(() => {
44
- coarse = true;
45
- installMatchMedia();
46
- vi.useFakeTimers();
47
- });
48
-
49
- afterEach(() => {
50
- vi.runOnlyPendingTimers();
51
- vi.useRealTimers();
52
- vi.unstubAllGlobals();
53
- cleanup();
54
- });
55
-
56
- it('fires onLongPress after the delay on a touch press held still', () => {
57
- const onLongPress = vi.fn();
58
- const { getByTestId } = render(<Harness onLongPress={onLongPress} delay={500} />);
59
- fireEvent.pointerDown(getByTestId('target'), pointer('touch'));
60
- expect(onLongPress).not.toHaveBeenCalled();
61
- act(() => void vi.advanceTimersByTime(500));
62
- expect(onLongPress).toHaveBeenCalledOnce();
63
- });
64
-
65
- it('does not arm for a mouse pointer (desktop keeps its own affordance)', () => {
66
- const onLongPress = vi.fn();
67
- const { getByTestId } = render(<Harness onLongPress={onLongPress} delay={500} />);
68
- fireEvent.pointerDown(getByTestId('target'), pointer('mouse'));
69
- act(() => void vi.advanceTimersByTime(1000));
70
- expect(onLongPress).not.toHaveBeenCalled();
71
- });
72
-
73
- it('tolerates finger jitter within moveTolerance', () => {
74
- const onLongPress = vi.fn();
75
- const { getByTestId } = render(
76
- <Harness onLongPress={onLongPress} delay={500} moveTolerance={10} />,
77
- );
78
- const el = getByTestId('target');
79
- fireEvent.pointerDown(el, pointer('touch', 0, 0));
80
- fireEvent.pointerMove(el, pointer('touch', 4, 4)); // ~5.7px < 10
81
- act(() => void vi.advanceTimersByTime(500));
82
- expect(onLongPress).toHaveBeenCalledOnce();
83
- });
84
-
85
- it('cancels when movement exceeds moveTolerance', () => {
86
- const onLongPress = vi.fn();
87
- const { getByTestId } = render(
88
- <Harness onLongPress={onLongPress} delay={500} moveTolerance={10} />,
89
- );
90
- const el = getByTestId('target');
91
- fireEvent.pointerDown(el, pointer('touch', 0, 0));
92
- fireEvent.pointerMove(el, pointer('touch', 20, 0)); // 20px > 10
93
- act(() => void vi.advanceTimersByTime(500));
94
- expect(onLongPress).not.toHaveBeenCalled();
95
- });
96
-
97
- it('cancels on pointercancel (touch converted to scroll)', () => {
98
- const onLongPress = vi.fn();
99
- const { getByTestId } = render(<Harness onLongPress={onLongPress} delay={500} />);
100
- const el = getByTestId('target');
101
- fireEvent.pointerDown(el, pointer('touch'));
102
- fireEvent.pointerCancel(el, pointer('touch'));
103
- act(() => void vi.advanceTimersByTime(500));
104
- expect(onLongPress).not.toHaveBeenCalled();
105
- });
106
-
107
- it('suppresses the click that may follow, but only for a bounded window', () => {
108
- const onLongPress = vi.fn();
109
- const { getByTestId } = render(
110
- <Harness onLongPress={onLongPress} delay={500} suppressClickMs={700} />,
111
- );
112
- const el = getByTestId('target');
113
- fireEvent.pointerDown(el, pointer('touch'));
114
- act(() => void vi.advanceTimersByTime(500));
115
- expect(onLongPress).toHaveBeenCalledOnce();
116
-
117
- // A click arriving right after the long-press is swallowed.
118
- const suppressed = fireEvent.click(el);
119
- expect(suppressed).toBe(false); // preventDefault called → fireEvent returns false
120
-
121
- // After the suppression window, a genuinely unrelated later tap is NOT eaten.
122
- act(() => void vi.advanceTimersByTime(800));
123
- const allowed = fireEvent.click(el);
124
- expect(allowed).toBe(true);
125
- });
126
-
127
- it('prevents the OS context menu while a press is pending', () => {
128
- const { getByTestId } = render(<Harness onLongPress={vi.fn()} delay={500} />);
129
- const el = getByTestId('target');
130
- fireEvent.pointerDown(el, pointer('touch'));
131
- const prevented = fireEvent.contextMenu(el);
132
- expect(prevented).toBe(false); // preventDefault called
133
- });
134
-
135
- it('does nothing when disabled', () => {
136
- const onLongPress = vi.fn();
137
- const { getByTestId } = render(<Harness onLongPress={onLongPress} delay={500} disabled />);
138
- fireEvent.pointerDown(getByTestId('target'), pointer('touch'));
139
- act(() => void vi.advanceTimersByTime(500));
140
- expect(onLongPress).not.toHaveBeenCalled();
141
- });
142
-
143
- it('emits suppression styles only on coarse-pointer devices', () => {
144
- coarse = true;
145
- installMatchMedia();
146
- const { getByTestId, rerender } = render(<Harness onLongPress={vi.fn()} testId="coarse" />);
147
- // jsdom applies the inline style object; user-select none is the tell.
148
- expect(getByTestId('coarse').style.userSelect).toBe('none');
149
-
150
- coarse = false;
151
- installMatchMedia();
152
- rerender(<Harness onLongPress={vi.fn()} testId="coarse" />);
153
- // A remount picks up the new (fine-pointer) matchMedia result.
154
- cleanup();
155
- const fine = render(<Harness onLongPress={vi.fn()} testId="fine" />);
156
- expect(fine.getByTestId('fine').style.userSelect).toBe('');
157
- });
158
- });
@@ -1,69 +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 { useOfflineTileState } from '../useOfflineTileState';
5
-
6
- function Harness({
7
- offline,
8
- deviceOnlyAvailable,
9
- }: {
10
- offline: 'offline-first' | 'device-only' | undefined;
11
- deviceOnlyAvailable: boolean;
12
- }) {
13
- const state = useOfflineTileState(offline, deviceOnlyAvailable);
14
- return <span data-testid="out">{String(state)}</span>;
15
- }
16
-
17
- describe('useOfflineTileState', () => {
18
- beforeEach(() => {
19
- vi.stubGlobal('navigator', { ...window.navigator, onLine: true });
20
- });
21
- afterEach(() => {
22
- vi.unstubAllGlobals();
23
- cleanup();
24
- });
25
-
26
- it('is null for a no-tier app while online', () => {
27
- const { getByTestId } = render(<Harness offline={undefined} deviceOnlyAvailable={false} />);
28
- expect(getByTestId('out').textContent).toBe('null');
29
- });
30
-
31
- it('connectivity-dims a no-tier app while offline', () => {
32
- vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
33
- const { getByTestId } = render(<Harness offline={undefined} deviceOnlyAvailable={false} />);
34
- expect(getByTestId('out').textContent).toBe('connectivity-dimmed');
35
- });
36
-
37
- it('never dims an offline-first app, online or offline', () => {
38
- const online = render(<Harness offline="offline-first" deviceOnlyAvailable={false} />);
39
- expect(online.getByTestId('out').textContent).toBe('null');
40
- cleanup();
41
-
42
- vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
43
- const offline = render(<Harness offline="offline-first" deviceOnlyAvailable={false} />);
44
- expect(offline.getByTestId('out').textContent).toBe('null');
45
- });
46
-
47
- it('capability-restricts a device-only app when unavailable, regardless of connectivity', () => {
48
- const online = render(<Harness offline="device-only" deviceOnlyAvailable={false} />);
49
- expect(online.getByTestId('out').textContent).toBe('capability-restricted');
50
- cleanup();
51
-
52
- vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
53
- const offline = render(<Harness offline="device-only" deviceOnlyAvailable={false} />);
54
- expect(offline.getByTestId('out').textContent).toBe('capability-restricted');
55
- });
56
-
57
- it('is not restricted for a device-only app when available, and not dimmed offline either', () => {
58
- const online = render(<Harness offline="device-only" deviceOnlyAvailable={true} />);
59
- expect(online.getByTestId('out').textContent).toBe('null');
60
- cleanup();
61
-
62
- // Availability is a capability signal, not a connectivity one — a
63
- // device-only app that IS available behaves like offline-first once the
64
- // capability question is settled.
65
- vi.stubGlobal('navigator', { ...window.navigator, onLine: false });
66
- const offline = render(<Harness offline="device-only" deviceOnlyAvailable={true} />);
67
- expect(offline.getByTestId('out').textContent).toBe('null');
68
- });
69
- });
@@ -1,87 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { act, cleanup, render } from '@testing-library/react';
4
- import { useResponsiveLayout } from '../useResponsiveLayout';
5
-
6
- // Same matchMedia mocking approach as useIsMobile.test.tsx, since this hook
7
- // is a thin wrapper over it and must not diverge in SSR/breakpoint behavior.
8
- let changeHandler: ((e: MediaQueryListEvent) => void) | null = null;
9
- let matches = false;
10
- let lastQuery = '';
11
-
12
- function installMatchMedia() {
13
- changeHandler = null;
14
- vi.stubGlobal(
15
- 'matchMedia',
16
- vi.fn().mockImplementation((query: string) => {
17
- lastQuery = query;
18
- return {
19
- matches,
20
- media: query,
21
- addEventListener: (_: string, cb: (e: MediaQueryListEvent) => void) => {
22
- changeHandler = cb;
23
- },
24
- removeEventListener: vi.fn(),
25
- addListener: vi.fn(),
26
- removeListener: vi.fn(),
27
- dispatchEvent: vi.fn(),
28
- };
29
- }),
30
- );
31
- }
32
-
33
- function Harness({ breakpointPx }: { breakpointPx?: number }) {
34
- const { isMobile, value } = useResponsiveLayout({
35
- web: 'web-tree',
36
- mobile: 'mobile-tree',
37
- breakpointPx,
38
- });
39
- return (
40
- <span data-testid="out" data-is-mobile={String(isMobile)}>
41
- {value}
42
- </span>
43
- );
44
- }
45
-
46
- describe('useResponsiveLayout', () => {
47
- beforeEach(() => {
48
- matches = false;
49
- installMatchMedia();
50
- });
51
- afterEach(() => {
52
- vi.unstubAllGlobals();
53
- cleanup();
54
- });
55
-
56
- it('defaults to the web value before/without a mobile match (SSR-safe default)', () => {
57
- matches = false;
58
- installMatchMedia();
59
- const { getByTestId } = render(<Harness />);
60
- expect(getByTestId('out').textContent).toBe('web-tree');
61
- expect(getByTestId('out').dataset.isMobile).toBe('false');
62
- });
63
-
64
- it('picks the mobile value once matchMedia reports a match', () => {
65
- matches = true;
66
- installMatchMedia();
67
- const { getByTestId } = render(<Harness />);
68
- expect(getByTestId('out').textContent).toBe('mobile-tree');
69
- expect(getByTestId('out').dataset.isMobile).toBe('true');
70
- });
71
-
72
- it('swaps live when the viewport crosses the breakpoint', () => {
73
- matches = false;
74
- installMatchMedia();
75
- const { getByTestId } = render(<Harness />);
76
- expect(getByTestId('out').textContent).toBe('web-tree');
77
- act(() => changeHandler?.({ matches: true } as MediaQueryListEvent));
78
- expect(getByTestId('out').textContent).toBe('mobile-tree');
79
- });
80
-
81
- it('passes a custom breakpointPx straight through to useIsMobile', () => {
82
- matches = false;
83
- installMatchMedia();
84
- render(<Harness breakpointPx={640} />);
85
- expect(lastQuery).toBe('(max-width: 640px)');
86
- });
87
- });
@@ -1,93 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { act, cleanup, fireEvent, render } from '@testing-library/react';
4
- import { useSnapCarousel, type UseSnapCarouselOptions } from '../useSnapCarousel';
5
-
6
- // jsdom doesn't implement scrollTo on elements.
7
- beforeEach(() => {
8
- vi.useFakeTimers();
9
- if (!Element.prototype.scrollTo) {
10
- Element.prototype.scrollTo = vi.fn();
11
- }
12
- });
13
-
14
- afterEach(() => {
15
- vi.runOnlyPendingTimers();
16
- vi.useRealTimers();
17
- cleanup();
18
- });
19
-
20
- function setLayout(el: HTMLElement, clientWidth: number, scrollLeft: number) {
21
- Object.defineProperty(el, 'clientWidth', { value: clientWidth, configurable: true });
22
- Object.defineProperty(el, 'scrollLeft', { value: scrollLeft, configurable: true });
23
- }
24
-
25
- function Harness(
26
- props: UseSnapCarouselOptions & { onScrollTo?: (fn: (i: number) => void) => void },
27
- ) {
28
- const { onScrollTo, ...options } = props;
29
- const { scrollRef, scrollToIndex } = useSnapCarousel(options);
30
- onScrollTo?.(scrollToIndex);
31
- return <div data-testid="scroller" ref={scrollRef} />;
32
- }
33
-
34
- describe('useSnapCarousel', () => {
35
- it('calls onSettle with the new index after the debounce window', () => {
36
- const onSettle = vi.fn();
37
- const { getByTestId } = render(<Harness itemCount={3} onSettle={onSettle} debounceMs={120} />);
38
- const el = getByTestId('scroller');
39
- setLayout(el, 300, 300); // scrollLeft 300 / width 300 -> index 1
40
- fireEvent.scroll(el);
41
- expect(onSettle).not.toHaveBeenCalled();
42
- act(() => void vi.advanceTimersByTime(120));
43
- expect(onSettle).toHaveBeenCalledWith(1);
44
- });
45
-
46
- it('debounces repeated scroll events into a single settle call', () => {
47
- const onSettle = vi.fn();
48
- const { getByTestId } = render(<Harness itemCount={3} onSettle={onSettle} debounceMs={120} />);
49
- const el = getByTestId('scroller');
50
- setLayout(el, 300, 0);
51
- fireEvent.scroll(el);
52
- act(() => void vi.advanceTimersByTime(60));
53
- setLayout(el, 300, 300);
54
- fireEvent.scroll(el);
55
- act(() => void vi.advanceTimersByTime(120));
56
- expect(onSettle).toHaveBeenCalledOnce();
57
- expect(onSettle).toHaveBeenCalledWith(1);
58
- });
59
-
60
- it('does not call onSettle again for the same index', () => {
61
- const onSettle = vi.fn();
62
- const { getByTestId } = render(<Harness itemCount={3} onSettle={onSettle} debounceMs={120} />);
63
- const el = getByTestId('scroller');
64
- setLayout(el, 300, 300);
65
- fireEvent.scroll(el);
66
- act(() => void vi.advanceTimersByTime(120));
67
- fireEvent.scroll(el);
68
- act(() => void vi.advanceTimersByTime(120));
69
- expect(onSettle).toHaveBeenCalledOnce();
70
- });
71
-
72
- it('clamps the settled index within [0, itemCount - 1]', () => {
73
- const onSettle = vi.fn();
74
- const { getByTestId } = render(<Harness itemCount={2} onSettle={onSettle} debounceMs={120} />);
75
- const el = getByTestId('scroller');
76
- setLayout(el, 300, 900); // rounds to index 3, clamps to itemCount - 1 = 1
77
- fireEvent.scroll(el);
78
- act(() => void vi.advanceTimersByTime(120));
79
- expect(onSettle).toHaveBeenCalledWith(1);
80
- });
81
-
82
- it('scrollToIndex scrolls the container to the target slide', () => {
83
- let scrollToIndex: ((index: number) => void) | undefined;
84
- const { getByTestId } = render(
85
- <Harness itemCount={3} onScrollTo={(fn) => (scrollToIndex = fn)} />,
86
- );
87
- const el = getByTestId('scroller');
88
- setLayout(el, 400, 0);
89
- const spy = vi.spyOn(el, 'scrollTo');
90
- scrollToIndex?.(2);
91
- expect(spy).toHaveBeenCalledWith({ left: 800, behavior: 'smooth' });
92
- });
93
- });