@octanejs/aria 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. package/package.json +6 -3
  2. package/src/breadcrumbs/useBreadcrumbItem.ts +95 -0
  3. package/src/breadcrumbs/useBreadcrumbs.ts +51 -0
  4. package/src/button/useButton.ts +273 -0
  5. package/src/button/useToggleButton.ts +131 -0
  6. package/src/button/useToggleButtonGroup.ts +131 -0
  7. package/src/checkbox/useCheckbox.ts +114 -0
  8. package/src/checkbox/useCheckboxGroup.ts +107 -0
  9. package/src/checkbox/useCheckboxGroupItem.ts +132 -0
  10. package/src/checkbox/utils.ts +15 -0
  11. package/src/combobox/useComboBox.ts +602 -0
  12. package/src/dialog/useDialog.ts +147 -0
  13. package/src/disclosure/useDisclosure.ts +180 -0
  14. package/src/focus/FocusRing.ts +69 -0
  15. package/src/focus/FocusScope.ts +1205 -0
  16. package/src/focus/useFocusRing.ts +125 -0
  17. package/src/focus/useHasTabbableChild.ts +82 -0
  18. package/src/focus/virtualFocus.ts +38 -0
  19. package/src/form/useFormValidation.ts +205 -0
  20. package/src/grid/useGridSelectionAnnouncement.ts +177 -0
  21. package/src/grid/useGridSelectionCheckbox.ts +86 -0
  22. package/src/grid/useHighlightSelectionDescription.ts +81 -0
  23. package/src/gridlist/useGridList.ts +236 -0
  24. package/src/gridlist/useGridListItem.ts +512 -0
  25. package/src/gridlist/useGridListSection.ts +78 -0
  26. package/src/gridlist/useGridListSelectionCheckbox.ts +47 -0
  27. package/src/gridlist/utils.ts +36 -0
  28. package/src/i18n/I18nProvider.ts +97 -0
  29. package/src/i18n/server.ts +115 -0
  30. package/src/i18n/useCollator.ts +42 -0
  31. package/src/i18n/useDateFormatter.ts +64 -0
  32. package/src/i18n/useDefaultLocale.ts +93 -0
  33. package/src/i18n/useFilter.ts +107 -0
  34. package/src/i18n/useListFormatter.ts +33 -0
  35. package/src/i18n/useLocalizedStringFormatter.ts +90 -0
  36. package/src/i18n/useNumberFormatter.ts +33 -0
  37. package/src/i18n/utils.ts +67 -0
  38. package/src/index.ts +268 -0
  39. package/src/intl/breadcrumbs/ar-AE.json +3 -0
  40. package/src/intl/breadcrumbs/bg-BG.json +3 -0
  41. package/src/intl/breadcrumbs/cs-CZ.json +3 -0
  42. package/src/intl/breadcrumbs/da-DK.json +3 -0
  43. package/src/intl/breadcrumbs/de-DE.json +3 -0
  44. package/src/intl/breadcrumbs/el-GR.json +3 -0
  45. package/src/intl/breadcrumbs/en-US.json +3 -0
  46. package/src/intl/breadcrumbs/es-ES.json +3 -0
  47. package/src/intl/breadcrumbs/et-EE.json +3 -0
  48. package/src/intl/breadcrumbs/fi-FI.json +3 -0
  49. package/src/intl/breadcrumbs/fr-FR.json +3 -0
  50. package/src/intl/breadcrumbs/he-IL.json +3 -0
  51. package/src/intl/breadcrumbs/hr-HR.json +3 -0
  52. package/src/intl/breadcrumbs/hu-HU.json +3 -0
  53. package/src/intl/breadcrumbs/index.ts +75 -0
  54. package/src/intl/breadcrumbs/it-IT.json +3 -0
  55. package/src/intl/breadcrumbs/ja-JP.json +3 -0
  56. package/src/intl/breadcrumbs/ko-KR.json +3 -0
  57. package/src/intl/breadcrumbs/lt-LT.json +3 -0
  58. package/src/intl/breadcrumbs/lv-LV.json +3 -0
  59. package/src/intl/breadcrumbs/nb-NO.json +3 -0
  60. package/src/intl/breadcrumbs/nl-NL.json +3 -0
  61. package/src/intl/breadcrumbs/pl-PL.json +3 -0
  62. package/src/intl/breadcrumbs/pt-BR.json +3 -0
  63. package/src/intl/breadcrumbs/pt-PT.json +3 -0
  64. package/src/intl/breadcrumbs/ro-RO.json +3 -0
  65. package/src/intl/breadcrumbs/ru-RU.json +3 -0
  66. package/src/intl/breadcrumbs/sk-SK.json +3 -0
  67. package/src/intl/breadcrumbs/sl-SI.json +3 -0
  68. package/src/intl/breadcrumbs/sr-SP.json +3 -0
  69. package/src/intl/breadcrumbs/sv-SE.json +3 -0
  70. package/src/intl/breadcrumbs/tr-TR.json +3 -0
  71. package/src/intl/breadcrumbs/uk-UA.json +3 -0
  72. package/src/intl/breadcrumbs/zh-CN.json +3 -0
  73. package/src/intl/breadcrumbs/zh-TW.json +3 -0
  74. package/src/intl/combobox/ar-AE.json +7 -0
  75. package/src/intl/combobox/bg-BG.json +7 -0
  76. package/src/intl/combobox/cs-CZ.json +7 -0
  77. package/src/intl/combobox/da-DK.json +7 -0
  78. package/src/intl/combobox/de-DE.json +7 -0
  79. package/src/intl/combobox/el-GR.json +7 -0
  80. package/src/intl/combobox/en-US.json +7 -0
  81. package/src/intl/combobox/es-ES.json +7 -0
  82. package/src/intl/combobox/et-EE.json +7 -0
  83. package/src/intl/combobox/fi-FI.json +7 -0
  84. package/src/intl/combobox/fr-FR.json +7 -0
  85. package/src/intl/combobox/he-IL.json +7 -0
  86. package/src/intl/combobox/hr-HR.json +7 -0
  87. package/src/intl/combobox/hu-HU.json +7 -0
  88. package/src/intl/combobox/index.ts +75 -0
  89. package/src/intl/combobox/it-IT.json +7 -0
  90. package/src/intl/combobox/ja-JP.json +7 -0
  91. package/src/intl/combobox/ko-KR.json +7 -0
  92. package/src/intl/combobox/lt-LT.json +7 -0
  93. package/src/intl/combobox/lv-LV.json +7 -0
  94. package/src/intl/combobox/nb-NO.json +7 -0
  95. package/src/intl/combobox/nl-NL.json +7 -0
  96. package/src/intl/combobox/pl-PL.json +7 -0
  97. package/src/intl/combobox/pt-BR.json +7 -0
  98. package/src/intl/combobox/pt-PT.json +7 -0
  99. package/src/intl/combobox/ro-RO.json +7 -0
  100. package/src/intl/combobox/ru-RU.json +7 -0
  101. package/src/intl/combobox/sk-SK.json +7 -0
  102. package/src/intl/combobox/sl-SI.json +7 -0
  103. package/src/intl/combobox/sr-SP.json +7 -0
  104. package/src/intl/combobox/sv-SE.json +7 -0
  105. package/src/intl/combobox/tr-TR.json +7 -0
  106. package/src/intl/combobox/uk-UA.json +7 -0
  107. package/src/intl/combobox/zh-CN.json +7 -0
  108. package/src/intl/combobox/zh-TW.json +7 -0
  109. package/src/intl/grid/ar-AE.json +8 -0
  110. package/src/intl/grid/bg-BG.json +8 -0
  111. package/src/intl/grid/cs-CZ.json +8 -0
  112. package/src/intl/grid/da-DK.json +8 -0
  113. package/src/intl/grid/de-DE.json +8 -0
  114. package/src/intl/grid/el-GR.json +8 -0
  115. package/src/intl/grid/en-US.json +8 -0
  116. package/src/intl/grid/es-ES.json +8 -0
  117. package/src/intl/grid/et-EE.json +8 -0
  118. package/src/intl/grid/fi-FI.json +8 -0
  119. package/src/intl/grid/fr-FR.json +8 -0
  120. package/src/intl/grid/he-IL.json +8 -0
  121. package/src/intl/grid/hr-HR.json +8 -0
  122. package/src/intl/grid/hu-HU.json +8 -0
  123. package/src/intl/grid/index.ts +75 -0
  124. package/src/intl/grid/it-IT.json +8 -0
  125. package/src/intl/grid/ja-JP.json +8 -0
  126. package/src/intl/grid/ko-KR.json +8 -0
  127. package/src/intl/grid/lt-LT.json +8 -0
  128. package/src/intl/grid/lv-LV.json +8 -0
  129. package/src/intl/grid/nb-NO.json +8 -0
  130. package/src/intl/grid/nl-NL.json +8 -0
  131. package/src/intl/grid/pl-PL.json +8 -0
  132. package/src/intl/grid/pt-BR.json +8 -0
  133. package/src/intl/grid/pt-PT.json +8 -0
  134. package/src/intl/grid/ro-RO.json +8 -0
  135. package/src/intl/grid/ru-RU.json +8 -0
  136. package/src/intl/grid/sk-SK.json +8 -0
  137. package/src/intl/grid/sl-SI.json +8 -0
  138. package/src/intl/grid/sr-SP.json +8 -0
  139. package/src/intl/grid/sv-SE.json +8 -0
  140. package/src/intl/grid/tr-TR.json +8 -0
  141. package/src/intl/grid/uk-UA.json +8 -0
  142. package/src/intl/grid/zh-CN.json +8 -0
  143. package/src/intl/grid/zh-TW.json +8 -0
  144. package/src/intl/gridlist/ar-AE.json +4 -0
  145. package/src/intl/gridlist/bg-BG.json +4 -0
  146. package/src/intl/gridlist/cs-CZ.json +4 -0
  147. package/src/intl/gridlist/da-DK.json +4 -0
  148. package/src/intl/gridlist/de-DE.json +4 -0
  149. package/src/intl/gridlist/el-GR.json +4 -0
  150. package/src/intl/gridlist/en-US.json +4 -0
  151. package/src/intl/gridlist/es-ES.json +4 -0
  152. package/src/intl/gridlist/et-EE.json +4 -0
  153. package/src/intl/gridlist/fi-FI.json +4 -0
  154. package/src/intl/gridlist/fr-FR.json +4 -0
  155. package/src/intl/gridlist/he-IL.json +4 -0
  156. package/src/intl/gridlist/hr-HR.json +4 -0
  157. package/src/intl/gridlist/hu-HU.json +4 -0
  158. package/src/intl/gridlist/index.ts +75 -0
  159. package/src/intl/gridlist/it-IT.json +4 -0
  160. package/src/intl/gridlist/ja-JP.json +4 -0
  161. package/src/intl/gridlist/ko-KR.json +4 -0
  162. package/src/intl/gridlist/lt-LT.json +4 -0
  163. package/src/intl/gridlist/lv-LV.json +4 -0
  164. package/src/intl/gridlist/nb-NO.json +4 -0
  165. package/src/intl/gridlist/nl-NL.json +4 -0
  166. package/src/intl/gridlist/pl-PL.json +4 -0
  167. package/src/intl/gridlist/pt-BR.json +4 -0
  168. package/src/intl/gridlist/pt-PT.json +4 -0
  169. package/src/intl/gridlist/ro-RO.json +4 -0
  170. package/src/intl/gridlist/ru-RU.json +4 -0
  171. package/src/intl/gridlist/sk-SK.json +4 -0
  172. package/src/intl/gridlist/sl-SI.json +4 -0
  173. package/src/intl/gridlist/sr-SP.json +4 -0
  174. package/src/intl/gridlist/sv-SE.json +4 -0
  175. package/src/intl/gridlist/tr-TR.json +4 -0
  176. package/src/intl/gridlist/uk-UA.json +4 -0
  177. package/src/intl/gridlist/zh-CN.json +4 -0
  178. package/src/intl/gridlist/zh-TW.json +4 -0
  179. package/src/intl/menu/ar-AE.json +3 -0
  180. package/src/intl/menu/bg-BG.json +3 -0
  181. package/src/intl/menu/cs-CZ.json +3 -0
  182. package/src/intl/menu/da-DK.json +3 -0
  183. package/src/intl/menu/de-DE.json +3 -0
  184. package/src/intl/menu/el-GR.json +3 -0
  185. package/src/intl/menu/en-US.json +3 -0
  186. package/src/intl/menu/es-ES.json +3 -0
  187. package/src/intl/menu/et-EE.json +3 -0
  188. package/src/intl/menu/fi-FI.json +3 -0
  189. package/src/intl/menu/fr-FR.json +3 -0
  190. package/src/intl/menu/he-IL.json +3 -0
  191. package/src/intl/menu/hr-HR.json +3 -0
  192. package/src/intl/menu/hu-HU.json +3 -0
  193. package/src/intl/menu/index.ts +75 -0
  194. package/src/intl/menu/it-IT.json +3 -0
  195. package/src/intl/menu/ja-JP.json +3 -0
  196. package/src/intl/menu/ko-KR.json +3 -0
  197. package/src/intl/menu/lt-LT.json +3 -0
  198. package/src/intl/menu/lv-LV.json +3 -0
  199. package/src/intl/menu/nb-NO.json +3 -0
  200. package/src/intl/menu/nl-NL.json +3 -0
  201. package/src/intl/menu/pl-PL.json +3 -0
  202. package/src/intl/menu/pt-BR.json +3 -0
  203. package/src/intl/menu/pt-PT.json +3 -0
  204. package/src/intl/menu/ro-RO.json +3 -0
  205. package/src/intl/menu/ru-RU.json +3 -0
  206. package/src/intl/menu/sk-SK.json +3 -0
  207. package/src/intl/menu/sl-SI.json +3 -0
  208. package/src/intl/menu/sr-SP.json +3 -0
  209. package/src/intl/menu/sv-SE.json +3 -0
  210. package/src/intl/menu/tr-TR.json +3 -0
  211. package/src/intl/menu/uk-UA.json +3 -0
  212. package/src/intl/menu/zh-CN.json +3 -0
  213. package/src/intl/menu/zh-TW.json +3 -0
  214. package/src/intl/numberfield/ar-AE.json +5 -0
  215. package/src/intl/numberfield/bg-BG.json +5 -0
  216. package/src/intl/numberfield/cs-CZ.json +5 -0
  217. package/src/intl/numberfield/da-DK.json +5 -0
  218. package/src/intl/numberfield/de-DE.json +5 -0
  219. package/src/intl/numberfield/el-GR.json +5 -0
  220. package/src/intl/numberfield/en-US.json +5 -0
  221. package/src/intl/numberfield/es-ES.json +5 -0
  222. package/src/intl/numberfield/et-EE.json +5 -0
  223. package/src/intl/numberfield/fi-FI.json +5 -0
  224. package/src/intl/numberfield/fr-FR.json +5 -0
  225. package/src/intl/numberfield/he-IL.json +5 -0
  226. package/src/intl/numberfield/hr-HR.json +5 -0
  227. package/src/intl/numberfield/hu-HU.json +5 -0
  228. package/src/intl/numberfield/index.ts +75 -0
  229. package/src/intl/numberfield/it-IT.json +5 -0
  230. package/src/intl/numberfield/ja-JP.json +5 -0
  231. package/src/intl/numberfield/ko-KR.json +5 -0
  232. package/src/intl/numberfield/lt-LT.json +5 -0
  233. package/src/intl/numberfield/lv-LV.json +5 -0
  234. package/src/intl/numberfield/nb-NO.json +5 -0
  235. package/src/intl/numberfield/nl-NL.json +5 -0
  236. package/src/intl/numberfield/pl-PL.json +5 -0
  237. package/src/intl/numberfield/pt-BR.json +5 -0
  238. package/src/intl/numberfield/pt-PT.json +5 -0
  239. package/src/intl/numberfield/ro-RO.json +5 -0
  240. package/src/intl/numberfield/ru-RU.json +5 -0
  241. package/src/intl/numberfield/sk-SK.json +5 -0
  242. package/src/intl/numberfield/sl-SI.json +5 -0
  243. package/src/intl/numberfield/sr-SP.json +5 -0
  244. package/src/intl/numberfield/sv-SE.json +5 -0
  245. package/src/intl/numberfield/tr-TR.json +5 -0
  246. package/src/intl/numberfield/uk-UA.json +5 -0
  247. package/src/intl/numberfield/zh-CN.json +5 -0
  248. package/src/intl/numberfield/zh-TW.json +5 -0
  249. package/src/intl/overlays/ar-AE.json +3 -0
  250. package/src/intl/overlays/bg-BG.json +3 -0
  251. package/src/intl/overlays/cs-CZ.json +3 -0
  252. package/src/intl/overlays/da-DK.json +3 -0
  253. package/src/intl/overlays/de-DE.json +3 -0
  254. package/src/intl/overlays/el-GR.json +3 -0
  255. package/src/intl/overlays/en-US.json +3 -0
  256. package/src/intl/overlays/es-ES.json +3 -0
  257. package/src/intl/overlays/et-EE.json +3 -0
  258. package/src/intl/overlays/fi-FI.json +3 -0
  259. package/src/intl/overlays/fr-FR.json +3 -0
  260. package/src/intl/overlays/he-IL.json +3 -0
  261. package/src/intl/overlays/hr-HR.json +3 -0
  262. package/src/intl/overlays/hu-HU.json +3 -0
  263. package/src/intl/overlays/index.ts +75 -0
  264. package/src/intl/overlays/it-IT.json +3 -0
  265. package/src/intl/overlays/ja-JP.json +3 -0
  266. package/src/intl/overlays/ko-KR.json +3 -0
  267. package/src/intl/overlays/lt-LT.json +3 -0
  268. package/src/intl/overlays/lv-LV.json +3 -0
  269. package/src/intl/overlays/nb-NO.json +3 -0
  270. package/src/intl/overlays/nl-NL.json +3 -0
  271. package/src/intl/overlays/pl-PL.json +3 -0
  272. package/src/intl/overlays/pt-BR.json +3 -0
  273. package/src/intl/overlays/pt-PT.json +3 -0
  274. package/src/intl/overlays/ro-RO.json +3 -0
  275. package/src/intl/overlays/ru-RU.json +3 -0
  276. package/src/intl/overlays/sk-SK.json +3 -0
  277. package/src/intl/overlays/sl-SI.json +3 -0
  278. package/src/intl/overlays/sr-SP.json +3 -0
  279. package/src/intl/overlays/sv-SE.json +3 -0
  280. package/src/intl/overlays/tr-TR.json +3 -0
  281. package/src/intl/overlays/uk-UA.json +3 -0
  282. package/src/intl/overlays/zh-CN.json +3 -0
  283. package/src/intl/overlays/zh-TW.json +3 -0
  284. package/src/intl/searchfield/ar-AE.json +3 -0
  285. package/src/intl/searchfield/bg-BG.json +3 -0
  286. package/src/intl/searchfield/cs-CZ.json +3 -0
  287. package/src/intl/searchfield/da-DK.json +3 -0
  288. package/src/intl/searchfield/de-DE.json +3 -0
  289. package/src/intl/searchfield/el-GR.json +3 -0
  290. package/src/intl/searchfield/en-US.json +3 -0
  291. package/src/intl/searchfield/es-ES.json +3 -0
  292. package/src/intl/searchfield/et-EE.json +3 -0
  293. package/src/intl/searchfield/fi-FI.json +3 -0
  294. package/src/intl/searchfield/fr-FR.json +3 -0
  295. package/src/intl/searchfield/he-IL.json +3 -0
  296. package/src/intl/searchfield/hr-HR.json +3 -0
  297. package/src/intl/searchfield/hu-HU.json +3 -0
  298. package/src/intl/searchfield/index.ts +75 -0
  299. package/src/intl/searchfield/it-IT.json +3 -0
  300. package/src/intl/searchfield/ja-JP.json +3 -0
  301. package/src/intl/searchfield/ko-KR.json +3 -0
  302. package/src/intl/searchfield/lt-LT.json +3 -0
  303. package/src/intl/searchfield/lv-LV.json +3 -0
  304. package/src/intl/searchfield/nb-NO.json +3 -0
  305. package/src/intl/searchfield/nl-NL.json +3 -0
  306. package/src/intl/searchfield/pl-PL.json +3 -0
  307. package/src/intl/searchfield/pt-BR.json +3 -0
  308. package/src/intl/searchfield/pt-PT.json +3 -0
  309. package/src/intl/searchfield/ro-RO.json +3 -0
  310. package/src/intl/searchfield/ru-RU.json +3 -0
  311. package/src/intl/searchfield/sk-SK.json +3 -0
  312. package/src/intl/searchfield/sl-SI.json +3 -0
  313. package/src/intl/searchfield/sr-SP.json +3 -0
  314. package/src/intl/searchfield/sv-SE.json +3 -0
  315. package/src/intl/searchfield/tr-TR.json +3 -0
  316. package/src/intl/searchfield/uk-UA.json +3 -0
  317. package/src/intl/searchfield/zh-CN.json +3 -0
  318. package/src/intl/searchfield/zh-TW.json +3 -0
  319. package/src/intl/spinbutton/ar-AE.json +3 -0
  320. package/src/intl/spinbutton/bg-BG.json +3 -0
  321. package/src/intl/spinbutton/cs-CZ.json +3 -0
  322. package/src/intl/spinbutton/da-DK.json +3 -0
  323. package/src/intl/spinbutton/de-DE.json +3 -0
  324. package/src/intl/spinbutton/el-GR.json +3 -0
  325. package/src/intl/spinbutton/en-US.json +3 -0
  326. package/src/intl/spinbutton/es-ES.json +3 -0
  327. package/src/intl/spinbutton/et-EE.json +3 -0
  328. package/src/intl/spinbutton/fi-FI.json +3 -0
  329. package/src/intl/spinbutton/fr-FR.json +3 -0
  330. package/src/intl/spinbutton/he-IL.json +3 -0
  331. package/src/intl/spinbutton/hr-HR.json +3 -0
  332. package/src/intl/spinbutton/hu-HU.json +3 -0
  333. package/src/intl/spinbutton/index.ts +75 -0
  334. package/src/intl/spinbutton/it-IT.json +3 -0
  335. package/src/intl/spinbutton/ja-JP.json +3 -0
  336. package/src/intl/spinbutton/ko-KR.json +3 -0
  337. package/src/intl/spinbutton/lt-LT.json +3 -0
  338. package/src/intl/spinbutton/lv-LV.json +3 -0
  339. package/src/intl/spinbutton/nb-NO.json +3 -0
  340. package/src/intl/spinbutton/nl-NL.json +3 -0
  341. package/src/intl/spinbutton/pl-PL.json +3 -0
  342. package/src/intl/spinbutton/pt-BR.json +3 -0
  343. package/src/intl/spinbutton/pt-PT.json +3 -0
  344. package/src/intl/spinbutton/ro-RO.json +3 -0
  345. package/src/intl/spinbutton/ru-RU.json +3 -0
  346. package/src/intl/spinbutton/sk-SK.json +3 -0
  347. package/src/intl/spinbutton/sl-SI.json +3 -0
  348. package/src/intl/spinbutton/sr-SP.json +3 -0
  349. package/src/intl/spinbutton/sv-SE.json +3 -0
  350. package/src/intl/spinbutton/tr-TR.json +3 -0
  351. package/src/intl/spinbutton/uk-UA.json +3 -0
  352. package/src/intl/spinbutton/zh-CN.json +3 -0
  353. package/src/intl/spinbutton/zh-TW.json +3 -0
  354. package/src/intl/tag/ar-AE.json +4 -0
  355. package/src/intl/tag/bg-BG.json +4 -0
  356. package/src/intl/tag/cs-CZ.json +4 -0
  357. package/src/intl/tag/da-DK.json +4 -0
  358. package/src/intl/tag/de-DE.json +4 -0
  359. package/src/intl/tag/el-GR.json +4 -0
  360. package/src/intl/tag/en-US.json +4 -0
  361. package/src/intl/tag/es-ES.json +4 -0
  362. package/src/intl/tag/et-EE.json +4 -0
  363. package/src/intl/tag/fi-FI.json +4 -0
  364. package/src/intl/tag/fr-FR.json +4 -0
  365. package/src/intl/tag/he-IL.json +4 -0
  366. package/src/intl/tag/hr-HR.json +4 -0
  367. package/src/intl/tag/hu-HU.json +4 -0
  368. package/src/intl/tag/index.ts +75 -0
  369. package/src/intl/tag/it-IT.json +4 -0
  370. package/src/intl/tag/ja-JP.json +4 -0
  371. package/src/intl/tag/ko-KR.json +4 -0
  372. package/src/intl/tag/lt-LT.json +4 -0
  373. package/src/intl/tag/lv-LV.json +4 -0
  374. package/src/intl/tag/nb-NO.json +4 -0
  375. package/src/intl/tag/nl-NL.json +4 -0
  376. package/src/intl/tag/pl-PL.json +4 -0
  377. package/src/intl/tag/pt-BR.json +4 -0
  378. package/src/intl/tag/pt-PT.json +4 -0
  379. package/src/intl/tag/ro-RO.json +4 -0
  380. package/src/intl/tag/ru-RU.json +4 -0
  381. package/src/intl/tag/sk-SK.json +4 -0
  382. package/src/intl/tag/sl-SI.json +4 -0
  383. package/src/intl/tag/sr-SP.json +4 -0
  384. package/src/intl/tag/sv-SE.json +4 -0
  385. package/src/intl/tag/tr-TR.json +4 -0
  386. package/src/intl/tag/uk-UA.json +4 -0
  387. package/src/intl/tag/zh-CN.json +4 -0
  388. package/src/intl/tag/zh-TW.json +4 -0
  389. package/src/label/useField.ts +67 -0
  390. package/src/label/useLabel.ts +78 -0
  391. package/src/link/useLink.ts +108 -0
  392. package/src/listbox/useListBox.ts +224 -0
  393. package/src/listbox/useListBoxSection.ts +74 -0
  394. package/src/listbox/useOption.ts +212 -0
  395. package/src/listbox/utils.ts +38 -0
  396. package/src/live-announcer/LiveAnnouncer.ts +172 -0
  397. package/src/menu/useMenu.ts +139 -0
  398. package/src/menu/useMenuItem.ts +453 -0
  399. package/src/menu/useMenuSection.ts +70 -0
  400. package/src/menu/useMenuTrigger.ts +189 -0
  401. package/src/menu/useSafelyMouseToSubmenu.ts +236 -0
  402. package/src/menu/useSubmenuTrigger.ts +357 -0
  403. package/src/menu/utils.ts +16 -0
  404. package/src/meter/useMeter.ts +43 -0
  405. package/src/numberfield/useNumberField.ts +572 -0
  406. package/src/overlays/DismissButton.ts +50 -0
  407. package/src/overlays/Overlay.ts +106 -0
  408. package/src/overlays/PortalProvider.ts +37 -0
  409. package/src/overlays/ariaHideOutside.ts +299 -0
  410. package/src/overlays/calculatePosition.ts +856 -0
  411. package/src/overlays/useCloseOnScroll.ts +75 -0
  412. package/src/overlays/useModal.ts +224 -0
  413. package/src/overlays/useModalOverlay.ts +103 -0
  414. package/src/overlays/useOverlay.ts +199 -0
  415. package/src/overlays/useOverlayPosition.ts +462 -0
  416. package/src/overlays/useOverlayTrigger.ts +94 -0
  417. package/src/overlays/usePopover.ts +170 -0
  418. package/src/overlays/usePreventScroll.ts +316 -0
  419. package/src/progress/useProgressBar.ts +115 -0
  420. package/src/radio/useRadio.ts +219 -0
  421. package/src/radio/useRadioGroup.ts +184 -0
  422. package/src/radio/utils.ts +15 -0
  423. package/src/searchfield/useSearchField.ts +156 -0
  424. package/src/select/HiddenSelect.ts +261 -0
  425. package/src/select/useSelect.ts +332 -0
  426. package/src/selection/DOMLayoutDelegate.ts +51 -0
  427. package/src/selection/ListKeyboardDelegate.ts +392 -0
  428. package/src/selection/useSelectableCollection.ts +750 -0
  429. package/src/selection/useSelectableItem.ts +499 -0
  430. package/src/selection/useSelectableList.ts +132 -0
  431. package/src/selection/useTypeSelect.ts +192 -0
  432. package/src/selection/utils.ts +50 -0
  433. package/src/separator/useSeparator.ts +41 -0
  434. package/src/slider/useSlider.ts +277 -0
  435. package/src/slider/useSliderThumb.ts +375 -0
  436. package/src/slider/utils.ts +20 -0
  437. package/src/spinbutton/useSpinButton.ts +380 -0
  438. package/src/stately/checkbox/useCheckboxGroupState.ts +177 -0
  439. package/src/stately/collections/CollectionBuilder.ts +332 -0
  440. package/src/stately/collections/Item.ts +78 -0
  441. package/src/stately/collections/Section.ts +52 -0
  442. package/src/stately/collections/getChildNodes.ts +94 -0
  443. package/src/stately/collections/getItemCount.ts +29 -0
  444. package/src/stately/collections/types.ts +20 -0
  445. package/src/stately/collections/useCollection.ts +54 -0
  446. package/src/stately/combobox/useComboBoxState.ts +763 -0
  447. package/src/stately/disclosure/useDisclosureGroupState.ts +108 -0
  448. package/src/stately/disclosure/useDisclosureState.ts +84 -0
  449. package/src/stately/form/useFormValidationState.ts +331 -0
  450. package/src/stately/index.ts +111 -0
  451. package/src/stately/list/ListCollection.ts +104 -0
  452. package/src/stately/list/useListState.ts +178 -0
  453. package/src/stately/list/useSingleSelectListState.ts +101 -0
  454. package/src/stately/menu/useMenuTriggerState.ts +120 -0
  455. package/src/stately/menu/useSubmenuTriggerState.ts +116 -0
  456. package/src/stately/numberfield/useNumberFieldState.ts +430 -0
  457. package/src/stately/overlays/useOverlayTriggerState.ts +85 -0
  458. package/src/stately/radio/useRadioGroupState.ts +150 -0
  459. package/src/stately/searchfield/useSearchFieldState.ts +79 -0
  460. package/src/stately/select/useSelectState.ts +322 -0
  461. package/src/stately/selection/Selection.ts +23 -0
  462. package/src/stately/selection/SelectionManager.ts +541 -0
  463. package/src/stately/selection/types.ts +117 -0
  464. package/src/stately/selection/useMultipleSelectionState.ts +178 -0
  465. package/src/stately/slider/useSliderState.ts +458 -0
  466. package/src/stately/tabs/useTabListState.ts +149 -0
  467. package/src/stately/toggle/useToggleGroupState.ts +109 -0
  468. package/src/stately/toggle/useToggleState.ts +100 -0
  469. package/src/stately/tooltip/useTooltipTriggerState.ts +218 -0
  470. package/src/stately/tree/TreeCollection.ts +92 -0
  471. package/src/stately/tree/useTreeState.ts +121 -0
  472. package/src/stately/utils/useControlledState.ts +7 -0
  473. package/src/switch/useSwitch.ts +77 -0
  474. package/src/tabs/TabsKeyboardDelegate.ts +99 -0
  475. package/src/tabs/useTab.ts +117 -0
  476. package/src/tabs/useTabList.ts +105 -0
  477. package/src/tabs/useTabPanel.ts +75 -0
  478. package/src/tabs/utils.ts +32 -0
  479. package/src/tag/useTag.ts +162 -0
  480. package/src/tag/useTagGroup.ts +192 -0
  481. package/src/textfield/useFormattedTextField.ts +203 -0
  482. package/src/textfield/useTextField.ts +248 -0
  483. package/src/toggle/useToggle.ts +265 -0
  484. package/src/toolbar/useToolbar.ts +147 -0
  485. package/src/tooltip/useTooltip.ts +64 -0
  486. package/src/tooltip/useTooltipTrigger.ts +187 -0
  487. package/src/utils/filterDOMProps.ts +121 -0
  488. package/src/utils/getScrollParent.ts +16 -0
  489. package/src/utils/getScrollParents.ts +20 -0
  490. package/src/utils/keyboard.ts +38 -0
  491. package/src/utils/scrollIntoView.ts +178 -0
  492. package/src/utils/useDeepMemo.ts +30 -0
  493. package/src/utils/useFormReset.ts +54 -0
  494. package/src/utils/useId.ts +5 -0
  495. package/src/utils/useLabels.ts +53 -0
  496. package/src/utils/useResizeObserver.ts +70 -0
  497. package/src/utils/useSlot.ts +78 -0
  498. package/src/utils/useUpdateEffect.ts +54 -0
  499. package/src/utils/useUpdateLayoutEffect.ts +58 -0
  500. package/src/visually-hidden/VisuallyHidden.ts +100 -0
@@ -0,0 +1,248 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/textfield/useTextField.ts).
2
+ // octane adaptations:
3
+ // - onChange→onInput DOM wiring: the per-keystroke state update rides octane's native
4
+ // `input` event (identical timing to React's synthetic onChange for text inputs). The
5
+ // user's own `onInput` prop still runs first (matching React's plugin order, where
6
+ // onInput fires before onChange), chained ahead of the setter.
7
+ // - The React intrinsic-element generic machinery (JSX.IntrinsicElements lookup types)
8
+ // collapses to a plain 'input' | 'textarea' parameter with structural prop bags.
9
+ // - `FocusableProps` is the ported native-event version; `enterKeyHint` is always the
10
+ // camelCase prop (the React-version probe collapses).
11
+ // - Public-hook slot threading.
12
+ import type {
13
+ AriaLabelingProps,
14
+ AriaValidationProps,
15
+ FocusableDOMProps,
16
+ HelpTextProps,
17
+ InputBase,
18
+ LabelableProps,
19
+ TextInputBase,
20
+ Validation,
21
+ ValidationResult,
22
+ ValueBase,
23
+ RefObject,
24
+ } from '@react-types/shared';
25
+ import { useState } from 'octane';
26
+
27
+ import type { FocusableProps } from '../interactions/useFocusable';
28
+ import { S, splitSlot, subSlot } from '../internal';
29
+ import { chain } from '../utils/chain';
30
+ import { filterDOMProps } from '../utils/filterDOMProps';
31
+ import { getEventTarget } from '../utils/shadowdom/DOMFunctions';
32
+ import { mergeProps } from '../utils/mergeProps';
33
+ import { useControlledState } from '../stately/utils/useControlledState';
34
+ import { useField } from '../label/useField';
35
+ import { useFocusable } from '../interactions/useFocusable';
36
+ import { useFormReset } from '../utils/useFormReset';
37
+ import { useFormValidation } from '../form/useFormValidation';
38
+ import { useFormValidationState } from '../stately/form/useFormValidationState';
39
+
40
+ type DOMAttributes = Record<string, any>;
41
+ type TextFieldIntrinsicElements = 'input' | 'textarea';
42
+
43
+ export interface TextFieldProps
44
+ extends
45
+ InputBase,
46
+ Validation<string>,
47
+ HelpTextProps,
48
+ FocusableProps,
49
+ TextInputBase,
50
+ ValueBase<string>,
51
+ LabelableProps {}
52
+
53
+ export interface AriaTextFieldProps
54
+ extends TextFieldProps, AriaLabelingProps, FocusableDOMProps, AriaValidationProps {
55
+ // https://www.w3.org/TR/wai-aria-1.2/#textbox
56
+ /**
57
+ * Identifies the currently active element when DOM focus is on a composite widget, textbox,
58
+ * group, or application.
59
+ */
60
+ 'aria-activedescendant'?: string;
61
+ /**
62
+ * Indicates whether inputting text could trigger display of one or more predictions of the user's
63
+ * intended value for an input and specifies how predictions would be presented if they are made.
64
+ */
65
+ 'aria-autocomplete'?: 'none' | 'inline' | 'list' | 'both';
66
+ /**
67
+ * Indicates the availability and type of interactive popup element, such as menu or dialog, that
68
+ * can be triggered by an element.
69
+ */
70
+ 'aria-haspopup'?: boolean | 'false' | 'true' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';
71
+ /**
72
+ * Identifies the element (or elements) whose contents or presence are controlled by the current
73
+ * element.
74
+ */
75
+ 'aria-controls'?: string;
76
+ /**
77
+ * An enumerated attribute that defines what action label or icon to preset for the enter key on
78
+ * virtual keyboards. See
79
+ * [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/enterkeyhint).
80
+ */
81
+ enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send';
82
+ // octane adaptation: the text-input DOM props are structural (upstream's
83
+ // TextInputDOMProps drags React handler types).
84
+ type?: string;
85
+ pattern?: string;
86
+ autoComplete?: string;
87
+ autoCapitalize?: 'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters';
88
+ maxLength?: number;
89
+ minLength?: number;
90
+ name?: string;
91
+ form?: string;
92
+ placeholder?: string;
93
+ inputMode?: string;
94
+ autoCorrect?: string;
95
+ spellCheck?: string | boolean;
96
+ onCopy?: (e: ClipboardEvent) => void;
97
+ onCut?: (e: ClipboardEvent) => void;
98
+ onPaste?: (e: ClipboardEvent) => void;
99
+ onCompositionEnd?: (e: CompositionEvent) => void;
100
+ onCompositionStart?: (e: CompositionEvent) => void;
101
+ onCompositionUpdate?: (e: CompositionEvent) => void;
102
+ onSelect?: (e: Event) => void;
103
+ onBeforeInput?: (e: InputEvent) => void;
104
+ onInput?: (e: Event) => void;
105
+ }
106
+
107
+ export interface AriaTextFieldOptions<
108
+ T extends TextFieldIntrinsicElements = 'input',
109
+ > extends AriaTextFieldProps {
110
+ /**
111
+ * The HTML element used to render the input, e.g. 'input', or 'textarea'. It determines whether
112
+ * certain HTML attributes will be included in `inputProps`. For example,
113
+ * [`type`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-type).
114
+ *
115
+ * @default 'input'
116
+ */
117
+ inputElementType?: T;
118
+ }
119
+
120
+ export interface TextFieldAria extends ValidationResult {
121
+ /** Props for the input element. */
122
+ inputProps: DOMAttributes;
123
+ /** Props for the text field's visible label element, if any. */
124
+ labelProps: DOMAttributes;
125
+ /** Props for the text field's description element, if any. */
126
+ descriptionProps: DOMAttributes;
127
+ /** Props for the text field's error message element, if any. */
128
+ errorMessageProps: DOMAttributes;
129
+ }
130
+
131
+ /**
132
+ * Provides the behavior and accessibility implementation for a text field.
133
+ */
134
+ export function useTextField<T extends TextFieldIntrinsicElements = 'input'>(
135
+ props: AriaTextFieldOptions<T>,
136
+ ref: RefObject<HTMLInputElement | HTMLTextAreaElement | null>,
137
+ ): TextFieldAria;
138
+ // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
139
+ export function useTextField<T extends TextFieldIntrinsicElements = 'input'>(
140
+ props: AriaTextFieldOptions<T>,
141
+ ref: RefObject<HTMLInputElement | HTMLTextAreaElement | null>,
142
+ slot: symbol | undefined,
143
+ ): TextFieldAria;
144
+ export function useTextField(...args: any[]): TextFieldAria {
145
+ const [user, slotArg] = splitSlot(args);
146
+ const slot = slotArg ?? S('useTextField');
147
+ const props = user[0] as AriaTextFieldOptions<any>;
148
+ const ref = user[1] as RefObject<HTMLInputElement | HTMLTextAreaElement | null>;
149
+
150
+ let {
151
+ inputElementType = 'input',
152
+ isDisabled = false,
153
+ isRequired = false,
154
+ isReadOnly = false,
155
+ type = 'text',
156
+ validationBehavior = 'aria',
157
+ } = props as any;
158
+ let [value, setValue] = useControlledState<string>(
159
+ props.value,
160
+ props.defaultValue || '',
161
+ props.onChange,
162
+ subSlot(slot, 'value'),
163
+ );
164
+ let { focusableProps } = useFocusable(props, ref, subSlot(slot, 'focusable'));
165
+ let validationState = useFormValidationState(
166
+ {
167
+ ...props,
168
+ value,
169
+ },
170
+ subSlot(slot, 'validationState'),
171
+ );
172
+ let { isInvalid, validationErrors, validationDetails } = validationState.displayValidation;
173
+ let { labelProps, fieldProps, descriptionProps, errorMessageProps } = useField(
174
+ {
175
+ ...props,
176
+ isInvalid,
177
+ errorMessage: props.errorMessage || validationErrors,
178
+ },
179
+ subSlot(slot, 'field'),
180
+ );
181
+ let domProps = filterDOMProps(props, { labelable: true });
182
+
183
+ const inputOnlyProps = {
184
+ type,
185
+ pattern: props.pattern,
186
+ };
187
+
188
+ let [initialValue] = useState(value, subSlot(slot, 'initialValue'));
189
+ useFormReset(ref, props.defaultValue ?? initialValue, setValue, subSlot(slot, 'reset'));
190
+ useFormValidation(props, validationState, ref, subSlot(slot, 'validation'));
191
+
192
+ return {
193
+ labelProps,
194
+ inputProps: mergeProps(domProps, inputElementType === 'input' ? inputOnlyProps : undefined, {
195
+ disabled: isDisabled,
196
+ readOnly: isReadOnly,
197
+ required: isRequired && validationBehavior === 'native',
198
+ 'aria-required': (isRequired && validationBehavior === 'aria') || undefined,
199
+ 'aria-invalid': isInvalid || undefined,
200
+ 'aria-errormessage': props['aria-errormessage'],
201
+ 'aria-activedescendant': props['aria-activedescendant'],
202
+ 'aria-autocomplete': props['aria-autocomplete'],
203
+ 'aria-haspopup': props['aria-haspopup'],
204
+ 'aria-controls': props['aria-controls'],
205
+ value,
206
+ // octane adaptation: the state update rides the native `input` event (no
207
+ // synthetic onChange); the user's own onInput runs first, matching React's
208
+ // dispatch order for the same native event.
209
+ onInput: chain(props.onInput, (e: Event) =>
210
+ setValue((getEventTarget(e) as HTMLInputElement).value),
211
+ ),
212
+ autoComplete: props.autoComplete,
213
+ autoCapitalize: props.autoCapitalize,
214
+ maxLength: props.maxLength,
215
+ minLength: props.minLength,
216
+ name: props.name,
217
+ form: props.form,
218
+ placeholder: props.placeholder,
219
+ inputMode: props.inputMode,
220
+ autoCorrect: props.autoCorrect,
221
+ spellCheck: props.spellCheck,
222
+ enterKeyHint: props.enterKeyHint,
223
+
224
+ // Clipboard events
225
+ onCopy: props.onCopy,
226
+ onCut: props.onCut,
227
+ onPaste: props.onPaste,
228
+
229
+ // Composition events
230
+ onCompositionEnd: props.onCompositionEnd,
231
+ onCompositionStart: props.onCompositionStart,
232
+ onCompositionUpdate: props.onCompositionUpdate,
233
+
234
+ // Selection events
235
+ onSelect: props.onSelect,
236
+
237
+ // Input events
238
+ onBeforeInput: props.onBeforeInput,
239
+ ...focusableProps,
240
+ ...fieldProps,
241
+ }),
242
+ descriptionProps,
243
+ errorMessageProps,
244
+ isInvalid,
245
+ validationErrors,
246
+ validationDetails,
247
+ };
248
+ }
@@ -0,0 +1,265 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/toggle/useToggle.ts).
2
+ // octane adaptations:
3
+ // - `react-stately/*` imports → the ported `../stately/*` modules.
4
+ // - DOM wiring uses octane's native `onInput` prop instead of React's synthetic `onChange`
5
+ // (for checkbox-type inputs the native `input` event fires on every toggle, matching the
6
+ // upstream timing); `React.ChangeEvent` reads become the native event via
7
+ // `getEventTarget`. Public value-level `onChange` callbacks are unchanged.
8
+ // - React's `LabelHTMLAttributes`/`InputHTMLAttributes`/`DOMAttributesWithRef` prop-bag
9
+ // types → a local structural `DOMAttributes` (octane native event props).
10
+ // - The dev-only "you must specify an aria-label" console.warn (and the locals that only
11
+ // fed it) is not ported (repo policy: no dev-only console warnings).
12
+ // - Public-hook slot threading (splitSlot/subSlot) per the binding convention.
13
+ import type {
14
+ AriaLabelingProps,
15
+ AriaValidationProps,
16
+ FocusableDOMProps,
17
+ InputDOMProps,
18
+ PressEvents,
19
+ RefObject,
20
+ ValidationResult,
21
+ } from '@react-types/shared';
22
+ import { useState } from 'octane';
23
+
24
+ import { S, splitSlot, subSlot } from '../internal';
25
+ import { filterDOMProps } from '../utils/filterDOMProps';
26
+ import { getEventTarget } from '../utils/shadowdom/DOMFunctions';
27
+ import { mergeProps } from '../utils/mergeProps';
28
+ import {
29
+ privateValidationStateProp,
30
+ useFormValidationState,
31
+ } from '../stately/form/useFormValidationState';
32
+ import type { ToggleProps, ToggleState } from '../stately/toggle/useToggleState';
33
+ import { useFocusable } from '../interactions/useFocusable';
34
+ import { useFormReset } from '../utils/useFormReset';
35
+ import { useFormValidation } from '../form/useFormValidation';
36
+ import { usePress } from '../interactions/usePress';
37
+ import { useSlotId2 } from '../utils/useSlot';
38
+
39
+ // octane adaptation: minimal structural prop bag (upstream's drags React attribute types).
40
+ type DOMAttributes = Record<string, any>;
41
+
42
+ export interface AriaToggleProps
43
+ extends
44
+ ToggleProps,
45
+ FocusableDOMProps,
46
+ AriaLabelingProps,
47
+ AriaValidationProps,
48
+ InputDOMProps,
49
+ Omit<PressEvents, 'onClick'> {
50
+ /**
51
+ * **Not recommended – use `onPress` instead.** octane adaptation: native MouseEvent
52
+ * (upstream's `PressEvents.onClick` is typed over React's synthetic event).
53
+ */
54
+ onClick?: (e: MouseEvent) => void;
55
+ /**
56
+ * Identifies the element (or elements) whose contents or presence are controlled by the current
57
+ * element.
58
+ */
59
+ 'aria-controls'?: string;
60
+ }
61
+
62
+ export interface ToggleAria extends ValidationResult {
63
+ /** Props to be spread on the label element. */
64
+ labelProps: DOMAttributes;
65
+ /** Props to be spread on the input element. */
66
+ inputProps: DOMAttributes;
67
+ /** Props for the checkbox description element, if any. */
68
+ descriptionProps: DOMAttributes;
69
+ /** Props for the checkbox error message element, if any. */
70
+ errorMessageProps: DOMAttributes;
71
+ /** Whether the toggle is selected. */
72
+ isSelected: boolean;
73
+ /** Whether the toggle is in a pressed state. */
74
+ isPressed: boolean;
75
+ /** Whether the toggle is disabled. */
76
+ isDisabled: boolean;
77
+ /** Whether the toggle is read only. */
78
+ isReadOnly: boolean;
79
+ /** Whether the toggle is invalid. */
80
+ isInvalid: boolean;
81
+ }
82
+
83
+ /**
84
+ * Handles interactions for toggle elements, e.g. Checkboxes and Switches.
85
+ */
86
+ export function useToggle(
87
+ props: AriaToggleProps,
88
+ state: ToggleState,
89
+ ref: RefObject<HTMLInputElement | null>,
90
+ ): ToggleAria;
91
+ // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
92
+ export function useToggle(
93
+ props: AriaToggleProps,
94
+ state: ToggleState,
95
+ ref: RefObject<HTMLInputElement | null>,
96
+ slot: symbol | undefined,
97
+ ): ToggleAria;
98
+ export function useToggle(...args: any[]): ToggleAria {
99
+ const [user, slotArg] = splitSlot(args);
100
+ const slot = slotArg ?? S('useToggle');
101
+ const props = user[0] as AriaToggleProps;
102
+ const state = user[1] as ToggleState;
103
+ const ref = user[2] as RefObject<HTMLInputElement | null>;
104
+
105
+ let {
106
+ isDisabled = false,
107
+ isReadOnly = false,
108
+ value,
109
+ name,
110
+ form,
111
+ isRequired,
112
+ validationBehavior = 'aria',
113
+ 'aria-describedby': ariaDescribedby,
114
+ onPressStart,
115
+ onPressEnd,
116
+ onPressChange,
117
+ onPress,
118
+ onPressUp,
119
+ onClick,
120
+ } = props;
121
+
122
+ // Create validation state here because it doesn't make sense to add to general useToggleState.
123
+ let validationState = useFormValidationState(
124
+ { ...props, value: state.isSelected },
125
+ subSlot(slot, 'validation'),
126
+ );
127
+ let { isInvalid, validationErrors, validationDetails } = validationState.displayValidation;
128
+
129
+ useFormValidation(props, validationState, ref, subSlot(slot, 'formValidation'));
130
+
131
+ let onInput = (e: Event) => {
132
+ // since we spread props on label, onInput will end up there as well as in here.
133
+ // so we have to stop propagation at the lowest level that we care about
134
+ e.stopPropagation();
135
+ state.setSelected((getEventTarget(e) as HTMLInputElement).checked);
136
+ };
137
+
138
+ // Handle press state for keyboard interactions and cases where labelProps is not used.
139
+ let { pressProps, isPressed } = usePress(
140
+ {
141
+ onPressStart,
142
+ onPressEnd,
143
+ onPressChange,
144
+ onPress,
145
+ onPressUp,
146
+ onClick,
147
+ isDisabled,
148
+ },
149
+ subSlot(slot, 'press'),
150
+ );
151
+
152
+ // Handle press state on the label.
153
+ let [isLabelPressed, setLabelPressed] = useState(false, subSlot(slot, 'labelPressed'));
154
+ let { pressProps: labelProps } = usePress(
155
+ {
156
+ onPressStart(e) {
157
+ // Keyboard interactions are handled directly on the input.
158
+ if (e.pointerType === 'keyboard' || e.pointerType === 'virtual') {
159
+ e.continuePropagation();
160
+ return;
161
+ }
162
+
163
+ onPressStart?.(e);
164
+ onPressChange?.(true);
165
+ setLabelPressed(true);
166
+ },
167
+ onPressEnd(e) {
168
+ // Keyboard interactions are handled directly on the input.
169
+ if (e.pointerType === 'keyboard' || e.pointerType === 'virtual') {
170
+ e.continuePropagation();
171
+ return;
172
+ }
173
+
174
+ onPressEnd?.(e);
175
+ onPressChange?.(false);
176
+ setLabelPressed(false);
177
+ },
178
+ onPressUp(e) {
179
+ if (e.pointerType === 'keyboard' || e.pointerType === 'virtual') {
180
+ e.continuePropagation();
181
+ return;
182
+ }
183
+
184
+ onPressUp?.(e);
185
+ },
186
+ onClick,
187
+ onPress(e) {
188
+ if (e.pointerType === 'keyboard' || e.pointerType === 'virtual') {
189
+ e.continuePropagation();
190
+ return;
191
+ }
192
+
193
+ onPress?.(e);
194
+ state.toggle();
195
+ ref.current?.focus();
196
+
197
+ let groupValidationState = (props as any)[privateValidationStateProp];
198
+
199
+ let { commitValidation } = groupValidationState ? groupValidationState : validationState;
200
+
201
+ commitValidation();
202
+ },
203
+ isDisabled: isDisabled || isReadOnly,
204
+ },
205
+ subSlot(slot, 'labelPress'),
206
+ );
207
+
208
+ let { focusableProps } = useFocusable(props, ref, subSlot(slot, 'focusable'));
209
+ let interactions = mergeProps(pressProps, focusableProps);
210
+ let domProps = filterDOMProps(props, { labelable: true });
211
+
212
+ useFormReset(ref, state.defaultSelected, state.setSelected, subSlot(slot, 'formReset'));
213
+
214
+ // Copied from useField because we don't want the label behavior that provides.
215
+ let descriptionProps = useSlotId2(undefined, subSlot(slot, 'description'));
216
+ let errorMessageProps = useSlotId2(undefined, subSlot(slot, 'errorMessage'));
217
+
218
+ return {
219
+ labelProps: mergeProps(labelProps, {
220
+ // octane adaptation: upstream preventDefaults ALL label clicks to stop the label's
221
+ // built-in click-forwarding (a second, doubled activation) — React's synthetic
222
+ // onChange still fires either way, and the controlled `checked` prop papers over
223
+ // the cancelled DOM activation. With native events, an unconditional preventDefault
224
+ // would ALSO cancel the input's own activation (no `input` event → no toggle) for
225
+ // virtual clicks (element.click(), assistive tech). Scope it to clicks that do NOT
226
+ // target the input: label-body clicks still can't double-forward, input-targeted
227
+ // clicks activate natively. Real pointer gestures toggle via the label press path
228
+ // on both sides; virtual label-body clicks toggle on NEITHER side (React's
229
+ // onChange only fires for clicks targeting the input).
230
+ onClick: (e: MouseEvent) => {
231
+ if (getEventTarget(e) !== ref.current) {
232
+ e.preventDefault();
233
+ }
234
+ },
235
+ }),
236
+ inputProps: mergeProps(domProps, {
237
+ checked: state.isSelected,
238
+ 'aria-required': (isRequired && validationBehavior === 'aria') || undefined,
239
+ required: isRequired && validationBehavior === 'native',
240
+ 'aria-invalid': isInvalid || props.validationState === 'invalid' || undefined,
241
+ 'aria-errormessage': props['aria-errormessage'],
242
+ 'aria-controls': props['aria-controls'],
243
+ 'aria-readonly': isReadOnly || undefined,
244
+ 'aria-describedby':
245
+ [descriptionProps.id, errorMessageProps.id, ariaDescribedby].filter(Boolean).join(' ') ||
246
+ undefined,
247
+ onInput,
248
+ disabled: isDisabled,
249
+ ...(value == null ? {} : { value }),
250
+ name,
251
+ form,
252
+ type: 'checkbox',
253
+ ...interactions,
254
+ }),
255
+ descriptionProps,
256
+ errorMessageProps,
257
+ isSelected: state.isSelected,
258
+ isPressed: isPressed || isLabelPressed,
259
+ isDisabled,
260
+ isReadOnly,
261
+ isInvalid: isInvalid || props.validationState === 'invalid',
262
+ validationErrors,
263
+ validationDetails,
264
+ };
265
+ }
@@ -0,0 +1,147 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/toolbar/useToolbar.ts).
2
+ // octane adaptations: React's FocusEventHandler/KeyboardEventHandler → native event
3
+ // handlers (octane delegates the *Capture props natively); public-hook slot threading.
4
+ import type { AriaLabelingProps, Orientation, RefObject } from '@react-types/shared';
5
+ import { useRef, useState } from 'octane';
6
+
7
+ import { S, splitSlot, subSlot } from '../internal';
8
+ import { createFocusManager } from '../focus/FocusScope';
9
+ import { filterDOMProps } from '../utils/filterDOMProps';
10
+ import { getActiveElement, getEventTarget, nodeContains } from '../utils/shadowdom/DOMFunctions';
11
+ import { useLayoutEffect } from '../utils/useLayoutEffect';
12
+ import { useLocale } from '../i18n/I18nProvider';
13
+
14
+ export interface AriaToolbarProps extends AriaLabelingProps {
15
+ /**
16
+ * The orientation of the entire toolbar.
17
+ *
18
+ * @default 'horizontal'
19
+ */
20
+ orientation?: Orientation;
21
+ }
22
+
23
+ export interface ToolbarAria {
24
+ /**
25
+ * Props for the toolbar container.
26
+ */
27
+ toolbarProps: Record<string, any>;
28
+ }
29
+
30
+ export function useToolbar(
31
+ props: AriaToolbarProps,
32
+ ref: RefObject<HTMLElement | null>,
33
+ ): ToolbarAria;
34
+ // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
35
+ export function useToolbar(
36
+ props: AriaToolbarProps,
37
+ ref: RefObject<HTMLElement | null>,
38
+ slot: symbol | undefined,
39
+ ): ToolbarAria;
40
+ export function useToolbar(...args: any[]): ToolbarAria {
41
+ const [user, slotArg] = splitSlot(args);
42
+ const slot = slotArg ?? S('useToolbar');
43
+ const props = user[0] as AriaToolbarProps;
44
+ const ref = user[1] as RefObject<HTMLElement | null>;
45
+
46
+ const {
47
+ 'aria-label': ariaLabel,
48
+ 'aria-labelledby': ariaLabelledBy,
49
+ orientation = 'horizontal',
50
+ } = props;
51
+ let [isInToolbar, setInToolbar] = useState(false, subSlot(slot, 'inToolbar'));
52
+ // should be safe because re-calling set state with the same value it already has is a no-op
53
+ // this will allow us to react should a parent re-render and change its role though
54
+ useLayoutEffect(
55
+ () => {
56
+ setInToolbar(!!(ref.current && ref.current.parentElement?.closest('[role="toolbar"]')));
57
+ },
58
+ null,
59
+ subSlot(slot, 'detect'),
60
+ );
61
+ const { direction } = useLocale(subSlot(slot, 'locale'));
62
+ const shouldReverse = direction === 'rtl' && orientation === 'horizontal';
63
+ let focusManager = createFocusManager(ref);
64
+
65
+ const onKeyDown = (e: KeyboardEvent) => {
66
+ // don't handle portalled events
67
+ if (!nodeContains(e.currentTarget as Element, getEventTarget(e) as HTMLElement)) {
68
+ return;
69
+ }
70
+ if (
71
+ (orientation === 'horizontal' && e.key === 'ArrowRight') ||
72
+ (orientation === 'vertical' && e.key === 'ArrowDown')
73
+ ) {
74
+ if (shouldReverse) {
75
+ focusManager.focusPrevious();
76
+ } else {
77
+ focusManager.focusNext();
78
+ }
79
+ } else if (
80
+ (orientation === 'horizontal' && e.key === 'ArrowLeft') ||
81
+ (orientation === 'vertical' && e.key === 'ArrowUp')
82
+ ) {
83
+ if (shouldReverse) {
84
+ focusManager.focusNext();
85
+ } else {
86
+ focusManager.focusPrevious();
87
+ }
88
+ } else if (e.key === 'Tab') {
89
+ // When the tab key is pressed, we want to move focus
90
+ // out of the entire toolbar. To do this, move focus
91
+ // to the first or last focusable child, and let the
92
+ // browser handle the Tab key as usual from there.
93
+ lastFocused.current = getActiveElement() as HTMLElement;
94
+ if (e.shiftKey) {
95
+ focusManager.focusFirst();
96
+ } else {
97
+ focusManager.focusLast();
98
+ }
99
+ return;
100
+ } else {
101
+ // if we didn't handle anything, return early so we don't preventDefault
102
+ return;
103
+ }
104
+
105
+ // Prevent arrow keys from being handled by nested action groups.
106
+ e.stopPropagation();
107
+ e.preventDefault();
108
+ };
109
+
110
+ // Record the last focused child when focus moves out of the toolbar.
111
+ const lastFocused = useRef<HTMLElement | null>(null, subSlot(slot, 'lastFocused'));
112
+ const onBlur = (e: FocusEvent) => {
113
+ if (
114
+ !nodeContains(e.currentTarget as Element, e.relatedTarget as Element) &&
115
+ !lastFocused.current
116
+ ) {
117
+ lastFocused.current = getEventTarget(e) as HTMLElement;
118
+ }
119
+ };
120
+
121
+ // Restore focus to the last focused child when focus returns into the toolbar.
122
+ // If the element was removed, do nothing, either the first item in the first group,
123
+ // or the last item in the last group will be focused, depending on direction.
124
+ const onFocus = (e: FocusEvent) => {
125
+ if (
126
+ lastFocused.current &&
127
+ !nodeContains(e.currentTarget as Element, e.relatedTarget as Element) &&
128
+ nodeContains(ref.current, getEventTarget(e) as Element)
129
+ ) {
130
+ lastFocused.current?.focus();
131
+ lastFocused.current = null;
132
+ }
133
+ };
134
+
135
+ return {
136
+ toolbarProps: {
137
+ ...filterDOMProps(props, { labelable: true }),
138
+ role: !isInToolbar ? 'toolbar' : 'group',
139
+ 'aria-orientation': orientation,
140
+ 'aria-label': ariaLabel,
141
+ 'aria-labelledby': ariaLabel == null ? ariaLabelledBy : undefined,
142
+ onKeyDownCapture: !isInToolbar ? onKeyDown : undefined,
143
+ onFocusCapture: !isInToolbar ? onFocus : undefined,
144
+ onBlurCapture: !isInToolbar ? onBlur : undefined,
145
+ },
146
+ };
147
+ }