@proyecto-viviana/solidaria 0.4.0 → 0.4.2

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 (480) hide show
  1. package/dist/_chunk/DragManager.js +627 -0
  2. package/dist/_chunk/DragManager.js.map +1 -0
  3. package/dist/_chunk/DragManager.jsx +627 -0
  4. package/dist/_chunk/DragManager.jsx.map +1 -0
  5. package/dist/_chunk/FocusScope.js +400 -0
  6. package/dist/_chunk/FocusScope.js.map +1 -0
  7. package/dist/_chunk/FocusScope.jsx +375 -0
  8. package/dist/_chunk/FocusScope.jsx.map +1 -0
  9. package/dist/_chunk/actiongroup.js +13 -79
  10. package/dist/_chunk/actiongroup.js.map +1 -1
  11. package/dist/_chunk/actiongroup.jsx +13 -79
  12. package/dist/_chunk/actiongroup.jsx.map +1 -1
  13. package/dist/_chunk/{live-announcer.js → announce.js} +1 -1
  14. package/dist/_chunk/announce.js.map +1 -0
  15. package/dist/_chunk/{live-announcer.jsx → announce.jsx} +1 -1
  16. package/dist/_chunk/announce.jsx.map +1 -0
  17. package/dist/_chunk/autocomplete.js +56 -8
  18. package/dist/_chunk/autocomplete.js.map +1 -1
  19. package/dist/_chunk/autocomplete.jsx +56 -8
  20. package/dist/_chunk/autocomplete.jsx.map +1 -1
  21. package/dist/_chunk/breadcrumbs.js +6 -4
  22. package/dist/_chunk/breadcrumbs.js.map +1 -1
  23. package/dist/_chunk/breadcrumbs.jsx +6 -4
  24. package/dist/_chunk/breadcrumbs.jsx.map +1 -1
  25. package/dist/_chunk/button.js +8 -9
  26. package/dist/_chunk/button.js.map +1 -1
  27. package/dist/_chunk/button.jsx +8 -9
  28. package/dist/_chunk/button.jsx.map +1 -1
  29. package/dist/_chunk/calendar.js +27 -26
  30. package/dist/_chunk/calendar.js.map +1 -1
  31. package/dist/_chunk/calendar.jsx +27 -26
  32. package/dist/_chunk/calendar.jsx.map +1 -1
  33. package/dist/_chunk/checkbox.js +5 -4
  34. package/dist/_chunk/checkbox.js.map +1 -1
  35. package/dist/_chunk/checkbox.jsx +5 -4
  36. package/dist/_chunk/checkbox.jsx.map +1 -1
  37. package/dist/_chunk/color.js +302 -18
  38. package/dist/_chunk/color.js.map +1 -1
  39. package/dist/_chunk/color.jsx +302 -18
  40. package/dist/_chunk/color.jsx.map +1 -1
  41. package/dist/_chunk/combobox.js +638 -12
  42. package/dist/_chunk/combobox.js.map +1 -1
  43. package/dist/_chunk/combobox.jsx +638 -12
  44. package/dist/_chunk/combobox.jsx.map +1 -1
  45. package/dist/_chunk/constants.js +19 -0
  46. package/dist/_chunk/constants.js.map +1 -0
  47. package/dist/_chunk/constants.jsx +19 -0
  48. package/dist/_chunk/constants.jsx.map +1 -0
  49. package/dist/_chunk/createCollator.js +3 -171
  50. package/dist/_chunk/createCollator.js.map +1 -1
  51. package/dist/_chunk/createCollator.jsx +3 -165
  52. package/dist/_chunk/createCollator.jsx.map +1 -1
  53. package/dist/_chunk/createField.js +2 -1
  54. package/dist/_chunk/createField.js.map +1 -1
  55. package/dist/_chunk/createField.jsx +2 -1
  56. package/dist/_chunk/createField.jsx.map +1 -1
  57. package/dist/_chunk/createFocus.js +12 -8
  58. package/dist/_chunk/createFocus.js.map +1 -1
  59. package/dist/_chunk/createFocus.jsx +12 -8
  60. package/dist/_chunk/createFocus.jsx.map +1 -1
  61. package/dist/_chunk/createFocusWithin.js +12 -13
  62. package/dist/_chunk/createFocusWithin.js.map +1 -1
  63. package/dist/_chunk/createFocusWithin.jsx +12 -13
  64. package/dist/_chunk/createFocusWithin.jsx.map +1 -1
  65. package/dist/_chunk/createFocusable.js +3 -3
  66. package/dist/_chunk/createFocusable.js.map +1 -1
  67. package/dist/_chunk/createFocusable.jsx +3 -3
  68. package/dist/_chunk/createFocusable.jsx.map +1 -1
  69. package/dist/_chunk/{form.js → createFormReset.js} +1 -1
  70. package/dist/_chunk/createFormReset.js.map +1 -0
  71. package/dist/_chunk/{form.jsx → createFormReset.jsx} +1 -1
  72. package/dist/_chunk/createFormReset.jsx.map +1 -0
  73. package/dist/_chunk/createHover.js +2 -1
  74. package/dist/_chunk/createHover.js.map +1 -1
  75. package/dist/_chunk/createHover.jsx +2 -1
  76. package/dist/_chunk/createHover.jsx.map +1 -1
  77. package/dist/_chunk/createInteractionModality.js +2 -3
  78. package/dist/_chunk/createInteractionModality.js.map +1 -1
  79. package/dist/_chunk/createInteractionModality.jsx +2 -3
  80. package/dist/_chunk/createInteractionModality.jsx.map +1 -1
  81. package/dist/_chunk/createLabel.js +2 -1
  82. package/dist/_chunk/createLabel.js.map +1 -1
  83. package/dist/_chunk/createLabel.jsx +2 -1
  84. package/dist/_chunk/createLabel.jsx.map +1 -1
  85. package/dist/_chunk/createLabels.js +3 -2
  86. package/dist/_chunk/createLabels.js.map +1 -1
  87. package/dist/_chunk/createLabels.jsx +3 -2
  88. package/dist/_chunk/createLabels.jsx.map +1 -1
  89. package/dist/_chunk/createLandmark.js +1 -1
  90. package/dist/_chunk/createLandmark.jsx +1 -1
  91. package/dist/_chunk/createProgressBar.js +2 -1
  92. package/dist/_chunk/createProgressBar.js.map +1 -1
  93. package/dist/_chunk/createProgressBar.jsx +2 -1
  94. package/dist/_chunk/createProgressBar.jsx.map +1 -1
  95. package/dist/_chunk/createSelectableItem.js +7 -3
  96. package/dist/_chunk/createSelectableItem.js.map +1 -1
  97. package/dist/_chunk/createSelectableItem.jsx +7 -3
  98. package/dist/_chunk/createSelectableItem.jsx.map +1 -1
  99. package/dist/_chunk/createStringFormatter.js +61 -0
  100. package/dist/_chunk/createStringFormatter.js.map +1 -0
  101. package/dist/_chunk/createStringFormatter.jsx +61 -0
  102. package/dist/_chunk/createStringFormatter.jsx.map +1 -0
  103. package/dist/_chunk/createToggle.js +5 -4
  104. package/dist/_chunk/createToggle.js.map +1 -1
  105. package/dist/_chunk/createToggle.jsx +5 -4
  106. package/dist/_chunk/createToggle.jsx.map +1 -1
  107. package/dist/_chunk/datepicker.js +1413 -1100
  108. package/dist/_chunk/datepicker.js.map +1 -1
  109. package/dist/_chunk/datepicker.jsx +1413 -1100
  110. package/dist/_chunk/datepicker.jsx.map +1 -1
  111. package/dist/_chunk/disclosure.js +2 -2
  112. package/dist/_chunk/disclosure.js.map +1 -1
  113. package/dist/_chunk/disclosure.jsx +2 -2
  114. package/dist/_chunk/disclosure.jsx.map +1 -1
  115. package/dist/_chunk/dnd.js +1586 -495
  116. package/dist/_chunk/dnd.js.map +1 -1
  117. package/dist/_chunk/dnd.jsx +1586 -495
  118. package/dist/_chunk/dnd.jsx.map +1 -1
  119. package/dist/_chunk/env.js +1 -19
  120. package/dist/_chunk/env.js.map +1 -1
  121. package/dist/_chunk/env.jsx +1 -19
  122. package/dist/_chunk/env.jsx.map +1 -1
  123. package/dist/_chunk/focus.js +1 -1
  124. package/dist/_chunk/focus.js.map +1 -1
  125. package/dist/_chunk/focus.jsx +1 -1
  126. package/dist/_chunk/focus.jsx.map +1 -1
  127. package/dist/_chunk/focus2.js +54 -318
  128. package/dist/_chunk/focus2.js.map +1 -1
  129. package/dist/_chunk/focus2.jsx +53 -292
  130. package/dist/_chunk/focus2.jsx.map +1 -1
  131. package/dist/_chunk/grid.js +1 -1
  132. package/dist/_chunk/grid.jsx +1 -1
  133. package/dist/_chunk/gridlist.js +14 -9
  134. package/dist/_chunk/gridlist.js.map +1 -1
  135. package/dist/_chunk/gridlist.jsx +14 -9
  136. package/dist/_chunk/gridlist.jsx.map +1 -1
  137. package/dist/_chunk/i18n.js +3 -58
  138. package/dist/_chunk/i18n.js.map +1 -1
  139. package/dist/_chunk/i18n.jsx +3 -58
  140. package/dist/_chunk/i18n.jsx.map +1 -1
  141. package/dist/_chunk/interactions.js +99 -9
  142. package/dist/_chunk/interactions.js.map +1 -1
  143. package/dist/_chunk/interactions.jsx +97 -9
  144. package/dist/_chunk/interactions.jsx.map +1 -1
  145. package/dist/_chunk/link.js +2 -1
  146. package/dist/_chunk/link.js.map +1 -1
  147. package/dist/_chunk/link.jsx +2 -1
  148. package/dist/_chunk/link.jsx.map +1 -1
  149. package/dist/_chunk/listbox.js +42 -10
  150. package/dist/_chunk/listbox.js.map +1 -1
  151. package/dist/_chunk/listbox.jsx +42 -10
  152. package/dist/_chunk/listbox.jsx.map +1 -1
  153. package/dist/_chunk/locale.js +173 -0
  154. package/dist/_chunk/locale.js.map +1 -0
  155. package/dist/_chunk/locale.jsx +167 -0
  156. package/dist/_chunk/locale.jsx.map +1 -0
  157. package/dist/_chunk/menu.js +5 -4
  158. package/dist/_chunk/menu.js.map +1 -1
  159. package/dist/_chunk/menu.jsx +5 -4
  160. package/dist/_chunk/menu.jsx.map +1 -1
  161. package/dist/_chunk/numberfield.js +3 -2
  162. package/dist/_chunk/numberfield.js.map +1 -1
  163. package/dist/_chunk/numberfield.jsx +3 -2
  164. package/dist/_chunk/numberfield.jsx.map +1 -1
  165. package/dist/_chunk/overlays.js +1 -1
  166. package/dist/_chunk/overlays.jsx +1 -1
  167. package/dist/_chunk/popover.js +3 -3
  168. package/dist/_chunk/popover.js.map +1 -1
  169. package/dist/_chunk/popover.jsx +3 -3
  170. package/dist/_chunk/popover.jsx.map +1 -1
  171. package/dist/_chunk/radio.js +7 -6
  172. package/dist/_chunk/radio.js.map +1 -1
  173. package/dist/_chunk/radio.jsx +7 -6
  174. package/dist/_chunk/radio.jsx.map +1 -1
  175. package/dist/_chunk/reactivity.js +21 -0
  176. package/dist/_chunk/reactivity.js.map +1 -0
  177. package/dist/_chunk/reactivity.jsx +21 -0
  178. package/dist/_chunk/reactivity.jsx.map +1 -0
  179. package/dist/_chunk/searchfield.js +2 -1
  180. package/dist/_chunk/searchfield.js.map +1 -1
  181. package/dist/_chunk/searchfield.jsx +2 -1
  182. package/dist/_chunk/searchfield.jsx.map +1 -1
  183. package/dist/_chunk/select.js +8 -5
  184. package/dist/_chunk/select.js.map +1 -1
  185. package/dist/_chunk/select.jsx +8 -5
  186. package/dist/_chunk/select.jsx.map +1 -1
  187. package/dist/_chunk/selection.js +8 -21
  188. package/dist/_chunk/selection.js.map +1 -1
  189. package/dist/_chunk/selection.jsx +8 -21
  190. package/dist/_chunk/selection.jsx.map +1 -1
  191. package/dist/_chunk/separator.js +1 -1
  192. package/dist/_chunk/separator.jsx +1 -1
  193. package/dist/_chunk/slider.js +5 -4
  194. package/dist/_chunk/slider.js.map +1 -1
  195. package/dist/_chunk/slider.jsx +5 -4
  196. package/dist/_chunk/slider.jsx.map +1 -1
  197. package/dist/_chunk/spinbutton.js +153 -0
  198. package/dist/_chunk/spinbutton.js.map +1 -0
  199. package/dist/_chunk/spinbutton.jsx +153 -0
  200. package/dist/_chunk/spinbutton.jsx.map +1 -0
  201. package/dist/_chunk/table.js +45 -8
  202. package/dist/_chunk/table.js.map +1 -1
  203. package/dist/_chunk/table.jsx +45 -8
  204. package/dist/_chunk/table.jsx.map +1 -1
  205. package/dist/_chunk/tabs.js +11 -8
  206. package/dist/_chunk/tabs.js.map +1 -1
  207. package/dist/_chunk/tabs.jsx +11 -8
  208. package/dist/_chunk/tabs.jsx.map +1 -1
  209. package/dist/_chunk/tag.js +54 -18
  210. package/dist/_chunk/tag.js.map +1 -1
  211. package/dist/_chunk/tag.jsx +54 -18
  212. package/dist/_chunk/tag.jsx.map +1 -1
  213. package/dist/_chunk/textfield.js +2 -1
  214. package/dist/_chunk/textfield.js.map +1 -1
  215. package/dist/_chunk/textfield.jsx +2 -1
  216. package/dist/_chunk/textfield.jsx.map +1 -1
  217. package/dist/_chunk/toolbar.js +4 -36
  218. package/dist/_chunk/toolbar.js.map +1 -1
  219. package/dist/_chunk/toolbar.jsx +4 -36
  220. package/dist/_chunk/toolbar.jsx.map +1 -1
  221. package/dist/_chunk/tooltip.js +2 -2
  222. package/dist/_chunk/tooltip.js.map +1 -1
  223. package/dist/_chunk/tooltip.jsx +2 -2
  224. package/dist/_chunk/tooltip.jsx.map +1 -1
  225. package/dist/_chunk/tree.js +42 -14
  226. package/dist/_chunk/tree.js.map +1 -1
  227. package/dist/_chunk/tree.jsx +42 -14
  228. package/dist/_chunk/tree.jsx.map +1 -1
  229. package/dist/_chunk/utils.js +59 -19
  230. package/dist/_chunk/utils.js.map +1 -1
  231. package/dist/_chunk/utils.jsx +59 -19
  232. package/dist/_chunk/utils.jsx.map +1 -1
  233. package/dist/_chunk/visually-hidden.js +3 -2
  234. package/dist/_chunk/visually-hidden.js.map +1 -1
  235. package/dist/_chunk/visually-hidden.jsx +3 -2
  236. package/dist/_chunk/visually-hidden.jsx.map +1 -1
  237. package/dist/actiongroup/createActionGroup.d.ts.map +1 -1
  238. package/dist/autocomplete/createAutocomplete.d.ts +10 -7
  239. package/dist/autocomplete/createAutocomplete.d.ts.map +1 -1
  240. package/dist/breadcrumbs/createBreadcrumbs.d.ts.map +1 -1
  241. package/dist/button/createToggleButtonGroup.d.ts.map +1 -1
  242. package/dist/calendar/createCalendar.d.ts.map +1 -1
  243. package/dist/calendar/createCalendarCell.d.ts.map +1 -1
  244. package/dist/calendar/createCalendarGrid.d.ts.map +1 -1
  245. package/dist/calendar/createRangeCalendar.d.ts.map +1 -1
  246. package/dist/calendar/createRangeCalendarCell.d.ts.map +1 -1
  247. package/dist/calendar/intl/index.d.ts +1 -1
  248. package/dist/calendar/intl/index.d.ts.map +1 -1
  249. package/dist/collections/index.js +1 -1
  250. package/dist/collections/index.jsx +1 -1
  251. package/dist/color/createColorArea.d.ts.map +1 -1
  252. package/dist/color/createColorField.d.ts.map +1 -1
  253. package/dist/color/createColorSlider.d.ts.map +1 -1
  254. package/dist/color/createColorSwatch.d.ts.map +1 -1
  255. package/dist/color/createColorWheel.d.ts.map +1 -1
  256. package/dist/color/intl/index.d.ts +30 -0
  257. package/dist/color/intl/index.d.ts.map +1 -0
  258. package/dist/combobox/createComboBox.d.ts.map +1 -1
  259. package/dist/combobox/intl/generated-locales.d.ts +16 -0
  260. package/dist/combobox/intl/generated-locales.d.ts.map +1 -0
  261. package/dist/combobox/intl/index.d.ts +2 -2
  262. package/dist/combobox/intl/index.d.ts.map +1 -1
  263. package/dist/datepicker/createDateField.d.ts +45 -23
  264. package/dist/datepicker/createDateField.d.ts.map +1 -1
  265. package/dist/datepicker/createDatePicker.d.ts +34 -6
  266. package/dist/datepicker/createDatePicker.d.ts.map +1 -1
  267. package/dist/datepicker/createDatePickerGroup.d.ts +13 -13
  268. package/dist/datepicker/createDatePickerGroup.d.ts.map +1 -1
  269. package/dist/datepicker/createDateRangePicker.d.ts +55 -7
  270. package/dist/datepicker/createDateRangePicker.d.ts.map +1 -1
  271. package/dist/datepicker/createDateSegment.d.ts +6 -15
  272. package/dist/datepicker/createDateSegment.d.ts.map +1 -1
  273. package/dist/datepicker/createDisplayNames.d.ts +17 -0
  274. package/dist/datepicker/createDisplayNames.d.ts.map +1 -0
  275. package/dist/datepicker/createTimeField.d.ts +12 -49
  276. package/dist/datepicker/createTimeField.d.ts.map +1 -1
  277. package/dist/datepicker/index.d.ts +3 -3
  278. package/dist/datepicker/index.d.ts.map +1 -1
  279. package/dist/datepicker/index.js +2 -2
  280. package/dist/datepicker/index.jsx +2 -2
  281. package/dist/datepicker/intl.d.ts +12 -0
  282. package/dist/datepicker/intl.d.ts.map +1 -0
  283. package/dist/dnd/DragManager.d.ts +86 -0
  284. package/dist/dnd/DragManager.d.ts.map +1 -0
  285. package/dist/dnd/DropTargetKeyboardNavigation.d.ts +42 -0
  286. package/dist/dnd/DropTargetKeyboardNavigation.d.ts.map +1 -0
  287. package/dist/dnd/createDrag.d.ts.map +1 -1
  288. package/dist/dnd/createDraggableCollection.d.ts.map +1 -1
  289. package/dist/dnd/createDraggableItem.d.ts +12 -7
  290. package/dist/dnd/createDraggableItem.d.ts.map +1 -1
  291. package/dist/dnd/createDroppableCollection.d.ts +7 -15
  292. package/dist/dnd/createDroppableCollection.d.ts.map +1 -1
  293. package/dist/dnd/index.d.ts +5 -1
  294. package/dist/dnd/index.d.ts.map +1 -1
  295. package/dist/dnd/index.js +3 -2
  296. package/dist/dnd/index.jsx +3 -2
  297. package/dist/dnd/intl/index.d.ts +39 -0
  298. package/dist/dnd/intl/index.d.ts.map +1 -0
  299. package/dist/dnd/utils.d.ts +5 -0
  300. package/dist/dnd/utils.d.ts.map +1 -1
  301. package/dist/focus/FocusScope.d.ts +7 -0
  302. package/dist/focus/FocusScope.d.ts.map +1 -1
  303. package/dist/focus/index.d.ts +2 -1
  304. package/dist/focus/index.d.ts.map +1 -1
  305. package/dist/focus/index.js +3 -2
  306. package/dist/focus/index.jsx +3 -2
  307. package/dist/focus/virtualFocus.d.ts +26 -0
  308. package/dist/focus/virtualFocus.d.ts.map +1 -0
  309. package/dist/form/index.js +1 -1
  310. package/dist/form/index.jsx +1 -1
  311. package/dist/gridlist/createGridList.d.ts.map +1 -1
  312. package/dist/i18n/index.js +4 -2
  313. package/dist/i18n/index.jsx +4 -2
  314. package/dist/index.d.ts +3 -3
  315. package/dist/index.d.ts.map +1 -1
  316. package/dist/index.js +18 -12
  317. package/dist/index.jsx +18 -12
  318. package/dist/interactions/FocusableProvider.d.ts.map +1 -1
  319. package/dist/interactions/createFocus.d.ts.map +1 -1
  320. package/dist/interactions/createFocusWithin.d.ts.map +1 -1
  321. package/dist/interactions/createInteractionModality.d.ts.map +1 -1
  322. package/dist/interactions/index.js +1 -2
  323. package/dist/interactions/index.jsx +1 -2
  324. package/dist/label/createLabels.d.ts.map +1 -1
  325. package/dist/listbox/createListBox.d.ts.map +1 -1
  326. package/dist/listbox/createOption.d.ts +1 -1
  327. package/dist/listbox/createOption.d.ts.map +1 -1
  328. package/dist/live-announcer/index.js +1 -1
  329. package/dist/live-announcer/index.jsx +1 -1
  330. package/dist/select/createSelect.d.ts +2 -0
  331. package/dist/select/createSelect.d.ts.map +1 -1
  332. package/dist/selection/createSelectableItem.d.ts.map +1 -1
  333. package/dist/selection/index.js +2 -1
  334. package/dist/selection/index.jsx +2 -1
  335. package/dist/spinbutton/createSpinButton.d.ts +41 -0
  336. package/dist/spinbutton/createSpinButton.d.ts.map +1 -0
  337. package/dist/spinbutton/index.d.ts +3 -0
  338. package/dist/spinbutton/index.d.ts.map +1 -0
  339. package/dist/spinbutton/index.js +2 -0
  340. package/dist/spinbutton/index.jsx +2 -0
  341. package/dist/spinbutton/intl.d.ts +5 -0
  342. package/dist/spinbutton/intl.d.ts.map +1 -0
  343. package/dist/table/createTable.d.ts.map +1 -1
  344. package/dist/table/createTableColumnHeader.d.ts.map +1 -1
  345. package/dist/table/createTableRow.d.ts.map +1 -1
  346. package/dist/table/createTableSelectionCheckbox.d.ts.map +1 -1
  347. package/dist/table/types.d.ts +8 -0
  348. package/dist/table/types.d.ts.map +1 -1
  349. package/dist/table/utils.d.ts +15 -0
  350. package/dist/table/utils.d.ts.map +1 -0
  351. package/dist/tabs/createTabs.d.ts +1 -0
  352. package/dist/tabs/createTabs.d.ts.map +1 -1
  353. package/dist/tag/createTag.d.ts.map +1 -1
  354. package/dist/tag/createTagGroup.d.ts +7 -0
  355. package/dist/tag/createTagGroup.d.ts.map +1 -1
  356. package/dist/toolbar/createToolbar.d.ts.map +1 -1
  357. package/dist/tree/createTree.d.ts.map +1 -1
  358. package/dist/tree/createTreeSelectionCheckbox.d.ts.map +1 -1
  359. package/dist/utils/animation.d.ts.map +1 -1
  360. package/dist/utils/dom.d.ts +1 -0
  361. package/dist/utils/dom.d.ts.map +1 -1
  362. package/dist/utils/index.d.ts +1 -1
  363. package/dist/utils/index.d.ts.map +1 -1
  364. package/dist/utils/index.js +4 -3
  365. package/dist/utils/index.jsx +4 -3
  366. package/package.json +2 -2
  367. package/src/actiongroup/createActionGroup.ts +26 -109
  368. package/src/autocomplete/createAutocomplete.ts +136 -15
  369. package/src/breadcrumbs/createBreadcrumbs.ts +12 -4
  370. package/src/button/createToggleButtonGroup.ts +19 -14
  371. package/src/calendar/createCalendar.ts +3 -4
  372. package/src/calendar/createCalendarCell.ts +17 -3
  373. package/src/calendar/createCalendarGrid.ts +5 -4
  374. package/src/calendar/createRangeCalendar.ts +27 -17
  375. package/src/calendar/createRangeCalendarCell.ts +17 -3
  376. package/src/calendar/intl/index.ts +8 -0
  377. package/src/color/createColorArea.ts +17 -10
  378. package/src/color/createColorField.ts +8 -1
  379. package/src/color/createColorSlider.ts +1 -2
  380. package/src/color/createColorSwatch.ts +4 -2
  381. package/src/color/createColorWheel.ts +0 -6
  382. package/src/color/intl/index.ts +316 -0
  383. package/src/combobox/createComboBox.ts +35 -4
  384. package/src/combobox/intl/generated-locales.ts +635 -0
  385. package/src/combobox/intl/index.ts +8 -2
  386. package/src/datepicker/createDateField.ts +228 -213
  387. package/src/datepicker/createDatePicker.ts +157 -146
  388. package/src/datepicker/createDatePickerGroup.ts +88 -82
  389. package/src/datepicker/createDateRangePicker.ts +230 -179
  390. package/src/datepicker/createDateSegment.ts +386 -389
  391. package/src/datepicker/createDisplayNames.ts +45 -0
  392. package/src/datepicker/createTimeField.ts +36 -129
  393. package/src/datepicker/index.ts +13 -14
  394. package/src/datepicker/intl.ts +633 -0
  395. package/src/dnd/DragManager.ts +693 -0
  396. package/src/dnd/DropTargetKeyboardNavigation.ts +337 -0
  397. package/src/dnd/createDrag.ts +31 -5
  398. package/src/dnd/createDraggableCollection.ts +33 -15
  399. package/src/dnd/createDraggableItem.ts +92 -5
  400. package/src/dnd/createDroppableCollection.ts +487 -373
  401. package/src/dnd/index.ts +11 -0
  402. package/src/dnd/intl/ar-AE.json +29 -0
  403. package/src/dnd/intl/bg-BG.json +29 -0
  404. package/src/dnd/intl/cs-CZ.json +29 -0
  405. package/src/dnd/intl/da-DK.json +29 -0
  406. package/src/dnd/intl/de-DE.json +29 -0
  407. package/src/dnd/intl/el-GR.json +29 -0
  408. package/src/dnd/intl/en-US.json +29 -0
  409. package/src/dnd/intl/es-ES.json +29 -0
  410. package/src/dnd/intl/et-EE.json +29 -0
  411. package/src/dnd/intl/fi-FI.json +29 -0
  412. package/src/dnd/intl/fr-FR.json +29 -0
  413. package/src/dnd/intl/he-IL.json +29 -0
  414. package/src/dnd/intl/hr-HR.json +29 -0
  415. package/src/dnd/intl/hu-HU.json +29 -0
  416. package/src/dnd/intl/index.ts +139 -0
  417. package/src/dnd/intl/it-IT.json +29 -0
  418. package/src/dnd/intl/ja-JP.json +29 -0
  419. package/src/dnd/intl/ko-KR.json +29 -0
  420. package/src/dnd/intl/lt-LT.json +29 -0
  421. package/src/dnd/intl/lv-LV.json +29 -0
  422. package/src/dnd/intl/nb-NO.json +29 -0
  423. package/src/dnd/intl/nl-NL.json +29 -0
  424. package/src/dnd/intl/pl-PL.json +29 -0
  425. package/src/dnd/intl/pt-BR.json +29 -0
  426. package/src/dnd/intl/pt-PT.json +29 -0
  427. package/src/dnd/intl/ro-RO.json +29 -0
  428. package/src/dnd/intl/ru-RU.json +29 -0
  429. package/src/dnd/intl/sk-SK.json +29 -0
  430. package/src/dnd/intl/sl-SI.json +29 -0
  431. package/src/dnd/intl/sr-SP.json +29 -0
  432. package/src/dnd/intl/sv-SE.json +29 -0
  433. package/src/dnd/intl/tr-TR.json +29 -0
  434. package/src/dnd/intl/uk-UA.json +29 -0
  435. package/src/dnd/intl/zh-CN.json +29 -0
  436. package/src/dnd/intl/zh-TW.json +29 -0
  437. package/src/dnd/utils.ts +36 -0
  438. package/src/focus/FocusScope.tsx +120 -12
  439. package/src/focus/index.ts +8 -0
  440. package/src/focus/virtualFocus.ts +55 -0
  441. package/src/gridlist/createGridList.ts +52 -16
  442. package/src/index.ts +11 -3
  443. package/src/interactions/FocusableProvider.tsx +11 -6
  444. package/src/interactions/createFocus.ts +26 -21
  445. package/src/interactions/createFocusWithin.ts +23 -24
  446. package/src/interactions/createInteractionModality.ts +5 -3
  447. package/src/label/createLabels.ts +7 -4
  448. package/src/listbox/createListBox.ts +74 -2
  449. package/src/listbox/createOption.ts +16 -1
  450. package/src/select/createSelect.ts +23 -2
  451. package/src/selection/createSelectableItem.ts +14 -0
  452. package/src/spinbutton/createSpinButton.ts +163 -0
  453. package/src/spinbutton/index.ts +10 -0
  454. package/src/spinbutton/intl.ts +115 -0
  455. package/src/table/createTable.ts +26 -1
  456. package/src/table/createTableColumnHeader.ts +10 -0
  457. package/src/table/createTableRow.ts +10 -0
  458. package/src/table/createTableSelectionCheckbox.ts +24 -1
  459. package/src/table/types.ts +8 -0
  460. package/src/table/utils.ts +41 -0
  461. package/src/tabs/createTabs.ts +53 -12
  462. package/src/tag/createTag.ts +21 -32
  463. package/src/tag/createTagGroup.ts +92 -0
  464. package/src/toolbar/createToolbar.ts +6 -58
  465. package/src/tree/createTree.ts +69 -14
  466. package/src/tree/createTreeSelectionCheckbox.ts +14 -1
  467. package/src/utils/animation.ts +119 -27
  468. package/src/utils/dom.ts +3 -2
  469. package/src/utils/index.ts +2 -0
  470. package/dist/_chunk/createLongPress.js +0 -91
  471. package/dist/_chunk/createLongPress.js.map +0 -1
  472. package/dist/_chunk/createLongPress.jsx +0 -91
  473. package/dist/_chunk/createLongPress.jsx.map +0 -1
  474. package/dist/_chunk/form.js.map +0 -1
  475. package/dist/_chunk/form.jsx.map +0 -1
  476. package/dist/_chunk/live-announcer.js.map +0 -1
  477. package/dist/_chunk/live-announcer.jsx.map +0 -1
  478. package/dist/datepicker/createTimeSegment.d.ts +0 -29
  479. package/dist/datepicker/createTimeSegment.d.ts.map +0 -1
  480. package/src/datepicker/createTimeSegment.ts +0 -352
@@ -1 +1 @@
1
- {"version":3,"file":"tree.jsx","names":[],"sources":["../../src/tree/createTree.ts","../../src/tree/createTreeItem.ts","../../src/tree/createTreeSelectionCheckbox.ts"],"sourcesContent":["/**\n * createTree - Provides accessibility for a tree component.\n * Based on @react-aria/tree/useTree.\n */\n\nimport { createEffect, createMemo, type Accessor } from \"solid-js\";\nimport type { JSX } from \"solid-js\";\nimport { createId } from \"@proyecto-viviana/solid-stately\";\nimport type { TreeState, TreeCollection, Key } from \"@proyecto-viviana/solid-stately\";\nimport type { AriaTreeProps, TreeAria } from \"./types\";\nimport { scrollIntoViewport } from \"../utils\";\nimport { getInteractionModality } from \"../interactions/createInteractionModality\";\n\n/**\n * Metadata stored for a tree instance.\n */\ninterface TreeData {\n /** The generated ID for the tree. */\n treeId: string;\n /** How keyboard navigation behaves within row children. */\n keyboardNavigationBehavior: \"arrow\" | \"tab\";\n /** Text direction for row-child arrow navigation and tree expansion keys. */\n direction: \"ltr\" | \"rtl\";\n /** Actions registered for the tree. */\n actions: {\n onAction?: (key: Key) => void;\n };\n}\n\n/**\n * WeakMap to store tree data for child components to access.\n */\nconst treeDataMap = new WeakMap<object, TreeData>();\n\n/**\n * Gets the tree data for a given state.\n */\nexport function getTreeData<T extends object, C extends TreeCollection<T>>(\n state: TreeState<T, C>,\n): TreeData | undefined {\n return treeDataMap.get(state);\n}\n\n/**\n * Whether a key should be skipped during keyboard navigation. Disabled keys only\n * block navigation under `disabledBehavior: \"all\"` (the default); under\n * `\"selection\"` they remain focusable (selection is still blocked elsewhere).\n * Mirrors `ListKeyboardDelegate.isDisabled` in React Aria.\n */\nfunction isNavigationDisabled<T extends object, C extends TreeCollection<T>>(\n state: TreeState<T, C>,\n key: Key,\n): boolean {\n return state.isDisabled(key) && state.disabledBehavior === \"all\";\n}\n\n/**\n * Walks from `startKey` via `step` until reaching a key that is navigable (not\n * disabled for navigation), mirroring React Aria's\n * `ListKeyboardDelegate.findNextNonDisabled`. `getFirstKey`/`getLastKey` and the\n * next/previous lookups all funnel through this so arrow keys, Home and End land\n * on enabled rows only.\n */\nfunction findNextNavigableKey<T extends object, C extends TreeCollection<T>>(\n state: TreeState<T, C>,\n startKey: Key | null,\n step: (key: Key) => Key | null,\n): Key | null {\n let key = startKey;\n while (key != null && isNavigationDisabled(state, key)) {\n key = step(key);\n }\n return key;\n}\n\n/**\n * Creates accessibility props for a tree.\n */\nexport function createTree<T extends object, C extends TreeCollection<T> = TreeCollection<T>>(\n props: Accessor<AriaTreeProps>,\n state: Accessor<TreeState<T, C>>,\n ref: Accessor<HTMLDivElement | null>,\n): TreeAria {\n // Generate a unique ID for the tree\n const treeId = props().id ?? createId();\n\n // Store tree data for child components\n const treeData: TreeData = {\n treeId,\n get keyboardNavigationBehavior() {\n return props().keyboardNavigationBehavior ?? \"arrow\";\n },\n get direction() {\n return props().direction ?? \"ltr\";\n },\n actions: {\n get onAction() {\n return props().onAction;\n },\n },\n };\n\n // Store in WeakMap using the state as key\n treeDataMap.set(state(), treeData);\n\n // Handle keyboard navigation\n const onKeyDown = (e: KeyboardEvent) => {\n const s = state();\n const p = props();\n const collection = s.collection;\n const focusedKey = s.focusedKey;\n const direction = p.direction ?? \"ltr\";\n // In RTL, ArrowLeft expands and ArrowRight collapses (opposite of LTR)\n const expandKey = direction === \"rtl\" ? \"ArrowLeft\" : \"ArrowRight\";\n const collapseKey = direction === \"rtl\" ? \"ArrowRight\" : \"ArrowLeft\";\n\n if (p.isDisabled) return;\n\n switch (e.key) {\n case \"ArrowDown\": {\n e.preventDefault();\n const nextKey =\n focusedKey != null\n ? findNextNavigableKey(s, collection.getKeyAfter(focusedKey), (k) =>\n collection.getKeyAfter(k),\n )\n : findNextNavigableKey(s, collection.getFirstKey(), (k) => collection.getKeyAfter(k));\n if (nextKey != null) {\n s.setFocusedKey(nextKey);\n }\n break;\n }\n case \"ArrowUp\": {\n e.preventDefault();\n const prevKey =\n focusedKey != null\n ? findNextNavigableKey(s, collection.getKeyBefore(focusedKey), (k) =>\n collection.getKeyBefore(k),\n )\n : findNextNavigableKey(s, collection.getLastKey(), (k) => collection.getKeyBefore(k));\n if (prevKey != null) {\n s.setFocusedKey(prevKey);\n }\n break;\n }\n case \"ArrowRight\":\n case \"ArrowLeft\": {\n e.preventDefault();\n if (focusedKey != null) {\n const node = collection.getItem(focusedKey);\n if (e.key === expandKey) {\n // Expand or move to first child\n if (node?.isExpandable) {\n if (!s.isExpanded(focusedKey)) {\n s.expandKey(focusedKey);\n } else {\n const children = [...collection.getChildren(focusedKey)];\n if (children.length > 0) {\n s.setFocusedKey(children[0].key);\n }\n }\n }\n } else if (e.key === collapseKey) {\n // Collapse or move to parent\n if (node?.isExpandable && s.isExpanded(focusedKey)) {\n s.collapseKey(focusedKey);\n } else if (node?.parentKey != null) {\n s.setFocusedKey(node.parentKey);\n }\n }\n }\n break;\n }\n case \"Home\": {\n e.preventDefault();\n const firstKey = findNextNavigableKey(s, collection.getFirstKey(), (k) =>\n collection.getKeyAfter(k),\n );\n if (firstKey != null) {\n s.setFocusedKey(firstKey);\n }\n break;\n }\n case \"End\": {\n e.preventDefault();\n const lastKey = findNextNavigableKey(s, collection.getLastKey(), (k) =>\n collection.getKeyBefore(k),\n );\n if (lastKey != null) {\n s.setFocusedKey(lastKey);\n }\n break;\n }\n case \"a\":\n case \"A\": {\n if ((e.ctrlKey || e.metaKey) && s.selectionMode === \"multiple\") {\n e.preventDefault();\n s.selectAll();\n }\n break;\n }\n // Space (selection) and Enter (action) are intentionally absent here.\n // Upstream's useSelectableCollection leaves activation to useSelectableItem.\n // The focus effect below moves DOM focus onto the focused row, so the row's\n // own createSelectableItem handlers receive those keys without duplicating\n // work in the bubbling tree handler.\n case \"Escape\": {\n if (s.selectionMode !== \"none\") {\n e.preventDefault();\n s.clearSelection();\n }\n break;\n }\n case \"*\": {\n // Expand all siblings at current level\n e.preventDefault();\n if (focusedKey != null) {\n const node = collection.getItem(focusedKey);\n if (node) {\n // Find all siblings at the same level\n const parentKey = node.parentKey;\n let siblings: Key[];\n if (parentKey != null) {\n siblings = [...collection.getChildren(parentKey)].map((n) => n.key);\n } else {\n // Root level siblings\n siblings = collection.rows.filter((n) => n.level === 0).map((n) => n.key);\n }\n // Expand all expandable siblings\n for (const siblingKey of siblings) {\n const sibling = collection.getItem(siblingKey);\n if (sibling?.isExpandable && !s.isExpanded(siblingKey)) {\n s.expandKey(siblingKey);\n }\n }\n }\n }\n break;\n }\n }\n };\n\n const onFocus = () => {\n const s = state();\n s.setFocused(true);\n\n // If nothing is focused, focus the first navigable item\n if (s.focusedKey == null) {\n const firstKey = findNextNavigableKey(s, s.collection.getFirstKey(), (k) =>\n s.collection.getKeyAfter(k),\n );\n if (firstKey != null) {\n s.setFocusedKey(firstKey);\n }\n }\n };\n\n const onBlur = () => {\n const s = state();\n s.setFocused(false);\n };\n\n createEffect(() => {\n const s = state();\n const key = s.focusedKey;\n const el = ref();\n if (!el || key == null) {\n return;\n }\n\n const active = document.activeElement;\n if (!active || (active !== el && !el.contains(active))) {\n return;\n }\n\n const target = el.querySelector<HTMLElement>(`[data-key=\"${key}\"]`);\n if (target && target !== active) {\n target.focus();\n\n if (getInteractionModality() !== \"pointer\") {\n scrollIntoViewport(target, { containingElement: el });\n }\n }\n });\n\n const treeProps = createMemo(() => {\n const p = props();\n const s = state();\n\n const baseProps: Record<string, unknown> = {\n role: \"treegrid\",\n id: treeId,\n \"aria-label\": p[\"aria-label\"],\n \"aria-labelledby\": p[\"aria-labelledby\"],\n \"aria-describedby\": p[\"aria-describedby\"],\n \"aria-multiselectable\": s.selectionMode === \"multiple\" ? true : undefined,\n \"aria-disabled\": p.isDisabled || undefined,\n tabIndex: p.isDisabled ? undefined : 0,\n onKeyDown,\n onFocus,\n onBlur,\n };\n\n // Add row count for virtualized trees\n if (p.isVirtualized) {\n baseProps[\"aria-rowcount\"] = s.collection.rowCount;\n }\n\n return baseProps as JSX.HTMLAttributes<HTMLDivElement>;\n });\n\n return {\n get treeProps() {\n return treeProps();\n },\n };\n}\n","/**\n * createTreeItem - Provides accessibility for a tree item.\n * Based on @react-aria/tree/useTreeItem.\n */\n\nimport { createMemo, type Accessor } from \"solid-js\";\nimport type { JSX } from \"solid-js\";\nimport { createId } from \"@proyecto-viviana/solid-stately\";\nimport type {\n Collection,\n Key,\n Selection,\n TreeState,\n TreeCollection,\n} from \"@proyecto-viviana/solid-stately\";\nimport type { AriaTreeItemProps, TreeItemAria } from \"./types\";\nimport { getTreeData } from \"./createTree\";\nimport { createSelectableItem, type SelectableItemState } from \"../selection/createSelectableItem\";\nimport { mergeCollectionRowInteractionProps } from \"../selection/createCollectionRowInteraction\";\nimport { mergeProps } from \"../utils/mergeProps\";\n\n/**\n * Creates accessibility props for a tree item.\n */\nexport function createTreeItem<T extends object, C extends TreeCollection<T> = TreeCollection<T>>(\n props: Accessor<AriaTreeItemProps<T>>,\n state: Accessor<TreeState<T, C>>,\n ref: Accessor<HTMLElement | null>,\n): TreeItemAria {\n const fallbackRowId = createId();\n const expandButtonId = createId();\n\n const rowId = createMemo(() => {\n const treeData = getTreeData(state());\n return treeData ? `${treeData.treeId}-row-${String(props().node.key)}` : fallbackRowId;\n });\n\n const isSelected = createMemo(() => {\n const s = state();\n const p = props();\n return s.isSelected(p.node.key);\n });\n\n const isExpanded = createMemo(() => {\n const s = state();\n const p = props();\n return s.isExpanded(p.node.key);\n });\n\n const isExpandable = createMemo(() => {\n const p = props();\n return p.node.isExpandable ?? false;\n });\n\n const level = createMemo(() => {\n const p = props();\n return p.node.level;\n });\n\n const selectableState: SelectableItemState<T> = {\n collection: () => state().collection as unknown as Collection<T>,\n isFocused: () => state().isFocused,\n setFocused: (focused: boolean) => state().setFocused(focused),\n focusedKey: () => state().focusedKey,\n childFocusStrategy: () => state().childFocusStrategy,\n setFocusedKey: (key: Key | null, strategy) => state().setFocusedKey(key, strategy),\n selectionMode: () => state().selectionMode,\n selectionBehavior: () => props().selectionBehavior ?? state().selectionBehavior,\n disallowEmptySelection: () => state().disallowEmptySelection,\n selectedKeys: () => state().selectedKeys as Selection,\n disabledKeys: () => state().disabledKeys,\n disabledBehavior: () => state().disabledBehavior,\n isEmpty: () => {\n const keys = state().selectedKeys;\n return keys !== \"all\" && keys.size === 0;\n },\n isSelectAll: () => state().selectedKeys === \"all\",\n isSelected: (key: Key) => state().isSelected(key),\n isDisabled: (key: Key) => {\n const s = state();\n const item = s.collection.getItem(key);\n return (\n s.disabledBehavior === \"all\" &&\n s.isDisabled(key) &&\n item?.props?.disabledBehavior !== \"selection\"\n );\n },\n canSelectItem: (key: Key) => {\n const s = state();\n return s.selectionMode !== \"none\" && !s.isDisabled(key);\n },\n setSelectionBehavior: (behavior) => state().setSelectionBehavior(behavior),\n toggleSelection: (key: Key) => state().toggleSelection(key),\n replaceSelection: (key: Key) => state().replaceSelection(key),\n setSelectedKeys: (keys: Iterable<Key>) => state().setSelectedKeys(keys),\n selectAll: () => state().selectAll(),\n clearSelection: () => state().clearSelection(),\n toggleSelectAll: () => state().toggleSelectAll(),\n extendSelection: (toKey: Key, _collection: Collection<T>) => state().extendSelection(toKey),\n };\n\n const selectableItem = createSelectableItem<T>(\n () => {\n const s = state();\n const p = props();\n const treeData = getTreeData(s);\n const treeAction = treeData?.actions.onAction;\n const shouldToggleOnAction =\n !treeAction && !p.onAction && s.selectionMode === \"none\" && isExpandable();\n\n return {\n key: p.node.key,\n id: rowId(),\n isVirtualized: p.isVirtualized,\n isDisabled: p.isDisabled,\n onAction:\n treeAction || p.onAction || shouldToggleOnAction\n ? () => {\n p.onAction?.();\n treeAction?.(p.node.key);\n if (shouldToggleOnAction) {\n s.toggleKey(p.node.key);\n }\n }\n : undefined,\n };\n },\n selectableState,\n ref,\n );\n\n // Compute sibling position (aria-posinset/aria-setsize)\n const siblingInfo = createMemo(() => {\n const s = state();\n const p = props();\n const node = p.node;\n const parentKey = node.parentKey;\n\n if (parentKey != null) {\n const parentNode = s.collection.getItem(parentKey);\n if (parentNode) {\n return {\n posinset: node.index + 1, // 1-based\n setsize: parentNode.childNodes.length,\n };\n }\n }\n\n // Root-level: count root nodes\n const rootNodes = s.collection.rows.filter((n) => n.level === 0);\n const rootIndex = rootNodes.findIndex((n) => n.key === node.key);\n return {\n posinset: rootIndex >= 0 ? rootIndex + 1 : node.index + 1,\n setsize: rootNodes.length,\n };\n });\n\n const rowProps = createMemo(() => {\n const p = props();\n const node = p.node;\n const { posinset, setsize } = siblingInfo();\n\n // Use textValue for aria-label (if available), or explicit textValue prop\n const textValue = p.textValue ?? node.textValue;\n\n const baseProps: Record<string, unknown> = {\n role: \"row\",\n \"aria-label\": textValue || undefined,\n \"aria-selected\": selectableState.canSelectItem?.(node.key) ? isSelected() : undefined,\n \"aria-disabled\": selectableItem.isDisabled() || undefined,\n \"aria-expanded\": isExpandable() ? isExpanded() : undefined,\n \"aria-level\": node.level + 1, // 1-based for ARIA\n \"aria-posinset\": posinset,\n \"aria-setsize\": setsize,\n };\n\n // Add aria-rowindex for virtualized trees\n if (p.isVirtualized && node.rowIndex != null) {\n baseProps[\"aria-rowindex\"] = node.rowIndex + 1; // 1-based\n }\n\n const treeData = getTreeData(state());\n const mergedProps = mergeProps<JSX.HTMLAttributes<HTMLDivElement>>(\n selectableItem.itemProps,\n baseProps,\n );\n\n return mergeCollectionRowInteractionProps(mergedProps, {\n ref,\n keyboardNavigationBehavior: () => treeData?.keyboardNavigationBehavior ?? \"arrow\",\n direction: () => treeData?.direction ?? \"ltr\",\n });\n });\n\n const gridCellProps = createMemo(() => {\n return {\n role: \"gridcell\",\n \"aria-colindex\": 1,\n } as JSX.HTMLAttributes<HTMLDivElement>;\n });\n\n // Expand button handler\n const onExpandClick = (e: MouseEvent) => {\n e.stopPropagation(); // Don't trigger row click\n const s = state();\n const p = props();\n\n if (selectableItem.isDisabled()) return;\n\n s.toggleKey(p.node.key);\n };\n\n const stopPointerPropagation = (e: Event) => {\n // Prevent row pointer handlers from flipping pressed state and re-rendering\n // before the button click handler can run.\n e.stopPropagation();\n };\n\n const expandButtonProps = createMemo(() => {\n const baseProps: Record<string, unknown> = {\n type: \"button\",\n id: expandButtonId,\n \"aria-label\": isExpanded() ? \"Collapse\" : \"Expand\",\n \"aria-labelledby\": isExpandable() ? `${expandButtonId} ${rowId()}` : undefined,\n \"data-react-aria-prevent-focus\": true,\n onClick: onExpandClick,\n onPointerDown: stopPointerPropagation,\n onPointerUp: stopPointerPropagation,\n onMouseDown: stopPointerPropagation,\n onMouseUp: stopPointerPropagation,\n tabIndex: -1, // Not in tab order, use arrow keys\n \"aria-hidden\": !isExpandable() ? true : undefined,\n };\n\n return baseProps as JSX.ButtonHTMLAttributes<HTMLButtonElement>;\n });\n\n return {\n get rowProps() {\n return rowProps();\n },\n get gridCellProps() {\n return gridCellProps();\n },\n get expandButtonProps() {\n return expandButtonProps();\n },\n get isSelected() {\n return isSelected();\n },\n get isDisabled() {\n return selectableItem.isDisabled();\n },\n get isPressed() {\n return selectableItem.isPressed();\n },\n get isExpanded() {\n return isExpanded();\n },\n get isExpandable() {\n return isExpandable();\n },\n get level() {\n return level();\n },\n };\n}\n","/**\n * createTreeSelectionCheckbox - Provides accessibility for a tree item's selection checkbox.\n * Based on @react-aria/gridlist/useGridListSelectionCheckbox.\n */\n\nimport { createMemo, type Accessor } from \"solid-js\";\nimport type { JSX } from \"solid-js\";\nimport type { TreeState, TreeCollection } from \"@proyecto-viviana/solid-stately\";\nimport type { AriaTreeSelectionCheckboxProps, TreeSelectionCheckboxAria } from \"./types\";\n\n/**\n * Creates accessibility props for a tree selection checkbox.\n */\nexport function createTreeSelectionCheckbox<\n T extends object,\n C extends TreeCollection<T> = TreeCollection<T>,\n>(\n props: Accessor<AriaTreeSelectionCheckboxProps>,\n state: Accessor<TreeState<T, C>>,\n): TreeSelectionCheckboxAria {\n const isSelected = createMemo(() => {\n const s = state();\n const p = props();\n return s.isSelected(p.key);\n });\n\n const isDisabled = createMemo(() => {\n const s = state();\n const p = props();\n return s.isDisabled(p.key);\n });\n\n const onChange = (e: Event) => {\n const s = state();\n const p = props();\n const target = e.target as HTMLInputElement;\n\n if (isDisabled()) return;\n\n if (target.checked) {\n s.toggleSelection(p.key);\n } else {\n s.toggleSelection(p.key);\n }\n };\n\n const onClick = (e: MouseEvent) => {\n // Stop propagation to prevent row click from also firing\n e.stopPropagation();\n };\n\n const checkboxProps = createMemo(() => {\n const baseProps: Record<string, unknown> = {\n type: \"checkbox\",\n \"aria-label\": \"Select\",\n checked: isSelected(),\n disabled: isDisabled(),\n onChange,\n onClick,\n tabIndex: -1, // Use arrow keys to navigate, not tab\n };\n\n return baseProps as JSX.InputHTMLAttributes<HTMLInputElement>;\n });\n\n return {\n get checkboxProps() {\n return checkboxProps();\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tree.jsx","names":["mergeProps"],"sources":["../../src/tree/createTree.ts","../../src/tree/createTreeItem.ts","../../src/tree/createTreeSelectionCheckbox.ts"],"sourcesContent":["/**\n * createTree - Provides accessibility for a tree component.\n * Based on @react-aria/tree/useTree.\n */\n\nimport { createEffect, createMemo, type Accessor } from \"solid-js\";\nimport type { JSX } from \"solid-js\";\nimport { createId } from \"@proyecto-viviana/solid-stately\";\nimport type { TreeState, TreeCollection, Key } from \"@proyecto-viviana/solid-stately\";\nimport type { AriaTreeProps, TreeAria } from \"./types\";\nimport { scrollIntoViewport } from \"../utils\";\nimport { getInteractionModality } from \"../interactions/createInteractionModality\";\n\n/**\n * Metadata stored for a tree instance.\n */\ninterface TreeData {\n /** The generated ID for the tree. */\n treeId: string;\n /** How keyboard navigation behaves within row children. */\n keyboardNavigationBehavior: \"arrow\" | \"tab\";\n /** Text direction for row-child arrow navigation and tree expansion keys. */\n direction: \"ltr\" | \"rtl\";\n /** Actions registered for the tree. */\n actions: {\n onAction?: (key: Key) => void;\n };\n}\n\n/**\n * WeakMap to store tree data for child components to access.\n */\nconst treeDataMap = new WeakMap<object, TreeData>();\n\n/**\n * Gets the tree data for a given state.\n */\nexport function getTreeData<T extends object, C extends TreeCollection<T>>(\n state: TreeState<T, C>,\n): TreeData | undefined {\n return treeDataMap.get(state);\n}\n\n/**\n * Whether a key should be skipped during keyboard navigation. Disabled keys only\n * block navigation under `disabledBehavior: \"all\"` (the default); under\n * `\"selection\"` they remain focusable (selection is still blocked elsewhere).\n * Mirrors `ListKeyboardDelegate.isDisabled` in React Aria.\n */\nfunction isNavigationDisabled<T extends object, C extends TreeCollection<T>>(\n state: TreeState<T, C>,\n key: Key,\n): boolean {\n return state.isDisabled(key) && state.disabledBehavior === \"all\";\n}\n\n/**\n * Walks from `startKey` via `step` until reaching a key that is navigable (not\n * disabled for navigation), mirroring React Aria's\n * `ListKeyboardDelegate.findNextNonDisabled`. `getFirstKey`/`getLastKey` and the\n * next/previous lookups all funnel through this so arrow keys, Home and End land\n * on enabled rows only.\n */\nfunction findNextNavigableKey<T extends object, C extends TreeCollection<T>>(\n state: TreeState<T, C>,\n startKey: Key | null,\n step: (key: Key) => Key | null,\n): Key | null {\n let key = startKey;\n while (key != null && isNavigationDisabled(state, key)) {\n key = step(key);\n }\n return key;\n}\n\n/**\n * Creates accessibility props for a tree.\n */\nexport function createTree<T extends object, C extends TreeCollection<T> = TreeCollection<T>>(\n props: Accessor<AriaTreeProps>,\n state: Accessor<TreeState<T, C>>,\n ref: Accessor<HTMLDivElement | null>,\n): TreeAria {\n // Generate a unique ID for the tree\n const treeId = props().id ?? createId();\n\n // Store tree data for child components\n const treeData: TreeData = {\n treeId,\n get keyboardNavigationBehavior() {\n return props().keyboardNavigationBehavior ?? \"arrow\";\n },\n get direction() {\n return props().direction ?? \"ltr\";\n },\n actions: {\n get onAction() {\n return props().onAction;\n },\n },\n };\n\n // Store in WeakMap using the state as key\n treeDataMap.set(state(), treeData);\n\n // Handle keyboard navigation\n const onKeyDown = (e: KeyboardEvent) => {\n const s = state();\n const p = props();\n const collection = s.collection;\n const focusedKey = s.focusedKey;\n const direction = p.direction ?? \"ltr\";\n // In RTL, ArrowLeft expands and ArrowRight collapses (opposite of LTR)\n const expandKey = direction === \"rtl\" ? \"ArrowLeft\" : \"ArrowRight\";\n const collapseKey = direction === \"rtl\" ? \"ArrowRight\" : \"ArrowLeft\";\n\n if (p.isDisabled) return;\n\n switch (e.key) {\n case \"ArrowDown\": {\n e.preventDefault();\n const nextKey =\n focusedKey != null\n ? findNextNavigableKey(s, collection.getKeyAfter(focusedKey), (k) =>\n collection.getKeyAfter(k),\n )\n : findNextNavigableKey(s, collection.getFirstKey(), (k) => collection.getKeyAfter(k));\n if (nextKey != null) {\n s.setFocusedKey(nextKey);\n }\n break;\n }\n case \"ArrowUp\": {\n e.preventDefault();\n const prevKey =\n focusedKey != null\n ? findNextNavigableKey(s, collection.getKeyBefore(focusedKey), (k) =>\n collection.getKeyBefore(k),\n )\n : findNextNavigableKey(s, collection.getLastKey(), (k) => collection.getKeyBefore(k));\n if (prevKey != null) {\n s.setFocusedKey(prevKey);\n }\n break;\n }\n case \"ArrowRight\":\n case \"ArrowLeft\": {\n e.preventDefault();\n if (focusedKey != null) {\n const node = collection.getItem(focusedKey);\n if (e.key === expandKey) {\n // Expand or move to first child\n if (node?.isExpandable) {\n if (!s.isExpanded(focusedKey)) {\n s.expandKey(focusedKey);\n } else {\n const children = [...collection.getChildren(focusedKey)];\n if (children.length > 0) {\n s.setFocusedKey(children[0].key);\n }\n }\n }\n } else if (e.key === collapseKey) {\n // Collapse or move to parent\n if (node?.isExpandable && s.isExpanded(focusedKey)) {\n s.collapseKey(focusedKey);\n } else if (node?.parentKey != null) {\n s.setFocusedKey(node.parentKey);\n }\n }\n }\n break;\n }\n case \"Home\": {\n e.preventDefault();\n const firstKey = findNextNavigableKey(s, collection.getFirstKey(), (k) =>\n collection.getKeyAfter(k),\n );\n if (firstKey != null) {\n s.setFocusedKey(firstKey);\n }\n break;\n }\n case \"End\": {\n e.preventDefault();\n const lastKey = findNextNavigableKey(s, collection.getLastKey(), (k) =>\n collection.getKeyBefore(k),\n );\n if (lastKey != null) {\n s.setFocusedKey(lastKey);\n }\n break;\n }\n case \"a\":\n case \"A\": {\n if ((e.ctrlKey || e.metaKey) && s.selectionMode === \"multiple\") {\n e.preventDefault();\n s.selectAll();\n }\n break;\n }\n // Space (selection) and Enter (action) are intentionally absent here.\n // Upstream's useSelectableCollection leaves activation to useSelectableItem.\n // The focus effect below moves DOM focus onto the focused row, so the row's\n // own createSelectableItem handlers receive those keys without duplicating\n // work in the bubbling tree handler.\n case \"Escape\": {\n if (s.selectionMode !== \"none\") {\n e.preventDefault();\n s.clearSelection();\n }\n break;\n }\n case \"*\": {\n // Expand all siblings at current level\n e.preventDefault();\n if (focusedKey != null) {\n const node = collection.getItem(focusedKey);\n if (node) {\n // Find all siblings at the same level\n const parentKey = node.parentKey;\n let siblings: Key[];\n if (parentKey != null) {\n siblings = [...collection.getChildren(parentKey)].map((n) => n.key);\n } else {\n // Root level siblings\n siblings = collection.rows.filter((n) => n.level === 0).map((n) => n.key);\n }\n // Expand all expandable siblings\n for (const siblingKey of siblings) {\n const sibling = collection.getItem(siblingKey);\n if (sibling?.isExpandable && !s.isExpanded(siblingKey)) {\n s.expandKey(siblingKey);\n }\n }\n }\n }\n break;\n }\n }\n };\n\n // The first / last SELECTED key in flattened (visible) order — mirrors React\n // Aria's `SelectionManager.firstSelectedKey`/`lastSelectedKey`, which entry\n // focus prefers over the first/last row.\n const firstSelectedKey = (s: TreeState<T, C>): Key | null => {\n let key = s.collection.getFirstKey();\n while (key != null) {\n if (s.isSelected(key)) return key;\n key = s.collection.getKeyAfter(key);\n }\n return null;\n };\n const lastSelectedKey = (s: TreeState<T, C>): Key | null => {\n let key = s.collection.getLastKey();\n while (key != null) {\n if (s.isSelected(key)) return key;\n key = s.collection.getKeyBefore(key);\n }\n return null;\n };\n\n // Entry focus is handled on `focusin` (BUBBLING) rather than `focus`\n // (non-bubbling): React Aria's `useSelectableCollection.onFocus` bubbles, so a\n // Shift+Tab that the browser parks on a tabbable descendant (e.g. a selection\n // checkbox, which is `tabIndex=0` like upstream) still reaches the collection\n // and is redirected to the focused/selected row. A Solid non-bubbling `focus`\n // handler on the treegrid only fires for forward Tab (the container is the first\n // tab stop) and would strand backward entry on the last checkbox — the same\n // trampoline gotcha the TagGroup port hit. See `createListBox.onListBoxFocus`.\n const onFocusIn = (e: FocusEvent) => {\n const s = state();\n s.setFocused(true);\n\n const currentTarget = e.currentTarget as Element | null;\n const relatedTarget = e.relatedTarget as Element | null;\n // Internal roving moves (focus already inside the tree) are driven by\n // `onKeyDown`; only seed focus when it enters from OUTSIDE the treegrid.\n if (!currentTarget || (relatedTarget && currentTarget.contains(relatedTarget))) {\n return;\n }\n\n let key = s.focusedKey;\n if (key == null) {\n // Shift+Tab backward into the tree (focus arrived from a FOLLOWING element)\n // enters at the last selected row, else the last navigable row; forward Tab\n // enters at the first selected row, else the first navigable row.\n const backward =\n !!relatedTarget &&\n !!(\n currentTarget.compareDocumentPosition(relatedTarget) &\n Node.DOCUMENT_POSITION_FOLLOWING\n );\n key = backward\n ? (lastSelectedKey(s) ??\n findNextNavigableKey(s, s.collection.getLastKey(), (k) => s.collection.getKeyBefore(k)))\n : (firstSelectedKey(s) ??\n findNextNavigableKey(s, s.collection.getFirstKey(), (k) => s.collection.getKeyAfter(k)));\n }\n if (key != null) {\n s.setFocusedKey(key);\n }\n };\n\n const onFocusOut = (e: FocusEvent) => {\n const s = state();\n const currentTarget = e.currentTarget as Element | null;\n const relatedTarget = e.relatedTarget as Element | null;\n // Only clear the focused flag once focus has left the treegrid entirely.\n if (!currentTarget || !relatedTarget || !currentTarget.contains(relatedTarget)) {\n s.setFocused(false);\n }\n };\n\n createEffect(() => {\n const s = state();\n const key = s.focusedKey;\n const el = ref();\n if (!el || key == null) {\n return;\n }\n\n const active = document.activeElement;\n if (!active || (active !== el && !el.contains(active))) {\n return;\n }\n\n const target = el.querySelector<HTMLElement>(`[data-key=\"${key}\"]`);\n if (target && target !== active) {\n target.focus();\n\n if (getInteractionModality() !== \"pointer\") {\n scrollIntoViewport(target, { containingElement: el });\n }\n }\n });\n\n const treeProps = createMemo(() => {\n const p = props();\n const s = state();\n\n const baseProps: Record<string, unknown> = {\n role: \"treegrid\",\n id: treeId,\n \"aria-label\": p[\"aria-label\"],\n \"aria-labelledby\": p[\"aria-labelledby\"],\n \"aria-describedby\": p[\"aria-describedby\"],\n \"aria-multiselectable\": s.selectionMode === \"multiple\" ? true : undefined,\n \"aria-disabled\": p.isDisabled || undefined,\n // Roving container tab stop: `0` while no row is focused (Tab enters the\n // tree), `-1` once a row takes focus (the row holds the tab stop). Mirrors\n // `useSelectableCollection` `tabIndex = focusedKey == null ? 0 : -1`.\n tabIndex: p.isDisabled ? undefined : s.focusedKey == null ? 0 : -1,\n onKeyDown,\n onFocusIn,\n onFocusOut,\n };\n\n // Add row count for virtualized trees\n if (p.isVirtualized) {\n baseProps[\"aria-rowcount\"] = s.collection.rowCount;\n }\n\n return baseProps as JSX.HTMLAttributes<HTMLDivElement>;\n });\n\n return {\n get treeProps() {\n return treeProps();\n },\n };\n}\n","/**\n * createTreeItem - Provides accessibility for a tree item.\n * Based on @react-aria/tree/useTreeItem.\n */\n\nimport { createMemo, type Accessor } from \"solid-js\";\nimport type { JSX } from \"solid-js\";\nimport { createId } from \"@proyecto-viviana/solid-stately\";\nimport type {\n Collection,\n Key,\n Selection,\n TreeState,\n TreeCollection,\n} from \"@proyecto-viviana/solid-stately\";\nimport type { AriaTreeItemProps, TreeItemAria } from \"./types\";\nimport { getTreeData } from \"./createTree\";\nimport { createSelectableItem, type SelectableItemState } from \"../selection/createSelectableItem\";\nimport { mergeCollectionRowInteractionProps } from \"../selection/createCollectionRowInteraction\";\nimport { mergeProps } from \"../utils/mergeProps\";\n\n/**\n * Creates accessibility props for a tree item.\n */\nexport function createTreeItem<T extends object, C extends TreeCollection<T> = TreeCollection<T>>(\n props: Accessor<AriaTreeItemProps<T>>,\n state: Accessor<TreeState<T, C>>,\n ref: Accessor<HTMLElement | null>,\n): TreeItemAria {\n const fallbackRowId = createId();\n const expandButtonId = createId();\n\n const rowId = createMemo(() => {\n const treeData = getTreeData(state());\n return treeData ? `${treeData.treeId}-row-${String(props().node.key)}` : fallbackRowId;\n });\n\n const isSelected = createMemo(() => {\n const s = state();\n const p = props();\n return s.isSelected(p.node.key);\n });\n\n const isExpanded = createMemo(() => {\n const s = state();\n const p = props();\n return s.isExpanded(p.node.key);\n });\n\n const isExpandable = createMemo(() => {\n const p = props();\n return p.node.isExpandable ?? false;\n });\n\n const level = createMemo(() => {\n const p = props();\n return p.node.level;\n });\n\n const selectableState: SelectableItemState<T> = {\n collection: () => state().collection as unknown as Collection<T>,\n isFocused: () => state().isFocused,\n setFocused: (focused: boolean) => state().setFocused(focused),\n focusedKey: () => state().focusedKey,\n childFocusStrategy: () => state().childFocusStrategy,\n setFocusedKey: (key: Key | null, strategy) => state().setFocusedKey(key, strategy),\n selectionMode: () => state().selectionMode,\n selectionBehavior: () => props().selectionBehavior ?? state().selectionBehavior,\n disallowEmptySelection: () => state().disallowEmptySelection,\n selectedKeys: () => state().selectedKeys as Selection,\n disabledKeys: () => state().disabledKeys,\n disabledBehavior: () => state().disabledBehavior,\n isEmpty: () => {\n const keys = state().selectedKeys;\n return keys !== \"all\" && keys.size === 0;\n },\n isSelectAll: () => state().selectedKeys === \"all\",\n isSelected: (key: Key) => state().isSelected(key),\n isDisabled: (key: Key) => {\n const s = state();\n const item = s.collection.getItem(key);\n return (\n s.disabledBehavior === \"all\" &&\n s.isDisabled(key) &&\n item?.props?.disabledBehavior !== \"selection\"\n );\n },\n canSelectItem: (key: Key) => {\n const s = state();\n return s.selectionMode !== \"none\" && !s.isDisabled(key);\n },\n setSelectionBehavior: (behavior) => state().setSelectionBehavior(behavior),\n toggleSelection: (key: Key) => state().toggleSelection(key),\n replaceSelection: (key: Key) => state().replaceSelection(key),\n setSelectedKeys: (keys: Iterable<Key>) => state().setSelectedKeys(keys),\n selectAll: () => state().selectAll(),\n clearSelection: () => state().clearSelection(),\n toggleSelectAll: () => state().toggleSelectAll(),\n extendSelection: (toKey: Key, _collection: Collection<T>) => state().extendSelection(toKey),\n };\n\n const selectableItem = createSelectableItem<T>(\n () => {\n const s = state();\n const p = props();\n const treeData = getTreeData(s);\n const treeAction = treeData?.actions.onAction;\n const shouldToggleOnAction =\n !treeAction && !p.onAction && s.selectionMode === \"none\" && isExpandable();\n\n return {\n key: p.node.key,\n id: rowId(),\n isVirtualized: p.isVirtualized,\n isDisabled: p.isDisabled,\n onAction:\n treeAction || p.onAction || shouldToggleOnAction\n ? () => {\n p.onAction?.();\n treeAction?.(p.node.key);\n if (shouldToggleOnAction) {\n s.toggleKey(p.node.key);\n }\n }\n : undefined,\n };\n },\n selectableState,\n ref,\n );\n\n // Compute sibling position (aria-posinset/aria-setsize)\n const siblingInfo = createMemo(() => {\n const s = state();\n const p = props();\n const node = p.node;\n const parentKey = node.parentKey;\n\n if (parentKey != null) {\n const parentNode = s.collection.getItem(parentKey);\n if (parentNode) {\n return {\n posinset: node.index + 1, // 1-based\n setsize: parentNode.childNodes.length,\n };\n }\n }\n\n // Root-level: count root nodes\n const rootNodes = s.collection.rows.filter((n) => n.level === 0);\n const rootIndex = rootNodes.findIndex((n) => n.key === node.key);\n return {\n posinset: rootIndex >= 0 ? rootIndex + 1 : node.index + 1,\n setsize: rootNodes.length,\n };\n });\n\n const rowProps = createMemo(() => {\n const p = props();\n const node = p.node;\n const { posinset, setsize } = siblingInfo();\n\n // Use textValue for aria-label (if available), or explicit textValue prop\n const textValue = p.textValue ?? node.textValue;\n\n const baseProps: Record<string, unknown> = {\n role: \"row\",\n \"aria-label\": textValue || undefined,\n \"aria-selected\": selectableState.canSelectItem?.(node.key) ? isSelected() : undefined,\n \"aria-disabled\": selectableItem.isDisabled() || undefined,\n \"aria-expanded\": isExpandable() ? isExpanded() : undefined,\n \"aria-level\": node.level + 1, // 1-based for ARIA\n \"aria-posinset\": posinset,\n \"aria-setsize\": setsize,\n };\n\n // Add aria-rowindex for virtualized trees\n if (p.isVirtualized && node.rowIndex != null) {\n baseProps[\"aria-rowindex\"] = node.rowIndex + 1; // 1-based\n }\n\n const treeData = getTreeData(state());\n const mergedProps = mergeProps<JSX.HTMLAttributes<HTMLDivElement>>(\n selectableItem.itemProps,\n baseProps,\n );\n\n return mergeCollectionRowInteractionProps(mergedProps, {\n ref,\n keyboardNavigationBehavior: () => treeData?.keyboardNavigationBehavior ?? \"arrow\",\n direction: () => treeData?.direction ?? \"ltr\",\n });\n });\n\n const gridCellProps = createMemo(() => {\n return {\n role: \"gridcell\",\n \"aria-colindex\": 1,\n } as JSX.HTMLAttributes<HTMLDivElement>;\n });\n\n // Expand button handler\n const onExpandClick = (e: MouseEvent) => {\n e.stopPropagation(); // Don't trigger row click\n const s = state();\n const p = props();\n\n if (selectableItem.isDisabled()) return;\n\n s.toggleKey(p.node.key);\n };\n\n const stopPointerPropagation = (e: Event) => {\n // Prevent row pointer handlers from flipping pressed state and re-rendering\n // before the button click handler can run.\n e.stopPropagation();\n };\n\n const expandButtonProps = createMemo(() => {\n const baseProps: Record<string, unknown> = {\n type: \"button\",\n id: expandButtonId,\n \"aria-label\": isExpanded() ? \"Collapse\" : \"Expand\",\n \"aria-labelledby\": isExpandable() ? `${expandButtonId} ${rowId()}` : undefined,\n \"data-react-aria-prevent-focus\": true,\n onClick: onExpandClick,\n onPointerDown: stopPointerPropagation,\n onPointerUp: stopPointerPropagation,\n onMouseDown: stopPointerPropagation,\n onMouseUp: stopPointerPropagation,\n tabIndex: -1, // Not in tab order, use arrow keys\n \"aria-hidden\": !isExpandable() ? true : undefined,\n };\n\n return baseProps as JSX.ButtonHTMLAttributes<HTMLButtonElement>;\n });\n\n return {\n get rowProps() {\n return rowProps();\n },\n get gridCellProps() {\n return gridCellProps();\n },\n get expandButtonProps() {\n return expandButtonProps();\n },\n get isSelected() {\n return isSelected();\n },\n get isDisabled() {\n return selectableItem.isDisabled();\n },\n get isPressed() {\n return selectableItem.isPressed();\n },\n get isExpanded() {\n return isExpanded();\n },\n get isExpandable() {\n return isExpandable();\n },\n get level() {\n return level();\n },\n };\n}\n","/**\n * createTreeSelectionCheckbox - Provides accessibility for a tree item's selection checkbox.\n * Based on @react-aria/gridlist/useGridListSelectionCheckbox.\n */\n\nimport { createMemo, type Accessor } from \"solid-js\";\nimport type { JSX } from \"solid-js\";\nimport { createId } from \"@proyecto-viviana/solid-stately\";\nimport type { TreeState, TreeCollection } from \"@proyecto-viviana/solid-stately\";\nimport type { AriaTreeSelectionCheckboxProps, TreeSelectionCheckboxAria } from \"./types\";\nimport { getTreeData } from \"./createTree\";\n\n/**\n * Creates accessibility props for a tree selection checkbox.\n */\nexport function createTreeSelectionCheckbox<\n T extends object,\n C extends TreeCollection<T> = TreeCollection<T>,\n>(\n props: Accessor<AriaTreeSelectionCheckboxProps>,\n state: Accessor<TreeState<T, C>>,\n): TreeSelectionCheckboxAria {\n const fallbackRowId = createId();\n const checkboxId = createId();\n\n // Mirror @react-aria/tree getRowId: the checkbox's aria-labelledby folds its own\n // \"Select\" label with the row's id so the SR announces \"Select <row text>\".\n const rowId = createMemo(() => {\n const treeData = getTreeData(state());\n return treeData ? `${treeData.treeId}-row-${String(props().key)}` : fallbackRowId;\n });\n\n const isSelected = createMemo(() => {\n const s = state();\n const p = props();\n return s.isSelected(p.key);\n });\n\n const isDisabled = createMemo(() => {\n const s = state();\n const p = props();\n return s.isDisabled(p.key);\n });\n\n const onChange = (e: Event) => {\n const s = state();\n const p = props();\n const target = e.target as HTMLInputElement;\n\n if (isDisabled()) return;\n\n if (target.checked) {\n s.toggleSelection(p.key);\n } else {\n s.toggleSelection(p.key);\n }\n };\n\n const onClick = (e: MouseEvent) => {\n // Stop propagation to prevent row click from also firing\n e.stopPropagation();\n };\n\n const checkboxProps = createMemo(() => {\n const baseProps: Record<string, unknown> = {\n type: \"checkbox\",\n id: checkboxId,\n \"aria-label\": \"Select\",\n \"aria-labelledby\": `${checkboxId} ${rowId()}`,\n checked: isSelected(),\n disabled: isDisabled(),\n onChange,\n onClick,\n };\n\n return baseProps as JSX.InputHTMLAttributes<HTMLInputElement>;\n });\n\n return {\n get checkboxProps() {\n return checkboxProps();\n },\n };\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { r as isTestEnv } from "./env.js";
2
2
  import { s as getOwnerDocument, u as getScrollParents } from "./focus.js";
3
- import { createEffect, createSignal, onCleanup } from "solid-js";
3
+ import { createComputed, createEffect, createMemo, createSignal, onCleanup } from "solid-js";
4
4
  import { isServer } from "solid-js/web";
5
5
  //#region src/utils/platform.ts
6
6
  function getNavigator() {
@@ -581,8 +581,20 @@ function clearDescriptionNodes() {
581
581
  /**
582
582
  * Runs `onEnd` once the element's animations settle while `isActive` is true.
583
583
  * Mirrors the private `useAnimation` helper in react-aria's animation utils.
584
+ *
585
+ * `deferNoAnimation` mirrors React's timing for the no-animation case. Upstream
586
+ * runs `onEnd` inside a `useLayoutEffect`, so an animation-less exit unmounts
587
+ * *after* React commits — i.e. after the triggering input event finishes
588
+ * dispatching (empirically, an Escape's teardown lands after `keyup`, not
589
+ * between `keydown` and `keyup`). A Solid `createEffect` runs synchronously
590
+ * inside the handler, so an animation-less exit would tear the overlay out
591
+ * mid-gesture, firing `focusout` before `keyup` and retargeting `keyup` to the
592
+ * body. Deferring `onEnd` to the next frame — the same primitive `FocusScope`
593
+ * uses to defer focus restore — reproduces React's post-commit ordering. Only
594
+ * the real-browser no-animation branch defers; the JSDOM branch stays
595
+ * synchronous so unit tests that assert immediate unmount are unaffected.
584
596
  */
585
- function createAnimation(ref, isActive, onEnd) {
597
+ function createAnimation(ref, isActive, onEnd, deferNoAnimation = false) {
586
598
  createEffect(() => {
587
599
  if (!isActive()) return;
588
600
  const element = ref();
@@ -591,17 +603,23 @@ function createAnimation(ref, isActive, onEnd) {
591
603
  onEnd();
592
604
  return;
593
605
  }
594
- const animations = element.getAnimations();
595
- if (animations.length === 0) {
596
- onEnd();
597
- return;
598
- }
599
606
  let canceled = false;
600
- Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {
601
- if (!canceled) onEnd();
607
+ let frame;
608
+ const settle = () => {
609
+ if (canceled) return;
610
+ if (deferNoAnimation && typeof requestAnimationFrame === "function") frame = requestAnimationFrame(() => {
611
+ if (!canceled) onEnd();
612
+ });
613
+ else onEnd();
614
+ };
615
+ const animations = element.getAnimations();
616
+ if (animations.length === 0) settle();
617
+ else Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {
618
+ settle();
602
619
  });
603
620
  onCleanup(() => {
604
621
  canceled = true;
622
+ if (frame !== void 0 && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame);
605
623
  });
606
624
  });
607
625
  }
@@ -644,19 +662,41 @@ function createEnterAnimation(ref, isReady = () => true) {
644
662
  * @param isOpen - Whether the element is currently open.
645
663
  */
646
664
  function createExitAnimation(ref, isOpen) {
647
- const [exitState, setExitState] = createSignal(isOpen() ? "open" : "closed");
648
- createEffect(() => {
665
+ const [exitFinished, setExitFinished] = createSignal(0);
666
+ const exitState = createMemo((prev) => {
649
667
  const open = isOpen();
650
- setExitState((current) => {
651
- if (current === "open" && !open) return "exiting";
652
- if ((current === "closed" || current === "exiting") && open) return "open";
653
- return current;
654
- });
668
+ const finish = exitFinished();
669
+ const compute = () => {
670
+ if (open) return {
671
+ state: "open",
672
+ ackedFinish: finish
673
+ };
674
+ if (prev.state === "open") return {
675
+ state: "exiting",
676
+ ackedFinish: finish
677
+ };
678
+ if (prev.state === "exiting") {
679
+ if (finish !== prev.ackedFinish) return {
680
+ state: "closed",
681
+ ackedFinish: finish
682
+ };
683
+ return prev;
684
+ }
685
+ return {
686
+ state: "closed",
687
+ ackedFinish: finish
688
+ };
689
+ };
690
+ return compute();
691
+ }, {
692
+ state: isOpen() ? "open" : "closed",
693
+ ackedFinish: 0
655
694
  });
656
- const isExiting = () => exitState() === "exiting";
695
+ const isExiting = () => exitState().state === "exiting";
696
+ createComputed(() => void exitState());
657
697
  createAnimation(ref, isExiting, () => {
658
- setExitState((state) => state === "exiting" ? "closed" : state);
659
- });
698
+ setExitFinished((n) => n + 1);
699
+ }, true);
660
700
  return isExiting;
661
701
  }
662
702
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../src/utils/platform.ts","../../src/utils/scrollIntoView.ts","../../src/utils/geometry.ts","../../src/utils/events.ts","../../src/utils/textSelection.ts","../../src/utils/keyboard.ts","../../src/utils/globalListeners.ts","../../src/utils/createDescription.ts","../../src/utils/animation.ts"],"sourcesContent":["/**\n * Platform detection utilities.\n * Based on @react-aria/utils platform detection.\n */\n\ninterface NavigatorWithUserAgentData extends Navigator {\n userAgentData?: {\n platform?: string;\n };\n}\n\nfunction getNavigator(): NavigatorWithUserAgentData | null {\n if (typeof window === \"undefined\" || window.navigator == null) return null;\n return window.navigator as NavigatorWithUserAgentData;\n}\n\nfunction testPlatform(re: RegExp): boolean {\n const nav = getNavigator();\n if (!nav) return false;\n return re.test(nav.platform || nav.userAgentData?.platform || \"\");\n}\n\nfunction testUserAgent(re: RegExp): boolean {\n const nav = getNavigator();\n return nav ? re.test(nav.userAgent) : false;\n}\n\nexport function isMac(): boolean {\n return testPlatform(/^Mac/i);\n}\n\nexport function isIPhone(): boolean {\n return testPlatform(/^iPhone/i);\n}\n\nexport function isIPad(): boolean {\n return testPlatform(/^iPad/i) || (isMac() && navigator.maxTouchPoints > 1);\n}\n\nexport function isIOS(): boolean {\n return isIPhone() || isIPad();\n}\n\nexport function isAppleDevice(): boolean {\n return isMac() || isIOS();\n}\n\nexport function isWebKit(): boolean {\n return testUserAgent(/AppleWebKit/i) && !isChrome();\n}\n\nexport function isChrome(): boolean {\n return testUserAgent(/Chrome/i);\n}\n\nexport function isAndroid(): boolean {\n return testUserAgent(/Android/i);\n}\n\nexport function isFirefox(): boolean {\n return testUserAgent(/Firefox/i);\n}\n","/**\n * Scroll-into-view utilities.\n * Based on @react-aria/utils scrollIntoView (react-aria/src/utils/scrollIntoView.ts).\n */\n\nimport { getScrollParents } from \"./dom\";\nimport { isIOS } from \"./platform\";\nimport { isTestEnv } from \"./env\";\n\ninterface ScrollIntoViewOpts {\n /** The position to align items along the block axis in. */\n block?: ScrollLogicalPosition;\n /** The position to align items along the inline axis in. */\n inline?: ScrollLogicalPosition;\n}\n\ninterface ScrollIntoViewportOpts {\n /** The optional containing element of the target to be centered in the viewport. */\n containingElement?: Element | null;\n}\n\n/**\n * Scrolls `scrollView` so that `element` is visible.\n * Similar to `element.scrollIntoView({block: 'nearest'})` (not supported in Edge),\n * but doesn't affect parents above `scrollView`.\n */\nexport function scrollIntoView(\n scrollView: HTMLElement,\n element: HTMLElement,\n opts: ScrollIntoViewOpts = {},\n): void {\n const { block = \"nearest\", inline = \"nearest\" } = opts;\n\n if (scrollView === element) {\n return;\n }\n\n let y = scrollView.scrollTop;\n let x = scrollView.scrollLeft;\n\n const target = element.getBoundingClientRect();\n const view = scrollView.getBoundingClientRect();\n const itemStyle = window.getComputedStyle(element);\n const viewStyle = window.getComputedStyle(scrollView);\n const root = document.scrollingElement || document.documentElement;\n const isRoot = scrollView === root;\n\n const viewTop = scrollView === root ? 0 : view.top;\n const viewBottom = scrollView === root ? scrollView.clientHeight : view.bottom;\n const viewLeft = scrollView === root ? 0 : view.left;\n const viewRight = scrollView === root ? scrollView.clientWidth : view.right;\n\n const scrollMarginTop = parseFloat(itemStyle.scrollMarginTop) || 0;\n const scrollMarginBottom = parseFloat(itemStyle.scrollMarginBottom) || 0;\n const scrollMarginLeft = parseFloat(itemStyle.scrollMarginLeft) || 0;\n const scrollMarginRight = parseFloat(itemStyle.scrollMarginRight) || 0;\n\n const scrollPaddingTop = parseFloat(viewStyle.scrollPaddingTop) || 0;\n const scrollPaddingBottom = parseFloat(viewStyle.scrollPaddingBottom) || 0;\n const scrollPaddingLeft = parseFloat(viewStyle.scrollPaddingLeft) || 0;\n const scrollPaddingRight = parseFloat(viewStyle.scrollPaddingRight) || 0;\n\n const borderTopWidth = parseFloat(viewStyle.borderTopWidth) || 0;\n const borderBottomWidth = parseFloat(viewStyle.borderBottomWidth) || 0;\n const borderLeftWidth = parseFloat(viewStyle.borderLeftWidth) || 0;\n const borderRightWidth = parseFloat(viewStyle.borderRightWidth) || 0;\n\n const scrollAreaTop = target.top - scrollMarginTop;\n const scrollAreaBottom = target.bottom + scrollMarginBottom;\n const scrollAreaLeft = target.left - scrollMarginLeft;\n const scrollAreaRight = target.right + scrollMarginRight;\n\n const scrollBarOffsetX = scrollView === root ? 0 : borderLeftWidth + borderRightWidth;\n const scrollBarOffsetY = scrollView === root ? 0 : borderTopWidth + borderBottomWidth;\n const scrollBarWidth =\n scrollView === root ? 0 : scrollView.offsetWidth - scrollView.clientWidth - scrollBarOffsetX;\n const scrollBarHeight =\n scrollView === root ? 0 : scrollView.offsetHeight - scrollView.clientHeight - scrollBarOffsetY;\n\n const scrollPortTop = viewTop + (isRoot ? 0 : borderTopWidth) + scrollPaddingTop;\n const scrollPortBottom =\n viewBottom - (isRoot ? 0 : borderBottomWidth) - scrollPaddingBottom - scrollBarHeight;\n let scrollPortLeft = viewLeft + (isRoot ? 0 : borderLeftWidth) + scrollPaddingLeft;\n let scrollPortRight = viewRight - (isRoot ? 0 : borderRightWidth) - scrollPaddingRight;\n\n // IOS always positions the scrollbar on the right ¯\\_(ツ)_/¯\n if (viewStyle.direction === \"rtl\" && !isIOS()) {\n scrollPortLeft += scrollBarWidth;\n } else {\n scrollPortRight -= scrollBarWidth;\n }\n\n const shouldScrollBlock = scrollAreaTop < scrollPortTop || scrollAreaBottom > scrollPortBottom;\n const shouldScrollInline = scrollAreaLeft < scrollPortLeft || scrollAreaRight > scrollPortRight;\n\n if (shouldScrollBlock && block === \"start\") {\n y += scrollAreaTop - scrollPortTop;\n } else if (shouldScrollBlock && block === \"center\") {\n y += (scrollAreaTop + scrollAreaBottom) / 2 - (scrollPortTop + scrollPortBottom) / 2;\n } else if (shouldScrollBlock && block === \"end\") {\n y += scrollAreaBottom - scrollPortBottom;\n } else if (shouldScrollBlock && block === \"nearest\") {\n const start = scrollAreaTop - scrollPortTop;\n const end = scrollAreaBottom - scrollPortBottom;\n y += Math.abs(start) <= Math.abs(end) ? start : end;\n }\n\n if (shouldScrollInline && inline === \"start\") {\n x += scrollAreaLeft - scrollPortLeft;\n } else if (shouldScrollInline && inline === \"center\") {\n x += (scrollAreaLeft + scrollAreaRight) / 2 - (scrollPortLeft + scrollPortRight) / 2;\n } else if (shouldScrollInline && inline === \"end\") {\n x += scrollAreaRight - scrollPortRight;\n } else if (shouldScrollInline && inline === \"nearest\") {\n const start = scrollAreaLeft - scrollPortLeft;\n const end = scrollAreaRight - scrollPortRight;\n x += Math.abs(start) <= Math.abs(end) ? start : end;\n }\n\n if (isTestEnv()) {\n scrollView.scrollLeft = x;\n scrollView.scrollTop = y;\n return;\n }\n\n scrollView.scrollTo({ left: x, top: y });\n}\n\n/**\n * Scrolls the `targetElement` so it is visible in the viewport. Accepts an optional\n * `opts.containingElement` that will be centered in the viewport prior to scrolling the\n * targetElement into view. If scrolling is prevented on the body (e.g. targetElement is in a\n * popover), this will only scroll the scroll parents of the targetElement up to but not including\n * the body itself.\n */\nexport function scrollIntoViewport(\n targetElement: Element | null,\n opts: ScrollIntoViewportOpts = {},\n): void {\n const { containingElement } = opts;\n if (targetElement && targetElement.isConnected) {\n const root = document.scrollingElement || document.documentElement;\n const isScrollPrevented = window.getComputedStyle(root).overflow === \"hidden\";\n if (!isScrollPrevented) {\n const { left: originalLeft, top: originalTop } = targetElement.getBoundingClientRect();\n\n // use scrollIntoView({block: 'nearest'}) instead of .focus to check if the element is fully in view or not since .focus()\n // won't cause a scroll if the element is already focused and doesn't behave consistently when an element is partially out of view horizontally vs vertically\n targetElement?.scrollIntoView?.({ block: \"nearest\" });\n const { left: newLeft, top: newTop } = targetElement.getBoundingClientRect();\n // Account for sub pixel differences from rounding\n if (Math.abs(originalLeft - newLeft) > 1 || Math.abs(originalTop - newTop) > 1) {\n containingElement?.scrollIntoView?.({ block: \"center\", inline: \"center\" });\n targetElement.scrollIntoView?.({ block: \"nearest\" });\n }\n } else {\n const { left: originalLeft, top: originalTop } = targetElement.getBoundingClientRect();\n\n // If scrolling is prevented, we don't want to scroll the body since it might move the overlay partially offscreen and the user can't scroll it back into view.\n let scrollParents = getScrollParents(targetElement, true);\n for (const scrollParent of scrollParents) {\n scrollIntoView(scrollParent as HTMLElement, targetElement as HTMLElement);\n }\n const { left: newLeft, top: newTop } = targetElement.getBoundingClientRect();\n // Account for sub pixel differences from rounding\n if (Math.abs(originalLeft - newLeft) > 1 || Math.abs(originalTop - newTop) > 1) {\n scrollParents = containingElement ? getScrollParents(containingElement, true) : [];\n // scroll containing element into view first, then rescroll target element into view like the non chrome flow above\n for (const scrollParent of scrollParents) {\n scrollIntoView(scrollParent as HTMLElement, containingElement as HTMLElement, {\n block: \"center\",\n inline: \"center\",\n });\n }\n for (const scrollParent of getScrollParents(targetElement, true)) {\n scrollIntoView(scrollParent as HTMLElement, targetElement as HTMLElement);\n }\n }\n }\n }\n}\n","/**\n * Geometry utilities for pointer/touch hit testing.\n * Based on @react-aria/interactions geometry utilities.\n */\n\nexport interface Rect {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\nexport interface EventPoint {\n clientX: number;\n clientY: number;\n width?: number;\n height?: number;\n radiusX?: number;\n radiusY?: number;\n}\n\n/**\n * Checks if two rectangles overlap.\n */\nexport function areRectanglesOverlapping(a: Rect, b: Rect): boolean {\n if (a.left > b.right || b.left > a.right) {\n return false;\n }\n\n if (a.top > b.bottom || b.top > a.bottom) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Gets the bounding rectangle for an event point (touch/pointer).\n * Takes into account the size of the touch point.\n */\nexport function getPointClientRect(point: EventPoint): Rect {\n let offsetX = 0;\n let offsetY = 0;\n\n if (point.width !== undefined && point.width > 0) {\n offsetX = point.width / 2;\n } else if (point.radiusX !== undefined && point.radiusX > 0) {\n // Fallback to radiusX/radiusY (Touch)\n offsetX = point.radiusX;\n }\n\n if (point.height !== undefined && point.height > 0) {\n offsetY = point.height / 2;\n } else if (point.radiusY !== undefined && point.radiusY > 0) {\n offsetY = point.radiusY;\n }\n\n return {\n top: point.clientY - offsetY,\n right: point.clientX + offsetX,\n bottom: point.clientY + offsetY,\n left: point.clientX - offsetX,\n };\n}\n\n/**\n * Checks if a pointer/touch point is over an element.\n */\nexport function isPointOverTarget(point: EventPoint, target: Element): boolean {\n const rect = target.getBoundingClientRect();\n const pointRect = getPointClientRect(point);\n\n return areRectanglesOverlapping(\n {\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left,\n },\n pointRect,\n );\n}\n\n/**\n * Gets the first touch from a TouchEvent's targetTouches.\n */\nexport function getTouchFromEvent(event: TouchEvent): Touch | null {\n const { targetTouches } = event;\n if (targetTouches.length > 0) {\n return targetTouches[0];\n }\n return null;\n}\n\n/**\n * Finds a touch by its identifier in changedTouches.\n */\nexport function getTouchById(event: TouchEvent, pointerId: number | null): Touch | null {\n if (pointerId == null) {\n return null;\n }\n\n const { changedTouches } = event;\n for (let i = 0; i < changedTouches.length; i++) {\n const touch = changedTouches[i];\n if (touch.identifier === pointerId) {\n return touch;\n }\n }\n\n return null;\n}\n","/**\n * Event utilities for detecting virtual clicks and event handling.\n * Based on @react-aria/utils event utilities.\n */\n\nimport { isAndroid } from \"./platform\";\n\n/**\n * Checks if a click event was generated from a virtual source like a screen reader.\n * Virtual clicks typically have detail of 0 and may have zero coordinates.\n */\nexport function isVirtualClick(event: MouseEvent | PointerEvent): boolean {\n // JAWS/NVDA with Firefox.\n if ((event as PointerEvent).pointerType === \"\" && event.isTrusted) {\n return true;\n }\n\n // Android TalkBack's detail value varies depending on the event listener providing the event.\n // If pointerType is defined, event is from a click listener.\n if (isAndroid() && (event as PointerEvent).pointerType) {\n return event.type === \"click\" && (event as MouseEvent).buttons === 1;\n }\n\n return event.detail === 0 && !(event as PointerEvent).pointerType;\n}\n\n/**\n * Checks if a pointer event was generated by a virtual source.\n * iOS VoiceOver fires pointer events with incorrect coordinates.\n * These events have zero width/height.\n */\nexport function isVirtualPointerEvent(event: PointerEvent): boolean {\n // If the pointer size is zero, then we assume it's from a screen reader.\n // Android TalkBack double tap will sometimes return a event with width and height of 1\n // and pointerType === 'mouse' so we need to check for a specific combination of event attributes.\n // Cannot use \"event.pressure === 0\" as the sole check due to Safari pointer events always returning pressure === 0.\n return (\n (!isAndroid() && event.width === 0 && event.height === 0) ||\n (event.width === 1 &&\n event.height === 1 &&\n event.pressure === 0 &&\n event.detail === 0 &&\n event.pointerType === \"mouse\")\n );\n}\n\n/**\n * Creates a synthetic mouse event for programmatic clicking.\n */\nexport function createMouseEvent(type: string, nativeEvent?: Event): MouseEvent {\n const init: MouseEventInit = {\n bubbles: true,\n cancelable: true,\n view: window,\n };\n\n // Copy properties from the native event if provided\n if (nativeEvent) {\n const e = nativeEvent as MouseEvent;\n init.screenX = e.screenX;\n init.screenY = e.screenY;\n init.clientX = e.clientX;\n init.clientY = e.clientY;\n init.ctrlKey = e.ctrlKey;\n init.shiftKey = e.shiftKey;\n init.altKey = e.altKey;\n init.metaKey = e.metaKey;\n init.button = e.button;\n init.buttons = e.buttons;\n init.relatedTarget = e.relatedTarget;\n }\n\n return new MouseEvent(type, init);\n}\n\n/**\n * Creates a chain of event handlers that calls each in sequence.\n */\nexport function chain<T extends (...args: any[]) => any>(\n ...callbacks: (T | undefined | null)[]\n): T {\n return ((...args: Parameters<T>) => {\n for (const callback of callbacks) {\n if (typeof callback === \"function\") {\n callback(...args);\n }\n }\n }) as T;\n}\n\n/**\n * Sets the target property on an event object.\n * Used for synthetic events where target needs to be modified.\n */\nexport function setEventTarget<T extends Event>(event: T, target: EventTarget): void {\n Object.defineProperty(event, \"target\", {\n value: target,\n writable: false,\n configurable: true,\n });\n Object.defineProperty(event, \"currentTarget\", {\n value: target,\n writable: false,\n configurable: true,\n });\n}\n","/**\n * Text selection management utilities.\n * Based on @react-aria/interactions textSelection utilities.\n *\n * On iOS, long press triggers text selection. The only way to prevent this\n * is to set user-select: none on the entire page. On other platforms,\n * we can just set it on the target element.\n */\n\nimport { isIOS } from \"./platform\";\nimport { getOwnerDocument } from \"./dom\";\n\ntype State = \"default\" | \"disabled\" | \"restoring\";\n\n// Global state to manage text selection across multiple press interactions\nlet state: State = \"default\";\nlet savedUserSelect = \"\";\nlet modifiedElementMap = new WeakMap<HTMLElement, string>();\n\n/**\n * Disables text selection on the page or element during press.\n * On iOS, applies to the entire document. On other platforms, just the target.\n */\nexport function disableTextSelection(target?: HTMLElement): void {\n if (isIOS()) {\n // iOS requires disabling selection on the entire page\n if (state === \"default\") {\n const documentElement = getOwnerDocument(target).documentElement;\n savedUserSelect = documentElement.style.webkitUserSelect;\n documentElement.style.webkitUserSelect = \"none\";\n }\n state = \"disabled\";\n } else if (target) {\n // On other platforms, just disable on the target\n const element = target as HTMLElement;\n if (!modifiedElementMap.has(element)) {\n modifiedElementMap.set(element, element.style.userSelect);\n element.style.userSelect = \"none\";\n }\n }\n}\n\n/**\n * Restores text selection after press ends.\n * On iOS, waits 300ms to avoid selection appearing during tap.\n */\nexport function restoreTextSelection(target?: HTMLElement): void {\n if (isIOS()) {\n // Don't restore if another press is active\n if (state !== \"disabled\") {\n return;\n }\n\n state = \"restoring\";\n\n // Wait for iOS to finish any pending selection actions\n // 300ms is the iOS long-press delay\n setTimeout(() => {\n // Use runAfterTransition to avoid CSS recomputation during animation\n runAfterTransition(() => {\n // Only restore if still in 'restoring' state (no new press started)\n if (state === \"restoring\") {\n const documentElement = getOwnerDocument(target).documentElement;\n if (savedUserSelect) {\n documentElement.style.webkitUserSelect = savedUserSelect;\n } else {\n documentElement.style.removeProperty(\"-webkit-user-select\");\n }\n savedUserSelect = \"\";\n state = \"default\";\n }\n });\n }, 300);\n } else if (target) {\n // On other platforms, restore immediately\n const element = target as HTMLElement;\n const savedValue = modifiedElementMap.get(element);\n if (savedValue !== undefined) {\n if (savedValue) {\n element.style.userSelect = savedValue;\n } else {\n element.style.removeProperty(\"user-select\");\n }\n modifiedElementMap.delete(element);\n }\n }\n}\n\n// Tracks pending transitions for runAfterTransition\nconst pendingTransitions = new Set<() => void>();\nlet transitionTimeout: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Runs a callback after CSS transitions complete.\n * Batches multiple callbacks to avoid unnecessary layout thrashing.\n */\nfunction runAfterTransition(callback: () => void): void {\n // If we haven't started tracking transitions, run immediately\n pendingTransitions.add(callback);\n\n // Debounce - wait for any transitions to settle\n if (transitionTimeout != null) {\n clearTimeout(transitionTimeout);\n }\n\n transitionTimeout = setTimeout(() => {\n // Run all pending callbacks\n for (const cb of pendingTransitions) {\n cb();\n }\n pendingTransitions.clear();\n transitionTimeout = null;\n }, 0);\n}\n","/**\n * Keyboard / modifier-key helpers.\n * Based on @react-aria/utils' keyboard utilities.\n */\n\nimport { isMac } from \"./platform\";\n\n/** The modifier-key fields consulted by {@link isCtrlKeyPressed}. */\ninterface ModifierKeyEvent {\n ctrlKey?: boolean;\n metaKey?: boolean;\n}\n\n/**\n * Returns whether the platform's non-contiguous selection modifier is pressed:\n * the Command key on macOS, the Control key elsewhere. Mirrors\n * `@react-aria/utils`' `isCtrlKeyPressed`.\n */\nexport function isCtrlKeyPressed(e: ModifierKeyEvent): boolean {\n if (isMac()) {\n return e.metaKey === true;\n }\n\n return e.ctrlKey === true;\n}\n","/**\n * Global listener management utility.\n * Based on @react-aria/utils useGlobalListeners hook, adapted for SolidJS.\n *\n * In SolidJS, we use onCleanup for automatic cleanup instead of useEffect return.\n */\n\nimport { onCleanup } from \"solid-js\";\n\nexport interface GlobalListenerOptions extends AddEventListenerOptions {\n /** Whether to add the listener to the window instead of document */\n isWindow?: boolean;\n}\n\n/**\n * Creates a manager for global event listeners that automatically cleans up.\n * Use this in a component to register document/window level listeners\n * that will be removed when the component unmounts.\n */\nexport function createGlobalListeners() {\n const listeners: Array<{\n target: EventTarget;\n type: string;\n handler: EventListener;\n options?: AddEventListenerOptions;\n }> = [];\n\n /**\n * Adds a global event listener.\n */\n function addGlobalListener<K extends keyof DocumentEventMap>(\n type: K,\n handler: (ev: DocumentEventMap[K]) => void,\n options?: GlobalListenerOptions,\n ): void;\n function addGlobalListener<K extends keyof WindowEventMap>(\n type: K,\n handler: (ev: WindowEventMap[K]) => void,\n options?: GlobalListenerOptions & { isWindow: true },\n ): void;\n function addGlobalListener(\n type: string,\n handler: EventListener,\n options?: GlobalListenerOptions,\n ): void {\n const target = options?.isWindow ? window : document;\n const listenerOptions = options\n ? {\n capture: options.capture,\n passive: options.passive,\n once: options.once,\n }\n : undefined;\n\n target.addEventListener(type, handler, listenerOptions);\n listeners.push({ target, type, handler, options: listenerOptions });\n }\n\n /**\n * Removes a specific global event listener.\n */\n function removeGlobalListener<K extends keyof DocumentEventMap>(\n type: K,\n handler: (ev: DocumentEventMap[K]) => void,\n options?: AddEventListenerOptions,\n ): void;\n function removeGlobalListener<K extends keyof WindowEventMap>(\n type: K,\n handler: (ev: WindowEventMap[K]) => void,\n options?: AddEventListenerOptions & { isWindow: true },\n ): void;\n function removeGlobalListener(\n type: string,\n handler: EventListener,\n options?: AddEventListenerOptions & { isWindow?: boolean },\n ): void {\n const target = options?.isWindow ? window : document;\n const listenerOptions = options\n ? {\n capture: options.capture,\n }\n : undefined;\n\n target.removeEventListener(type, handler, listenerOptions);\n\n // Remove from tracked listeners\n const index = listeners.findIndex(\n (l) =>\n l.target === target &&\n l.type === type &&\n l.handler === handler &&\n l.options?.capture === listenerOptions?.capture,\n );\n if (index !== -1) {\n listeners.splice(index, 1);\n }\n }\n\n /**\n * Removes all registered global listeners.\n */\n function removeAllGlobalListeners(): void {\n for (const { target, type, handler, options } of listeners) {\n target.removeEventListener(type, handler, options);\n }\n listeners.length = 0;\n }\n\n // Automatically clean up when the component/scope is disposed\n onCleanup(removeAllGlobalListeners);\n\n return {\n addGlobalListener,\n removeGlobalListener,\n removeAllGlobalListeners,\n };\n}\n\n/**\n * Simple utility to add a single global listener with automatic cleanup.\n * For one-off listeners where the full manager isn't needed.\n */\nexport function addGlobalListenerOnce<K extends keyof DocumentEventMap>(\n type: K,\n handler: (ev: DocumentEventMap[K]) => void,\n options?: GlobalListenerOptions,\n): () => void {\n const target = options?.isWindow ? window : document;\n const listenerOptions = options\n ? {\n capture: options.capture,\n passive: options.passive,\n once: options.once,\n }\n : undefined;\n\n target.addEventListener(type, handler as EventListener, listenerOptions);\n\n return () => {\n target.removeEventListener(type, handler as EventListener, listenerOptions);\n };\n}\n","/**\n * createDescription - Creates a hidden element for dynamic aria-describedby content.\n *\n * This utility creates a visually hidden element containing description text and\n * returns an aria-describedby prop pointing to it. Multiple components using the\n * same description will share the same element (reference counted).\n *\n * Port of @react-aria/utils/useDescription.\n *\n * @example\n * ```tsx\n * function SortableColumn(props) {\n * const descriptionProps = createDescription(\n * () => props.sortDirection ? `Sorted ${props.sortDirection}` : undefined\n * );\n *\n * return (\n * <th {...descriptionProps}>\n * {props.children}\n * </th>\n * );\n * }\n * ```\n */\n\nimport { createSignal, createEffect, onCleanup, type Accessor } from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\n\nexport interface DescriptionProps {\n \"aria-describedby\"?: string;\n}\n\nlet descriptionId = 0;\nconst descriptionNodes = new Map<string, { refCount: number; element: Element }>();\n\n/**\n * Creates an invisible description element and returns aria-describedby props.\n *\n * The element is created in the DOM and reference counted - multiple uses of\n * the same description text will share the same element. When all references\n * are removed, the element is cleaned up.\n *\n * @param description - Accessor that returns the description text, or undefined\n * @returns Object with aria-describedby prop (or empty object if no description)\n *\n * @example\n * ```tsx\n * const descProps = createDescription(() => 'Press Enter to submit');\n * return <button {...descProps}>Submit</button>;\n * ```\n */\nexport function createDescription(description: Accessor<string | undefined>): DescriptionProps {\n if (isServer) {\n return {};\n }\n\n const [id, setId] = createSignal<string | undefined>();\n\n createEffect(() => {\n const desc = description();\n\n if (!desc) {\n setId(undefined);\n return;\n }\n\n let node = descriptionNodes.get(desc);\n\n if (!node) {\n const newId = `solidaria-description-${descriptionId++}`;\n setId(newId);\n\n const element = document.createElement(\"div\");\n element.id = newId;\n element.style.display = \"none\";\n element.textContent = desc;\n document.body.appendChild(element);\n\n node = { refCount: 0, element };\n descriptionNodes.set(desc, node);\n } else {\n setId(node.element.id);\n }\n\n node.refCount++;\n\n onCleanup(() => {\n if (node && --node.refCount === 0) {\n node.element.remove();\n descriptionNodes.delete(desc);\n }\n });\n });\n\n return {\n get \"aria-describedby\"() {\n const desc = description();\n return desc ? id() : undefined;\n },\n };\n}\n\n/**\n * Utility to get all active description nodes (for testing).\n * @internal\n */\nexport function getDescriptionNodeCount(): number {\n return descriptionNodes.size;\n}\n\n/**\n * Utility to clear all description nodes (for testing cleanup).\n * @internal\n */\nexport function clearDescriptionNodes(): void {\n for (const [, node] of descriptionNodes) {\n node.element.remove();\n }\n descriptionNodes.clear();\n}\n","/**\n * Enter/exit animation primitives for Solidaria.\n *\n * A faithful SolidJS port of `react-aria`'s `useEnterAnimation` /\n * `useExitAnimation` (react-aria/src/utils/animation.ts). These drive the\n * `data-entering` / `data-exiting` render-prop flags that overlay styles key\n * their motion tokens off of (opacity/translate transitions on Modal, Popover,\n * Tooltip, …). Without them a styled overlay ships the tokens but never flips\n * the state that triggers the transition, so it appears/disappears instantly.\n *\n * Two mechanisms are covered, exactly as upstream:\n * 1. CSS `@keyframes` — the `animation` property is present while entering and\n * removed when the animation finishes.\n * 2. CSS transitions — the initial styles apply while entering and are removed\n * immediately, so the transition plays. Premature transitions triggered\n * before the ready state (e.g. a popover positioned after mount) are\n * cancelled so only the intended enter transition runs.\n *\n * SolidJS notes:\n * - Refs are passed as accessors (`() => element`) rather than React ref\n * objects, so a signal-backed ref re-runs the effect when the element mounts.\n * - `isReady` gates the enter animation. In React the caller unmounts the\n * overlay while closed, so the hook re-initializes per open; a Solid component\n * often stays mounted with its overlay behind a `<Show>`, so pass\n * `isReady={isOpen}` to defer the enter until the element actually mounts.\n * - `createEffect` replaces `useLayoutEffect`; effects never run during SSR, so\n * the `CSSTransition` reference is only touched on the client.\n */\n\nimport { createEffect, createSignal, onCleanup, type Accessor } from \"solid-js\";\n\n/** A reactive accessor for the animated element (null until mounted). */\nexport type ElementAccessor = () => Element | null | undefined;\n\n/**\n * Runs `onEnd` once the element's animations settle while `isActive` is true.\n * Mirrors the private `useAnimation` helper in react-aria's animation utils.\n */\nfunction createAnimation(\n ref: ElementAccessor,\n isActive: Accessor<boolean>,\n onEnd: () => void,\n): void {\n createEffect(() => {\n if (!isActive()) return;\n const element = ref();\n if (!element) return;\n\n if (!(\"getAnimations\" in element)) {\n // JSDOM and other environments without the Web Animations API.\n onEnd();\n return;\n }\n\n const animations = element.getAnimations();\n if (animations.length === 0) {\n onEnd();\n return;\n }\n\n let canceled = false;\n Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {\n if (!canceled) onEnd();\n });\n\n onCleanup(() => {\n canceled = true;\n });\n });\n}\n\n/**\n * Tracks whether an element is playing its enter animation.\n *\n * Returns an accessor that is `true` while the element should carry\n * `data-entering` (its initial, pre-transition styles), then flips to `false`\n * once the animation is set up — which removes the initial styles and lets the\n * CSS transition play.\n *\n * @param ref - Accessor for the animated element.\n * @param isReady - Whether the element is ready to animate in. Defaults to\n * `true`. Pass an `isOpen` accessor when the component stays mounted while the\n * overlay is hidden, so the enter state does not resolve before the element\n * mounts.\n */\nexport function createEnterAnimation(\n ref: ElementAccessor,\n isReady: Accessor<boolean> = () => true,\n): Accessor<boolean> {\n const [isEntering, setIsEntering] = createSignal(true);\n const isAnimationReady = () => isEntering() && isReady();\n\n // Cancel any transitions triggered before the ready state (case 2 above), so\n // only the intended enter transition — the one that starts when the initial\n // styles are removed — runs.\n createEffect(() => {\n if (!isAnimationReady()) return;\n const element = ref();\n if (!element || !(\"getAnimations\" in element)) return;\n for (const animation of element.getAnimations()) {\n if (animation instanceof CSSTransition) {\n animation.cancel();\n }\n }\n });\n\n createAnimation(ref, isAnimationReady, () => setIsEntering(false));\n\n return isAnimationReady;\n}\n\n/**\n * Tracks whether an element is playing its exit animation.\n *\n * Keeps the caller informed so the element can stay mounted (`isOpen ||\n * isExiting`) until its exit transition finishes. Implements the same\n * `'closed' | 'open' | 'exiting'` state machine as react-aria's\n * `useExitAnimation`, including interruption: reopening mid-exit returns to the\n * open state.\n *\n * @param ref - Accessor for the animated element.\n * @param isOpen - Whether the element is currently open.\n */\nexport function createExitAnimation(\n ref: ElementAccessor,\n isOpen: Accessor<boolean>,\n): Accessor<boolean> {\n const [exitState, setExitState] = createSignal<\"closed\" | \"open\" | \"exiting\">(\n isOpen() ? \"open\" : \"closed\",\n );\n\n createEffect(() => {\n const open = isOpen();\n setExitState((current) => {\n // Open element requested to close: begin exiting.\n if (current === \"open\" && !open) return \"exiting\";\n // Closed or mid-exit element requested to open: the animation was\n // interrupted (or it is a fresh open), so return to the open state.\n if ((current === \"closed\" || current === \"exiting\") && open) return \"open\";\n return current;\n });\n });\n\n const isExiting = () => exitState() === \"exiting\";\n\n createAnimation(ref, isExiting, () => {\n setExitState((state) => (state === \"exiting\" ? \"closed\" : state));\n });\n\n return isExiting;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../src/utils/platform.ts","../../src/utils/scrollIntoView.ts","../../src/utils/geometry.ts","../../src/utils/events.ts","../../src/utils/textSelection.ts","../../src/utils/keyboard.ts","../../src/utils/globalListeners.ts","../../src/utils/createDescription.ts","../../src/utils/animation.ts"],"sourcesContent":["/**\n * Platform detection utilities.\n * Based on @react-aria/utils platform detection.\n */\n\ninterface NavigatorWithUserAgentData extends Navigator {\n userAgentData?: {\n platform?: string;\n };\n}\n\nfunction getNavigator(): NavigatorWithUserAgentData | null {\n if (typeof window === \"undefined\" || window.navigator == null) return null;\n return window.navigator as NavigatorWithUserAgentData;\n}\n\nfunction testPlatform(re: RegExp): boolean {\n const nav = getNavigator();\n if (!nav) return false;\n return re.test(nav.platform || nav.userAgentData?.platform || \"\");\n}\n\nfunction testUserAgent(re: RegExp): boolean {\n const nav = getNavigator();\n return nav ? re.test(nav.userAgent) : false;\n}\n\nexport function isMac(): boolean {\n return testPlatform(/^Mac/i);\n}\n\nexport function isIPhone(): boolean {\n return testPlatform(/^iPhone/i);\n}\n\nexport function isIPad(): boolean {\n return testPlatform(/^iPad/i) || (isMac() && navigator.maxTouchPoints > 1);\n}\n\nexport function isIOS(): boolean {\n return isIPhone() || isIPad();\n}\n\nexport function isAppleDevice(): boolean {\n return isMac() || isIOS();\n}\n\nexport function isWebKit(): boolean {\n return testUserAgent(/AppleWebKit/i) && !isChrome();\n}\n\nexport function isChrome(): boolean {\n return testUserAgent(/Chrome/i);\n}\n\nexport function isAndroid(): boolean {\n return testUserAgent(/Android/i);\n}\n\nexport function isFirefox(): boolean {\n return testUserAgent(/Firefox/i);\n}\n","/**\n * Scroll-into-view utilities.\n * Based on @react-aria/utils scrollIntoView (react-aria/src/utils/scrollIntoView.ts).\n */\n\nimport { getScrollParents } from \"./dom\";\nimport { isIOS } from \"./platform\";\nimport { isTestEnv } from \"./env\";\n\ninterface ScrollIntoViewOpts {\n /** The position to align items along the block axis in. */\n block?: ScrollLogicalPosition;\n /** The position to align items along the inline axis in. */\n inline?: ScrollLogicalPosition;\n}\n\ninterface ScrollIntoViewportOpts {\n /** The optional containing element of the target to be centered in the viewport. */\n containingElement?: Element | null;\n}\n\n/**\n * Scrolls `scrollView` so that `element` is visible.\n * Similar to `element.scrollIntoView({block: 'nearest'})` (not supported in Edge),\n * but doesn't affect parents above `scrollView`.\n */\nexport function scrollIntoView(\n scrollView: HTMLElement,\n element: HTMLElement,\n opts: ScrollIntoViewOpts = {},\n): void {\n const { block = \"nearest\", inline = \"nearest\" } = opts;\n\n if (scrollView === element) {\n return;\n }\n\n let y = scrollView.scrollTop;\n let x = scrollView.scrollLeft;\n\n const target = element.getBoundingClientRect();\n const view = scrollView.getBoundingClientRect();\n const itemStyle = window.getComputedStyle(element);\n const viewStyle = window.getComputedStyle(scrollView);\n const root = document.scrollingElement || document.documentElement;\n const isRoot = scrollView === root;\n\n const viewTop = scrollView === root ? 0 : view.top;\n const viewBottom = scrollView === root ? scrollView.clientHeight : view.bottom;\n const viewLeft = scrollView === root ? 0 : view.left;\n const viewRight = scrollView === root ? scrollView.clientWidth : view.right;\n\n const scrollMarginTop = parseFloat(itemStyle.scrollMarginTop) || 0;\n const scrollMarginBottom = parseFloat(itemStyle.scrollMarginBottom) || 0;\n const scrollMarginLeft = parseFloat(itemStyle.scrollMarginLeft) || 0;\n const scrollMarginRight = parseFloat(itemStyle.scrollMarginRight) || 0;\n\n const scrollPaddingTop = parseFloat(viewStyle.scrollPaddingTop) || 0;\n const scrollPaddingBottom = parseFloat(viewStyle.scrollPaddingBottom) || 0;\n const scrollPaddingLeft = parseFloat(viewStyle.scrollPaddingLeft) || 0;\n const scrollPaddingRight = parseFloat(viewStyle.scrollPaddingRight) || 0;\n\n const borderTopWidth = parseFloat(viewStyle.borderTopWidth) || 0;\n const borderBottomWidth = parseFloat(viewStyle.borderBottomWidth) || 0;\n const borderLeftWidth = parseFloat(viewStyle.borderLeftWidth) || 0;\n const borderRightWidth = parseFloat(viewStyle.borderRightWidth) || 0;\n\n const scrollAreaTop = target.top - scrollMarginTop;\n const scrollAreaBottom = target.bottom + scrollMarginBottom;\n const scrollAreaLeft = target.left - scrollMarginLeft;\n const scrollAreaRight = target.right + scrollMarginRight;\n\n const scrollBarOffsetX = scrollView === root ? 0 : borderLeftWidth + borderRightWidth;\n const scrollBarOffsetY = scrollView === root ? 0 : borderTopWidth + borderBottomWidth;\n const scrollBarWidth =\n scrollView === root ? 0 : scrollView.offsetWidth - scrollView.clientWidth - scrollBarOffsetX;\n const scrollBarHeight =\n scrollView === root ? 0 : scrollView.offsetHeight - scrollView.clientHeight - scrollBarOffsetY;\n\n const scrollPortTop = viewTop + (isRoot ? 0 : borderTopWidth) + scrollPaddingTop;\n const scrollPortBottom =\n viewBottom - (isRoot ? 0 : borderBottomWidth) - scrollPaddingBottom - scrollBarHeight;\n let scrollPortLeft = viewLeft + (isRoot ? 0 : borderLeftWidth) + scrollPaddingLeft;\n let scrollPortRight = viewRight - (isRoot ? 0 : borderRightWidth) - scrollPaddingRight;\n\n // IOS always positions the scrollbar on the right ¯\\_(ツ)_/¯\n if (viewStyle.direction === \"rtl\" && !isIOS()) {\n scrollPortLeft += scrollBarWidth;\n } else {\n scrollPortRight -= scrollBarWidth;\n }\n\n const shouldScrollBlock = scrollAreaTop < scrollPortTop || scrollAreaBottom > scrollPortBottom;\n const shouldScrollInline = scrollAreaLeft < scrollPortLeft || scrollAreaRight > scrollPortRight;\n\n if (shouldScrollBlock && block === \"start\") {\n y += scrollAreaTop - scrollPortTop;\n } else if (shouldScrollBlock && block === \"center\") {\n y += (scrollAreaTop + scrollAreaBottom) / 2 - (scrollPortTop + scrollPortBottom) / 2;\n } else if (shouldScrollBlock && block === \"end\") {\n y += scrollAreaBottom - scrollPortBottom;\n } else if (shouldScrollBlock && block === \"nearest\") {\n const start = scrollAreaTop - scrollPortTop;\n const end = scrollAreaBottom - scrollPortBottom;\n y += Math.abs(start) <= Math.abs(end) ? start : end;\n }\n\n if (shouldScrollInline && inline === \"start\") {\n x += scrollAreaLeft - scrollPortLeft;\n } else if (shouldScrollInline && inline === \"center\") {\n x += (scrollAreaLeft + scrollAreaRight) / 2 - (scrollPortLeft + scrollPortRight) / 2;\n } else if (shouldScrollInline && inline === \"end\") {\n x += scrollAreaRight - scrollPortRight;\n } else if (shouldScrollInline && inline === \"nearest\") {\n const start = scrollAreaLeft - scrollPortLeft;\n const end = scrollAreaRight - scrollPortRight;\n x += Math.abs(start) <= Math.abs(end) ? start : end;\n }\n\n if (isTestEnv()) {\n scrollView.scrollLeft = x;\n scrollView.scrollTop = y;\n return;\n }\n\n scrollView.scrollTo({ left: x, top: y });\n}\n\n/**\n * Scrolls the `targetElement` so it is visible in the viewport. Accepts an optional\n * `opts.containingElement` that will be centered in the viewport prior to scrolling the\n * targetElement into view. If scrolling is prevented on the body (e.g. targetElement is in a\n * popover), this will only scroll the scroll parents of the targetElement up to but not including\n * the body itself.\n */\nexport function scrollIntoViewport(\n targetElement: Element | null,\n opts: ScrollIntoViewportOpts = {},\n): void {\n const { containingElement } = opts;\n if (targetElement && targetElement.isConnected) {\n const root = document.scrollingElement || document.documentElement;\n const isScrollPrevented = window.getComputedStyle(root).overflow === \"hidden\";\n if (!isScrollPrevented) {\n const { left: originalLeft, top: originalTop } = targetElement.getBoundingClientRect();\n\n // use scrollIntoView({block: 'nearest'}) instead of .focus to check if the element is fully in view or not since .focus()\n // won't cause a scroll if the element is already focused and doesn't behave consistently when an element is partially out of view horizontally vs vertically\n targetElement?.scrollIntoView?.({ block: \"nearest\" });\n const { left: newLeft, top: newTop } = targetElement.getBoundingClientRect();\n // Account for sub pixel differences from rounding\n if (Math.abs(originalLeft - newLeft) > 1 || Math.abs(originalTop - newTop) > 1) {\n containingElement?.scrollIntoView?.({ block: \"center\", inline: \"center\" });\n targetElement.scrollIntoView?.({ block: \"nearest\" });\n }\n } else {\n const { left: originalLeft, top: originalTop } = targetElement.getBoundingClientRect();\n\n // If scrolling is prevented, we don't want to scroll the body since it might move the overlay partially offscreen and the user can't scroll it back into view.\n let scrollParents = getScrollParents(targetElement, true);\n for (const scrollParent of scrollParents) {\n scrollIntoView(scrollParent as HTMLElement, targetElement as HTMLElement);\n }\n const { left: newLeft, top: newTop } = targetElement.getBoundingClientRect();\n // Account for sub pixel differences from rounding\n if (Math.abs(originalLeft - newLeft) > 1 || Math.abs(originalTop - newTop) > 1) {\n scrollParents = containingElement ? getScrollParents(containingElement, true) : [];\n // scroll containing element into view first, then rescroll target element into view like the non chrome flow above\n for (const scrollParent of scrollParents) {\n scrollIntoView(scrollParent as HTMLElement, containingElement as HTMLElement, {\n block: \"center\",\n inline: \"center\",\n });\n }\n for (const scrollParent of getScrollParents(targetElement, true)) {\n scrollIntoView(scrollParent as HTMLElement, targetElement as HTMLElement);\n }\n }\n }\n }\n}\n","/**\n * Geometry utilities for pointer/touch hit testing.\n * Based on @react-aria/interactions geometry utilities.\n */\n\nexport interface Rect {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\nexport interface EventPoint {\n clientX: number;\n clientY: number;\n width?: number;\n height?: number;\n radiusX?: number;\n radiusY?: number;\n}\n\n/**\n * Checks if two rectangles overlap.\n */\nexport function areRectanglesOverlapping(a: Rect, b: Rect): boolean {\n if (a.left > b.right || b.left > a.right) {\n return false;\n }\n\n if (a.top > b.bottom || b.top > a.bottom) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Gets the bounding rectangle for an event point (touch/pointer).\n * Takes into account the size of the touch point.\n */\nexport function getPointClientRect(point: EventPoint): Rect {\n let offsetX = 0;\n let offsetY = 0;\n\n if (point.width !== undefined && point.width > 0) {\n offsetX = point.width / 2;\n } else if (point.radiusX !== undefined && point.radiusX > 0) {\n // Fallback to radiusX/radiusY (Touch)\n offsetX = point.radiusX;\n }\n\n if (point.height !== undefined && point.height > 0) {\n offsetY = point.height / 2;\n } else if (point.radiusY !== undefined && point.radiusY > 0) {\n offsetY = point.radiusY;\n }\n\n return {\n top: point.clientY - offsetY,\n right: point.clientX + offsetX,\n bottom: point.clientY + offsetY,\n left: point.clientX - offsetX,\n };\n}\n\n/**\n * Checks if a pointer/touch point is over an element.\n */\nexport function isPointOverTarget(point: EventPoint, target: Element): boolean {\n const rect = target.getBoundingClientRect();\n const pointRect = getPointClientRect(point);\n\n return areRectanglesOverlapping(\n {\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left,\n },\n pointRect,\n );\n}\n\n/**\n * Gets the first touch from a TouchEvent's targetTouches.\n */\nexport function getTouchFromEvent(event: TouchEvent): Touch | null {\n const { targetTouches } = event;\n if (targetTouches.length > 0) {\n return targetTouches[0];\n }\n return null;\n}\n\n/**\n * Finds a touch by its identifier in changedTouches.\n */\nexport function getTouchById(event: TouchEvent, pointerId: number | null): Touch | null {\n if (pointerId == null) {\n return null;\n }\n\n const { changedTouches } = event;\n for (let i = 0; i < changedTouches.length; i++) {\n const touch = changedTouches[i];\n if (touch.identifier === pointerId) {\n return touch;\n }\n }\n\n return null;\n}\n","/**\n * Event utilities for detecting virtual clicks and event handling.\n * Based on @react-aria/utils event utilities.\n */\n\nimport { isAndroid } from \"./platform\";\n\n/**\n * Checks if a click event was generated from a virtual source like a screen reader.\n * Virtual clicks typically have detail of 0 and may have zero coordinates.\n */\nexport function isVirtualClick(event: MouseEvent | PointerEvent): boolean {\n // JAWS/NVDA with Firefox.\n if ((event as PointerEvent).pointerType === \"\" && event.isTrusted) {\n return true;\n }\n\n // Android TalkBack's detail value varies depending on the event listener providing the event.\n // If pointerType is defined, event is from a click listener.\n if (isAndroid() && (event as PointerEvent).pointerType) {\n return event.type === \"click\" && (event as MouseEvent).buttons === 1;\n }\n\n return event.detail === 0 && !(event as PointerEvent).pointerType;\n}\n\n/**\n * Checks if a pointer event was generated by a virtual source.\n * iOS VoiceOver fires pointer events with incorrect coordinates.\n * These events have zero width/height.\n */\nexport function isVirtualPointerEvent(event: PointerEvent): boolean {\n // If the pointer size is zero, then we assume it's from a screen reader.\n // Android TalkBack double tap will sometimes return a event with width and height of 1\n // and pointerType === 'mouse' so we need to check for a specific combination of event attributes.\n // Cannot use \"event.pressure === 0\" as the sole check due to Safari pointer events always returning pressure === 0.\n return (\n (!isAndroid() && event.width === 0 && event.height === 0) ||\n (event.width === 1 &&\n event.height === 1 &&\n event.pressure === 0 &&\n event.detail === 0 &&\n event.pointerType === \"mouse\")\n );\n}\n\n/**\n * Creates a synthetic mouse event for programmatic clicking.\n */\nexport function createMouseEvent(type: string, nativeEvent?: Event): MouseEvent {\n const init: MouseEventInit = {\n bubbles: true,\n cancelable: true,\n view: window,\n };\n\n // Copy properties from the native event if provided\n if (nativeEvent) {\n const e = nativeEvent as MouseEvent;\n init.screenX = e.screenX;\n init.screenY = e.screenY;\n init.clientX = e.clientX;\n init.clientY = e.clientY;\n init.ctrlKey = e.ctrlKey;\n init.shiftKey = e.shiftKey;\n init.altKey = e.altKey;\n init.metaKey = e.metaKey;\n init.button = e.button;\n init.buttons = e.buttons;\n init.relatedTarget = e.relatedTarget;\n }\n\n return new MouseEvent(type, init);\n}\n\n/**\n * Creates a chain of event handlers that calls each in sequence.\n */\nexport function chain<T extends (...args: any[]) => any>(\n ...callbacks: (T | undefined | null)[]\n): T {\n return ((...args: Parameters<T>) => {\n for (const callback of callbacks) {\n if (typeof callback === \"function\") {\n callback(...args);\n }\n }\n }) as T;\n}\n\n/**\n * Sets the target property on an event object.\n * Used for synthetic events where target needs to be modified.\n */\nexport function setEventTarget<T extends Event>(event: T, target: EventTarget): void {\n Object.defineProperty(event, \"target\", {\n value: target,\n writable: false,\n configurable: true,\n });\n Object.defineProperty(event, \"currentTarget\", {\n value: target,\n writable: false,\n configurable: true,\n });\n}\n","/**\n * Text selection management utilities.\n * Based on @react-aria/interactions textSelection utilities.\n *\n * On iOS, long press triggers text selection. The only way to prevent this\n * is to set user-select: none on the entire page. On other platforms,\n * we can just set it on the target element.\n */\n\nimport { isIOS } from \"./platform\";\nimport { getOwnerDocument } from \"./dom\";\n\ntype State = \"default\" | \"disabled\" | \"restoring\";\n\n// Global state to manage text selection across multiple press interactions\nlet state: State = \"default\";\nlet savedUserSelect = \"\";\nlet modifiedElementMap = new WeakMap<HTMLElement, string>();\n\n/**\n * Disables text selection on the page or element during press.\n * On iOS, applies to the entire document. On other platforms, just the target.\n */\nexport function disableTextSelection(target?: HTMLElement): void {\n if (isIOS()) {\n // iOS requires disabling selection on the entire page\n if (state === \"default\") {\n const documentElement = getOwnerDocument(target).documentElement;\n savedUserSelect = documentElement.style.webkitUserSelect;\n documentElement.style.webkitUserSelect = \"none\";\n }\n state = \"disabled\";\n } else if (target) {\n // On other platforms, just disable on the target\n const element = target as HTMLElement;\n if (!modifiedElementMap.has(element)) {\n modifiedElementMap.set(element, element.style.userSelect);\n element.style.userSelect = \"none\";\n }\n }\n}\n\n/**\n * Restores text selection after press ends.\n * On iOS, waits 300ms to avoid selection appearing during tap.\n */\nexport function restoreTextSelection(target?: HTMLElement): void {\n if (isIOS()) {\n // Don't restore if another press is active\n if (state !== \"disabled\") {\n return;\n }\n\n state = \"restoring\";\n\n // Wait for iOS to finish any pending selection actions\n // 300ms is the iOS long-press delay\n setTimeout(() => {\n // Use runAfterTransition to avoid CSS recomputation during animation\n runAfterTransition(() => {\n // Only restore if still in 'restoring' state (no new press started)\n if (state === \"restoring\") {\n const documentElement = getOwnerDocument(target).documentElement;\n if (savedUserSelect) {\n documentElement.style.webkitUserSelect = savedUserSelect;\n } else {\n documentElement.style.removeProperty(\"-webkit-user-select\");\n }\n savedUserSelect = \"\";\n state = \"default\";\n }\n });\n }, 300);\n } else if (target) {\n // On other platforms, restore immediately\n const element = target as HTMLElement;\n const savedValue = modifiedElementMap.get(element);\n if (savedValue !== undefined) {\n if (savedValue) {\n element.style.userSelect = savedValue;\n } else {\n element.style.removeProperty(\"user-select\");\n }\n modifiedElementMap.delete(element);\n }\n }\n}\n\n// Tracks pending transitions for runAfterTransition\nconst pendingTransitions = new Set<() => void>();\nlet transitionTimeout: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Runs a callback after CSS transitions complete.\n * Batches multiple callbacks to avoid unnecessary layout thrashing.\n */\nfunction runAfterTransition(callback: () => void): void {\n // If we haven't started tracking transitions, run immediately\n pendingTransitions.add(callback);\n\n // Debounce - wait for any transitions to settle\n if (transitionTimeout != null) {\n clearTimeout(transitionTimeout);\n }\n\n transitionTimeout = setTimeout(() => {\n // Run all pending callbacks\n for (const cb of pendingTransitions) {\n cb();\n }\n pendingTransitions.clear();\n transitionTimeout = null;\n }, 0);\n}\n","/**\n * Keyboard / modifier-key helpers.\n * Based on @react-aria/utils' keyboard utilities.\n */\n\nimport { isMac } from \"./platform\";\n\n/** The modifier-key fields consulted by {@link isCtrlKeyPressed}. */\ninterface ModifierKeyEvent {\n ctrlKey?: boolean;\n metaKey?: boolean;\n}\n\n/**\n * Returns whether the platform's non-contiguous selection modifier is pressed:\n * the Command key on macOS, the Control key elsewhere. Mirrors\n * `@react-aria/utils`' `isCtrlKeyPressed`.\n */\nexport function isCtrlKeyPressed(e: ModifierKeyEvent): boolean {\n if (isMac()) {\n return e.metaKey === true;\n }\n\n return e.ctrlKey === true;\n}\n","/**\n * Global listener management utility.\n * Based on @react-aria/utils useGlobalListeners hook, adapted for SolidJS.\n *\n * In SolidJS, we use onCleanup for automatic cleanup instead of useEffect return.\n */\n\nimport { onCleanup } from \"solid-js\";\n\nexport interface GlobalListenerOptions extends AddEventListenerOptions {\n /** Whether to add the listener to the window instead of document */\n isWindow?: boolean;\n}\n\n/**\n * Creates a manager for global event listeners that automatically cleans up.\n * Use this in a component to register document/window level listeners\n * that will be removed when the component unmounts.\n */\nexport function createGlobalListeners() {\n const listeners: Array<{\n target: EventTarget;\n type: string;\n handler: EventListener;\n options?: AddEventListenerOptions;\n }> = [];\n\n /**\n * Adds a global event listener.\n */\n function addGlobalListener<K extends keyof DocumentEventMap>(\n type: K,\n handler: (ev: DocumentEventMap[K]) => void,\n options?: GlobalListenerOptions,\n ): void;\n function addGlobalListener<K extends keyof WindowEventMap>(\n type: K,\n handler: (ev: WindowEventMap[K]) => void,\n options?: GlobalListenerOptions & { isWindow: true },\n ): void;\n function addGlobalListener(\n type: string,\n handler: EventListener,\n options?: GlobalListenerOptions,\n ): void {\n const target = options?.isWindow ? window : document;\n const listenerOptions = options\n ? {\n capture: options.capture,\n passive: options.passive,\n once: options.once,\n }\n : undefined;\n\n target.addEventListener(type, handler, listenerOptions);\n listeners.push({ target, type, handler, options: listenerOptions });\n }\n\n /**\n * Removes a specific global event listener.\n */\n function removeGlobalListener<K extends keyof DocumentEventMap>(\n type: K,\n handler: (ev: DocumentEventMap[K]) => void,\n options?: AddEventListenerOptions,\n ): void;\n function removeGlobalListener<K extends keyof WindowEventMap>(\n type: K,\n handler: (ev: WindowEventMap[K]) => void,\n options?: AddEventListenerOptions & { isWindow: true },\n ): void;\n function removeGlobalListener(\n type: string,\n handler: EventListener,\n options?: AddEventListenerOptions & { isWindow?: boolean },\n ): void {\n const target = options?.isWindow ? window : document;\n const listenerOptions = options\n ? {\n capture: options.capture,\n }\n : undefined;\n\n target.removeEventListener(type, handler, listenerOptions);\n\n // Remove from tracked listeners\n const index = listeners.findIndex(\n (l) =>\n l.target === target &&\n l.type === type &&\n l.handler === handler &&\n l.options?.capture === listenerOptions?.capture,\n );\n if (index !== -1) {\n listeners.splice(index, 1);\n }\n }\n\n /**\n * Removes all registered global listeners.\n */\n function removeAllGlobalListeners(): void {\n for (const { target, type, handler, options } of listeners) {\n target.removeEventListener(type, handler, options);\n }\n listeners.length = 0;\n }\n\n // Automatically clean up when the component/scope is disposed\n onCleanup(removeAllGlobalListeners);\n\n return {\n addGlobalListener,\n removeGlobalListener,\n removeAllGlobalListeners,\n };\n}\n\n/**\n * Simple utility to add a single global listener with automatic cleanup.\n * For one-off listeners where the full manager isn't needed.\n */\nexport function addGlobalListenerOnce<K extends keyof DocumentEventMap>(\n type: K,\n handler: (ev: DocumentEventMap[K]) => void,\n options?: GlobalListenerOptions,\n): () => void {\n const target = options?.isWindow ? window : document;\n const listenerOptions = options\n ? {\n capture: options.capture,\n passive: options.passive,\n once: options.once,\n }\n : undefined;\n\n target.addEventListener(type, handler as EventListener, listenerOptions);\n\n return () => {\n target.removeEventListener(type, handler as EventListener, listenerOptions);\n };\n}\n","/**\n * createDescription - Creates a hidden element for dynamic aria-describedby content.\n *\n * This utility creates a visually hidden element containing description text and\n * returns an aria-describedby prop pointing to it. Multiple components using the\n * same description will share the same element (reference counted).\n *\n * Port of @react-aria/utils/useDescription.\n *\n * @example\n * ```tsx\n * function SortableColumn(props) {\n * const descriptionProps = createDescription(\n * () => props.sortDirection ? `Sorted ${props.sortDirection}` : undefined\n * );\n *\n * return (\n * <th {...descriptionProps}>\n * {props.children}\n * </th>\n * );\n * }\n * ```\n */\n\nimport { createSignal, createEffect, onCleanup, type Accessor } from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\n\nexport interface DescriptionProps {\n \"aria-describedby\"?: string;\n}\n\nlet descriptionId = 0;\nconst descriptionNodes = new Map<string, { refCount: number; element: Element }>();\n\n/**\n * Creates an invisible description element and returns aria-describedby props.\n *\n * The element is created in the DOM and reference counted - multiple uses of\n * the same description text will share the same element. When all references\n * are removed, the element is cleaned up.\n *\n * @param description - Accessor that returns the description text, or undefined\n * @returns Object with aria-describedby prop (or empty object if no description)\n *\n * @example\n * ```tsx\n * const descProps = createDescription(() => 'Press Enter to submit');\n * return <button {...descProps}>Submit</button>;\n * ```\n */\nexport function createDescription(description: Accessor<string | undefined>): DescriptionProps {\n if (isServer) {\n return {};\n }\n\n const [id, setId] = createSignal<string | undefined>();\n\n createEffect(() => {\n const desc = description();\n\n if (!desc) {\n setId(undefined);\n return;\n }\n\n let node = descriptionNodes.get(desc);\n\n if (!node) {\n const newId = `solidaria-description-${descriptionId++}`;\n setId(newId);\n\n const element = document.createElement(\"div\");\n element.id = newId;\n element.style.display = \"none\";\n element.textContent = desc;\n document.body.appendChild(element);\n\n node = { refCount: 0, element };\n descriptionNodes.set(desc, node);\n } else {\n setId(node.element.id);\n }\n\n node.refCount++;\n\n onCleanup(() => {\n if (node && --node.refCount === 0) {\n node.element.remove();\n descriptionNodes.delete(desc);\n }\n });\n });\n\n return {\n get \"aria-describedby\"() {\n const desc = description();\n return desc ? id() : undefined;\n },\n };\n}\n\n/**\n * Utility to get all active description nodes (for testing).\n * @internal\n */\nexport function getDescriptionNodeCount(): number {\n return descriptionNodes.size;\n}\n\n/**\n * Utility to clear all description nodes (for testing cleanup).\n * @internal\n */\nexport function clearDescriptionNodes(): void {\n for (const [, node] of descriptionNodes) {\n node.element.remove();\n }\n descriptionNodes.clear();\n}\n","/**\n * Enter/exit animation primitives for Solidaria.\n *\n * A faithful SolidJS port of `react-aria`'s `useEnterAnimation` /\n * `useExitAnimation` (react-aria/src/utils/animation.ts). These drive the\n * `data-entering` / `data-exiting` render-prop flags that overlay styles key\n * their motion tokens off of (opacity/translate transitions on Modal, Popover,\n * Tooltip, …). Without them a styled overlay ships the tokens but never flips\n * the state that triggers the transition, so it appears/disappears instantly.\n *\n * Two mechanisms are covered, exactly as upstream:\n * 1. CSS `@keyframes` — the `animation` property is present while entering and\n * removed when the animation finishes.\n * 2. CSS transitions — the initial styles apply while entering and are removed\n * immediately, so the transition plays. Premature transitions triggered\n * before the ready state (e.g. a popover positioned after mount) are\n * cancelled so only the intended enter transition runs.\n *\n * SolidJS notes:\n * - Refs are passed as accessors (`() => element`) rather than React ref\n * objects, so a signal-backed ref re-runs the effect when the element mounts.\n * - `isReady` gates the enter animation. In React the caller unmounts the\n * overlay while closed, so the hook re-initializes per open; a Solid component\n * often stays mounted with its overlay behind a `<Show>`, so pass\n * `isReady={isOpen}` to defer the enter until the element actually mounts.\n * - `createEffect` replaces `useLayoutEffect`; effects never run during SSR, so\n * the `CSSTransition` reference is only touched on the client.\n */\n\nimport {\n createComputed,\n createEffect,\n createMemo,\n createSignal,\n onCleanup,\n type Accessor,\n} from \"solid-js\";\n\n/** A reactive accessor for the animated element (null until mounted). */\nexport type ElementAccessor = () => Element | null | undefined;\n\n/**\n * Runs `onEnd` once the element's animations settle while `isActive` is true.\n * Mirrors the private `useAnimation` helper in react-aria's animation utils.\n *\n * `deferNoAnimation` mirrors React's timing for the no-animation case. Upstream\n * runs `onEnd` inside a `useLayoutEffect`, so an animation-less exit unmounts\n * *after* React commits — i.e. after the triggering input event finishes\n * dispatching (empirically, an Escape's teardown lands after `keyup`, not\n * between `keydown` and `keyup`). A Solid `createEffect` runs synchronously\n * inside the handler, so an animation-less exit would tear the overlay out\n * mid-gesture, firing `focusout` before `keyup` and retargeting `keyup` to the\n * body. Deferring `onEnd` to the next frame — the same primitive `FocusScope`\n * uses to defer focus restore — reproduces React's post-commit ordering. Only\n * the real-browser no-animation branch defers; the JSDOM branch stays\n * synchronous so unit tests that assert immediate unmount are unaffected.\n */\nfunction createAnimation(\n ref: ElementAccessor,\n isActive: Accessor<boolean>,\n onEnd: () => void,\n deferNoAnimation = false,\n): void {\n createEffect(() => {\n if (!isActive()) return;\n const element = ref();\n if (!element) return;\n\n if (!(\"getAnimations\" in element)) {\n // JSDOM and other environments without the Web Animations API.\n onEnd();\n return;\n }\n\n // `settle` mirrors React's post-commit `useLayoutEffect` timing (see the\n // `deferNoAnimation` note above): a Solid effect runs synchronously inside\n // the triggering input handler, and even the Web-Animations `finished`\n // promise resolves in a microtask that drains *before* the gesture's later\n // events (e.g. an Escape's `keyup`). Deferring the settle to the next frame\n // pushes the overlay teardown past the rest of the current event dispatch,\n // reproducing React's ordering (teardown after `keyup`, not between\n // `keydown` and `keyup`). A real, non-trivial exit transition already\n // finishes long after the gesture, so the extra frame is imperceptible; it\n // only matters for the instant/near-zero-duration exits that would\n // otherwise tear the focused overlay out mid-gesture. Unit environments\n // (no `requestAnimationFrame`, or the no-defer callers) settle synchronously.\n //\n // A single owner-bound `onCleanup` tracks both the pending frame and a\n // `canceled` flag — the flag guards the promise path, whose `.then` runs\n // outside the reactive owner where `onCleanup` could not register.\n let canceled = false;\n let frame: number | undefined;\n const settle = () => {\n if (canceled) return;\n if (deferNoAnimation && typeof requestAnimationFrame === \"function\") {\n frame = requestAnimationFrame(() => {\n if (!canceled) onEnd();\n });\n } else {\n onEnd();\n }\n };\n\n const animations = element.getAnimations();\n if (animations.length === 0) {\n settle();\n } else {\n Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {\n settle();\n });\n }\n\n onCleanup(() => {\n canceled = true;\n if (frame !== undefined && typeof cancelAnimationFrame === \"function\") {\n cancelAnimationFrame(frame);\n }\n });\n });\n}\n\n/**\n * Tracks whether an element is playing its enter animation.\n *\n * Returns an accessor that is `true` while the element should carry\n * `data-entering` (its initial, pre-transition styles), then flips to `false`\n * once the animation is set up — which removes the initial styles and lets the\n * CSS transition play.\n *\n * @param ref - Accessor for the animated element.\n * @param isReady - Whether the element is ready to animate in. Defaults to\n * `true`. Pass an `isOpen` accessor when the component stays mounted while the\n * overlay is hidden, so the enter state does not resolve before the element\n * mounts.\n */\nexport function createEnterAnimation(\n ref: ElementAccessor,\n isReady: Accessor<boolean> = () => true,\n): Accessor<boolean> {\n const [isEntering, setIsEntering] = createSignal(true);\n const isAnimationReady = () => isEntering() && isReady();\n\n // Cancel any transitions triggered before the ready state (case 2 above), so\n // only the intended enter transition — the one that starts when the initial\n // styles are removed — runs.\n createEffect(() => {\n if (!isAnimationReady()) return;\n const element = ref();\n if (!element || !(\"getAnimations\" in element)) return;\n for (const animation of element.getAnimations()) {\n if (animation instanceof CSSTransition) {\n animation.cancel();\n }\n }\n });\n\n createAnimation(ref, isAnimationReady, () => setIsEntering(false));\n\n return isAnimationReady;\n}\n\n/**\n * Tracks whether an element is playing its exit animation.\n *\n * Keeps the caller informed so the element can stay mounted (`isOpen ||\n * isExiting`) until its exit transition finishes. Implements the same\n * `'closed' | 'open' | 'exiting'` state machine as react-aria's\n * `useExitAnimation`, including interruption: reopening mid-exit returns to the\n * open state.\n *\n * @param ref - Accessor for the animated element.\n * @param isOpen - Whether the element is currently open.\n */\nexport function createExitAnimation(\n ref: ElementAccessor,\n isOpen: Accessor<boolean>,\n): Accessor<boolean> {\n // The state machine's synchronous edges (open→exiting on close, →open on\n // reopen) are computed in a `createMemo`, NOT a `createEffect`. This is the\n // Solid equivalent of react-aria's `setState`-*during-render*: because the\n // memo is a dependency of the caller's mount gate (`isOpen() || isExiting()`),\n // Solid recomputes it *before* the gate in the same synchronous propagation\n // that flips `isOpen`. A `createEffect` runs in the later effects phase, so\n // the gate would first observe `!isOpen && !isExiting` and unmount the\n // overlay, then the effect would flip `exiting` true and remount it from\n // scratch — recreating the whole subtree (Dialog section, focus scope) and\n // firing a spurious focus bounce mid-gesture. The memo closes that window so\n // the overlay stays mounted continuously through the exit, matching React's\n // single-commit `isOpen || isExiting`.\n //\n // Only the *async* edge (exiting→closed, when the animation settles) stays\n // event-driven: `createAnimation` bumps `exitFinished`, and the memo\n // acknowledges the new value via `ackedFinish` carried in its own previous\n // result — a pure epoch/ack so the memo never mutates external state.\n type ExitState = \"closed\" | \"open\" | \"exiting\";\n const [exitFinished, setExitFinished] = createSignal(0);\n\n const exitState = createMemo<{ state: ExitState; ackedFinish: number }>(\n (prev) => {\n const open = isOpen();\n const finish = exitFinished();\n const compute = (): { state: ExitState; ackedFinish: number } => {\n if (open) return { state: \"open\", ackedFinish: finish };\n // Open element requested to close: begin exiting.\n if (prev.state === \"open\") return { state: \"exiting\", ackedFinish: finish };\n // Mid-exit: settle to closed only once the animation reports a new finish.\n if (prev.state === \"exiting\") {\n if (finish !== prev.ackedFinish) return { state: \"closed\", ackedFinish: finish };\n return prev;\n }\n return { state: \"closed\", ackedFinish: finish };\n };\n return compute();\n },\n { state: isOpen() ? \"open\" : \"closed\", ackedFinish: 0 },\n );\n\n const isExiting = () => exitState().state === \"exiting\";\n\n // Keep the state machine eagerly subscribed. The caller's mount gate\n // `isOpen() || isExiting()` short-circuits on `isOpen()` while open and never\n // reads `isExiting`, so this lazy memo would go unobserved for the whole open\n // lifetime — never advancing to \"open\". Then on close it would recompute once,\n // straight from its stale initial \"closed\" back to \"closed\" (the \"open→exiting\"\n // edge never taken), collapsing the exit: `combinedExiting` stays false, the\n // caller's `<Show>` sees the gate go falsy, and the overlay Portal unmounts\n // synchronously mid-gesture (blurring the focused dialog to <body> before the\n // triggering key's `keyup`). An eager reader forces the memo to track `isOpen`\n // continuously so `prev.state === \"open\"` holds when the close edge runs —\n // mirroring React, whose component re-renders and re-derives this every commit.\n createComputed(() => void exitState());\n\n createAnimation(\n ref,\n isExiting,\n () => {\n setExitFinished((n) => n + 1);\n },\n true,\n );\n\n return isExiting;\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { r as isTestEnv } from "./env.jsx";
2
2
  import { s as getOwnerDocument, u as getScrollParents } from "./focus.jsx";
3
- import { createEffect, createSignal, onCleanup } from "solid-js";
3
+ import { createComputed, createEffect, createMemo, createSignal, onCleanup } from "solid-js";
4
4
  import { isServer } from "solid-js/web";
5
5
  //#region src/utils/platform.ts
6
6
  function getNavigator() {
@@ -581,8 +581,20 @@ function clearDescriptionNodes() {
581
581
  /**
582
582
  * Runs `onEnd` once the element's animations settle while `isActive` is true.
583
583
  * Mirrors the private `useAnimation` helper in react-aria's animation utils.
584
+ *
585
+ * `deferNoAnimation` mirrors React's timing for the no-animation case. Upstream
586
+ * runs `onEnd` inside a `useLayoutEffect`, so an animation-less exit unmounts
587
+ * *after* React commits — i.e. after the triggering input event finishes
588
+ * dispatching (empirically, an Escape's teardown lands after `keyup`, not
589
+ * between `keydown` and `keyup`). A Solid `createEffect` runs synchronously
590
+ * inside the handler, so an animation-less exit would tear the overlay out
591
+ * mid-gesture, firing `focusout` before `keyup` and retargeting `keyup` to the
592
+ * body. Deferring `onEnd` to the next frame — the same primitive `FocusScope`
593
+ * uses to defer focus restore — reproduces React's post-commit ordering. Only
594
+ * the real-browser no-animation branch defers; the JSDOM branch stays
595
+ * synchronous so unit tests that assert immediate unmount are unaffected.
584
596
  */
585
- function createAnimation(ref, isActive, onEnd) {
597
+ function createAnimation(ref, isActive, onEnd, deferNoAnimation = false) {
586
598
  createEffect(() => {
587
599
  if (!isActive()) return;
588
600
  const element = ref();
@@ -591,17 +603,23 @@ function createAnimation(ref, isActive, onEnd) {
591
603
  onEnd();
592
604
  return;
593
605
  }
594
- const animations = element.getAnimations();
595
- if (animations.length === 0) {
596
- onEnd();
597
- return;
598
- }
599
606
  let canceled = false;
600
- Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {
601
- if (!canceled) onEnd();
607
+ let frame;
608
+ const settle = () => {
609
+ if (canceled) return;
610
+ if (deferNoAnimation && typeof requestAnimationFrame === "function") frame = requestAnimationFrame(() => {
611
+ if (!canceled) onEnd();
612
+ });
613
+ else onEnd();
614
+ };
615
+ const animations = element.getAnimations();
616
+ if (animations.length === 0) settle();
617
+ else Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {
618
+ settle();
602
619
  });
603
620
  onCleanup(() => {
604
621
  canceled = true;
622
+ if (frame !== void 0 && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame);
605
623
  });
606
624
  });
607
625
  }
@@ -644,19 +662,41 @@ function createEnterAnimation(ref, isReady = () => true) {
644
662
  * @param isOpen - Whether the element is currently open.
645
663
  */
646
664
  function createExitAnimation(ref, isOpen) {
647
- const [exitState, setExitState] = createSignal(isOpen() ? "open" : "closed");
648
- createEffect(() => {
665
+ const [exitFinished, setExitFinished] = createSignal(0);
666
+ const exitState = createMemo((prev) => {
649
667
  const open = isOpen();
650
- setExitState((current) => {
651
- if (current === "open" && !open) return "exiting";
652
- if ((current === "closed" || current === "exiting") && open) return "open";
653
- return current;
654
- });
668
+ const finish = exitFinished();
669
+ const compute = () => {
670
+ if (open) return {
671
+ state: "open",
672
+ ackedFinish: finish
673
+ };
674
+ if (prev.state === "open") return {
675
+ state: "exiting",
676
+ ackedFinish: finish
677
+ };
678
+ if (prev.state === "exiting") {
679
+ if (finish !== prev.ackedFinish) return {
680
+ state: "closed",
681
+ ackedFinish: finish
682
+ };
683
+ return prev;
684
+ }
685
+ return {
686
+ state: "closed",
687
+ ackedFinish: finish
688
+ };
689
+ };
690
+ return compute();
691
+ }, {
692
+ state: isOpen() ? "open" : "closed",
693
+ ackedFinish: 0
655
694
  });
656
- const isExiting = () => exitState() === "exiting";
695
+ const isExiting = () => exitState().state === "exiting";
696
+ createComputed(() => void exitState());
657
697
  createAnimation(ref, isExiting, () => {
658
- setExitState((state) => state === "exiting" ? "closed" : state);
659
- });
698
+ setExitFinished((n) => n + 1);
699
+ }, true);
660
700
  return isExiting;
661
701
  }
662
702
  //#endregion