@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,212 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/listbox/useOption.ts).
2
+ // octane adaptations:
3
+ // - `DOMAttributes` is a local structural prop-bag alias (upstream's is typed over React's
4
+ // synthetic handlers); `optionProps` is typed as that bag so the virtualized
5
+ // `aria-posinset`/`aria-setsize` assignments type-check.
6
+ // - `getItemCount` / `ListState` from the ported stately collections/list.
7
+ // - Public-hook slot threading (splitSlot/subSlot) per the binding convention
8
+ // (`useLinkProps` composes only context-reading hooks and takes no slot, matching
9
+ // the ported useLink).
10
+ import { chain } from '../utils/chain';
11
+
12
+ import type { FocusableElement, Key, RefObject } from '@react-types/shared';
13
+ import { filterDOMProps } from '../utils/filterDOMProps';
14
+ import { getItemCount } from '../stately/collections/getItemCount';
15
+ import { getItemId, listData } from './utils';
16
+ import { isFocusVisible } from '../interactions/useFocusVisible';
17
+ import type { ListState } from '../stately/list/useListState';
18
+ import { mergeProps } from '../utils/mergeProps';
19
+ import { type SelectableItemStates, useSelectableItem } from '../selection/useSelectableItem';
20
+ import { useHover } from '../interactions/useHover';
21
+ import { useLinkProps } from '../utils/openLink';
22
+ import { useSlotId } from '../utils/useId';
23
+
24
+ import { S, splitSlot, subSlot } from '../internal';
25
+
26
+ // octane adaptation: minimal structural DOMAttributes (upstream's drags React's synthetic
27
+ // handler types along).
28
+ type DOMAttributes = Record<string, any>;
29
+
30
+ export interface OptionAria extends SelectableItemStates {
31
+ /** Props for the option element. */
32
+ optionProps: DOMAttributes;
33
+
34
+ /** Props for the main text element inside the option. */
35
+ labelProps: DOMAttributes;
36
+
37
+ /** Props for the description text element inside the option, if any. */
38
+ descriptionProps: DOMAttributes;
39
+
40
+ /** Whether the option is currently focused. */
41
+ isFocused: boolean;
42
+
43
+ /** Whether the option is keyboard focused. */
44
+ isFocusVisible: boolean;
45
+ }
46
+
47
+ export interface AriaOptionProps {
48
+ /**
49
+ * Whether the option is disabled.
50
+ *
51
+ * @deprecated
52
+ */
53
+ isDisabled?: boolean;
54
+
55
+ /**
56
+ * Whether the option is selected.
57
+ *
58
+ * @deprecated
59
+ */
60
+ isSelected?: boolean;
61
+
62
+ /** A screen reader only label for the option. */
63
+ 'aria-label'?: string;
64
+
65
+ /** The unique key for the option. */
66
+ key: Key;
67
+
68
+ /**
69
+ * Whether selection should occur on press up instead of press down.
70
+ *
71
+ * @deprecated
72
+ */
73
+ shouldSelectOnPressUp?: boolean;
74
+
75
+ /**
76
+ * Whether the option should be focused when the user hovers over it.
77
+ *
78
+ * @deprecated
79
+ */
80
+ shouldFocusOnHover?: boolean;
81
+
82
+ /**
83
+ * Whether the option is contained in a virtual scrolling listbox.
84
+ *
85
+ * @deprecated
86
+ */
87
+ isVirtualized?: boolean;
88
+
89
+ /**
90
+ * Whether the option should use virtual focus instead of being focused directly.
91
+ *
92
+ * @deprecated
93
+ */
94
+ shouldUseVirtualFocus?: boolean;
95
+ }
96
+
97
+ /**
98
+ * Provides the behavior and accessibility implementation for an option in a listbox.
99
+ * See `useListBox` for more details about listboxes.
100
+ *
101
+ * @param props - Props for the option.
102
+ * @param state - State for the listbox, as returned by `useListState`.
103
+ */
104
+ export function useOption<T>(
105
+ props: AriaOptionProps,
106
+ state: ListState<T>,
107
+ ref: RefObject<FocusableElement | null>,
108
+ ): OptionAria;
109
+ // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
110
+ export function useOption<T>(
111
+ props: AriaOptionProps,
112
+ state: ListState<T>,
113
+ ref: RefObject<FocusableElement | null>,
114
+ slot: symbol | undefined,
115
+ ): OptionAria;
116
+ export function useOption(...args: any[]): OptionAria {
117
+ const [user, slotArg] = splitSlot(args);
118
+ const slot = slotArg ?? S('useOption');
119
+ const props = user[0] as AriaOptionProps;
120
+ const state = user[1] as ListState<unknown>;
121
+ const ref = user[2] as RefObject<FocusableElement | null>;
122
+
123
+ let { key } = props;
124
+
125
+ let data = listData.get(state);
126
+
127
+ let isDisabled = props.isDisabled ?? state.selectionManager.isDisabled(key);
128
+ let isSelected = props.isSelected ?? state.selectionManager.isSelected(key);
129
+ let shouldSelectOnPressUp = props.shouldSelectOnPressUp ?? data?.shouldSelectOnPressUp;
130
+ let shouldFocusOnHover = props.shouldFocusOnHover ?? data?.shouldFocusOnHover;
131
+ let shouldUseVirtualFocus = props.shouldUseVirtualFocus ?? data?.shouldUseVirtualFocus;
132
+ let isVirtualized = props.isVirtualized ?? data?.isVirtualized;
133
+
134
+ let labelId = useSlotId(undefined, subSlot(slot, 'labelId'));
135
+ let descriptionId = useSlotId(undefined, subSlot(slot, 'descriptionId'));
136
+
137
+ let optionProps: DOMAttributes = {
138
+ role: 'option',
139
+ 'aria-disabled': isDisabled || undefined,
140
+ 'aria-selected': state.selectionManager.selectionMode !== 'none' ? isSelected : undefined,
141
+ 'aria-label': props['aria-label'],
142
+ 'aria-labelledby': labelId,
143
+ 'aria-describedby': descriptionId,
144
+ };
145
+
146
+ let item = state.collection.getItem(key);
147
+ if (isVirtualized) {
148
+ let index = Number(item?.index);
149
+ optionProps['aria-posinset'] = Number.isNaN(index) ? undefined : index + 1;
150
+ optionProps['aria-setsize'] = getItemCount(state.collection);
151
+ }
152
+
153
+ let onAction = data?.onAction ? () => data?.onAction?.(key) : undefined;
154
+ let id = getItemId(state, key);
155
+ let { itemProps, isPressed, isFocused, hasAction, allowsSelection } = useSelectableItem(
156
+ {
157
+ selectionManager: state.selectionManager,
158
+ key,
159
+ ref,
160
+ shouldSelectOnPressUp,
161
+ allowsDifferentPressOrigin: shouldSelectOnPressUp && shouldFocusOnHover,
162
+ isVirtualized,
163
+ shouldUseVirtualFocus,
164
+ isDisabled,
165
+ onAction:
166
+ onAction || item?.props?.onAction ? chain(item?.props?.onAction, onAction) : undefined,
167
+ linkBehavior: data?.linkBehavior,
168
+ // @ts-ignore
169
+ UNSTABLE_itemBehavior: data?.['UNSTABLE_itemBehavior'],
170
+ id,
171
+ },
172
+ subSlot(slot, 'item'),
173
+ );
174
+
175
+ let { hoverProps } = useHover(
176
+ {
177
+ isDisabled: isDisabled || !shouldFocusOnHover,
178
+ onHoverStart() {
179
+ if (!isFocusVisible()) {
180
+ state.selectionManager.setFocused(true);
181
+ state.selectionManager.setFocusedKey(key);
182
+ }
183
+ },
184
+ },
185
+ subSlot(slot, 'hover'),
186
+ );
187
+
188
+ let domProps = filterDOMProps(item?.props);
189
+ delete domProps.id;
190
+ let linkProps = useLinkProps(item?.props);
191
+
192
+ return {
193
+ optionProps: {
194
+ ...optionProps,
195
+ ...mergeProps(domProps, itemProps, hoverProps, linkProps),
196
+ id,
197
+ },
198
+ labelProps: {
199
+ id: labelId,
200
+ },
201
+ descriptionProps: {
202
+ id: descriptionId,
203
+ },
204
+ isFocused,
205
+ isFocusVisible: isFocused && state.selectionManager.isFocused && isFocusVisible(),
206
+ isSelected,
207
+ isDisabled,
208
+ isPressed,
209
+ allowsSelection,
210
+ hasAction,
211
+ };
212
+ }
@@ -0,0 +1,38 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/listbox/utils.ts).
2
+ // octane adaptations: `ListState` type from the ported stately list state (upstream:
3
+ // 'react-stately/useListState').
4
+ import type { Key } from '@react-types/shared';
5
+ import type { ListState } from '../stately/list/useListState';
6
+
7
+ interface ListData {
8
+ id?: string;
9
+ shouldSelectOnPressUp?: boolean;
10
+ shouldFocusOnHover?: boolean;
11
+ shouldUseVirtualFocus?: boolean;
12
+ isVirtualized?: boolean;
13
+ onAction?: (key: Key) => void;
14
+ linkBehavior?: 'action' | 'selection' | 'override';
15
+ }
16
+
17
+ export const listData: WeakMap<ListState<unknown>, ListData> = new WeakMap<
18
+ ListState<unknown>,
19
+ ListData
20
+ >();
21
+
22
+ function normalizeKey(key: Key): string {
23
+ if (typeof key === 'string') {
24
+ return key.replace(/\s*/g, '');
25
+ }
26
+
27
+ return '' + key;
28
+ }
29
+
30
+ export function getItemId<T>(state: ListState<T>, itemKey: Key): string {
31
+ let data = listData.get(state);
32
+
33
+ if (!data) {
34
+ throw new Error('Unknown list');
35
+ }
36
+
37
+ return `${data.id}-option-${normalizeKey(itemKey)}`;
38
+ }
@@ -0,0 +1,172 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/live-announcer/LiveAnnouncer.tsx).
2
+ // octane adaptations:
3
+ // - This is a plain-DOM utility upstream too (no React), so the port is verbatim apart
4
+ // from the test-environment probe: upstream checks React's IS_REACT_ACT_ENVIRONMENT /
5
+ // the jest global to skip the Safari announce delay under test; octane's suite runs
6
+ // under vitest, so the probe also treats a defined `process.env.VITEST` as a test
7
+ // environment. The 100ms first-announce delay for real browsers is preserved.
8
+ // - `.tsx` → `.ts` (there was never any JSX in the file).
9
+
10
+ type Assertiveness = 'assertive' | 'polite';
11
+
12
+ /* Inspired by https://github.com/AlmeroSteyn/react-aria-live */
13
+ const LIVEREGION_TIMEOUT_DELAY = 7000;
14
+
15
+ let liveAnnouncer: LiveAnnouncer | null = null;
16
+
17
+ type Message = string | { 'aria-labelledby': string };
18
+
19
+ function isTestEnvironment(): boolean {
20
+ const g = globalThis as any;
21
+ if (typeof g.IS_REACT_ACT_ENVIRONMENT === 'boolean') {
22
+ return g.IS_REACT_ACT_ENVIRONMENT;
23
+ }
24
+ return typeof g.jest !== 'undefined' || g.process?.env?.VITEST !== undefined;
25
+ }
26
+
27
+ /**
28
+ * Announces the message using screen reader technology.
29
+ */
30
+ export function announce(
31
+ message: Message,
32
+ assertiveness: Assertiveness = 'assertive',
33
+ timeout: number = LIVEREGION_TIMEOUT_DELAY,
34
+ ): void {
35
+ if (!liveAnnouncer) {
36
+ liveAnnouncer = new LiveAnnouncer();
37
+ // wait for the live announcer regions to be added to the dom, then announce
38
+ // otherwise Safari won't announce the message if it's added too quickly
39
+ // found most times less than 100ms were not consistent when announcing with Safari
40
+
41
+ // if we're in a test environment, announce without waiting
42
+ if (!isTestEnvironment()) {
43
+ setTimeout(() => {
44
+ if (liveAnnouncer?.isAttached()) {
45
+ liveAnnouncer?.announce(message, assertiveness, timeout);
46
+ }
47
+ }, 100);
48
+ } else {
49
+ liveAnnouncer.announce(message, assertiveness, timeout);
50
+ }
51
+ } else {
52
+ liveAnnouncer.announce(message, assertiveness, timeout);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Stops all queued announcements.
58
+ */
59
+ export function clearAnnouncer(assertiveness: Assertiveness): void {
60
+ if (liveAnnouncer) {
61
+ liveAnnouncer.clear(assertiveness);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Removes the announcer from the DOM.
67
+ */
68
+ export function destroyAnnouncer(): void {
69
+ if (liveAnnouncer) {
70
+ liveAnnouncer.destroy();
71
+ liveAnnouncer = null;
72
+ }
73
+ }
74
+
75
+ // LiveAnnouncer is implemented using vanilla DOM, not the framework. Upstream keeps it
76
+ // framework-free so the global announce() API works without a root or portal; the same
77
+ // reasoning applies verbatim in octane.
78
+ class LiveAnnouncer {
79
+ node: HTMLElement | null = null;
80
+ assertiveLog: HTMLElement | null = null;
81
+ politeLog: HTMLElement | null = null;
82
+
83
+ constructor() {
84
+ if (typeof document !== 'undefined') {
85
+ this.node = document.createElement('div');
86
+ this.node.dataset.liveAnnouncer = 'true';
87
+ // copied from VisuallyHidden
88
+ Object.assign(this.node.style, {
89
+ border: 0,
90
+ clip: 'rect(0 0 0 0)',
91
+ clipPath: 'inset(50%)',
92
+ height: '1px',
93
+ margin: '-1px',
94
+ overflow: 'hidden',
95
+ padding: 0,
96
+ position: 'absolute',
97
+ width: '1px',
98
+ whiteSpace: 'nowrap',
99
+ });
100
+
101
+ this.assertiveLog = this.createLog('assertive');
102
+ this.node.appendChild(this.assertiveLog);
103
+
104
+ this.politeLog = this.createLog('polite');
105
+ this.node.appendChild(this.politeLog);
106
+
107
+ document.body.prepend(this.node);
108
+ }
109
+ }
110
+
111
+ isAttached() {
112
+ return this.node?.isConnected;
113
+ }
114
+
115
+ createLog(ariaLive: string) {
116
+ let node = document.createElement('div');
117
+ node.setAttribute('role', 'log');
118
+ node.setAttribute('aria-live', ariaLive);
119
+ node.setAttribute('aria-relevant', 'additions');
120
+ return node;
121
+ }
122
+
123
+ destroy() {
124
+ if (!this.node) {
125
+ return;
126
+ }
127
+
128
+ document.body.removeChild(this.node);
129
+ this.node = null;
130
+ }
131
+
132
+ announce(message: Message, assertiveness = 'assertive', timeout = LIVEREGION_TIMEOUT_DELAY) {
133
+ if (!this.node) {
134
+ return;
135
+ }
136
+
137
+ let node = document.createElement('div');
138
+ if (typeof message === 'object') {
139
+ // To read an aria-labelledby, the element must have an appropriate role, such as img.
140
+ node.setAttribute('role', 'img');
141
+ node.setAttribute('aria-labelledby', message['aria-labelledby']);
142
+ } else {
143
+ node.textContent = message;
144
+ }
145
+
146
+ if (assertiveness === 'assertive') {
147
+ this.assertiveLog?.appendChild(node);
148
+ } else {
149
+ this.politeLog?.appendChild(node);
150
+ }
151
+
152
+ if (message !== '') {
153
+ setTimeout(() => {
154
+ node.remove();
155
+ }, timeout);
156
+ }
157
+ }
158
+
159
+ clear(assertiveness: Assertiveness) {
160
+ if (!this.node) {
161
+ return;
162
+ }
163
+
164
+ if ((!assertiveness || assertiveness === 'assertive') && this.assertiveLog) {
165
+ this.assertiveLog.innerHTML = '';
166
+ }
167
+
168
+ if ((!assertiveness || assertiveness === 'polite') && this.politeLog) {
169
+ this.politeLog.innerHTML = '';
170
+ }
171
+ }
172
+ }
@@ -0,0 +1,139 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/menu/useMenu.ts).
2
+ // octane adaptations:
3
+ // - `KeyboardEvents` is the ported NATIVE-event version (from useKeyboard); the menu-level
4
+ // onKeyDown wrapper receives the native KeyboardEvent; `DOMAttributes` is a local
5
+ // structural prop-bag alias (upstream's is typed over React's synthetic handlers).
6
+ // - `TreeState` type from the ported stately tree state.
7
+ // - The dev-only missing-label console.warn is not ported (repo policy, per useLabel).
8
+ // - Public-hook slot threading (splitSlot/subSlot) per the binding convention.
9
+ import type {
10
+ AriaLabelingProps,
11
+ CollectionBase,
12
+ DOMProps,
13
+ FocusStrategy,
14
+ Key,
15
+ KeyboardDelegate,
16
+ MultipleSelection,
17
+ RefObject,
18
+ } from '@react-types/shared';
19
+ import { filterDOMProps } from '../utils/filterDOMProps';
20
+ import type { KeyboardEvents } from '../interactions/useKeyboard';
21
+ import { menuData } from './utils';
22
+ import { mergeProps } from '../utils/mergeProps';
23
+ import type { TreeState } from '../stately/tree/useTreeState';
24
+ import { useSelectableList } from '../selection/useSelectableList';
25
+
26
+ import { S, splitSlot, subSlot } from '../internal';
27
+
28
+ // octane adaptation: minimal structural DOMAttributes (upstream's drags React's synthetic
29
+ // handler types along).
30
+ type DOMAttributes = Record<string, any>;
31
+
32
+ export interface MenuProps<T> extends CollectionBase<T>, MultipleSelection {
33
+ /** Where the focus should be set. */
34
+ autoFocus?: boolean | FocusStrategy;
35
+ /** Whether keyboard navigation is circular. */
36
+ shouldFocusWrap?: boolean;
37
+ /** Handler that is called when an item is selected. */
38
+ onAction?: (key: Key, value: T) => void;
39
+ /** Handler that is called when the menu should close after selecting an item. */
40
+ onClose?: () => void;
41
+ }
42
+
43
+ export interface AriaMenuProps<T> extends MenuProps<T>, DOMProps, AriaLabelingProps {
44
+ /**
45
+ * Whether pressing the escape key should clear selection in the menu or not.
46
+ *
47
+ * Most experiences should not modify this option as it eliminates a keyboard user's ability to
48
+ * easily clear selection. Only use if the escape key is being handled externally or should not
49
+ * trigger selection clearing contextually.
50
+ *
51
+ * @default 'clearSelection'
52
+ */
53
+ escapeKeyBehavior?: 'clearSelection' | 'none';
54
+ }
55
+
56
+ export interface MenuAria {
57
+ /** Props for the menu element. */
58
+ menuProps: DOMAttributes;
59
+ }
60
+
61
+ export interface AriaMenuOptions<T> extends Omit<AriaMenuProps<T>, 'children'>, KeyboardEvents {
62
+ /** Whether the menu uses virtual scrolling. */
63
+ isVirtualized?: boolean;
64
+ /**
65
+ * An optional keyboard delegate implementation for type to select,
66
+ * to override the default.
67
+ */
68
+ keyboardDelegate?: KeyboardDelegate;
69
+ /**
70
+ * Whether the menu items should use virtual focus instead of being focused directly.
71
+ */
72
+ shouldUseVirtualFocus?: boolean;
73
+ }
74
+
75
+ /**
76
+ * Provides the behavior and accessibility implementation for a menu component.
77
+ * A menu displays a list of actions or options that a user can choose.
78
+ *
79
+ * @param props - Props for the menu.
80
+ * @param state - State for the menu, as returned by `useListState`.
81
+ */
82
+ export function useMenu<T>(
83
+ props: AriaMenuOptions<T>,
84
+ state: TreeState<T>,
85
+ ref: RefObject<HTMLElement | null>,
86
+ ): MenuAria;
87
+ // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
88
+ export function useMenu<T>(
89
+ props: AriaMenuOptions<T>,
90
+ state: TreeState<T>,
91
+ ref: RefObject<HTMLElement | null>,
92
+ slot: symbol | undefined,
93
+ ): MenuAria;
94
+ export function useMenu(...args: any[]): MenuAria {
95
+ const [user, slotArg] = splitSlot(args);
96
+ const slot = slotArg ?? S('useMenu');
97
+ const props = user[0] as AriaMenuOptions<unknown>;
98
+ const state = user[1] as TreeState<unknown>;
99
+ const ref = user[2] as RefObject<HTMLElement | null>;
100
+
101
+ let { shouldFocusWrap = true, onKeyDown, onKeyUp, ...otherProps } = props;
102
+
103
+ let domProps = filterDOMProps(props, { labelable: true });
104
+ let { listProps } = useSelectableList(
105
+ {
106
+ ...otherProps,
107
+ ref,
108
+ selectionManager: state.selectionManager,
109
+ collection: state.collection,
110
+ disabledKeys: state.disabledKeys,
111
+ shouldFocusWrap,
112
+ linkBehavior: 'override',
113
+ },
114
+ subSlot(slot, 'list'),
115
+ );
116
+
117
+ menuData.set(state, {
118
+ onClose: props.onClose,
119
+ onAction: props.onAction,
120
+ shouldUseVirtualFocus: props.shouldUseVirtualFocus,
121
+ });
122
+
123
+ return {
124
+ menuProps: mergeProps(
125
+ domProps,
126
+ { onKeyDown, onKeyUp },
127
+ {
128
+ role: 'menu',
129
+ ...listProps,
130
+ onKeyDown: (e: KeyboardEvent) => {
131
+ // don't clear the menu selected keys if the user is presses escape since escape closes the menu
132
+ if (e.key !== 'Escape' || props.shouldUseVirtualFocus) {
133
+ listProps.onKeyDown?.(e);
134
+ }
135
+ },
136
+ },
137
+ ),
138
+ };
139
+ }