@passui/react 0.1.17 → 0.1.19

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 (366) hide show
  1. package/README.md +102 -1
  2. package/dist/types/src/appearance/index.d.ts +2 -0
  3. package/dist/types/src/appearance/platform.d.ts +9 -0
  4. package/dist/types/src/appearance/theme.d.ts +71 -0
  5. package/dist/types/src/components/ambient/ambient.d.ts +12 -0
  6. package/dist/types/src/components/ambient/index.d.ts +1 -0
  7. package/dist/types/src/components/button/button-styles.d.ts +12 -0
  8. package/dist/types/src/components/button/button.d.ts +30 -0
  9. package/dist/types/src/components/button/icon-button.d.ts +10 -0
  10. package/dist/types/src/components/button/pending-spinner.d.ts +5 -0
  11. package/dist/types/src/components/button/use-pending-indicator.d.ts +2 -0
  12. package/dist/types/src/components/chip/chip.d.ts +7 -0
  13. package/dist/types/src/components/compact-date-picker/calendar-month.d.ts +25 -0
  14. package/dist/types/src/components/compact-date-picker/compact-date-picker.d.ts +27 -0
  15. package/dist/types/src/components/compact-time-picker/compact-time-picker.d.ts +26 -0
  16. package/dist/types/src/components/compact-time-picker/time-value.d.ts +18 -0
  17. package/dist/types/src/components/content-view/content-view.d.ts +48 -0
  18. package/dist/types/src/components/content-view/index.d.ts +1 -0
  19. package/dist/types/src/components/context-menu/conceal-menu-source.d.ts +2 -0
  20. package/dist/types/src/components/context-menu/context-menu-host.d.ts +2 -0
  21. package/dist/types/src/components/context-menu/context-menu-store.d.ts +57 -0
  22. package/dist/types/src/components/context-menu/menu-navigation.d.ts +6 -0
  23. package/dist/types/src/components/context-menu/menu-position.d.ts +21 -0
  24. package/dist/types/src/components/context-menu/menu-reveal.d.ts +22 -0
  25. package/dist/types/src/components/context-menu/use-context-menu.d.ts +14 -0
  26. package/dist/types/src/components/conversation/conversation.d.ts +43 -0
  27. package/dist/types/src/components/conversation/index.d.ts +1 -0
  28. package/dist/types/src/components/date-picker/date-picker.d.ts +16 -0
  29. package/dist/types/src/components/date-picker/date-value.d.ts +2 -0
  30. package/dist/types/src/components/dialog/dialog-host.d.ts +6 -0
  31. package/dist/types/src/components/dialog/dialog-store.d.ts +21 -0
  32. package/dist/types/src/components/dialog/dialog.d.ts +30 -0
  33. package/dist/types/src/components/dialog/index.d.ts +1 -0
  34. package/dist/types/src/components/disclosure-group/disclosure-group.d.ts +13 -0
  35. package/dist/types/src/components/divider/divider.d.ts +9 -0
  36. package/dist/types/src/components/inline-disclosure/inline-disclosure.d.ts +15 -0
  37. package/dist/types/src/components/labeled-content/labeled-content.d.ts +19 -0
  38. package/dist/types/src/components/locale-switcher/index.d.ts +1 -0
  39. package/dist/types/src/components/locale-switcher/locale-switcher.d.ts +10 -0
  40. package/dist/types/src/components/menu/menu.d.ts +16 -0
  41. package/dist/types/src/components/picker/picker-trigger.d.ts +2 -0
  42. package/dist/types/src/components/picker/picker.d.ts +37 -0
  43. package/dist/types/src/components/popover/popover-fit.d.ts +21 -0
  44. package/dist/types/src/components/popover/popover.d.ts +14 -0
  45. package/dist/types/src/components/profile-image/profile-image.d.ts +4 -0
  46. package/dist/types/src/components/progress-view/progress-view.d.ts +13 -0
  47. package/dist/types/src/components/search-field/search-field.d.ts +2 -0
  48. package/dist/types/src/components/search-list/search-list.d.ts +19 -0
  49. package/dist/types/src/components/section/section.d.ts +15 -0
  50. package/dist/types/src/components/secure-field/secure-field.d.ts +4 -0
  51. package/dist/types/src/components/segmented-control/segmented-control.d.ts +20 -0
  52. package/dist/types/src/components/sheet/modal-environment.d.ts +2 -0
  53. package/dist/types/src/components/sheet/sheet-portal.d.ts +5 -0
  54. package/dist/types/src/components/sheet/sheet.d.ts +21 -0
  55. package/dist/types/src/components/sheet/use-sheet-focus.d.ts +3 -0
  56. package/dist/types/src/components/sidebar/sidebar.d.ts +18 -0
  57. package/dist/types/src/components/slider/slider.d.ts +14 -0
  58. package/dist/types/src/components/stat-tile/index.d.ts +1 -0
  59. package/dist/types/src/components/stat-tile/stat-tile.d.ts +15 -0
  60. package/dist/types/src/components/status-indicator/status-indicator.d.ts +14 -0
  61. package/dist/types/src/components/stepper/stepper.d.ts +19 -0
  62. package/dist/types/src/components/swatch-picker/swatch-picker.d.ts +17 -0
  63. package/dist/types/src/components/tab-bar/tab-bar.d.ts +40 -0
  64. package/dist/types/src/components/tab-view/tab-view.d.ts +24 -0
  65. package/dist/types/src/components/table/table.d.ts +10 -0
  66. package/dist/types/src/components/text-editor/text-editor.d.ts +2 -0
  67. package/dist/types/src/components/text-field/text-field.d.ts +18 -0
  68. package/dist/types/src/components/toast/toast-store.d.ts +47 -0
  69. package/dist/types/src/components/toast/toaster.d.ts +10 -0
  70. package/dist/types/src/components/toggle/toggle.d.ts +17 -0
  71. package/dist/types/src/components/tooltip/tooltip-host.d.ts +6 -0
  72. package/dist/types/src/components/view-controller/index.d.ts +1 -0
  73. package/dist/types/src/components/view-controller/view-controller.d.ts +21 -0
  74. package/dist/types/src/hooks/scroll/minimize-decision.d.ts +2 -0
  75. package/dist/types/src/hooks/use-anchored-placement.d.ts +7 -0
  76. package/dist/types/src/hooks/use-dismiss.d.ts +9 -0
  77. package/dist/types/src/hooks/use-floating-dismiss.d.ts +3 -0
  78. package/dist/types/src/hooks/use-media-query.d.ts +21 -0
  79. package/dist/types/src/hooks/use-minimize-on-scroll.d.ts +6 -0
  80. package/dist/types/src/hooks/use-visual-viewport.d.ts +4 -0
  81. package/dist/types/src/hooks/viewport/types.d.ts +19 -0
  82. package/dist/types/src/hooks/viewport/viewport-metrics.d.ts +3 -0
  83. package/dist/types/src/icons/icons.d.ts +612 -0
  84. package/dist/types/src/index.d.ts +58 -0
  85. package/dist/types/src/lib/anchored-placement.d.ts +39 -0
  86. package/dist/types/src/lib/class-names.d.ts +2 -0
  87. package/dist/types/src/lib/clipboard.d.ts +6 -0
  88. package/dist/types/src/lib/date.d.ts +50 -0
  89. package/dist/types/src/lib/floating-layers.d.ts +8 -0
  90. package/dist/types/src/lib/haptics.d.ts +8 -0
  91. package/dist/types/src/lib/language.d.ts +4 -0
  92. package/dist/types/src/lib/range-value.d.ts +4 -0
  93. package/dist/types/src/lib/screen-edges.d.ts +12 -0
  94. package/dist/types/src/lib/shapes.d.ts +17 -0
  95. package/dist/types/src/motion/transitions.d.ts +97 -0
  96. package/dist/types/src/tokens.d.ts +1 -0
  97. package/package.json +192 -40
  98. package/src/appearance/platform.tsx +10 -47
  99. package/src/appearance/theme.tsx +42 -142
  100. package/src/components/ambient/ambient.tsx +2 -10
  101. package/src/components/button/button-styles.ts +13 -31
  102. package/src/components/button/button.tsx +19 -14
  103. package/src/components/button/icon-button.tsx +14 -56
  104. package/src/components/button/use-pending-indicator.ts +2 -7
  105. package/src/components/chip/chip.tsx +8 -13
  106. package/src/components/compact-date-picker/calendar-month.ts +13 -57
  107. package/src/components/compact-date-picker/compact-date-picker.tsx +44 -123
  108. package/src/components/compact-time-picker/compact-time-picker.tsx +46 -130
  109. package/src/components/compact-time-picker/time-value.ts +4 -16
  110. package/src/components/content-view/content-view.tsx +13 -56
  111. package/src/components/context-menu/conceal-menu-source.ts +1 -4
  112. package/src/components/context-menu/context-menu-host.tsx +125 -195
  113. package/src/components/context-menu/context-menu-store.ts +3 -11
  114. package/src/components/context-menu/menu-navigation.ts +29 -0
  115. package/src/components/context-menu/menu-position.ts +6 -27
  116. package/src/components/context-menu/menu-reveal.ts +13 -54
  117. package/src/components/context-menu/use-context-menu.ts +6 -30
  118. package/src/components/conversation/conversation.tsx +26 -72
  119. package/src/components/date-picker/date-picker.tsx +8 -37
  120. package/src/components/date-picker/date-value.ts +5 -30
  121. package/src/components/dialog/dialog-host.tsx +31 -76
  122. package/src/components/dialog/dialog-store.ts +1 -3
  123. package/src/components/dialog/dialog.tsx +23 -80
  124. package/src/components/disclosure-group/disclosure-group.tsx +70 -0
  125. package/src/components/divider/divider.tsx +31 -0
  126. package/src/components/inline-disclosure/inline-disclosure.tsx +49 -0
  127. package/src/components/labeled-content/labeled-content.tsx +24 -18
  128. package/src/components/locale-switcher/locale-switcher.tsx +20 -70
  129. package/src/components/menu/menu.tsx +68 -0
  130. package/src/components/picker/picker-trigger.ts +10 -0
  131. package/src/components/picker/picker.tsx +72 -203
  132. package/src/components/popover/popover-fit.ts +69 -0
  133. package/src/components/popover/popover.tsx +94 -77
  134. package/src/components/profile-image/profile-image.tsx +6 -28
  135. package/src/components/progress-view/progress-view.tsx +65 -0
  136. package/src/components/search-field/search-field.tsx +27 -25
  137. package/src/components/search-list/search-list.tsx +43 -69
  138. package/src/components/section/section.tsx +18 -17
  139. package/src/components/secure-field/secure-field.tsx +5 -7
  140. package/src/components/segmented-control/segmented-control.tsx +20 -29
  141. package/src/components/sheet/modal-environment.ts +16 -54
  142. package/src/components/sheet/sheet-portal.tsx +10 -42
  143. package/src/components/sheet/sheet.tsx +17 -25
  144. package/src/components/sheet/use-sheet-focus.ts +15 -51
  145. package/src/components/sidebar/sidebar.tsx +27 -30
  146. package/src/components/slider/slider.tsx +76 -0
  147. package/src/components/stat-tile/stat-tile.tsx +9 -30
  148. package/src/components/status-indicator/status-indicator.tsx +12 -19
  149. package/src/components/stepper/stepper.tsx +80 -0
  150. package/src/components/swatch-picker/swatch-picker.tsx +19 -15
  151. package/src/components/tab-bar/tab-bar.tsx +59 -59
  152. package/src/components/tab-view/tab-view.tsx +52 -57
  153. package/src/components/table/table.tsx +14 -62
  154. package/src/components/text-editor/text-editor.tsx +2 -12
  155. package/src/components/text-field/text-field.tsx +11 -40
  156. package/src/components/toast/toast-store.ts +9 -30
  157. package/src/components/toast/toaster.tsx +90 -104
  158. package/src/components/toggle/toggle.tsx +28 -24
  159. package/src/components/tooltip/tooltip-host.tsx +70 -67
  160. package/src/components/view-controller/view-controller.tsx +4 -21
  161. package/src/hooks/scroll/minimize-decision.ts +1 -5
  162. package/src/hooks/use-anchored-placement.ts +4 -14
  163. package/src/hooks/use-dismiss.ts +5 -23
  164. package/src/hooks/use-floating-dismiss.ts +28 -0
  165. package/src/hooks/use-media-query.ts +12 -31
  166. package/src/hooks/use-minimize-on-scroll.ts +10 -34
  167. package/src/hooks/use-visual-viewport.ts +5 -14
  168. package/src/hooks/viewport/viewport-metrics.ts +4 -16
  169. package/src/icons/icons.tsx +167 -121
  170. package/src/index.ts +9 -1
  171. package/src/lib/anchored-placement.ts +5 -15
  172. package/src/lib/class-names.ts +1 -2
  173. package/src/lib/clipboard.ts +14 -0
  174. package/src/lib/date.ts +4 -15
  175. package/src/lib/floating-layers.ts +18 -8
  176. package/src/lib/haptics.ts +1 -3
  177. package/src/lib/language.ts +2 -7
  178. package/src/lib/range-value.ts +32 -0
  179. package/src/lib/screen-edges.ts +2 -6
  180. package/src/lib/shapes.ts +5 -20
  181. package/src/motion/transitions.ts +18 -12
  182. package/src/components/ambient/ambient.docs.tsx +0 -68
  183. package/src/components/ambient/examples/ambient-images.tsx +0 -30
  184. package/src/components/ambient/examples/ambient-now-playing.tsx +0 -55
  185. package/src/components/ambient/examples/ambient-showcase.tsx +0 -33
  186. package/src/components/ambient/examples/ambient-usage.tsx +0 -19
  187. package/src/components/button/button.docs.tsx +0 -116
  188. package/src/components/button/examples/button-disabled.tsx +0 -19
  189. package/src/components/button/examples/button-icon.tsx +0 -39
  190. package/src/components/button/examples/button-link.tsx +0 -12
  191. package/src/components/button/examples/button-pending.tsx +0 -27
  192. package/src/components/button/examples/button-showcase.tsx +0 -115
  193. package/src/components/button/examples/button-sizes.tsx +0 -12
  194. package/src/components/button/examples/button-usage.tsx +0 -12
  195. package/src/components/button/examples/button-variants.tsx +0 -15
  196. package/src/components/button/examples/button-with-icon.tsx +0 -32
  197. package/src/components/button/examples/icon-button-player.tsx +0 -38
  198. package/src/components/button/examples/icon-button-showcase.tsx +0 -83
  199. package/src/components/button/examples/icon-button-usage.tsx +0 -11
  200. package/src/components/button/examples/icon-button-variants.tsx +0 -39
  201. package/src/components/button/icon-button.docs.tsx +0 -68
  202. package/src/components/chip/chip.docs.tsx +0 -37
  203. package/src/components/chip/examples/chip-in-rows.tsx +0 -19
  204. package/src/components/chip/examples/chip-showcase.tsx +0 -51
  205. package/src/components/chip/examples/chip-tones.tsx +0 -13
  206. package/src/components/chip/examples/chip-usage.tsx +0 -5
  207. package/src/components/compact-date-picker/compact-date-picker.docs.tsx +0 -81
  208. package/src/components/compact-date-picker/examples/compact-date-picker-showcase.tsx +0 -35
  209. package/src/components/compact-date-picker/examples/compact-date-picker-usage.tsx +0 -22
  210. package/src/components/compact-time-picker/compact-time-picker.docs.tsx +0 -80
  211. package/src/components/compact-time-picker/examples/compact-time-picker-showcase.tsx +0 -31
  212. package/src/components/compact-time-picker/examples/compact-time-picker-usage.tsx +0 -21
  213. package/src/components/content-view/content-view.docs.tsx +0 -61
  214. package/src/components/content-view/examples/content-view-header-action.tsx +0 -33
  215. package/src/components/content-view/examples/content-view-showcase.tsx +0 -65
  216. package/src/components/content-view/examples/content-view-stats.tsx +0 -35
  217. package/src/components/content-view/examples/content-view-usage.tsx +0 -14
  218. package/src/components/context-menu/context-menu.docs.tsx +0 -92
  219. package/src/components/context-menu/examples/context-menu-checked.tsx +0 -37
  220. package/src/components/context-menu/examples/context-menu-list.tsx +0 -85
  221. package/src/components/context-menu/examples/context-menu-showcase.tsx +0 -56
  222. package/src/components/context-menu/examples/context-menu-toolbar.tsx +0 -63
  223. package/src/components/context-menu/examples/context-menu-usage.tsx +0 -24
  224. package/src/components/conversation/conversation.docs.tsx +0 -88
  225. package/src/components/conversation/examples/conversation-composer.tsx +0 -36
  226. package/src/components/conversation/examples/conversation-days.tsx +0 -48
  227. package/src/components/conversation/examples/conversation-showcase.tsx +0 -71
  228. package/src/components/conversation/examples/conversation-usage.tsx +0 -28
  229. package/src/components/date-picker/date-picker.docs.tsx +0 -88
  230. package/src/components/date-picker/examples/date-picker-locales.tsx +0 -41
  231. package/src/components/date-picker/examples/date-picker-past-only.tsx +0 -29
  232. package/src/components/date-picker/examples/date-picker-showcase.tsx +0 -49
  233. package/src/components/date-picker/examples/date-picker-usage.tsx +0 -22
  234. package/src/components/dialog/dialog.docs.tsx +0 -114
  235. package/src/components/dialog/examples/dialog-confirm.tsx +0 -24
  236. package/src/components/dialog/examples/dialog-form.tsx +0 -46
  237. package/src/components/dialog/examples/dialog-inline.tsx +0 -48
  238. package/src/components/dialog/examples/dialog-showcase.tsx +0 -53
  239. package/src/components/dialog/examples/dialog-usage.tsx +0 -31
  240. package/src/components/labeled-content/examples/labeled-content-descriptions.tsx +0 -37
  241. package/src/components/labeled-content/examples/labeled-content-showcase.tsx +0 -54
  242. package/src/components/labeled-content/examples/labeled-content-usage.tsx +0 -22
  243. package/src/components/labeled-content/examples/labeled-content-values.tsx +0 -26
  244. package/src/components/labeled-content/examples/labeled-content-wide.tsx +0 -46
  245. package/src/components/labeled-content/labeled-content.docs.tsx +0 -69
  246. package/src/components/locale-switcher/examples/locale-switcher-native-names.tsx +0 -30
  247. package/src/components/locale-switcher/examples/locale-switcher-showcase.tsx +0 -46
  248. package/src/components/locale-switcher/examples/locale-switcher-translated-page.tsx +0 -35
  249. package/src/components/locale-switcher/examples/locale-switcher-usage.tsx +0 -20
  250. package/src/components/locale-switcher/locale-switcher.docs.tsx +0 -91
  251. package/src/components/picker/examples/picker-details.tsx +0 -44
  252. package/src/components/picker/examples/picker-searchable.tsx +0 -48
  253. package/src/components/picker/examples/picker-showcase.tsx +0 -66
  254. package/src/components/picker/examples/picker-usage.tsx +0 -20
  255. package/src/components/picker/picker.docs.tsx +0 -68
  256. package/src/components/popover/examples/popover-help.tsx +0 -57
  257. package/src/components/popover/examples/popover-menu.tsx +0 -51
  258. package/src/components/popover/examples/popover-showcase.tsx +0 -61
  259. package/src/components/popover/examples/popover-usage.tsx +0 -31
  260. package/src/components/popover/popover.docs.tsx +0 -84
  261. package/src/components/profile-image/examples/profile-image-fallbacks.tsx +0 -29
  262. package/src/components/profile-image/examples/profile-image-group.tsx +0 -34
  263. package/src/components/profile-image/examples/profile-image-showcase.tsx +0 -30
  264. package/src/components/profile-image/examples/profile-image-usage.tsx +0 -14
  265. package/src/components/profile-image/profile-image.docs.tsx +0 -81
  266. package/src/components/search-field/examples/search-field-filter.tsx +0 -53
  267. package/src/components/search-field/examples/search-field-showcase.tsx +0 -56
  268. package/src/components/search-field/examples/search-field-toolbar.tsx +0 -27
  269. package/src/components/search-field/examples/search-field-usage.tsx +0 -18
  270. package/src/components/search-field/search-field.docs.tsx +0 -58
  271. package/src/components/search-list/examples/search-list-dropdown.tsx +0 -53
  272. package/src/components/search-list/examples/search-list-groups.tsx +0 -64
  273. package/src/components/search-list/examples/search-list-showcase.tsx +0 -67
  274. package/src/components/search-list/examples/search-list-usage.tsx +0 -27
  275. package/src/components/search-list/search-list.docs.tsx +0 -87
  276. package/src/components/section/examples/section-actions.tsx +0 -35
  277. package/src/components/section/examples/section-groups.tsx +0 -41
  278. package/src/components/section/examples/section-showcase.tsx +0 -63
  279. package/src/components/section/examples/section-usage.tsx +0 -19
  280. package/src/components/section/section.docs.tsx +0 -51
  281. package/src/components/secure-field/examples/secure-field-new-password.tsx +0 -56
  282. package/src/components/secure-field/examples/secure-field-reveal.tsx +0 -20
  283. package/src/components/secure-field/examples/secure-field-showcase.tsx +0 -62
  284. package/src/components/secure-field/examples/secure-field-usage.tsx +0 -19
  285. package/src/components/secure-field/secure-field.docs.tsx +0 -72
  286. package/src/components/segmented-control/examples/segmented-control-overflow.tsx +0 -28
  287. package/src/components/segmented-control/examples/segmented-control-showcase.tsx +0 -59
  288. package/src/components/segmented-control/examples/segmented-control-usage.tsx +0 -20
  289. package/src/components/segmented-control/examples/segmented-control-views.tsx +0 -32
  290. package/src/components/segmented-control/segmented-control.docs.tsx +0 -61
  291. package/src/components/sheet/examples/sheet-choices.tsx +0 -58
  292. package/src/components/sheet/examples/sheet-share.tsx +0 -51
  293. package/src/components/sheet/examples/sheet-showcase.tsx +0 -74
  294. package/src/components/sheet/examples/sheet-usage.tsx +0 -32
  295. package/src/components/sheet/sheet.docs.tsx +0 -75
  296. package/src/components/sidebar/examples/sidebar-groups.tsx +0 -133
  297. package/src/components/sidebar/examples/sidebar-showcase.tsx +0 -123
  298. package/src/components/sidebar/examples/sidebar-unread.tsx +0 -66
  299. package/src/components/sidebar/examples/sidebar-usage.tsx +0 -52
  300. package/src/components/sidebar/sidebar.docs.tsx +0 -135
  301. package/src/components/stat-tile/examples/stat-tile-filters.tsx +0 -32
  302. package/src/components/stat-tile/examples/stat-tile-grid.tsx +0 -21
  303. package/src/components/stat-tile/examples/stat-tile-showcase.tsx +0 -52
  304. package/src/components/stat-tile/examples/stat-tile-usage.tsx +0 -13
  305. package/src/components/stat-tile/stat-tile.docs.tsx +0 -60
  306. package/src/components/status-indicator/examples/status-indicator-live.tsx +0 -34
  307. package/src/components/status-indicator/examples/status-indicator-showcase.tsx +0 -39
  308. package/src/components/status-indicator/examples/status-indicator-states.tsx +0 -17
  309. package/src/components/status-indicator/examples/status-indicator-usage.tsx +0 -9
  310. package/src/components/status-indicator/status-indicator.docs.tsx +0 -43
  311. package/src/components/swatch-picker/examples/swatch-picker-accents.tsx +0 -42
  312. package/src/components/swatch-picker/examples/swatch-picker-labels.tsx +0 -45
  313. package/src/components/swatch-picker/examples/swatch-picker-showcase.tsx +0 -70
  314. package/src/components/swatch-picker/examples/swatch-picker-usage.tsx +0 -39
  315. package/src/components/swatch-picker/swatch-picker.docs.tsx +0 -60
  316. package/src/components/tab-bar/examples/tab-bar-five-tabs.tsx +0 -66
  317. package/src/components/tab-bar/examples/tab-bar-minimize.tsx +0 -71
  318. package/src/components/tab-bar/examples/tab-bar-showcase.tsx +0 -82
  319. package/src/components/tab-bar/examples/tab-bar-usage.tsx +0 -54
  320. package/src/components/tab-bar/tab-bar.docs.tsx +0 -136
  321. package/src/components/tab-view/examples/tab-view-keyboard.tsx +0 -39
  322. package/src/components/tab-view/examples/tab-view-settings.tsx +0 -56
  323. package/src/components/tab-view/examples/tab-view-showcase.tsx +0 -53
  324. package/src/components/tab-view/examples/tab-view-usage.tsx +0 -23
  325. package/src/components/tab-view/tab-view.docs.tsx +0 -77
  326. package/src/components/table/examples/table-empty.tsx +0 -53
  327. package/src/components/table/examples/table-invoices.tsx +0 -102
  328. package/src/components/table/examples/table-selection.tsx +0 -150
  329. package/src/components/table/examples/table-showcase.tsx +0 -115
  330. package/src/components/table/examples/table-usage.tsx +0 -67
  331. package/src/components/table/examples/table-wide.tsx +0 -75
  332. package/src/components/table/table.docs.tsx +0 -131
  333. package/src/components/text-editor/examples/text-editor-comment.tsx +0 -48
  334. package/src/components/text-editor/examples/text-editor-count.tsx +0 -38
  335. package/src/components/text-editor/examples/text-editor-showcase.tsx +0 -58
  336. package/src/components/text-editor/examples/text-editor-usage.tsx +0 -25
  337. package/src/components/text-editor/text-editor.docs.tsx +0 -61
  338. package/src/components/text-field/examples/text-field-icons.tsx +0 -72
  339. package/src/components/text-field/examples/text-field-showcase.tsx +0 -50
  340. package/src/components/text-field/examples/text-field-usage.tsx +0 -18
  341. package/src/components/text-field/examples/text-field-validation.tsx +0 -27
  342. package/src/components/text-field/text-field.docs.tsx +0 -118
  343. package/src/components/toast/examples/toast-action.tsx +0 -32
  344. package/src/components/toast/examples/toast-promise.tsx +0 -45
  345. package/src/components/toast/examples/toast-showcase.tsx +0 -49
  346. package/src/components/toast/examples/toast-usage.tsx +0 -13
  347. package/src/components/toast/toast.docs.tsx +0 -79
  348. package/src/components/toggle/examples/toggle-checkboxes.tsx +0 -43
  349. package/src/components/toggle/examples/toggle-settings.tsx +0 -31
  350. package/src/components/toggle/examples/toggle-showcase.tsx +0 -59
  351. package/src/components/toggle/examples/toggle-usage.tsx +0 -13
  352. package/src/components/toggle/toggle.docs.tsx +0 -69
  353. package/src/components/tooltip/examples/tooltip-icon-buttons.tsx +0 -27
  354. package/src/components/tooltip/examples/tooltip-shortcuts.tsx +0 -38
  355. package/src/components/tooltip/examples/tooltip-showcase.tsx +0 -44
  356. package/src/components/tooltip/examples/tooltip-usage.tsx +0 -13
  357. package/src/components/tooltip/tooltip.docs.tsx +0 -56
  358. package/src/components/view-controller/examples/view-controller-action.tsx +0 -27
  359. package/src/components/view-controller/examples/view-controller-settings.tsx +0 -31
  360. package/src/components/view-controller/examples/view-controller-showcase.tsx +0 -45
  361. package/src/components/view-controller/examples/view-controller-usage.tsx +0 -19
  362. package/src/components/view-controller/view-controller.docs.tsx +0 -71
  363. package/src/docs/index.ts +0 -3
  364. package/src/docs/registry.ts +0 -113
  365. package/src/docs/snippet.ts +0 -17
  366. package/src/docs/types.ts +0 -180
@@ -0,0 +1,76 @@
1
+ import { type ComponentProps, useId } from "react"
2
+ import { cn } from "../../lib/class-names"
3
+ import { clampRange } from "../../lib/range-value"
4
+
5
+ export interface SliderProps
6
+ extends Omit<
7
+ ComponentProps<"input">,
8
+ "type" | "value" | "defaultValue" | "onChange" | "min" | "max" | "step"
9
+ > {
10
+ value: number
11
+ onChange: (value: number) => void
12
+ label: string
13
+ min?: number
14
+ max?: number
15
+ step?: number
16
+ description?: string
17
+ /** Provides a localized, spoken description of the current value. */
18
+ formatValue?: (value: number) => string
19
+ }
20
+
21
+ /** Native keyboard, touch and pointer behavior with Passui's control treatment. */
22
+ export function Slider({
23
+ value,
24
+ onChange,
25
+ label,
26
+ min = 0,
27
+ max = 100,
28
+ step = 1,
29
+ description,
30
+ formatValue,
31
+ id: suppliedId,
32
+ className,
33
+ disabled,
34
+ ...props
35
+ }: SliderProps) {
36
+ const generatedId = useId()
37
+ const id = suppliedId ?? generatedId
38
+ const upper = Math.max(min, max)
39
+ const current = clampRange(value, min, upper)
40
+
41
+ return (
42
+ <div className={cn("flex min-w-0 flex-col gap-2", disabled && "opacity-45")}>
43
+ <label htmlFor={id} className="text-subheadline font-semibold text-label">
44
+ {label}
45
+ </label>
46
+ <input
47
+ {...props}
48
+ id={id}
49
+ type="range"
50
+ min={min}
51
+ max={upper}
52
+ step={step > 0 ? step : 1}
53
+ value={current}
54
+ disabled={disabled || upper === min}
55
+ aria-valuetext={formatValue?.(current)}
56
+ aria-describedby={description ? `${id}-description` : undefined}
57
+ onChange={(event) => onChange(Number(event.currentTarget.value))}
58
+ className={cn(
59
+ "h-11 w-full min-w-0 cursor-pointer appearance-none bg-transparent accent-accent",
60
+ "focus-visible:rounded-lg focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent-text",
61
+ "[&::-webkit-slider-runnable-track]:h-1.5 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-separator",
62
+ "[&::-webkit-slider-thumb]:-mt-[7px] [&::-webkit-slider-thumb]:size-5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-accent [&::-webkit-slider-thumb]:bg-elevated [&::-webkit-slider-thumb]:shadow-sm",
63
+ "[&::-moz-range-track]:h-1.5 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-separator",
64
+ "[&::-moz-range-progress]:h-1.5 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-accent",
65
+ "[&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-accent [&::-moz-range-thumb]:bg-elevated",
66
+ className
67
+ )}
68
+ />
69
+ {description && (
70
+ <p id={`${id}-description`} className="text-footnote text-label-secondary">
71
+ {description}
72
+ </p>
73
+ )}
74
+ </div>
75
+ )
76
+ }
@@ -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,80 @@
1
+ import { useId } from "react"
2
+ import { cn } from "../../lib/class-names"
3
+ import { clampRange, stepRange } from "../../lib/range-value"
4
+
5
+ export interface StepperProps {
6
+ value: number
7
+ onChange: (value: number) => void
8
+ label: string
9
+ /** Localized accessible names for each action. */
10
+ labels: { decrement: string; increment: string }
11
+ min?: number
12
+ max?: number
13
+ step?: number
14
+ disabled?: boolean
15
+ className?: string
16
+ /** Formats the displayed value. */
17
+ formatValue?: (value: number) => string
18
+ }
19
+
20
+ /** Discrete increments with disabled boundary actions and a spoken value. */
21
+ export function Stepper({
22
+ value,
23
+ onChange,
24
+ label,
25
+ labels,
26
+ min = 0,
27
+ max = 100,
28
+ step = 1,
29
+ disabled = false,
30
+ className,
31
+ formatValue,
32
+ }: StepperProps) {
33
+ const id = useId()
34
+ const upper = Math.max(min, max)
35
+ const current = clampRange(value, min, upper)
36
+ const decrement = stepRange(current, -1, min, upper, step > 0 ? step : 1)
37
+ const increment = stepRange(current, 1, min, upper, step > 0 ? step : 1)
38
+ const buttonStyle = cn(
39
+ "flex size-11 shrink-0 items-center justify-center rounded-xl text-title2 text-accent-text",
40
+ "transition-colors hover:bg-fill focus-visible:outline-2 focus-visible:outline-offset-2",
41
+ "focus-visible:outline-accent-text disabled:cursor-not-allowed disabled:opacity-35"
42
+ )
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 font-semibold text-label">
47
+ {label}
48
+ </span>
49
+ <div className="flex shrink-0 items-center gap-1 rounded-2xl border border-separator bg-elevated p-1">
50
+ <button
51
+ type="button"
52
+ aria-label={labels.decrement}
53
+ aria-describedby={id}
54
+ disabled={disabled || decrement === current}
55
+ onClick={() => onChange(decrement)}
56
+ className={buttonStyle}
57
+ >
58
+ −
59
+ </button>
60
+ <output
61
+ aria-live="polite"
62
+ aria-labelledby={id}
63
+ className="min-w-10 text-center text-subheadline tabular-nums text-label"
64
+ >
65
+ {formatValue?.(current) ?? current}
66
+ </output>
67
+ <button
68
+ type="button"
69
+ aria-label={labels.increment}
70
+ aria-describedby={id}
71
+ disabled={disabled || increment === current}
72
+ onClick={() => onChange(increment)}
73
+ className={buttonStyle}
74
+ >
75
+ +
76
+ </button>
77
+ </div>
78
+ </div>
79
+ )
80
+ }
@@ -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}
@@ -1,5 +1,5 @@
1
- import { motion } from "motion/react"
2
- import { type ReactNode, useId } from "react"
1
+ import { motion, useReducedMotion } from "motion/react"
2
+ import { Fragment, type ReactNode, useId } from "react"
3
3
  import { useMinimizeOnScroll } from "../../hooks/use-minimize-on-scroll"
4
4
  import { SearchIcon } from "../../icons/icons"
5
5
  import { cn } from "../../lib/class-names"
@@ -19,6 +19,22 @@ export interface TabBarLinkProps {
19
19
  children: ReactNode
20
20
  }
21
21
 
22
+ export type TabBarMinimizeBehavior = "platform" | "scroll" | "never"
23
+
24
+ export interface TabBarProps<Tab extends TabBarTab> {
25
+ /** `platform` follows the platform, `scroll` always minimizes, `never` stays expanded. @default "platform" */
26
+ minimizeBehavior?: TabBarMinimizeBehavior
27
+ tabs: readonly Tab[]
28
+ /** Active tab ID, or null for a destination outside the bar. */
29
+ active: Tab["id"] | null
30
+ /** Renders your router's link with the supplied appearance and accessibility props. */
31
+ renderLink: (tab: Tab, props: TabBarLinkProps) => ReactNode
32
+ search?: { label: string; onPress: () => void }
33
+ /** Accessible name for the navigation. */
34
+ label: string
35
+ className?: string
36
+ }
37
+
22
38
  /**
23
39
  * The app's main places a thumb's reach away, drawn as iOS 26 draws them: a
24
40
  * floating glass capsule of tabs, with Search as its own round button at the
@@ -36,25 +52,12 @@ export function TabBar<Tab extends TabBarTab>({
36
52
  label,
37
53
  className,
38
54
  minimizeBehavior = "platform",
39
- }: {
40
- minimizeBehavior?: "platform" | "scroll" | "never"
41
- tabs: readonly Tab[]
42
- /** Null in places the bar has no tab for. */
43
- active: Tab["id"] | null
44
- renderLink: (
45
- tab: Tab,
46
- props: TabBarLinkProps
47
- ) => ReactNode
48
- search?: { label: string; onPress: () => void }
49
- /** Names the navigation for screen readers. */
50
- label: string
51
- className?: string
52
- }) {
55
+ }: TabBarProps<Tab>) {
53
56
  // Scopes the sliding selection to this bar, so two bars on one
54
57
  // screen (a docs page, a split view) never trade their highlight.
55
58
  const selectionId = `${useId()}-tab-selection`
56
- const [scrolledAway, setScrolledAway] =
57
- useMinimizeOnScroll()
59
+ const reducedMotion = useReducedMotion()
60
+ const [scrolledAway, setScrolledAway] = useMinimizeOnScroll()
58
61
  // Platform behavior keeps Android expanded; apps can opt into scroll minimization.
59
62
  const minimized =
60
63
  scrolledAway &&
@@ -70,8 +73,8 @@ export function TabBar<Tab extends TabBarTab>({
70
73
  )}
71
74
  >
72
75
  <motion.div
73
- layout
74
- transition={spring.smooth}
76
+ layout={!reducedMotion}
77
+ transition={reducedMotion ? { duration: 0 } : spring.smooth}
75
78
  // A tap on the shrunken capsule brings every tab back.
76
79
  onClickCapture={(event) => {
77
80
  if (!minimized) return
@@ -87,41 +90,41 @@ export function TabBar<Tab extends TabBarTab>({
87
90
  {tabs.map((tab) => {
88
91
  const current = tab.id === active
89
92
  if (minimized && !current) return null
90
- return renderLink(tab, {
91
- "aria-current": current
92
- ? "page"
93
- : undefined,
94
- // Switching tabs is silent, as on Apple and Android: no haptic.
95
- onClick: () => {},
96
- className: cn(
97
- "relative isolate flex h-11 min-w-0 flex-col items-center justify-center gap-0.5 rounded-full font-semibold text-[10px] tracking-[0.01em] no-underline transition-[color,transform] duration-fast active:scale-[0.94]",
98
- minimized
99
- ? "w-11"
100
- : "flex-1 px-1",
101
- current
102
- ? "text-accent-text"
103
- : "text-label-secondary"
104
- ),
105
- children: (
106
- <>
107
- {current && (
108
- <motion.span
109
- layoutId={selectionId}
110
- className="glass-lens absolute inset-0 -z-10 rounded-full"
111
- transition={
112
- spring.snappy
113
- }
114
- />
115
- )}
116
- {tab.icon}
117
- {!minimized && (
118
- <span className="max-w-full truncate">
119
- {tab.label}
120
- </span>
121
- )}
122
- </>
123
- ),
124
- })
93
+ return (
94
+ <Fragment key={tab.id}>
95
+ {renderLink(tab, {
96
+ "aria-current": current ? "page" : undefined,
97
+ // Switching tabs is silent, as on Apple and Android: no haptic.
98
+ onClick: () => {},
99
+ className: cn(
100
+ "relative isolate flex h-11 min-w-0 flex-col items-center justify-center gap-0.5 rounded-full font-semibold text-[10px] tracking-[0.01em] no-underline transition-[color,transform] duration-fast active:scale-[0.94]",
101
+ minimized ? "w-11" : "flex-1 px-1",
102
+ current ? "text-accent-text" : "text-label-secondary"
103
+ ),
104
+ children: (
105
+ <>
106
+ {current && (
107
+ <motion.span
108
+ layoutId={selectionId}
109
+ className="glass-lens absolute inset-0 -z-10 rounded-full"
110
+ transition={
111
+ reducedMotion ? { duration: 0 } : spring.snappy
112
+ }
113
+ />
114
+ )}
115
+ {tab.icon}
116
+ <span
117
+ className={
118
+ minimized ? "sr-only" : "max-w-full truncate"
119
+ }
120
+ >
121
+ {tab.label}
122
+ </span>
123
+ </>
124
+ ),
125
+ })}
126
+ </Fragment>
127
+ )
125
128
  })}
126
129
  </motion.div>
127
130
  {search && (
@@ -141,8 +144,5 @@ export function TabBar<Tab extends TabBarTab>({
141
144
  }
142
145
 
143
146
  function onAndroid() {
144
- return (
145
- typeof document !== "undefined" &&
146
- document.documentElement.dataset.os === "android"
147
- )
147
+ return typeof document !== "undefined" && document.documentElement.dataset.os === "android"
148
148
  }
@@ -1,11 +1,25 @@
1
- import {
2
- useId,
3
- useRef,
4
- useState,
5
- type ReactNode,
6
- } from "react"
1
+ import { useId, useRef, useState, type ReactNode } from "react"
7
2
  import { cn } from "../../lib/class-names"
8
3
 
4
+ export type TabViewAlign = "start" | "center"
5
+
6
+ export interface TabViewProps<Value extends string> {
7
+ /** Available tabs, in keyboard navigation order. */
8
+ options: readonly { value: Value; label: string; disabled?: boolean }[]
9
+ /** Initial selection when value is not controlled. */
10
+ defaultValue: Value
11
+ /** Controlled selection; omit to keep selection inside TabView. */
12
+ value?: Value
13
+ onValueChange?: (value: Value) => void
14
+ /** Tab alignment: `start` or `center`. @default "center" */
15
+ align?: TabViewAlign
16
+ /** Accessible name for the tab list. */
17
+ label: string
18
+ /** Renders the selected tab's panel. */
19
+ children: (value: Value) => ReactNode
20
+ className?: string
21
+ }
22
+
9
23
  /** Content tabs with native buttons, roving focus and automatic keyboard activation. */
10
24
  export function TabView<Value extends string>({
11
25
  options,
@@ -16,16 +30,7 @@ export function TabView<Value extends string>({
16
30
  label,
17
31
  children,
18
32
  className,
19
- }: {
20
- options: readonly { value: Value; label: string }[]
21
- defaultValue: Value
22
- value?: Value
23
- onValueChange?: (value: Value) => void
24
- align?: "start" | "center"
25
- label: string
26
- children: (value: Value) => ReactNode
27
- className?: string
28
- }) {
33
+ }: TabViewProps<Value>) {
29
34
  const id = useId()
30
35
  const buttons = useRef<(HTMLButtonElement | null)[]>([])
31
36
  const [selected, setSelected] = useState(defaultValue)
@@ -34,28 +39,18 @@ export function TabView<Value extends string>({
34
39
  if (controlledValue === undefined) setSelected(next)
35
40
  onValueChange?.(next)
36
41
  }
37
- const value = options.some(
38
- (option) => option.value === current
39
- )
40
- ? current
41
- : options[0]?.value
42
+ const enabled = options.filter((option) => !option.disabled)
43
+ const value = enabled.some((option) => option.value === current) ? current : enabled[0]?.value
42
44
  if (value === undefined) return null
43
45
 
44
46
  return (
45
- <div
46
- className={cn(
47
- "flex w-full flex-col gap-5",
48
- className
49
- )}
50
- >
47
+ <div className={cn("flex w-full flex-col gap-5", className)}>
51
48
  <div
52
49
  role="tablist"
53
50
  aria-label={label}
54
51
  className={cn(
55
52
  "inline-flex h-8 w-fit max-w-full items-center gap-5 p-[3px]",
56
- align === "start"
57
- ? "self-start"
58
- : "mx-auto justify-center"
53
+ align === "start" ? "self-start" : "mx-auto justify-center"
59
54
  )}
60
55
  >
61
56
  {options.map((option, index) => (
@@ -66,38 +61,39 @@ export function TabView<Value extends string>({
66
61
  id={`${id}-tab-${index}`}
67
62
  aria-controls={`${id}-panel-${index}`}
68
63
  aria-selected={option.value === value}
69
- tabIndex={
70
- option.value === value ? 0 : -1
71
- }
64
+ aria-disabled={option.disabled || undefined}
65
+ disabled={option.disabled}
66
+ tabIndex={option.value === value ? 0 : -1}
72
67
  ref={(element) => {
73
68
  buttons.current[index] = element
74
69
  }}
75
70
  onClick={() => select(option.value)}
76
71
  onKeyDown={(event) => {
77
- const rtl =
78
- getComputedStyle(
79
- event.currentTarget
80
- ).direction === "rtl"
72
+ const rtl = getComputedStyle(event.currentTarget).direction === "rtl"
81
73
  let next: number
82
- if (event.key === "Home") next = 0
83
- else if (event.key === "End")
84
- next = options.length - 1
85
- else if (
86
- event.key === "ArrowRight"
87
- )
88
- next = index + (rtl ? -1 : 1)
89
- else if (
90
- event.key === "ArrowLeft"
91
- )
92
- next = index + (rtl ? 1 : -1)
93
- else return
74
+ let step: number
75
+ if (event.key === "Home") {
76
+ next = -1
77
+ step = 1
78
+ } else if (event.key === "End") {
79
+ next = options.length
80
+ step = -1
81
+ } else if (event.key === "ArrowRight") {
82
+ step = rtl ? -1 : 1
83
+ next = index
84
+ } else if (event.key === "ArrowLeft") {
85
+ step = rtl ? 1 : -1
86
+ next = index
87
+ } else return
94
88
  event.preventDefault()
95
- next =
96
- (next + options.length) %
97
- options.length
98
- const option = options[next]
99
- if (option) select(option.value)
100
- buttons.current[next]?.focus()
89
+ for (let offset = 0; offset < options.length; offset++) {
90
+ next = (next + step + options.length) % options.length
91
+ const option = options[next]
92
+ if (!option || option.disabled) continue
93
+ select(option.value)
94
+ buttons.current[next]?.focus()
95
+ break
96
+ }
101
97
  }}
102
98
  className={cn(
103
99
  "relative inline-flex h-[calc(100%-1px)] shrink-0 items-center justify-center border border-transparent p-0 text-sm font-medium whitespace-nowrap",
@@ -121,8 +117,7 @@ export function TabView<Value extends string>({
121
117
  hidden={option.value !== value}
122
118
  className="w-full outline-offset-4"
123
119
  >
124
- {option.value === value &&
125
- children(option.value)}
120
+ {option.value === value && children(option.value)}
126
121
  </div>
127
122
  ))}
128
123
  </div>