@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
@@ -1,44 +1,50 @@
1
- import {
2
- AnimatePresence,
3
- motion,
4
- useReducedMotion,
5
- } from "motion/react"
6
- import {
7
- type KeyboardEvent,
8
- useCallback,
9
- useEffect,
10
- useId,
11
- useLayoutEffect,
12
- useMemo,
13
- useRef,
14
- useState,
15
- } from "react"
1
+ import { useAnchoredDisclosure } from "../../hooks/use-anchored-disclosure"
2
+ import { type KeyboardEvent, useCallback, useEffect, useId, useMemo, useRef, useState } from "react"
16
3
  import { createPortal } from "react-dom"
17
- import { FLOATING_LAYER } from "../../hooks/use-dismiss"
18
- import {
19
- CheckIcon,
20
- SearchIcon,
21
- SelectorIcon,
22
- } from "../../icons/icons"
4
+ import { CheckIcon, SearchIcon, SelectorIcon } from "../../icons/icons"
23
5
  import { cn } from "../../lib/class-names"
24
- import {
25
- type AnchoredPlacement,
26
- placeInViewport,
27
- } from "../../lib/anchored-placement"
28
- import { registerFloatingLayer } from "../../lib/floating-layers"
29
6
  import { haptic } from "../../lib/haptics"
30
- import { screenEdges } from "../../lib/screen-edges"
31
- import { spring } from "../../motion/transitions"
7
+ import { AnchoredSurface } from "../popover/anchored-surface"
8
+ import { pickerTriggerStyle } from "./picker-trigger"
32
9
 
33
10
  export interface PickerOption<T extends string> {
34
11
  value: T
35
12
  label: string
36
13
  /** A quieter second line or trailing note, such as "Free" or a region. */
14
+ disabled?: boolean
15
+ keywords?: string[]
37
16
  detail?: string
38
17
  /** The option's own language, so it is spoken and shaped right. */
39
18
  lang?: string
40
19
  }
41
20
 
21
+ /** Values and callbacks share the option value type, including literal unions. */
22
+ export interface PickerProps<T extends string> {
23
+ /** The selected option's value. */
24
+ value: T
25
+ /** Available choices. Use a literal union for a fixed set of values. */
26
+ options: ReadonlyArray<PickerOption<T>>
27
+ /** Called with the selected option value. */
28
+ onChange: (value: NoInfer<T>) => void
29
+ /** Accessible name for the trigger. */
30
+ label: string
31
+ /** Shown when the selected value has no matching option. */
32
+ placeholder?: string
33
+ /** Defaults to on for lists of ten or more options. */
34
+ searchable?: boolean
35
+ /** Label for the filter field. @default "Search" */
36
+ searchPlaceholder?: string
37
+ /** Shown when the filter matches nothing. @default "No matches" */
38
+ emptyLabel?: string
39
+ /** Offers a new value when no option has the same label or value. */
40
+ onCreate?: (query: string) => void
41
+ /** Localized creation action; receives the trimmed query. */
42
+ createLabel?: (query: string) => string
43
+ className?: string
44
+ /** Prevents opening or choosing an option. @default false */
45
+ disabled?: boolean
46
+ }
47
+
42
48
  /** Long lists get a filter field, as in the system pickers. */
43
49
  const SEARCH_FROM = 10
44
50
 
@@ -58,41 +64,28 @@ export function Picker<T extends string>({
58
64
  searchPlaceholder = "Search",
59
65
  emptyLabel = "No matches",
60
66
  className,
61
- }: {
62
- value: T
63
- options: ReadonlyArray<PickerOption<T>>
64
- onChange: (value: T) => void
65
- /** Read by assistive technology; the visible label is the field around it. */
66
- label: string
67
- placeholder?: string
68
- /** Defaults to on for lists longer than ten. */
69
- searchable?: boolean
70
- searchPlaceholder?: string
71
- /** Shown when the filter matches nothing. */
72
- emptyLabel?: string
73
- className?: string
74
- }) {
75
- const [open, setOpen] = useState(false)
67
+ onCreate,
68
+ createLabel,
69
+ disabled = false,
70
+ }: PickerProps<T>) {
71
+ const panel = useAnchoredDisclosure(disabled)
72
+ const { open } = panel
76
73
  const trigger = useRef<HTMLButtonElement>(null)
77
74
  const listId = useId()
78
- const selected = options.find(
79
- (option) => option.value === value
80
- )
75
+ const selected = options.find((option) => option.value === value)
81
76
 
82
- const close = useCallback((refocus: boolean) => {
83
- setOpen(false)
84
- if (refocus) trigger.current?.focus()
85
- }, [])
77
+ const close = useCallback(
78
+ (refocus: boolean) => {
79
+ panel.close()
80
+ if (refocus) trigger.current?.focus({ preventScroll: true })
81
+ },
82
+ [panel.close]
83
+ )
86
84
 
87
- const onTriggerKey = (
88
- event: KeyboardEvent<HTMLButtonElement>
89
- ) => {
90
- if (
91
- event.key === "ArrowDown" ||
92
- event.key === "ArrowUp"
93
- ) {
85
+ const onTriggerKey = (event: KeyboardEvent<HTMLButtonElement>) => {
86
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
94
87
  event.preventDefault()
95
- setOpen(true)
88
+ panel.show()
96
89
  }
97
90
  }
98
91
 
@@ -104,90 +97,57 @@ export function Picker<T extends string>({
104
97
  role="combobox"
105
98
  aria-label={label}
106
99
  aria-haspopup="listbox"
107
- aria-expanded={open}
108
- aria-controls={open ? listId : undefined}
109
- onClick={() => setOpen((current) => !current)}
100
+ aria-expanded={open && !disabled}
101
+ aria-controls={open && !disabled ? listId : undefined}
102
+ disabled={disabled}
103
+ onClick={() => panel.toggle()}
110
104
  onKeyDown={onTriggerKey}
111
- className={cn(
112
- "flex w-full min-w-0 items-center gap-2 rounded-lg control-field px-3 py-2 text-start text-subheadline text-label",
113
- className
114
- )}
105
+ className={pickerTriggerStyle(className)}
115
106
  >
116
107
  <span
117
108
  lang={selected?.lang}
118
- className={cn(
119
- "min-w-0 grow truncate",
120
- !selected && "text-label-tertiary"
121
- )}
109
+ className={cn("min-w-0 grow truncate", !selected && "text-label-tertiary")}
122
110
  >
123
111
  {selected?.label ?? placeholder ?? ""}
124
112
  </span>
125
- <SelectorIcon
126
- size={15}
127
- strokeWidth={2}
128
- className="shrink-0 text-label-tertiary"
129
- />
113
+ <SelectorIcon size={15} strokeWidth={2} className="shrink-0 text-label-tertiary" />
130
114
  </button>
131
115
  {typeof document !== "undefined" &&
132
116
  createPortal(
133
- <AnimatePresence>
134
- {open && trigger.current && (
135
- <SelectList
136
- id={listId}
137
- anchor={trigger.current}
138
- options={options}
139
- value={value}
140
- label={label}
141
- searchable={
142
- searchable ??
143
- options.length >
144
- SEARCH_FROM
145
- }
146
- searchPlaceholder={
147
- searchPlaceholder
148
- }
149
- emptyLabel={emptyLabel}
150
- onPick={(next) => {
151
- close(true)
152
- if (next === value) return
153
- haptic("selection")
154
- onChange(next)
155
- }}
156
- onClose={close}
157
- />
158
- )}
159
- </AnimatePresence>,
117
+ panel.mounted && trigger.current ? (
118
+ <SelectList
119
+ open={open}
120
+ onExited={panel.onExited}
121
+ id={listId}
122
+ anchor={trigger.current}
123
+ options={options}
124
+ value={value}
125
+ label={label}
126
+ searchable={
127
+ searchable ?? (Boolean(onCreate) || options.length >= SEARCH_FROM)
128
+ }
129
+ searchPlaceholder={searchPlaceholder}
130
+ emptyLabel={emptyLabel}
131
+ onCreate={onCreate}
132
+ createLabel={createLabel}
133
+ onPick={(next) => {
134
+ close(true)
135
+ if (next === value) return
136
+ haptic("selection")
137
+ onChange(next)
138
+ }}
139
+ onClose={close}
140
+ />
141
+ ) : null,
160
142
  document.body
161
143
  )}
162
144
  </>
163
145
  )
164
146
  }
165
147
 
166
- function place(anchor: HTMLElement): AnchoredPlacement {
167
- const rect = anchor.getBoundingClientRect()
168
- const viewport = window.visualViewport
169
- const frame = {
170
- anchor: {
171
- top: rect.top,
172
- bottom: rect.bottom,
173
- left: rect.left,
174
- },
175
- viewport: {
176
- width: viewport?.width ?? window.innerWidth,
177
- height: viewport?.height ?? window.innerHeight,
178
- },
179
- edges: screenEdges(),
180
- }
181
- const width = Math.min(Math.max(rect.width, 220), 360)
182
- const placed = placeInViewport(frame, width, 240)
183
- // Long lists scroll rather than stretch past 420 px.
184
- return {
185
- ...placed,
186
- maxHeight: Math.min(placed.maxHeight ?? 420, 420),
187
- }
188
- }
189
-
190
148
  function SelectList<T extends string>({
149
+ open,
150
+ onExited,
191
151
  id,
192
152
  anchor,
193
153
  options,
@@ -198,7 +158,11 @@ function SelectList<T extends string>({
198
158
  emptyLabel,
199
159
  onPick,
200
160
  onClose,
161
+ onCreate,
162
+ createLabel,
201
163
  }: {
164
+ open: boolean
165
+ onExited: () => void
202
166
  id: string
203
167
  anchor: HTMLElement
204
168
  options: ReadonlyArray<PickerOption<T>>
@@ -207,16 +171,13 @@ function SelectList<T extends string>({
207
171
  searchable: boolean
208
172
  searchPlaceholder: string
209
173
  emptyLabel: string
174
+ onCreate?: (query: string) => void
175
+ createLabel?: (query: string) => string
210
176
  onPick: (value: T) => void
211
177
  onClose: (refocus: boolean) => void
212
178
  }) {
213
- const root = useRef<HTMLDivElement>(null)
214
- const reducedMotion = useReducedMotion()
215
179
  const list = useRef<HTMLDivElement>(null)
216
180
  const search = useRef<HTMLInputElement>(null)
217
- const [placement, setPlacement] = useState(() =>
218
- place(anchor)
219
- )
220
181
  const [query, setQuery] = useState("")
221
182
  const typed = useRef({ text: "", at: 0 })
222
183
 
@@ -224,93 +185,58 @@ function SelectList<T extends string>({
224
185
  const needle = query.trim().toLocaleLowerCase()
225
186
  if (!needle) return options
226
187
  return options.filter((option) =>
227
- `${option.label} ${option.detail ?? ""} ${option.value}`
188
+ `${option.label} ${option.detail ?? ""} ${option.value} ${(option.keywords ?? []).join(" ")}`
228
189
  .toLocaleLowerCase()
229
190
  .includes(needle)
230
191
  )
231
192
  }, [options, query])
232
193
 
194
+ const enabled = shown.filter((option) => !option.disabled)
195
+ const trimmed = query.trim()
196
+ const canCreate = Boolean(
197
+ onCreate &&
198
+ trimmed &&
199
+ !options.some(
200
+ (option) =>
201
+ option.label.toLocaleLowerCase() === trimmed.toLocaleLowerCase() ||
202
+ option.value.toLocaleLowerCase() === trimmed.toLocaleLowerCase()
203
+ )
204
+ )
205
+ const create = () => {
206
+ if (!canCreate) return
207
+ onClose(true)
208
+ onCreate?.(trimmed)
209
+ }
233
210
  const [active, setActive] = useState(() =>
234
211
  Math.max(
235
212
  0,
236
- options.findIndex(
237
- (option) => option.value === value
238
- )
213
+ options
214
+ .filter((option) => !option.disabled)
215
+ .findIndex((option) => option.value === value)
239
216
  )
240
217
  )
241
- const activeOption =
242
- shown[Math.min(active, shown.length - 1)]
218
+ const last = enabled.length + (canCreate ? 1 : 0) - 1
219
+ const activeOption = enabled[Math.min(active, last)]
220
+ const activeId = activeOption
221
+ ? `${id}-${activeOption.value}`
222
+ : canCreate
223
+ ? `${id}-create`
224
+ : undefined
243
225
 
244
- useLayoutEffect(() => {
245
- if (!root.current) return
246
- const unregister = registerFloatingLayer(
247
- root.current,
248
- anchor
249
- )
226
+ useEffect(() => {
250
227
  if (searchable) search.current?.focus()
251
228
  else list.current?.focus()
252
- return unregister
253
- }, [searchable, anchor])
229
+ }, [searchable])
254
230
 
255
231
  // The chosen option starts in view, then follows the keyboard.
256
232
  useEffect(() => {
257
233
  if (!activeOption) return
258
234
  list.current
259
- ?.querySelector(
260
- `[data-value="${CSS.escape(activeOption.value)}"]`
261
- )
235
+ ?.querySelector(`[data-value="${CSS.escape(activeOption.value)}"]`)
262
236
  ?.scrollIntoView({ block: "nearest" })
263
237
  }, [activeOption])
264
238
 
265
- useEffect(() => {
266
- const onPointer = (event: PointerEvent) => {
267
- const target = event.target as Node
268
- if (
269
- !root.current?.contains(target) &&
270
- !anchor.contains(target)
271
- )
272
- onClose(false)
273
- }
274
- const onScroll = (event: Event) => {
275
- if (!root.current?.contains(event.target as Node))
276
- setPlacement(place(anchor))
277
- }
278
- const onResize = () => setPlacement(place(anchor))
279
- const onBlur = () => onClose(false)
280
- document.addEventListener(
281
- "pointerdown",
282
- onPointer,
283
- true
284
- )
285
- window.addEventListener("scroll", onScroll, true)
286
- window.addEventListener("resize", onResize)
287
- window.visualViewport?.addEventListener(
288
- "resize",
289
- onResize
290
- )
291
- window.addEventListener("blur", onBlur)
292
- return () => {
293
- document.removeEventListener(
294
- "pointerdown",
295
- onPointer,
296
- true
297
- )
298
- window.removeEventListener(
299
- "scroll",
300
- onScroll,
301
- true
302
- )
303
- window.removeEventListener("resize", onResize)
304
- window.visualViewport?.removeEventListener(
305
- "resize",
306
- onResize
307
- )
308
- window.removeEventListener("blur", onBlur)
309
- }
310
- }, [anchor, onClose])
311
-
312
239
  const onKeyDown = (event: KeyboardEvent) => {
313
- const last = shown.length - 1
314
240
  const step = (to: number) => {
315
241
  event.preventDefault()
316
242
  setActive(Math.max(0, Math.min(last, to)))
@@ -319,102 +245,52 @@ function SelectList<T extends string>({
319
245
  if (event.key === "ArrowDown") step(current + 1)
320
246
  else if (event.key === "ArrowUp") step(current - 1)
321
247
  else if (event.key === "Home" && !searchable) step(0)
322
- else if (event.key === "End" && !searchable)
323
- step(last)
248
+ else if (event.key === "End" && !searchable) step(last)
324
249
  else if (event.key === "PageDown") step(current + 8)
325
250
  else if (event.key === "PageUp") step(current - 8)
326
- else if (
327
- event.key === "Enter" ||
328
- (event.key === " " && !searchable)
329
- ) {
251
+ else if (event.key === "Enter" || (event.key === " " && !searchable)) {
330
252
  event.preventDefault()
331
253
  if (activeOption) onPick(activeOption.value)
254
+ else if (canCreate) create()
332
255
  } else if (event.key === "Escape") {
333
256
  event.preventDefault()
334
257
  event.stopPropagation()
335
258
  onClose(true)
336
259
  } else if (event.key === "Tab") {
337
260
  onClose(false)
338
- } else if (
339
- !searchable &&
340
- event.key.length === 1 &&
341
- !event.metaKey &&
342
- !event.ctrlKey
343
- ) {
261
+ } else if (!searchable && event.key.length === 1 && !event.metaKey && !event.ctrlKey) {
344
262
  // Type to jump, as in a native pop-up button.
345
263
  const now = Date.now()
346
- const text =
347
- (now - typed.current.at < 700
348
- ? typed.current.text
349
- : "") + event.key
264
+ const text = (now - typed.current.at < 700 ? typed.current.text : "") + event.key
350
265
  typed.current = { text, at: now }
351
- const match = shown.findIndex((option) =>
352
- option.label
353
- .toLocaleLowerCase()
354
- .startsWith(text.toLocaleLowerCase())
266
+ const match = enabled.findIndex((option) =>
267
+ option.label.toLocaleLowerCase().startsWith(text.toLocaleLowerCase())
355
268
  )
356
269
  if (match >= 0) setActive(match)
357
270
  }
358
271
  }
359
272
 
360
273
  return (
361
- <motion.div
362
- ref={root}
363
- initial={
364
- reducedMotion
365
- ? { opacity: 0 }
366
- : {
367
- opacity: 0,
368
- scale: 0.96,
369
- y: placement.above ? 6 : -6,
370
- }
371
- }
372
- animate={{ opacity: 1, scale: 1, y: 0 }}
373
- exit={
374
- reducedMotion
375
- ? { opacity: 0 }
376
- : {
377
- opacity: 0,
378
- scale: 0.98,
379
- transition: { duration: 0.1 },
380
- }
381
- }
382
- transition={
383
- reducedMotion
384
- ? { duration: 0 }
385
- : spring.smooth
386
- }
387
- style={{
388
- left: placement.left,
389
- width: placement.width,
390
- top: placement.top,
391
- bottom: placement.bottom,
392
- maxHeight: placement.maxHeight,
393
- transformOrigin: placement.above
394
- ? "50% 100%"
395
- : "50% 0%",
396
- }}
397
- className="glass-menu fixed z-[80] flex flex-col overflow-hidden rounded-3xl"
398
- {...{ [FLOATING_LAYER]: "" }}
274
+ <AnchoredSurface
275
+ open={open}
276
+ onExited={onExited}
277
+ anchor={anchor}
278
+ width={Math.min(Math.max(anchor.getBoundingClientRect().width, 220), 360)}
279
+ needed={240}
280
+ onClose={onClose}
399
281
  onKeyDown={onKeyDown}
282
+ contentClassName="overflow-hidden"
400
283
  >
401
284
  {searchable && (
402
285
  <div className="flex shrink-0 items-center gap-2 border-b border-separator/70 px-3 py-2">
403
- <SearchIcon
404
- size={15}
405
- className="shrink-0 text-label-tertiary"
406
- />
286
+ <SearchIcon size={15} className="shrink-0 text-label-tertiary" />
407
287
  <input
408
288
  ref={search}
409
289
  value={query}
410
290
  placeholder={searchPlaceholder}
411
291
  aria-label={searchPlaceholder}
412
292
  aria-controls={id}
413
- aria-activedescendant={
414
- activeOption
415
- ? `${id}-${activeOption.value}`
416
- : undefined
417
- }
293
+ aria-activedescendant={activeId}
418
294
  onChange={(event) => {
419
295
  setQuery(event.target.value)
420
296
  setActive(0)
@@ -429,14 +305,10 @@ function SelectList<T extends string>({
429
305
  role="listbox"
430
306
  aria-label={label}
431
307
  tabIndex={-1}
432
- aria-activedescendant={
433
- activeOption
434
- ? `${id}-${activeOption.value}`
435
- : undefined
436
- }
308
+ aria-activedescendant={activeId}
437
309
  className="no-scrollbar flex min-h-0 flex-col overflow-y-auto overscroll-contain p-1.5 outline-none"
438
310
  >
439
- {shown.map((option, index) => {
311
+ {shown.map((option) => {
440
312
  const chosen = option.value === value
441
313
  const focused = option === activeOption
442
314
  return (
@@ -447,19 +319,17 @@ function SelectList<T extends string>({
447
319
  role="option"
448
320
  tabIndex={-1}
449
321
  aria-selected={chosen}
322
+ aria-disabled={option.disabled || undefined}
450
323
  lang={option.lang}
451
324
  onPointerMove={() =>
452
- setActive(index)
453
- }
454
- onClick={() =>
455
- onPick(option.value)
325
+ !option.disabled && setActive(enabled.indexOf(option))
456
326
  }
327
+ onClick={() => !option.disabled && onPick(option.value)}
457
328
  className={cn(
458
329
  "flex min-h-8 cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-subheadline [@media(pointer:coarse)]:min-h-11",
459
330
  focused ? "bg-fill" : "",
460
- chosen
461
- ? "font-semibold text-label"
462
- : "text-label"
331
+ option.disabled && "opacity-40",
332
+ chosen ? "font-semibold text-label" : "text-label"
463
333
  )}
464
334
  >
465
335
  <span className="flex w-4 shrink-0 justify-center">
@@ -471,9 +341,7 @@ function SelectList<T extends string>({
471
341
  />
472
342
  )}
473
343
  </span>
474
- <span className="min-w-0 grow break-words">
475
- {option.label}
476
- </span>
344
+ <span className="min-w-0 grow break-words">{option.label}</span>
477
345
  {option.detail && (
478
346
  <span className="shrink-0 text-caption font-normal text-label-tertiary">
479
347
  {option.detail}
@@ -482,12 +350,26 @@ function SelectList<T extends string>({
482
350
  </div>
483
351
  )
484
352
  })}
485
- {shown.length === 0 && (
486
- <p className="px-3 py-2 text-footnote text-label-tertiary">
487
- {emptyLabel}
488
- </p>
353
+ {canCreate && (
354
+ <div
355
+ id={`${id}-create`}
356
+ role="option"
357
+ aria-selected={false}
358
+ tabIndex={-1}
359
+ onPointerMove={() => setActive(enabled.length)}
360
+ onClick={create}
361
+ className={cn(
362
+ "flex min-h-9 cursor-default items-center rounded-lg px-2 py-1.5 text-subheadline text-accent-text",
363
+ !activeOption && "bg-fill"
364
+ )}
365
+ >
366
+ {createLabel?.(trimmed) ?? trimmed}
367
+ </div>
368
+ )}
369
+ {shown.length === 0 && !canCreate && (
370
+ <p className="px-3 py-2 text-footnote text-label-tertiary">{emptyLabel}</p>
489
371
  )}
490
372
  </div>
491
- </motion.div>
373
+ </AnchoredSurface>
492
374
  )
493
375
  }