@seekalfred/primitives 0.6.0 → 0.7.3

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 (346) hide show
  1. package/README.md +214 -15
  2. package/dist/activity-heatmap/activity-heatmap.d.ts +92 -0
  3. package/dist/activity-heatmap/activity-heatmap.js +699 -0
  4. package/dist/activity-heatmap/activity-heatmap.js.map +1 -0
  5. package/dist/activity-heatmap/index.d.ts +2 -0
  6. package/dist/activity-heatmap/index.js +2 -0
  7. package/dist/alert/alert.d.ts +53 -4
  8. package/dist/alert/alert.js +100 -11
  9. package/dist/alert/alert.js.map +1 -1
  10. package/dist/alert/index.d.ts +2 -2
  11. package/dist/alert/index.js +2 -2
  12. package/dist/alert-dialog/alert-dialog.d.ts +58 -18
  13. package/dist/alert-dialog/alert-dialog.js +152 -9
  14. package/dist/alert-dialog/alert-dialog.js.map +1 -1
  15. package/dist/alert-dialog/index.d.ts +2 -2
  16. package/dist/alert-dialog/index.js +2 -2
  17. package/dist/animated-counter/animated-counter.d.ts +38 -0
  18. package/dist/animated-counter/animated-counter.js +230 -0
  19. package/dist/animated-counter/animated-counter.js.map +1 -0
  20. package/dist/animated-counter/index.d.ts +2 -0
  21. package/dist/animated-counter/index.js +2 -0
  22. package/dist/announcement-bar/announcement-bar.d.ts +67 -0
  23. package/dist/announcement-bar/announcement-bar.js +364 -0
  24. package/dist/announcement-bar/announcement-bar.js.map +1 -0
  25. package/dist/announcement-bar/index.d.ts +2 -0
  26. package/dist/announcement-bar/index.js +2 -0
  27. package/dist/badge/badge.d.ts +1 -1
  28. package/dist/bar-chart/bar-chart.d.ts +51 -0
  29. package/dist/bar-chart/bar-chart.js +565 -0
  30. package/dist/bar-chart/bar-chart.js.map +1 -0
  31. package/dist/bar-chart/index.d.ts +2 -0
  32. package/dist/bar-chart/index.js +2 -0
  33. package/dist/breadcrumb/breadcrumb.d.ts +2 -2
  34. package/dist/breadcrumb/breadcrumb.js +12 -3
  35. package/dist/breadcrumb/breadcrumb.js.map +1 -1
  36. package/dist/brush-chart/brush-chart.d.ts +64 -0
  37. package/dist/brush-chart/brush-chart.js +1056 -0
  38. package/dist/brush-chart/brush-chart.js.map +1 -0
  39. package/dist/brush-chart/index.d.ts +2 -0
  40. package/dist/brush-chart/index.js +2 -0
  41. package/dist/button/button.d.ts +1 -1
  42. package/dist/button/button.js +31 -21
  43. package/dist/button/button.js.map +1 -1
  44. package/dist/button-group/button-group.js +3 -4
  45. package/dist/button-group/button-group.js.map +1 -1
  46. package/dist/calendar/calendar.d.ts +1 -1
  47. package/dist/card/card.d.ts +22 -1
  48. package/dist/card/card.js +60 -7
  49. package/dist/card/card.js.map +1 -1
  50. package/dist/card-stack/card-stack.d.ts +54 -0
  51. package/dist/card-stack/card-stack.js +492 -0
  52. package/dist/card-stack/card-stack.js.map +1 -0
  53. package/dist/card-stack/index.d.ts +2 -0
  54. package/dist/card-stack/index.js +2 -0
  55. package/dist/carousel/carousel.d.ts +77 -0
  56. package/dist/carousel/carousel.js +415 -0
  57. package/dist/carousel/carousel.js.map +1 -0
  58. package/dist/carousel/index.d.ts +2 -0
  59. package/dist/carousel/index.js +2 -0
  60. package/dist/checkbox/checkbox.js +4 -4
  61. package/dist/checkbox/checkbox.js.map +1 -1
  62. package/dist/chip-group/chip-group.d.ts +37 -0
  63. package/dist/chip-group/chip-group.js +148 -0
  64. package/dist/chip-group/chip-group.js.map +1 -0
  65. package/dist/chip-group/index.d.ts +2 -0
  66. package/dist/chip-group/index.js +2 -0
  67. package/dist/copy-button/copy-button.d.ts +18 -2
  68. package/dist/copy-button/copy-button.js +29 -8
  69. package/dist/copy-button/copy-button.js.map +1 -1
  70. package/dist/countdown/countdown.d.ts +45 -0
  71. package/dist/countdown/countdown.js +298 -0
  72. package/dist/countdown/countdown.js.map +1 -0
  73. package/dist/countdown/index.d.ts +2 -0
  74. package/dist/countdown/index.js +2 -0
  75. package/dist/date-picker/picker-parts.js +1 -1
  76. package/dist/date-picker/picker-parts.js.map +1 -1
  77. package/dist/dialog/dialog.js +1 -1
  78. package/dist/dialog/dialog.js.map +1 -1
  79. package/dist/donut-chart/donut-chart.d.ts +86 -0
  80. package/dist/donut-chart/donut-chart.js +593 -0
  81. package/dist/donut-chart/donut-chart.js.map +1 -0
  82. package/dist/donut-chart/index.d.ts +2 -0
  83. package/dist/donut-chart/index.js +2 -0
  84. package/dist/empty-state/empty-state.d.ts +42 -10
  85. package/dist/empty-state/empty-state.js +44 -26
  86. package/dist/empty-state/empty-state.js.map +1 -1
  87. package/dist/empty-state/index.d.ts +2 -2
  88. package/dist/empty-state/index.js +2 -2
  89. package/dist/file-drop-zone/file-drop-zone.js +1 -1
  90. package/dist/file-drop-zone/file-drop-zone.js.map +1 -1
  91. package/dist/filter-bar/filter-bar.d.ts +50 -26
  92. package/dist/filter-bar/filter-bar.js +317 -157
  93. package/dist/filter-bar/filter-bar.js.map +1 -1
  94. package/dist/gauge/gauge.d.ts +45 -0
  95. package/dist/gauge/gauge.js +219 -0
  96. package/dist/gauge/gauge.js.map +1 -0
  97. package/dist/gauge/index.d.ts +2 -0
  98. package/dist/gauge/index.js +2 -0
  99. package/dist/in-view-title/in-view-title.d.ts +33 -0
  100. package/dist/in-view-title/in-view-title.js +119 -0
  101. package/dist/in-view-title/in-view-title.js.map +1 -0
  102. package/dist/in-view-title/index.d.ts +2 -0
  103. package/dist/in-view-title/index.js +2 -0
  104. package/dist/index.d.ts +53 -10
  105. package/dist/index.js +52 -12
  106. package/dist/input/input.js +4 -4
  107. package/dist/input/input.js.map +1 -1
  108. package/dist/lib/cn.js +11 -1
  109. package/dist/lib/cn.js.map +1 -1
  110. package/dist/lib/field-message.js +28 -10
  111. package/dist/lib/field-message.js.map +1 -1
  112. package/dist/lib/field-shell.js +10 -3
  113. package/dist/lib/field-shell.js.map +1 -1
  114. package/dist/lib/field-surface.js +31 -9
  115. package/dist/lib/field-surface.js.map +1 -1
  116. package/dist/lib/flag-emoji.js +50 -0
  117. package/dist/lib/flag-emoji.js.map +1 -0
  118. package/dist/lib/flip.js +11 -3
  119. package/dist/lib/flip.js.map +1 -1
  120. package/dist/lib/menu-highlight.js +64 -0
  121. package/dist/lib/menu-highlight.js.map +1 -0
  122. package/dist/lib/motion.js +9 -2
  123. package/dist/lib/motion.js.map +1 -1
  124. package/dist/lib/rolling-value.js +1 -1
  125. package/dist/lib/rolling-value.js.map +1 -1
  126. package/dist/lib/spring-tween.js +500 -0
  127. package/dist/lib/spring-tween.js.map +1 -0
  128. package/dist/lib/swap-text.js +3 -1
  129. package/dist/lib/swap-text.js.map +1 -1
  130. package/dist/lib/use-copy-feedback.js +17 -3
  131. package/dist/lib/use-copy-feedback.js.map +1 -1
  132. package/dist/line-chart/index.d.ts +2 -0
  133. package/dist/line-chart/index.js +2 -0
  134. package/dist/line-chart/line-chart.d.ts +116 -0
  135. package/dist/line-chart/line-chart.js +740 -0
  136. package/dist/line-chart/line-chart.js.map +1 -0
  137. package/dist/mention-input/index.d.ts +2 -0
  138. package/dist/mention-input/index.js +2 -0
  139. package/dist/mention-input/mention-input.d.ts +98 -0
  140. package/dist/mention-input/mention-input.js +576 -0
  141. package/dist/mention-input/mention-input.js.map +1 -0
  142. package/dist/menu/menu.d.ts +2 -0
  143. package/dist/menu/menu.js +23 -12
  144. package/dist/menu/menu.js.map +1 -1
  145. package/dist/money-input/index.d.ts +2 -0
  146. package/dist/money-input/index.js +2 -0
  147. package/dist/money-input/money-input.d.ts +86 -0
  148. package/dist/money-input/money-input.js +613 -0
  149. package/dist/money-input/money-input.js.map +1 -0
  150. package/dist/morph-select/index.d.ts +2 -0
  151. package/dist/morph-select/index.js +2 -0
  152. package/dist/morph-select/morph-select.d.ts +89 -0
  153. package/dist/morph-select/morph-select.js +712 -0
  154. package/dist/morph-select/morph-select.js.map +1 -0
  155. package/dist/multi-select/index.d.ts +2 -0
  156. package/dist/multi-select/index.js +2 -0
  157. package/dist/multi-select/multi-select.d.ts +77 -0
  158. package/dist/multi-select/multi-select.js +209 -0
  159. package/dist/multi-select/multi-select.js.map +1 -0
  160. package/dist/number-field/index.d.ts +2 -0
  161. package/dist/number-field/index.js +2 -0
  162. package/dist/number-field/number-field.d.ts +42 -0
  163. package/dist/number-field/number-field.js +199 -0
  164. package/dist/number-field/number-field.js.map +1 -0
  165. package/dist/onboarding-checklist/index.d.ts +2 -0
  166. package/dist/onboarding-checklist/index.js +2 -0
  167. package/dist/onboarding-checklist/onboarding-checklist.d.ts +55 -0
  168. package/dist/onboarding-checklist/onboarding-checklist.js +577 -0
  169. package/dist/onboarding-checklist/onboarding-checklist.js.map +1 -0
  170. package/dist/password-field/password-field.d.ts +16 -0
  171. package/dist/password-field/password-field.js +39 -10
  172. package/dist/password-field/password-field.js.map +1 -1
  173. package/dist/phone-input/index.d.ts +3 -0
  174. package/dist/phone-input/index.js +3 -0
  175. package/dist/phone-input/phone-countries.d.ts +29 -0
  176. package/dist/phone-input/phone-countries.js +170 -0
  177. package/dist/phone-input/phone-countries.js.map +1 -0
  178. package/dist/phone-input/phone-input.d.ts +66 -0
  179. package/dist/phone-input/phone-input.js +440 -0
  180. package/dist/phone-input/phone-input.js.map +1 -0
  181. package/dist/popover/index.d.ts +2 -2
  182. package/dist/popover/index.js +2 -2
  183. package/dist/popover/popover.d.ts +51 -2
  184. package/dist/popover/popover.js +59 -8
  185. package/dist/popover/popover.js.map +1 -1
  186. package/dist/progress/progress.d.ts +16 -2
  187. package/dist/progress/progress.js +16 -9
  188. package/dist/progress/progress.js.map +1 -1
  189. package/dist/radio-group/index.d.ts +2 -2
  190. package/dist/radio-group/index.js +2 -2
  191. package/dist/radio-group/radio-group.d.ts +33 -3
  192. package/dist/radio-group/radio-group.js +110 -10
  193. package/dist/radio-group/radio-group.js.map +1 -1
  194. package/dist/reactions/index.d.ts +2 -0
  195. package/dist/reactions/index.js +2 -0
  196. package/dist/reactions/reactions.d.ts +50 -0
  197. package/dist/reactions/reactions.js +315 -0
  198. package/dist/reactions/reactions.js.map +1 -0
  199. package/dist/rich-text-editor/index.d.ts +3 -0
  200. package/dist/rich-text-editor/index.js +2 -0
  201. package/dist/rich-text-editor/rich-text-editor.d.ts +70 -0
  202. package/dist/rich-text-editor/rich-text-editor.js +909 -0
  203. package/dist/rich-text-editor/rich-text-editor.js.map +1 -0
  204. package/dist/rich-text-editor/rich-text-engine.d.ts +16 -0
  205. package/dist/rich-text-editor/rich-text-engine.js +366 -0
  206. package/dist/rich-text-editor/rich-text-engine.js.map +1 -0
  207. package/dist/rich-text-editor/rich-text-html.js +174 -0
  208. package/dist/rich-text-editor/rich-text-html.js.map +1 -0
  209. package/dist/rich-text-editor/rich-text-icons.js +43 -0
  210. package/dist/rich-text-editor/rich-text-icons.js.map +1 -0
  211. package/dist/ridgeline/index.d.ts +2 -0
  212. package/dist/ridgeline/index.js +2 -0
  213. package/dist/ridgeline/ridgeline.d.ts +55 -0
  214. package/dist/ridgeline/ridgeline.js +701 -0
  215. package/dist/ridgeline/ridgeline.js.map +1 -0
  216. package/dist/scroll-area/index.d.ts +2 -2
  217. package/dist/scroll-area/index.js +2 -2
  218. package/dist/scroll-area/scroll-area.d.ts +68 -31
  219. package/dist/scroll-area/scroll-area.js +212 -62
  220. package/dist/scroll-area/scroll-area.js.map +1 -1
  221. package/dist/scrub-input/evaluate.d.ts +14 -0
  222. package/dist/scrub-input/evaluate.js +72 -0
  223. package/dist/scrub-input/evaluate.js.map +1 -0
  224. package/dist/scrub-input/index.d.ts +3 -0
  225. package/dist/scrub-input/index.js +3 -0
  226. package/dist/scrub-input/scrub-input.d.ts +74 -0
  227. package/dist/scrub-input/scrub-input.js +486 -0
  228. package/dist/scrub-input/scrub-input.js.map +1 -0
  229. package/dist/search-field/search-field.d.ts +24 -2
  230. package/dist/search-field/search-field.js +24 -9
  231. package/dist/search-field/search-field.js.map +1 -1
  232. package/dist/select/select.d.ts +3 -1
  233. package/dist/select/select.js +28 -14
  234. package/dist/select/select.js.map +1 -1
  235. package/dist/separator/separator.d.ts +22 -10
  236. package/dist/separator/separator.js +33 -11
  237. package/dist/separator/separator.js.map +1 -1
  238. package/dist/sheet/sheet.js +2 -1
  239. package/dist/sheet/sheet.js.map +1 -1
  240. package/dist/shortcut-recorder/index.d.ts +3 -0
  241. package/dist/shortcut-recorder/index.js +3 -0
  242. package/dist/shortcut-recorder/shortcut-model.d.ts +27 -0
  243. package/dist/shortcut-recorder/shortcut-model.js +206 -0
  244. package/dist/shortcut-recorder/shortcut-model.js.map +1 -0
  245. package/dist/shortcut-recorder/shortcut-recorder.d.ts +93 -0
  246. package/dist/shortcut-recorder/shortcut-recorder.js +489 -0
  247. package/dist/shortcut-recorder/shortcut-recorder.js.map +1 -0
  248. package/dist/slider/index.d.ts +2 -2
  249. package/dist/slider/slider.d.ts +46 -14
  250. package/dist/slider/slider.js +151 -67
  251. package/dist/slider/slider.js.map +1 -1
  252. package/dist/slope-chart/index.d.ts +2 -0
  253. package/dist/slope-chart/index.js +2 -0
  254. package/dist/slope-chart/slope-chart.d.ts +54 -0
  255. package/dist/slope-chart/slope-chart.js +568 -0
  256. package/dist/slope-chart/slope-chart.js.map +1 -0
  257. package/dist/sparkline/index.d.ts +2 -0
  258. package/dist/sparkline/index.js +2 -0
  259. package/dist/sparkline/sparkline.d.ts +46 -0
  260. package/dist/sparkline/sparkline.js +390 -0
  261. package/dist/sparkline/sparkline.js.map +1 -0
  262. package/dist/split-bar/index.d.ts +2 -0
  263. package/dist/split-bar/index.js +2 -0
  264. package/dist/split-bar/split-bar.d.ts +62 -0
  265. package/dist/split-bar/split-bar.js +513 -0
  266. package/dist/split-bar/split-bar.js.map +1 -0
  267. package/dist/split-button/split-button.d.ts +1 -1
  268. package/dist/split-button/split-button.js +12 -11
  269. package/dist/split-button/split-button.js.map +1 -1
  270. package/dist/stat-card/index.d.ts +2 -2
  271. package/dist/stat-card/index.js +2 -2
  272. package/dist/stat-card/stat-card.d.ts +58 -5
  273. package/dist/stat-card/stat-card.js +144 -17
  274. package/dist/stat-card/stat-card.js.map +1 -1
  275. package/dist/stepper/index.d.ts +2 -0
  276. package/dist/stepper/index.js +2 -0
  277. package/dist/stepper/stepper.d.ts +51 -0
  278. package/dist/stepper/stepper.js +215 -0
  279. package/dist/stepper/stepper.js.map +1 -0
  280. package/dist/streamgraph/index.d.ts +2 -0
  281. package/dist/streamgraph/index.js +2 -0
  282. package/dist/streamgraph/streamgraph.d.ts +70 -0
  283. package/dist/streamgraph/streamgraph.js +613 -0
  284. package/dist/streamgraph/streamgraph.js.map +1 -0
  285. package/dist/styles.css +1 -1
  286. package/dist/swipe-actions/index.d.ts +2 -0
  287. package/dist/swipe-actions/index.js +2 -0
  288. package/dist/swipe-actions/swipe-actions.d.ts +67 -0
  289. package/dist/swipe-actions/swipe-actions.js +552 -0
  290. package/dist/swipe-actions/swipe-actions.js.map +1 -0
  291. package/dist/switch/switch.js +2 -2
  292. package/dist/switch/switch.js.map +1 -1
  293. package/dist/table/index.d.ts +2 -2
  294. package/dist/table/index.js +2 -2
  295. package/dist/table/table.d.ts +55 -3
  296. package/dist/table/table.js +340 -165
  297. package/dist/table/table.js.map +1 -1
  298. package/dist/tabs/tabs.js +2 -2
  299. package/dist/tabs/tabs.js.map +1 -1
  300. package/dist/tag-input/index.d.ts +2 -0
  301. package/dist/tag-input/index.js +2 -0
  302. package/dist/tag-input/tag-input.d.ts +40 -0
  303. package/dist/tag-input/tag-input.js +269 -0
  304. package/dist/tag-input/tag-input.js.map +1 -0
  305. package/dist/text-morph/index.d.ts +2 -0
  306. package/dist/text-morph/index.js +2 -0
  307. package/dist/text-morph/text-morph.d.ts +23 -0
  308. package/dist/text-morph/text-morph.js +21 -0
  309. package/dist/text-morph/text-morph.js.map +1 -0
  310. package/dist/text-reveal/index.d.ts +2 -0
  311. package/dist/text-reveal/index.js +2 -0
  312. package/dist/text-reveal/text-reveal.d.ts +27 -0
  313. package/dist/text-reveal/text-reveal.js +51 -0
  314. package/dist/text-reveal/text-reveal.js.map +1 -0
  315. package/dist/text-shimmer/index.d.ts +2 -0
  316. package/dist/text-shimmer/index.js +2 -0
  317. package/dist/text-shimmer/text-shimmer.d.ts +29 -0
  318. package/dist/text-shimmer/text-shimmer.js +29 -0
  319. package/dist/text-shimmer/text-shimmer.js.map +1 -0
  320. package/dist/time-picker/time-picker.d.ts +36 -1
  321. package/dist/time-picker/time-picker.js +35 -7
  322. package/dist/time-picker/time-picker.js.map +1 -1
  323. package/dist/toast/index.d.ts +2 -2
  324. package/dist/toast/index.js +2 -2
  325. package/dist/toast/toast.d.ts +7 -1
  326. package/dist/toast/toast.js +82 -40
  327. package/dist/toast/toast.js.map +1 -1
  328. package/dist/tooltip/tooltip.d.ts +9 -2
  329. package/dist/tooltip/tooltip.js +7 -7
  330. package/dist/tooltip/tooltip.js.map +1 -1
  331. package/dist/treemap/index.d.ts +2 -0
  332. package/dist/treemap/index.js +2 -0
  333. package/dist/treemap/treemap.d.ts +53 -0
  334. package/dist/treemap/treemap.js +699 -0
  335. package/dist/treemap/treemap.js.map +1 -0
  336. package/dist/usage-meter/index.d.ts +2 -0
  337. package/dist/usage-meter/index.js +2 -0
  338. package/dist/usage-meter/usage-meter.d.ts +80 -0
  339. package/dist/usage-meter/usage-meter.js +458 -0
  340. package/dist/usage-meter/usage-meter.js.map +1 -0
  341. package/dist/waffle-chart/index.d.ts +2 -0
  342. package/dist/waffle-chart/index.js +2 -0
  343. package/dist/waffle-chart/waffle-chart.d.ts +57 -0
  344. package/dist/waffle-chart/waffle-chart.js +426 -0
  345. package/dist/waffle-chart/waffle-chart.js.map +1 -0
  346. package/package.json +165 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"morph-select.js","names":[],"sources":["../../src/morph-select/morph-select.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type FocusEvent,\n type KeyboardEvent,\n type ReactNode,\n} from \"react\";\n\nimport { labelVariants } from \"../label/label.js\";\nimport { cn, cnAll } from \"../lib/cn.js\";\nimport {\n prefersReducedMotion,\n useExitBackstop,\n useIsomorphicLayoutEffect,\n useLeavingItems,\n type Rect,\n} from \"../lib/motion.js\";\n\n/** One choice. */\nexport interface MorphSelectOption {\n value: string;\n label: string;\n /** A 20px mark shown before the label, in the list and in the trigger. An avatar or a plain icon. */\n icon?: ReactNode;\n /** Short trailing detail such as an offset or a count. Rendered with tabular numerals. */\n meta?: string;\n /** Extra words that match this option when searching. */\n keywords?: string;\n disabled?: boolean;\n}\n\n/** A labelled run of options. */\nexport interface MorphSelectGroup {\n label: string;\n options: MorphSelectOption[];\n}\n\nexport type MorphSelectItem = MorphSelectOption | MorphSelectGroup;\n\n/**\n * MorphSelect: a select whose trigger is the list. Opening grows the trigger itself\n * into the options surface (its width, height and corners spring from the closed\n * control to the open panel), a highlight glides between options, and the chosen\n * option's label lifts out of the list and settles into the trigger while the trigger\n * springs to its new width. Supports groups, type-ahead, search for long lists, and the\n * full listbox keyboard model: arrows, Home, End, PageUp, PageDown, Enter, Space,\n * Escape and Alt+ArrowUp.\n *\n * Use it for compact property pickers and form fields with up to a few hundred options.\n * Prefer a combobox when people mostly type free text, and Select when the list should\n * float over the page instead of growing from the trigger.\n *\n * It is its own listbox rather than a React Aria Select: a Select's list lives in a\n * popover, a separate surface that cannot be the trigger.\n */\nexport interface MorphSelectProps {\n /** Visible label, also the accessible name of the trigger and the list. */\n label: string;\n /** Keeps the label for assistive technology only. */\n labelHidden?: boolean;\n items: MorphSelectItem[];\n /** The chosen value. Controlled when given; `null` is nothing chosen. */\n value?: string | null;\n defaultValue?: string | null;\n onValueChange?: (value: string, option: MorphSelectOption) => void;\n /** Shown while nothing is chosen. @default \"Select\" */\n placeholder?: string;\n /** Shows a search field in place of the trigger when open. \"auto\" turns it on above eight options. @default \"auto\" */\n searchable?: boolean | \"auto\";\n searchPlaceholder?: string;\n /** Width of the open surface in px. It never gets narrower than the trigger. @default 272 */\n panelWidth?: number;\n /** Tallest the option list gets before it scrolls, in px. @default 296 */\n maxListHeight?: number;\n /** Which edge of the trigger stays put while the surface grows. @default \"start\" */\n align?: \"start\" | \"end\";\n /**\n * Control scale: the same heights as Select and Input.\n * @default \"md\"\n */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Adds a hidden input for native form submission. */\n name?: string;\n disabled?: boolean;\n /**\n * The trigger's `id`, so a `<label htmlFor>` outside the select (or a form\n * library that focuses a field by id) reaches the real control. When such a\n * label exists it NAMES the trigger: the trigger then drops its\n * `aria-labelledby` to the inner `label`, which would otherwise outrank the\n * outside label in the accessible-name computation.\n */\n id?: string;\n /**\n * Marks the choice as wrong: the trigger takes the invalid border and is\n * `aria-invalid`. Pair it with `errorMessage`, or the state is shown visually in colour only.\n */\n isInvalid?: boolean;\n /**\n * Why the choice is wrong, under the control. It shows only while `isInvalid`\n * is set, and is named in the trigger's and the search field's `aria-describedby`.\n */\n errorMessage?: ReactNode;\n /** Extra classes for the wrapper. Merged last. */\n className?: string;\n}\n\ninterface Section {\n key: string;\n label?: string;\n options: MorphSelectOption[];\n}\ninterface Change {\n value: string | null;\n dir: number;\n fly: { x: number; y: number } | null;\n}\n\nconst TYPEAHEAD_RESET = 600;\nconst PAGE = 8;\n\nconst isGroup = (item: MorphSelectItem): item is MorphSelectGroup => \"options\" in item;\n\n/** Loose options between groups gather into unlabelled sections, so the list keeps the order it was given. */\nfunction normalize(items: MorphSelectItem[]): Section[] {\n const out: Section[] = [];\n items.forEach((item, index) => {\n if (isGroup(item)) {\n out.push({ key: `group-${index}`, label: item.label, options: item.options });\n return;\n }\n const last = out[out.length - 1];\n if (last && !last.label) last.options.push(item);\n else out.push({ key: `loose-${index}`, options: [item] });\n });\n return out;\n}\n\nconst matches = (option: MorphSelectOption, needle: string) =>\n `${option.label} ${option.meta ?? \"\"} ${option.keywords ?? \"\"}`.toLowerCase().includes(needle);\n\n/** The closed trigger's width, rounded up. offsetWidth rounds to the nearest pixel, and half a pixel short is enough to ellipsize the label. */\nfunction triggerWidth(node: HTMLElement) {\n const exact = node.getBoundingClientRect().width;\n const rounded = node.offsetWidth;\n // Under a scaled ancestor the rect is scaled too, so fall back to the layout width with a pixel of slack.\n return Math.abs(exact - rounded) <= 0.5 ? Math.ceil(exact - 0.01) : rounded + 1;\n}\n\n/** The layout the closed trigger and its invisible measuring copy share, so the copy's width is the trigger's. */\nconst triggerLayout =\n \"box-border flex h-(--ms-h) items-center gap-2 ps-(--ms-pad) pe-10 font-medium whitespace-nowrap\";\n\nconst iconClass =\n \"grid size-5 flex-none place-items-center text-text-secondary [&>svg]:size-4 [&>img]:size-5 [&>img]:rounded-full [&>img]:object-cover\";\n\n/** The label a layer shows: the icon, then the text, or the placeholder. */\nfunction Value({ option, placeholder }: { option: MorphSelectOption | undefined; placeholder: string }) {\n if (!option) return <span className=\"font-normal text-muted-foreground\">{placeholder}</span>;\n return (\n <>\n {option.icon ? (\n <span className={iconClass} aria-hidden=\"true\">\n {option.icon}\n </span>\n ) : null}\n <span className=\"min-w-0 truncate\">{option.label}</span>\n </>\n );\n}\n\n/** A replaced label on its way out, popped out of flow where it stood and lifting away. */\nfunction LeavingLayer({\n id,\n rect,\n dir,\n fly,\n onDone,\n children,\n}: {\n id: number;\n rect: Rect;\n dir: number;\n fly: boolean;\n onDone: (id: number) => void;\n children: ReactNode;\n}) {\n const remove = useCallback(() => onDone(id), [onDone, id]);\n useExitBackstop(true, remove);\n return (\n <span\n aria-hidden=\"true\"\n data-leaving=\"\"\n onAnimationEnd={(event) => {\n if (event.target === event.currentTarget) remove();\n }}\n // field-swap-out lifts by 0.3em times --dir: a label that flew to the trigger lifts 0.3em, one that rolled lifts 0.45em the way the list ran.\n style={{ ...rect, \"--dir\": fly ? 1 : dir * 1.5 } as CSSProperties}\n className=\"absolute flex min-w-0 items-center gap-2 motion-safe:animate-field-swap-out motion-reduce:animate-fade-out\"\n >\n {children}\n </span>\n );\n}\n\nexport function MorphSelect({\n label,\n labelHidden = false,\n items,\n value,\n defaultValue = null,\n onValueChange,\n placeholder = \"Select\",\n searchable = \"auto\",\n searchPlaceholder,\n panelWidth = 272,\n maxListHeight = 296,\n align = \"start\",\n size = \"md\",\n name,\n disabled = false,\n id,\n isInvalid = false,\n errorMessage,\n className,\n}: MorphSelectProps) {\n const uid = useId();\n const labelId = `${uid}-label`;\n const errorId = `${uid}-error`;\n // As on Select: the message shows only while the field is invalid.\n const showError = isInvalid && errorMessage != null;\n const listId = `${uid}-list`;\n const optionId = (index: number) => `${uid}-option-${index}`;\n\n const rootRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLDivElement>(null);\n const shapeRef = useRef<HTMLDivElement>(null);\n const measureRef = useRef<HTMLSpanElement>(null);\n const faceRef = useRef<HTMLDivElement>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n // An outside <label htmlFor={id}> names the trigger natively. aria-labelledby\n // outranks it, so while one exists the trigger does not point at the inner label.\n const [outsideLabel, setOutsideLabel] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const slotRef = useRef<HTMLSpanElement>(null);\n const layerRef = useRef<HTMLSpanElement>(null);\n const highlightRef = useRef<HTMLSpanElement>(null);\n const searchRowRef = useRef<HTMLDivElement>(null);\n const optionRefs = useRef(new Map<string, HTMLElement>());\n\n const sections = useMemo(() => normalize(items), [items]);\n const all = useMemo(() => sections.flatMap((section) => section.options), [sections]);\n const indexOf = useMemo(() => new Map(all.map((option, index) => [option.value, index])), [all]);\n const canSearch = searchable === \"auto\" ? all.length > 8 : searchable;\n\n const [inner, setInner] = useState<string | null>(defaultValue);\n const selected = value !== undefined ? value : inner;\n const selectedOption = selected === null ? undefined : all.find((option) => option.value === selected);\n\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [active, setActive] = useState<string | null>(null);\n const [change, setChange] = useState<Change>({ value: null, dir: 1, fly: null });\n\n const needle = query.trim().toLowerCase();\n const visibleSections = useMemo(\n () =>\n needle\n ? sections\n .map((section) => ({\n ...section,\n options: section.options.filter((option) => matches(option, needle)),\n }))\n .filter((section) => section.options.length)\n : sections,\n [needle, sections],\n );\n const enabled = useMemo(\n () => visibleSections.flatMap((section) => section.options).filter((option) => !option.disabled),\n [visibleSections],\n );\n const current =\n active !== null && enabled.some((option) => option.value === active)\n ? active\n : (enabled[0]?.value ?? null);\n const resultCount = visibleSections.reduce((sum, section) => sum + section.options.length, 0);\n\n /* ---------------------------------------------- The shape ---------------------------------------------- */\n\n // One surface whose width and height follow the trigger and the open list. The sizes are written straight to the\n // two boxes, and the transitions in CSS do the moving, so a new label never waits on a render. Nothing animates\n // until the first measurement has landed (data-ready).\n const sizes = useRef({ trigger: 0, lid: 0, listW: 0, listH: 0 });\n const live = useRef({ open: false, anchorW: 0 });\n\n const place = useCallback(() => {\n const { trigger, lid, listW, listH } = sizes.current;\n const shape = shapeRef.current;\n const anchor = anchorRef.current;\n if (!trigger || !lid || !shape || !anchor) return;\n const isOpen = live.current.open;\n // A trigger that widens springs; one that narrows never overshoots, so it never dips under its label.\n if (trigger !== live.current.anchorW) {\n anchor.toggleAttribute(\"data-widening\", trigger > live.current.anchorW);\n live.current.anchorW = trigger;\n }\n anchor.style.width = `${trigger}px`;\n shape.style.width = `${isOpen ? Math.max(trigger, listW) : trigger}px`;\n shape.style.height = `${isOpen ? lid + listH : lid}px`;\n }, []);\n\n const read = useCallback(() => {\n const measure = measureRef.current;\n const face = faceRef.current;\n const root = rootRef.current;\n if (!measure || !face || !root) return;\n // The list is never narrower than the trigger; the width goes to CSS directly so a new label never waits on a render.\n const trigger = triggerWidth(measure);\n root.style.setProperty(\"--ms-trigger-w\", `${trigger}px`);\n sizes.current = {\n trigger,\n lid: measure.offsetHeight,\n listW: face.offsetWidth,\n listH: face.offsetHeight,\n };\n place();\n }, [place]);\n\n useIsomorphicLayoutEffect(() => {\n const measure = measureRef.current;\n const face = faceRef.current;\n const root = rootRef.current;\n if (!measure || !face || !root) return;\n read();\n // The first sizes are in place: from here on a change of size moves.\n void shapeRef.current?.offsetWidth;\n root.setAttribute(\"data-ready\", \"\");\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(read);\n observer.observe(measure);\n observer.observe(face);\n return () => observer.disconnect();\n }, [read]);\n\n useIsomorphicLayoutEffect(() => {\n if (live.current.open === open) return;\n live.current.open = open;\n // A pick changes the label and closes in the same commit, so both faces are read fresh before the shape moves.\n read();\n }, [open, read]);\n\n /* ---------------------------------------------- The highlight ---------------------------------------------- */\n\n const scrollIntent = useRef(false);\n useIsomorphicLayoutEffect(() => {\n const highlight = highlightRef.current;\n if (!highlight) return;\n const node = open && current !== null ? optionRefs.current.get(current) : undefined;\n if (!node) {\n highlight.removeAttribute(\"data-on\");\n return;\n }\n const top = node.offsetTop;\n const height = node.offsetHeight;\n // It appears where it is needed, and glides from there.\n highlight.toggleAttribute(\"data-jump\", !highlight.hasAttribute(\"data-on\") || prefersReducedMotion());\n highlight.style.translate = `0 ${top}px`;\n highlight.style.height = `${height}px`;\n highlight.setAttribute(\"data-on\", \"\");\n const scroller = scrollRef.current;\n if (scroller && scrollIntent.current) {\n scrollIntent.current = false;\n const pad = 6;\n if (top < scroller.scrollTop + pad) scroller.scrollTop = top - pad;\n else if (top + height > scroller.scrollTop + scroller.clientHeight - pad)\n scroller.scrollTop = top + height - scroller.clientHeight + pad;\n }\n }, [current, open, visibleSections]);\n\n /* ---------------------------------------------- Focus and keys ---------------------------------------------- */\n\n useIsomorphicLayoutEffect(() => {\n setOutsideLabel(id != null && (triggerRef.current?.labels?.length ?? 0) > 0);\n }, [id]);\n\n const showSearch = open && canSearch;\n // Written as attributes, since React 18 and 19 disagree about the `inert` prop and both agree about the attribute: the\n // closed list and the idle search row take no focus and are hidden from assistive technology; a search row in use replaces the trigger.\n useIsomorphicLayoutEffect(() => {\n triggerRef.current?.toggleAttribute(\"inert\", showSearch);\n searchRowRef.current?.toggleAttribute(\"inert\", !showSearch);\n const face = faceRef.current;\n if (!face) return;\n face.toggleAttribute(\"inert\", !open);\n if (open) face.removeAttribute(\"aria-hidden\");\n else face.setAttribute(\"aria-hidden\", \"true\");\n }, [open, showSearch]);\n\n // Focus lands in the lid: the search field when there is one, otherwise the trigger that keeps the active option.\n const pendingFocus = useRef<\"trigger\" | \"input\" | null>(null);\n useIsomorphicLayoutEffect(() => {\n const target = pendingFocus.current;\n pendingFocus.current = null;\n if (target === \"input\") inputRef.current?.focus({ preventScroll: true });\n if (target === \"trigger\") triggerRef.current?.focus({ preventScroll: true });\n }, [open]);\n\n const typeahead = useRef({ buffer: \"\", at: 0 });\n /** Space opens and picks on keydown; the click a button fires on the matching keyup must not undo it. */\n const suppressClick = useRef(false);\n const [announcement, setAnnouncement] = useState(\"\");\n\n function openList(focus?: string | null, seed = \"\") {\n if (disabled || open) return;\n setQuery(seed);\n setActive(focus !== undefined ? focus : selected);\n scrollIntent.current = true;\n pendingFocus.current = canSearch ? \"input\" : \"trigger\";\n setAnnouncement(\"\");\n setOpen(true);\n }\n\n const close = useCallback((restoreFocus: boolean) => {\n typeahead.current.buffer = \"\";\n if (restoreFocus) pendingFocus.current = \"trigger\";\n setOpen(false);\n }, []);\n\n function commit(option: MorphSelectOption | undefined, source?: HTMLElement | null) {\n if (!option || option.disabled) return;\n if (option.value !== selected) {\n // The chosen label starts where it stood in the list and settles into the trigger.\n let fly: Change[\"fly\"] = null;\n const slot = slotRef.current;\n const part = source?.querySelector<HTMLElement>(\"[data-part='value']\");\n if (!prefersReducedMotion() && part && slot) {\n const from = part.getBoundingClientRect();\n const to = slot.getBoundingClientRect();\n fly = { x: from.left - to.left, y: from.top + from.height / 2 - (to.top + to.height / 2) };\n }\n const from = selected === null ? -1 : (indexOf.get(selected) ?? -1);\n const to = indexOf.get(option.value) ?? 0;\n setChange({ value: option.value, dir: from < 0 ? 1 : Math.sign(to - from) || 1, fly });\n if (value === undefined) setInner(option.value);\n onValueChange?.(option.value, option);\n }\n close(true);\n }\n\n function typeTo(char: string) {\n const now = performance.now();\n const state = typeahead.current;\n state.buffer = now - state.at > TYPEAHEAD_RESET ? char : state.buffer + char;\n state.at = now;\n const buffer = state.buffer.toLowerCase();\n const repeated = buffer.split(\"\").every((letter) => letter === buffer[0]);\n const search = repeated ? buffer[0]! : buffer;\n const pool = all.filter((option) => !option.disabled);\n const from = open ? current : selected;\n const at = pool.findIndex((option) => option.value === from);\n const offset = repeated || buffer.length === 1 ? 1 : 0;\n const ordered = [...pool.slice(at + offset), ...pool.slice(0, at + offset)];\n return ordered.find((option) => option.label.toLowerCase().startsWith(search));\n }\n\n function move(to: string | null | undefined) {\n if (to === undefined || to === null) return;\n scrollIntent.current = true;\n setActive(to);\n }\n\n function onKey(event: KeyboardEvent<HTMLElement>, fromInput: boolean) {\n const { key } = event;\n if (key === \" \" && !fromInput) suppressClick.current = true;\n const printable = key.length === 1 && !event.metaKey && !event.ctrlKey && !event.altKey;\n const typing =\n performance.now() - typeahead.current.at < TYPEAHEAD_RESET && typeahead.current.buffer.length > 0;\n\n if (!open) {\n if (key === \"ArrowDown\" || key === \"ArrowUp\" || key === \"Enter\" || (key === \" \" && !typing)) {\n event.preventDefault();\n openList();\n return;\n }\n if (key === \"Home\" || key === \"End\") {\n event.preventDefault();\n const pool = all.filter((option) => !option.disabled);\n openList((key === \"Home\" ? pool[0] : pool[pool.length - 1])?.value ?? null);\n return;\n }\n if (printable) {\n event.preventDefault();\n if (canSearch) openList(undefined, key);\n else {\n const hit = typeTo(key);\n openList(hit?.value ?? selected);\n }\n }\n return;\n }\n\n const at = enabled.findIndex((option) => option.value === current);\n const caretKeys = fromInput && query.length > 0;\n const pick = () => commit(enabled[at], optionRefs.current.get(current ?? \"\"));\n switch (key) {\n case \"ArrowDown\":\n event.preventDefault();\n move(enabled[Math.min(enabled.length - 1, at + 1)]?.value);\n return;\n case \"ArrowUp\":\n event.preventDefault();\n if (event.altKey) {\n pick();\n return;\n }\n move(enabled[Math.max(0, at - 1)]?.value);\n return;\n case \"PageDown\":\n event.preventDefault();\n move(enabled[Math.min(enabled.length - 1, at + PAGE)]?.value);\n return;\n case \"PageUp\":\n event.preventDefault();\n move(enabled[Math.max(0, at - PAGE)]?.value);\n return;\n case \"Home\":\n if (caretKeys) return;\n event.preventDefault();\n move(enabled[0]?.value);\n return;\n case \"End\":\n if (caretKeys) return;\n event.preventDefault();\n move(enabled[enabled.length - 1]?.value);\n return;\n case \"Enter\":\n event.preventDefault();\n pick();\n return;\n case \"Escape\":\n event.preventDefault();\n event.stopPropagation();\n close(true);\n return;\n case \"Tab\":\n close(false);\n return;\n }\n if (fromInput) return;\n if (key === \" \" && !typing) {\n event.preventDefault();\n pick();\n return;\n }\n if (printable) {\n event.preventDefault();\n move(typeTo(key)?.value);\n }\n }\n\n // A press outside or focus leaving the control folds the list back into the trigger.\n useEffect(() => {\n if (!open) return;\n const down = (event: PointerEvent) => {\n if (!rootRef.current?.contains(event.target as Node)) close(false);\n };\n document.addEventListener(\"pointerdown\", down);\n return () => document.removeEventListener(\"pointerdown\", down);\n }, [close, open]);\n function onBlur(event: FocusEvent<HTMLDivElement>) {\n const next = event.relatedTarget as Node | null;\n if (open && next && !event.currentTarget.contains(next)) close(false);\n }\n\n function onQuery(next: string) {\n setQuery(next);\n setActive(null);\n scrollIntent.current = true;\n if (scrollRef.current) scrollRef.current.scrollTop = 0;\n const text = next.trim().toLowerCase();\n const count = text ? all.filter((option) => matches(option, text)).length : all.length;\n setAnnouncement(text ? (count ? `${count} ${count === 1 ? \"option\" : \"options\"}` : \"No matches\") : \"\");\n }\n\n /* ---------------------------------------------- The chosen label ---------------------------------------------- */\n\n // The trigger's value is a layer: a new one flies in from the list (or rolls, when it cannot) while the old one lifts away.\n const layerKey = selected ?? \"__empty\";\n const flying = change.value === selected ? change.fly : null;\n const { leaving, changed, remove } = useLeavingItems(\n layerKey,\n { key: layerKey, node: <Value option={selectedOption} placeholder={placeholder} />, dir: change.dir, fly: Boolean(flying) },\n () => layerRef.current,\n );\n\n const rootStyle = {\n \"--ms-panel-w\": `${panelWidth}px`,\n \"--ms-list-max\": `${maxListHeight}px`,\n } as CSSProperties;\n const layerStyle = {\n \"--dir\": change.dir,\n ...(flying ? { \"--fly-x\": `${flying.x}px`, \"--fly-y\": `${flying.y}px` } : {}),\n } as CSSProperties;\n\n return (\n <div\n ref={rootRef}\n data-slot=\"morph-select\"\n data-open={open || undefined}\n data-align={align}\n data-size={size}\n data-disabled={disabled || undefined}\n data-invalid={isInvalid || undefined}\n style={rootStyle}\n onBlur={onBlur}\n className={cn(\n \"morph-select-root group/ms relative inline-grid min-w-0 justify-items-start gap-2 font-sans leading-(--leading-normal) text-foreground data-[align=end]:justify-items-end data-[open]:z-30 data-[size=sm]:text-sm data-[size=md]:text-base data-[size=lg]:text-base\",\n className,\n )}\n >\n <span id={labelId} data-slot=\"morph-select-label\" className={cnAll(labelVariants(), labelHidden && \"sr-only\")}>\n {label}\n </span>\n\n <div ref={anchorRef} className=\"morph-select-anchor\">\n {/* Sizes the closed trigger. It holds the chosen label with the trigger's own padding, so the width has a target before anything moves. */}\n <span ref={measureRef} aria-hidden=\"true\" className={cnAll(triggerLayout, \"morph-select-measure\")}>\n <Value option={selectedOption} placeholder={placeholder} />\n </span>\n\n <div\n ref={shapeRef}\n data-slot=\"morph-select-shape\"\n data-open={open || undefined}\n data-disabled={disabled || undefined}\n data-invalid={isInvalid || undefined}\n className=\"morph-select-shape\"\n >\n {/* The lid is the trigger row. It stays at the top of the surface in both states and sits above the list, so a lifted label passes over it. */}\n <div className=\"absolute inset-x-0 top-0 z-10 h-(--ms-h)\">\n <button\n ref={triggerRef}\n id={id}\n type=\"button\"\n role=\"combobox\"\n data-slot=\"morph-select-trigger\"\n aria-labelledby={outsideLabel ? undefined : labelId}\n aria-invalid={isInvalid || undefined}\n aria-describedby={showError ? errorId : undefined}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-controls={listId}\n aria-activedescendant={\n open && !canSearch && current !== null ? optionId(indexOf.get(current) ?? 0) : undefined\n }\n disabled={disabled}\n tabIndex={showSearch ? -1 : 0}\n onClick={() => {\n if (suppressClick.current) {\n suppressClick.current = false;\n return;\n }\n if (open) close(true);\n else openList();\n }}\n onKeyDown={(event) => onKey(event, false)}\n onKeyUp={(event) => {\n if (event.key === \" \")\n window.setTimeout(() => {\n suppressClick.current = false;\n });\n }}\n className={cnAll(\n triggerLayout,\n \"absolute inset-0 w-full cursor-pointer border-0 bg-transparent text-start text-foreground outline-none [font-family:inherit] [font-size:inherit] [line-height:inherit] [letter-spacing:inherit] [-webkit-tap-highlight-color:transparent] [touch-action:manipulation] disabled:cursor-not-allowed\",\n )}\n >\n <span\n ref={slotRef}\n data-hidden={showSearch || undefined}\n className=\"relative block h-full min-w-0 flex-1 data-[hidden]:opacity-0 motion-safe:transition-opacity motion-safe:duration-(--duration-instant) motion-safe:ease-settle\"\n >\n {leaving.map((item) => (\n <LeavingLayer\n key={item.id}\n id={item.id}\n rect={item.rect}\n dir={item.value.dir}\n fly={item.value.fly}\n onDone={remove}\n >\n {item.value.node}\n </LeavingLayer>\n ))}\n <span\n key={layerKey}\n ref={layerRef}\n style={layerStyle}\n className={cnAll(\n \"absolute inset-0 flex min-w-0 items-center gap-2\",\n changed &&\n (flying\n ? \"motion-safe:animate-morph-select-fly motion-reduce:animate-fade-in\"\n : \"motion-safe:animate-select-value-in motion-reduce:animate-fade-in\"),\n )}\n >\n <Value option={selectedOption} placeholder={placeholder} />\n </span>\n </span>\n </button>\n\n {canSearch ? (\n <div\n ref={searchRowRef}\n className={cnAll(\n \"absolute inset-0 flex items-center gap-2 ps-(--ms-pad) pe-1.5 motion-safe:transition-opacity motion-safe:duration-(--duration-quick) motion-safe:ease-settle\",\n showSearch ? \"opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n >\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"size-4 flex-none text-muted-foreground\"\n >\n <circle cx=\"7\" cy=\"7\" r=\"4.25\" />\n <path d=\"m10.5 10.5 3 3\" />\n </svg>\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n data-slot=\"morph-select-search\"\n aria-label={`Search ${label.toLowerCase()}`}\n aria-invalid={isInvalid || undefined}\n aria-describedby={showError ? errorId : undefined}\n aria-expanded={open}\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={\n open && current !== null ? optionId(indexOf.get(current) ?? 0) : undefined\n }\n placeholder={searchPlaceholder ?? selectedOption?.label ?? \"Search\"}\n value={query}\n autoComplete=\"off\"\n spellCheck={false}\n onChange={(event) => onQuery(event.target.value)}\n onKeyDown={(event) => onKey(event, true)}\n className=\"h-full min-w-0 flex-1 border-0 bg-transparent p-0 [font:inherit] text-foreground outline-none placeholder:text-muted-foreground\"\n />\n {query ? (\n <button\n type=\"button\"\n aria-label=\"Clear search\"\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => {\n onQuery(\"\");\n inputRef.current?.focus();\n }}\n className=\"grid size-6 flex-none cursor-pointer place-items-center rounded-pill border-0 bg-muted p-0 text-text-secondary outline-none motion-safe:animate-field-clear-in motion-reduce:animate-fade-in hover:text-foreground\"\n >\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n className=\"size-3.5\"\n >\n <path d=\"m4 4 8 8M12 4l-8 8\" />\n </svg>\n </button>\n ) : null}\n {/* Sits exactly over the shared chevron, so the chevron closes the list in both lid states. */}\n <button\n type=\"button\"\n aria-label={`Close ${label.toLowerCase()}`}\n onClick={() => close(true)}\n className=\"size-9 flex-none cursor-pointer rounded-pill border-0 bg-transparent p-0 outline-none motion-safe:transition-[background-color] motion-safe:duration-(--duration-quick) motion-safe:ease-settle hover:bg-muted\"\n />\n </div>\n ) : null}\n\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"pointer-events-none absolute end-4 top-1/2 -mt-2 size-4 text-muted-foreground motion-safe:transition-[rotate] motion-safe:duration-(--duration-gentle) motion-safe:ease-gentle group-data-[open]/ms:rotate-180\"\n >\n <path d=\"m4 6 4 4 4-4\" />\n </svg>\n </div>\n\n <div\n ref={faceRef}\n data-open={open || undefined}\n className=\"morph-select-face\"\n >\n <div\n ref={scrollRef}\n className=\"max-h-(--ms-list-max) overflow-y-auto overscroll-contain pt-1.5 [scrollbar-width:thin]\"\n >\n <div id={listId} role=\"listbox\" aria-labelledby={labelId} className=\"relative grid grid-cols-1 gap-0.5\">\n <span ref={highlightRef} aria-hidden=\"true\" className=\"morph-select-highlight\" />\n {visibleSections.map((section) => {\n const rows = section.options.map((option) => {\n const index = indexOf.get(option.value) ?? 0;\n const isSelected = option.value === selected;\n return (\n <div\n key={option.value}\n id={optionId(index)}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={option.disabled || undefined}\n data-slot=\"morph-select-option\"\n data-active={option.value === current || undefined}\n ref={(node) => {\n if (node) optionRefs.current.set(option.value, node);\n else optionRefs.current.delete(option.value);\n }}\n onPointerMove={(event) => {\n if (event.pointerType === \"mouse\" && !option.disabled && option.value !== current)\n setActive(option.value);\n }}\n onPointerDown={(event) => event.preventDefault()}\n onClick={(event) => commit(option, event.currentTarget)}\n className=\"morph-select-option relative box-border flex min-h-9 cursor-pointer select-none items-center gap-2 rounded-lg text-text-secondary outline-none data-[active]:text-foreground aria-selected:text-foreground aria-disabled:cursor-not-allowed aria-disabled:opacity-(--opacity-disabled) motion-safe:transition-colors motion-safe:duration-(--duration-quick) motion-safe:ease-settle\"\n >\n <span data-part=\"value\" className=\"flex min-w-0 flex-1 items-center gap-2 font-medium\">\n {option.icon ? (\n <span className={iconClass} aria-hidden=\"true\">\n {option.icon}\n </span>\n ) : null}\n <span className=\"min-w-0 truncate\">{option.label}</span>\n </span>\n {option.meta ? (\n <span className=\"flex-none text-xs tabular-nums text-muted-foreground\">\n {option.meta}\n </span>\n ) : null}\n <span\n aria-hidden=\"true\"\n data-on={isSelected || undefined}\n className=\"grid size-4 flex-none scale-60 place-items-center text-foreground opacity-0 data-[on]:scale-100 data-[on]:opacity-100 motion-safe:transition-[opacity,scale] motion-safe:duration-(--duration-quick) motion-safe:ease-settle\"\n >\n <svg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"size-4\"\n >\n <path d=\"m3.5 8.5 3 3 6-6\" />\n </svg>\n </span>\n </div>\n );\n });\n return section.label ? (\n <div\n key={section.key}\n role=\"group\"\n aria-labelledby={`${uid}-${section.key}`}\n className=\"grid grid-cols-1 gap-0.5 not-first:mt-1\"\n >\n <div\n id={`${uid}-${section.key}`}\n role=\"presentation\"\n className=\"px-2.5 pt-2 pb-1 text-xs text-muted-foreground\"\n >\n {section.label}\n </div>\n {rows}\n </div>\n ) : (\n <div key={section.key} role=\"presentation\" className=\"grid grid-cols-1 gap-0.5 not-first:mt-1\">\n {rows}\n </div>\n );\n })}\n {resultCount === 0 ? (\n <p className=\"m-0 px-2.5 pt-3 pb-3.5 text-sm text-muted-foreground\">\n No matches for “{query.trim()}”\n </p>\n ) : null}\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {showError ? (\n <span\n id={errorId}\n data-slot=\"morph-select-error\"\n className=\"text-sm leading-(--leading-normal) text-destructive-strong\"\n >\n {errorMessage}\n </span>\n ) : null}\n {name ? <input type=\"hidden\" name={name} value={selected ?? \"\"} /> : null}\n <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {announcement}\n </span>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { MultiSelect, MultiSelectGroup, MultiSelectGroupProps, MultiSelectProps, multiSelectGroupHeaderVariants, multiSelectGroupVariants } from "./multi-select.js";
2
+ export { MultiSelect, MultiSelectGroup, type MultiSelectGroupProps, type MultiSelectProps, multiSelectGroupHeaderVariants, multiSelectGroupVariants };
@@ -0,0 +1,2 @@
1
+ import { MultiSelect, MultiSelectGroup, multiSelectGroupHeaderVariants, multiSelectGroupVariants } from "./multi-select.js";
2
+ export { MultiSelect, MultiSelectGroup, multiSelectGroupHeaderVariants, multiSelectGroupVariants };
@@ -0,0 +1,77 @@
1
+ import { ReactNode } from "react";
2
+ import { Key, SelectProps } from "react-aria-components";
3
+ //#region src/multi-select/multi-select.d.ts
4
+ /**
5
+ * MultiSelect: pick several options from a list. A Select in multiple mode
6
+ * (React Aria), so the keyboard, typeahead, focus and screen-reader behaviour
7
+ * are Select's own; the list stays open while picking.
8
+ *
9
+ * The trigger shows the first picks as chips and the rest as "+N". A new chip
10
+ * fades up from a blur and grows in on the snappy spring while the chips beside
11
+ * it glide over; the count rolls up or down as it changes. A clear button scales
12
+ * in beside the chevron when anything is picked. Options are `SelectItem`s, whose
13
+ * tick pops in as an option is picked; `MultiSelectGroup` gathers them under a
14
+ * heading.
15
+ */
16
+ export interface MultiSelectProps extends Omit<SelectProps<object, "multiple">, "className" | "style" | "children" | "items" | "selectionMode"> {
17
+ /** `SelectItem` children. */
18
+ children?: ReactNode;
19
+ /** What is being chosen, and the control's accessible name. */
20
+ label: ReactNode;
21
+ labelHidden?: boolean;
22
+ /** Shown while nothing is picked. @default "Select options" */
23
+ placeholder?: string;
24
+ /** Why the selection is wrong. Rendered under the control. */
25
+ errorMessage?: ReactNode;
26
+ /** Chips shown in the trigger before the rest become "+N". @default 2 */
27
+ maxVisible?: number;
28
+ /**
29
+ * Words after the overflow count, so `"more"` reads "+2 more". Off by default:
30
+ * the count alone, "+2".
31
+ */
32
+ moreLabel?: string;
33
+ /**
34
+ * While some picks are folded into "+N", hovering or focusing the trigger shows
35
+ * a tooltip listing them. Off by default.
36
+ *
37
+ * @default false
38
+ */
39
+ overflowTooltip?: boolean;
40
+ /** Accessible name of the clear button. @default "Clear selections" */
41
+ clearLabel?: string;
42
+ /** @default "md" */
43
+ size?: "sm" | "md" | "lg";
44
+ /** Extra classes for the wrapper. Merged last. */
45
+ className?: string;
46
+ }
47
+ export declare const MultiSelect: import("react").ForwardRefExoticComponent<MultiSelectProps & import("react").RefAttributes<HTMLButtonElement>>;
48
+ export declare const multiSelectGroupVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
49
+ export declare const multiSelectGroupHeaderVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
50
+ /**
51
+ * A run of options under a heading, such as "Countries" and "Regions". React
52
+ * Aria's ListBoxSection, so the heading names the group for assistive tech and
53
+ * the arrow keys move straight through from one group to the next.
54
+ *
55
+ * @example
56
+ * <MultiSelect label="Markets">
57
+ * <MultiSelectGroup title="Countries">
58
+ * <SelectItem id="IN">India</SelectItem>
59
+ * </MultiSelectGroup>
60
+ * <MultiSelectGroup title="Regions">
61
+ * <SelectItem id="europe">Europe</SelectItem>
62
+ * </MultiSelectGroup>
63
+ * </MultiSelect>
64
+ */
65
+ export interface MultiSelectGroupProps {
66
+ /** The heading drawn above the group, and the group's accessible name. */
67
+ title: ReactNode;
68
+ /** `SelectItem` children. */
69
+ children?: ReactNode;
70
+ /** Identifies the group in the collection. Defaults to a generated id. */
71
+ id?: Key;
72
+ /** Extra classes for the group. Merged last. */
73
+ className?: string;
74
+ }
75
+ export declare const MultiSelectGroup: import("react").ForwardRefExoticComponent<MultiSelectGroupProps & import("react").RefAttributes<HTMLElement>>;
76
+ //#endregion
77
+ //# sourceMappingURL=multi-select.d.ts.map
@@ -0,0 +1,209 @@
1
+ "use client";
2
+ import { cn, cnAll } from "../lib/cn.js";
3
+ import { SwapText } from "../lib/swap-text.js";
4
+ import { useFlip } from "../lib/flip.js";
5
+ import { Tooltip as Tooltip$1, TooltipTrigger as TooltipTrigger$1 } from "../tooltip/tooltip.js";
6
+ import { labelVariants } from "../label/label.js";
7
+ import { selectPopoverVariants, selectTriggerVariants, selectVariants } from "../select/select.js";
8
+ import { cva } from "class-variance-authority";
9
+ import { forwardRef, useContext, useRef, useState } from "react";
10
+ import { Button, ButtonContext, FieldError, Header, Label, ListBox, ListBoxSection, Popover, Select, SelectStateContext, SelectValue } from "react-aria-components";
11
+ import { jsx, jsxs } from "react/jsx-runtime";
12
+ //#region src/multi-select/multi-select.tsx
13
+ /** The picked options as chips, then "+N", reading Select's own state. */
14
+ function Chips({ placeholder, maxVisible, moreLabel, moreRef }) {
15
+ const state = useContext(SelectStateContext);
16
+ const keys = state?.value ?? [];
17
+ const labelOf = (key) => state?.collection.getItem(key)?.textValue ?? String(key);
18
+ const shown = keys.slice(0, maxVisible);
19
+ const rest = keys.length - shown.length;
20
+ const row = useRef(null);
21
+ useFlip(row, keys.join("|"), "var(--duration-smooth)", "var(--ease-smooth)");
22
+ const [initial] = useState(() => new Set(keys));
23
+ const [count, setCount] = useState({
24
+ rest,
25
+ dir: 1
26
+ });
27
+ if (count.rest !== rest) setCount({
28
+ rest,
29
+ dir: rest > count.rest ? 1 : -1
30
+ });
31
+ return /* @__PURE__ */ jsxs("span", {
32
+ ref: row,
33
+ "aria-hidden": "true",
34
+ className: "relative flex min-h-6.5 min-w-0 flex-1 items-center gap-1.5 overflow-hidden",
35
+ children: [
36
+ keys.length === 0 ? /* @__PURE__ */ jsx("span", {
37
+ "data-slot": "multi-select-placeholder",
38
+ className: "truncate text-muted-foreground motion-safe:animate-fade-in",
39
+ children: placeholder
40
+ }) : null,
41
+ shown.map((key) => /* @__PURE__ */ jsx("span", {
42
+ "data-flip": "",
43
+ "data-slot": "multi-select-chip",
44
+ className: cnAll("multi-select-chip", !initial.has(key) && "motion-safe:animate-chip-reveal"),
45
+ children: labelOf(key)
46
+ }, String(key))),
47
+ rest > 0 ? /* @__PURE__ */ jsxs("span", {
48
+ ref: moreRef,
49
+ "data-flip": "",
50
+ "data-slot": "multi-select-more",
51
+ className: "multi-select-chip text-text-secondary tabular-nums",
52
+ children: [
53
+ "+",
54
+ /* @__PURE__ */ jsx(SwapText, {
55
+ swapKey: String(rest),
56
+ dir: count.dir,
57
+ motion: "rise",
58
+ children: rest
59
+ }),
60
+ moreLabel ? /* @__PURE__ */ jsx("span", {
61
+ "data-slot": "multi-select-more-label",
62
+ className: "whitespace-pre",
63
+ children: ` ${moreLabel}`
64
+ }) : null
65
+ ]
66
+ }) : null
67
+ ]
68
+ });
69
+ }
70
+ /** The labels of the picks folded into "+N", in the order they were picked. */
71
+ function useHiddenLabels(maxVisible) {
72
+ const state = useContext(SelectStateContext);
73
+ return (state?.value ?? []).slice(maxVisible).map((key) => state?.collection.getItem(key)?.textValue ?? String(key));
74
+ }
75
+ /**
76
+ * Wraps the trigger in a tooltip naming the picks hidden behind "+N", placed
77
+ * against the +N chip rather than the whole field. Always rendered, so turning
78
+ * `overflowTooltip` on or off never swaps the trigger element (and drops its
79
+ * focus); disabled while off or while nothing is hidden, so it never opens empty.
80
+ */
81
+ function OverflowTooltip({ enabled, maxVisible, anchorRef, children }) {
82
+ const hidden = useHiddenLabels(maxVisible);
83
+ return /* @__PURE__ */ jsxs(TooltipTrigger$1, {
84
+ isDisabled: !enabled || hidden.length === 0,
85
+ children: [children, /* @__PURE__ */ jsx(Tooltip$1, {
86
+ triggerRef: anchorRef,
87
+ "data-slot": "multi-select-overflow-tooltip",
88
+ children: hidden.join(", ")
89
+ })]
90
+ });
91
+ }
92
+ /** Clears every pick. It sits outside the trigger, so it is its own tab stop. */
93
+ function Clear({ label, disabled }) {
94
+ const state = useContext(SelectStateContext);
95
+ const keys = state?.value ?? [];
96
+ if (!state || keys.length === 0 || disabled) return null;
97
+ return /* @__PURE__ */ jsx(ButtonContext.Provider, {
98
+ value: null,
99
+ children: /* @__PURE__ */ jsx(Button, {
100
+ "aria-label": label,
101
+ "data-slot": "multi-select-clear",
102
+ onPress: () => {
103
+ state.setValue([]);
104
+ state.close();
105
+ },
106
+ className: "multi-select-clear motion-safe:animate-field-clear-in motion-reduce:animate-fade-in",
107
+ children: /* @__PURE__ */ jsx("svg", {
108
+ "aria-hidden": "true",
109
+ viewBox: "0 0 16 16",
110
+ fill: "none",
111
+ stroke: "currentColor",
112
+ strokeWidth: "1.75",
113
+ strokeLinecap: "round",
114
+ className: "size-3.5",
115
+ children: /* @__PURE__ */ jsx("path", { d: "m4 4 8 8M12 4l-8 8" })
116
+ })
117
+ })
118
+ });
119
+ }
120
+ const MultiSelect = forwardRef(function MultiSelect({ children, label, labelHidden, placeholder = "Select options", errorMessage, maxVisible = 2, moreLabel, overflowTooltip = false, clearLabel = "Clear selections", size = "md", className, ...props }, ref) {
121
+ const moreRef = useRef(null);
122
+ const trigger = /* @__PURE__ */ jsxs(Button, {
123
+ ref,
124
+ "data-slot": "multi-select-trigger",
125
+ className: cnAll(selectTriggerVariants({ size }), "pe-16 multi-select-trigger"),
126
+ children: [
127
+ /* @__PURE__ */ jsx(SelectValue, {
128
+ "data-slot": "multi-select-value",
129
+ className: "sr-only",
130
+ children: ({ isPlaceholder, selectedText }) => isPlaceholder ? placeholder : selectedText
131
+ }),
132
+ /* @__PURE__ */ jsx(Chips, {
133
+ placeholder,
134
+ maxVisible,
135
+ moreLabel,
136
+ moreRef
137
+ }),
138
+ /* @__PURE__ */ jsx("svg", {
139
+ "aria-hidden": "true",
140
+ viewBox: "0 0 16 16",
141
+ fill: "none",
142
+ stroke: "currentColor",
143
+ strokeWidth: "1.75",
144
+ strokeLinecap: "round",
145
+ strokeLinejoin: "round",
146
+ className: "absolute end-(--density-control-pad-md) text-muted-foreground motion-safe:transition-[rotate] motion-safe:duration-(--duration-gentle) motion-safe:ease-gentle group-aria-expanded/trigger:rotate-180",
147
+ children: /* @__PURE__ */ jsx("path", { d: "m4 6 4 4 4-4" })
148
+ })
149
+ ]
150
+ });
151
+ return /* @__PURE__ */ jsxs(Select, {
152
+ ...props,
153
+ selectionMode: "multiple",
154
+ "data-slot": "multi-select",
155
+ className: cn(selectVariants(), className),
156
+ children: [
157
+ /* @__PURE__ */ jsx(Label, {
158
+ "data-slot": "multi-select-label",
159
+ className: cnAll(labelVariants(), labelHidden && "sr-only"),
160
+ children: label
161
+ }),
162
+ /* @__PURE__ */ jsxs("div", {
163
+ className: "relative",
164
+ children: [/* @__PURE__ */ jsx(OverflowTooltip, {
165
+ enabled: overflowTooltip,
166
+ maxVisible,
167
+ anchorRef: moreRef,
168
+ children: trigger
169
+ }), /* @__PURE__ */ jsx(Clear, {
170
+ label: clearLabel,
171
+ disabled: props.isDisabled ?? false
172
+ })]
173
+ }),
174
+ errorMessage == null ? null : /* @__PURE__ */ jsx(FieldError, {
175
+ "data-slot": "multi-select-error",
176
+ className: "text-sm leading-(--leading-normal) text-destructive-strong",
177
+ children: errorMessage
178
+ }),
179
+ /* @__PURE__ */ jsx(Popover, {
180
+ "data-slot": "multi-select-popover",
181
+ className: selectPopoverVariants(),
182
+ children: /* @__PURE__ */ jsx(ListBox, {
183
+ "data-slot": "multi-select-list",
184
+ className: "outline-none",
185
+ children
186
+ })
187
+ })
188
+ ]
189
+ });
190
+ });
191
+ const multiSelectGroupVariants = cva(["flex flex-col not-first:mt-1"]);
192
+ const multiSelectGroupHeaderVariants = cva(["px-2 pt-1.5 pb-1 text-xs leading-(--leading-normal) font-semibold text-muted-foreground"]);
193
+ const MultiSelectGroup = forwardRef(function MultiSelectGroup({ title, children, id, className }, ref) {
194
+ return /* @__PURE__ */ jsxs(ListBoxSection, {
195
+ ref,
196
+ id,
197
+ "data-slot": "multi-select-group",
198
+ className: cn(multiSelectGroupVariants(), className),
199
+ children: [/* @__PURE__ */ jsx(Header, {
200
+ "data-slot": "multi-select-group-header",
201
+ className: multiSelectGroupHeaderVariants(),
202
+ children: title
203
+ }), children]
204
+ });
205
+ });
206
+ //#endregion
207
+ export { MultiSelect, MultiSelectGroup, multiSelectGroupHeaderVariants, multiSelectGroupVariants };
208
+
209
+ //# sourceMappingURL=multi-select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-select.js","names":["TooltipTrigger","Tooltip","AriaButton","AriaSelectValue","AriaSelect","AriaLabel","AriaFieldError","AriaPopover","AriaListBox","AriaListBoxSection","AriaHeader"],"sources":["../../src/multi-select/multi-select.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport { forwardRef, useContext, useRef, useState, type ReactNode, type RefObject } from \"react\";\nimport {\n Button as AriaButton,\n ButtonContext,\n FieldError as AriaFieldError,\n Header as AriaHeader,\n Label as AriaLabel,\n ListBox as AriaListBox,\n ListBoxSection as AriaListBoxSection,\n Popover as AriaPopover,\n Select as AriaSelect,\n SelectStateContext,\n SelectValue as AriaSelectValue,\n type Key,\n type SelectProps as AriaSelectProps,\n} from \"react-aria-components\";\n\nimport { labelVariants } from \"../label/label.js\";\nimport { cn, cnAll } from \"../lib/cn.js\";\nimport { useFlip } from \"../lib/flip.js\";\nimport { SwapText } from \"../lib/swap-text.js\";\nimport { selectPopoverVariants, selectTriggerVariants, selectVariants } from \"../select/select.js\";\nimport { Tooltip, TooltipTrigger } from \"../tooltip/tooltip.js\";\n\n/**\n * MultiSelect: pick several options from a list. A Select in multiple mode\n * (React Aria), so the keyboard, typeahead, focus and screen-reader behaviour\n * are Select's own; the list stays open while picking.\n *\n * The trigger shows the first picks as chips and the rest as \"+N\". A new chip\n * fades up from a blur and grows in on the snappy spring while the chips beside\n * it glide over; the count rolls up or down as it changes. A clear button scales\n * in beside the chevron when anything is picked. Options are `SelectItem`s, whose\n * tick pops in as an option is picked; `MultiSelectGroup` gathers them under a\n * heading.\n */\nexport interface MultiSelectProps extends Omit<\n AriaSelectProps<object, \"multiple\">,\n \"className\" | \"style\" | \"children\" | \"items\" | \"selectionMode\"\n> {\n /** `SelectItem` children. */\n children?: ReactNode;\n /** What is being chosen, and the control's accessible name. */\n label: ReactNode;\n labelHidden?: boolean;\n /** Shown while nothing is picked. @default \"Select options\" */\n placeholder?: string;\n /** Why the selection is wrong. Rendered under the control. */\n errorMessage?: ReactNode;\n /** Chips shown in the trigger before the rest become \"+N\". @default 2 */\n maxVisible?: number;\n /**\n * Words after the overflow count, so `\"more\"` reads \"+2 more\". Off by default:\n * the count alone, \"+2\".\n */\n moreLabel?: string;\n /**\n * While some picks are folded into \"+N\", hovering or focusing the trigger shows\n * a tooltip listing them. Off by default.\n *\n * @default false\n */\n overflowTooltip?: boolean;\n /** Accessible name of the clear button. @default \"Clear selections\" */\n clearLabel?: string;\n /** @default \"md\" */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Extra classes for the wrapper. Merged last. */\n className?: string;\n}\n\n/** The picked options as chips, then \"+N\", reading Select's own state. */\nfunction Chips({\n placeholder,\n maxVisible,\n moreLabel,\n moreRef,\n}: {\n placeholder: string;\n maxVisible: number;\n moreLabel: string | undefined;\n moreRef: RefObject<HTMLSpanElement | null>;\n}) {\n const state = useContext(SelectStateContext);\n const keys = (state?.value as Key[] | undefined) ?? [];\n const labelOf = (key: Key) => state?.collection.getItem(key)?.textValue ?? String(key);\n const shown = keys.slice(0, maxVisible);\n const rest = keys.length - shown.length;\n const row = useRef<HTMLSpanElement>(null);\n // The chips beside a new or removed one glide to their new place.\n useFlip(row, keys.join(\"|\"), \"var(--duration-smooth)\", \"var(--ease-smooth)\");\n // Chips there at first paint never animate; later ones grow in.\n const [initial] = useState(() => new Set(keys));\n const [count, setCount] = useState({ rest, dir: 1 });\n if (count.rest !== rest) setCount({ rest, dir: rest > count.rest ? 1 : -1 });\n return (\n <span\n ref={row}\n aria-hidden=\"true\"\n className=\"relative flex min-h-6.5 min-w-0 flex-1 items-center gap-1.5 overflow-hidden\"\n >\n {keys.length === 0 ? (\n <span\n data-slot=\"multi-select-placeholder\"\n className=\"truncate text-muted-foreground motion-safe:animate-fade-in\"\n >\n {placeholder}\n </span>\n ) : null}\n {shown.map((key) => (\n <span\n key={String(key)}\n data-flip=\"\"\n data-slot=\"multi-select-chip\"\n className={cnAll(\n \"multi-select-chip\",\n !initial.has(key) && \"motion-safe:animate-chip-reveal\",\n )}\n >\n {labelOf(key)}\n </span>\n ))}\n {rest > 0 ? (\n <span\n ref={moreRef}\n data-flip=\"\"\n data-slot=\"multi-select-more\"\n className=\"multi-select-chip text-text-secondary tabular-nums\"\n >\n +\n <SwapText swapKey={String(rest)} dir={count.dir} motion=\"rise\">\n {rest}\n </SwapText>\n {/* The chip is a flex box, which drops a leading space in a bare text\n node; whitespace-pre keeps \"+2 more\" from reading \"+2more\". */}\n {moreLabel ? (\n <span data-slot=\"multi-select-more-label\" className=\"whitespace-pre\">\n {` ${moreLabel}`}\n </span>\n ) : null}\n </span>\n ) : null}\n </span>\n );\n}\n\n/** The labels of the picks folded into \"+N\", in the order they were picked. */\nfunction useHiddenLabels(maxVisible: number) {\n const state = useContext(SelectStateContext);\n const keys = (state?.value as Key[] | undefined) ?? [];\n return keys\n .slice(maxVisible)\n .map((key) => state?.collection.getItem(key)?.textValue ?? String(key));\n}\n\n/**\n * Wraps the trigger in a tooltip naming the picks hidden behind \"+N\", placed\n * against the +N chip rather than the whole field. Always rendered, so turning\n * `overflowTooltip` on or off never swaps the trigger element (and drops its\n * focus); disabled while off or while nothing is hidden, so it never opens empty.\n */\nfunction OverflowTooltip({\n enabled,\n maxVisible,\n anchorRef,\n children,\n}: {\n enabled: boolean;\n maxVisible: number;\n anchorRef: RefObject<HTMLSpanElement | null>;\n children: ReactNode;\n}) {\n const hidden = useHiddenLabels(maxVisible);\n return (\n <TooltipTrigger isDisabled={!enabled || hidden.length === 0}>\n {children}\n <Tooltip triggerRef={anchorRef} data-slot=\"multi-select-overflow-tooltip\">\n {hidden.join(\", \")}\n </Tooltip>\n </TooltipTrigger>\n );\n}\n\n/** Clears every pick. It sits outside the trigger, so it is its own tab stop. */\nfunction Clear({ label, disabled }: { label: string; disabled: boolean }) {\n const state = useContext(SelectStateContext);\n const keys = (state?.value as Key[] | undefined) ?? [];\n if (!state || keys.length === 0 || disabled) return null;\n // Select hands its trigger props to every Button inside it; clear that, or this\n // button would become a second trigger named by the label.\n return (\n <ButtonContext.Provider value={null}>\n <AriaButton\n aria-label={label}\n data-slot=\"multi-select-clear\"\n onPress={() => {\n state.setValue([]);\n state.close();\n }}\n className=\"multi-select-clear motion-safe:animate-field-clear-in motion-reduce:animate-fade-in\"\n >\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n className=\"size-3.5\"\n >\n <path d=\"m4 4 8 8M12 4l-8 8\" />\n </svg>\n </AriaButton>\n </ButtonContext.Provider>\n );\n}\n\nexport const MultiSelect = forwardRef<HTMLButtonElement, MultiSelectProps>(function MultiSelect(\n {\n children,\n label,\n labelHidden,\n placeholder = \"Select options\",\n errorMessage,\n maxVisible = 2,\n moreLabel,\n overflowTooltip = false,\n clearLabel = \"Clear selections\",\n size = \"md\",\n className,\n ...props\n },\n ref,\n) {\n const moreRef = useRef<HTMLSpanElement>(null);\n const trigger = (\n <AriaButton\n ref={ref}\n data-slot=\"multi-select-trigger\"\n className={cnAll(selectTriggerVariants({ size }), \"pe-16 multi-select-trigger\")}\n >\n <AriaSelectValue data-slot=\"multi-select-value\" className=\"sr-only\">\n {({ isPlaceholder, selectedText }) => (isPlaceholder ? placeholder : selectedText)}\n </AriaSelectValue>\n <Chips\n placeholder={placeholder}\n maxVisible={maxVisible}\n moreLabel={moreLabel}\n moreRef={moreRef}\n />\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"absolute end-(--density-control-pad-md) text-muted-foreground motion-safe:transition-[rotate] motion-safe:duration-(--duration-gentle) motion-safe:ease-gentle group-aria-expanded/trigger:rotate-180\"\n >\n <path d=\"m4 6 4 4 4-4\" />\n </svg>\n </AriaButton>\n );\n return (\n <AriaSelect<object, \"multiple\">\n {...props}\n selectionMode=\"multiple\"\n data-slot=\"multi-select\"\n className={cn(selectVariants(), className)}\n >\n <AriaLabel\n data-slot=\"multi-select-label\"\n className={cnAll(labelVariants(), labelHidden && \"sr-only\")}\n >\n {label}\n </AriaLabel>\n <div className=\"relative\">\n <OverflowTooltip enabled={overflowTooltip} maxVisible={maxVisible} anchorRef={moreRef}>\n {trigger}\n </OverflowTooltip>\n <Clear label={clearLabel} disabled={props.isDisabled ?? false} />\n </div>\n {errorMessage == null ? null : (\n <AriaFieldError\n data-slot=\"multi-select-error\"\n className=\"text-sm leading-(--leading-normal) text-destructive-strong\"\n >\n {errorMessage}\n </AriaFieldError>\n )}\n <AriaPopover data-slot=\"multi-select-popover\" className={selectPopoverVariants()}>\n <AriaListBox data-slot=\"multi-select-list\" className=\"outline-none\">\n {children}\n </AriaListBox>\n </AriaPopover>\n </AriaSelect>\n );\n});\n\nexport const multiSelectGroupVariants = cva([\"flex flex-col not-first:mt-1\"]);\n\nexport const multiSelectGroupHeaderVariants = cva([\n \"px-2 pt-1.5 pb-1 text-xs leading-(--leading-normal) font-semibold text-muted-foreground\",\n]);\n\n/**\n * A run of options under a heading, such as \"Countries\" and \"Regions\". React\n * Aria's ListBoxSection, so the heading names the group for assistive tech and\n * the arrow keys move straight through from one group to the next.\n *\n * @example\n * <MultiSelect label=\"Markets\">\n * <MultiSelectGroup title=\"Countries\">\n * <SelectItem id=\"IN\">India</SelectItem>\n * </MultiSelectGroup>\n * <MultiSelectGroup title=\"Regions\">\n * <SelectItem id=\"europe\">Europe</SelectItem>\n * </MultiSelectGroup>\n * </MultiSelect>\n */\nexport interface MultiSelectGroupProps {\n /** The heading drawn above the group, and the group's accessible name. */\n title: ReactNode;\n /** `SelectItem` children. */\n children?: ReactNode;\n /** Identifies the group in the collection. Defaults to a generated id. */\n id?: Key;\n /** Extra classes for the group. Merged last. */\n className?: string;\n}\n\nexport const MultiSelectGroup = forwardRef<HTMLElement, MultiSelectGroupProps>(\n function MultiSelectGroup({ title, children, id, className }, ref) {\n return (\n <AriaListBoxSection\n ref={ref}\n id={id}\n data-slot=\"multi-select-group\"\n className={cn(multiSelectGroupVariants(), className)}\n >\n <AriaHeader\n data-slot=\"multi-select-group-header\"\n className={multiSelectGroupHeaderVariants()}\n >\n {title}\n </AriaHeader>\n {children}\n </AriaListBoxSection>\n );\n },\n);\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { NumberField, NumberFieldProps } from "./number-field.js";
2
+ export { NumberField, type NumberFieldProps };
@@ -0,0 +1,2 @@
1
+ import { NumberField } from "./number-field.js";
2
+ export { NumberField };
@@ -0,0 +1,42 @@
1
+ import { NumberFieldProps } from "react-aria-components";
2
+ //#region src/number-field/number-field.d.ts
3
+ /**
4
+ * NumberField: a number with stepper buttons and rolling digits, on React Aria's
5
+ * `NumberField`. Parsing and formatting follow the locale, the arrow keys, PageUp,
6
+ * PageDown, Home and End step and jump, a held stepper repeats, and the field
7
+ * clamps to `minValue` and `maxValue` and snaps to `step`. A currency, a percent
8
+ * or a unit comes from `formatOptions`.
9
+ *
10
+ * The digits you see are drawn over the real input: each place value is its own
11
+ * column, so 9 to 10 opens a column and rolls the ones, and a gained or lost digit
12
+ * opens or closes its width. While you type, the columns follow the text at once
13
+ * and the caret never lags; the roll returns with the next step. A press at a limit
14
+ * (an arrow key past the maximum) pushes the digits toward it and they spring home.
15
+ *
16
+ * `description` and `error` open under the field on a spring, as Input's do.
17
+ */
18
+ interface NumberFieldProps$1 extends Omit<NumberFieldProps, "className" | "style" | "children"> {
19
+ /** What the number is, and the field's accessible name. */
20
+ label: string;
21
+ /** Render the label for screen readers only. */
22
+ labelHidden?: boolean;
23
+ /** Helper text under the field. A string, because the copy is animated word by word. */
24
+ description?: string;
25
+ /** Error text under the field. Sets `aria-invalid` and is announced as an alert. */
26
+ error?: string;
27
+ /** Shown, muted, while the field is empty. */
28
+ placeholder?: string;
29
+ /** PageUp, PageDown and Shift with an arrow move this far. React Aria steps by one on PageUp. Defaults to ten steps. */
30
+ largeStep?: number;
31
+ /**
32
+ * Control scale: the same heights as Input and Button.
33
+ * @default "md"
34
+ */
35
+ size?: "sm" | "md" | "lg";
36
+ /** Extra classes for the wrapper. Merged last. */
37
+ className?: string;
38
+ }
39
+ declare const NumberField$1: import("react").ForwardRefExoticComponent<NumberFieldProps$1 & import("react").RefAttributes<HTMLInputElement>>;
40
+ //#endregion
41
+ export { NumberField$1 as NumberField, NumberFieldProps$1 as NumberFieldProps };
42
+ //# sourceMappingURL=number-field.d.ts.map