@funstack/ui 0.1.0-alpha.2 → 0.1.0-alpha.4

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 (403) hide show
  1. package/dist/accordion/accordion-context.mjs.map +1 -1
  2. package/dist/accordion/accordion-item.mjs +18 -4
  3. package/dist/accordion/accordion-item.mjs.map +1 -1
  4. package/dist/accordion/accordion-panel.mjs +2 -3
  5. package/dist/accordion/accordion-panel.mjs.map +1 -1
  6. package/dist/accordion/accordion-root.d.mts.map +1 -1
  7. package/dist/accordion/accordion-root.mjs +34 -15
  8. package/dist/accordion/accordion-root.mjs.map +1 -1
  9. package/dist/accordion/accordion-trigger.mjs +4 -5
  10. package/dist/accordion/accordion-trigger.mjs.map +1 -1
  11. package/dist/checkbox/checkbox.d.mts +5 -3
  12. package/dist/checkbox/checkbox.d.mts.map +1 -1
  13. package/dist/checkbox/checkbox.mjs +25 -9
  14. package/dist/checkbox/checkbox.mjs.map +1 -1
  15. package/dist/checkbox-group/checkbox-group-context.mjs.map +1 -1
  16. package/dist/checkbox-group/checkbox-group-item.d.mts +2 -1
  17. package/dist/checkbox-group/checkbox-group-item.d.mts.map +1 -1
  18. package/dist/checkbox-group/checkbox-group-item.mjs +3 -1
  19. package/dist/checkbox-group/checkbox-group-item.mjs.map +1 -1
  20. package/dist/checkbox-group/checkbox-group-root.d.mts +5 -2
  21. package/dist/checkbox-group/checkbox-group-root.d.mts.map +1 -1
  22. package/dist/checkbox-group/checkbox-group-root.mjs +24 -5
  23. package/dist/checkbox-group/checkbox-group-root.mjs.map +1 -1
  24. package/dist/combobox/combobox-clear.mjs +2 -1
  25. package/dist/combobox/combobox-clear.mjs.map +1 -1
  26. package/dist/combobox/combobox-context.mjs.map +1 -1
  27. package/dist/combobox/combobox-input.d.mts +3 -1
  28. package/dist/combobox/combobox-input.d.mts.map +1 -1
  29. package/dist/combobox/combobox-input.mjs +16 -2
  30. package/dist/combobox/combobox-input.mjs.map +1 -1
  31. package/dist/combobox/combobox-list.mjs +3 -2
  32. package/dist/combobox/combobox-list.mjs.map +1 -1
  33. package/dist/combobox/combobox-popup.d.mts.map +1 -1
  34. package/dist/combobox/combobox-popup.mjs +7 -2
  35. package/dist/combobox/combobox-popup.mjs.map +1 -1
  36. package/dist/combobox/combobox-root.d.mts.map +1 -1
  37. package/dist/combobox/combobox-root.mjs +20 -5
  38. package/dist/combobox/combobox-root.mjs.map +1 -1
  39. package/dist/combobox/combobox-trigger.mjs +2 -1
  40. package/dist/combobox/combobox-trigger.mjs.map +1 -1
  41. package/dist/dialog/dialog-close.d.mts +17 -10
  42. package/dist/dialog/dialog-close.d.mts.map +1 -1
  43. package/dist/dialog/dialog-close.mjs +33 -21
  44. package/dist/dialog/dialog-close.mjs.map +1 -1
  45. package/dist/dialog/dialog-context.mjs.map +1 -1
  46. package/dist/dialog/dialog-form.d.mts +23 -10
  47. package/dist/dialog/dialog-form.d.mts.map +1 -1
  48. package/dist/dialog/dialog-form.mjs +51 -32
  49. package/dist/dialog/dialog-form.mjs.map +1 -1
  50. package/dist/dialog/dialog-popup.d.mts +10 -4
  51. package/dist/dialog/dialog-popup.d.mts.map +1 -1
  52. package/dist/dialog/dialog-popup.mjs +117 -44
  53. package/dist/dialog/dialog-popup.mjs.map +1 -1
  54. package/dist/dialog/dialog-root.d.mts +14 -8
  55. package/dist/dialog/dialog-root.d.mts.map +1 -1
  56. package/dist/dialog/dialog-root.mjs +67 -12
  57. package/dist/dialog/dialog-root.mjs.map +1 -1
  58. package/dist/dialog/dialog-trigger.d.mts +3 -2
  59. package/dist/dialog/dialog-trigger.d.mts.map +1 -1
  60. package/dist/dialog/dialog-trigger.mjs +2 -1
  61. package/dist/dialog/dialog-trigger.mjs.map +1 -1
  62. package/dist/dialog/index.d.mts +4 -2
  63. package/dist/dialog/index.d.mts.map +1 -1
  64. package/dist/dialog/index.mjs +4 -2
  65. package/dist/dialog/index.mjs.map +1 -1
  66. package/dist/field/field-control.d.mts +33 -0
  67. package/dist/field/field-control.d.mts.map +1 -0
  68. package/dist/field/field-control.mjs +68 -0
  69. package/dist/field/field-control.mjs.map +1 -0
  70. package/dist/field/field-description.d.mts +24 -0
  71. package/dist/field/field-description.d.mts.map +1 -0
  72. package/dist/field/field-description.mjs +34 -0
  73. package/dist/field/field-description.mjs.map +1 -0
  74. package/dist/field/field-error.d.mts +30 -0
  75. package/dist/field/field-error.d.mts.map +1 -0
  76. package/dist/field/field-error.mjs +42 -0
  77. package/dist/field/field-error.mjs.map +1 -0
  78. package/dist/field/field-label.d.mts +25 -0
  79. package/dist/field/field-label.d.mts.map +1 -0
  80. package/dist/field/field-label.mjs +46 -0
  81. package/dist/field/field-label.mjs.map +1 -0
  82. package/dist/field/field-root.d.mts +53 -0
  83. package/dist/field/field-root.d.mts.map +1 -0
  84. package/dist/field/field-root.mjs +319 -0
  85. package/dist/field/field-root.mjs.map +1 -0
  86. package/dist/field/index.d.mts +18 -0
  87. package/dist/field/index.d.mts.map +1 -0
  88. package/dist/field/index.mjs +17 -0
  89. package/dist/field/index.mjs.map +1 -0
  90. package/dist/form/form-root.d.mts +58 -0
  91. package/dist/form/form-root.d.mts.map +1 -0
  92. package/dist/form/form-root.mjs +147 -0
  93. package/dist/form/form-root.mjs.map +1 -0
  94. package/dist/form/form-submit.d.mts +31 -0
  95. package/dist/form/form-submit.d.mts.map +1 -0
  96. package/dist/form/form-submit.mjs +53 -0
  97. package/dist/form/form-submit.mjs.map +1 -0
  98. package/dist/form/index.d.mts +11 -0
  99. package/dist/form/index.d.mts.map +1 -0
  100. package/dist/form/index.mjs +11 -0
  101. package/dist/form/index.mjs.map +1 -0
  102. package/dist/index.d.mts +53 -1
  103. package/dist/index.mjs +11 -1
  104. package/dist/internal/announce.mjs +53 -0
  105. package/dist/internal/announce.mjs.map +1 -0
  106. package/dist/internal/content-focus-probe.mjs +42 -0
  107. package/dist/internal/content-focus-probe.mjs.map +1 -0
  108. package/dist/internal/decimal.mjs +27 -0
  109. package/dist/internal/decimal.mjs.map +1 -0
  110. package/dist/internal/dev-warn.mjs +17 -0
  111. package/dist/internal/dev-warn.mjs.map +1 -0
  112. package/dist/internal/field-context.d.mts +19 -0
  113. package/dist/internal/field-context.d.mts.map +1 -0
  114. package/dist/internal/field-context.mjs +14 -0
  115. package/dist/internal/field-context.mjs.map +1 -0
  116. package/dist/internal/focus-first-invalid.mjs +67 -0
  117. package/dist/internal/focus-first-invalid.mjs.map +1 -0
  118. package/dist/internal/form-status-watcher.mjs +31 -0
  119. package/dist/internal/form-status-watcher.mjs.map +1 -0
  120. package/dist/internal/modal-registry.mjs +39 -0
  121. package/dist/internal/modal-registry.mjs.map +1 -0
  122. package/dist/internal/range-value.mjs +51 -0
  123. package/dist/internal/range-value.mjs.map +1 -0
  124. package/dist/internal/render-element.mjs +54 -0
  125. package/dist/internal/render-element.mjs.map +1 -0
  126. package/dist/internal/toolbar-context.mjs +17 -0
  127. package/dist/internal/toolbar-context.mjs.map +1 -0
  128. package/dist/internal/types.d.mts +3 -1
  129. package/dist/internal/types.d.mts.map +1 -1
  130. package/dist/internal/use-controllable-action.mjs +33 -15
  131. package/dist/internal/use-controllable-action.mjs.map +1 -1
  132. package/dist/internal/use-exit-animation.mjs +26 -6
  133. package/dist/internal/use-exit-animation.mjs.map +1 -1
  134. package/dist/internal/use-field-control.mjs +109 -0
  135. package/dist/internal/use-field-control.mjs.map +1 -0
  136. package/dist/internal/use-form-owner-event.mjs +44 -0
  137. package/dist/internal/use-form-owner-event.mjs.map +1 -0
  138. package/dist/internal/use-form-reset.mjs +10 -33
  139. package/dist/internal/use-form-reset.mjs.map +1 -1
  140. package/dist/internal/use-latest.mjs +32 -0
  141. package/dist/internal/use-latest.mjs.map +1 -0
  142. package/dist/internal/use-modal-registration.mjs +47 -0
  143. package/dist/internal/use-modal-registration.mjs.map +1 -0
  144. package/dist/internal/use-native-group-reconciliation.mjs +6 -5
  145. package/dist/internal/use-native-group-reconciliation.mjs.map +1 -1
  146. package/dist/internal/use-native-select-value.mjs +7 -5
  147. package/dist/internal/use-native-select-value.mjs.map +1 -1
  148. package/dist/internal/use-popover-popup.mjs +11 -24
  149. package/dist/internal/use-popover-popup.mjs.map +1 -1
  150. package/dist/internal/use-popover-root.mjs +58 -23
  151. package/dist/internal/use-popover-root.mjs.map +1 -1
  152. package/dist/internal/use-popover-trigger.mjs +1 -1
  153. package/dist/internal/use-render.mjs +11 -34
  154. package/dist/internal/use-render.mjs.map +1 -1
  155. package/dist/internal/use-roving-focus.mjs +255 -0
  156. package/dist/internal/use-roving-focus.mjs.map +1 -0
  157. package/dist/internal/validity.d.mts +24 -0
  158. package/dist/internal/validity.d.mts.map +1 -0
  159. package/dist/internal/validity.mjs +108 -0
  160. package/dist/internal/validity.mjs.map +1 -0
  161. package/dist/menu/menu-checkbox-item.mjs +2 -1
  162. package/dist/menu/menu-checkbox-item.mjs.map +1 -1
  163. package/dist/menu/menu-group.d.mts.map +1 -1
  164. package/dist/menu/menu-group.mjs +3 -2
  165. package/dist/menu/menu-group.mjs.map +1 -1
  166. package/dist/menu/menu-item.mjs +2 -1
  167. package/dist/menu/menu-item.mjs.map +1 -1
  168. package/dist/menu/menu-popup.d.mts.map +1 -1
  169. package/dist/menu/menu-popup.mjs +7 -2
  170. package/dist/menu/menu-popup.mjs.map +1 -1
  171. package/dist/menu/menu-radio-group.mjs +9 -4
  172. package/dist/menu/menu-radio-group.mjs.map +1 -1
  173. package/dist/menu/menu-radio-item.mjs +2 -1
  174. package/dist/menu/menu-radio-item.mjs.map +1 -1
  175. package/dist/menu/menu-root.mjs +1 -1
  176. package/dist/menu/menu-root.mjs.map +1 -1
  177. package/dist/menu/menu-trigger.d.mts +2 -1
  178. package/dist/menu/menu-trigger.d.mts.map +1 -1
  179. package/dist/menu/menu-trigger.mjs +15 -4
  180. package/dist/menu/menu-trigger.mjs.map +1 -1
  181. package/dist/meter/index.d.mts +24 -0
  182. package/dist/meter/index.d.mts.map +1 -0
  183. package/dist/meter/index.mjs +23 -0
  184. package/dist/meter/index.mjs.map +1 -0
  185. package/dist/meter/meter-context.mjs +13 -0
  186. package/dist/meter/meter-context.mjs.map +1 -0
  187. package/dist/meter/meter-indicator.d.mts +19 -0
  188. package/dist/meter/meter-indicator.d.mts.map +1 -0
  189. package/dist/meter/meter-indicator.mjs +25 -0
  190. package/dist/meter/meter-indicator.mjs.map +1 -0
  191. package/dist/meter/meter-label.d.mts +19 -0
  192. package/dist/meter/meter-label.d.mts.map +1 -0
  193. package/dist/meter/meter-label.mjs +28 -0
  194. package/dist/meter/meter-label.mjs.map +1 -0
  195. package/dist/meter/meter-region.d.mts +4 -0
  196. package/dist/meter/meter-region.d.mts.map +1 -0
  197. package/dist/meter/meter-region.mjs +39 -0
  198. package/dist/meter/meter-region.mjs.map +1 -0
  199. package/dist/meter/meter-root.d.mts +71 -0
  200. package/dist/meter/meter-root.d.mts.map +1 -0
  201. package/dist/meter/meter-root.mjs +83 -0
  202. package/dist/meter/meter-root.mjs.map +1 -0
  203. package/dist/meter/meter-track.d.mts +19 -0
  204. package/dist/meter/meter-track.d.mts.map +1 -0
  205. package/dist/meter/meter-track.mjs +25 -0
  206. package/dist/meter/meter-track.mjs.map +1 -0
  207. package/dist/meter/meter-value.d.mts +20 -0
  208. package/dist/meter/meter-value.d.mts.map +1 -0
  209. package/dist/meter/meter-value.mjs +29 -0
  210. package/dist/meter/meter-value.mjs.map +1 -0
  211. package/dist/number-field/index.d.mts +26 -0
  212. package/dist/number-field/index.d.mts.map +1 -0
  213. package/dist/number-field/index.mjs +26 -0
  214. package/dist/number-field/index.mjs.map +1 -0
  215. package/dist/number-field/number-field-arithmetic.mjs +78 -0
  216. package/dist/number-field/number-field-arithmetic.mjs.map +1 -0
  217. package/dist/number-field/number-field-context.d.mts +2 -0
  218. package/dist/number-field/number-field-context.mjs +13 -0
  219. package/dist/number-field/number-field-context.mjs.map +1 -0
  220. package/dist/number-field/number-field-decrement.d.mts +16 -0
  221. package/dist/number-field/number-field-decrement.d.mts.map +1 -0
  222. package/dist/number-field/number-field-decrement.mjs +19 -0
  223. package/dist/number-field/number-field-decrement.mjs.map +1 -0
  224. package/dist/number-field/number-field-format.mjs +279 -0
  225. package/dist/number-field/number-field-format.mjs.map +1 -0
  226. package/dist/number-field/number-field-increment.d.mts +32 -0
  227. package/dist/number-field/number-field-increment.d.mts.map +1 -0
  228. package/dist/number-field/number-field-increment.mjs +68 -0
  229. package/dist/number-field/number-field-increment.mjs.map +1 -0
  230. package/dist/number-field/number-field-input.d.mts +29 -0
  231. package/dist/number-field/number-field-input.d.mts.map +1 -0
  232. package/dist/number-field/number-field-input.mjs +163 -0
  233. package/dist/number-field/number-field-input.mjs.map +1 -0
  234. package/dist/number-field/number-field-label.d.mts +23 -0
  235. package/dist/number-field/number-field-label.d.mts.map +1 -0
  236. package/dist/number-field/number-field-label.mjs +47 -0
  237. package/dist/number-field/number-field-label.mjs.map +1 -0
  238. package/dist/number-field/number-field-root.d.mts +108 -0
  239. package/dist/number-field/number-field-root.d.mts.map +1 -0
  240. package/dist/number-field/number-field-root.mjs +523 -0
  241. package/dist/number-field/number-field-root.mjs.map +1 -0
  242. package/dist/number-field/use-step-button.mjs +107 -0
  243. package/dist/number-field/use-step-button.mjs.map +1 -0
  244. package/dist/popover/popover-close.mjs +2 -1
  245. package/dist/popover/popover-close.mjs.map +1 -1
  246. package/dist/popover/popover-popup.d.mts.map +1 -1
  247. package/dist/popover/popover-popup.mjs +7 -2
  248. package/dist/popover/popover-popup.mjs.map +1 -1
  249. package/dist/popover/popover-root.mjs +1 -1
  250. package/dist/progress/index.d.mts +24 -0
  251. package/dist/progress/index.d.mts.map +1 -0
  252. package/dist/progress/index.mjs +24 -0
  253. package/dist/progress/index.mjs.map +1 -0
  254. package/dist/progress/progress-context.mjs +13 -0
  255. package/dist/progress/progress-context.mjs.map +1 -0
  256. package/dist/progress/progress-indicator.d.mts +19 -0
  257. package/dist/progress/progress-indicator.d.mts.map +1 -0
  258. package/dist/progress/progress-indicator.mjs +29 -0
  259. package/dist/progress/progress-indicator.mjs.map +1 -0
  260. package/dist/progress/progress-label.d.mts +19 -0
  261. package/dist/progress/progress-label.d.mts.map +1 -0
  262. package/dist/progress/progress-label.mjs +30 -0
  263. package/dist/progress/progress-label.mjs.map +1 -0
  264. package/dist/progress/progress-root.d.mts +68 -0
  265. package/dist/progress/progress-root.d.mts.map +1 -0
  266. package/dist/progress/progress-root.mjs +80 -0
  267. package/dist/progress/progress-root.mjs.map +1 -0
  268. package/dist/progress/progress-track.d.mts +19 -0
  269. package/dist/progress/progress-track.d.mts.map +1 -0
  270. package/dist/progress/progress-track.mjs +29 -0
  271. package/dist/progress/progress-track.mjs.map +1 -0
  272. package/dist/progress/progress-value.d.mts +20 -0
  273. package/dist/progress/progress-value.d.mts.map +1 -0
  274. package/dist/progress/progress-value.mjs +33 -0
  275. package/dist/progress/progress-value.mjs.map +1 -0
  276. package/dist/radio-group/radio-group-root.d.mts +4 -2
  277. package/dist/radio-group/radio-group-root.d.mts.map +1 -1
  278. package/dist/radio-group/radio-group-root.mjs +34 -8
  279. package/dist/radio-group/radio-group-root.mjs.map +1 -1
  280. package/dist/select/select-group.d.mts.map +1 -1
  281. package/dist/select/select-group.mjs +6 -4
  282. package/dist/select/select-group.mjs.map +1 -1
  283. package/dist/select/select-root.d.mts +4 -2
  284. package/dist/select/select-root.d.mts.map +1 -1
  285. package/dist/select/select-root.mjs +26 -6
  286. package/dist/select/select-root.mjs.map +1 -1
  287. package/dist/slider/index.d.mts +32 -0
  288. package/dist/slider/index.d.mts.map +1 -0
  289. package/dist/slider/index.mjs +27 -0
  290. package/dist/slider/index.mjs.map +1 -0
  291. package/dist/slider/slider-arithmetic.mjs +104 -0
  292. package/dist/slider/slider-arithmetic.mjs.map +1 -0
  293. package/dist/slider/slider-context.mjs +13 -0
  294. package/dist/slider/slider-context.mjs.map +1 -0
  295. package/dist/slider/slider-indicator.d.mts +22 -0
  296. package/dist/slider/slider-indicator.d.mts.map +1 -0
  297. package/dist/slider/slider-indicator.mjs +36 -0
  298. package/dist/slider/slider-indicator.mjs.map +1 -0
  299. package/dist/slider/slider-label.d.mts +23 -0
  300. package/dist/slider/slider-label.d.mts.map +1 -0
  301. package/dist/slider/slider-label.mjs +44 -0
  302. package/dist/slider/slider-label.mjs.map +1 -0
  303. package/dist/slider/slider-root.d.mts +111 -0
  304. package/dist/slider/slider-root.d.mts.map +1 -0
  305. package/dist/slider/slider-root.mjs +583 -0
  306. package/dist/slider/slider-root.mjs.map +1 -0
  307. package/dist/slider/slider-thumb.d.mts +58 -0
  308. package/dist/slider/slider-thumb.d.mts.map +1 -0
  309. package/dist/slider/slider-thumb.mjs +146 -0
  310. package/dist/slider/slider-thumb.mjs.map +1 -0
  311. package/dist/slider/slider-track.d.mts +29 -0
  312. package/dist/slider/slider-track.d.mts.map +1 -0
  313. package/dist/slider/slider-track.mjs +55 -0
  314. package/dist/slider/slider-track.mjs.map +1 -0
  315. package/dist/slider/slider-value.d.mts +34 -0
  316. package/dist/slider/slider-value.d.mts.map +1 -0
  317. package/dist/slider/slider-value.mjs +38 -0
  318. package/dist/slider/slider-value.mjs.map +1 -0
  319. package/dist/switch/switch.d.mts +5 -3
  320. package/dist/switch/switch.d.mts.map +1 -1
  321. package/dist/switch/switch.mjs +24 -8
  322. package/dist/switch/switch.mjs.map +1 -1
  323. package/dist/tabs/tabs-indicator.mjs +2 -1
  324. package/dist/tabs/tabs-indicator.mjs.map +1 -1
  325. package/dist/tabs/tabs-root.mjs +13 -3
  326. package/dist/tabs/tabs-root.mjs.map +1 -1
  327. package/dist/tabs/tabs-tab.mjs +2 -1
  328. package/dist/tabs/tabs-tab.mjs.map +1 -1
  329. package/dist/toast/index.d.mts +25 -0
  330. package/dist/toast/index.d.mts.map +1 -0
  331. package/dist/toast/index.mjs +26 -0
  332. package/dist/toast/index.mjs.map +1 -0
  333. package/dist/toast/toast-action.d.mts +39 -0
  334. package/dist/toast/toast-action.d.mts.map +1 -0
  335. package/dist/toast/toast-action.mjs +65 -0
  336. package/dist/toast/toast-action.mjs.map +1 -0
  337. package/dist/toast/toast-close.d.mts +25 -0
  338. package/dist/toast/toast-close.d.mts.map +1 -0
  339. package/dist/toast/toast-close.mjs +47 -0
  340. package/dist/toast/toast-close.mjs.map +1 -0
  341. package/dist/toast/toast-context.mjs +19 -0
  342. package/dist/toast/toast-context.mjs.map +1 -0
  343. package/dist/toast/toast-description.d.mts +24 -0
  344. package/dist/toast/toast-description.d.mts.map +1 -0
  345. package/dist/toast/toast-description.mjs +35 -0
  346. package/dist/toast/toast-description.mjs.map +1 -0
  347. package/dist/toast/toast-root.d.mts +43 -0
  348. package/dist/toast/toast-root.d.mts.map +1 -0
  349. package/dist/toast/toast-root.mjs +205 -0
  350. package/dist/toast/toast-root.mjs.map +1 -0
  351. package/dist/toast/toast-title.d.mts +24 -0
  352. package/dist/toast/toast-title.d.mts.map +1 -0
  353. package/dist/toast/toast-title.mjs +33 -0
  354. package/dist/toast/toast-title.mjs.map +1 -0
  355. package/dist/toast/toast-viewport.d.mts +52 -0
  356. package/dist/toast/toast-viewport.d.mts.map +1 -0
  357. package/dist/toast/toast-viewport.mjs +644 -0
  358. package/dist/toast/toast-viewport.mjs.map +1 -0
  359. package/dist/toast/toast.d.mts +119 -0
  360. package/dist/toast/toast.d.mts.map +1 -0
  361. package/dist/toast/toast.mjs +157 -0
  362. package/dist/toast/toast.mjs.map +1 -0
  363. package/dist/toggle/toggle.mjs +2 -1
  364. package/dist/toggle/toggle.mjs.map +1 -1
  365. package/dist/toggle-group/index.d.mts +16 -0
  366. package/dist/toggle-group/index.d.mts.map +1 -0
  367. package/dist/toggle-group/index.mjs +15 -0
  368. package/dist/toggle-group/index.mjs.map +1 -0
  369. package/dist/toggle-group/toggle-group-context.d.mts +4 -0
  370. package/dist/toggle-group/toggle-group-context.d.mts.map +1 -0
  371. package/dist/toggle-group/toggle-group-context.mjs +13 -0
  372. package/dist/toggle-group/toggle-group-context.mjs.map +1 -0
  373. package/dist/toggle-group/toggle-group-item.d.mts +47 -0
  374. package/dist/toggle-group/toggle-group-item.d.mts.map +1 -0
  375. package/dist/toggle-group/toggle-group-item.mjs +63 -0
  376. package/dist/toggle-group/toggle-group-item.mjs.map +1 -0
  377. package/dist/toggle-group/toggle-group-root.d.mts +95 -0
  378. package/dist/toggle-group/toggle-group-root.d.mts.map +1 -0
  379. package/dist/toggle-group/toggle-group-root.mjs +211 -0
  380. package/dist/toggle-group/toggle-group-root.mjs.map +1 -0
  381. package/dist/toolbar/index.d.mts +18 -0
  382. package/dist/toolbar/index.d.mts.map +1 -0
  383. package/dist/toolbar/index.mjs +18 -0
  384. package/dist/toolbar/index.mjs.map +1 -0
  385. package/dist/toolbar/toolbar-button.d.mts +42 -0
  386. package/dist/toolbar/toolbar-button.d.mts.map +1 -0
  387. package/dist/toolbar/toolbar-button.mjs +50 -0
  388. package/dist/toolbar/toolbar-button.mjs.map +1 -0
  389. package/dist/toolbar/toolbar-root.d.mts +38 -0
  390. package/dist/toolbar/toolbar-root.d.mts.map +1 -0
  391. package/dist/toolbar/toolbar-root.mjs +66 -0
  392. package/dist/toolbar/toolbar-root.mjs.map +1 -0
  393. package/dist/toolbar/toolbar-separator.d.mts +25 -0
  394. package/dist/toolbar/toolbar-separator.d.mts.map +1 -0
  395. package/dist/toolbar/toolbar-separator.mjs +31 -0
  396. package/dist/toolbar/toolbar-separator.mjs.map +1 -0
  397. package/dist/tooltip/tooltip-popup.mjs +2 -1
  398. package/dist/tooltip/tooltip-popup.mjs.map +1 -1
  399. package/dist/tooltip/tooltip-root.mjs +16 -2
  400. package/dist/tooltip/tooltip-root.mjs.map +1 -1
  401. package/dist/tooltip/tooltip-trigger.mjs +2 -1
  402. package/dist/tooltip/tooltip-trigger.mjs.map +1 -1
  403. package/package.json +10 -1
@@ -1 +1 @@
1
- {"version":3,"file":"combobox-list.mjs","names":[],"sources":["../../src/combobox/combobox-list.tsx"],"sourcesContent":["\"use client\";\nimport { use, useCallback, useRef } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport {\n ComboboxListContext,\n ComboboxPopupContext,\n useComboboxContext,\n} from \"./combobox-context.js\";\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nexport interface ComboboxListState {\n /** The deferred text the results are for: render the Options for it. */\n readonly query: string;\n /** The results shown are for an older text (`aria-busy`). */\n readonly stale: boolean;\n /** No option is mounted and the results are settled. */\n readonly empty: boolean;\n}\n\nexport interface ComboboxListProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"id\" | \"role\" | \"aria-busy\" | \"className\" | \"style\" | \"children\"\n> {\n className?: StateValue<string | undefined, ComboboxListState>;\n style?: StateValue<CSSProperties | undefined, ComboboxListState>;\n /**\n * Usually a function of `{ query }` rendering the Options for it, under your own `<Suspense>`\n * for an async search. The previous results stay visible while the next ones load.\n */\n children?: StateValue<ReactNode, ComboboxListState>;\n render?: RenderProp<ComponentPropsWithRef<\"div\">, ComboboxListState>;\n}\n\n/**\n * The listbox: `<div role=\"listbox\" aria-labelledby={label}>` (only while a `Combobox.Label` is\n * mounted), the element the input's `aria-controls` names. Its children are the results for the\n * deferred `query` (the library filters nothing, design 6.1); while they are for an older text it\n * carries `aria-busy=\"true\"` and `data-stale`. Contains only Options and Groups; a `Status`\n * rendered as a Suspense fallback inside it marks the results as loading (`aria-busy=\"true\"`).\n *\n * Owned keys (conventions 1.2): `id`, `role`, `aria-labelledby` (token-merged), `aria-busy`,\n * `data-stale`, `data-empty`.\n */\nexport function ComboboxList({ className, style, children, render, ...rest }: ComboboxListProps) {\n const ctx = useComboboxContext(\"Combobox.List\");\n const inPopup = use(ComboboxPopupContext);\n useDevWarning(\n !inPopup,\n \"Combobox.List: rendered outside a Combobox.Popup. The listbox must be inside the Popup, \" +\n \"which is the element the library shows and hides.\",\n );\n const { listRef } = ctx;\n const warnedName = useRef(false);\n\n const ref = useCallback(\n (element: HTMLElement) => {\n listRef.current = element;\n if (isDev && !warnedName.current) {\n // A mounted Label registers in a layout effect whose re-render is flushed before this\n // microtask, so `aria-labelledby` is in the DOM by then if it ever will be.\n queueMicrotask(() => {\n if (warnedName.current || !element.isConnected) return;\n if (element.hasAttribute(\"aria-labelledby\") || element.hasAttribute(\"aria-label\")) return;\n warnedName.current = true;\n console.error(\n \"Combobox.List: the listbox has no accessible name. Render a Combobox.Label, or give \" +\n \"the List an `aria-label` / `aria-labelledby`.\",\n );\n });\n }\n return () => {\n if (listRef.current === element) listRef.current = null;\n };\n },\n [listRef],\n );\n\n const state: ComboboxListState = { query: ctx.query, stale: ctx.stale, empty: ctx.empty };\n\n const libraryProps: ComponentPropsWithRef<\"div\"> & DataAttributes = {\n id: ctx.ids.list,\n role: \"listbox\",\n ...(ctx.hasLabel && { \"aria-labelledby\": ctx.ids.label }),\n \"aria-busy\": ctx.stale || ctx.loading ? true : undefined,\n \"data-stale\": dataAttr(ctx.stale),\n \"data-empty\": dataAttr(ctx.empty),\n };\n\n return useRender<ComponentPropsWithRef<\"div\">, ComboboxListState>({\n defaultElement: \"div\",\n render,\n state,\n className,\n style,\n children: (s) => (\n <ComboboxListContext value={true}>{resolveStateValue(children, s)}</ComboboxListContext>\n ),\n props: rest,\n libraryProps,\n ref,\n });\n}\n\nComboboxList.displayName = \"ComboboxList\";\n"],"mappings":";;;;;;;;AAcA,MAAM,QAAQ,QAAQ,IAAI,aAAa;;;;;;;;;;;AAmCvC,SAAgB,aAAa,EAAE,WAAW,OAAO,UAAU,QAAQ,GAAG,QAA2B;CAC/F,MAAM,MAAM,mBAAmB,eAAe;CAC9C,MAAM,UAAU,IAAI,oBAAoB;CACxC,cACE,CAAC,SACD,2IAEF;CACA,MAAM,EAAE,YAAY;CACpB,MAAM,aAAa,OAAO,KAAK;CAE/B,MAAM,MAAM,aACT,YAAyB;EACxB,QAAQ,UAAU;EAClB,IAAI,SAAS,CAAC,WAAW,SAGvB,qBAAqB;GACnB,IAAI,WAAW,WAAW,CAAC,QAAQ,aAAa;GAChD,IAAI,QAAQ,aAAa,iBAAiB,KAAK,QAAQ,aAAa,YAAY,GAAG;GACnF,WAAW,UAAU;GACrB,QAAQ,MACN,mIAEF;EACF,CAAC;EAEH,aAAa;GACX,IAAI,QAAQ,YAAY,SAAS,QAAQ,UAAU;EACrD;CACF,GACA,CAAC,OAAO,CACV;CAEA,MAAM,QAA2B;EAAE,OAAO,IAAI;EAAO,OAAO,IAAI;EAAO,OAAO,IAAI;CAAM;CAExF,MAAM,eAA8D;EAClE,IAAI,IAAI,IAAI;EACZ,MAAM;EACN,GAAI,IAAI,YAAY,EAAE,mBAAmB,IAAI,IAAI,MAAM;EACvD,aAAa,IAAI,SAAS,IAAI,UAAU,OAAO,KAAA;EAC/C,cAAc,SAAS,IAAI,KAAK;EAChC,cAAc,SAAS,IAAI,KAAK;CAClC;CAEA,OAAO,UAA2D;EAChE,gBAAgB;EAChB;EACA;EACA;EACA;EACA,WAAW,MACT,oBAAC,qBAAD;GAAqB,OAAO;GAAO,UAAA,kBAAkB,UAAU,CAAC;EAAuB,CAAA;EAEzF,OAAO;EACP;EACA;CACF,CAAC;AACH;AAEA,aAAa,cAAc"}
1
+ {"version":3,"file":"combobox-list.mjs","names":[],"sources":["../../src/combobox/combobox-list.tsx"],"sourcesContent":["\"use client\";\nimport { use, useCallback, useRef } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport {\n ComboboxListContext,\n ComboboxPopupContext,\n useComboboxContext,\n} from \"./combobox-context.js\";\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nexport interface ComboboxListState {\n /** The deferred text the results are for: render the Options for it. */\n readonly query: string;\n /** The results shown are for an older text (`aria-busy`). */\n readonly stale: boolean;\n /** No option is mounted and the results are settled. */\n readonly empty: boolean;\n}\n\nexport interface ComboboxListProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"id\" | \"role\" | \"aria-busy\" | \"className\" | \"style\" | \"children\"\n> {\n className?: StateValue<string | undefined, ComboboxListState>;\n style?: StateValue<CSSProperties | undefined, ComboboxListState>;\n /**\n * Usually a function of `{ query }` rendering the Options for it, under your own `<Suspense>`\n * for an async search. The previous results stay visible while the next ones load.\n */\n children?: StateValue<ReactNode, ComboboxListState>;\n render?: RenderProp<ComponentPropsWithRef<\"div\">, ComboboxListState>;\n}\n\n/**\n * The listbox: `<div role=\"listbox\" aria-labelledby={label}>` (only while a `Combobox.Label` is\n * mounted), the element the input's `aria-controls` names. Its children are the results for the\n * deferred `query` (the library filters nothing, design 6.1); while they are for an older text it\n * carries `aria-busy=\"true\"` and `data-stale`. Contains only Options and Groups; a `Status`\n * rendered as a Suspense fallback inside it marks the results as loading (`aria-busy=\"true\"`).\n *\n * Owned keys (conventions 1.2): `id`, `role`, `aria-labelledby` (token-merged), `aria-busy`,\n * `data-stale`, `data-empty`.\n */\nexport function ComboboxList({ className, style, children, render, ...rest }: ComboboxListProps) {\n const ctx = useComboboxContext(\"Combobox.List\");\n const inPopup = use(ComboboxPopupContext);\n useDevWarning(\n !inPopup,\n \"Combobox.List: rendered outside a Combobox.Popup. The listbox must be inside the Popup, \" +\n \"which is the element the library shows and hides.\",\n );\n const { listRef } = ctx;\n const warnedName = useRef(false);\n\n const ref = useCallback(\n (element: HTMLElement) => {\n listRef.current = element;\n if (isDev && !warnedName.current) {\n // A mounted Label registers in a layout effect whose re-render is flushed before this\n // microtask, so `aria-labelledby` is in the DOM by then if it ever will be.\n queueMicrotask(() => {\n if (warnedName.current || !element.isConnected) return;\n if (element.hasAttribute(\"aria-labelledby\") || element.hasAttribute(\"aria-label\")) return;\n warnedName.current = true;\n console.error(\n \"Combobox.List: the listbox has no accessible name. Render a Combobox.Label, or give \" +\n \"the List an `aria-label` / `aria-labelledby`.\",\n );\n });\n }\n return () => {\n if (listRef.current === element) listRef.current = null;\n };\n },\n [listRef],\n );\n\n const state: ComboboxListState = { query: ctx.query, stale: ctx.stale, empty: ctx.empty };\n\n const libraryProps: ComponentPropsWithRef<\"div\"> & DataAttributes = {\n id: ctx.ids.list,\n role: \"listbox\",\n ...(ctx.hasLabel\n ? { \"aria-labelledby\": ctx.ids.label }\n : ctx.fieldLabelId !== undefined && { \"aria-labelledby\": ctx.fieldLabelId }),\n \"aria-busy\": ctx.stale || ctx.loading ? true : undefined,\n \"data-stale\": dataAttr(ctx.stale),\n \"data-empty\": dataAttr(ctx.empty),\n };\n\n return useRender<ComponentPropsWithRef<\"div\">, ComboboxListState>({\n defaultElement: \"div\",\n render,\n state,\n className,\n style,\n children: (s) => (\n <ComboboxListContext value={true}>{resolveStateValue(children, s)}</ComboboxListContext>\n ),\n props: rest,\n libraryProps,\n ref,\n });\n}\n\nComboboxList.displayName = \"ComboboxList\";\n"],"mappings":";;;;;;;;;AAcA,MAAM,QAAQ,QAAQ,IAAI,aAAa;;;;;;;;;;;AAmCvC,SAAgB,aAAa,EAAE,WAAW,OAAO,UAAU,QAAQ,GAAG,QAA2B;CAC/F,MAAM,MAAM,mBAAmB,eAAe;CAC9C,MAAM,UAAU,IAAI,oBAAoB;CACxC,cACE,CAAC,SACD,2IAEF;CACA,MAAM,EAAE,YAAY;CACpB,MAAM,aAAa,OAAO,KAAK;CAE/B,MAAM,MAAM,aACT,YAAyB;EACxB,QAAQ,UAAU;EAClB,IAAI,SAAS,CAAC,WAAW,SAGvB,qBAAqB;GACnB,IAAI,WAAW,WAAW,CAAC,QAAQ,aAAa;GAChD,IAAI,QAAQ,aAAa,iBAAiB,KAAK,QAAQ,aAAa,YAAY,GAAG;GACnF,WAAW,UAAU;GACrB,QAAQ,MACN,mIAEF;EACF,CAAC;EAEH,aAAa;GACX,IAAI,QAAQ,YAAY,SAAS,QAAQ,UAAU;EACrD;CACF,GACA,CAAC,OAAO,CACV;CAEA,MAAM,QAA2B;EAAE,OAAO,IAAI;EAAO,OAAO,IAAI;EAAO,OAAO,IAAI;CAAM;CAExF,MAAM,eAA8D;EAClE,IAAI,IAAI,IAAI;EACZ,MAAM;EACN,GAAI,IAAI,WACJ,EAAE,mBAAmB,IAAI,IAAI,MAAM,IACnC,IAAI,iBAAiB,KAAA,KAAa,EAAE,mBAAmB,IAAI,aAAa;EAC5E,aAAa,IAAI,SAAS,IAAI,UAAU,OAAO,KAAA;EAC/C,cAAc,SAAS,IAAI,KAAK;EAChC,cAAc,SAAS,IAAI,KAAK;CAClC;CAEA,OAAO,UAA2D;EAChE,gBAAgB;EAChB;EACA;EACA;EACA;EACA,WAAW,MACT,oBAAC,qBAAD;GAAqB,OAAO;GAAO,UAAA,kBAAkB,UAAU,CAAC;EAAuB,CAAA;EAEzF,OAAO;EACP;EACA;CACF,CAAC;AACH;AAEA,aAAa,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"combobox-popup.d.mts","names":[],"sources":["../../src/combobox/combobox-popup.tsx"],"mappings":";;;iBAmBiB;;WAEN;;WAEA;;WAEA;;iBAGM,2BAA2B,KAC1C;;;;;EAeA;;;;;;;;EAQA,aAAa;EACb,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,WAAW,WAAW,WAAW;;EAEjC,SAAS,WAAW,8BAA8B;;;;;;;;;;;;;;wBAmBpC,gBACd,aACA,YACA,WACA,OACA,UACA,WACG,QACF,qBAAkB;yBARL"}
1
+ {"version":3,"file":"combobox-popup.d.mts","names":[],"sources":["../../src/combobox/combobox-popup.tsx"],"mappings":";;;iBAoBiB;;WAEN;;WAEA;;WAEA;;iBAGM,2BAA2B,KAC1C;;;;;EAeA;;;;;;;;EAQA,aAAa;EACb,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,WAAW,WAAW,WAAW;;EAEjC,SAAS,WAAW,8BAA8B;;;;;;;;;;;;;;wBAmBpC,gBACd,aACA,YACA,WACA,OACA,UACA,WACG,QACF,qBAAkB;yBARL"}
@@ -2,7 +2,9 @@
2
2
  import { useTransitionBoundary } from "../internal/transition-boundary.mjs";
3
3
  import { dataAttr } from "../internal/data-attr.mjs";
4
4
  import { mergeRefs } from "../internal/merge-props.mjs";
5
- import { resolveStateValue, useRender } from "../internal/use-render.mjs";
5
+ import { resolveStateValue } from "../internal/render-element.mjs";
6
+ import { useRender } from "../internal/use-render.mjs";
7
+ import { ToolbarContext } from "../internal/toolbar-context.mjs";
6
8
  import { usePopoverPopup } from "../internal/use-popover-popup.mjs";
7
9
  import { ComboboxPopupContext, useComboboxContext } from "./combobox-context.mjs";
8
10
  import { Activity, useCallback, useMemo } from "react";
@@ -58,7 +60,10 @@ function ComboboxPopup({ keepMounted, transition, className, style, children, re
58
60
  else node = visible ? wrapContent(resolveStateValue(children, s)) : null;
59
61
  return /* @__PURE__ */ jsx(ComboboxPopupContext, {
60
62
  value: true,
61
- children: node
63
+ children: /* @__PURE__ */ jsx(ToolbarContext, {
64
+ value: null,
65
+ children: node
66
+ })
62
67
  });
63
68
  };
64
69
  const element = useRender({
@@ -1 +1 @@
1
- {"version":3,"file":"combobox-popup.mjs","names":[],"sources":["../../src/combobox/combobox-popup.tsx"],"sourcesContent":["\"use client\";\nimport { Activity, useCallback, useMemo } from \"react\";\nimport type {\n ComponentPropsWithRef,\n CSSProperties,\n MouseEvent,\n PointerEvent,\n ReactNode,\n ViewTransitionClass,\n} from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport { mergeRefs } from \"../internal/merge-props.js\";\nimport { useTransitionBoundary } from \"../internal/transition-boundary.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { usePopoverPopup } from \"../internal/use-popover-popup.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport { ComboboxPopupContext, useComboboxContext } from \"./combobox-context.js\";\n\nexport interface ComboboxPopupState {\n /** Committed open state. Read `:popover-open` for the DOM truth. */\n readonly open: boolean;\n /** The results shown are for an older text. */\n readonly stale: boolean;\n /** The deferred text the results are for. */\n readonly query: string;\n}\n\nexport interface ComboboxPopupProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n | \"id\"\n | \"popover\"\n | \"onToggle\"\n | \"onBeforeToggle\"\n | \"onPointerDown\"\n | \"onMouseDown\"\n | \"className\"\n | \"style\"\n | \"children\"\n> {\n /**\n * `false` (default): the children are not rendered while the listbox is closed. `true`: they\n * stay mounted inside `<Activity mode=\"hidden\">`.\n */\n keepMounted?: boolean;\n /**\n * Forwarded to the `<ViewTransition default>` around the popover element itself. Animates\n * library-driven opens and closes (typing, the Trigger, an accepted option) in every engine;\n * dismissals are the browser's (CSS only). **A deferred results render also activates the\n * boundary** (React: updates from `useDeferredValue` animate), so use a type map with\n * `default: \"none\"` unless every result change should cross-fade. Static.\n */\n transition?: ViewTransitionClass;\n className?: StateValue<string | undefined, ComboboxPopupState>;\n style?: StateValue<CSSProperties | undefined, ComboboxPopupState>;\n children?: StateValue<ReactNode, ComboboxPopupState>;\n /** Must render a `<div>`: a `<dialog>` would pull focus out of the input. */\n render?: RenderProp<ComponentPropsWithRef<\"div\">, ComboboxPopupState>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nconst preventDefault = (event: { preventDefault(): void }) => event.preventDefault();\n\n/**\n * The listbox's container: `<div popover=\"auto\">`, opened by the library with\n * `showPopover({ source: input })` and placed below (or, flipped, above) the input with CSS\n * Anchor Positioning, at least as wide as the input. Focus never enters it: a press anywhere in\n * it is `preventDefault()`ed so the input keeps focus (design 7.1). Holds the `List` and, outside\n * it, `Empty` and `Status`. Style it with `:popover-open`; it emits `data-stale` but no\n * `data-open`.\n *\n * Owned keys (conventions 1.2): `id`, `popover`, `onPointerDown`, `onMouseDown`, `data-stale`.\n * Inline `position-area`, `position-try-fallbacks` and `min-width` sit under the consumer's\n * `style` (`style={{ positionTryFallbacks: \"none\" }}` removes the flip).\n */\nexport function ComboboxPopup({\n keepMounted,\n transition,\n className,\n style,\n children,\n render,\n ...rest\n}: ComboboxPopupProps) {\n const ctx = useComboboxContext(\"Combobox.Popup\");\n const { popover } = ctx;\n\n const { setElement, visible, wrapContent } = usePopoverPopup(popover, {\n part: \"Combobox.Popup\",\n initialFocus: undefined,\n // Focus stays in the input: nothing inside the popup is ever focused.\n resolveInitialFocus: () => null,\n keepMounted,\n transition,\n });\n\n const devRef = useCallback((element: HTMLElement) => {\n if (isDev && element.tagName !== \"DIV\") {\n console.error(\n `Combobox.Popup: rendered a <${element.tagName.toLowerCase()}>. Render a <div>: a ` +\n \"<dialog popover> runs the dialog focusing steps and takes focus out of the input.\",\n );\n }\n return () => {};\n }, []);\n const ref = useMemo(() => mergeRefs(setElement, devRef), [setElement, devRef]);\n\n const state: ComboboxPopupState = {\n open: popover.committed,\n stale: ctx.stale,\n query: ctx.query,\n };\n\n const libraryProps: ComponentPropsWithRef<\"div\"> & DataAttributes = {\n id: popover.ids.popup,\n popover: \"auto\",\n onPointerDown: (event: PointerEvent<HTMLDivElement>) => preventDefault(event),\n onMouseDown: (event: MouseEvent<HTMLDivElement>) => preventDefault(event),\n \"data-stale\": dataAttr(ctx.stale),\n };\n\n const content = (s: ComboboxPopupState): ReactNode => {\n let node: ReactNode;\n if (keepMounted === true) {\n node = (\n <Activity mode={visible ? \"visible\" : \"hidden\"}>\n {wrapContent(resolveStateValue(children, s))}\n </Activity>\n );\n } else {\n node = visible ? wrapContent(resolveStateValue(children, s)) : null;\n }\n return <ComboboxPopupContext value={true}>{node}</ComboboxPopupContext>;\n };\n\n const element = useRender<ComponentPropsWithRef<\"div\">, ComboboxPopupState>({\n defaultElement: \"div\",\n render,\n state,\n className,\n // Logical keywords: right under `direction: rtl` with no JS (design 7.2). The consumer wins.\n style: (s) => ({\n positionArea: \"block-end span-inline-end\",\n positionTryFallbacks: \"flip-block\",\n minWidth: \"anchor-size(width)\",\n ...resolveStateValue(style, s),\n }),\n children: content,\n props: rest,\n libraryProps,\n ref,\n });\n\n return useTransitionBoundary(\"Combobox.Popup\", transition, element);\n}\n\nComboboxPopup.displayName = \"ComboboxPopup\";\n"],"mappings":";;;;;;;;;;AA4DA,MAAM,QAAQ,QAAQ,IAAI,aAAa;AAEvC,MAAM,kBAAkB,UAAsC,MAAM,eAAe;;;;;;;;;;;;;AAcnF,SAAgB,cAAc,EAC5B,aACA,YACA,WACA,OACA,UACA,QACA,GAAG,QACkB;CACrB,MAAM,MAAM,mBAAmB,gBAAgB;CAC/C,MAAM,EAAE,YAAY;CAEpB,MAAM,EAAE,YAAY,SAAS,gBAAgB,gBAAgB,SAAS;EACpE,MAAM;EACN,cAAc,KAAA;EAEd,2BAA2B;EAC3B;EACA;CACF,CAAC;CAED,MAAM,SAAS,aAAa,YAAyB;EACnD,IAAI,SAAS,QAAQ,YAAY,OAC/B,QAAQ,MACN,+BAA+B,QAAQ,QAAQ,YAAY,EAAE,uGAE/D;EAEF,aAAa,CAAC;CAChB,GAAG,CAAC,CAAC;CACL,MAAM,MAAM,cAAc,UAAU,YAAY,MAAM,GAAG,CAAC,YAAY,MAAM,CAAC;CAE7E,MAAM,QAA4B;EAChC,MAAM,QAAQ;EACd,OAAO,IAAI;EACX,OAAO,IAAI;CACb;CAEA,MAAM,eAA8D;EAClE,IAAI,QAAQ,IAAI;EAChB,SAAS;EACT,gBAAgB,UAAwC,eAAe,KAAK;EAC5E,cAAc,UAAsC,eAAe,KAAK;EACxE,cAAc,SAAS,IAAI,KAAK;CAClC;CAEA,MAAM,WAAW,MAAqC;EACpD,IAAI;EACJ,IAAI,gBAAgB,MAClB,OACE,oBAAC,UAAD;GAAU,MAAM,UAAU,YAAY;GACnC,UAAA,YAAY,kBAAkB,UAAU,CAAC,CAAC;EACnC,CAAA;OAGZ,OAAO,UAAU,YAAY,kBAAkB,UAAU,CAAC,CAAC,IAAI;EAEjE,OAAO,oBAAC,sBAAD;GAAsB,OAAO;GAAO,UAAA;EAA2B,CAAA;CACxE;CAEA,MAAM,UAAU,UAA4D;EAC1E,gBAAgB;EAChB;EACA;EACA;EAEA,QAAQ,OAAO;GACb,cAAc;GACd,sBAAsB;GACtB,UAAU;GACV,GAAG,kBAAkB,OAAO,CAAC;EAC/B;EACA,UAAU;EACV,OAAO;EACP;EACA;CACF,CAAC;CAED,OAAO,sBAAsB,kBAAkB,YAAY,OAAO;AACpE;AAEA,cAAc,cAAc"}
1
+ {"version":3,"file":"combobox-popup.mjs","names":[],"sources":["../../src/combobox/combobox-popup.tsx"],"sourcesContent":["\"use client\";\nimport { Activity, useCallback, useMemo } from \"react\";\nimport type {\n ComponentPropsWithRef,\n CSSProperties,\n MouseEvent,\n PointerEvent,\n ReactNode,\n ViewTransitionClass,\n} from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport { mergeRefs } from \"../internal/merge-props.js\";\nimport { ToolbarContext } from \"../internal/toolbar-context.js\";\nimport { useTransitionBoundary } from \"../internal/transition-boundary.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { usePopoverPopup } from \"../internal/use-popover-popup.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport { ComboboxPopupContext, useComboboxContext } from \"./combobox-context.js\";\n\nexport interface ComboboxPopupState {\n /** Committed open state. Read `:popover-open` for the DOM truth. */\n readonly open: boolean;\n /** The results shown are for an older text. */\n readonly stale: boolean;\n /** The deferred text the results are for. */\n readonly query: string;\n}\n\nexport interface ComboboxPopupProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n | \"id\"\n | \"popover\"\n | \"onToggle\"\n | \"onBeforeToggle\"\n | \"onPointerDown\"\n | \"onMouseDown\"\n | \"className\"\n | \"style\"\n | \"children\"\n> {\n /**\n * `false` (default): the children are not rendered while the listbox is closed. `true`: they\n * stay mounted inside `<Activity mode=\"hidden\">`.\n */\n keepMounted?: boolean;\n /**\n * Forwarded to the `<ViewTransition default>` around the popover element itself. Animates\n * library-driven opens and closes (typing, the Trigger, an accepted option) in every engine;\n * dismissals are the browser's (CSS only). **A deferred results render also activates the\n * boundary** (React: updates from `useDeferredValue` animate), so use a type map with\n * `default: \"none\"` unless every result change should cross-fade. Static.\n */\n transition?: ViewTransitionClass;\n className?: StateValue<string | undefined, ComboboxPopupState>;\n style?: StateValue<CSSProperties | undefined, ComboboxPopupState>;\n children?: StateValue<ReactNode, ComboboxPopupState>;\n /** Must render a `<div>`: a `<dialog>` would pull focus out of the input. */\n render?: RenderProp<ComponentPropsWithRef<\"div\">, ComboboxPopupState>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nconst preventDefault = (event: { preventDefault(): void }) => event.preventDefault();\n\n/**\n * The listbox's container: `<div popover=\"auto\">`, opened by the library with\n * `showPopover({ source: input })` and placed below (or, flipped, above) the input with CSS\n * Anchor Positioning, at least as wide as the input. Focus never enters it: a press anywhere in\n * it is `preventDefault()`ed so the input keeps focus (design 7.1). Holds the `List` and, outside\n * it, `Empty` and `Status`. Style it with `:popover-open`; it emits `data-stale` but no\n * `data-open`.\n *\n * Owned keys (conventions 1.2): `id`, `popover`, `onPointerDown`, `onMouseDown`, `data-stale`.\n * Inline `position-area`, `position-try-fallbacks` and `min-width` sit under the consumer's\n * `style` (`style={{ positionTryFallbacks: \"none\" }}` removes the flip).\n */\nexport function ComboboxPopup({\n keepMounted,\n transition,\n className,\n style,\n children,\n render,\n ...rest\n}: ComboboxPopupProps) {\n const ctx = useComboboxContext(\"Combobox.Popup\");\n const { popover } = ctx;\n\n const { setElement, visible, wrapContent } = usePopoverPopup(popover, {\n part: \"Combobox.Popup\",\n initialFocus: undefined,\n // Focus stays in the input: nothing inside the popup is ever focused.\n resolveInitialFocus: () => null,\n keepMounted,\n transition,\n });\n\n const devRef = useCallback((element: HTMLElement) => {\n if (isDev && element.tagName !== \"DIV\") {\n console.error(\n `Combobox.Popup: rendered a <${element.tagName.toLowerCase()}>. Render a <div>: a ` +\n \"<dialog popover> runs the dialog focusing steps and takes focus out of the input.\",\n );\n }\n return () => {};\n }, []);\n const ref = useMemo(() => mergeRefs(setElement, devRef), [setElement, devRef]);\n\n const state: ComboboxPopupState = {\n open: popover.committed,\n stale: ctx.stale,\n query: ctx.query,\n };\n\n const libraryProps: ComponentPropsWithRef<\"div\"> & DataAttributes = {\n id: popover.ids.popup,\n popover: \"auto\",\n onPointerDown: (event: PointerEvent<HTMLDivElement>) => preventDefault(event),\n onMouseDown: (event: MouseEvent<HTMLDivElement>) => preventDefault(event),\n \"data-stale\": dataAttr(ctx.stale),\n };\n\n const content = (s: ComboboxPopupState): ReactNode => {\n let node: ReactNode;\n if (keepMounted === true) {\n node = (\n <Activity mode={visible ? \"visible\" : \"hidden\"}>\n {wrapContent(resolveStateValue(children, s))}\n </Activity>\n );\n } else {\n node = visible ? wrapContent(resolveStateValue(children, s)) : null;\n }\n // Not part of an enclosing Toolbar (the engine excludes `[popover]`).\n return (\n <ComboboxPopupContext value={true}>\n <ToolbarContext value={null}>{node}</ToolbarContext>\n </ComboboxPopupContext>\n );\n };\n\n const element = useRender<ComponentPropsWithRef<\"div\">, ComboboxPopupState>({\n defaultElement: \"div\",\n render,\n state,\n className,\n // Logical keywords: right under `direction: rtl` with no JS (design 7.2). The consumer wins.\n style: (s) => ({\n positionArea: \"block-end span-inline-end\",\n positionTryFallbacks: \"flip-block\",\n minWidth: \"anchor-size(width)\",\n ...resolveStateValue(style, s),\n }),\n children: content,\n props: rest,\n libraryProps,\n ref,\n });\n\n return useTransitionBoundary(\"Combobox.Popup\", transition, element);\n}\n\nComboboxPopup.displayName = \"ComboboxPopup\";\n"],"mappings":";;;;;;;;;;;;AA6DA,MAAM,QAAQ,QAAQ,IAAI,aAAa;AAEvC,MAAM,kBAAkB,UAAsC,MAAM,eAAe;;;;;;;;;;;;;AAcnF,SAAgB,cAAc,EAC5B,aACA,YACA,WACA,OACA,UACA,QACA,GAAG,QACkB;CACrB,MAAM,MAAM,mBAAmB,gBAAgB;CAC/C,MAAM,EAAE,YAAY;CAEpB,MAAM,EAAE,YAAY,SAAS,gBAAgB,gBAAgB,SAAS;EACpE,MAAM;EACN,cAAc,KAAA;EAEd,2BAA2B;EAC3B;EACA;CACF,CAAC;CAED,MAAM,SAAS,aAAa,YAAyB;EACnD,IAAI,SAAS,QAAQ,YAAY,OAC/B,QAAQ,MACN,+BAA+B,QAAQ,QAAQ,YAAY,EAAE,uGAE/D;EAEF,aAAa,CAAC;CAChB,GAAG,CAAC,CAAC;CACL,MAAM,MAAM,cAAc,UAAU,YAAY,MAAM,GAAG,CAAC,YAAY,MAAM,CAAC;CAE7E,MAAM,QAA4B;EAChC,MAAM,QAAQ;EACd,OAAO,IAAI;EACX,OAAO,IAAI;CACb;CAEA,MAAM,eAA8D;EAClE,IAAI,QAAQ,IAAI;EAChB,SAAS;EACT,gBAAgB,UAAwC,eAAe,KAAK;EAC5E,cAAc,UAAsC,eAAe,KAAK;EACxE,cAAc,SAAS,IAAI,KAAK;CAClC;CAEA,MAAM,WAAW,MAAqC;EACpD,IAAI;EACJ,IAAI,gBAAgB,MAClB,OACE,oBAAC,UAAD;GAAU,MAAM,UAAU,YAAY;GACnC,UAAA,YAAY,kBAAkB,UAAU,CAAC,CAAC;EACnC,CAAA;OAGZ,OAAO,UAAU,YAAY,kBAAkB,UAAU,CAAC,CAAC,IAAI;EAGjE,OACE,oBAAC,sBAAD;GAAsB,OAAO;GAC3B,UAAA,oBAAC,gBAAD;IAAgB,OAAO;IAAO,UAAA;GAAqB,CAAA;EAC/B,CAAA;CAE1B;CAEA,MAAM,UAAU,UAA4D;EAC1E,gBAAgB;EAChB;EACA;EACA;EAEA,QAAQ,OAAO;GACb,cAAc;GACd,sBAAsB;GACtB,UAAU;GACV,GAAG,kBAAkB,OAAO,CAAC;EAC/B;EACA,UAAU;EACV,OAAO;EACP;EACA;CACF,CAAC;CAED,OAAO,sBAAsB,kBAAkB,YAAY,OAAO;AACpE;AAEA,cAAc,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"combobox-root.d.mts","names":[],"sources":["../../src/combobox/combobox-root.tsx"],"mappings":";;;;iBAgCiB,mCAAmC;;;;;;;WAOzC,QAAQ;;WAER;;;iBAIM,wCAAwC;;;;;;;WAO9C,QAAQ;;;iBAIF,kCAAkC;;;;;;;WAOxC,QAAQ;;iBAGF;;WAEN;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;WACA;;iBAGM;;EAEf;;EAEA;;;;;;;;EAQA,oBAAoB,4BAA4B;;EAGhD;;;;;EAKA;;;;;;;;EAQA,yBAAyB,2BAA2B;;EAGpD;;EAEA;;;;;EAKA,mBAAmB,sBAAsB;;;;;;;EAQzC;;;;;EAKA;;EAEA;;EAEA;;;;;;;EAOA,YAAY,eAAe,OAAO;;EAGlC;;EAEA;;EAEA;EACA,WAAW,WAAW,WAAW;;;;;;;;;;;wBA+DnB,aAAa,OAAO,oCAAiB,IAAA;yBAArC"}
1
+ {"version":3,"file":"combobox-root.d.mts","names":[],"sources":["../../src/combobox/combobox-root.tsx"],"mappings":";;;;iBAmCiB,mCAAmC;;;;;;;WAOzC,QAAQ;;WAER;;;iBAIM,wCAAwC;;;;;;;WAO9C,QAAQ;;;iBAIF,kCAAkC;;;;;;;WAOxC,QAAQ;;iBAGF;;WAEN;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;WACA;;iBAGM;;EAEf;;EAEA;;;;;;;;EAQA,oBAAoB,4BAA4B;;EAGhD;;;;;EAKA;;;;;;;;EAQA,yBAAyB,2BAA2B;;EAGpD;;EAEA;;;;;EAKA,mBAAmB,sBAAsB;;;;;;;EAQzC;;;;;EAKA;;EAEA;;EAEA;;;;;;;EAOA,YAAY,eAAe,OAAO;;EAGlC;;EAEA;;EAEA;EACA,WAAW,WAAW,WAAW;;;;;;;;;;;wBA+DnB,aAAa,OAAO,oCAAiB,IAAA;yBAArC"}
@@ -1,12 +1,14 @@
1
1
  "use client";
2
2
  import { createActionDetails } from "../internal/action-details.mjs";
3
3
  import { useControllableAction } from "../internal/use-controllable-action.mjs";
4
- import { resolveStateValue } from "../internal/use-render.mjs";
4
+ import { resolveStateValue } from "../internal/render-element.mjs";
5
5
  import { useDevWarning } from "../internal/use-dev-warning.mjs";
6
+ import { FieldContext } from "../internal/field-context.mjs";
7
+ import { useFieldValueChange } from "../internal/use-field-control.mjs";
6
8
  import { useFormReset } from "../internal/use-form-reset.mjs";
7
9
  import { usePopoverRoot } from "../internal/use-popover-root.mjs";
8
10
  import { ComboboxContext } from "./combobox-context.mjs";
9
- import { useCallback, useDeferredValue, useEffect, useId, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
11
+ import { use, useCallback, useDeferredValue, useEffect, useId, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
10
12
  import { jsx, jsxs } from "react/jsx-runtime";
11
13
  import { flushSync } from "react-dom";
12
14
  //#region src/combobox/combobox-root.tsx
@@ -39,14 +41,18 @@ function isThenable(value) {
39
41
  * `name` is given.
40
42
  */
41
43
  function ComboboxRoot(props) {
42
- const { value, defaultValue, valueChangeAction, inputValue: inputValueProp, defaultInputValue, open, defaultOpen, openChangeAction, allowCustomValue = false, autoHighlight = false, openOnClick = false, loop = false, name, form, disabled = false, children } = props;
44
+ const { value, defaultValue, valueChangeAction, inputValue: inputValueProp, defaultInputValue, open, defaultOpen, openChangeAction, allowCustomValue = false, autoHighlight = false, openOnClick = false, loop = false, form, children } = props;
45
+ const field = use(FieldContext);
46
+ const name = props.name ?? field?.name;
47
+ const disabled = (props.disabled ?? false) || (field?.disabled ?? false);
48
+ const fieldControlId = field?.ids.control;
43
49
  const id = useId();
44
50
  const ids = useMemo(() => ({
45
- input: `${id}-input`,
51
+ input: fieldControlId ?? `${id}-input`,
46
52
  label: `${id}-label`,
47
53
  list: `${id}-list`,
48
54
  optionPrefix: `${id}-option-`
49
- }), [id]);
55
+ }), [id, fieldControlId]);
50
56
  const popover = usePopoverRoot({
51
57
  component: "combobox",
52
58
  part: "Combobox.Root",
@@ -129,6 +135,8 @@ function ComboboxRoot(props) {
129
135
  useInsertionEffect(() => {
130
136
  committedRef.current = selection.committed;
131
137
  });
138
+ /** The next change of the optimistic selection comes from the user (a dispatch). */
139
+ const userEdit = useRef(false);
132
140
  const dispatchValue = (next, event, fields, options) => {
133
141
  const details = createActionDetails(event, fields);
134
142
  const dispatchId = ++dispatchSeq.current;
@@ -144,8 +152,14 @@ function ComboboxRoot(props) {
144
152
  text: options.text,
145
153
  settled: false
146
154
  };
155
+ if (next !== selection.optimistic) userEdit.current = true;
147
156
  selection.dispatch(next, details);
148
157
  };
158
+ useFieldValueChange(selection.optimistic, () => {
159
+ const edit = userEdit.current;
160
+ userEdit.current = false;
161
+ return edit;
162
+ });
149
163
  const [registry] = useState(() => /* @__PURE__ */ new Map());
150
164
  const [optionCount, setOptionCount] = useState(0);
151
165
  const [statusCount, setStatusCount] = useState(0);
@@ -476,6 +490,7 @@ function ComboboxRoot(props) {
476
490
  empty,
477
491
  loading,
478
492
  hasLabel: labelCount > 0,
493
+ fieldLabelId: field?.ids.label,
479
494
  disabled,
480
495
  inputRef,
481
496
  listRef,
@@ -1 +1 @@
1
- {"version":3,"file":"combobox-root.mjs","names":[],"sources":["../../src/combobox/combobox-root.tsx"],"sourcesContent":["\"use client\";\nimport {\n useCallback,\n useDeferredValue,\n useEffect,\n useId,\n useInsertionEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { flushSync } from \"react-dom\";\nimport type { ReactNode, RefObject } from \"react\";\nimport { createActionDetails } from \"../internal/action-details.js\";\nimport type {\n ActionDetails,\n ChangeAction,\n ChangeReason,\n StateValue,\n UrgentChangeAction,\n} from \"../internal/types.js\";\nimport { useControllableAction } from \"../internal/use-controllable-action.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport { useFormReset } from \"../internal/use-form-reset.js\";\nimport type { FormAssociatedElement } from \"../internal/use-form-reset.js\";\nimport { usePopoverRoot } from \"../internal/use-popover-root.js\";\nimport { resolveStateValue } from \"../internal/use-render.js\";\nimport { ComboboxContext } from \"./combobox-context.js\";\nimport type { ComboboxContextValue, ComboboxOptionEntry } from \"./combobox-context.js\";\n\n/** Details passed as the second argument of `Combobox.Root`'s `valueChangeAction`. */\nexport interface ComboboxValueChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: the user accepted an option (Enter, click; `details.event` is the `keydown` or\n * `click`), committed free text with `allowCustomValue` (Enter: the `keydown`; focus leaving:\n * the `focusout`), or pressed Clear (`click`).\n * `\"platform\"`: a form reset (`details.event` is the `reset` event).\n */\n readonly reason: ChangeReason;\n /** `true` when `next` is free text committed under `allowCustomValue`, not an option's value. */\n readonly custom: boolean;\n}\n\n/** Details passed as the second argument of `Combobox.Root`'s `inputValueChangeAction`. */\nexport interface ComboboxInputValueChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: typing (the `input` event), an accepted option's label, Clear.\n * `\"dismiss\"`: a revert: focus left with unmatched text, or the selection rolled back.\n * `\"platform\"`: form reset (the `reset` event), or text found in the input at mount\n * (`undefined`).\n */\n readonly reason: ChangeReason;\n}\n\n/** Details passed as the second argument of `Combobox.Root`'s `openChangeAction`. */\nexport interface ComboboxOpenChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: typing, ArrowDown / ArrowUp / Alt+ArrowDown, the Trigger, a click on the input\n * with `openOnClick`, an accepted option (the close after it), a foreign `showPopover()`.\n * `\"dismiss\"`: Escape, light dismiss, focus leaving the combobox, another top-layer element.\n * `\"platform\"`: the popup was found open on mount (only script can cause it).\n */\n readonly reason: ChangeReason;\n}\n\nexport interface ComboboxRootState {\n /** Optimistic selection. Content rendered from it must not suspend. */\n readonly value: string | null;\n /** The text in the input (urgent). */\n readonly inputValue: string;\n /** The deferred text the mounted results are for. */\n readonly query: string;\n /** `inputValue !== query`: the results shown are for an older text. */\n readonly stale: boolean;\n /** The value of the option `aria-activedescendant` points at, or `null`. */\n readonly activeValue: string | null;\n /** Optimistic open state. */\n readonly open: boolean;\n /** A `valueChangeAction` or `openChangeAction` dispatched through this Combobox is in flight. */\n readonly pending: boolean;\n readonly disabled: boolean;\n}\n\nexport interface ComboboxRootProps {\n /** Controlled selection. `null`: nothing selected. `undefined`: uncontrolled. */\n value?: string | null;\n /** Initial selection in uncontrolled mode. Default `null`. */\n defaultValue?: string | null;\n /**\n * Runs inside the Root's transition when the user accepts an option, commits free text\n * (`allowCustomValue`), presses Clear, or the form resets. Awaited; the listbox closes in the\n * commit that ends it; a rejection rolls the input text and `data-selected` back and leaves\n * the listbox open. May be a Server Function. A `setState` after your own `await` needs\n * `startTransition`.\n */\n valueChangeAction?: ChangeAction<string | null, ComboboxValueChangeDetails>;\n\n /** Controlled input text. `undefined`: uncontrolled. */\n inputValue?: string;\n /**\n * Initial input text. Default `\"\"`. Pass the selected value's label when `defaultValue` is\n * set: the library never derives the text from the value.\n */\n defaultInputValue?: string;\n /**\n * The urgent lane: called synchronously, outside any Transition, on every change of the text\n * (typing, and the library's own writes: an accepted option's label, a revert, Clear, a form\n * reset, text typed before hydration). Not awaited; nothing is pending for it. A controlled\n * parent updates its state in the body (an urgent update, which is what a controlled text\n * input needs).\n */\n inputValueChangeAction?: UrgentChangeAction<string, ComboboxInputValueChangeDetails>;\n\n /** Controlled open state. `undefined`: uncontrolled. */\n open?: boolean;\n /** Initial open state when uncontrolled. Opens after hydration. */\n defaultOpen?: boolean;\n /**\n * Awaited for opens and for the close after an accepted option (or the Trigger); a\n * notification for dismissals (Escape, a click outside, focus leaving).\n */\n openChangeAction?: ChangeAction<boolean, ComboboxOpenChangeDetails>;\n\n /**\n * Free text is a value: Enter with no active option, or focus leaving with text that is not\n * the selected option's label, dispatches the text with `details.custom: true` (empty text\n * dispatches `null`). Default `false`: unmatched text reverts to the selection's label when\n * focus leaves.\n */\n allowCustomValue?: boolean;\n /**\n * Make the first enabled option active when the results for an open or an edit settle (APG\n * \"automatic selection\"). Stale results are never highlighted. Default `false`.\n */\n autoHighlight?: boolean;\n /** Open the listbox on a pointer click in the input (not on focus). Default `false`. */\n openOnClick?: boolean;\n /** Wrap from the last option to the first and back with the arrow keys. Default `false`. */\n loop?: boolean;\n /**\n * The message `ariaNotify()` announces on the List when the results settle, from the number\n * of mounted options. Default (English): `\"No results\"`, `\"1 result\"`, `\"N results\"`. Override\n * for localisation or a richer message; return `null` to announce nothing. Ignored where\n * `ariaNotify` is missing.\n */\n announce?: (count: number, state: ComboboxRootState) => string | null;\n\n /** Form participation through a hidden input with this name (value `\"\"` for `null`). */\n name?: string;\n /** The `form` attribute of the hidden input. */\n form?: string;\n /** Disables the Input, Trigger and Clear; nothing dispatches for user interaction. */\n disabled?: boolean;\n children?: StateValue<ReactNode, ComboboxRootState>;\n}\n\n/** The default announcement (design 6.4; conventions 11: English, always overridable). */\nexport function defaultComboboxAnnouncement(count: number): string {\n if (count === 0) return \"No results\";\n if (count === 1) return \"1 result\";\n return `${count} results`;\n}\n\nconst VALUE_TRANSITION_TYPES = [\"fsui-combobox\", \"fsui-combobox-select\"] as const;\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nfunction isPopoverOpen(element: Element | null): boolean {\n if (element === null) return false;\n try {\n return element.matches(\":popover-open\");\n } catch {\n return false;\n }\n}\n\nfunction isThenable(value: unknown): boolean {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\n/** What a value dispatch carries for the Root's own follow-up (by `details` identity). */\ninterface DispatchMeta {\n readonly id: number;\n /** The open this dispatch belongs to (Popover 3.4): a newer open drops the close. */\n readonly generation: number;\n /** Close the listbox once the action settled (an accepted option, Enter on free text). */\n readonly close: boolean;\n /** The text the library wrote with the dispatch: typing since then keeps the listbox open. */\n readonly text: string | undefined;\n}\n\n/** The text the library wrote for a user dispatch, reverted if the value does not land. */\ninterface TextRecord {\n readonly id: number;\n readonly value: string | null;\n readonly text: string;\n settled: boolean;\n}\n\ninterface OrderedOption extends ComboboxOptionEntry {\n readonly value: string;\n}\n\n/**\n * Owns the two states of a combobox (design/components/combobox.md 2): the selection (`value`,\n * a transition with `useOptimistic`, like every other value) and the text (`inputValue`, the\n * library's **urgent** lane: `inputValueChangeAction` is called synchronously, outside any\n * transition). The results render from `useDeferredValue(inputValue)`; the active option is\n * urgent virtual focus (`aria-activedescendant`); the listbox is a `popover=\"auto\"` opened by the\n * library with the input as `source`. Renders no DOM, except one `<input type=\"hidden\">` when\n * `name` is given.\n */\nexport function ComboboxRoot(props: ComboboxRootProps) {\n const {\n value,\n defaultValue,\n valueChangeAction,\n inputValue: inputValueProp,\n defaultInputValue,\n open,\n defaultOpen,\n openChangeAction,\n allowCustomValue = false,\n autoHighlight = false,\n openOnClick = false,\n loop = false,\n name,\n form,\n disabled = false,\n children,\n } = props;\n\n const id = useId();\n const ids = useMemo(\n () => ({\n input: `${id}-input`,\n label: `${id}-label`,\n list: `${id}-list`,\n optionPrefix: `${id}-option-`,\n }),\n [id],\n );\n\n const popover = usePopoverRoot<ComboboxOpenChangeDetails>({\n component: \"combobox\",\n part: \"Combobox.Root\",\n mode: \"library\",\n open,\n defaultOpen,\n openChangeAction,\n });\n\n // --- Refs the handlers read after an `await` or from a timer ------------------------------\n\n const propsRef = useRef(props);\n const popoverRef = useRef(popover);\n useInsertionEffect(() => {\n propsRef.current = props;\n popoverRef.current = popover;\n });\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n const listRef = useRef<HTMLElement | null>(null);\n const hiddenRef = useRef<HTMLInputElement | null>(null);\n\n // --- Text: the urgent lane (design 4) ------------------------------------------------------\n\n const [internalText, setInternalText] = useState(() => defaultInputValue ?? inputValueProp ?? \"\");\n const text = inputValueProp ?? internalText;\n const query = useDeferredValue(text);\n const stale = text !== query;\n const textRef = useRef(text);\n useInsertionEffect(() => {\n textRef.current = text;\n });\n\n const warnedThenable = useRef(false);\n /** Writes the text (urgent) and calls `inputValueChangeAction` synchronously (design 2.2). */\n const writeText = useCallback(\n (next: string, reason: ChangeReason, event: Event | undefined): void => {\n const latest = propsRef.current;\n if (latest.inputValue === undefined) setInternalText(next);\n textRef.current = next;\n const action = latest.inputValueChangeAction;\n if (action === undefined) return;\n const result: unknown = action(next, createActionDetails(event, { reason }));\n if (isDev && !warnedThenable.current && isThenable(result)) {\n warnedThenable.current = true;\n console.error(\n \"Combobox.Root: `inputValueChangeAction` returned a promise. It is the urgent lane: \" +\n \"called synchronously and never awaited. Put async work in `valueChangeAction`, or \" +\n \"derive the results from the deferred `query`.\",\n );\n }\n },\n [],\n );\n\n // --- Labels (design 2.3) -------------------------------------------------------------------\n\n const [labels] = useState(() => {\n const map = new Map<string, string>();\n const initialValue = value !== undefined ? value : (defaultValue ?? null);\n if (initialValue !== null) map.set(initialValue, defaultInputValue ?? inputValueProp ?? \"\");\n return map;\n });\n const labelFor = useCallback(\n (v: string | null): string => (v === null ? \"\" : (labels.get(v) ?? \"\")),\n [labels],\n );\n\n // --- Selection: a transition (design 3.1, 5.2) --------------------------------------------\n\n const dispatchSeq = useRef(0);\n const [dispatchMeta] = useState(() => new WeakMap<object, DispatchMeta>());\n const textRecord = useRef<TextRecord | null>(null);\n const committedRef = useRef<string | null>(null);\n\n const runValueAction = async (\n next: string | null,\n details: ComboboxValueChangeDetails,\n ): Promise<void> => {\n const meta = dispatchMeta.get(details);\n try {\n await valueChangeAction?.(next, details);\n } catch (error) {\n // Walkthrough 4: the text rolls back with the optimistic value. A synchronous throw lands\n // here inside the Root's `startTransition` callback; yield once so the write (and the\n // consumer's `inputValueChangeAction`) is urgent, as every text write (conventions 2.6).\n await undefined;\n const record = textRecord.current;\n if (meta !== undefined && record !== null && record.id === meta.id) {\n textRecord.current = null;\n if (textRef.current === record.text) {\n writeText(labelFor(committedRef.current), \"dismiss\", undefined);\n }\n }\n throw error;\n }\n const record = textRecord.current;\n if (meta !== undefined && record !== null && record.id === meta.id) record.settled = true;\n // Menu decision 3: close in the commit that ends the action, unless a newer dispatch took\n // over, the user dismissed and re-opened meanwhile, or the user is typing a new search.\n const current = popoverRef.current;\n if (\n meta !== undefined &&\n meta.close &&\n meta.id === dispatchSeq.current &&\n current.openGeneration() === meta.generation &&\n (meta.text === undefined || textRef.current === meta.text)\n ) {\n current.requestClose(details.event, \"activate\");\n }\n };\n\n const selection = useControllableAction<string | null, ComboboxValueChangeDetails>({\n controlled: value,\n defaultValue,\n initialValue: null,\n action: runValueAction,\n transitionTypes: () => VALUE_TRANSITION_TYPES,\n warn: { component: \"Combobox.Root\", prop: \"value\" },\n });\n useInsertionEffect(() => {\n committedRef.current = selection.committed;\n });\n\n const dispatchValue = (\n next: string | null,\n event: Event | undefined,\n fields: { reason: ChangeReason; custom: boolean },\n options: { close: boolean; text: string | undefined },\n ): void => {\n const details = createActionDetails(event, fields);\n const dispatchId = ++dispatchSeq.current;\n dispatchMeta.set(details, {\n id: dispatchId,\n generation: popover.openGeneration(),\n close: options.close,\n text: options.text,\n });\n textRecord.current =\n options.text === undefined\n ? null\n : { id: dispatchId, value: next, text: options.text, settled: false };\n selection.dispatch(next, details);\n };\n\n // --- Option registry and the active option (design 2, 6.5) --------------------------------\n\n const [registry] = useState(() => new Map<string, ComboboxOptionEntry>());\n const [optionCount, setOptionCount] = useState(0);\n const [statusCount, setStatusCount] = useState(0);\n // The same count for the announcement effect: the open commit's passive effects can run before\n // the re-render the Status's registration scheduled (the race `registry` avoids for options).\n const statusCountRef = useRef(0);\n const [labelCount, setLabelCount] = useState(0);\n const warnedDuplicate = useRef(false);\n\n const registerOption = useCallback(\n (optionValue: string, entry: ComboboxOptionEntry) => {\n const existing = registry.get(optionValue);\n if (\n isDev &&\n !warnedDuplicate.current &&\n existing !== undefined &&\n existing.element !== entry.element &&\n existing.element.isConnected\n ) {\n warnedDuplicate.current = true;\n console.error(\n `Combobox.Option: two options have the value ${JSON.stringify(optionValue)}. ` +\n \"Option ids are derived from the value, so they must be unique within one Combobox.\",\n );\n }\n registry.set(optionValue, entry);\n labels.set(optionValue, entry.label ?? (entry.element.textContent ?? \"\").trim());\n setOptionCount(registry.size);\n return () => {\n if (registry.get(optionValue) === entry) registry.delete(optionValue);\n setOptionCount(registry.size);\n };\n },\n [registry, labels],\n );\n\n const registerStatus = useCallback(() => {\n statusCountRef.current += 1;\n setStatusCount((count) => count + 1);\n return () => {\n statusCountRef.current -= 1;\n setStatusCount((count) => count - 1);\n };\n }, []);\n\n const registerLabel = useCallback(() => {\n setLabelCount((count) => count + 1);\n return () => setLabelCount((count) => count - 1);\n }, []);\n\n const [activeValue, setActiveValue] = useState<string | null>(null);\n const activeRef = useRef<string | null>(null);\n const setActive = useCallback((next: string | null) => {\n activeRef.current = next;\n setActiveValue(next);\n }, []);\n // The edge to activate once the open has options (ArrowDown / ArrowUp while closed).\n const pendingEdge = useRef<\"first\" | \"last\" | null>(null);\n // `autoHighlight` (APG automatic selection) highlights once per open and once per edit, when\n // the results for it settle. Home / End / Left / Right clear the active option without\n // re-arming it, so the caret keys really return visual focus to the input.\n const autoArmed = useRef(true);\n\n const orderedOptions = useCallback((): OrderedOption[] => {\n const options: OrderedOption[] = [];\n for (const [optionValue, entry] of registry) options.push({ value: optionValue, ...entry });\n options.sort((a, b) =>\n a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1,\n );\n return options;\n }, [registry]);\n\n // A Status inside the List is a Suspense fallback: the results are loading (design 6.3).\n const loading = statusCount > 0;\n const empty = optionCount === 0 && !stale && !loading;\n\n // Revalidation (design 6.5): urgent, in a layout effect after every commit; never dispatches.\n useLayoutEffect(() => {\n const current = activeRef.current;\n if (!popover.committed) {\n // Keep the edge of an open that is on its way (the optimistic commit comes first).\n if (!popover.intended()) pendingEdge.current = null;\n autoArmed.current = true;\n if (current !== null) setActive(null);\n return;\n }\n const enabled = orderedOptions().filter((option) => !option.disabled);\n let next = current;\n if (pendingEdge.current !== null && enabled.length > 0) {\n next = (pendingEdge.current === \"first\" ? enabled[0] : enabled.at(-1))!.value;\n pendingEdge.current = null;\n } else if (next !== null && !enabled.some((option) => option.value === next)) {\n next = null;\n }\n if (next !== null) {\n // Something is active (keys, hover): nothing to highlight for these results.\n autoArmed.current = false;\n } else if (autoHighlight && autoArmed.current && !stale && enabled.length > 0) {\n // Only settled results: a stale list's first option is never auto-highlighted, so a fast\n // Enter commits the typed text or does nothing (design L5).\n next = enabled[0]!.value;\n autoArmed.current = false;\n }\n if (next !== current) setActive(next);\n });\n\n // The selection did not land (a controlled parent refused it, or the caught-inside variant of\n // a controlled parent): the text goes back to the committed value's label (design 2.2).\n // Labels for values set from outside are learnt from the text the consumer passed with them.\n const prevCommitted = useRef(selection.committed);\n useLayoutEffect(() => {\n const record = textRecord.current;\n if (\n record !== null &&\n record.settled &&\n !selection.pending &&\n selection.latestInFlight() === null\n ) {\n textRecord.current = null;\n if (selection.committed !== record.value && textRef.current === record.text) {\n writeText(labelFor(selection.committed), \"dismiss\", undefined);\n }\n }\n if (prevCommitted.current !== selection.committed) {\n prevCommitted.current = selection.committed;\n const committed = selection.committed;\n if (committed !== null && textRecord.current === null && !labels.has(committed)) {\n labels.set(committed, textRef.current);\n }\n }\n });\n\n // --- Announcements (design 6.4) -----------------------------------------------------------\n\n const state: ComboboxRootState = {\n value: selection.optimistic,\n inputValue: text,\n query,\n stale,\n activeValue,\n open: popover.optimistic,\n pending: selection.pending || popover.pending,\n disabled,\n };\n\n const lastAnnounced = useRef<string | null>(null);\n useEffect(() => {\n if (!popover.committed) {\n lastAnnounced.current = null;\n return;\n }\n if (stale || statusCountRef.current > 0) return;\n // The registry, not `optionCount`: a commit's passive effects can run before the re-render\n // that the Options' registration scheduled.\n const count = registry.size;\n const key = `${count}\\u0000${query}`;\n if (lastAnnounced.current === key) return;\n lastAnnounced.current = key;\n const list = listRef.current as (HTMLElement & { ariaNotify?: (m: string) => void }) | null;\n if (list === null || typeof list.ariaNotify !== \"function\") return;\n const announce = propsRef.current.announce ?? defaultComboboxAnnouncement;\n const message = announce(count, state);\n if (message !== null) list.ariaNotify(message);\n });\n\n // --- Form: hidden input, reset, mount reconciliation (design 11.1, walkthroughs 10, 11) ----\n\n const [mountValue] = useState(value);\n const [mountText] = useState(inputValueProp);\n // Reset targets (conventions 3.8 rule 6): uncontrolled, the latest default props; controlled,\n // the mount-time values.\n const valueResetTarget = value !== undefined ? (mountValue ?? null) : (defaultValue ?? null);\n const inputDefaultValue =\n inputValueProp !== undefined ? (mountText ?? \"\") : (defaultInputValue ?? \"\");\n // After a form reset a controlled parent may not adopt the text: put React's value back into\n // the DOM (react-dom only does that after its own input events).\n const [resync, setResync] = useState(0);\n useLayoutEffect(() => {\n const input = inputRef.current;\n if (resync > 0 && input !== null && input.value !== textRef.current) {\n input.value = textRef.current;\n }\n }, [resync]);\n\n const formElement = useMemo<RefObject<FormAssociatedElement | null>>(\n () => ({\n get current() {\n return hiddenRef.current ?? inputRef.current;\n },\n set current(_ignored) {},\n }),\n [],\n );\n useFormReset(\n formElement,\n (event) => {\n const input = inputRef.current;\n const domText = input?.value ?? inputDefaultValue;\n if (domText !== textRef.current) writeText(domText, \"platform\", event);\n // A controlled parent that does not adopt the text gets the DOM re-synced.\n setResync((n) => n + 1);\n if (valueResetTarget !== selection.optimistic) {\n dispatchValue(\n valueResetTarget,\n event,\n { reason: \"platform\", custom: false },\n { close: false, text: undefined },\n );\n }\n },\n () => {\n // react-dom writes `defaultValue = value` after every update of a controlled input, so the\n // reset target is written here, right before the browser's reset algorithm reads it.\n const input = inputRef.current;\n if (input !== null && input.defaultValue !== inputDefaultValue) {\n input.defaultValue = inputDefaultValue;\n }\n },\n );\n\n // Walkthrough 11: react-dom keeps a hydrated text input's DOM value and fires no `onChange`.\n const reconciled = useRef(false);\n useLayoutEffect(() => {\n if (reconciled.current) return;\n reconciled.current = true;\n const input = inputRef.current;\n if (input !== null && input.value !== textRef.current) {\n writeText(input.value, \"platform\", undefined);\n }\n }, [writeText]);\n\n const [missingText] = useState(\n () =>\n (value ?? defaultValue ?? null) !== null &&\n inputValueProp === undefined &&\n defaultInputValue === undefined,\n );\n useDevWarning(\n missingText,\n \"Combobox.Root: `value` / `defaultValue` is set but neither `inputValue` nor \" +\n \"`defaultInputValue` is: the input will show no text for the selection. The library never \" +\n \"derives the text from the value; pass the selected option's label as well.\",\n );\n\n // --- Interaction (design 5, 8) -------------------------------------------------------------\n\n const accept = (optionValue: string, event: Event): void => {\n if (disabled) return;\n const entry = registry.get(optionValue);\n if (entry === undefined || entry.disabled) return;\n const label = entry.label ?? (entry.element.textContent ?? \"\").trim();\n labels.set(optionValue, label);\n pendingEdge.current = null;\n if (activeRef.current !== optionValue) setActive(optionValue);\n writeText(label, \"activate\", event);\n // Re-accepting the selected option dispatches nothing and closes (conventions 2.3 item 8).\n if (optionValue === selection.optimistic) {\n popover.requestClose(event, \"activate\");\n return;\n }\n dispatchValue(\n optionValue,\n event,\n { reason: \"activate\", custom: false },\n { close: true, text: label },\n );\n };\n\n /** Free text as the value (design 5.3). Returns whether it dispatched. */\n const commitText = (event: Event, close: boolean): boolean => {\n const current = selection.optimistic;\n const typed = textRef.current;\n if (typed === labelFor(current)) return false;\n const next = typed === \"\" ? null : typed;\n if (next === current) return false;\n if (next !== null) labels.set(next, typed);\n dispatchValue(\n next,\n event,\n { reason: \"activate\", custom: next !== null },\n { close, text: typed },\n );\n return true;\n };\n\n const clear = (event: Event): void => {\n if (disabled) return;\n if (textRef.current !== \"\") writeText(\"\", \"activate\", event);\n if (selection.optimistic !== null) {\n dispatchValue(null, event, { reason: \"activate\", custom: false }, { close: false, text: \"\" });\n }\n inputRef.current?.focus();\n };\n\n const typed = (next: string, event: Event): void => {\n if (disabled) return;\n writeText(next, \"activate\", event);\n pendingEdge.current = null;\n // APG: editing moves visual focus back to the input; `autoHighlight` picks the first option\n // again once the results for the new text settle.\n if (activeRef.current !== null) setActive(null);\n autoArmed.current = true;\n popover.requestOpen(event, \"activate\");\n };\n\n const move = (direction: 1 | -1): void => {\n const enabled = orderedOptions().filter((option) => !option.disabled);\n if (enabled.length === 0) return;\n const last = enabled.length - 1;\n const index = enabled.findIndex((option) => option.value === activeRef.current);\n let next: number;\n if (direction === 1) next = index < 0 ? 0 : index >= last ? (loop ? 0 : last) : index + 1;\n else next = index < 0 ? last : index <= 0 ? (loop ? last : 0) : index - 1;\n const target = enabled[next]!;\n setActive(target.value);\n if (typeof target.element.scrollIntoView === \"function\") {\n target.element.scrollIntoView({ block: \"nearest\" });\n }\n };\n\n const activeEnabled = (): string | null => {\n const current = activeRef.current;\n if (current === null) return null;\n const entry = registry.get(current);\n return entry !== undefined && !entry.disabled ? current : null;\n };\n\n const keyDown = (event: KeyboardEvent): boolean => {\n if (disabled || event.ctrlKey || event.metaKey) return false;\n // IME: the key belongs to the composition (Enter commits it, arrows pick a candidate).\n if (event.isComposing || event.keyCode === 229) return false;\n // What the user sees, not what is intended: right after Escape the platform has hidden the\n // popup but its `toggle` (and the library's notification) is still queued, and an open that\n // is still committing shows nothing yet. Enter must submit and arrows must open in both.\n const isOpen = isPopoverOpen(popover.popupRef.current);\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n if (event.altKey) {\n if (!isOpen) popover.requestOpen(event, \"activate\");\n } else if (!isOpen) {\n pendingEdge.current = \"first\";\n popover.requestOpen(event, \"activate\");\n } else {\n move(1);\n }\n return true;\n case \"ArrowUp\":\n event.preventDefault();\n if (event.altKey) {\n if (isOpen) {\n const active = activeEnabled();\n if (active !== null) accept(active, event);\n else popover.requestClose(event, \"activate\");\n }\n } else if (!isOpen) {\n pendingEdge.current = \"last\";\n popover.requestOpen(event, \"activate\");\n } else {\n move(-1);\n }\n return true;\n case \"Enter\": {\n if (isOpen) {\n // An open listbox means the user is choosing: never submit from here.\n event.preventDefault();\n const active = activeEnabled();\n if (active !== null) accept(active, event);\n else if (allowCustomValue && !commitText(event, true)) {\n popover.requestClose(event, \"activate\");\n }\n return true;\n }\n // Closed: not prevented, so a form still submits. The key's default action (implicit\n // submission) must see the optimistic hidden value: Firefox submits before React's\n // scheduled flush of the optimistic render, so it is flushed here (design 5.3).\n if (allowCustomValue) flushSync(() => commitText(event, false));\n return false;\n }\n case \"Home\":\n case \"End\":\n case \"ArrowLeft\":\n case \"ArrowRight\":\n // APG: the caret keys move visual focus to the input (not prevented: the caret moves).\n if (activeRef.current !== null) setActive(null);\n return false;\n default:\n return false;\n }\n };\n\n /** Focus has left the input and the popup (design 5.4). */\n const leave = (event: Event): void => {\n // `disabled`: nothing dispatches (disabling a focused input blurs it).\n if (disabled) return;\n const popup = popover.popupRef.current;\n if (popup !== null && isPopoverOpen(popup)) {\n popover.recordCloseIntent({ reason: \"dismiss\", event });\n popup.hidePopover();\n }\n pendingEdge.current = null;\n if (allowCustomValue) {\n commitText(event, false);\n return;\n }\n const label = labelFor(selection.optimistic);\n if (textRef.current !== label) writeText(label, \"dismiss\", event);\n };\n const leaveRef = useRef(leave);\n useInsertionEffect(() => {\n leaveRef.current = leave;\n });\n\n const focusOut = (event: FocusEvent): void => {\n const input = inputRef.current;\n const popup = popover.popupRef.current;\n const next = event.relatedTarget;\n if (next instanceof Node) {\n if (next === input || (popup !== null && popup.contains(next))) return;\n leave(event);\n return;\n }\n // No related target: the window lost focus (nothing to do), or a click landed on something\n // that takes no focus (the page itself: focus moved to <body>). Decide after the click.\n if (input === null) return;\n const doc = input.ownerDocument;\n setTimeout(() => {\n if (!doc.hasFocus()) return;\n const active = doc.activeElement;\n if (active === input || (active !== null && popup !== null && popup.contains(active))) {\n return;\n }\n if (input.isConnected) leaveRef.current(event);\n }, 0);\n };\n\n const inputClick = (event: MouseEvent): void => {\n if (disabled || !openOnClick) return;\n popover.requestOpen(event, \"activate\");\n };\n\n const context: ComboboxContextValue = {\n popover,\n ids,\n value: selection.optimistic,\n valuePending: selection.pending,\n pending: state.pending,\n inputValue: text,\n query,\n stale,\n activeValue,\n empty,\n loading,\n hasLabel: labelCount > 0,\n disabled,\n inputRef,\n listRef,\n registerOption,\n registerStatus,\n registerLabel,\n setActive,\n accept,\n clear,\n typed,\n keyDown,\n focusOut,\n inputClick,\n };\n\n return (\n <ComboboxContext value={context}>\n {name !== undefined && (\n <input\n ref={hiddenRef}\n type=\"hidden\"\n name={name}\n form={form}\n value={selection.optimistic ?? \"\"}\n />\n )}\n {resolveStateValue(children, state)}\n </ComboboxContext>\n );\n}\n\nComboboxRoot.displayName = \"ComboboxRoot\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"combobox-root.mjs","names":[],"sources":["../../src/combobox/combobox-root.tsx"],"sourcesContent":["\"use client\";\nimport {\n use,\n useCallback,\n useDeferredValue,\n useEffect,\n useId,\n useInsertionEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { flushSync } from \"react-dom\";\nimport type { ReactNode, RefObject } from \"react\";\nimport { createActionDetails } from \"../internal/action-details.js\";\nimport { FieldContext } from \"../internal/field-context.js\";\nimport { useFieldValueChange } from \"../internal/use-field-control.js\";\nimport type {\n ActionDetails,\n ChangeAction,\n ChangeReason,\n StateValue,\n UrgentChangeAction,\n} from \"../internal/types.js\";\nimport { useControllableAction } from \"../internal/use-controllable-action.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport { useFormReset } from \"../internal/use-form-reset.js\";\nimport type { FormAssociatedElement } from \"../internal/use-form-reset.js\";\nimport { usePopoverRoot } from \"../internal/use-popover-root.js\";\nimport { resolveStateValue } from \"../internal/use-render.js\";\nimport { ComboboxContext } from \"./combobox-context.js\";\nimport type { ComboboxContextValue, ComboboxOptionEntry } from \"./combobox-context.js\";\n\n/** Details passed as the second argument of `Combobox.Root`'s `valueChangeAction`. */\nexport interface ComboboxValueChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: the user accepted an option (Enter, click; `details.event` is the `keydown` or\n * `click`), committed free text with `allowCustomValue` (Enter: the `keydown`; focus leaving:\n * the `focusout`), or pressed Clear (`click`).\n * `\"platform\"`: a form reset (`details.event` is the `reset` event).\n */\n readonly reason: ChangeReason;\n /** `true` when `next` is free text committed under `allowCustomValue`, not an option's value. */\n readonly custom: boolean;\n}\n\n/** Details passed as the second argument of `Combobox.Root`'s `inputValueChangeAction`. */\nexport interface ComboboxInputValueChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: typing (the `input` event), an accepted option's label, Clear.\n * `\"dismiss\"`: a revert: focus left with unmatched text, or the selection rolled back.\n * `\"platform\"`: form reset (the `reset` event), or text found in the input at mount\n * (`undefined`).\n */\n readonly reason: ChangeReason;\n}\n\n/** Details passed as the second argument of `Combobox.Root`'s `openChangeAction`. */\nexport interface ComboboxOpenChangeDetails extends ActionDetails {\n /**\n * `\"activate\"`: typing, ArrowDown / ArrowUp / Alt+ArrowDown, the Trigger, a click on the input\n * with `openOnClick`, an accepted option (the close after it), a foreign `showPopover()`.\n * `\"dismiss\"`: Escape, light dismiss, focus leaving the combobox, another top-layer element.\n * `\"platform\"`: the popup was found open on mount (only script can cause it).\n */\n readonly reason: ChangeReason;\n}\n\nexport interface ComboboxRootState {\n /** Optimistic selection. Content rendered from it must not suspend. */\n readonly value: string | null;\n /** The text in the input (urgent). */\n readonly inputValue: string;\n /** The deferred text the mounted results are for. */\n readonly query: string;\n /** `inputValue !== query`: the results shown are for an older text. */\n readonly stale: boolean;\n /** The value of the option `aria-activedescendant` points at, or `null`. */\n readonly activeValue: string | null;\n /** Optimistic open state. */\n readonly open: boolean;\n /** A `valueChangeAction` or `openChangeAction` dispatched through this Combobox is in flight. */\n readonly pending: boolean;\n readonly disabled: boolean;\n}\n\nexport interface ComboboxRootProps {\n /** Controlled selection. `null`: nothing selected. `undefined`: uncontrolled. */\n value?: string | null;\n /** Initial selection in uncontrolled mode. Default `null`. */\n defaultValue?: string | null;\n /**\n * Runs inside the Root's transition when the user accepts an option, commits free text\n * (`allowCustomValue`), presses Clear, or the form resets. Awaited; the listbox closes in the\n * commit that ends it; a rejection rolls the input text and `data-selected` back and leaves\n * the listbox open. May be a Server Function. A `setState` after your own `await` needs\n * `startTransition`.\n */\n valueChangeAction?: ChangeAction<string | null, ComboboxValueChangeDetails>;\n\n /** Controlled input text. `undefined`: uncontrolled. */\n inputValue?: string;\n /**\n * Initial input text. Default `\"\"`. Pass the selected value's label when `defaultValue` is\n * set: the library never derives the text from the value.\n */\n defaultInputValue?: string;\n /**\n * The urgent lane: called synchronously, outside any Transition, on every change of the text\n * (typing, and the library's own writes: an accepted option's label, a revert, Clear, a form\n * reset, text typed before hydration). Not awaited; nothing is pending for it. A controlled\n * parent updates its state in the body (an urgent update, which is what a controlled text\n * input needs).\n */\n inputValueChangeAction?: UrgentChangeAction<string, ComboboxInputValueChangeDetails>;\n\n /** Controlled open state. `undefined`: uncontrolled. */\n open?: boolean;\n /** Initial open state when uncontrolled. Opens after hydration. */\n defaultOpen?: boolean;\n /**\n * Awaited for opens and for the close after an accepted option (or the Trigger); a\n * notification for dismissals (Escape, a click outside, focus leaving).\n */\n openChangeAction?: ChangeAction<boolean, ComboboxOpenChangeDetails>;\n\n /**\n * Free text is a value: Enter with no active option, or focus leaving with text that is not\n * the selected option's label, dispatches the text with `details.custom: true` (empty text\n * dispatches `null`). Default `false`: unmatched text reverts to the selection's label when\n * focus leaves.\n */\n allowCustomValue?: boolean;\n /**\n * Make the first enabled option active when the results for an open or an edit settle (APG\n * \"automatic selection\"). Stale results are never highlighted. Default `false`.\n */\n autoHighlight?: boolean;\n /** Open the listbox on a pointer click in the input (not on focus). Default `false`. */\n openOnClick?: boolean;\n /** Wrap from the last option to the first and back with the arrow keys. Default `false`. */\n loop?: boolean;\n /**\n * The message `ariaNotify()` announces on the List when the results settle, from the number\n * of mounted options. Default (English): `\"No results\"`, `\"1 result\"`, `\"N results\"`. Override\n * for localisation or a richer message; return `null` to announce nothing. Ignored where\n * `ariaNotify` is missing.\n */\n announce?: (count: number, state: ComboboxRootState) => string | null;\n\n /** Form participation through a hidden input with this name (value `\"\"` for `null`). */\n name?: string;\n /** The `form` attribute of the hidden input. */\n form?: string;\n /** Disables the Input, Trigger and Clear; nothing dispatches for user interaction. */\n disabled?: boolean;\n children?: StateValue<ReactNode, ComboboxRootState>;\n}\n\n/** The default announcement (design 6.4; conventions 11: English, always overridable). */\nexport function defaultComboboxAnnouncement(count: number): string {\n if (count === 0) return \"No results\";\n if (count === 1) return \"1 result\";\n return `${count} results`;\n}\n\nconst VALUE_TRANSITION_TYPES = [\"fsui-combobox\", \"fsui-combobox-select\"] as const;\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nfunction isPopoverOpen(element: Element | null): boolean {\n if (element === null) return false;\n try {\n return element.matches(\":popover-open\");\n } catch {\n return false;\n }\n}\n\nfunction isThenable(value: unknown): boolean {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\n/** What a value dispatch carries for the Root's own follow-up (by `details` identity). */\ninterface DispatchMeta {\n readonly id: number;\n /** The open this dispatch belongs to (Popover 3.4): a newer open drops the close. */\n readonly generation: number;\n /** Close the listbox once the action settled (an accepted option, Enter on free text). */\n readonly close: boolean;\n /** The text the library wrote with the dispatch: typing since then keeps the listbox open. */\n readonly text: string | undefined;\n}\n\n/** The text the library wrote for a user dispatch, reverted if the value does not land. */\ninterface TextRecord {\n readonly id: number;\n readonly value: string | null;\n readonly text: string;\n settled: boolean;\n}\n\ninterface OrderedOption extends ComboboxOptionEntry {\n readonly value: string;\n}\n\n/**\n * Owns the two states of a combobox (design/components/combobox.md 2): the selection (`value`,\n * a transition with `useOptimistic`, like every other value) and the text (`inputValue`, the\n * library's **urgent** lane: `inputValueChangeAction` is called synchronously, outside any\n * transition). The results render from `useDeferredValue(inputValue)`; the active option is\n * urgent virtual focus (`aria-activedescendant`); the listbox is a `popover=\"auto\"` opened by the\n * library with the input as `source`. Renders no DOM, except one `<input type=\"hidden\">` when\n * `name` is given.\n */\nexport function ComboboxRoot(props: ComboboxRootProps) {\n const {\n value,\n defaultValue,\n valueChangeAction,\n inputValue: inputValueProp,\n defaultInputValue,\n open,\n defaultOpen,\n openChangeAction,\n allowCustomValue = false,\n autoHighlight = false,\n openOnClick = false,\n loop = false,\n form,\n children,\n } = props;\n\n // Inside a Field.Root (design/components/field-form.md 7.2): the Input is the Field's control\n // (its id is the Field's, so `Field.Label` points at it), the hidden input's `name` and\n // `disabled` default from the Field, and the List is named by `Field.Label` when no\n // `Combobox.Label` is mounted.\n const field = use(FieldContext);\n const name = props.name ?? field?.name;\n const disabled = (props.disabled ?? false) || (field?.disabled ?? false);\n const fieldControlId = field?.ids.control;\n\n const id = useId();\n const ids = useMemo(\n () => ({\n input: fieldControlId ?? `${id}-input`,\n label: `${id}-label`,\n list: `${id}-list`,\n optionPrefix: `${id}-option-`,\n }),\n [id, fieldControlId],\n );\n\n const popover = usePopoverRoot<ComboboxOpenChangeDetails>({\n component: \"combobox\",\n part: \"Combobox.Root\",\n mode: \"library\",\n open,\n defaultOpen,\n openChangeAction,\n });\n\n // --- Refs the handlers read after an `await` or from a timer ------------------------------\n\n const propsRef = useRef(props);\n const popoverRef = useRef(popover);\n useInsertionEffect(() => {\n propsRef.current = props;\n popoverRef.current = popover;\n });\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n const listRef = useRef<HTMLElement | null>(null);\n const hiddenRef = useRef<HTMLInputElement | null>(null);\n\n // --- Text: the urgent lane (design 4) ------------------------------------------------------\n\n const [internalText, setInternalText] = useState(() => defaultInputValue ?? inputValueProp ?? \"\");\n const text = inputValueProp ?? internalText;\n const query = useDeferredValue(text);\n const stale = text !== query;\n const textRef = useRef(text);\n useInsertionEffect(() => {\n textRef.current = text;\n });\n\n const warnedThenable = useRef(false);\n /** Writes the text (urgent) and calls `inputValueChangeAction` synchronously (design 2.2). */\n const writeText = useCallback(\n (next: string, reason: ChangeReason, event: Event | undefined): void => {\n const latest = propsRef.current;\n if (latest.inputValue === undefined) setInternalText(next);\n textRef.current = next;\n const action = latest.inputValueChangeAction;\n if (action === undefined) return;\n const result: unknown = action(next, createActionDetails(event, { reason }));\n if (isDev && !warnedThenable.current && isThenable(result)) {\n warnedThenable.current = true;\n console.error(\n \"Combobox.Root: `inputValueChangeAction` returned a promise. It is the urgent lane: \" +\n \"called synchronously and never awaited. Put async work in `valueChangeAction`, or \" +\n \"derive the results from the deferred `query`.\",\n );\n }\n },\n [],\n );\n\n // --- Labels (design 2.3) -------------------------------------------------------------------\n\n const [labels] = useState(() => {\n const map = new Map<string, string>();\n const initialValue = value !== undefined ? value : (defaultValue ?? null);\n if (initialValue !== null) map.set(initialValue, defaultInputValue ?? inputValueProp ?? \"\");\n return map;\n });\n const labelFor = useCallback(\n (v: string | null): string => (v === null ? \"\" : (labels.get(v) ?? \"\")),\n [labels],\n );\n\n // --- Selection: a transition (design 3.1, 5.2) --------------------------------------------\n\n const dispatchSeq = useRef(0);\n const [dispatchMeta] = useState(() => new WeakMap<object, DispatchMeta>());\n const textRecord = useRef<TextRecord | null>(null);\n const committedRef = useRef<string | null>(null);\n\n const runValueAction = async (\n next: string | null,\n details: ComboboxValueChangeDetails,\n ): Promise<void> => {\n const meta = dispatchMeta.get(details);\n try {\n await valueChangeAction?.(next, details);\n } catch (error) {\n // Walkthrough 4: the text rolls back with the optimistic value. A synchronous throw lands\n // here inside the Root's `startTransition` callback; yield once so the write (and the\n // consumer's `inputValueChangeAction`) is urgent, as every text write (conventions 2.6).\n await undefined;\n const record = textRecord.current;\n if (meta !== undefined && record !== null && record.id === meta.id) {\n textRecord.current = null;\n if (textRef.current === record.text) {\n writeText(labelFor(committedRef.current), \"dismiss\", undefined);\n }\n }\n throw error;\n }\n const record = textRecord.current;\n if (meta !== undefined && record !== null && record.id === meta.id) record.settled = true;\n // Menu decision 3: close in the commit that ends the action, unless a newer dispatch took\n // over, the user dismissed and re-opened meanwhile, or the user is typing a new search.\n const current = popoverRef.current;\n if (\n meta !== undefined &&\n meta.close &&\n meta.id === dispatchSeq.current &&\n current.openGeneration() === meta.generation &&\n (meta.text === undefined || textRef.current === meta.text)\n ) {\n current.requestClose(details.event, \"activate\");\n }\n };\n\n const selection = useControllableAction<string | null, ComboboxValueChangeDetails>({\n controlled: value,\n defaultValue,\n initialValue: null,\n action: runValueAction,\n transitionTypes: () => VALUE_TRANSITION_TYPES,\n warn: { component: \"Combobox.Root\", prop: \"value\" },\n });\n useInsertionEffect(() => {\n committedRef.current = selection.committed;\n });\n\n /** The next change of the optimistic selection comes from the user (a dispatch). */\n const userEdit = useRef(false);\n const dispatchValue = (\n next: string | null,\n event: Event | undefined,\n fields: { reason: ChangeReason; custom: boolean },\n options: { close: boolean; text: string | undefined },\n ): void => {\n const details = createActionDetails(event, fields);\n const dispatchId = ++dispatchSeq.current;\n dispatchMeta.set(details, {\n id: dispatchId,\n generation: popover.openGeneration(),\n close: options.close,\n text: options.text,\n });\n textRecord.current =\n options.text === undefined\n ? null\n : { id: dispatchId, value: next, text: options.text, settled: false };\n if (next !== selection.optimistic) userEdit.current = true;\n selection.dispatch(next, details);\n };\n\n // Inside a Field: React writes the hidden input with no `input` / `change` event, so the Field\n // is told after the commit (its `validate` reads the hidden input; a user's pick dismisses a\n // shown server error like typing would).\n useFieldValueChange(selection.optimistic, () => {\n const edit = userEdit.current;\n userEdit.current = false;\n return edit;\n });\n\n // --- Option registry and the active option (design 2, 6.5) --------------------------------\n\n const [registry] = useState(() => new Map<string, ComboboxOptionEntry>());\n const [optionCount, setOptionCount] = useState(0);\n const [statusCount, setStatusCount] = useState(0);\n // The same count for the announcement effect: the open commit's passive effects can run before\n // the re-render the Status's registration scheduled (the race `registry` avoids for options).\n const statusCountRef = useRef(0);\n const [labelCount, setLabelCount] = useState(0);\n const warnedDuplicate = useRef(false);\n\n const registerOption = useCallback(\n (optionValue: string, entry: ComboboxOptionEntry) => {\n const existing = registry.get(optionValue);\n if (\n isDev &&\n !warnedDuplicate.current &&\n existing !== undefined &&\n existing.element !== entry.element &&\n existing.element.isConnected\n ) {\n warnedDuplicate.current = true;\n console.error(\n `Combobox.Option: two options have the value ${JSON.stringify(optionValue)}. ` +\n \"Option ids are derived from the value, so they must be unique within one Combobox.\",\n );\n }\n registry.set(optionValue, entry);\n labels.set(optionValue, entry.label ?? (entry.element.textContent ?? \"\").trim());\n setOptionCount(registry.size);\n return () => {\n if (registry.get(optionValue) === entry) registry.delete(optionValue);\n setOptionCount(registry.size);\n };\n },\n [registry, labels],\n );\n\n const registerStatus = useCallback(() => {\n statusCountRef.current += 1;\n setStatusCount((count) => count + 1);\n return () => {\n statusCountRef.current -= 1;\n setStatusCount((count) => count - 1);\n };\n }, []);\n\n const registerLabel = useCallback(() => {\n setLabelCount((count) => count + 1);\n return () => setLabelCount((count) => count - 1);\n }, []);\n\n const [activeValue, setActiveValue] = useState<string | null>(null);\n const activeRef = useRef<string | null>(null);\n const setActive = useCallback((next: string | null) => {\n activeRef.current = next;\n setActiveValue(next);\n }, []);\n // The edge to activate once the open has options (ArrowDown / ArrowUp while closed).\n const pendingEdge = useRef<\"first\" | \"last\" | null>(null);\n // `autoHighlight` (APG automatic selection) highlights once per open and once per edit, when\n // the results for it settle. Home / End / Left / Right clear the active option without\n // re-arming it, so the caret keys really return visual focus to the input.\n const autoArmed = useRef(true);\n\n const orderedOptions = useCallback((): OrderedOption[] => {\n const options: OrderedOption[] = [];\n for (const [optionValue, entry] of registry) options.push({ value: optionValue, ...entry });\n options.sort((a, b) =>\n a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1,\n );\n return options;\n }, [registry]);\n\n // A Status inside the List is a Suspense fallback: the results are loading (design 6.3).\n const loading = statusCount > 0;\n const empty = optionCount === 0 && !stale && !loading;\n\n // Revalidation (design 6.5): urgent, in a layout effect after every commit; never dispatches.\n useLayoutEffect(() => {\n const current = activeRef.current;\n if (!popover.committed) {\n // Keep the edge of an open that is on its way (the optimistic commit comes first).\n if (!popover.intended()) pendingEdge.current = null;\n autoArmed.current = true;\n if (current !== null) setActive(null);\n return;\n }\n const enabled = orderedOptions().filter((option) => !option.disabled);\n let next = current;\n if (pendingEdge.current !== null && enabled.length > 0) {\n next = (pendingEdge.current === \"first\" ? enabled[0] : enabled.at(-1))!.value;\n pendingEdge.current = null;\n } else if (next !== null && !enabled.some((option) => option.value === next)) {\n next = null;\n }\n if (next !== null) {\n // Something is active (keys, hover): nothing to highlight for these results.\n autoArmed.current = false;\n } else if (autoHighlight && autoArmed.current && !stale && enabled.length > 0) {\n // Only settled results: a stale list's first option is never auto-highlighted, so a fast\n // Enter commits the typed text or does nothing (design L5).\n next = enabled[0]!.value;\n autoArmed.current = false;\n }\n if (next !== current) setActive(next);\n });\n\n // The selection did not land (a controlled parent refused it, or the caught-inside variant of\n // a controlled parent): the text goes back to the committed value's label (design 2.2).\n // Labels for values set from outside are learnt from the text the consumer passed with them.\n const prevCommitted = useRef(selection.committed);\n useLayoutEffect(() => {\n const record = textRecord.current;\n if (\n record !== null &&\n record.settled &&\n !selection.pending &&\n selection.latestInFlight() === null\n ) {\n textRecord.current = null;\n if (selection.committed !== record.value && textRef.current === record.text) {\n writeText(labelFor(selection.committed), \"dismiss\", undefined);\n }\n }\n if (prevCommitted.current !== selection.committed) {\n prevCommitted.current = selection.committed;\n const committed = selection.committed;\n if (committed !== null && textRecord.current === null && !labels.has(committed)) {\n labels.set(committed, textRef.current);\n }\n }\n });\n\n // --- Announcements (design 6.4) -----------------------------------------------------------\n\n const state: ComboboxRootState = {\n value: selection.optimistic,\n inputValue: text,\n query,\n stale,\n activeValue,\n open: popover.optimistic,\n pending: selection.pending || popover.pending,\n disabled,\n };\n\n const lastAnnounced = useRef<string | null>(null);\n useEffect(() => {\n if (!popover.committed) {\n lastAnnounced.current = null;\n return;\n }\n if (stale || statusCountRef.current > 0) return;\n // The registry, not `optionCount`: a commit's passive effects can run before the re-render\n // that the Options' registration scheduled.\n const count = registry.size;\n const key = `${count}\\u0000${query}`;\n if (lastAnnounced.current === key) return;\n lastAnnounced.current = key;\n const list = listRef.current as (HTMLElement & { ariaNotify?: (m: string) => void }) | null;\n if (list === null || typeof list.ariaNotify !== \"function\") return;\n const announce = propsRef.current.announce ?? defaultComboboxAnnouncement;\n const message = announce(count, state);\n if (message !== null) list.ariaNotify(message);\n });\n\n // --- Form: hidden input, reset, mount reconciliation (design 11.1, walkthroughs 10, 11) ----\n\n const [mountValue] = useState(value);\n const [mountText] = useState(inputValueProp);\n // Reset targets (conventions 3.8 rule 6): uncontrolled, the latest default props; controlled,\n // the mount-time values.\n const valueResetTarget = value !== undefined ? (mountValue ?? null) : (defaultValue ?? null);\n const inputDefaultValue =\n inputValueProp !== undefined ? (mountText ?? \"\") : (defaultInputValue ?? \"\");\n // After a form reset a controlled parent may not adopt the text: put React's value back into\n // the DOM (react-dom only does that after its own input events).\n const [resync, setResync] = useState(0);\n useLayoutEffect(() => {\n const input = inputRef.current;\n if (resync > 0 && input !== null && input.value !== textRef.current) {\n input.value = textRef.current;\n }\n }, [resync]);\n\n const formElement = useMemo<RefObject<FormAssociatedElement | null>>(\n () => ({\n get current() {\n return hiddenRef.current ?? inputRef.current;\n },\n set current(_ignored) {},\n }),\n [],\n );\n useFormReset(\n formElement,\n (event) => {\n const input = inputRef.current;\n const domText = input?.value ?? inputDefaultValue;\n if (domText !== textRef.current) writeText(domText, \"platform\", event);\n // A controlled parent that does not adopt the text gets the DOM re-synced.\n setResync((n) => n + 1);\n if (valueResetTarget !== selection.optimistic) {\n dispatchValue(\n valueResetTarget,\n event,\n { reason: \"platform\", custom: false },\n { close: false, text: undefined },\n );\n }\n },\n () => {\n // react-dom writes `defaultValue = value` after every update of a controlled input, so the\n // reset target is written here, right before the browser's reset algorithm reads it.\n const input = inputRef.current;\n if (input !== null && input.defaultValue !== inputDefaultValue) {\n input.defaultValue = inputDefaultValue;\n }\n },\n );\n\n // Walkthrough 11: react-dom keeps a hydrated text input's DOM value and fires no `onChange`.\n const reconciled = useRef(false);\n useLayoutEffect(() => {\n if (reconciled.current) return;\n reconciled.current = true;\n const input = inputRef.current;\n if (input !== null && input.value !== textRef.current) {\n writeText(input.value, \"platform\", undefined);\n }\n }, [writeText]);\n\n const [missingText] = useState(\n () =>\n (value ?? defaultValue ?? null) !== null &&\n inputValueProp === undefined &&\n defaultInputValue === undefined,\n );\n useDevWarning(\n missingText,\n \"Combobox.Root: `value` / `defaultValue` is set but neither `inputValue` nor \" +\n \"`defaultInputValue` is: the input will show no text for the selection. The library never \" +\n \"derives the text from the value; pass the selected option's label as well.\",\n );\n\n // --- Interaction (design 5, 8) -------------------------------------------------------------\n\n const accept = (optionValue: string, event: Event): void => {\n if (disabled) return;\n const entry = registry.get(optionValue);\n if (entry === undefined || entry.disabled) return;\n const label = entry.label ?? (entry.element.textContent ?? \"\").trim();\n labels.set(optionValue, label);\n pendingEdge.current = null;\n if (activeRef.current !== optionValue) setActive(optionValue);\n writeText(label, \"activate\", event);\n // Re-accepting the selected option dispatches nothing and closes (conventions 2.3 item 8).\n if (optionValue === selection.optimistic) {\n popover.requestClose(event, \"activate\");\n return;\n }\n dispatchValue(\n optionValue,\n event,\n { reason: \"activate\", custom: false },\n { close: true, text: label },\n );\n };\n\n /** Free text as the value (design 5.3). Returns whether it dispatched. */\n const commitText = (event: Event, close: boolean): boolean => {\n const current = selection.optimistic;\n const typed = textRef.current;\n if (typed === labelFor(current)) return false;\n const next = typed === \"\" ? null : typed;\n if (next === current) return false;\n if (next !== null) labels.set(next, typed);\n dispatchValue(\n next,\n event,\n { reason: \"activate\", custom: next !== null },\n { close, text: typed },\n );\n return true;\n };\n\n const clear = (event: Event): void => {\n if (disabled) return;\n if (textRef.current !== \"\") writeText(\"\", \"activate\", event);\n if (selection.optimistic !== null) {\n dispatchValue(null, event, { reason: \"activate\", custom: false }, { close: false, text: \"\" });\n }\n inputRef.current?.focus();\n };\n\n const typed = (next: string, event: Event): void => {\n if (disabled) return;\n writeText(next, \"activate\", event);\n pendingEdge.current = null;\n // APG: editing moves visual focus back to the input; `autoHighlight` picks the first option\n // again once the results for the new text settle.\n if (activeRef.current !== null) setActive(null);\n autoArmed.current = true;\n popover.requestOpen(event, \"activate\");\n };\n\n const move = (direction: 1 | -1): void => {\n const enabled = orderedOptions().filter((option) => !option.disabled);\n if (enabled.length === 0) return;\n const last = enabled.length - 1;\n const index = enabled.findIndex((option) => option.value === activeRef.current);\n let next: number;\n if (direction === 1) next = index < 0 ? 0 : index >= last ? (loop ? 0 : last) : index + 1;\n else next = index < 0 ? last : index <= 0 ? (loop ? last : 0) : index - 1;\n const target = enabled[next]!;\n setActive(target.value);\n if (typeof target.element.scrollIntoView === \"function\") {\n target.element.scrollIntoView({ block: \"nearest\" });\n }\n };\n\n const activeEnabled = (): string | null => {\n const current = activeRef.current;\n if (current === null) return null;\n const entry = registry.get(current);\n return entry !== undefined && !entry.disabled ? current : null;\n };\n\n const keyDown = (event: KeyboardEvent): boolean => {\n if (disabled || event.ctrlKey || event.metaKey) return false;\n // IME: the key belongs to the composition (Enter commits it, arrows pick a candidate).\n if (event.isComposing || event.keyCode === 229) return false;\n // What the user sees, not what is intended: right after Escape the platform has hidden the\n // popup but its `toggle` (and the library's notification) is still queued, and an open that\n // is still committing shows nothing yet. Enter must submit and arrows must open in both.\n const isOpen = isPopoverOpen(popover.popupRef.current);\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n if (event.altKey) {\n if (!isOpen) popover.requestOpen(event, \"activate\");\n } else if (!isOpen) {\n pendingEdge.current = \"first\";\n popover.requestOpen(event, \"activate\");\n } else {\n move(1);\n }\n return true;\n case \"ArrowUp\":\n event.preventDefault();\n if (event.altKey) {\n if (isOpen) {\n const active = activeEnabled();\n if (active !== null) accept(active, event);\n else popover.requestClose(event, \"activate\");\n }\n } else if (!isOpen) {\n pendingEdge.current = \"last\";\n popover.requestOpen(event, \"activate\");\n } else {\n move(-1);\n }\n return true;\n case \"Enter\": {\n if (isOpen) {\n // An open listbox means the user is choosing: never submit from here.\n event.preventDefault();\n const active = activeEnabled();\n if (active !== null) accept(active, event);\n else if (allowCustomValue && !commitText(event, true)) {\n popover.requestClose(event, \"activate\");\n }\n return true;\n }\n // Closed: not prevented, so a form still submits. The key's default action (implicit\n // submission) must see the optimistic hidden value: Firefox submits before React's\n // scheduled flush of the optimistic render, so it is flushed here (design 5.3).\n if (allowCustomValue) flushSync(() => commitText(event, false));\n return false;\n }\n case \"Home\":\n case \"End\":\n case \"ArrowLeft\":\n case \"ArrowRight\":\n // APG: the caret keys move visual focus to the input (not prevented: the caret moves).\n if (activeRef.current !== null) setActive(null);\n return false;\n default:\n return false;\n }\n };\n\n /** Focus has left the input and the popup (design 5.4). */\n const leave = (event: Event): void => {\n // `disabled`: nothing dispatches (disabling a focused input blurs it).\n if (disabled) return;\n const popup = popover.popupRef.current;\n if (popup !== null && isPopoverOpen(popup)) {\n popover.recordCloseIntent({ reason: \"dismiss\", event });\n popup.hidePopover();\n }\n pendingEdge.current = null;\n if (allowCustomValue) {\n commitText(event, false);\n return;\n }\n const label = labelFor(selection.optimistic);\n if (textRef.current !== label) writeText(label, \"dismiss\", event);\n };\n const leaveRef = useRef(leave);\n useInsertionEffect(() => {\n leaveRef.current = leave;\n });\n\n const focusOut = (event: FocusEvent): void => {\n const input = inputRef.current;\n const popup = popover.popupRef.current;\n const next = event.relatedTarget;\n if (next instanceof Node) {\n if (next === input || (popup !== null && popup.contains(next))) return;\n leave(event);\n return;\n }\n // No related target: the window lost focus (nothing to do), or a click landed on something\n // that takes no focus (the page itself: focus moved to <body>). Decide after the click.\n if (input === null) return;\n const doc = input.ownerDocument;\n setTimeout(() => {\n if (!doc.hasFocus()) return;\n const active = doc.activeElement;\n if (active === input || (active !== null && popup !== null && popup.contains(active))) {\n return;\n }\n if (input.isConnected) leaveRef.current(event);\n }, 0);\n };\n\n const inputClick = (event: MouseEvent): void => {\n if (disabled || !openOnClick) return;\n popover.requestOpen(event, \"activate\");\n };\n\n const context: ComboboxContextValue = {\n popover,\n ids,\n value: selection.optimistic,\n valuePending: selection.pending,\n pending: state.pending,\n inputValue: text,\n query,\n stale,\n activeValue,\n empty,\n loading,\n hasLabel: labelCount > 0,\n fieldLabelId: field?.ids.label,\n disabled,\n inputRef,\n listRef,\n registerOption,\n registerStatus,\n registerLabel,\n setActive,\n accept,\n clear,\n typed,\n keyDown,\n focusOut,\n inputClick,\n };\n\n return (\n <ComboboxContext value={context}>\n {name !== undefined && (\n <input\n ref={hiddenRef}\n type=\"hidden\"\n name={name}\n form={form}\n value={selection.optimistic ?? \"\"}\n />\n )}\n {resolveStateValue(children, state)}\n </ComboboxContext>\n );\n}\n\nComboboxRoot.displayName = \"ComboboxRoot\";\n"],"mappings":";;;;;;;;;;;;;;;AAiKA,SAAgB,4BAA4B,OAAuB;CACjE,IAAI,UAAU,GAAG,OAAO;CACxB,IAAI,UAAU,GAAG,OAAO;CACxB,OAAO,GAAG,MAAM;AAClB;AAEA,MAAM,yBAAyB,CAAC,iBAAiB,sBAAsB;AAEvE,MAAM,QAAQ,QAAQ,IAAI,aAAa;AAEvC,SAAS,cAAc,SAAkC;CACvD,IAAI,YAAY,MAAM,OAAO;CAC7B,IAAI;EACF,OAAO,QAAQ,QAAQ,eAAe;CACxC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,WAAW,OAAyB;CAC3C,OACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA6B,SAAS;AAElD;;;;;;;;;;AAkCA,SAAgB,aAAa,OAA0B;CACrD,MAAM,EACJ,OACA,cACA,mBACA,YAAY,gBACZ,mBACA,MACA,aACA,kBACA,mBAAmB,OACnB,gBAAgB,OAChB,cAAc,OACd,OAAO,OACP,MACA,aACE;CAMJ,MAAM,QAAQ,IAAI,YAAY;CAC9B,MAAM,OAAO,MAAM,QAAQ,OAAO;CAClC,MAAM,YAAY,MAAM,YAAY,WAAW,OAAO,YAAY;CAClE,MAAM,iBAAiB,OAAO,IAAI;CAElC,MAAM,KAAK,MAAM;CACjB,MAAM,MAAM,eACH;EACL,OAAO,kBAAkB,GAAG,GAAG;EAC/B,OAAO,GAAG,GAAG;EACb,MAAM,GAAG,GAAG;EACZ,cAAc,GAAG,GAAG;CACtB,IACA,CAAC,IAAI,cAAc,CACrB;CAEA,MAAM,UAAU,eAA0C;EACxD,WAAW;EACX,MAAM;EACN,MAAM;EACN;EACA;EACA;CACF,CAAC;CAID,MAAM,WAAW,OAAO,KAAK;CAC7B,MAAM,aAAa,OAAO,OAAO;CACjC,yBAAyB;EACvB,SAAS,UAAU;EACnB,WAAW,UAAU;CACvB,CAAC;CAED,MAAM,WAAW,OAAgC,IAAI;CACrD,MAAM,UAAU,OAA2B,IAAI;CAC/C,MAAM,YAAY,OAAgC,IAAI;CAItD,MAAM,CAAC,cAAc,mBAAmB,eAAe,qBAAqB,kBAAkB,EAAE;CAChG,MAAM,OAAO,kBAAkB;CAC/B,MAAM,QAAQ,iBAAiB,IAAI;CACnC,MAAM,QAAQ,SAAS;CACvB,MAAM,UAAU,OAAO,IAAI;CAC3B,yBAAyB;EACvB,QAAQ,UAAU;CACpB,CAAC;CAED,MAAM,iBAAiB,OAAO,KAAK;;CAEnC,MAAM,YAAY,aACf,MAAc,QAAsB,UAAmC;EACtE,MAAM,SAAS,SAAS;EACxB,IAAI,OAAO,eAAe,KAAA,GAAW,gBAAgB,IAAI;EACzD,QAAQ,UAAU;EAClB,MAAM,SAAS,OAAO;EACtB,IAAI,WAAW,KAAA,GAAW;EAC1B,MAAM,SAAkB,OAAO,MAAM,oBAAoB,OAAO,EAAE,OAAO,CAAC,CAAC;EAC3E,IAAI,SAAS,CAAC,eAAe,WAAW,WAAW,MAAM,GAAG;GAC1D,eAAe,UAAU;GACzB,QAAQ,MACN,oNAGF;EACF;CACF,GACA,CAAC,CACH;CAIA,MAAM,CAAC,UAAU,eAAe;EAC9B,MAAM,sBAAM,IAAI,IAAoB;EACpC,MAAM,eAAe,UAAU,KAAA,IAAY,QAAS,gBAAgB;EACpE,IAAI,iBAAiB,MAAM,IAAI,IAAI,cAAc,qBAAqB,kBAAkB,EAAE;EAC1F,OAAO;CACT,CAAC;CACD,MAAM,WAAW,aACd,MAA8B,MAAM,OAAO,KAAM,OAAO,IAAI,CAAC,KAAK,IACnE,CAAC,MAAM,CACT;CAIA,MAAM,cAAc,OAAO,CAAC;CAC5B,MAAM,CAAC,gBAAgB,+BAAe,IAAI,QAA8B,CAAC;CACzE,MAAM,aAAa,OAA0B,IAAI;CACjD,MAAM,eAAe,OAAsB,IAAI;CAE/C,MAAM,iBAAiB,OACrB,MACA,YACkB;EAClB,MAAM,OAAO,aAAa,IAAI,OAAO;EACrC,IAAI;GACF,MAAM,oBAAoB,MAAM,OAAO;EACzC,SAAS,OAAO;GAId,MAAM,KAAA;GACN,MAAM,SAAS,WAAW;GAC1B,IAAI,SAAS,KAAA,KAAa,WAAW,QAAQ,OAAO,OAAO,KAAK,IAAI;IAClE,WAAW,UAAU;IACrB,IAAI,QAAQ,YAAY,OAAO,MAC7B,UAAU,SAAS,aAAa,OAAO,GAAG,WAAW,KAAA,CAAS;GAElE;GACA,MAAM;EACR;EACA,MAAM,SAAS,WAAW;EAC1B,IAAI,SAAS,KAAA,KAAa,WAAW,QAAQ,OAAO,OAAO,KAAK,IAAI,OAAO,UAAU;EAGrF,MAAM,UAAU,WAAW;EAC3B,IACE,SAAS,KAAA,KACT,KAAK,SACL,KAAK,OAAO,YAAY,WACxB,QAAQ,eAAe,MAAM,KAAK,eACjC,KAAK,SAAS,KAAA,KAAa,QAAQ,YAAY,KAAK,OAErD,QAAQ,aAAa,QAAQ,OAAO,UAAU;CAElD;CAEA,MAAM,YAAY,sBAAiE;EACjF,YAAY;EACZ;EACA,cAAc;EACd,QAAQ;EACR,uBAAuB;EACvB,MAAM;GAAE,WAAW;GAAiB,MAAM;EAAQ;CACpD,CAAC;CACD,yBAAyB;EACvB,aAAa,UAAU,UAAU;CACnC,CAAC;;CAGD,MAAM,WAAW,OAAO,KAAK;CAC7B,MAAM,iBACJ,MACA,OACA,QACA,YACS;EACT,MAAM,UAAU,oBAAoB,OAAO,MAAM;EACjD,MAAM,aAAa,EAAE,YAAY;EACjC,aAAa,IAAI,SAAS;GACxB,IAAI;GACJ,YAAY,QAAQ,eAAe;GACnC,OAAO,QAAQ;GACf,MAAM,QAAQ;EAChB,CAAC;EACD,WAAW,UACT,QAAQ,SAAS,KAAA,IACb,OACA;GAAE,IAAI;GAAY,OAAO;GAAM,MAAM,QAAQ;GAAM,SAAS;EAAM;EACxE,IAAI,SAAS,UAAU,YAAY,SAAS,UAAU;EACtD,UAAU,SAAS,MAAM,OAAO;CAClC;CAKA,oBAAoB,UAAU,kBAAkB;EAC9C,MAAM,OAAO,SAAS;EACtB,SAAS,UAAU;EACnB,OAAO;CACT,CAAC;CAID,MAAM,CAAC,YAAY,+BAAe,IAAI,IAAiC,CAAC;CACxE,MAAM,CAAC,aAAa,kBAAkB,SAAS,CAAC;CAChD,MAAM,CAAC,aAAa,kBAAkB,SAAS,CAAC;CAGhD,MAAM,iBAAiB,OAAO,CAAC;CAC/B,MAAM,CAAC,YAAY,iBAAiB,SAAS,CAAC;CAC9C,MAAM,kBAAkB,OAAO,KAAK;CAEpC,MAAM,iBAAiB,aACpB,aAAqB,UAA+B;EACnD,MAAM,WAAW,SAAS,IAAI,WAAW;EACzC,IACE,SACA,CAAC,gBAAgB,WACjB,aAAa,KAAA,KACb,SAAS,YAAY,MAAM,WAC3B,SAAS,QAAQ,aACjB;GACA,gBAAgB,UAAU;GAC1B,QAAQ,MACN,+CAA+C,KAAK,UAAU,WAAW,EAAE,qFAE7E;EACF;EACA,SAAS,IAAI,aAAa,KAAK;EAC/B,OAAO,IAAI,aAAa,MAAM,UAAU,MAAM,QAAQ,eAAe,GAAA,CAAI,KAAK,CAAC;EAC/E,eAAe,SAAS,IAAI;EAC5B,aAAa;GACX,IAAI,SAAS,IAAI,WAAW,MAAM,OAAO,SAAS,OAAO,WAAW;GACpE,eAAe,SAAS,IAAI;EAC9B;CACF,GACA,CAAC,UAAU,MAAM,CACnB;CAEA,MAAM,iBAAiB,kBAAkB;EACvC,eAAe,WAAW;EAC1B,gBAAgB,UAAU,QAAQ,CAAC;EACnC,aAAa;GACX,eAAe,WAAW;GAC1B,gBAAgB,UAAU,QAAQ,CAAC;EACrC;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,gBAAgB,kBAAkB;EACtC,eAAe,UAAU,QAAQ,CAAC;EAClC,aAAa,eAAe,UAAU,QAAQ,CAAC;CACjD,GAAG,CAAC,CAAC;CAEL,MAAM,CAAC,aAAa,kBAAkB,SAAwB,IAAI;CAClE,MAAM,YAAY,OAAsB,IAAI;CAC5C,MAAM,YAAY,aAAa,SAAwB;EACrD,UAAU,UAAU;EACpB,eAAe,IAAI;CACrB,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,OAAgC,IAAI;CAIxD,MAAM,YAAY,OAAO,IAAI;CAE7B,MAAM,iBAAiB,kBAAmC;EACxD,MAAM,UAA2B,CAAC;EAClC,KAAK,MAAM,CAAC,aAAa,UAAU,UAAU,QAAQ,KAAK;GAAE,OAAO;GAAa,GAAG;EAAM,CAAC;EAC1F,QAAQ,MAAM,GAAG,MACf,EAAE,QAAQ,wBAAwB,EAAE,OAAO,IAAI,KAAK,8BAA8B,KAAK,CACzF;EACA,OAAO;CACT,GAAG,CAAC,QAAQ,CAAC;CAGb,MAAM,UAAU,cAAc;CAC9B,MAAM,QAAQ,gBAAgB,KAAK,CAAC,SAAS,CAAC;CAG9C,sBAAsB;EACpB,MAAM,UAAU,UAAU;EAC1B,IAAI,CAAC,QAAQ,WAAW;GAEtB,IAAI,CAAC,QAAQ,SAAS,GAAG,YAAY,UAAU;GAC/C,UAAU,UAAU;GACpB,IAAI,YAAY,MAAM,UAAU,IAAI;GACpC;EACF;EACA,MAAM,UAAU,eAAe,CAAC,CAAC,QAAQ,WAAW,CAAC,OAAO,QAAQ;EACpE,IAAI,OAAO;EACX,IAAI,YAAY,YAAY,QAAQ,QAAQ,SAAS,GAAG;GACtD,QAAQ,YAAY,YAAY,UAAU,QAAQ,KAAK,QAAQ,GAAG,EAAE,EAAA,CAAI;GACxE,YAAY,UAAU;EACxB,OAAO,IAAI,SAAS,QAAQ,CAAC,QAAQ,MAAM,WAAW,OAAO,UAAU,IAAI,GACzE,OAAO;EAET,IAAI,SAAS,MAEX,UAAU,UAAU;OACf,IAAI,iBAAiB,UAAU,WAAW,CAAC,SAAS,QAAQ,SAAS,GAAG;GAG7E,OAAO,QAAQ,EAAE,CAAE;GACnB,UAAU,UAAU;EACtB;EACA,IAAI,SAAS,SAAS,UAAU,IAAI;CACtC,CAAC;CAKD,MAAM,gBAAgB,OAAO,UAAU,SAAS;CAChD,sBAAsB;EACpB,MAAM,SAAS,WAAW;EAC1B,IACE,WAAW,QACX,OAAO,WACP,CAAC,UAAU,WACX,UAAU,eAAe,MAAM,MAC/B;GACA,WAAW,UAAU;GACrB,IAAI,UAAU,cAAc,OAAO,SAAS,QAAQ,YAAY,OAAO,MACrE,UAAU,SAAS,UAAU,SAAS,GAAG,WAAW,KAAA,CAAS;EAEjE;EACA,IAAI,cAAc,YAAY,UAAU,WAAW;GACjD,cAAc,UAAU,UAAU;GAClC,MAAM,YAAY,UAAU;GAC5B,IAAI,cAAc,QAAQ,WAAW,YAAY,QAAQ,CAAC,OAAO,IAAI,SAAS,GAC5E,OAAO,IAAI,WAAW,QAAQ,OAAO;EAEzC;CACF,CAAC;CAID,MAAM,QAA2B;EAC/B,OAAO,UAAU;EACjB,YAAY;EACZ;EACA;EACA;EACA,MAAM,QAAQ;EACd,SAAS,UAAU,WAAW,QAAQ;EACtC;CACF;CAEA,MAAM,gBAAgB,OAAsB,IAAI;CAChD,gBAAgB;EACd,IAAI,CAAC,QAAQ,WAAW;GACtB,cAAc,UAAU;GACxB;EACF;EACA,IAAI,SAAS,eAAe,UAAU,GAAG;EAGzC,MAAM,QAAQ,SAAS;EACvB,MAAM,MAAM,GAAG,MAAM,QAAQ;EAC7B,IAAI,cAAc,YAAY,KAAK;EACnC,cAAc,UAAU;EACxB,MAAM,OAAO,QAAQ;EACrB,IAAI,SAAS,QAAQ,OAAO,KAAK,eAAe,YAAY;EAE5D,MAAM,WADW,SAAS,QAAQ,YAAY,4BAAA,CACrB,OAAO,KAAK;EACrC,IAAI,YAAY,MAAM,KAAK,WAAW,OAAO;CAC/C,CAAC;CAID,MAAM,CAAC,cAAc,SAAS,KAAK;CACnC,MAAM,CAAC,aAAa,SAAS,cAAc;CAG3C,MAAM,mBAAmB,UAAU,KAAA,IAAa,cAAc,OAAS,gBAAgB;CACvF,MAAM,oBACJ,mBAAmB,KAAA,IAAa,aAAa,KAAO,qBAAqB;CAG3E,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,sBAAsB;EACpB,MAAM,QAAQ,SAAS;EACvB,IAAI,SAAS,KAAK,UAAU,QAAQ,MAAM,UAAU,QAAQ,SAC1D,MAAM,QAAQ,QAAQ;CAE1B,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,cAAc,eACX;EACL,IAAI,UAAU;GACZ,OAAO,UAAU,WAAW,SAAS;EACvC;EACA,IAAI,QAAQ,UAAU,CAAC;CACzB,IACA,CAAC,CACH;CACA,aACE,cACC,UAAU;EAET,MAAM,UADQ,SAAS,SACA,SAAS;EAChC,IAAI,YAAY,QAAQ,SAAS,UAAU,SAAS,YAAY,KAAK;EAErE,WAAW,MAAM,IAAI,CAAC;EACtB,IAAI,qBAAqB,UAAU,YACjC,cACE,kBACA,OACA;GAAE,QAAQ;GAAY,QAAQ;EAAM,GACpC;GAAE,OAAO;GAAO,MAAM,KAAA;EAAU,CAClC;CAEJ,SACM;EAGJ,MAAM,QAAQ,SAAS;EACvB,IAAI,UAAU,QAAQ,MAAM,iBAAiB,mBAC3C,MAAM,eAAe;CAEzB,CACF;CAGA,MAAM,aAAa,OAAO,KAAK;CAC/B,sBAAsB;EACpB,IAAI,WAAW,SAAS;EACxB,WAAW,UAAU;EACrB,MAAM,QAAQ,SAAS;EACvB,IAAI,UAAU,QAAQ,MAAM,UAAU,QAAQ,SAC5C,UAAU,MAAM,OAAO,YAAY,KAAA,CAAS;CAEhD,GAAG,CAAC,SAAS,CAAC;CAEd,MAAM,CAAC,eAAe,gBAEjB,SAAS,gBAAgB,UAAU,QACpC,mBAAmB,KAAA,KACnB,sBAAsB,KAAA,CAC1B;CACA,cACE,aACA,iPAGF;CAIA,MAAM,UAAU,aAAqB,UAAuB;EAC1D,IAAI,UAAU;EACd,MAAM,QAAQ,SAAS,IAAI,WAAW;EACtC,IAAI,UAAU,KAAA,KAAa,MAAM,UAAU;EAC3C,MAAM,QAAQ,MAAM,UAAU,MAAM,QAAQ,eAAe,GAAA,CAAI,KAAK;EACpE,OAAO,IAAI,aAAa,KAAK;EAC7B,YAAY,UAAU;EACtB,IAAI,UAAU,YAAY,aAAa,UAAU,WAAW;EAC5D,UAAU,OAAO,YAAY,KAAK;EAElC,IAAI,gBAAgB,UAAU,YAAY;GACxC,QAAQ,aAAa,OAAO,UAAU;GACtC;EACF;EACA,cACE,aACA,OACA;GAAE,QAAQ;GAAY,QAAQ;EAAM,GACpC;GAAE,OAAO;GAAM,MAAM;EAAM,CAC7B;CACF;;CAGA,MAAM,cAAc,OAAc,UAA4B;EAC5D,MAAM,UAAU,UAAU;EAC1B,MAAM,QAAQ,QAAQ;EACtB,IAAI,UAAU,SAAS,OAAO,GAAG,OAAO;EACxC,MAAM,OAAO,UAAU,KAAK,OAAO;EACnC,IAAI,SAAS,SAAS,OAAO;EAC7B,IAAI,SAAS,MAAM,OAAO,IAAI,MAAM,KAAK;EACzC,cACE,MACA,OACA;GAAE,QAAQ;GAAY,QAAQ,SAAS;EAAK,GAC5C;GAAE;GAAO,MAAM;EAAM,CACvB;EACA,OAAO;CACT;CAEA,MAAM,SAAS,UAAuB;EACpC,IAAI,UAAU;EACd,IAAI,QAAQ,YAAY,IAAI,UAAU,IAAI,YAAY,KAAK;EAC3D,IAAI,UAAU,eAAe,MAC3B,cAAc,MAAM,OAAO;GAAE,QAAQ;GAAY,QAAQ;EAAM,GAAG;GAAE,OAAO;GAAO,MAAM;EAAG,CAAC;EAE9F,SAAS,SAAS,MAAM;CAC1B;CAEA,MAAM,SAAS,MAAc,UAAuB;EAClD,IAAI,UAAU;EACd,UAAU,MAAM,YAAY,KAAK;EACjC,YAAY,UAAU;EAGtB,IAAI,UAAU,YAAY,MAAM,UAAU,IAAI;EAC9C,UAAU,UAAU;EACpB,QAAQ,YAAY,OAAO,UAAU;CACvC;CAEA,MAAM,QAAQ,cAA4B;EACxC,MAAM,UAAU,eAAe,CAAC,CAAC,QAAQ,WAAW,CAAC,OAAO,QAAQ;EACpE,IAAI,QAAQ,WAAW,GAAG;EAC1B,MAAM,OAAO,QAAQ,SAAS;EAC9B,MAAM,QAAQ,QAAQ,WAAW,WAAW,OAAO,UAAU,UAAU,OAAO;EAC9E,IAAI;EACJ,IAAI,cAAc,GAAG,OAAO,QAAQ,IAAI,IAAI,SAAS,OAAQ,OAAO,IAAI,OAAQ,QAAQ;OACnF,OAAO,QAAQ,IAAI,OAAO,SAAS,IAAK,OAAO,OAAO,IAAK,QAAQ;EACxE,MAAM,SAAS,QAAQ;EACvB,UAAU,OAAO,KAAK;EACtB,IAAI,OAAO,OAAO,QAAQ,mBAAmB,YAC3C,OAAO,QAAQ,eAAe,EAAE,OAAO,UAAU,CAAC;CAEtD;CAEA,MAAM,sBAAqC;EACzC,MAAM,UAAU,UAAU;EAC1B,IAAI,YAAY,MAAM,OAAO;EAC7B,MAAM,QAAQ,SAAS,IAAI,OAAO;EAClC,OAAO,UAAU,KAAA,KAAa,CAAC,MAAM,WAAW,UAAU;CAC5D;CAEA,MAAM,WAAW,UAAkC;EACjD,IAAI,YAAY,MAAM,WAAW,MAAM,SAAS,OAAO;EAEvD,IAAI,MAAM,eAAe,MAAM,YAAY,KAAK,OAAO;EAIvD,MAAM,SAAS,cAAc,QAAQ,SAAS,OAAO;EACrD,QAAQ,MAAM,KAAd;GACE,KAAK;IACH,MAAM,eAAe;IACrB,IAAI,MAAM,QACJ;SAAA,CAAC,QAAQ,QAAQ,YAAY,OAAO,UAAU;IAAA,OAC7C,IAAI,CAAC,QAAQ;KAClB,YAAY,UAAU;KACtB,QAAQ,YAAY,OAAO,UAAU;IACvC,OACE,KAAK,CAAC;IAER,OAAO;GACT,KAAK;IACH,MAAM,eAAe;IACrB,IAAI,MAAM,QACJ;SAAA,QAAQ;MACV,MAAM,SAAS,cAAc;MAC7B,IAAI,WAAW,MAAM,OAAO,QAAQ,KAAK;WACpC,QAAQ,aAAa,OAAO,UAAU;KAC7C;WACK,IAAI,CAAC,QAAQ;KAClB,YAAY,UAAU;KACtB,QAAQ,YAAY,OAAO,UAAU;IACvC,OACE,KAAK,EAAE;IAET,OAAO;GACT,KAAK;IACH,IAAI,QAAQ;KAEV,MAAM,eAAe;KACrB,MAAM,SAAS,cAAc;KAC7B,IAAI,WAAW,MAAM,OAAO,QAAQ,KAAK;UACpC,IAAI,oBAAoB,CAAC,WAAW,OAAO,IAAI,GAClD,QAAQ,aAAa,OAAO,UAAU;KAExC,OAAO;IACT;IAIA,IAAI,kBAAkB,gBAAgB,WAAW,OAAO,KAAK,CAAC;IAC9D,OAAO;GAET,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;IAEH,IAAI,UAAU,YAAY,MAAM,UAAU,IAAI;IAC9C,OAAO;GACT,SACE,OAAO;EACX;CACF;;CAGA,MAAM,SAAS,UAAuB;EAEpC,IAAI,UAAU;EACd,MAAM,QAAQ,QAAQ,SAAS;EAC/B,IAAI,UAAU,QAAQ,cAAc,KAAK,GAAG;GAC1C,QAAQ,kBAAkB;IAAE,QAAQ;IAAW;GAAM,CAAC;GACtD,MAAM,YAAY;EACpB;EACA,YAAY,UAAU;EACtB,IAAI,kBAAkB;GACpB,WAAW,OAAO,KAAK;GACvB;EACF;EACA,MAAM,QAAQ,SAAS,UAAU,UAAU;EAC3C,IAAI,QAAQ,YAAY,OAAO,UAAU,OAAO,WAAW,KAAK;CAClE;CACA,MAAM,WAAW,OAAO,KAAK;CAC7B,yBAAyB;EACvB,SAAS,UAAU;CACrB,CAAC;CAED,MAAM,YAAY,UAA4B;EAC5C,MAAM,QAAQ,SAAS;EACvB,MAAM,QAAQ,QAAQ,SAAS;EAC/B,MAAM,OAAO,MAAM;EACnB,IAAI,gBAAgB,MAAM;GACxB,IAAI,SAAS,SAAU,UAAU,QAAQ,MAAM,SAAS,IAAI,GAAI;GAChE,MAAM,KAAK;GACX;EACF;EAGA,IAAI,UAAU,MAAM;EACpB,MAAM,MAAM,MAAM;EAClB,iBAAiB;GACf,IAAI,CAAC,IAAI,SAAS,GAAG;GACrB,MAAM,SAAS,IAAI;GACnB,IAAI,WAAW,SAAU,WAAW,QAAQ,UAAU,QAAQ,MAAM,SAAS,MAAM,GACjF;GAEF,IAAI,MAAM,aAAa,SAAS,QAAQ,KAAK;EAC/C,GAAG,CAAC;CACN;CAEA,MAAM,cAAc,UAA4B;EAC9C,IAAI,YAAY,CAAC,aAAa;EAC9B,QAAQ,YAAY,OAAO,UAAU;CACvC;CAEA,MAAM,UAAgC;EACpC;EACA;EACA,OAAO,UAAU;EACjB,cAAc,UAAU;EACxB,SAAS,MAAM;EACf,YAAY;EACZ;EACA;EACA;EACA;EACA;EACA,UAAU,aAAa;EACvB,cAAc,OAAO,IAAI;EACzB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CAEA,OACE,qBAAC,iBAAD;EAAiB,OAAO;EAAxB,UAAA,CACG,SAAS,KAAA,KACR,oBAAC,SAAD;GACE,KAAK;GACL,MAAK;GACC;GACA;GACN,OAAO,UAAU,cAAc;EAChC,CAAA,GAEF,kBAAkB,UAAU,KAAK,CACnB;;AAErB;AAEA,aAAa,cAAc"}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { dataAttr } from "../internal/data-attr.mjs";
3
- import { rendersButton, useRender } from "../internal/use-render.mjs";
3
+ import { rendersButton } from "../internal/render-element.mjs";
4
+ import { useRender } from "../internal/use-render.mjs";
4
5
  import { useComboboxContext } from "./combobox-context.mjs";
5
6
  import { useCallback, useRef } from "react";
6
7
  //#region src/combobox/combobox-trigger.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"combobox-trigger.mjs","names":[],"sources":["../../src/combobox/combobox-trigger.tsx"],"sourcesContent":["\"use client\";\nimport { useCallback, useRef } from \"react\";\nimport type {\n ComponentPropsWithRef,\n CSSProperties,\n MouseEvent,\n PointerEvent,\n ReactNode,\n} from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport { useComboboxContext } from \"./combobox-context.js\";\n\nexport interface ComboboxTriggerState {\n /** Optimistic open state. */\n readonly open: boolean;\n /** The open (or close) transition is in flight. */\n readonly pending: boolean;\n readonly disabled: boolean;\n}\n\nexport interface ComboboxTriggerProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n | \"onClick\"\n | \"onPointerDown\"\n | \"onMouseDown\"\n | \"onPointerCancel\"\n | \"tabIndex\"\n | \"aria-expanded\"\n | \"aria-controls\"\n | \"disabled\"\n | \"className\"\n | \"style\"\n | \"children\"\n> {\n /** Disables this button; the Root's `disabled` does too. */\n disabled?: boolean;\n className?: StateValue<string | undefined, ComboboxTriggerState>;\n style?: StateValue<CSSProperties | undefined, ComboboxTriggerState>;\n /** Rendered from optimistic state; must not suspend. */\n children?: StateValue<ReactNode, ComboboxTriggerState>;\n /** Should render a `<button>`. */\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ComboboxTriggerState>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\n/**\n * Development check (design 9): an icon-only Trigger needs a name from the consumer. Checked a\n * microtask after the element attaches, once per instance.\n */\nexport function useNameWarning(part: string): (element: HTMLElement) => () => void {\n const warned = useRef(false);\n return useCallback(\n (element: HTMLElement) => {\n if (!isDev || warned.current) return () => {};\n queueMicrotask(() => {\n if (warned.current || !element.isConnected) return;\n if (element.hasAttribute(\"aria-label\") || element.hasAttribute(\"aria-labelledby\")) return;\n if ((element.textContent ?? \"\").trim() !== \"\" || element.hasAttribute(\"title\")) return;\n warned.current = true;\n console.error(`${part}: the button has no accessible name. Give it an \\`aria-label\\`.`);\n });\n return () => {};\n },\n [part],\n );\n}\n\n/**\n * The optional button that toggles the listbox: `<button type=\"button\" tabindex=\"-1\"\n * aria-expanded aria-controls>` (the APG keeps it out of the Tab sequence; the input is the one\n * stop). A press does not take focus from the input, and a click focuses the input. No\n * `commandfor`: the listbox is anchored to the input, never to this button (design 1).\n *\n * Owned keys: `type` (on a `<button>`), `tabIndex`, `disabled`, `aria-expanded`,\n * `aria-controls` (token-merged), `onClick`, `onPointerDown`, `onPointerCancel`, `onMouseDown`,\n * `data-open`, `data-pending`, `data-disabled`.\n */\nexport function ComboboxTrigger({\n disabled: ownDisabled = false,\n className,\n style,\n children,\n render,\n ...rest\n}: ComboboxTriggerProps) {\n const ctx = useComboboxContext(\"Combobox.Trigger\");\n const { popover } = ctx;\n const disabled = ownDisabled || ctx.disabled;\n // What the user saw at the press: a press outside the popup light-dismisses it before the\n // click arrives, so the toggle is decided against the state at `pointerdown`.\n const openAtPress = useRef<boolean | null>(null);\n const ref = useNameWarning(\"Combobox.Trigger\");\n\n const state: ComboboxTriggerState = {\n open: popover.optimistic,\n pending: popover.pending,\n disabled,\n };\n\n const libraryProps: ComponentPropsWithRef<\"button\"> & DataAttributes = {\n ...(rendersButton(render) && { type: \"button\" as const }),\n tabIndex: -1,\n disabled,\n \"aria-expanded\": popover.optimistic,\n \"aria-controls\": ctx.ids.list,\n onPointerDown: (event: PointerEvent<HTMLButtonElement>) => {\n openAtPress.current = popover.intended();\n event.preventDefault();\n },\n onPointerCancel: () => {\n // The press never becomes a click.\n openAtPress.current = null;\n },\n onMouseDown: (event: MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n },\n onClick: (event: MouseEvent<HTMLButtonElement>) => {\n // `detail === 0`: a click without a press (assistive technology, `element.click()`); a\n // snapshot left by a press that never clicked (dragged off) does not belong to it.\n const pressed = event.detail === 0 ? null : openAtPress.current;\n const wasOpen = pressed ?? popover.intended();\n openAtPress.current = null;\n if (disabled) return;\n const native = event.nativeEvent;\n if (wasOpen) popover.requestClose(native, \"activate\");\n else popover.requestOpen(native, \"activate\");\n ctx.inputRef.current?.focus();\n },\n \"data-open\": dataAttr(popover.optimistic),\n \"data-pending\": dataAttr(popover.pending),\n \"data-disabled\": dataAttr(disabled),\n };\n\n return useRender<ComponentPropsWithRef<\"button\">, ComboboxTriggerState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps,\n ref,\n });\n}\n\nComboboxTrigger.displayName = \"ComboboxTrigger\";\n"],"mappings":";;;;;;AA+CA,MAAM,QAAQ,QAAQ,IAAI,aAAa;;;;;AAMvC,SAAgB,eAAe,MAAoD;CACjF,MAAM,SAAS,OAAO,KAAK;CAC3B,OAAO,aACJ,YAAyB;EACxB,IAAI,CAAC,SAAS,OAAO,SAAS,aAAa,CAAC;EAC5C,qBAAqB;GACnB,IAAI,OAAO,WAAW,CAAC,QAAQ,aAAa;GAC5C,IAAI,QAAQ,aAAa,YAAY,KAAK,QAAQ,aAAa,iBAAiB,GAAG;GACnF,KAAK,QAAQ,eAAe,GAAA,CAAI,KAAK,MAAM,MAAM,QAAQ,aAAa,OAAO,GAAG;GAChF,OAAO,UAAU;GACjB,QAAQ,MAAM,GAAG,KAAK,gEAAgE;EACxF,CAAC;EACD,aAAa,CAAC;CAChB,GACA,CAAC,IAAI,CACP;AACF;;;;;;;;;;;AAYA,SAAgB,gBAAgB,EAC9B,UAAU,cAAc,OACxB,WACA,OACA,UACA,QACA,GAAG,QACoB;CACvB,MAAM,MAAM,mBAAmB,kBAAkB;CACjD,MAAM,EAAE,YAAY;CACpB,MAAM,WAAW,eAAe,IAAI;CAGpC,MAAM,cAAc,OAAuB,IAAI;CAC/C,MAAM,MAAM,eAAe,kBAAkB;CAE7C,MAAM,QAA8B;EAClC,MAAM,QAAQ;EACd,SAAS,QAAQ;EACjB;CACF;CAEA,MAAM,eAAiE;EACrE,GAAI,cAAc,MAAM,KAAK,EAAE,MAAM,SAAkB;EACvD,UAAU;EACV;EACA,iBAAiB,QAAQ;EACzB,iBAAiB,IAAI,IAAI;EACzB,gBAAgB,UAA2C;GACzD,YAAY,UAAU,QAAQ,SAAS;GACvC,MAAM,eAAe;EACvB;EACA,uBAAuB;GAErB,YAAY,UAAU;EACxB;EACA,cAAc,UAAyC;GACrD,MAAM,eAAe;EACvB;EACA,UAAU,UAAyC;GAIjD,MAAM,WADU,MAAM,WAAW,IAAI,OAAO,YAAY,YAC7B,QAAQ,SAAS;GAC5C,YAAY,UAAU;GACtB,IAAI,UAAU;GACd,MAAM,SAAS,MAAM;GACrB,IAAI,SAAS,QAAQ,aAAa,QAAQ,UAAU;QAC/C,QAAQ,YAAY,QAAQ,UAAU;GAC3C,IAAI,SAAS,SAAS,MAAM;EAC9B;EACA,aAAa,SAAS,QAAQ,UAAU;EACxC,gBAAgB,SAAS,QAAQ,OAAO;EACxC,iBAAiB,SAAS,QAAQ;CACpC;CAEA,OAAO,UAAiE;EACtE,gBAAgB;EAChB;EACA;EACA;EACA;EACA;EACA,OAAO;EACP;EACA;CACF,CAAC;AACH;AAEA,gBAAgB,cAAc"}
1
+ {"version":3,"file":"combobox-trigger.mjs","names":[],"sources":["../../src/combobox/combobox-trigger.tsx"],"sourcesContent":["\"use client\";\nimport { useCallback, useRef } from \"react\";\nimport type {\n ComponentPropsWithRef,\n CSSProperties,\n MouseEvent,\n PointerEvent,\n ReactNode,\n} from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport { useComboboxContext } from \"./combobox-context.js\";\n\nexport interface ComboboxTriggerState {\n /** Optimistic open state. */\n readonly open: boolean;\n /** The open (or close) transition is in flight. */\n readonly pending: boolean;\n readonly disabled: boolean;\n}\n\nexport interface ComboboxTriggerProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n | \"onClick\"\n | \"onPointerDown\"\n | \"onMouseDown\"\n | \"onPointerCancel\"\n | \"tabIndex\"\n | \"aria-expanded\"\n | \"aria-controls\"\n | \"disabled\"\n | \"className\"\n | \"style\"\n | \"children\"\n> {\n /** Disables this button; the Root's `disabled` does too. */\n disabled?: boolean;\n className?: StateValue<string | undefined, ComboboxTriggerState>;\n style?: StateValue<CSSProperties | undefined, ComboboxTriggerState>;\n /** Rendered from optimistic state; must not suspend. */\n children?: StateValue<ReactNode, ComboboxTriggerState>;\n /** Should render a `<button>`. */\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ComboboxTriggerState>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\n/**\n * Development check (design 9): an icon-only Trigger needs a name from the consumer. Checked a\n * microtask after the element attaches, once per instance.\n */\nexport function useNameWarning(part: string): (element: HTMLElement) => () => void {\n const warned = useRef(false);\n return useCallback(\n (element: HTMLElement) => {\n if (!isDev || warned.current) return () => {};\n queueMicrotask(() => {\n if (warned.current || !element.isConnected) return;\n if (element.hasAttribute(\"aria-label\") || element.hasAttribute(\"aria-labelledby\")) return;\n if ((element.textContent ?? \"\").trim() !== \"\" || element.hasAttribute(\"title\")) return;\n warned.current = true;\n console.error(`${part}: the button has no accessible name. Give it an \\`aria-label\\`.`);\n });\n return () => {};\n },\n [part],\n );\n}\n\n/**\n * The optional button that toggles the listbox: `<button type=\"button\" tabindex=\"-1\"\n * aria-expanded aria-controls>` (the APG keeps it out of the Tab sequence; the input is the one\n * stop). A press does not take focus from the input, and a click focuses the input. No\n * `commandfor`: the listbox is anchored to the input, never to this button (design 1).\n *\n * Owned keys: `type` (on a `<button>`), `tabIndex`, `disabled`, `aria-expanded`,\n * `aria-controls` (token-merged), `onClick`, `onPointerDown`, `onPointerCancel`, `onMouseDown`,\n * `data-open`, `data-pending`, `data-disabled`.\n */\nexport function ComboboxTrigger({\n disabled: ownDisabled = false,\n className,\n style,\n children,\n render,\n ...rest\n}: ComboboxTriggerProps) {\n const ctx = useComboboxContext(\"Combobox.Trigger\");\n const { popover } = ctx;\n const disabled = ownDisabled || ctx.disabled;\n // What the user saw at the press: a press outside the popup light-dismisses it before the\n // click arrives, so the toggle is decided against the state at `pointerdown`.\n const openAtPress = useRef<boolean | null>(null);\n const ref = useNameWarning(\"Combobox.Trigger\");\n\n const state: ComboboxTriggerState = {\n open: popover.optimistic,\n pending: popover.pending,\n disabled,\n };\n\n const libraryProps: ComponentPropsWithRef<\"button\"> & DataAttributes = {\n ...(rendersButton(render) && { type: \"button\" as const }),\n tabIndex: -1,\n disabled,\n \"aria-expanded\": popover.optimistic,\n \"aria-controls\": ctx.ids.list,\n onPointerDown: (event: PointerEvent<HTMLButtonElement>) => {\n openAtPress.current = popover.intended();\n event.preventDefault();\n },\n onPointerCancel: () => {\n // The press never becomes a click.\n openAtPress.current = null;\n },\n onMouseDown: (event: MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n },\n onClick: (event: MouseEvent<HTMLButtonElement>) => {\n // `detail === 0`: a click without a press (assistive technology, `element.click()`); a\n // snapshot left by a press that never clicked (dragged off) does not belong to it.\n const pressed = event.detail === 0 ? null : openAtPress.current;\n const wasOpen = pressed ?? popover.intended();\n openAtPress.current = null;\n if (disabled) return;\n const native = event.nativeEvent;\n if (wasOpen) popover.requestClose(native, \"activate\");\n else popover.requestOpen(native, \"activate\");\n ctx.inputRef.current?.focus();\n },\n \"data-open\": dataAttr(popover.optimistic),\n \"data-pending\": dataAttr(popover.pending),\n \"data-disabled\": dataAttr(disabled),\n };\n\n return useRender<ComponentPropsWithRef<\"button\">, ComboboxTriggerState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps,\n ref,\n });\n}\n\nComboboxTrigger.displayName = \"ComboboxTrigger\";\n"],"mappings":";;;;;;;AA+CA,MAAM,QAAQ,QAAQ,IAAI,aAAa;;;;;AAMvC,SAAgB,eAAe,MAAoD;CACjF,MAAM,SAAS,OAAO,KAAK;CAC3B,OAAO,aACJ,YAAyB;EACxB,IAAI,CAAC,SAAS,OAAO,SAAS,aAAa,CAAC;EAC5C,qBAAqB;GACnB,IAAI,OAAO,WAAW,CAAC,QAAQ,aAAa;GAC5C,IAAI,QAAQ,aAAa,YAAY,KAAK,QAAQ,aAAa,iBAAiB,GAAG;GACnF,KAAK,QAAQ,eAAe,GAAA,CAAI,KAAK,MAAM,MAAM,QAAQ,aAAa,OAAO,GAAG;GAChF,OAAO,UAAU;GACjB,QAAQ,MAAM,GAAG,KAAK,gEAAgE;EACxF,CAAC;EACD,aAAa,CAAC;CAChB,GACA,CAAC,IAAI,CACP;AACF;;;;;;;;;;;AAYA,SAAgB,gBAAgB,EAC9B,UAAU,cAAc,OACxB,WACA,OACA,UACA,QACA,GAAG,QACoB;CACvB,MAAM,MAAM,mBAAmB,kBAAkB;CACjD,MAAM,EAAE,YAAY;CACpB,MAAM,WAAW,eAAe,IAAI;CAGpC,MAAM,cAAc,OAAuB,IAAI;CAC/C,MAAM,MAAM,eAAe,kBAAkB;CAE7C,MAAM,QAA8B;EAClC,MAAM,QAAQ;EACd,SAAS,QAAQ;EACjB;CACF;CAEA,MAAM,eAAiE;EACrE,GAAI,cAAc,MAAM,KAAK,EAAE,MAAM,SAAkB;EACvD,UAAU;EACV;EACA,iBAAiB,QAAQ;EACzB,iBAAiB,IAAI,IAAI;EACzB,gBAAgB,UAA2C;GACzD,YAAY,UAAU,QAAQ,SAAS;GACvC,MAAM,eAAe;EACvB;EACA,uBAAuB;GAErB,YAAY,UAAU;EACxB;EACA,cAAc,UAAyC;GACrD,MAAM,eAAe;EACvB;EACA,UAAU,UAAyC;GAIjD,MAAM,WADU,MAAM,WAAW,IAAI,OAAO,YAAY,YAC7B,QAAQ,SAAS;GAC5C,YAAY,UAAU;GACtB,IAAI,UAAU;GACd,MAAM,SAAS,MAAM;GACrB,IAAI,SAAS,QAAQ,aAAa,QAAQ,UAAU;QAC/C,QAAQ,YAAY,QAAQ,UAAU;GAC3C,IAAI,SAAS,SAAS,MAAM;EAC9B;EACA,aAAa,SAAS,QAAQ,UAAU;EACxC,gBAAgB,SAAS,QAAQ,OAAO;EACxC,iBAAiB,SAAS,QAAQ;CACpC;CAEA,OAAO,UAAiE;EACtE,gBAAgB;EAChB;EACA;EACA;EACA;EACA;EACA,OAAO;EACP;EACA;CACF,CAAC;AACH;AAEA,gBAAgB,cAAc"}
@@ -13,13 +13,18 @@ export interface DialogCloseDetails extends ActionDetails {
13
13
  }
14
14
  export interface DialogCloseProps extends Omit<ComponentPropsWithRef<"button">, "onClick" | "value" | "className" | "style" | "children"> {
15
15
  /**
16
- * Runs inside this part's own transition, then closes the dialog with `close(value)`. A
17
- * rejection reaches the nearest Error Boundary above the Close part and leaves the dialog open.
18
- * Without `action` the button is a native `command="request-close"` invoker (JS-free).
16
+ * Runs inside this part's own transition (`data-pending` on the button), then closes the
17
+ * dialog with `value` as `returnValue`: in library mode through the Root
18
+ * (`openChangeAction(false)` awaited, view transition if set), in JS-free mode with
19
+ * `close(value)`. A rejection reaches the nearest Error Boundary above the Close part and
20
+ * leaves the dialog open. If the dialog was dismissed and opened again while the action ran,
21
+ * the close is dropped: it belonged to the earlier open. Without `action` in JS-free mode the
22
+ * button is a native `command="request-close"` invoker.
19
23
  */
20
24
  action?: Action<[details: DialogCloseDetails]>;
21
- /** Becomes `dialog.returnValue` (and `details.returnValue` of the close notification). */
25
+ /** Becomes `dialog.returnValue` (and `details.returnValue` of `openChangeAction(false)`). */
22
26
  value?: string;
27
+ /** Native `disabled`; owned, so a `render` element cannot re-enable the button. */
23
28
  disabled?: boolean;
24
29
  className?: StateValue<string | undefined, DialogCloseState>;
25
30
  style?: StateValue<CSSProperties | undefined, DialogCloseState>;
@@ -27,14 +32,16 @@ export interface DialogCloseProps extends Omit<ComponentPropsWithRef<"button">,
27
32
  render?: RenderProp<ComponentPropsWithRef<"button">, DialogCloseState>;
28
33
  }
29
34
  /**
30
- * A close button: `<button type="button" commandfor command="request-close">`. Without `action`
31
- * the browser closes the dialog (a close request: `cancel`, then `close`), with `value` as the
32
- * `returnValue`. With `action` the click is cancelled, the action runs in this part's own
33
- * transition (`data-pending` on the button) and the dialog closes with `close(value)` once it
34
- * resolves; a rejection leaves the dialog open.
35
+ * A close button: `<button type="button" commandfor command="request-close">`. In JS-free mode
36
+ * without `action` the browser closes the dialog (a close request: `cancel`, then `close`), with
37
+ * `value` as the `returnValue`. In library mode the click is always cancelled and the close goes
38
+ * through the Root (`openChangeAction(false)` awaited, then `close(value)` in the commit, inside
39
+ * the view transition if the Popup's `transition` is set). With `action` the action runs first in
40
+ * this part's own transition (`data-pending` on the button); a rejection leaves the dialog open.
35
41
  *
36
42
  * Owned keys (conventions 1.2): `type` (on a `<button>` only), `disabled`, `commandfor`,
37
- * `command`, `value`, `onClick` (with `action`), `data-pending`, `data-disabled`.
43
+ * `command`, `value`, `onClick` (library mode, or with `action`), `data-pending`,
44
+ * `data-disabled`.
38
45
  */
39
46
  export declare function DialogClose({ action, value, disabled, className, style, children, render, ...rest }: DialogCloseProps): ReactNode;
40
47
  export declare namespace DialogClose {
@@ -1 +1 @@
1
- {"version":3,"file":"dialog-close.d.mts","names":[],"sources":["../../src/dialog/dialog-close.tsx"],"mappings":";;;iBAWiB;;WAEN;WACA;;;iBAIM,2BAA2B;;WAEjC;;iBAGM,yBAAyB,KACxC;;;;;;EAQA,SAAS,QAAQ,SAAS;;EAE1B;EACA;EACA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,WAAW,WAAW,WAAW;EACjC,SAAS,WAAW,iCAAiC;;;;;;;;;;;;wBAevC,cACd,QACA,OACA,UACA,WACA,OACA,UACA,WACG,QACF,mBAAgB;yBATH"}
1
+ {"version":3,"file":"dialog-close.d.mts","names":[],"sources":["../../src/dialog/dialog-close.tsx"],"mappings":";;;iBAWiB;;WAEN;WACA;;;iBAIM,2BAA2B;;WAEjC;;iBAGM,yBAAyB,KACxC;;;;;;;;;;EAYA,SAAS,QAAQ,SAAS;;EAE1B;;EAEA;EACA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,WAAW,WAAW,WAAW;EACjC,SAAS,WAAW,iCAAiC;;;;;;;;;;;;;;wBAiBvC,cACd,QACA,OACA,UACA,WACA,OACA,UACA,WACG,QACF,mBAAgB;yBATH"}
@@ -1,51 +1,63 @@
1
1
  "use client";
2
2
  import { createActionDetails } from "../internal/action-details.mjs";
3
3
  import { dataAttr } from "../internal/data-attr.mjs";
4
- import { rendersButton, useRender } from "../internal/use-render.mjs";
4
+ import { rendersButton } from "../internal/render-element.mjs";
5
+ import { useRender } from "../internal/use-render.mjs";
5
6
  import { useActionTrigger } from "../internal/use-action-trigger.mjs";
6
7
  import { useDialogContext } from "./dialog-context.mjs";
7
8
  import { useCallback } from "react";
8
9
  //#region src/dialog/dialog-close.tsx
9
10
  const isDev = process.env.NODE_ENV !== "production";
10
11
  /**
11
- * A close button: `<button type="button" commandfor command="request-close">`. Without `action`
12
- * the browser closes the dialog (a close request: `cancel`, then `close`), with `value` as the
13
- * `returnValue`. With `action` the click is cancelled, the action runs in this part's own
14
- * transition (`data-pending` on the button) and the dialog closes with `close(value)` once it
15
- * resolves; a rejection leaves the dialog open.
12
+ * A close button: `<button type="button" commandfor command="request-close">`. In JS-free mode
13
+ * without `action` the browser closes the dialog (a close request: `cancel`, then `close`), with
14
+ * `value` as the `returnValue`. In library mode the click is always cancelled and the close goes
15
+ * through the Root (`openChangeAction(false)` awaited, then `close(value)` in the commit, inside
16
+ * the view transition if the Popup's `transition` is set). With `action` the action runs first in
17
+ * this part's own transition (`data-pending` on the button); a rejection leaves the dialog open.
16
18
  *
17
19
  * Owned keys (conventions 1.2): `type` (on a `<button>` only), `disabled`, `commandfor`,
18
- * `command`, `value`, `onClick` (with `action`), `data-pending`, `data-disabled`.
20
+ * `command`, `value`, `onClick` (library mode, or with `action`), `data-pending`,
21
+ * `data-disabled`.
19
22
  */
20
23
  function DialogClose({ action, value, disabled = false, className, style, children, render, ...rest }) {
21
24
  const ctx = useDialogContext("Dialog.Close");
22
25
  const { pending, run } = useActionTrigger(ctx.openGeneration);
23
26
  const { ids, dialogRef, recordCloseIntent } = ctx;
24
- const hasAction = action !== void 0;
27
+ const isLibrary = ctx.mode === "library";
28
+ const installClick = isLibrary || action !== void 0;
25
29
  const state = {
26
30
  pending,
27
31
  disabled
28
32
  };
29
33
  const devRef = useCallback((element) => {
30
- if (isDev && !hasAction && element.tagName !== "BUTTON") console.error(`Dialog.Close: rendered a <${element.tagName.toLowerCase()}> without \`action\`. Only a <button> runs \`command="request-close"\`; this element will not close the dialog.`);
34
+ if (isDev && !installClick && element.tagName !== "BUTTON") console.error(`Dialog.Close: rendered a <${element.tagName.toLowerCase()}> in JS-free mode without \`action\`. Only a <button> runs \`command="request-close"\`; this element will not close the dialog.`);
31
35
  return () => {};
32
- }, [hasAction]);
36
+ }, [installClick]);
37
+ const close = (event, returnValue) => {
38
+ if (isLibrary) {
39
+ ctx.requestClose(event, "activate", returnValue);
40
+ return;
41
+ }
42
+ const dialog = dialogRef.current;
43
+ if (dialog === null || !dialog.open) return;
44
+ recordCloseIntent({
45
+ reason: "activate",
46
+ event
47
+ });
48
+ dialog.close(returnValue);
49
+ };
33
50
  const onClick = (event) => {
34
- if (action === void 0) return;
35
51
  event.preventDefault();
36
52
  if (disabled) return;
37
53
  const native = event.nativeEvent;
38
54
  const returnValue = value ?? "";
55
+ if (action === void 0) {
56
+ close(native, returnValue);
57
+ return;
58
+ }
39
59
  const details = createActionDetails(native, { returnValue });
40
- run(() => action(details), () => {
41
- const dialog = dialogRef.current;
42
- if (dialog === null || !dialog.open) return;
43
- recordCloseIntent({
44
- reason: "activate",
45
- event: native
46
- });
47
- dialog.close(returnValue);
48
- });
60
+ run(() => action(details), () => close(native, returnValue));
49
61
  };
50
62
  const libraryProps = {
51
63
  ...rendersButton(render) && { type: "button" },
@@ -53,7 +65,7 @@ function DialogClose({ action, value, disabled = false, className, style, childr
53
65
  commandfor: ids.dialog,
54
66
  command: "request-close",
55
67
  value,
56
- ...hasAction && { onClick },
68
+ ...installClick && { onClick },
57
69
  "data-pending": dataAttr(pending),
58
70
  "data-disabled": dataAttr(disabled)
59
71
  };