@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,512 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/gridlist/useGridListItem.ts).
2
+ // octane adaptations:
3
+ // - Handlers receive NATIVE events (there is no synthetic layer): keydown handlers take
4
+ // the native KeyboardEvent, `e.nativeEvent` reads collapse to the event itself (the
5
+ // ArrowUp/ArrowDown re-dispatch builds `new KeyboardEvent(e.type, e)` — WebIDL
6
+ // dictionary conversion reads the inherited native-event accessors), and upstream's
7
+ // synthetic `e.isPropagationStopped()` reads the native `cancelBubble` flag (same
8
+ // source of truth the ported interactions/utils shim uses). `onKeyDownCapture` maps to
9
+ // the capture phase natively in octane, matching upstream's React capture prop.
10
+ // - `ListState`/`TreeState` come from the ported stately hooks; `HTMLAttributes` /
11
+ // `DOMAttributes` collapse to a structural prop bag.
12
+ // - Public-hook slot threading (splitSlot/subSlot).
13
+ import { chain } from '../utils/chain';
14
+ import type {
15
+ Collection,
16
+ FocusableElement,
17
+ Key,
18
+ RefObject,
19
+ Node as RSNode,
20
+ } from '@react-types/shared';
21
+ import { focusSafely } from '../interactions/focusSafely';
22
+ import {
23
+ getActiveElement,
24
+ getEventTarget,
25
+ isFocusWithin,
26
+ nodeContains,
27
+ } from '../utils/shadowdom/DOMFunctions';
28
+ import { getFocusableTreeWalker } from '../focus/FocusScope';
29
+ import { getRowId, listMap } from './utils';
30
+ import { getScrollParent } from '../utils/getScrollParent';
31
+ import { useRef } from 'octane';
32
+ import { isFocusVisible } from '../interactions/useFocusVisible';
33
+ import { isTabbable } from '../utils/isFocusable';
34
+ import type { ListState } from '../stately/list/useListState';
35
+ import { mergeProps } from '../utils/mergeProps';
36
+ import { scrollIntoViewport } from '../utils/scrollIntoView';
37
+ import { SelectableItemStates, useSelectableItem } from '../selection/useSelectableItem';
38
+ import type { TreeState } from '../stately/tree/useTreeState';
39
+ import { useLocale } from '../i18n/I18nProvider';
40
+ import { useSlotId } from '../utils/useId';
41
+ import { useSyntheticLinkProps } from '../utils/openLink';
42
+
43
+ import { S, splitSlot, subSlot } from '../internal';
44
+
45
+ // octane adaptation: minimal structural DOMAttributes (upstream's drags React's synthetic
46
+ // handler types along).
47
+ type DOMAttributes = Record<string, any>;
48
+
49
+ export interface AriaGridListItemOptions {
50
+ /**
51
+ * An object representing the list item. Contains all the relevant information that makes up the
52
+ * list row.
53
+ */
54
+ node: RSNode<unknown>;
55
+ /** Whether the list row is contained in a virtual scroller. */
56
+ isVirtualized?: boolean;
57
+ /** Whether selection should occur on press up instead of press down. */
58
+ shouldSelectOnPressUp?: boolean;
59
+ /** Whether this item has children, even if not loaded yet. */
60
+ hasChildItems?: boolean;
61
+ }
62
+
63
+ export interface GridListItemAria extends SelectableItemStates {
64
+ /** Props for the list row element. */
65
+ rowProps: DOMAttributes;
66
+ /** Props for the grid cell element within the list row. */
67
+ gridCellProps: DOMAttributes;
68
+ /** Props for the list item description element, if any. */
69
+ descriptionProps: DOMAttributes;
70
+ }
71
+
72
+ const EXPANSION_KEYS = {
73
+ expand: {
74
+ ltr: 'ArrowRight',
75
+ rtl: 'ArrowLeft',
76
+ },
77
+ collapse: {
78
+ ltr: 'ArrowLeft',
79
+ rtl: 'ArrowRight',
80
+ },
81
+ };
82
+
83
+ /**
84
+ * Provides the behavior and accessibility implementation for a row in a grid list.
85
+ *
86
+ * @param props - Props for the row.
87
+ * @param state - State of the parent list, as returned by `useListState`.
88
+ * @param ref - The ref attached to the row element.
89
+ */
90
+ export function useGridListItem<T>(
91
+ props: AriaGridListItemOptions,
92
+ state: ListState<T> | TreeState<T>,
93
+ ref: RefObject<FocusableElement | null>,
94
+ ): GridListItemAria;
95
+ // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
96
+ export function useGridListItem<T>(
97
+ props: AriaGridListItemOptions,
98
+ state: ListState<T> | TreeState<T>,
99
+ ref: RefObject<FocusableElement | null>,
100
+ slot: symbol | undefined,
101
+ ): GridListItemAria;
102
+ export function useGridListItem(...args: any[]): GridListItemAria {
103
+ const [user, slotArg] = splitSlot(args);
104
+ const slot = slotArg ?? S('useGridListItem');
105
+ const props = user[0] as AriaGridListItemOptions;
106
+ const state = user[1] as ListState<any> | TreeState<any>;
107
+ const ref = user[2] as RefObject<FocusableElement | null>;
108
+
109
+ // Copied from useGridCell + some modifications to make it not so grid specific
110
+ let { node, isVirtualized } = props;
111
+
112
+ // let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/gridlist');
113
+ let { direction } = useLocale(subSlot(slot, 'locale'));
114
+ let { onAction, linkBehavior, keyboardNavigationBehavior, shouldSelectOnPressUp } =
115
+ listMap.get(state)!;
116
+ let descriptionId = useSlotId(undefined, subSlot(slot, 'descriptionId'));
117
+
118
+ // We need to track the key of the item at the time it was last focused so that we force
119
+ // focus to go to the item when the DOM node is reused for a different item in a virtualizer.
120
+ let keyWhenFocused = useRef<Key | null>(null, subSlot(slot, 'keyWhenFocused'));
121
+ let focus = () => {
122
+ // Don't shift focus to the row if the active element is a element within the row already
123
+ // (e.g. clicking on a row button)
124
+ if (
125
+ ref.current !== null &&
126
+ ((keyWhenFocused.current != null && node.key !== keyWhenFocused.current) ||
127
+ !isFocusWithin(ref.current))
128
+ ) {
129
+ focusSafely(ref.current);
130
+ }
131
+ };
132
+
133
+ let treeGridRowProps: DOMAttributes = {};
134
+ let hasChildRows = props.hasChildItems;
135
+ let hasLink = state.selectionManager.isLink(node.key);
136
+ if (node != null && 'expandedKeys' in state) {
137
+ // TODO: ideally node.hasChildNodes would be a way to tell if a row has child nodes, but the row's contents make it so that value is always
138
+ // true...
139
+ let children = state.collection.getChildren?.(node.key);
140
+ hasChildRows = hasChildRows || [...(children ?? [])].length > 1;
141
+
142
+ if (
143
+ onAction == null &&
144
+ !hasLink &&
145
+ state.selectionManager.selectionMode === 'none' &&
146
+ hasChildRows
147
+ ) {
148
+ onAction = () => state.toggleKey(node.key);
149
+ }
150
+
151
+ let isExpanded = hasChildRows ? state.expandedKeys.has(node.key) : undefined;
152
+ let setSize = 1;
153
+ let index = node.index;
154
+ if (node.level >= 0 && node?.parentKey != null) {
155
+ let parent = state.collection.getItem(node.parentKey);
156
+ if (parent) {
157
+ // siblings must exist because our original node exists
158
+ let siblings = getDirectChildren(parent, state.collection);
159
+ setSize = [...siblings].filter((row) => row.type === 'item').length;
160
+ if (index > 0 && siblings[0].type !== 'item') {
161
+ index -= 1; // subtract one for the parent item's content node
162
+ }
163
+ }
164
+ } else {
165
+ setSize = [...state.collection].filter(
166
+ (row) => row.level === 0 && row.type === 'item',
167
+ ).length;
168
+ }
169
+
170
+ treeGridRowProps = {
171
+ 'aria-expanded': isExpanded,
172
+ 'aria-level': node.level + 1,
173
+ 'aria-posinset': index + 1,
174
+ 'aria-setsize': setSize,
175
+ };
176
+ }
177
+
178
+ let { itemProps, ...itemStates } = useSelectableItem(
179
+ {
180
+ selectionManager: state.selectionManager,
181
+ key: node.key,
182
+ ref,
183
+ isVirtualized,
184
+ shouldSelectOnPressUp: props.shouldSelectOnPressUp || shouldSelectOnPressUp,
185
+ onAction:
186
+ onAction || node.props?.onAction
187
+ ? chain(node.props?.onAction, onAction ? () => onAction(node.key) : undefined)
188
+ : undefined,
189
+ focus,
190
+ linkBehavior,
191
+ },
192
+ subSlot(slot, 'selectableItem'),
193
+ );
194
+
195
+ let onKeyDownCapture = (e: KeyboardEvent) => {
196
+ let activeElement = getActiveElement();
197
+ if (
198
+ !nodeContains(e.currentTarget as Element, getEventTarget(e) as Element) ||
199
+ !ref.current ||
200
+ !activeElement
201
+ ) {
202
+ return;
203
+ }
204
+
205
+ let walker = getFocusableTreeWalker(ref.current);
206
+ walker.currentNode = activeElement;
207
+
208
+ if (
209
+ handleTreeExpansionKeys(e, state, node, hasChildRows, direction, activeElement, ref.current)
210
+ ) {
211
+ return;
212
+ }
213
+
214
+ switch (e.key) {
215
+ case 'ArrowLeft': {
216
+ if (keyboardNavigationBehavior === 'arrow') {
217
+ // Find the next focusable element within the row.
218
+ let focusable =
219
+ direction === 'rtl'
220
+ ? (walker.nextNode() as FocusableElement)
221
+ : (walker.previousNode() as FocusableElement);
222
+
223
+ if (focusable) {
224
+ e.preventDefault();
225
+ e.stopPropagation();
226
+ focusSafely(focusable);
227
+ scrollIntoViewport(focusable, { containingElement: getScrollParent(ref.current) });
228
+ } else {
229
+ // If there is no next focusable child, then return focus back to the row
230
+ e.preventDefault();
231
+ e.stopPropagation();
232
+ if (direction === 'rtl') {
233
+ focusSafely(ref.current);
234
+ scrollIntoViewport(ref.current, { containingElement: getScrollParent(ref.current) });
235
+ } else {
236
+ walker.currentNode = ref.current;
237
+ let lastElement = last(walker);
238
+ if (lastElement) {
239
+ focusSafely(lastElement);
240
+ scrollIntoViewport(lastElement, {
241
+ containingElement: getScrollParent(ref.current),
242
+ });
243
+ }
244
+ }
245
+ }
246
+ }
247
+ break;
248
+ }
249
+ case 'ArrowRight': {
250
+ if (keyboardNavigationBehavior === 'arrow') {
251
+ let focusable =
252
+ direction === 'rtl'
253
+ ? (walker.previousNode() as FocusableElement)
254
+ : (walker.nextNode() as FocusableElement);
255
+
256
+ if (focusable) {
257
+ e.preventDefault();
258
+ e.stopPropagation();
259
+ focusSafely(focusable);
260
+ scrollIntoViewport(focusable, { containingElement: getScrollParent(ref.current) });
261
+ } else {
262
+ e.preventDefault();
263
+ e.stopPropagation();
264
+ if (direction === 'ltr') {
265
+ focusSafely(ref.current);
266
+ scrollIntoViewport(ref.current, { containingElement: getScrollParent(ref.current) });
267
+ } else {
268
+ walker.currentNode = ref.current;
269
+ let lastElement = last(walker);
270
+ if (lastElement) {
271
+ focusSafely(lastElement);
272
+ scrollIntoViewport(lastElement, {
273
+ containingElement: getScrollParent(ref.current),
274
+ });
275
+ }
276
+ }
277
+ }
278
+ }
279
+ break;
280
+ }
281
+ case 'ArrowUp':
282
+ case 'ArrowDown':
283
+ // Prevent this event from reaching row children, e.g. menu buttons. We want arrow keys to navigate
284
+ // to the row above/below instead. We need to re-dispatch the event from a higher parent so it still
285
+ // bubbles and gets handled by useSelectableCollection.
286
+ if (!e.altKey && nodeContains(ref.current, getEventTarget(e) as Element)) {
287
+ e.stopPropagation();
288
+ e.preventDefault();
289
+ // octane adaptation: the native event IS `e.nativeEvent`.
290
+ ref.current.parentElement?.dispatchEvent(new KeyboardEvent(e.type, e));
291
+ }
292
+ break;
293
+ }
294
+ };
295
+
296
+ let onFocus = (e: FocusEvent) => {
297
+ keyWhenFocused.current = node.key;
298
+ if (getEventTarget(e) !== ref.current) {
299
+ // useSelectableItem only handles setting the focused key when
300
+ // the focused element is the row itself. We also want to
301
+ // set the focused key when a child element receives focus.
302
+ // If focus is currently visible (e.g. the user is navigating with the keyboard),
303
+ // then skip this. We want to restore focus to the previously focused row
304
+ // in that case since the list should act like a single tab stop.
305
+ if (!isFocusVisible()) {
306
+ state.selectionManager.setFocusedKey(node.key);
307
+ }
308
+ return;
309
+ }
310
+ };
311
+
312
+ let onKeyDown = (e: KeyboardEvent) => {
313
+ let activeElement = getActiveElement();
314
+ if (
315
+ !nodeContains(e.currentTarget as Element, getEventTarget(e) as Element) ||
316
+ !ref.current ||
317
+ !activeElement
318
+ ) {
319
+ return;
320
+ }
321
+
322
+ if (keyboardNavigationBehavior === 'tab') {
323
+ // Stop propagation for all events that originate from the children of the gridlist item since we don't want to trigger
324
+ // grid level interactions (row navigation/typeselect/etc)
325
+ // exception made for Tab since that needs to propagate to useSelectableCollection to tab out of the gridlist, might be others?
326
+ if (getEventTarget(e) !== ref.current && e.key !== 'Tab') {
327
+ e.stopPropagation();
328
+ return;
329
+ }
330
+
331
+ if (
332
+ handleTreeExpansionKeys(e, state, node, hasChildRows, direction, activeElement, ref.current)
333
+ ) {
334
+ return;
335
+ }
336
+ }
337
+
338
+ switch (e.key) {
339
+ case 'Tab': {
340
+ if (keyboardNavigationBehavior === 'tab') {
341
+ // If there is another focusable element within this item, stop propagation so the tab key
342
+ // is handled by the browser and not by useSelectableCollection (which would take us out of the list).
343
+ let walker = getFocusableTreeWalker(ref.current, { tabbable: true });
344
+ walker.currentNode = activeElement;
345
+ let next = e.shiftKey ? walker.previousNode() : walker.nextNode();
346
+
347
+ if (next) {
348
+ e.stopPropagation();
349
+ }
350
+ }
351
+ }
352
+ }
353
+ };
354
+
355
+ let syntheticLinkProps = useSyntheticLinkProps(node.props);
356
+ let linkProps = itemStates.hasAction ? syntheticLinkProps : {};
357
+ // TODO: re-add when we get translations and fix this for iOS VO
358
+ // let rowAnnouncement;
359
+ // if (onAction) {
360
+ // rowAnnouncement = stringFormatter.format('hasActionAnnouncement');
361
+ // } else if (hasLink) {
362
+ // rowAnnouncement = stringFormatter.format('hasLinkAnnouncement', {
363
+ // link: node.props.href
364
+ // });
365
+ // }
366
+
367
+ let rowProps: DOMAttributes = mergeProps(itemProps, linkProps, {
368
+ role: 'row',
369
+ onKeyDownCapture: keyboardNavigationBehavior === 'arrow' ? onKeyDownCapture : undefined,
370
+ onFocus,
371
+ // 'aria-label': [(node.textValue || undefined), rowAnnouncement].filter(Boolean).join(', '),
372
+ 'aria-label': (node as any)['aria-label'] || node.textValue || undefined,
373
+ 'aria-selected': state.selectionManager.canSelectItem(node.key)
374
+ ? state.selectionManager.isSelected(node.key)
375
+ : undefined,
376
+ 'aria-disabled': state.selectionManager.isDisabled(node.key) || undefined,
377
+ 'aria-labelledby':
378
+ descriptionId && ((node as any)['aria-label'] || node.textValue)
379
+ ? `${getRowId(state, node.key)} ${descriptionId}`
380
+ : undefined,
381
+ id: getRowId(state, node.key),
382
+ });
383
+
384
+ // we need to guard against space/enter triggering selection/row link via usePress (from itemProps) so check if propagation
385
+ // is stopped. this also fixes space not working in a textfield in a tree parent row
386
+ let baseOnKeyDown = rowProps.onKeyDown;
387
+ rowProps.onKeyDown = (e: KeyboardEvent) => {
388
+ onKeyDown(e);
389
+ // octane adaptation: synthetic isPropagationStopped() → the native cancelBubble flag.
390
+ if (!(e as any).cancelBubble) {
391
+ baseOnKeyDown?.(e);
392
+ }
393
+ };
394
+
395
+ // guard against presses triggering row selecition when they happen on elements within the row
396
+ // am currently assuming if it is tabbable it is interactive, but maybe can use a different kind of check
397
+ let baseOnPointerDown = rowProps.onPointerDown;
398
+ rowProps.onPointerDown = (e: PointerEvent) => {
399
+ let target = getEventTarget(e) as Element | null;
400
+ if (target && target !== ref.current && isTabbable(target)) {
401
+ e.stopPropagation();
402
+ return;
403
+ }
404
+ baseOnPointerDown?.(e);
405
+ };
406
+
407
+ let baseOnMouseDown = rowProps.onMouseDown;
408
+ rowProps.onMouseDown = (e: MouseEvent) => {
409
+ let target = getEventTarget(e) as Element | null;
410
+ if (target && target !== ref.current && isTabbable(target)) {
411
+ e.stopPropagation();
412
+ return;
413
+ }
414
+ baseOnMouseDown?.(e);
415
+ };
416
+
417
+ if (isVirtualized) {
418
+ let { collection } = state;
419
+ let nodes = [...collection];
420
+ // TODO: refactor ListCollection to store an absolute index of a node's position?
421
+ rowProps['aria-rowindex'] = nodes.find((node) => node.type === 'section')
422
+ ? [...collection.getKeys()]
423
+ .filter((key) => collection.getItem(key)?.type !== 'section')
424
+ .findIndex((key) => key === node.key) + 1
425
+ : node.index + 1;
426
+ }
427
+
428
+ let gridCellProps = {
429
+ role: 'gridcell',
430
+ 'aria-colindex': 1,
431
+ };
432
+
433
+ // TODO: should isExpanded and hasChildRows be a item state that gets returned by the hook?
434
+ return {
435
+ rowProps: { ...mergeProps(rowProps, treeGridRowProps) },
436
+ gridCellProps,
437
+ descriptionProps: {
438
+ id: descriptionId,
439
+ },
440
+ ...itemStates,
441
+ };
442
+ }
443
+
444
+ function handleTreeExpansionKeys<T>(
445
+ e: KeyboardEvent,
446
+ state: ListState<T> | TreeState<T>,
447
+ node: RSNode<unknown>,
448
+ hasChildRows: boolean | undefined,
449
+ direction: string,
450
+ activeElement: Element | null,
451
+ rowRef: FocusableElement | null,
452
+ ): boolean {
453
+ if (!('expandedKeys' in state) || activeElement !== rowRef) {
454
+ return false;
455
+ }
456
+ if (
457
+ e.key === (EXPANSION_KEYS['expand'] as Record<string, string>)[direction] &&
458
+ state.selectionManager.focusedKey === node.key &&
459
+ hasChildRows &&
460
+ !state.expandedKeys.has(node.key)
461
+ ) {
462
+ state.toggleKey(node.key);
463
+ e.stopPropagation();
464
+ return true;
465
+ } else if (
466
+ e.key === (EXPANSION_KEYS['collapse'] as Record<string, string>)[direction] &&
467
+ state.selectionManager.focusedKey === node.key
468
+ ) {
469
+ // If item is collapsible, collapse it; else move to parent
470
+ if (hasChildRows && state.expandedKeys.has(node.key)) {
471
+ state.toggleKey(node.key);
472
+ e.stopPropagation();
473
+ return true;
474
+ } else if (
475
+ !state.expandedKeys.has(node.key) &&
476
+ node.parentKey &&
477
+ state.collection.getItem(node.parentKey)?.type === 'item'
478
+ ) {
479
+ // Item is a leaf or already collapsed, move focus to parent
480
+ state.selectionManager.setFocusedKey(node.parentKey);
481
+ e.stopPropagation();
482
+ return true;
483
+ }
484
+ }
485
+ return false;
486
+ }
487
+
488
+ function last(walker: TreeWalker) {
489
+ let next: FocusableElement | null = null;
490
+ let last: FocusableElement | null = null;
491
+ do {
492
+ last = walker.lastChild() as FocusableElement | null;
493
+ if (last) {
494
+ next = last;
495
+ }
496
+ } while (last);
497
+ return next;
498
+ }
499
+
500
+ function getDirectChildren<T>(parent: RSNode<T>, collection: Collection<RSNode<T>>) {
501
+ // We can't assume that we can use firstChildKey because if a person builds a tree using hooks, they would not have access to that property (using type Node vs CollectionNode)
502
+ // Instead, get all children and start at the first node (rather than just using firstChildKey) and only look at its siblings
503
+ let children = collection.getChildren?.(parent.key);
504
+ let childArray = children ? Array.from(children) : [];
505
+ let node = childArray.length > 0 ? childArray[0] : null;
506
+ let siblings: RSNode<T>[] = [];
507
+ while (node) {
508
+ siblings.push(node);
509
+ node = node.nextKey != null ? collection.getItem(node.nextKey) : null;
510
+ }
511
+ return siblings;
512
+ }
@@ -0,0 +1,78 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/gridlist/useGridListSection.ts).
2
+ // octane adaptations: `ListState` comes from the ported stately list hook;
3
+ // `DOMAttributes` is a local structural prop-bag alias; public-hook slot threading.
4
+ import type { RefObject } from '@react-types/shared';
5
+ import type { ListState } from '../stately/list/useListState';
6
+ import { useLabels } from '../utils/useLabels';
7
+ import { useSlotId } from '../utils/useId';
8
+
9
+ import { S, splitSlot, subSlot } from '../internal';
10
+
11
+ // octane adaptation: minimal structural DOMAttributes (upstream's drags React's synthetic
12
+ // handler types along).
13
+ type DOMAttributes = Record<string, any>;
14
+
15
+ export interface AriaGridListSectionProps {
16
+ /** An accessibility label for the section. Required if `heading` is not present. */
17
+ 'aria-label'?: string;
18
+ }
19
+
20
+ export interface GridListSectionAria {
21
+ /** Props for the wrapper list item. */
22
+ rowProps: DOMAttributes;
23
+
24
+ /** Props for the heading element, if any. */
25
+ rowHeaderProps: DOMAttributes;
26
+
27
+ /** Props for the grid's row group element. */
28
+ rowGroupProps: DOMAttributes;
29
+ }
30
+
31
+ /**
32
+ * Provides the behavior and accessibility implementation for a section in a grid list.
33
+ * See `useGridList` for more details about grid list.
34
+ *
35
+ * @param props - Props for the section.
36
+ */
37
+ export function useGridListSection<T>(
38
+ props: AriaGridListSectionProps,
39
+ state: ListState<T>,
40
+ ref: RefObject<HTMLElement | null>,
41
+ ): GridListSectionAria;
42
+ // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
43
+ export function useGridListSection<T>(
44
+ props: AriaGridListSectionProps,
45
+ state: ListState<T>,
46
+ ref: RefObject<HTMLElement | null>,
47
+ slot: symbol | undefined,
48
+ ): GridListSectionAria;
49
+ export function useGridListSection(...args: any[]): GridListSectionAria {
50
+ const [user, slotArg] = splitSlot(args);
51
+ const slot = slotArg ?? S('useGridListSection');
52
+ const props = user[0] as AriaGridListSectionProps;
53
+
54
+ let { 'aria-label': ariaLabel } = props;
55
+ let headingId = useSlotId(undefined, subSlot(slot, 'headingId'));
56
+ let labelProps = useLabels(
57
+ {
58
+ 'aria-label': ariaLabel,
59
+ 'aria-labelledby': headingId,
60
+ },
61
+ undefined,
62
+ subSlot(slot, 'labels'),
63
+ );
64
+
65
+ return {
66
+ rowProps: {
67
+ role: 'row',
68
+ },
69
+ rowHeaderProps: {
70
+ id: headingId,
71
+ role: 'rowheader',
72
+ },
73
+ rowGroupProps: {
74
+ role: 'rowgroup',
75
+ ...labelProps,
76
+ },
77
+ };
78
+ }
@@ -0,0 +1,47 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/gridlist/useGridListSelectionCheckbox.ts).
2
+ // octane adaptations: `ListState` comes from the ported stately list hook; the grid-area
3
+ // import resolves to the ported GRID SUBSET useGridSelectionCheckbox (whose state
4
+ // parameter is structural, so upstream's `state as any` cast collapses); public-hook
5
+ // slot threading.
6
+ import {
7
+ AriaGridSelectionCheckboxProps,
8
+ GridSelectionCheckboxAria,
9
+ useGridSelectionCheckbox,
10
+ } from '../grid/useGridSelectionCheckbox';
11
+ import { getRowId } from './utils';
12
+ import type { ListState } from '../stately/list/useListState';
13
+
14
+ import { S, splitSlot, subSlot } from '../internal';
15
+
16
+ /**
17
+ * Provides the behavior and accessibility implementation for a selection checkbox in a grid list.
18
+ *
19
+ * @param props - Props for the selection checkbox.
20
+ * @param state - State of the list, as returned by `useListState`.
21
+ */
22
+ export function useGridListSelectionCheckbox<T>(
23
+ props: AriaGridSelectionCheckboxProps,
24
+ state: ListState<T>,
25
+ ): GridSelectionCheckboxAria;
26
+ // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
27
+ export function useGridListSelectionCheckbox<T>(
28
+ props: AriaGridSelectionCheckboxProps,
29
+ state: ListState<T>,
30
+ slot: symbol | undefined,
31
+ ): GridSelectionCheckboxAria;
32
+ export function useGridListSelectionCheckbox(...args: any[]): GridSelectionCheckboxAria {
33
+ const [user, slotArg] = splitSlot(args);
34
+ const slot = slotArg ?? S('useGridListSelectionCheckbox');
35
+ const props = user[0] as AriaGridSelectionCheckboxProps;
36
+ const state = user[1] as ListState<any>;
37
+
38
+ let { key } = props;
39
+ const { checkboxProps } = useGridSelectionCheckbox(props, state, subSlot(slot, 'checkbox'));
40
+
41
+ return {
42
+ checkboxProps: {
43
+ ...checkboxProps,
44
+ 'aria-labelledby': `${checkboxProps.id} ${getRowId(state, key)}`,
45
+ },
46
+ };
47
+ }
@@ -0,0 +1,36 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/gridlist/utils.ts).
2
+ // octane adaptations: `ListState` type comes from the ported stately list hook.
3
+ import type { Key } from '@react-types/shared';
4
+ import type { ListState } from '../stately/list/useListState';
5
+
6
+ interface ListMapShared {
7
+ id: string;
8
+ onAction?: (key: Key) => void;
9
+ linkBehavior?: 'action' | 'selection' | 'override';
10
+ keyboardNavigationBehavior: 'arrow' | 'tab';
11
+ shouldSelectOnPressUp?: boolean;
12
+ }
13
+
14
+ // Used to share:
15
+ // id of the list and onAction between useList, useListItem, and useListSelectionCheckbox
16
+ export const listMap: WeakMap<ListState<unknown>, ListMapShared> = new WeakMap<
17
+ ListState<unknown>,
18
+ ListMapShared
19
+ >();
20
+
21
+ export function getRowId<T>(state: ListState<T>, key: Key): string {
22
+ let { id } = listMap.get(state) ?? {};
23
+ if (!id) {
24
+ throw new Error('Unknown list');
25
+ }
26
+
27
+ return `${id}-${normalizeKey(key)}`;
28
+ }
29
+
30
+ export function normalizeKey(key: Key): string {
31
+ if (typeof key === 'string') {
32
+ return key.replace(/\s*/g, '');
33
+ }
34
+
35
+ return '' + key;
36
+ }