@passui/react 0.1.17 → 0.1.20

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 (408) hide show
  1. package/README.md +140 -1
  2. package/THIRD_PARTY_NOTICES.md +25 -0
  3. package/dist/types/src/appearance/index.d.ts +2 -0
  4. package/dist/types/src/appearance/platform.d.ts +9 -0
  5. package/dist/types/src/appearance/theme.d.ts +71 -0
  6. package/dist/types/src/components/accordion/accordion.d.ts +19 -0
  7. package/dist/types/src/components/ambient/ambient.d.ts +12 -0
  8. package/dist/types/src/components/ambient/index.d.ts +1 -0
  9. package/dist/types/src/components/aspect-ratio/aspect-ratio.d.ts +7 -0
  10. package/dist/types/src/components/breadcrumb/breadcrumb.d.ts +16 -0
  11. package/dist/types/src/components/button/button-styles.d.ts +12 -0
  12. package/dist/types/src/components/button/button.d.ts +32 -0
  13. package/dist/types/src/components/button/icon-button.d.ts +10 -0
  14. package/dist/types/src/components/button/pending-spinner.d.ts +5 -0
  15. package/dist/types/src/components/button/use-pending-indicator.d.ts +2 -0
  16. package/dist/types/src/components/chip/chip.d.ts +7 -0
  17. package/dist/types/src/components/code-block/code-block.d.ts +10 -0
  18. package/dist/types/src/components/combo-box/combo-box.d.ts +9 -0
  19. package/dist/types/src/components/command/command.d.ts +18 -0
  20. package/dist/types/src/components/compact-date-picker/calendar-month.d.ts +25 -0
  21. package/dist/types/src/components/compact-date-picker/compact-date-picker.d.ts +27 -0
  22. package/dist/types/src/components/compact-time-picker/compact-time-picker.d.ts +26 -0
  23. package/dist/types/src/components/compact-time-picker/time-value.d.ts +18 -0
  24. package/dist/types/src/components/content-unavailable-view/content-unavailable-view.d.ts +9 -0
  25. package/dist/types/src/components/content-view/content-view.d.ts +48 -0
  26. package/dist/types/src/components/content-view/index.d.ts +1 -0
  27. package/dist/types/src/components/context-menu/conceal-menu-source.d.ts +2 -0
  28. package/dist/types/src/components/context-menu/context-menu-host.d.ts +2 -0
  29. package/dist/types/src/components/context-menu/context-menu-store.d.ts +57 -0
  30. package/dist/types/src/components/context-menu/menu-navigation.d.ts +6 -0
  31. package/dist/types/src/components/context-menu/menu-position.d.ts +21 -0
  32. package/dist/types/src/components/context-menu/menu-reveal.d.ts +17 -0
  33. package/dist/types/src/components/context-menu/use-context-menu.d.ts +14 -0
  34. package/dist/types/src/components/conversation/conversation.d.ts +43 -0
  35. package/dist/types/src/components/conversation/index.d.ts +1 -0
  36. package/dist/types/src/components/date-picker/date-picker.d.ts +16 -0
  37. package/dist/types/src/components/date-picker/date-value.d.ts +2 -0
  38. package/dist/types/src/components/dialog/dialog-host.d.ts +6 -0
  39. package/dist/types/src/components/dialog/dialog-store.d.ts +23 -0
  40. package/dist/types/src/components/dialog/dialog.d.ts +30 -0
  41. package/dist/types/src/components/dialog/index.d.ts +1 -0
  42. package/dist/types/src/components/disclosure-group/disclosure-group.d.ts +15 -0
  43. package/dist/types/src/components/divider/divider.d.ts +9 -0
  44. package/dist/types/src/components/inline-disclosure/inline-disclosure.d.ts +15 -0
  45. package/dist/types/src/components/keyboard-shortcut/keyboard-shortcut.d.ts +5 -0
  46. package/dist/types/src/components/labeled-content/labeled-content.d.ts +19 -0
  47. package/dist/types/src/components/locale-switcher/index.d.ts +1 -0
  48. package/dist/types/src/components/locale-switcher/locale-switcher.d.ts +10 -0
  49. package/dist/types/src/components/menu/menu.d.ts +16 -0
  50. package/dist/types/src/components/one-time-code/one-time-code.d.ts +18 -0
  51. package/dist/types/src/components/picker/picker-trigger.d.ts +2 -0
  52. package/dist/types/src/components/picker/picker.d.ts +43 -0
  53. package/dist/types/src/components/popover/anchored-surface.d.ts +13 -0
  54. package/dist/types/src/components/popover/popover-fit.d.ts +21 -0
  55. package/dist/types/src/components/popover/popover.d.ts +18 -0
  56. package/dist/types/src/components/profile-image/profile-image.d.ts +4 -0
  57. package/dist/types/src/components/progress-view/progress-view.d.ts +13 -0
  58. package/dist/types/src/components/progress-view/use-liquid-progress.d.ts +3 -0
  59. package/dist/types/src/components/radio-group/radio-group.d.ts +17 -0
  60. package/dist/types/src/components/search-field/expanding-search-field.d.ts +5 -0
  61. package/dist/types/src/components/search-field/search-field.d.ts +6 -0
  62. package/dist/types/src/components/search-list/search-list.d.ts +19 -0
  63. package/dist/types/src/components/section/section.d.ts +15 -0
  64. package/dist/types/src/components/secure-field/secure-field.d.ts +4 -0
  65. package/dist/types/src/components/segmented-control/segmented-control.d.ts +20 -0
  66. package/dist/types/src/components/sheet/modal-environment.d.ts +2 -0
  67. package/dist/types/src/components/sheet/sheet-portal.d.ts +5 -0
  68. package/dist/types/src/components/sheet/sheet.d.ts +21 -0
  69. package/dist/types/src/components/sheet/use-sheet-focus.d.ts +3 -0
  70. package/dist/types/src/components/sidebar/sidebar.d.ts +19 -0
  71. package/dist/types/src/components/skeleton/skeleton.d.ts +6 -0
  72. package/dist/types/src/components/slider/slider.d.ts +14 -0
  73. package/dist/types/src/components/slosh-slider/liquid-step.d.ts +6 -0
  74. package/dist/types/src/components/slosh-slider/slosh-slider.d.ts +18 -0
  75. package/dist/types/src/components/stat-tile/index.d.ts +1 -0
  76. package/dist/types/src/components/stat-tile/stat-tile.d.ts +15 -0
  77. package/dist/types/src/components/status-indicator/status-indicator.d.ts +14 -0
  78. package/dist/types/src/components/stepper/rolling-digit.d.ts +11 -0
  79. package/dist/types/src/components/stepper/stepper.d.ts +19 -0
  80. package/dist/types/src/components/swatch-picker/swatch-picker.d.ts +17 -0
  81. package/dist/types/src/components/tab-bar/tab-bar.d.ts +40 -0
  82. package/dist/types/src/components/tab-view/tab-view.d.ts +24 -0
  83. package/dist/types/src/components/table/table.d.ts +10 -0
  84. package/dist/types/src/components/text-editor/text-editor.d.ts +2 -0
  85. package/dist/types/src/components/text-field/text-field.d.ts +20 -0
  86. package/dist/types/src/components/toast/toast-store.d.ts +47 -0
  87. package/dist/types/src/components/toast/toaster.d.ts +10 -0
  88. package/dist/types/src/components/toggle/toggle.d.ts +17 -0
  89. package/dist/types/src/components/tooltip/tooltip-host.d.ts +6 -0
  90. package/dist/types/src/components/view-controller/index.d.ts +1 -0
  91. package/dist/types/src/components/view-controller/view-controller.d.ts +21 -0
  92. package/dist/types/src/components/wake-slider/wake-slider.d.ts +12 -0
  93. package/dist/types/src/hooks/scroll/minimize-decision.d.ts +2 -0
  94. package/dist/types/src/hooks/use-anchored-disclosure.d.ts +9 -0
  95. package/dist/types/src/hooks/use-anchored-placement.d.ts +7 -0
  96. package/dist/types/src/hooks/use-dismiss.d.ts +9 -0
  97. package/dist/types/src/hooks/use-floating-dismiss.d.ts +3 -0
  98. package/dist/types/src/hooks/use-media-query.d.ts +21 -0
  99. package/dist/types/src/hooks/use-minimize-on-scroll.d.ts +6 -0
  100. package/dist/types/src/hooks/use-visual-viewport.d.ts +4 -0
  101. package/dist/types/src/hooks/viewport/types.d.ts +19 -0
  102. package/dist/types/src/hooks/viewport/viewport-metrics.d.ts +3 -0
  103. package/dist/types/src/icons/icons.d.ts +612 -0
  104. package/dist/types/src/index.d.ts +71 -0
  105. package/dist/types/src/lib/anchored-placement.d.ts +39 -0
  106. package/dist/types/src/lib/class-names.d.ts +2 -0
  107. package/dist/types/src/lib/clipboard.d.ts +6 -0
  108. package/dist/types/src/lib/date.d.ts +50 -0
  109. package/dist/types/src/lib/floating-layers.d.ts +8 -0
  110. package/dist/types/src/lib/haptics.d.ts +8 -0
  111. package/dist/types/src/lib/language.d.ts +4 -0
  112. package/dist/types/src/lib/range-value.d.ts +4 -0
  113. package/dist/types/src/lib/screen-edges.d.ts +12 -0
  114. package/dist/types/src/lib/shapes.d.ts +17 -0
  115. package/dist/types/src/motion/transitions.d.ts +97 -0
  116. package/dist/types/src/tokens.d.ts +1 -0
  117. package/package.json +248 -40
  118. package/src/appearance/platform.tsx +10 -47
  119. package/src/appearance/theme.tsx +42 -142
  120. package/src/components/accordion/accordion.tsx +48 -0
  121. package/src/components/ambient/ambient.tsx +2 -10
  122. package/src/components/aspect-ratio/aspect-ratio.tsx +22 -0
  123. package/src/components/breadcrumb/breadcrumb.tsx +53 -0
  124. package/src/components/button/button-styles.ts +13 -31
  125. package/src/components/button/button.tsx +24 -15
  126. package/src/components/button/icon-button.tsx +14 -56
  127. package/src/components/button/use-pending-indicator.ts +2 -7
  128. package/src/components/chip/chip.tsx +8 -13
  129. package/src/components/code-block/code-block.tsx +41 -0
  130. package/src/components/combo-box/combo-box.tsx +13 -0
  131. package/src/components/command/command.tsx +119 -0
  132. package/src/components/compact-date-picker/calendar-month.ts +13 -57
  133. package/src/components/compact-date-picker/compact-date-picker.tsx +72 -195
  134. package/src/components/compact-time-picker/compact-time-picker.tsx +74 -195
  135. package/src/components/compact-time-picker/time-value.ts +4 -16
  136. package/src/components/content-unavailable-view/content-unavailable-view.tsx +37 -0
  137. package/src/components/content-view/content-view.tsx +13 -56
  138. package/src/components/context-menu/conceal-menu-source.ts +1 -4
  139. package/src/components/context-menu/context-menu-host.tsx +132 -198
  140. package/src/components/context-menu/context-menu-store.ts +5 -14
  141. package/src/components/context-menu/menu-navigation.ts +29 -0
  142. package/src/components/context-menu/menu-position.ts +6 -27
  143. package/src/components/context-menu/menu-reveal.ts +14 -52
  144. package/src/components/context-menu/use-context-menu.ts +6 -30
  145. package/src/components/conversation/conversation.tsx +26 -72
  146. package/src/components/date-picker/date-picker.tsx +8 -37
  147. package/src/components/date-picker/date-value.ts +5 -30
  148. package/src/components/dialog/dialog-host.tsx +37 -76
  149. package/src/components/dialog/dialog-store.ts +16 -7
  150. package/src/components/dialog/dialog.tsx +23 -80
  151. package/src/components/disclosure-group/disclosure-group.tsx +79 -0
  152. package/src/components/divider/divider.tsx +31 -0
  153. package/src/components/inline-disclosure/inline-disclosure.tsx +49 -0
  154. package/src/components/keyboard-shortcut/keyboard-shortcut.tsx +17 -0
  155. package/src/components/labeled-content/labeled-content.tsx +24 -18
  156. package/src/components/locale-switcher/locale-switcher.tsx +20 -70
  157. package/src/components/menu/menu.tsx +68 -0
  158. package/src/components/one-time-code/one-time-code.tsx +168 -0
  159. package/src/components/picker/picker-trigger.ts +10 -0
  160. package/src/components/picker/picker.tsx +165 -283
  161. package/src/components/popover/anchored-surface.tsx +223 -0
  162. package/src/components/popover/popover-fit.ts +69 -0
  163. package/src/components/popover/popover.tsx +209 -63
  164. package/src/components/profile-image/profile-image.tsx +6 -28
  165. package/src/components/progress-view/progress-view.tsx +70 -0
  166. package/src/components/progress-view/use-liquid-progress.ts +43 -0
  167. package/src/components/radio-group/radio-group.tsx +63 -0
  168. package/src/components/search-field/expanding-search-field.tsx +183 -0
  169. package/src/components/search-field/search-field.tsx +25 -7
  170. package/src/components/search-list/search-list.tsx +58 -75
  171. package/src/components/section/section.tsx +18 -17
  172. package/src/components/secure-field/secure-field.tsx +5 -7
  173. package/src/components/segmented-control/segmented-control.tsx +20 -29
  174. package/src/components/sheet/modal-environment.ts +16 -54
  175. package/src/components/sheet/sheet-portal.tsx +10 -42
  176. package/src/components/sheet/sheet.tsx +17 -25
  177. package/src/components/sheet/use-sheet-focus.ts +15 -51
  178. package/src/components/sidebar/sidebar.tsx +44 -38
  179. package/src/components/skeleton/skeleton.tsx +19 -0
  180. package/src/components/slider/slider.tsx +76 -0
  181. package/src/components/slosh-slider/liquid-step.ts +42 -0
  182. package/src/components/slosh-slider/slosh-slider.tsx +251 -0
  183. package/src/components/stat-tile/stat-tile.tsx +9 -30
  184. package/src/components/status-indicator/status-indicator.tsx +12 -19
  185. package/src/components/stepper/rolling-digit.tsx +77 -0
  186. package/src/components/stepper/stepper.tsx +101 -0
  187. package/src/components/swatch-picker/swatch-picker.tsx +19 -15
  188. package/src/components/tab-bar/tab-bar.tsx +59 -59
  189. package/src/components/tab-view/tab-view.tsx +52 -57
  190. package/src/components/table/table.tsx +14 -62
  191. package/src/components/text-editor/text-editor.tsx +2 -12
  192. package/src/components/text-field/text-field.tsx +53 -44
  193. package/src/components/toast/toast-store.ts +9 -30
  194. package/src/components/toast/toaster.tsx +90 -104
  195. package/src/components/toggle/toggle.tsx +165 -44
  196. package/src/components/tooltip/tooltip-host.tsx +70 -67
  197. package/src/components/view-controller/view-controller.tsx +4 -21
  198. package/src/components/wake-slider/wake-slider.tsx +237 -0
  199. package/src/hooks/scroll/minimize-decision.ts +1 -5
  200. package/src/hooks/use-anchored-disclosure.ts +23 -0
  201. package/src/hooks/use-anchored-placement.ts +7 -14
  202. package/src/hooks/use-dismiss.ts +5 -23
  203. package/src/hooks/use-floating-dismiss.ts +28 -0
  204. package/src/hooks/use-media-query.ts +12 -31
  205. package/src/hooks/use-minimize-on-scroll.ts +10 -34
  206. package/src/hooks/use-visual-viewport.ts +5 -14
  207. package/src/hooks/viewport/viewport-metrics.ts +4 -16
  208. package/src/icons/icons.tsx +229 -183
  209. package/src/index.ts +27 -1
  210. package/src/lib/anchored-placement.ts +12 -18
  211. package/src/lib/class-names.ts +1 -2
  212. package/src/lib/clipboard.ts +14 -0
  213. package/src/lib/date.ts +4 -15
  214. package/src/lib/floating-layers.ts +18 -8
  215. package/src/lib/haptics.ts +1 -3
  216. package/src/lib/language.ts +2 -7
  217. package/src/lib/range-value.ts +32 -0
  218. package/src/lib/screen-edges.ts +2 -6
  219. package/src/lib/shapes.ts +5 -20
  220. package/src/motion/transitions.ts +18 -12
  221. package/src/styles/code-block.css +33 -0
  222. package/src/styles/motion-controls.css +189 -0
  223. package/src/styles/styles.css +3 -0
  224. package/src/components/ambient/ambient.docs.tsx +0 -68
  225. package/src/components/ambient/examples/ambient-images.tsx +0 -30
  226. package/src/components/ambient/examples/ambient-now-playing.tsx +0 -55
  227. package/src/components/ambient/examples/ambient-showcase.tsx +0 -33
  228. package/src/components/ambient/examples/ambient-usage.tsx +0 -19
  229. package/src/components/button/button.docs.tsx +0 -116
  230. package/src/components/button/examples/button-disabled.tsx +0 -19
  231. package/src/components/button/examples/button-icon.tsx +0 -39
  232. package/src/components/button/examples/button-link.tsx +0 -12
  233. package/src/components/button/examples/button-pending.tsx +0 -27
  234. package/src/components/button/examples/button-showcase.tsx +0 -115
  235. package/src/components/button/examples/button-sizes.tsx +0 -12
  236. package/src/components/button/examples/button-usage.tsx +0 -12
  237. package/src/components/button/examples/button-variants.tsx +0 -15
  238. package/src/components/button/examples/button-with-icon.tsx +0 -32
  239. package/src/components/button/examples/icon-button-player.tsx +0 -38
  240. package/src/components/button/examples/icon-button-showcase.tsx +0 -83
  241. package/src/components/button/examples/icon-button-usage.tsx +0 -11
  242. package/src/components/button/examples/icon-button-variants.tsx +0 -39
  243. package/src/components/button/icon-button.docs.tsx +0 -68
  244. package/src/components/chip/chip.docs.tsx +0 -37
  245. package/src/components/chip/examples/chip-in-rows.tsx +0 -19
  246. package/src/components/chip/examples/chip-showcase.tsx +0 -51
  247. package/src/components/chip/examples/chip-tones.tsx +0 -13
  248. package/src/components/chip/examples/chip-usage.tsx +0 -5
  249. package/src/components/compact-date-picker/compact-date-picker.docs.tsx +0 -81
  250. package/src/components/compact-date-picker/examples/compact-date-picker-showcase.tsx +0 -35
  251. package/src/components/compact-date-picker/examples/compact-date-picker-usage.tsx +0 -22
  252. package/src/components/compact-time-picker/compact-time-picker.docs.tsx +0 -80
  253. package/src/components/compact-time-picker/examples/compact-time-picker-showcase.tsx +0 -31
  254. package/src/components/compact-time-picker/examples/compact-time-picker-usage.tsx +0 -21
  255. package/src/components/content-view/content-view.docs.tsx +0 -61
  256. package/src/components/content-view/examples/content-view-header-action.tsx +0 -33
  257. package/src/components/content-view/examples/content-view-showcase.tsx +0 -65
  258. package/src/components/content-view/examples/content-view-stats.tsx +0 -35
  259. package/src/components/content-view/examples/content-view-usage.tsx +0 -14
  260. package/src/components/context-menu/context-menu.docs.tsx +0 -92
  261. package/src/components/context-menu/examples/context-menu-checked.tsx +0 -37
  262. package/src/components/context-menu/examples/context-menu-list.tsx +0 -85
  263. package/src/components/context-menu/examples/context-menu-showcase.tsx +0 -56
  264. package/src/components/context-menu/examples/context-menu-toolbar.tsx +0 -63
  265. package/src/components/context-menu/examples/context-menu-usage.tsx +0 -24
  266. package/src/components/conversation/conversation.docs.tsx +0 -88
  267. package/src/components/conversation/examples/conversation-composer.tsx +0 -36
  268. package/src/components/conversation/examples/conversation-days.tsx +0 -48
  269. package/src/components/conversation/examples/conversation-showcase.tsx +0 -71
  270. package/src/components/conversation/examples/conversation-usage.tsx +0 -28
  271. package/src/components/date-picker/date-picker.docs.tsx +0 -88
  272. package/src/components/date-picker/examples/date-picker-locales.tsx +0 -41
  273. package/src/components/date-picker/examples/date-picker-past-only.tsx +0 -29
  274. package/src/components/date-picker/examples/date-picker-showcase.tsx +0 -49
  275. package/src/components/date-picker/examples/date-picker-usage.tsx +0 -22
  276. package/src/components/dialog/dialog.docs.tsx +0 -114
  277. package/src/components/dialog/examples/dialog-confirm.tsx +0 -24
  278. package/src/components/dialog/examples/dialog-form.tsx +0 -46
  279. package/src/components/dialog/examples/dialog-inline.tsx +0 -48
  280. package/src/components/dialog/examples/dialog-showcase.tsx +0 -53
  281. package/src/components/dialog/examples/dialog-usage.tsx +0 -31
  282. package/src/components/labeled-content/examples/labeled-content-descriptions.tsx +0 -37
  283. package/src/components/labeled-content/examples/labeled-content-showcase.tsx +0 -54
  284. package/src/components/labeled-content/examples/labeled-content-usage.tsx +0 -22
  285. package/src/components/labeled-content/examples/labeled-content-values.tsx +0 -26
  286. package/src/components/labeled-content/examples/labeled-content-wide.tsx +0 -46
  287. package/src/components/labeled-content/labeled-content.docs.tsx +0 -69
  288. package/src/components/locale-switcher/examples/locale-switcher-native-names.tsx +0 -30
  289. package/src/components/locale-switcher/examples/locale-switcher-showcase.tsx +0 -46
  290. package/src/components/locale-switcher/examples/locale-switcher-translated-page.tsx +0 -35
  291. package/src/components/locale-switcher/examples/locale-switcher-usage.tsx +0 -20
  292. package/src/components/locale-switcher/locale-switcher.docs.tsx +0 -91
  293. package/src/components/picker/examples/picker-details.tsx +0 -44
  294. package/src/components/picker/examples/picker-searchable.tsx +0 -48
  295. package/src/components/picker/examples/picker-showcase.tsx +0 -66
  296. package/src/components/picker/examples/picker-usage.tsx +0 -20
  297. package/src/components/picker/picker.docs.tsx +0 -68
  298. package/src/components/popover/examples/popover-help.tsx +0 -57
  299. package/src/components/popover/examples/popover-menu.tsx +0 -51
  300. package/src/components/popover/examples/popover-showcase.tsx +0 -61
  301. package/src/components/popover/examples/popover-usage.tsx +0 -31
  302. package/src/components/popover/popover.docs.tsx +0 -84
  303. package/src/components/profile-image/examples/profile-image-fallbacks.tsx +0 -29
  304. package/src/components/profile-image/examples/profile-image-group.tsx +0 -34
  305. package/src/components/profile-image/examples/profile-image-showcase.tsx +0 -30
  306. package/src/components/profile-image/examples/profile-image-usage.tsx +0 -14
  307. package/src/components/profile-image/profile-image.docs.tsx +0 -81
  308. package/src/components/search-field/examples/search-field-filter.tsx +0 -53
  309. package/src/components/search-field/examples/search-field-showcase.tsx +0 -56
  310. package/src/components/search-field/examples/search-field-toolbar.tsx +0 -27
  311. package/src/components/search-field/examples/search-field-usage.tsx +0 -18
  312. package/src/components/search-field/search-field.docs.tsx +0 -58
  313. package/src/components/search-list/examples/search-list-dropdown.tsx +0 -53
  314. package/src/components/search-list/examples/search-list-groups.tsx +0 -64
  315. package/src/components/search-list/examples/search-list-showcase.tsx +0 -67
  316. package/src/components/search-list/examples/search-list-usage.tsx +0 -27
  317. package/src/components/search-list/search-list.docs.tsx +0 -87
  318. package/src/components/section/examples/section-actions.tsx +0 -35
  319. package/src/components/section/examples/section-groups.tsx +0 -41
  320. package/src/components/section/examples/section-showcase.tsx +0 -63
  321. package/src/components/section/examples/section-usage.tsx +0 -19
  322. package/src/components/section/section.docs.tsx +0 -51
  323. package/src/components/secure-field/examples/secure-field-new-password.tsx +0 -56
  324. package/src/components/secure-field/examples/secure-field-reveal.tsx +0 -20
  325. package/src/components/secure-field/examples/secure-field-showcase.tsx +0 -62
  326. package/src/components/secure-field/examples/secure-field-usage.tsx +0 -19
  327. package/src/components/secure-field/secure-field.docs.tsx +0 -72
  328. package/src/components/segmented-control/examples/segmented-control-overflow.tsx +0 -28
  329. package/src/components/segmented-control/examples/segmented-control-showcase.tsx +0 -59
  330. package/src/components/segmented-control/examples/segmented-control-usage.tsx +0 -20
  331. package/src/components/segmented-control/examples/segmented-control-views.tsx +0 -32
  332. package/src/components/segmented-control/segmented-control.docs.tsx +0 -61
  333. package/src/components/sheet/examples/sheet-choices.tsx +0 -58
  334. package/src/components/sheet/examples/sheet-share.tsx +0 -51
  335. package/src/components/sheet/examples/sheet-showcase.tsx +0 -74
  336. package/src/components/sheet/examples/sheet-usage.tsx +0 -32
  337. package/src/components/sheet/sheet.docs.tsx +0 -75
  338. package/src/components/sidebar/examples/sidebar-groups.tsx +0 -133
  339. package/src/components/sidebar/examples/sidebar-showcase.tsx +0 -123
  340. package/src/components/sidebar/examples/sidebar-unread.tsx +0 -66
  341. package/src/components/sidebar/examples/sidebar-usage.tsx +0 -52
  342. package/src/components/sidebar/sidebar.docs.tsx +0 -135
  343. package/src/components/stat-tile/examples/stat-tile-filters.tsx +0 -32
  344. package/src/components/stat-tile/examples/stat-tile-grid.tsx +0 -21
  345. package/src/components/stat-tile/examples/stat-tile-showcase.tsx +0 -52
  346. package/src/components/stat-tile/examples/stat-tile-usage.tsx +0 -13
  347. package/src/components/stat-tile/stat-tile.docs.tsx +0 -60
  348. package/src/components/status-indicator/examples/status-indicator-live.tsx +0 -34
  349. package/src/components/status-indicator/examples/status-indicator-showcase.tsx +0 -39
  350. package/src/components/status-indicator/examples/status-indicator-states.tsx +0 -17
  351. package/src/components/status-indicator/examples/status-indicator-usage.tsx +0 -9
  352. package/src/components/status-indicator/status-indicator.docs.tsx +0 -43
  353. package/src/components/swatch-picker/examples/swatch-picker-accents.tsx +0 -42
  354. package/src/components/swatch-picker/examples/swatch-picker-labels.tsx +0 -45
  355. package/src/components/swatch-picker/examples/swatch-picker-showcase.tsx +0 -70
  356. package/src/components/swatch-picker/examples/swatch-picker-usage.tsx +0 -39
  357. package/src/components/swatch-picker/swatch-picker.docs.tsx +0 -60
  358. package/src/components/tab-bar/examples/tab-bar-five-tabs.tsx +0 -66
  359. package/src/components/tab-bar/examples/tab-bar-minimize.tsx +0 -71
  360. package/src/components/tab-bar/examples/tab-bar-showcase.tsx +0 -82
  361. package/src/components/tab-bar/examples/tab-bar-usage.tsx +0 -54
  362. package/src/components/tab-bar/tab-bar.docs.tsx +0 -136
  363. package/src/components/tab-view/examples/tab-view-keyboard.tsx +0 -39
  364. package/src/components/tab-view/examples/tab-view-settings.tsx +0 -56
  365. package/src/components/tab-view/examples/tab-view-showcase.tsx +0 -53
  366. package/src/components/tab-view/examples/tab-view-usage.tsx +0 -23
  367. package/src/components/tab-view/tab-view.docs.tsx +0 -77
  368. package/src/components/table/examples/table-empty.tsx +0 -53
  369. package/src/components/table/examples/table-invoices.tsx +0 -102
  370. package/src/components/table/examples/table-selection.tsx +0 -150
  371. package/src/components/table/examples/table-showcase.tsx +0 -115
  372. package/src/components/table/examples/table-usage.tsx +0 -67
  373. package/src/components/table/examples/table-wide.tsx +0 -75
  374. package/src/components/table/table.docs.tsx +0 -131
  375. package/src/components/text-editor/examples/text-editor-comment.tsx +0 -48
  376. package/src/components/text-editor/examples/text-editor-count.tsx +0 -38
  377. package/src/components/text-editor/examples/text-editor-showcase.tsx +0 -58
  378. package/src/components/text-editor/examples/text-editor-usage.tsx +0 -25
  379. package/src/components/text-editor/text-editor.docs.tsx +0 -61
  380. package/src/components/text-field/examples/text-field-icons.tsx +0 -72
  381. package/src/components/text-field/examples/text-field-showcase.tsx +0 -50
  382. package/src/components/text-field/examples/text-field-usage.tsx +0 -18
  383. package/src/components/text-field/examples/text-field-validation.tsx +0 -27
  384. package/src/components/text-field/text-field.docs.tsx +0 -118
  385. package/src/components/toast/examples/toast-action.tsx +0 -32
  386. package/src/components/toast/examples/toast-promise.tsx +0 -45
  387. package/src/components/toast/examples/toast-showcase.tsx +0 -49
  388. package/src/components/toast/examples/toast-usage.tsx +0 -13
  389. package/src/components/toast/toast.docs.tsx +0 -79
  390. package/src/components/toggle/examples/toggle-checkboxes.tsx +0 -43
  391. package/src/components/toggle/examples/toggle-settings.tsx +0 -31
  392. package/src/components/toggle/examples/toggle-showcase.tsx +0 -59
  393. package/src/components/toggle/examples/toggle-usage.tsx +0 -13
  394. package/src/components/toggle/toggle.docs.tsx +0 -69
  395. package/src/components/tooltip/examples/tooltip-icon-buttons.tsx +0 -27
  396. package/src/components/tooltip/examples/tooltip-shortcuts.tsx +0 -38
  397. package/src/components/tooltip/examples/tooltip-showcase.tsx +0 -44
  398. package/src/components/tooltip/examples/tooltip-usage.tsx +0 -13
  399. package/src/components/tooltip/tooltip.docs.tsx +0 -56
  400. package/src/components/view-controller/examples/view-controller-action.tsx +0 -27
  401. package/src/components/view-controller/examples/view-controller-settings.tsx +0 -31
  402. package/src/components/view-controller/examples/view-controller-showcase.tsx +0 -45
  403. package/src/components/view-controller/examples/view-controller-usage.tsx +0 -19
  404. package/src/components/view-controller/view-controller.docs.tsx +0 -71
  405. package/src/docs/index.ts +0 -3
  406. package/src/docs/registry.ts +0 -113
  407. package/src/docs/snippet.ts +0 -17
  408. package/src/docs/types.ts +0 -180
@@ -0,0 +1,251 @@
1
+ // Adapted from Bencho. See THIRD_PARTY_NOTICES.md for the MIT notice.
2
+ import { type CSSProperties, useEffect, useRef } from "react"
3
+ import { useMediaQuery } from "../../hooks/use-media-query"
4
+ import { cn } from "../../lib/class-names"
5
+ import { clampRange as clamp } from "../../lib/range-value"
6
+ import { stepLiquid } from "./liquid-step"
7
+
8
+ export interface SloshSliderProps {
9
+ label: string
10
+ value?: number
11
+ defaultValue?: number
12
+ onChange?: (value: number) => void
13
+ /** 0 is rigid; 100 is loose liquid. @default 15 */
14
+ viscosity?: number
15
+ /** How far the handle coasts after release, 0–100. @default 55 */
16
+ momentum?: number
17
+ /** Lean of the liquid's leading edge, 0–100. @default 45 */
18
+ tilt?: number
19
+ /** Track corner, from square to a pill, 0–20. @default 20 */
20
+ corner?: number
21
+ disabled?: boolean
22
+ className?: string
23
+ formatValue?: (value: number) => string
24
+ }
25
+
26
+ /* A slider whose value has mass.
27
+
28
+ The handle is rigid — it is under your finger and anything under a
29
+ finger that lags it is broken. The FILL is a second spring behind it,
30
+ softer and barely damped, so a fast drag throws it past the handle,
31
+ into the end stop, and rocks it back before it settles.
32
+
33
+ The tilt is what sells it as liquid. A bar that lags is a laggy bar;
34
+ a bar whose leading edge leans has a meniscus. Same lag, different object.
35
+
36
+ The loop writes geometry directly and parks as soon as it rests.
37
+ React receives only changed integer values for the application's state. */
38
+ export function SloshSlider({
39
+ label,
40
+ value,
41
+ defaultValue = 62,
42
+ onChange,
43
+ viscosity = 15,
44
+ momentum = 55,
45
+ tilt = 45,
46
+ corner = 20,
47
+ disabled = false,
48
+ className,
49
+ formatValue,
50
+ }: SloshSliderProps) {
51
+ const reduced = useMediaQuery("(prefers-reduced-motion: reduce)")
52
+ const track = useRef<HTMLDivElement>(null)
53
+ const fillEl = useRef<HTMLDivElement>(null)
54
+ const knobEl = useRef<HTMLDivElement>(null)
55
+ const initial = clamp(value ?? defaultValue, 0, 100)
56
+ const state = useRef({
57
+ value: initial,
58
+ handleVelocity: 0,
59
+ fill: initial,
60
+ velocity: 0,
61
+ held: false,
62
+ raf: 0,
63
+ previous: 0,
64
+ last: { value: initial, time: 0 },
65
+ notified: Math.round(initial),
66
+ })
67
+ const settings = useRef({ viscosity, momentum, tilt, reduced, onChange, formatValue })
68
+ settings.current = { viscosity, momentum, tilt, reduced, onChange, formatValue }
69
+ const run = useRef<() => void>(() => {})
70
+
71
+ useEffect(() => {
72
+ const s = state.current
73
+ const paint = () => {
74
+ if (!track.current || !fillEl.current || !knobEl.current) return
75
+ fillEl.current.style.width = `${s.fill.toFixed(2)}%`
76
+ knobEl.current.style.insetInlineStart = `${s.value.toFixed(2)}%`
77
+ /* Proportional to how fast the fill is actually moving: upright
78
+ at rest, so it cannot be decoration when nothing travels. */
79
+ const lean = settings.current.reduced
80
+ ? 0
81
+ : clamp((clamp(settings.current.tilt, 0, 100) / 100) * s.velocity * 3, -20, 20)
82
+ fillEl.current.style.setProperty("--slosh-lean", `${lean.toFixed(2)}px`)
83
+ const next = Math.round(s.value)
84
+ track.current.setAttribute("aria-valuenow", String(next))
85
+ const spoken = settings.current.formatValue?.(next)
86
+ if (spoken) track.current.setAttribute("aria-valuetext", spoken)
87
+ else track.current.removeAttribute("aria-valuetext")
88
+ if (s.notified !== next) {
89
+ s.notified = next
90
+ settings.current.onChange?.(next)
91
+ }
92
+ }
93
+ const tick = (time: number) => {
94
+ const dt = s.previous ? clamp((time - s.previous) / 16.67, 0, 2.5) : 1
95
+ s.previous = time
96
+ const knobs = settings.current
97
+ /* Friction is per frame, raised to dt: a dropped frame must
98
+ not double the deceleration. The release is a throw, not a stop. */
99
+ if (!s.held && s.handleVelocity) {
100
+ s.value += s.handleVelocity * dt
101
+ s.handleVelocity *= (0.86 + (clamp(knobs.momentum, 0, 100) / 100) * 0.115) ** dt
102
+ if (s.value <= 0 || s.value >= 100) {
103
+ s.value = clamp(s.value, 0, 100)
104
+ s.handleVelocity = 0
105
+ }
106
+ if (Math.abs(s.handleVelocity) < 0.01) s.handleVelocity = 0
107
+ }
108
+ const next = stepLiquid(s, s.value, knobs.reduced ? 0 : knobs.viscosity, dt)
109
+ s.fill = next.fill
110
+ s.velocity = next.velocity
111
+ paint()
112
+ if (!s.handleVelocity && !s.velocity && Math.abs(s.fill - s.value) < 0.02) {
113
+ s.raf = 0
114
+ s.previous = 0
115
+ return
116
+ }
117
+ s.raf = requestAnimationFrame(tick)
118
+ }
119
+ run.current = () => {
120
+ // The handle paints on the input event; it never waits for the fill.
121
+ paint()
122
+ if (!s.raf) s.raf = requestAnimationFrame(tick)
123
+ }
124
+ paint()
125
+ return () => {
126
+ cancelAnimationFrame(s.raf)
127
+ s.raf = 0
128
+ s.previous = 0
129
+ }
130
+ }, [])
131
+
132
+ // biome-ignore lint/correctness/useExhaustiveDependencies: Motion settings can wake a parked loop without changing its value.
133
+ useEffect(() => {
134
+ const s = state.current
135
+ if (value !== undefined && Math.round(clamp(value, 0, 100)) !== s.notified) {
136
+ s.value = clamp(value, 0, 100)
137
+ s.notified = Math.round(s.value)
138
+ s.handleVelocity = 0
139
+ }
140
+ if (reduced || disabled) {
141
+ s.handleVelocity = 0
142
+ s.held = false
143
+ }
144
+ run.current()
145
+ }, [value, reduced, disabled, viscosity, tilt, formatValue])
146
+
147
+ const readAt = (clientX: number) => {
148
+ const t = track.current
149
+ if (!t) return 0
150
+ const box = t.getBoundingClientRect()
151
+ const fraction = box.width ? (clientX - box.left) / box.width : 0
152
+ return clamp(
153
+ (getComputedStyle(t).direction === "rtl" ? 1 - fraction : fraction) * 100,
154
+ 0,
155
+ 100
156
+ )
157
+ }
158
+ const release = (cancelled = false) => {
159
+ const s = state.current
160
+ if (!s.held) return
161
+ s.held = false
162
+ /* Leaves along its measured velocity, capped so a full-track flick
163
+ does not simply pin it. A cancelled gesture never throws. */
164
+ s.handleVelocity = cancelled || reduced ? 0 : clamp(s.handleVelocity, -6, 6)
165
+ if (performance.now() - s.last.time > 100) s.handleVelocity = 0
166
+ run.current()
167
+ }
168
+ return (
169
+ <div
170
+ className={cn("passui-slosh-slider not-typeset", disabled && "opacity-40", className)}
171
+ style={{ "--slosh-radius": `${clamp(corner, 0, 20)}px` } as CSSProperties}
172
+ >
173
+ {/* Nothing but the track: the liquid is the value's motion, not a
174
+ second numeric readout that lags and overshoots beside it. */}
175
+ <div
176
+ ref={track}
177
+ className="passui-slosh-track"
178
+ role="slider"
179
+ tabIndex={disabled ? -1 : 0}
180
+ aria-label={label}
181
+ aria-disabled={disabled || undefined}
182
+ aria-valuemin={0}
183
+ aria-valuemax={100}
184
+ aria-valuenow={Math.round(initial)}
185
+ aria-valuetext={formatValue?.(Math.round(initial))}
186
+ onPointerDown={(event) => {
187
+ if (disabled || event.button !== 0) return
188
+ event.currentTarget.focus()
189
+ event.currentTarget.setPointerCapture(event.pointerId)
190
+ const s = state.current
191
+ s.held = true
192
+ s.handleVelocity = 0
193
+ s.value = readAt(event.clientX)
194
+ s.last = { value: s.value, time: performance.now() }
195
+ run.current()
196
+ }}
197
+ onPointerMove={(event) => {
198
+ const s = state.current
199
+ if (!s.held || disabled) return
200
+ const next = readAt(event.clientX),
201
+ now = performance.now()
202
+ /* Per frame, not per ms: the loop's release velocity must
203
+ use the same unit as the spring. */
204
+ s.handleVelocity =
205
+ ((next - s.last.value) / Math.max(1, now - s.last.time)) * 16.67
206
+ s.last = { value: next, time: now }
207
+ s.value = next
208
+ run.current()
209
+ }}
210
+ onPointerUp={() => release()}
211
+ onPointerCancel={() => release(true)}
212
+ onLostPointerCapture={() => release(true)}
213
+ onKeyDown={(event) => {
214
+ if (disabled) return
215
+ const s = state.current,
216
+ step = event.shiftKey ? 10 : 2
217
+ const rtl = getComputedStyle(event.currentTarget).direction === "rtl"
218
+ const next =
219
+ event.key === "ArrowUp" || event.key === (rtl ? "ArrowLeft" : "ArrowRight")
220
+ ? s.value + step
221
+ : event.key === "ArrowDown" ||
222
+ event.key === (rtl ? "ArrowRight" : "ArrowLeft")
223
+ ? s.value - step
224
+ : event.key === "Home"
225
+ ? 0
226
+ : event.key === "End"
227
+ ? 100
228
+ : null
229
+ if (next === null) return
230
+ event.preventDefault()
231
+ s.handleVelocity = 0
232
+ s.value = clamp(next, 0, 100)
233
+ run.current()
234
+ }}
235
+ >
236
+ <div
237
+ aria-hidden="true"
238
+ ref={fillEl}
239
+ className="passui-slosh-fill"
240
+ style={{ width: `${initial}%` }}
241
+ />
242
+ <div
243
+ aria-hidden="true"
244
+ ref={knobEl}
245
+ className="passui-slosh-knob"
246
+ style={{ insetInlineStart: `${initial}%` }}
247
+ />
248
+ </div>
249
+ </div>
250
+ )
251
+ }
@@ -3,7 +3,7 @@ import { cn } from "../../lib/class-names"
3
3
 
4
4
  export type StatTileTone = "critical"
5
5
 
6
- type StatTileProps = {
6
+ export interface StatTileProps {
7
7
  label: string
8
8
  value: number
9
9
  /** A quiet line under the number, like "3 signed in now". */
@@ -16,41 +16,20 @@ type StatTileProps = {
16
16
  }
17
17
 
18
18
  /** One number with its label, optionally a toggle. */
19
- export function StatTile({
20
- label,
21
- value,
22
- caption,
23
- tone,
24
- onClick,
25
- active = false,
26
- }: StatTileProps) {
19
+ export function StatTile({ label, value, caption, tone, onClick, active = false }: StatTileProps) {
27
20
  const body = (
28
21
  <>
29
- <span className="text-xs text-muted-foreground">
30
- {label}
31
- </span>
32
- <span
33
- className={cn(
34
- "text-lg font-semibold tabular-nums tracking-tight",
35
- tone === "critical" &&
36
- value > 0 &&
37
- "text-destructive"
38
- )}
39
- >
22
+ <span className="text-label-secondary">{label}</span>
23
+ <span className={cn("tabular-nums", tone === "critical" && value > 0 && "text-danger")}>
40
24
  {value.toLocaleString("en-US")}
41
25
  </span>
42
- {caption && (
43
- <span className="text-xs text-muted-foreground">
44
- {caption}
45
- </span>
46
- )}
26
+ {caption && <span className="text-label-secondary">{caption}</span>}
47
27
  </>
48
28
  )
49
29
  const className =
50
- "flex min-w-0 flex-col gap-1 rounded-2xl border border-border/35 bg-card p-4 text-left shadow-xs"
30
+ "flex min-w-0 flex-col gap-2 rounded-2xl border border-separator/35 bg-elevated p-4 text-left shadow-xs"
51
31
 
52
- if (!onClick)
53
- return <div className={className}>{body}</div>
32
+ if (!onClick) return <div className={className}>{body}</div>
54
33
  return (
55
34
  <button
56
35
  type="button"
@@ -58,8 +37,8 @@ export function StatTile({
58
37
  onClick={onClick}
59
38
  className={cn(
60
39
  className,
61
- "ring-1 ring-transparent transition-colors hover:bg-muted/60",
62
- active && "bg-muted/70 ring-foreground/15"
40
+ "ring-1 ring-transparent transition-colors hover:bg-fill/60",
41
+ active && "bg-fill/70 ring-label/15"
63
42
  )}
64
43
  >
65
44
  {body}
@@ -1,3 +1,4 @@
1
+ import type { HTMLAttributes, ReactNode } from "react"
1
2
  import { cn } from "../../lib/class-names"
2
3
 
3
4
  const dots = {
@@ -6,29 +7,21 @@ const dots = {
6
7
  offline: "bg-label-tertiary",
7
8
  } as const
8
9
 
9
- export function StatusIndicator({
10
- state,
11
- children,
12
- className,
13
- ...props
14
- }: React.HTMLAttributes<HTMLSpanElement> & {
15
- state: keyof typeof dots
16
- children: React.ReactNode
17
- }) {
10
+ export type StatusIndicatorState = keyof typeof dots
11
+
12
+ export interface StatusIndicatorProps extends HTMLAttributes<HTMLSpanElement> {
13
+ /** Visual treatment of the status dot. */
14
+ state: StatusIndicatorState
15
+ children: ReactNode
16
+ }
17
+
18
+ export function StatusIndicator({ state, children, className, ...props }: StatusIndicatorProps) {
18
19
  return (
19
20
  <span
20
- className={cn(
21
- "flex items-center gap-1.5 text-footnote text-label-tertiary",
22
- className
23
- )}
21
+ className={cn("flex items-center gap-1.5 text-footnote text-label-tertiary", className)}
24
22
  {...props}
25
23
  >
26
- <span
27
- className={cn(
28
- "size-[7px] rounded-full",
29
- dots[state]
30
- )}
31
- />
24
+ <span aria-hidden="true" className={cn("size-[7px] rounded-full", dots[state])} />
32
25
  {children}
33
26
  </span>
34
27
  )
@@ -0,0 +1,77 @@
1
+ import { useEffect, useRef } from "react"
2
+ import { useMediaQuery } from "../../hooks/use-media-query"
3
+
4
+ /** Counts at a place retain carries: the tens column of 1284 targets 128. */
5
+ export function digitAt(count: number) {
6
+ return ((Math.floor(count) % 10) + 10) % 10
7
+ }
8
+
9
+ export function advanceDigit(position: number, velocity: number, target: number, frames: number) {
10
+ const nextVelocity = (velocity + (target - position) * 0.16 * frames) * 0.7 ** frames
11
+ return { position: position + nextVelocity * frames, velocity: nextVelocity }
12
+ }
13
+
14
+ /** Three recycled cells keep the strip continuous through either side of zero. */
15
+ export function RollingDigit({ count, place }: { count: number; place: number }) {
16
+ const strip = useRef<HTMLSpanElement>(null)
17
+ const state = useRef({ position: count, velocity: 0 })
18
+ const reduced = useMediaQuery("(prefers-reduced-motion: reduce)")
19
+ useEffect(() => {
20
+ let frame = 0
21
+ let previous = 0
22
+ let due = 0
23
+ const paint = (position: number, velocity: number) => {
24
+ const node = strip.current
25
+ if (!node) return
26
+ const base = Math.floor(position)
27
+ for (let index = 0; index < node.children.length; index++) {
28
+ node.children[index]!.textContent = String(digitAt(base + index - 1))
29
+ }
30
+ node.style.transform = `translateY(${(-(position - base + 1) * 100) / 3}%)`
31
+ node.style.filter = `blur(${Math.min(2, Math.abs(velocity) * 1.4)}px)`
32
+ }
33
+ if (reduced) {
34
+ state.current = { position: count, velocity: 0 }
35
+ paint(count, 0)
36
+ return
37
+ }
38
+ const tick = (now: number) => {
39
+ if (!due) due = now + place * 28
40
+ const frames = previous ? Math.min((now - previous) / (1000 / 60), 2) : 1
41
+ previous = now
42
+ if (now >= due) {
43
+ state.current = advanceDigit(
44
+ state.current.position,
45
+ state.current.velocity,
46
+ count,
47
+ frames
48
+ )
49
+ if (
50
+ Math.abs(count - state.current.position) < 0.002 &&
51
+ Math.abs(state.current.velocity) < 0.002
52
+ ) {
53
+ state.current = { position: count, velocity: 0 }
54
+ paint(count, 0)
55
+ return
56
+ }
57
+ paint(state.current.position, state.current.velocity)
58
+ }
59
+ frame = requestAnimationFrame(tick)
60
+ }
61
+ frame = requestAnimationFrame(tick)
62
+ return () => cancelAnimationFrame(frame)
63
+ }, [count, place, reduced])
64
+ return (
65
+ <span className="relative inline-block h-[1.5em] w-[1ch] overflow-hidden align-middle">
66
+ <span
67
+ ref={strip}
68
+ className="absolute inset-x-0 top-0 flex flex-col leading-[1.5em]"
69
+ style={{ transform: "translateY(-33.333333%)" }}
70
+ >
71
+ <span>{digitAt(count - 1)}</span>
72
+ <span>{digitAt(count)}</span>
73
+ <span>{digitAt(count + 1)}</span>
74
+ </span>
75
+ </span>
76
+ )
77
+ }
@@ -0,0 +1,101 @@
1
+ import { useId } from "react"
2
+ import { Button } from "../button/button"
3
+ import { cn } from "../../lib/class-names"
4
+ import { clampRange, stepRange } from "../../lib/range-value"
5
+ import { RollingDigit } from "./rolling-digit"
6
+
7
+ export interface StepperProps {
8
+ value: number
9
+ onChange: (value: number) => void
10
+ label: string
11
+ /** Localized accessible names for each action. */
12
+ labels: { decrement: string; increment: string }
13
+ min?: number
14
+ max?: number
15
+ step?: number
16
+ disabled?: boolean
17
+ className?: string
18
+ /** Formats the displayed value. */
19
+ formatValue?: (value: number) => string
20
+ }
21
+
22
+ /** Discrete increments with disabled boundary actions and a spoken value. */
23
+ export function Stepper({
24
+ value,
25
+ onChange,
26
+ label,
27
+ labels,
28
+ min = 0,
29
+ max = 100,
30
+ step = 1,
31
+ disabled = false,
32
+ className,
33
+ formatValue,
34
+ }: StepperProps) {
35
+ const id = useId()
36
+ const upper = Math.max(min, max)
37
+ const current = clampRange(value, min, upper)
38
+ const decrement = stepRange(current, -1, min, upper, step > 0 ? step : 1)
39
+ const increment = stepRange(current, 1, min, upper, step > 0 ? step : 1)
40
+ const displayed = formatValue?.(current) ?? String(current)
41
+ const digits = displayed.replace(/[^0-9]/g, "")
42
+ let digitIndex = 0
43
+
44
+ return (
45
+ <div className={cn("flex min-w-0 items-center justify-between gap-3", className)}>
46
+ <span id={id} className="min-w-0 text-subheadline text-label">
47
+ {label}
48
+ </span>
49
+ <div className="flex shrink-0 items-center gap-3">
50
+ <output
51
+ aria-live="polite"
52
+ aria-labelledby={id}
53
+ className="text-subheadline tabular-nums text-label"
54
+ >
55
+ <span aria-hidden="true" className="inline-flex items-center">
56
+ {Array.from(displayed).map((character, index) => {
57
+ if (!/[0-9]/.test(character))
58
+ return <span key={`separator-${index}`}>{character}</span>
59
+ const prefix = digits.slice(0, ++digitIndex)
60
+ const place = digits.length - digitIndex
61
+ return (
62
+ <RollingDigit
63
+ key={`place-${place}`}
64
+ count={Number(prefix)}
65
+ place={place}
66
+ />
67
+ )
68
+ })}
69
+ </span>
70
+ <span className="sr-only">{displayed}</span>
71
+ </output>
72
+ <div className="flex items-center divide-x divide-separator overflow-hidden rounded-lg bg-fill">
73
+ <Button
74
+ type="button"
75
+ variant="ghost"
76
+ size="icon"
77
+ aria-label={labels.decrement}
78
+ aria-describedby={id}
79
+ disabled={disabled || decrement === current}
80
+ onClick={() => onChange(decrement)}
81
+ className="size-8 rounded-none text-title3 text-accent-text [@media(pointer:coarse)]:size-11"
82
+ >
83
+ −
84
+ </Button>
85
+ <Button
86
+ type="button"
87
+ variant="ghost"
88
+ size="icon"
89
+ aria-label={labels.increment}
90
+ aria-describedby={id}
91
+ disabled={disabled || increment === current}
92
+ onClick={() => onChange(increment)}
93
+ className="size-8 rounded-none text-title3 text-accent-text [@media(pointer:coarse)]:size-11"
94
+ >
95
+ +
96
+ </Button>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ )
101
+ }
@@ -5,24 +5,30 @@ import { cn } from "../../lib/class-names"
5
5
  import { haptic } from "../../lib/haptics"
6
6
  import { spring } from "../../motion/transitions"
7
7
 
8
+ export interface SwatchPickerOption<T extends string> {
9
+ value: T
10
+ label: string
11
+ /** Swatch background color. */
12
+ color: string
13
+ /** Color of the selected checkmark. */
14
+ ink: string
15
+ }
16
+
17
+ export interface SwatchPickerProps<T extends string> {
18
+ value: T
19
+ options: ReadonlyArray<SwatchPickerOption<T>>
20
+ onChange: (value: T) => void
21
+ /** Accessible name for the group. */
22
+ label: string
23
+ }
24
+
8
25
  /** Colour swatches with a check on the chosen one. */
9
26
  export function SwatchPicker<T extends string>({
10
27
  value,
11
28
  options,
12
29
  onChange,
13
30
  label,
14
- }: {
15
- value: T
16
- /** `ink` colours the check drawn on the swatch. */
17
- options: Array<{
18
- value: T
19
- label: string
20
- color: string
21
- ink: string
22
- }>
23
- onChange: (value: T) => void
24
- label: string
25
- }) {
31
+ }: SwatchPickerProps<T>) {
26
32
  const name = useId()
27
33
  return (
28
34
  <fieldset className="flex flex-wrap gap-3">
@@ -81,9 +87,7 @@ export function SwatchPicker<T extends string>({
81
87
  <span
82
88
  className={cn(
83
89
  "text-caption2",
84
- selected
85
- ? "font-semibold text-label"
86
- : "text-label-tertiary"
90
+ selected ? "font-semibold text-label" : "text-label-tertiary"
87
91
  )}
88
92
  >
89
93
  {option.label}