@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,147 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/dialog/useDialog.ts).
2
+ // octane adaptations: `DOMAttributes` is a local structural prop-bag alias (upstream's is typed
3
+ // over React's synthetic handlers); the onBlur handler receives a NATIVE DOM FocusEvent (no
4
+ // synthetic layer); `useEffect`/`useRef` import from 'octane'; the dep-less dev-warning
5
+ // `useEffect` gets an explicit `null` dep arg (the explicit `[ref]` dep array is kept verbatim);
6
+ // public-hook slot threading (splitSlot/subSlot) per the binding convention — sibling ported
7
+ // hooks (useSlotId, useOverlayFocusContain) receive a derived sub-slot as their trailing arg.
8
+ import type { AriaLabelingProps, DOMProps, FocusableElement, RefObject } from '@react-types/shared';
9
+ import { filterDOMProps } from '../utils/filterDOMProps';
10
+ import { focusSafely } from '../interactions/focusSafely';
11
+ import { getActiveElement, isFocusWithin } from '../utils/shadowdom/DOMFunctions';
12
+ import { useEffect, useRef } from 'octane';
13
+ import { useOverlayFocusContain } from '../overlays/Overlay';
14
+ import { useSlotId } from '../utils/useId';
15
+
16
+ import { S, splitSlot, subSlot } from '../internal';
17
+
18
+ // octane adaptation: minimal structural DOMAttributes (upstream's drags React's synthetic
19
+ // handler types along).
20
+ type DOMAttributes = Record<string, any>;
21
+
22
+ export interface AriaDialogProps extends DOMProps, AriaLabelingProps {
23
+ /**
24
+ * The accessibility role for the dialog.
25
+ *
26
+ * @default 'dialog'
27
+ */
28
+ role?: 'dialog' | 'alertdialog';
29
+ }
30
+
31
+ export interface DialogAria {
32
+ /** Props for the dialog container element. */
33
+ dialogProps: DOMAttributes;
34
+
35
+ /** Props for the dialog title element. */
36
+ titleProps: DOMAttributes;
37
+ }
38
+
39
+ /**
40
+ * Provides the behavior and accessibility implementation for a dialog component.
41
+ * A dialog is an overlay shown above other content in an application.
42
+ */
43
+ export function useDialog(
44
+ props: AriaDialogProps,
45
+ ref: RefObject<FocusableElement | null>,
46
+ ): DialogAria;
47
+ // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
48
+ export function useDialog(
49
+ props: AriaDialogProps,
50
+ ref: RefObject<FocusableElement | null>,
51
+ slot: symbol | undefined,
52
+ ): DialogAria;
53
+ export function useDialog(...args: any[]): DialogAria {
54
+ const [user, slotArg] = splitSlot(args);
55
+ const slot = slotArg ?? S('useDialog');
56
+ const props = user[0] as AriaDialogProps;
57
+ const ref = user[1] as RefObject<FocusableElement | null>;
58
+
59
+ let { role = 'dialog' } = props;
60
+ let titleId: string | undefined = useSlotId(undefined, subSlot(slot, 'title'));
61
+ titleId = props['aria-label'] ? undefined : titleId;
62
+
63
+ let isRefocusing = useRef(false, subSlot(slot, 'refocusing'));
64
+
65
+ // Focus the dialog itself on mount, unless a child element is already focused.
66
+ useEffect(
67
+ () => {
68
+ if (ref.current && !isFocusWithin(ref.current)) {
69
+ focusSafely(ref.current);
70
+
71
+ // Safari on iOS does not move the VoiceOver cursor to the dialog
72
+ // or announce that it has opened until it has rendered. A workaround
73
+ // is to wait for half a second, then blur and re-focus the dialog.
74
+ let timeout = setTimeout(() => {
75
+ // Check that the dialog is still focused, or focused was lost to the body.
76
+ if (getActiveElement() === ref.current || getActiveElement() === document.body) {
77
+ isRefocusing.current = true;
78
+ if (ref.current) {
79
+ ref.current.blur();
80
+ focusSafely(ref.current);
81
+ }
82
+ isRefocusing.current = false;
83
+ }
84
+ }, 500);
85
+
86
+ return () => {
87
+ clearTimeout(timeout);
88
+ };
89
+ }
90
+ },
91
+ [ref],
92
+ subSlot(slot, 'autofocus'),
93
+ );
94
+
95
+ useOverlayFocusContain(subSlot(slot, 'focusContain'));
96
+
97
+ // Warn in dev mode if the dialog has no accessible title.
98
+ // This catches a common mistake where useDialog and useOverlayTriggerState
99
+ // are used in the same component, causing the title element to not be
100
+ // in the DOM when useSlotId queries for it.
101
+ // Check the DOM element directly since aria-labelledby may be added by
102
+ // wrapper components (e.g. RAC Dialog uses trigger ID as a fallback).
103
+ let hasWarned = useRef(false, subSlot(slot, 'warned'));
104
+ useEffect(
105
+ () => {
106
+ if (process.env.NODE_ENV !== 'production' && !hasWarned.current && ref.current) {
107
+ let el = ref.current;
108
+ let hasAriaLabel = el.hasAttribute('aria-label');
109
+ let hasAriaLabelledby = el.hasAttribute('aria-labelledby');
110
+ if (!hasAriaLabel && !hasAriaLabelledby) {
111
+ console.warn(
112
+ 'A dialog must have a title for accessibility. ' +
113
+ 'Either provide an aria-label or aria-labelledby prop, or render a heading element inside the dialog.',
114
+ );
115
+ hasWarned.current = true;
116
+ }
117
+ }
118
+ },
119
+ null,
120
+ subSlot(slot, 'warn'),
121
+ );
122
+
123
+ // We do not use aria-modal due to a Safari bug which forces the first focusable element to be focused
124
+ // on mount when inside an iframe, no matter which element we programmatically focus.
125
+ // See https://bugs.webkit.org/show_bug.cgi?id=211934.
126
+ // useModal sets aria-hidden on all elements outside the dialog, so the dialog will behave as a modal
127
+ // even without aria-modal on the dialog itself.
128
+ return {
129
+ dialogProps: {
130
+ ...filterDOMProps(props, { labelable: true }),
131
+ role,
132
+ tabIndex: -1,
133
+ 'aria-labelledby': props['aria-labelledby'] || titleId,
134
+ // Prevent blur events from reaching useOverlay, which may cause
135
+ // popovers to close. Since focus is contained within the dialog,
136
+ // we don't want this to occur due to the above useEffect.
137
+ onBlur: (e: any) => {
138
+ if (isRefocusing.current) {
139
+ e.stopPropagation();
140
+ }
141
+ },
142
+ },
143
+ titleProps: {
144
+ id: titleId,
145
+ },
146
+ };
147
+ }
@@ -0,0 +1,180 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/disclosure/useDisclosure.ts).
2
+ // octane adaptations: `flushSync` from 'octane'; React's HTMLAttributes → structural
3
+ // prop bag; public-hook slot threading.
4
+ import type { PressEvent, RefObject } from '@react-types/shared';
5
+ import { flushSync, useCallback, useEffect, useRef } from 'octane';
6
+
7
+ import { S, splitSlot, subSlot } from '../internal';
8
+ import type { AriaButtonProps } from '../button/useButton';
9
+ import type { DisclosureState } from '../stately/disclosure/useDisclosureState';
10
+ import { useEvent } from '../utils/useEvent';
11
+ import { useId } from '../utils/useId';
12
+ import { useIsSSR } from '../ssr/SSRProvider';
13
+ import { useLayoutEffect } from '../utils/useLayoutEffect';
14
+
15
+ export interface AriaDisclosureProps {
16
+ /** Whether the disclosure is disabled. */
17
+ isDisabled?: boolean;
18
+ /** Handler that is called when the disclosure's expanded state changes. */
19
+ onExpandedChange?: (isExpanded: boolean) => void;
20
+ /** Whether the disclosure is expanded (controlled). */
21
+ isExpanded?: boolean;
22
+ /** Whether the disclosure is expanded by default (uncontrolled). */
23
+ defaultExpanded?: boolean;
24
+ }
25
+
26
+ export interface DisclosureAria {
27
+ /** Props for the disclosure button. */
28
+ buttonProps: AriaButtonProps;
29
+ /** Props for the disclosure panel. */
30
+ panelProps: Record<string, any>;
31
+ }
32
+
33
+ /**
34
+ * Provides the behavior and accessibility implementation for a disclosure component.
35
+ */
36
+ export function useDisclosure(
37
+ props: AriaDisclosureProps,
38
+ state: DisclosureState,
39
+ ref: RefObject<HTMLElement | null>,
40
+ ): DisclosureAria;
41
+ // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
42
+ export function useDisclosure(
43
+ props: AriaDisclosureProps,
44
+ state: DisclosureState,
45
+ ref: RefObject<HTMLElement | null>,
46
+ slot: symbol | undefined,
47
+ ): DisclosureAria;
48
+ export function useDisclosure(...args: any[]): DisclosureAria {
49
+ const [user, slotArg] = splitSlot(args);
50
+ const slot = slotArg ?? S('useDisclosure');
51
+ const props = user[0] as AriaDisclosureProps;
52
+ const state = user[1] as DisclosureState;
53
+ const ref = user[2] as RefObject<HTMLElement | null>;
54
+
55
+ let { isDisabled } = props;
56
+ let triggerId = useId(subSlot(slot, 'triggerId'));
57
+ let panelId = useId(subSlot(slot, 'panelId'));
58
+ let isSSR = useIsSSR(subSlot(slot, 'ssr'));
59
+
60
+ let raf = useRef<number | null>(null, subSlot(slot, 'raf'));
61
+
62
+ let handleBeforeMatch = useCallback(
63
+ () => {
64
+ // Wait a frame to revert browser's removal of hidden attribute
65
+ raf.current = requestAnimationFrame(() => {
66
+ if (ref.current) {
67
+ ref.current.setAttribute('hidden', 'until-found');
68
+ }
69
+ });
70
+ // Force sync state update
71
+ flushSync(() => {
72
+ state.toggle();
73
+ });
74
+ },
75
+ [ref, state],
76
+ subSlot(slot, 'beforeMatch'),
77
+ );
78
+
79
+ useEvent(ref, 'beforematch', handleBeforeMatch, subSlot(slot, 'beforeMatchEvent'));
80
+
81
+ let isExpandedRef = useRef<boolean | null>(null, subSlot(slot, 'wasExpanded'));
82
+ useLayoutEffect(
83
+ () => {
84
+ // Cancel any pending RAF to prevent stale updates
85
+ if (raf.current) {
86
+ cancelAnimationFrame(raf.current);
87
+ }
88
+ if (ref.current && !isSSR) {
89
+ let panel = ref.current;
90
+
91
+ if (isExpandedRef.current == null || typeof panel.getAnimations !== 'function') {
92
+ // On initial render (and in tests), set attributes without animation.
93
+ if (state.isExpanded) {
94
+ panel.removeAttribute('hidden');
95
+ panel.style.setProperty('--disclosure-panel-width', 'auto');
96
+ panel.style.setProperty('--disclosure-panel-height', 'auto');
97
+ } else {
98
+ panel.setAttribute('hidden', 'until-found');
99
+ panel.style.setProperty('--disclosure-panel-width', '0px');
100
+ panel.style.setProperty('--disclosure-panel-height', '0px');
101
+ }
102
+ } else if (state.isExpanded !== isExpandedRef.current) {
103
+ if (state.isExpanded) {
104
+ panel.removeAttribute('hidden');
105
+
106
+ // Set the width and height as pixels so they can be animated.
107
+ panel.style.setProperty('--disclosure-panel-width', panel.scrollWidth + 'px');
108
+ panel.style.setProperty('--disclosure-panel-height', panel.scrollHeight + 'px');
109
+
110
+ Promise.all(panel.getAnimations().map((a) => a.finished))
111
+ .then(() => {
112
+ // After the animations complete, switch back to auto so the content can resize.
113
+ panel.style.setProperty('--disclosure-panel-width', 'auto');
114
+ panel.style.setProperty('--disclosure-panel-height', 'auto');
115
+ })
116
+ .catch(() => {});
117
+ } else {
118
+ panel.style.setProperty('--disclosure-panel-width', panel.scrollWidth + 'px');
119
+ panel.style.setProperty('--disclosure-panel-height', panel.scrollHeight + 'px');
120
+
121
+ // Force style re-calculation to trigger animations.
122
+ window.getComputedStyle(panel).height;
123
+
124
+ // Animate to zero size.
125
+ panel.style.setProperty('--disclosure-panel-width', '0px');
126
+ panel.style.setProperty('--disclosure-panel-height', '0px');
127
+
128
+ // Wait for animations to apply the hidden attribute.
129
+ Promise.all(panel.getAnimations().map((a) => a.finished))
130
+ .then(() => panel.setAttribute('hidden', 'until-found'))
131
+ .catch(() => {});
132
+ }
133
+ }
134
+
135
+ isExpandedRef.current = state.isExpanded;
136
+ }
137
+ },
138
+ [isDisabled, ref, state.isExpanded, isSSR],
139
+ subSlot(slot, 'panelSync'),
140
+ );
141
+
142
+ useEffect(
143
+ () => {
144
+ return () => {
145
+ if (raf.current) {
146
+ cancelAnimationFrame(raf.current);
147
+ }
148
+ };
149
+ },
150
+ [],
151
+ subSlot(slot, 'rafCleanup'),
152
+ );
153
+
154
+ return {
155
+ buttonProps: {
156
+ id: triggerId,
157
+ 'aria-expanded': state.isExpanded,
158
+ 'aria-controls': panelId,
159
+ onPress: (e: PressEvent) => {
160
+ if (!isDisabled && e.pointerType !== 'keyboard') {
161
+ state.toggle();
162
+ }
163
+ },
164
+ isDisabled,
165
+ onPressStart(e: PressEvent) {
166
+ if (e.pointerType === 'keyboard' && !isDisabled) {
167
+ state.toggle();
168
+ }
169
+ },
170
+ },
171
+ panelProps: {
172
+ id: panelId,
173
+ // This can be overridden at the panel element level.
174
+ role: 'group',
175
+ 'aria-labelledby': triggerId,
176
+ 'aria-hidden': !state.isExpanded,
177
+ hidden: isSSR ? !state.isExpanded : undefined,
178
+ },
179
+ };
180
+ }
@@ -0,0 +1,69 @@
1
+ // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/focus/FocusRing.tsx).
2
+ // octane adaptations:
3
+ // - Built with octane's `Children`/`cloneElement` over element DESCRIPTORS (prop-position
4
+ // JSX / createElement results); a single-element array unwraps before `Children.only`,
5
+ // per the binding's children convention (see interactions/useFocusable.ts Focusable).
6
+ // - `React.ReactElement` types → `any` (octane descriptors); component slot via S().
7
+ // - `clsx` stays (upstream dependency); the merged `className` composes through
8
+ // `mergeProps` exactly like upstream.
9
+
10
+ import clsx from 'clsx';
11
+ import { Children, cloneElement } from 'octane';
12
+
13
+ import { S, subSlot } from '../internal';
14
+ import { mergeProps } from '../utils/mergeProps';
15
+ import { useFocusRing } from './useFocusRing';
16
+
17
+ export interface FocusRingProps {
18
+ /** Child element to apply CSS classes to. */
19
+ children: any;
20
+ /** CSS class to apply when the element is focused. */
21
+ focusClass?: string;
22
+ /** CSS class to apply when the element has keyboard focus. */
23
+ focusRingClass?: string;
24
+ /**
25
+ * Whether to show the focus ring when something
26
+ * inside the container element has focus (true), or
27
+ * only if the container itself has focus (false).
28
+ *
29
+ * @default false
30
+ */
31
+ within?: boolean;
32
+ /** Whether the element is a text input. */
33
+ isTextInput?: boolean;
34
+ /** Whether the element will be auto focused. */
35
+ autoFocus?: boolean;
36
+ }
37
+
38
+ /**
39
+ * A utility component that applies a CSS class when an element has keyboard focus.
40
+ * Focus rings are visible only when the user is interacting with a keyboard,
41
+ * not with a mouse, touch, or other input methods.
42
+ */
43
+ export function FocusRing(props: FocusRingProps): any {
44
+ const slot = S('FocusRing');
45
+ let { children, focusClass, focusRingClass } = props;
46
+ let { isFocused, isFocusVisible, focusProps } = useFocusRing(props, subSlot(slot, 'ring'));
47
+
48
+ // octane adaptation: children arrive as descriptors; a single-element array unwraps
49
+ // (octane convention — see interactions/useFocusable.ts Focusable).
50
+ let target: any = children;
51
+ if (Array.isArray(children)) {
52
+ const arr = Children.toArray(children);
53
+ if (arr.length === 1) {
54
+ target = arr[0];
55
+ }
56
+ }
57
+ let child: any = Children.only(target);
58
+
59
+ return cloneElement(
60
+ child,
61
+ mergeProps(child.props as any, {
62
+ ...focusProps,
63
+ className: clsx({
64
+ [focusClass || '']: isFocused,
65
+ [focusRingClass || '']: isFocusVisible,
66
+ }),
67
+ }),
68
+ );
69
+ }