@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,15 +1,32 @@
1
1
  /**
2
2
  * createDateSegment hook for Solidaria
3
3
  *
4
- * Provides the behavior and accessibility implementation for a date segment.
5
- * Based on @react-aria/datepicker useDateSegment
4
+ * Provides the behavior and accessibility implementation for a single editable
5
+ * date segment. Faithful port of @react-aria/datepicker `useDateSegment` — the
6
+ * spinbutton wiring (value stepping + live announcements) is delegated to
7
+ * `createSpinButton`, numeric text entry flows through native `beforeinput`
8
+ * events, and segment focus recovery on unmount mirrors upstream's layout effect.
6
9
  */
7
10
 
8
- import { createSignal, createMemo, onCleanup } from "solid-js";
11
+ import { createMemo, createEffect, onCleanup } from "solid-js";
12
+ import { toCalendar, CalendarDate } from "@internationalized/date";
13
+ import { NumberParser } from "@internationalized/number";
9
14
  import { access, type MaybeAccessor } from "../utils/reactivity";
10
- import { scrollIntoViewport, getScrollParent } from "../utils";
15
+ import { mergeProps } from "../utils/mergeProps";
16
+ import {
17
+ isMac,
18
+ isIOS,
19
+ scrollIntoViewport,
20
+ getScrollParent,
21
+ nodeContains,
22
+ } from "../utils";
23
+ import { createId } from "../ssr";
24
+ import { createLabels } from "../label/createLabels";
25
+ import { useLocale, createDateFormatter, createFilter } from "../i18n";
26
+ import { createSpinButton } from "../spinbutton";
27
+ import { createDisplayNames } from "./createDisplayNames";
28
+ import { hookData } from "./createDateField";
11
29
  import type { DateFieldState, DateSegment, DateSegmentType } from "@proyecto-viviana/solid-stately";
12
- import { useLocale } from "../i18n";
13
30
 
14
31
  export interface AriaDateSegmentProps {
15
32
  /** The segment data. */
@@ -23,18 +40,18 @@ export interface AriaDateSegmentProps {
23
40
  export interface DateSegmentAria {
24
41
  /** Props for the segment element. */
25
42
  segmentProps: Record<string, unknown>;
26
- /** Whether the segment is focused. */
27
- isFocused: boolean;
28
- /** Whether the segment is editable. */
29
- isEditable: boolean;
30
- /** Whether the segment is a placeholder. */
31
- isPlaceholder: boolean;
32
- /** The text to display. */
33
- text: string;
34
- /** Whether the segment is hovered. */
35
- isHovered: boolean;
36
- /** Whether the segment has keyboard focus visible. */
37
- isFocusVisible: boolean;
43
+ }
44
+
45
+ function commonPrefixLength(strings: string[]): number {
46
+ strings.sort();
47
+ const first = strings[0];
48
+ const last = strings[strings.length - 1];
49
+ for (let i = 0; i < first.length; i++) {
50
+ if (first[i] !== last[i]) {
51
+ return i;
52
+ }
53
+ }
54
+ return 0;
38
55
  }
39
56
 
40
57
  /**
@@ -43,433 +60,413 @@ export interface DateSegmentAria {
43
60
  export function createDateSegment<T extends DateFieldState>(
44
61
  props: MaybeAccessor<AriaDateSegmentProps>,
45
62
  state: T,
46
- ref?: () => HTMLElement | null,
63
+ ref: () => HTMLElement | null,
47
64
  ): DateSegmentAria {
48
65
  const getProps = () => access(props);
49
- const [isFocused, setIsFocused] = createSignal(false);
50
- const [isFocusVisible, setIsFocusVisible] = createSignal(false);
51
- const [isHovered, setIsHovered] = createSignal(false);
52
- const [enteredKeys, setEnteredKeys] = createSignal("");
53
- const [isComposing, setIsComposing] = createSignal(false);
54
- const locale = useLocale();
66
+ const segment = () => getProps().segment;
67
+ let enteredKeys = "";
68
+ const localeInfo = useLocale();
69
+ const locale = () => localeInfo().locale;
70
+ const direction = () => localeInfo().direction;
71
+ const displayNames = createDisplayNames();
72
+ const hd = hookData.get(state as unknown as object) as
73
+ | {
74
+ ariaLabel?: string;
75
+ ariaLabelledBy?: string;
76
+ ariaDescribedBy?: () => string | undefined;
77
+ focusManager: {
78
+ focusNext: () => HTMLElement | null;
79
+ focusPrevious: () => HTMLElement | null;
80
+ };
81
+ }
82
+ | undefined;
83
+ const focusManager = hd?.focusManager;
84
+ const segmentId = createId();
85
+
86
+ const resolvedOptions = state.dateFormatter.resolvedOptions();
87
+ const monthDateFormatter = createDateFormatter({
88
+ month: "long",
89
+ timeZone: resolvedOptions.timeZone,
90
+ });
91
+ const hourDateFormatter = createDateFormatter({
92
+ hour: "numeric",
93
+ hour12: resolvedOptions.hour12,
94
+ timeZone: resolvedOptions.timeZone,
95
+ });
55
96
 
56
- // Get the segment from props
57
- const segment = createMemo(() => getProps().segment);
97
+ const textValue = createMemo(() => {
98
+ const seg = segment();
99
+ let value = seg.isPlaceholder ? "" : seg.text;
100
+ if (seg.type === "month" && !seg.isPlaceholder) {
101
+ const monthTextValue = monthDateFormatter().format(state.dateValue());
102
+ value = monthTextValue !== value ? `${value} \u{2013} ${monthTextValue}` : monthTextValue;
103
+ } else if (seg.type === "hour" && !seg.isPlaceholder) {
104
+ value = hourDateFormatter().format(state.dateValue());
105
+ }
106
+ return value;
107
+ });
58
108
 
59
- // Check if editable
60
- const isEditable = createMemo(() => {
109
+ const spinButton = createSpinButton(() => {
61
110
  const seg = segment();
62
- return seg.isEditable && !state.isDisabled() && !state.isReadOnly();
111
+ return {
112
+ // The ARIA spec says aria-valuenow is optional if there's no value, but aXe requires it.
113
+ value: seg.value ?? undefined,
114
+ textValue: textValue(),
115
+ minValue: seg.minValue,
116
+ maxValue: seg.maxValue,
117
+ isDisabled: state.isDisabled(),
118
+ isReadOnly: state.isReadOnly() || !seg.isEditable,
119
+ isRequired: state.isRequired(),
120
+ onIncrement: () => {
121
+ enteredKeys = "";
122
+ state.increment(seg.type);
123
+ },
124
+ onDecrement: () => {
125
+ enteredKeys = "";
126
+ state.decrement(seg.type);
127
+ },
128
+ onIncrementPage: () => {
129
+ enteredKeys = "";
130
+ state.incrementPage(seg.type);
131
+ },
132
+ onDecrementPage: () => {
133
+ enteredKeys = "";
134
+ state.decrementPage(seg.type);
135
+ },
136
+ onIncrementToMax: () => {
137
+ enteredKeys = "";
138
+ state.incrementToMax(seg.type);
139
+ },
140
+ onDecrementToMin: () => {
141
+ enteredKeys = "";
142
+ state.decrementToMin(seg.type);
143
+ },
144
+ };
63
145
  });
64
146
 
65
- // Long press state for ArrowUp / ArrowDown
66
- let longPressTimeout: ReturnType<typeof setTimeout> | null = null;
67
- let longPressInterval: ReturnType<typeof setInterval> | null = null;
68
- let hadPointerDown = false;
147
+ const parser = createMemo(() => new NumberParser(locale(), { maximumFractionDigits: 0 }));
69
148
 
70
- const clearLongPress = () => {
71
- if (longPressTimeout) {
72
- clearTimeout(longPressTimeout);
73
- longPressTimeout = null;
149
+ const backspace = () => {
150
+ const seg = segment();
151
+ if (seg.text === seg.placeholder) {
152
+ focusManager?.focusPrevious();
74
153
  }
75
- if (longPressInterval) {
76
- clearInterval(longPressInterval);
77
- longPressInterval = null;
154
+ if (parser().isValidPartialNumber(seg.text) && !state.isReadOnly() && !seg.isPlaceholder) {
155
+ let newValue = seg.text.slice(0, -1);
156
+ const parsed = parser().parse(newValue);
157
+ newValue = parsed === 0 ? "" : newValue;
158
+ if (newValue.length === 0 || parsed === 0) {
159
+ state.clearSegment(seg.type);
160
+ } else {
161
+ state.setSegment(seg.type, parsed);
162
+ }
163
+ enteredKeys = newValue;
164
+ } else if (seg.type === "dayPeriod" || seg.type === "era") {
165
+ state.clearSegment(seg.type);
78
166
  }
79
167
  };
80
168
 
81
- const startLongPress = (action: () => void) => {
82
- clearLongPress();
83
- longPressTimeout = setTimeout(() => {
84
- action();
85
- longPressInterval = setInterval(() => {
86
- action();
87
- }, 100);
88
- }, 300);
89
- };
90
-
91
- onCleanup(() => {
92
- clearLongPress();
93
- });
94
-
95
- const focusSegment = (target: "first" | "last" | "prev" | "next") => {
96
- const el = ref?.();
97
- if (!el) return;
98
-
99
- const container = el.parentElement;
100
- if (!container) return;
101
-
102
- const segments = Array.from(container.querySelectorAll<HTMLElement>('[role="spinbutton"]'));
103
-
104
- if (segments.length === 0) return;
105
-
106
- if (target === "first") {
107
- segments[0]?.focus();
108
- return;
169
+ const onKeyDown = (e: KeyboardEvent) => {
170
+ // Firefox does not fire selectstart for Ctrl/Cmd + A
171
+ if (e.key === "a" && (isMac() ? e.metaKey : e.ctrlKey)) {
172
+ e.preventDefault();
109
173
  }
110
-
111
- if (target === "last") {
112
- segments[segments.length - 1]?.focus();
174
+ if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) {
113
175
  return;
114
176
  }
115
-
116
- const currentIndex = segments.indexOf(el);
117
- if (currentIndex < 0) return;
118
-
119
- const nextIndex = target === "next" ? currentIndex + 1 : currentIndex - 1;
120
- if (nextIndex >= 0 && nextIndex < segments.length) {
121
- segments[nextIndex]?.focus();
122
- }
123
- };
124
-
125
- const clearCurrentSegment = (type: DateSegmentType) => {
126
- state.clearSegment(type);
127
- setEnteredKeys("");
128
- };
129
-
130
- // Handle keyboard input
131
- const handleKeyDown = (e: KeyboardEvent) => {
132
- if (!isEditable()) return;
133
- if (isComposing()) return;
134
-
135
- const seg = segment();
136
- const type = seg.type;
137
-
138
- if (type === "literal") return;
139
-
140
- // Keyboard interaction means focus is visible
141
- setIsFocusVisible(true);
142
-
143
177
  switch (e.key) {
144
- case "ArrowRight":
145
- e.preventDefault();
146
- focusSegment(locale().direction === "rtl" ? "prev" : "next");
147
- break;
148
- case "ArrowLeft":
149
- e.preventDefault();
150
- focusSegment(locale().direction === "rtl" ? "next" : "prev");
151
- break;
152
- case "ArrowUp":
153
- e.preventDefault();
154
- state.incrementSegment(type);
155
- if (!e.repeat) {
156
- startLongPress(() => state.incrementSegment(type));
157
- }
158
- break;
159
- case "ArrowDown":
160
- e.preventDefault();
161
- state.decrementSegment(type);
162
- if (!e.repeat) {
163
- startLongPress(() => state.decrementSegment(type));
164
- }
165
- break;
166
- case "Home":
167
- e.preventDefault();
168
- focusSegment("first");
169
- break;
170
- case "End":
171
- e.preventDefault();
172
- focusSegment("last");
173
- break;
174
178
  case "Backspace":
175
- e.preventDefault();
176
- // Match common date-field UX: backspace on an empty placeholder moves to previous segment.
177
- if (seg.isPlaceholder) {
178
- focusSegment("prev");
179
- } else {
180
- clearCurrentSegment(type);
181
- }
182
- break;
183
179
  case "Delete":
180
+ // Safari on iOS does not fire beforeinput for the backspace key because the cursor is at the start.
184
181
  e.preventDefault();
185
- clearCurrentSegment(type);
186
- break;
187
- default:
188
- // Handle numeric input
189
- const normalizedDigit = normalizeDigit(e.key);
190
- if (normalizedDigit) {
191
- e.preventDefault();
192
- handleNumericInput(normalizedDigit, type, seg);
193
- }
182
+ e.stopPropagation();
183
+ backspace();
194
184
  break;
195
185
  }
196
186
  };
197
187
 
198
- const handleKeyUp = () => {
199
- clearLongPress();
200
- };
201
-
202
- // Handle numeric input
203
- const handleNumericInput = (key: string, type: DateSegmentType, seg: DateSegment) => {
204
- const newKeys = enteredKeys() + key;
205
- const numValue = parseInt(newKeys, 10);
206
- const maxValue = seg.maxValue ?? 99;
207
- const minValue = seg.minValue ?? 0;
208
- const maxDigits = String(maxValue).length;
209
-
210
- // Check if we should accept more digits
211
- if (numValue <= maxValue) {
212
- state.setSegment(type, numValue);
188
+ const { startsWith } = createFilter({ sensitivity: "base" })();
189
+ const amPmFormatter = createDateFormatter({ hour: "numeric", hour12: true });
190
+ const am = createMemo(() => {
191
+ const date = new Date();
192
+ date.setHours(0);
193
+ return amPmFormatter().formatToParts(date).find((part) => part.type === "dayPeriod")?.value ?? "";
194
+ });
195
+ const pm = createMemo(() => {
196
+ const date = new Date();
197
+ date.setHours(12);
198
+ return amPmFormatter().formatToParts(date).find((part) => part.type === "dayPeriod")?.value ?? "";
199
+ });
213
200
 
214
- // If entering more digits wouldn't make sense, clear entered keys
215
- const potentialNextValue = parseInt(newKeys + "0", 10);
216
- if (potentialNextValue > maxValue || newKeys.length >= maxDigits) {
217
- setEnteredKeys("");
218
- focusSegment("next");
219
- } else {
220
- setEnteredKeys(newKeys);
221
- }
222
- } else {
223
- // Start fresh with just this key
224
- const singleValue = parseInt(key, 10);
225
- if (singleValue >= minValue && singleValue <= maxValue) {
226
- state.setSegment(type, singleValue);
227
- const potentialNextValue = parseInt(key + "0", 10);
228
- if (potentialNextValue > maxValue || key.length >= maxDigits) {
229
- setEnteredKeys("");
230
- focusSegment("next");
231
- } else {
232
- setEnteredKeys(key);
233
- }
234
- } else {
235
- setEnteredKeys("");
201
+ // Get a list of formatted era names so users can type the first character to choose one.
202
+ const eraFormatter = createDateFormatter({ year: "numeric", era: "narrow", timeZone: "UTC" });
203
+ const eras = createMemo(() => {
204
+ if (segment().type !== "era") {
205
+ return [] as Array<{ era: string; formatted: string }>;
206
+ }
207
+ const date = toCalendar(new CalendarDate(1, 1, 1), state.calendar);
208
+ const list = state.calendar.getEras().map((era) => {
209
+ const eraDate = date.set({ year: 1, month: 1, day: 1, era }).toDate("UTC");
210
+ const parts = eraFormatter().formatToParts(eraDate);
211
+ const formatted = parts.find((p) => p.type === "era")?.value ?? "";
212
+ return { era, formatted };
213
+ });
214
+ const prefixLength = commonPrefixLength(list.map((era) => era.formatted));
215
+ if (prefixLength) {
216
+ for (const era of list) {
217
+ era.formatted = era.formatted.slice(prefixLength);
236
218
  }
237
219
  }
238
- };
239
-
240
- const handleBeforeInput = (e: InputEvent) => {
241
- if (!isEditable()) return;
242
- if (isComposing()) return;
220
+ return list;
221
+ });
243
222
 
223
+ const onInput = (key: string) => {
244
224
  const seg = segment();
245
- if (seg.type === "literal") return;
246
-
247
- if (e.inputType === "deleteContentBackward" || e.inputType === "deleteContentForward") {
248
- e.preventDefault();
249
- clearCurrentSegment(seg.type);
225
+ if (state.isDisabled() || state.isReadOnly()) {
250
226
  return;
251
227
  }
252
-
253
- if (e.inputType === "insertText" && e.data) {
254
- const normalizedDigit = normalizeDigit(e.data);
255
- if (!normalizedDigit) return;
256
- e.preventDefault();
257
- handleNumericInput(normalizedDigit, seg.type, seg);
228
+ const newValue = enteredKeys + key;
229
+ switch (seg.type) {
230
+ case "dayPeriod":
231
+ if (startsWith(am(), key)) {
232
+ state.setSegment("dayPeriod", 0);
233
+ } else if (startsWith(pm(), key)) {
234
+ state.setSegment("dayPeriod", 1);
235
+ } else {
236
+ break;
237
+ }
238
+ focusManager?.focusNext();
239
+ break;
240
+ case "era": {
241
+ const matched = eras().find((e) => startsWith(e.formatted, key));
242
+ if (matched) {
243
+ state.setSegment("era", matched.era as unknown as number);
244
+ focusManager?.focusNext();
245
+ }
246
+ break;
247
+ }
248
+ case "day":
249
+ case "hour":
250
+ case "minute":
251
+ case "second":
252
+ case "month":
253
+ case "year": {
254
+ if (!parser().isValidPartialNumber(newValue)) {
255
+ return;
256
+ }
257
+ const numberValue = parser().parse(newValue);
258
+ let segmentValue = numberValue;
259
+ if (seg.maxValue !== undefined && numberValue > seg.maxValue) {
260
+ segmentValue = parser().parse(key);
261
+ }
262
+ if (isNaN(numberValue)) {
263
+ return;
264
+ }
265
+ state.setSegment(seg.type, segmentValue);
266
+ if (
267
+ seg.maxValue !== undefined &&
268
+ (Number(numberValue + "0") > seg.maxValue || newValue.length >= String(seg.maxValue).length)
269
+ ) {
270
+ enteredKeys = "";
271
+ focusManager?.focusNext();
272
+ } else {
273
+ enteredKeys = newValue;
274
+ }
275
+ break;
276
+ }
258
277
  }
259
278
  };
260
279
 
261
- const handleCompositionStart = () => {
262
- if (!isEditable()) return;
263
- setIsComposing(true);
264
- setEnteredKeys("");
265
- };
266
-
267
- const handleCompositionEnd = (e: CompositionEvent) => {
268
- if (!isEditable()) return;
269
- setIsComposing(false);
270
-
271
- const seg = segment();
272
- if (seg.type === "literal") return;
273
-
274
- const digits = extractNormalizedDigits(e.data ?? "");
275
- if (digits.length === 0) return;
276
-
277
- for (const digit of digits) {
278
- handleNumericInput(digit, seg.type, seg);
280
+ const onFocus = () => {
281
+ enteredKeys = "";
282
+ const el = ref();
283
+ if (el) {
284
+ scrollIntoViewport(el, { containingElement: getScrollParent(el) });
285
+ // Collapse selection to start or Chrome won't fire input events.
286
+ const selection = window.getSelection();
287
+ selection?.collapse(el);
279
288
  }
280
289
  };
281
290
 
282
- // Handle focus
283
- const handleFocus = () => {
284
- setIsFocused(true);
285
- setEnteredKeys("");
286
-
287
- if (!hadPointerDown) {
288
- setIsFocusVisible(true);
291
+ // Enforce that the selection is collapsed when inside a date segment. Otherwise, when tapping on a
292
+ // segment in Android Chrome and then entering text, composition events break the DOM structure.
293
+ createEffect(() => {
294
+ if (typeof document === "undefined") {
295
+ return;
289
296
  }
290
- hadPointerDown = false;
297
+ const handler = () => {
298
+ const selection = window.getSelection();
299
+ if (selection?.anchorNode && nodeContains(ref(), selection.anchorNode)) {
300
+ selection.collapse(ref());
301
+ }
302
+ };
303
+ document.addEventListener("selectionchange", handler);
304
+ onCleanup(() => document.removeEventListener("selectionchange", handler));
305
+ });
291
306
 
292
- const el = ref?.();
293
- if (el) {
294
- scrollIntoViewport(el, { containingElement: getScrollParent(el) });
307
+ let compositionValue = "";
308
+ createEffect(() => {
309
+ const el = ref();
310
+ if (!el) {
311
+ return;
295
312
  }
313
+ const onBeforeInput = (e: InputEvent) => {
314
+ if (!ref()) {
315
+ return;
316
+ }
317
+ e.preventDefault();
318
+ switch (e.inputType) {
319
+ case "deleteContentBackward":
320
+ case "deleteContentForward":
321
+ if (parser().isValidPartialNumber(segment().text) && !state.isReadOnly()) {
322
+ backspace();
323
+ }
324
+ break;
325
+ case "insertCompositionText":
326
+ // insertCompositionText cannot be canceled. Record current state to restore in `input`.
327
+ compositionValue = el.textContent ?? "";
328
+ // Safari gets stuck in a composition state unless we also assign to the value here.
329
+ // eslint-disable-next-line no-self-assign
330
+ el.textContent = el.textContent;
331
+ break;
332
+ default:
333
+ if (e.data != null) {
334
+ onInput(e.data);
335
+ }
336
+ break;
337
+ }
338
+ };
339
+ const onInputEvent = (e: InputEvent) => {
340
+ const { inputType, data } = e;
341
+ switch (inputType) {
342
+ case "insertCompositionText":
343
+ if (ref()) {
344
+ el.textContent = compositionValue;
345
+ }
346
+ if (data != null && (startsWith(am(), data) || startsWith(pm(), data))) {
347
+ onInput(data);
348
+ }
349
+ break;
350
+ }
351
+ };
352
+ el.addEventListener("beforeinput", onBeforeInput as EventListener);
353
+ el.addEventListener("input", onInputEvent as EventListener);
354
+ onCleanup(() => {
355
+ el.removeEventListener("beforeinput", onBeforeInput as EventListener);
356
+ el.removeEventListener("input", onInputEvent as EventListener);
357
+ });
358
+ });
296
359
 
297
- // Select all text in the segment
298
- if (el && typeof window !== "undefined") {
299
- const selection = window.getSelection();
300
- if (selection) {
301
- const range = new Range();
302
- range.selectNodeContents(el);
303
- selection.removeAllRanges();
304
- selection.addRange(range);
360
+ // If the focused segment is removed, focus the previous one, or the next one if there was no previous one.
361
+ let focusedElement: HTMLElement | null = null;
362
+ createEffect(() => {
363
+ focusedElement = ref();
364
+ });
365
+ onCleanup(() => {
366
+ if (typeof document !== "undefined" && document.activeElement === focusedElement) {
367
+ const prev = focusManager?.focusPrevious();
368
+ if (!prev) {
369
+ focusManager?.focusNext();
305
370
  }
306
371
  }
307
- };
308
-
309
- const handleBlur = () => {
310
- setIsFocused(false);
311
- setIsFocusVisible(false);
312
- setEnteredKeys("");
313
- clearLongPress();
314
- state.confirmPlaceholder();
315
- };
316
-
317
- const handleMouseEnter = () => {
318
- setIsHovered(true);
319
- };
320
-
321
- const handleMouseLeave = () => {
322
- setIsHovered(false);
323
- };
372
+ });
324
373
 
325
- // Segment props
326
- const segmentProps = createMemo(() => {
374
+ const segmentProps = createMemo<Record<string, unknown>>(() => {
327
375
  const seg = segment();
328
- const type = seg.type;
329
376
  const p = getProps();
330
377
 
331
- // Literal segments don't need interaction props
332
- if (type === "literal") {
333
- return {
334
- "aria-hidden": true,
335
- };
378
+ // spinbuttons cannot be focused with VoiceOver on iOS.
379
+ const touchPropOverrides =
380
+ isIOS() || seg.type === "timeZoneName"
381
+ ? {
382
+ role: "textbox",
383
+ "aria-valuemax": null,
384
+ "aria-valuemin": null,
385
+ "aria-valuetext": null,
386
+ "aria-valuenow": null,
387
+ }
388
+ : {};
389
+
390
+ // Only apply aria-describedby to the first segment, unless the field is invalid.
391
+ let ariaDescribedBy = hd?.ariaDescribedBy?.();
392
+ const firstEditable = state.segments().find((s) => s.isEditable);
393
+ if (firstEditable && firstEditable.type !== seg.type && !state.isInvalid()) {
394
+ ariaDescribedBy = undefined;
395
+ }
396
+ // Allow an explicitly passed describedby (e.g. from a datepicker) to compose.
397
+ ariaDescribedBy = [p["aria-describedby"], ariaDescribedBy].filter(Boolean).join(" ") || undefined;
398
+
399
+ const isEditable = !state.isDisabled() && !state.isReadOnly() && seg.isEditable;
400
+ // Prepend the label passed from the field to each segment name.
401
+ const name = seg.type === "literal" ? "" : displayNames().of(seg.type);
402
+ const ariaLabel = hd?.ariaLabel;
403
+ const ariaLabelledBy = hd?.ariaLabelledBy;
404
+ // Upstream generates a separate id inside useLabels and lets react-aria's
405
+ // mergeProps collapse it with the segment's own id via mergeIds' SSR ref
406
+ // registry. Solid has no such registry, so we thread the segment id straight
407
+ // into createLabels: the self-reference token then IS the element id, which
408
+ // is the exact observable result mergeIds produces ("month, <field label>").
409
+ const labelProps = createLabels({
410
+ id: segmentId,
411
+ "aria-label": `${name}${ariaLabel ? `, ${ariaLabel}` : ""}${ariaLabelledBy ? ", " : ""}`,
412
+ "aria-labelledby": ariaLabelledBy,
413
+ });
414
+
415
+ // Literal segments should not be visible to screen readers.
416
+ if (seg.type === "literal") {
417
+ return { "aria-hidden": true };
336
418
  }
337
419
 
338
- return {
339
- role: "spinbutton",
340
- tabIndex: isEditable() ? 0 : -1,
341
- "aria-label": getSegmentLabel(type, locale().locale),
342
- "aria-valuenow": seg.value,
343
- "aria-valuemin": seg.minValue,
344
- "aria-valuemax": seg.maxValue,
345
- "aria-valuetext": seg.isPlaceholder ? "" : seg.text,
346
- "aria-readonly": state.isReadOnly() || undefined,
347
- "aria-disabled": state.isDisabled() || undefined,
348
- "aria-invalid": state.isInvalid() || undefined,
349
- "aria-controls": p["aria-controls"] || undefined,
350
- "aria-describedby": p["aria-describedby"] || undefined,
351
- contentEditable: isEditable(),
352
- suppressContentEditableWarning: true,
353
- inputMode: "numeric" as const,
354
- autoCorrect: "off",
355
- enterKeyHint: "next" as const,
356
- spellCheck: false,
357
- "data-placeholder": seg.isPlaceholder ? "true" : undefined,
358
- "data-readonly": state.isReadOnly() || undefined,
359
- "data-disabled": state.isDisabled() || undefined,
360
- "data-invalid": state.isInvalid() || undefined,
361
- "data-type": seg.type,
362
- "data-hovered": isHovered() || undefined,
363
- "data-focused": isFocused() || undefined,
364
- "data-focus-visible": isFocusVisible() || undefined,
365
- onKeyDown: handleKeyDown,
366
- onKeyUp: handleKeyUp,
367
- onFocus: handleFocus,
368
- onBlur: handleBlur,
369
- onBeforeInput: handleBeforeInput,
370
- onCompositionStart: handleCompositionStart,
371
- onCompositionEnd: handleCompositionEnd,
372
- onMouseEnter: handleMouseEnter,
373
- onMouseLeave: handleMouseLeave,
374
- onPointerDown: (e: PointerEvent) => {
375
- // Prevent cursor positioning in the middle of the segment
376
- e.preventDefault();
377
- hadPointerDown = true;
378
- setIsFocusVisible(false);
420
+ // Kebab-case CSS property names: this style object is merged via mergeProps
421
+ // and applied by Solid's runtime `style()` spread helper, which calls
422
+ // `el.style.setProperty(key, value)` with the raw key. setProperty ignores
423
+ // camelCase names (`unicodeBidi`, `caretColor`) but honors real CSS property
424
+ // names, so upstream's React CSSProperties must be written kebab here to
425
+ // actually take effect (React auto-kebabs camelCase; a Solid spread does
426
+ // not). `direction` matched already precisely because it is single-word.
427
+ const segmentStyle: Record<string, string> = { "caret-color": "transparent" };
428
+ if (direction() === "rtl") {
429
+ segmentStyle["unicode-bidi"] = "embed";
430
+ const format = (resolvedOptions as unknown as Record<string, unknown>)[seg.type];
431
+ if (format === "numeric" || format === "2-digit") {
432
+ segmentStyle.direction = "ltr";
433
+ }
434
+ }
435
+
436
+ return mergeProps(spinButton.spinButtonProps as Record<string, unknown>, labelProps as Record<string, unknown>, {
437
+ id: segmentId,
438
+ ...touchPropOverrides,
439
+ "aria-invalid": state.isInvalid() ? "true" : undefined,
440
+ "aria-describedby": ariaDescribedBy,
441
+ "aria-readonly": state.isReadOnly() || !seg.isEditable ? "true" : undefined,
442
+ "aria-controls": (p["aria-controls"] as string | undefined) || undefined,
443
+ "data-placeholder": seg.isPlaceholder || undefined,
444
+ contentEditable: isEditable,
445
+ suppressContentEditableWarning: isEditable,
446
+ spellCheck: isEditable ? "false" : undefined,
447
+ autoCorrect: isEditable ? "off" : undefined,
448
+ enterKeyHint: isEditable ? "next" : undefined,
449
+ inputMode:
450
+ state.isDisabled() || seg.type === "dayPeriod" || seg.type === "era" || !isEditable
451
+ ? undefined
452
+ : "numeric",
453
+ tabIndex: state.isDisabled() ? undefined : 0,
454
+ onKeyDown,
455
+ onFocus,
456
+ style: segmentStyle,
457
+ // Prevent pointer events from reaching the group's press handler, and allow native focus.
458
+ onPointerDown(e: PointerEvent) {
459
+ e.stopPropagation();
379
460
  },
380
- onPointerUp: () => {
381
- clearLongPress();
461
+ onMouseDown(e: MouseEvent) {
462
+ e.stopPropagation();
382
463
  },
383
- };
384
- });
385
-
386
- // Text to display
387
- const text = createMemo(() => {
388
- const seg = segment();
389
- return seg.isPlaceholder ? seg.placeholder : seg.text;
464
+ });
390
465
  });
391
466
 
392
467
  return {
393
468
  get segmentProps() {
394
469
  return segmentProps();
395
470
  },
396
- get isFocused() {
397
- return isFocused();
398
- },
399
- get isEditable() {
400
- return isEditable();
401
- },
402
- get isPlaceholder() {
403
- return segment().isPlaceholder;
404
- },
405
- get text() {
406
- return text();
407
- },
408
- get isHovered() {
409
- return isHovered();
410
- },
411
- get isFocusVisible() {
412
- return isFocusVisible();
413
- },
414
471
  };
415
472
  }
416
-
417
- const SEGMENT_LABELS: Record<string, Record<Exclude<DateSegmentType, "literal">, string>> = {
418
- en: {
419
- year: "Year",
420
- month: "Month",
421
- day: "Day",
422
- hour: "Hour",
423
- minute: "Minute",
424
- second: "Second",
425
- dayPeriod: "AM/PM",
426
- era: "Era",
427
- timeZoneName: "Time zone",
428
- },
429
- es: {
430
- year: "Año",
431
- month: "Mes",
432
- day: "Día",
433
- hour: "Hora",
434
- minute: "Minuto",
435
- second: "Segundo",
436
- dayPeriod: "AM/PM",
437
- era: "Era",
438
- timeZoneName: "Zona horaria",
439
- },
440
- };
441
-
442
- function getSegmentLabel(type: DateSegmentType, locale: string): string {
443
- if (type === "literal") return "";
444
-
445
- const language = locale.toLowerCase().split("-")[0] ?? "en";
446
- const labels = SEGMENT_LABELS[language] ?? SEGMENT_LABELS.en;
447
- return labels[type];
448
- }
449
-
450
- function normalizeDigit(input: string): string | null {
451
- if (/^[0-9]$/.test(input)) {
452
- return input;
453
- }
454
-
455
- const codePoint = input.codePointAt(0);
456
- if (codePoint == null) return null;
457
-
458
- // Full-width digits 0-9
459
- if (codePoint >= 0xff10 && codePoint <= 0xff19) {
460
- return String(codePoint - 0xff10);
461
- }
462
-
463
- return null;
464
- }
465
-
466
- function extractNormalizedDigits(value: string): string[] {
467
- const digits: string[] = [];
468
- for (const char of value) {
469
- const normalized = normalizeDigit(char);
470
- if (normalized) {
471
- digits.push(normalized);
472
- }
473
- }
474
- return digits;
475
- }