@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.
- package/package.json +6 -3
- package/src/breadcrumbs/useBreadcrumbItem.ts +95 -0
- package/src/breadcrumbs/useBreadcrumbs.ts +51 -0
- package/src/button/useButton.ts +273 -0
- package/src/button/useToggleButton.ts +131 -0
- package/src/button/useToggleButtonGroup.ts +131 -0
- package/src/checkbox/useCheckbox.ts +114 -0
- package/src/checkbox/useCheckboxGroup.ts +107 -0
- package/src/checkbox/useCheckboxGroupItem.ts +132 -0
- package/src/checkbox/utils.ts +15 -0
- package/src/combobox/useComboBox.ts +602 -0
- package/src/dialog/useDialog.ts +147 -0
- package/src/disclosure/useDisclosure.ts +180 -0
- package/src/focus/FocusRing.ts +69 -0
- package/src/focus/FocusScope.ts +1205 -0
- package/src/focus/useFocusRing.ts +125 -0
- package/src/focus/useHasTabbableChild.ts +82 -0
- package/src/focus/virtualFocus.ts +38 -0
- package/src/form/useFormValidation.ts +205 -0
- package/src/grid/useGridSelectionAnnouncement.ts +177 -0
- package/src/grid/useGridSelectionCheckbox.ts +86 -0
- package/src/grid/useHighlightSelectionDescription.ts +81 -0
- package/src/gridlist/useGridList.ts +236 -0
- package/src/gridlist/useGridListItem.ts +512 -0
- package/src/gridlist/useGridListSection.ts +78 -0
- package/src/gridlist/useGridListSelectionCheckbox.ts +47 -0
- package/src/gridlist/utils.ts +36 -0
- package/src/i18n/I18nProvider.ts +97 -0
- package/src/i18n/server.ts +115 -0
- package/src/i18n/useCollator.ts +42 -0
- package/src/i18n/useDateFormatter.ts +64 -0
- package/src/i18n/useDefaultLocale.ts +93 -0
- package/src/i18n/useFilter.ts +107 -0
- package/src/i18n/useListFormatter.ts +33 -0
- package/src/i18n/useLocalizedStringFormatter.ts +90 -0
- package/src/i18n/useNumberFormatter.ts +33 -0
- package/src/i18n/utils.ts +67 -0
- package/src/index.ts +268 -0
- package/src/intl/breadcrumbs/ar-AE.json +3 -0
- package/src/intl/breadcrumbs/bg-BG.json +3 -0
- package/src/intl/breadcrumbs/cs-CZ.json +3 -0
- package/src/intl/breadcrumbs/da-DK.json +3 -0
- package/src/intl/breadcrumbs/de-DE.json +3 -0
- package/src/intl/breadcrumbs/el-GR.json +3 -0
- package/src/intl/breadcrumbs/en-US.json +3 -0
- package/src/intl/breadcrumbs/es-ES.json +3 -0
- package/src/intl/breadcrumbs/et-EE.json +3 -0
- package/src/intl/breadcrumbs/fi-FI.json +3 -0
- package/src/intl/breadcrumbs/fr-FR.json +3 -0
- package/src/intl/breadcrumbs/he-IL.json +3 -0
- package/src/intl/breadcrumbs/hr-HR.json +3 -0
- package/src/intl/breadcrumbs/hu-HU.json +3 -0
- package/src/intl/breadcrumbs/index.ts +75 -0
- package/src/intl/breadcrumbs/it-IT.json +3 -0
- package/src/intl/breadcrumbs/ja-JP.json +3 -0
- package/src/intl/breadcrumbs/ko-KR.json +3 -0
- package/src/intl/breadcrumbs/lt-LT.json +3 -0
- package/src/intl/breadcrumbs/lv-LV.json +3 -0
- package/src/intl/breadcrumbs/nb-NO.json +3 -0
- package/src/intl/breadcrumbs/nl-NL.json +3 -0
- package/src/intl/breadcrumbs/pl-PL.json +3 -0
- package/src/intl/breadcrumbs/pt-BR.json +3 -0
- package/src/intl/breadcrumbs/pt-PT.json +3 -0
- package/src/intl/breadcrumbs/ro-RO.json +3 -0
- package/src/intl/breadcrumbs/ru-RU.json +3 -0
- package/src/intl/breadcrumbs/sk-SK.json +3 -0
- package/src/intl/breadcrumbs/sl-SI.json +3 -0
- package/src/intl/breadcrumbs/sr-SP.json +3 -0
- package/src/intl/breadcrumbs/sv-SE.json +3 -0
- package/src/intl/breadcrumbs/tr-TR.json +3 -0
- package/src/intl/breadcrumbs/uk-UA.json +3 -0
- package/src/intl/breadcrumbs/zh-CN.json +3 -0
- package/src/intl/breadcrumbs/zh-TW.json +3 -0
- package/src/intl/combobox/ar-AE.json +7 -0
- package/src/intl/combobox/bg-BG.json +7 -0
- package/src/intl/combobox/cs-CZ.json +7 -0
- package/src/intl/combobox/da-DK.json +7 -0
- package/src/intl/combobox/de-DE.json +7 -0
- package/src/intl/combobox/el-GR.json +7 -0
- package/src/intl/combobox/en-US.json +7 -0
- package/src/intl/combobox/es-ES.json +7 -0
- package/src/intl/combobox/et-EE.json +7 -0
- package/src/intl/combobox/fi-FI.json +7 -0
- package/src/intl/combobox/fr-FR.json +7 -0
- package/src/intl/combobox/he-IL.json +7 -0
- package/src/intl/combobox/hr-HR.json +7 -0
- package/src/intl/combobox/hu-HU.json +7 -0
- package/src/intl/combobox/index.ts +75 -0
- package/src/intl/combobox/it-IT.json +7 -0
- package/src/intl/combobox/ja-JP.json +7 -0
- package/src/intl/combobox/ko-KR.json +7 -0
- package/src/intl/combobox/lt-LT.json +7 -0
- package/src/intl/combobox/lv-LV.json +7 -0
- package/src/intl/combobox/nb-NO.json +7 -0
- package/src/intl/combobox/nl-NL.json +7 -0
- package/src/intl/combobox/pl-PL.json +7 -0
- package/src/intl/combobox/pt-BR.json +7 -0
- package/src/intl/combobox/pt-PT.json +7 -0
- package/src/intl/combobox/ro-RO.json +7 -0
- package/src/intl/combobox/ru-RU.json +7 -0
- package/src/intl/combobox/sk-SK.json +7 -0
- package/src/intl/combobox/sl-SI.json +7 -0
- package/src/intl/combobox/sr-SP.json +7 -0
- package/src/intl/combobox/sv-SE.json +7 -0
- package/src/intl/combobox/tr-TR.json +7 -0
- package/src/intl/combobox/uk-UA.json +7 -0
- package/src/intl/combobox/zh-CN.json +7 -0
- package/src/intl/combobox/zh-TW.json +7 -0
- package/src/intl/grid/ar-AE.json +8 -0
- package/src/intl/grid/bg-BG.json +8 -0
- package/src/intl/grid/cs-CZ.json +8 -0
- package/src/intl/grid/da-DK.json +8 -0
- package/src/intl/grid/de-DE.json +8 -0
- package/src/intl/grid/el-GR.json +8 -0
- package/src/intl/grid/en-US.json +8 -0
- package/src/intl/grid/es-ES.json +8 -0
- package/src/intl/grid/et-EE.json +8 -0
- package/src/intl/grid/fi-FI.json +8 -0
- package/src/intl/grid/fr-FR.json +8 -0
- package/src/intl/grid/he-IL.json +8 -0
- package/src/intl/grid/hr-HR.json +8 -0
- package/src/intl/grid/hu-HU.json +8 -0
- package/src/intl/grid/index.ts +75 -0
- package/src/intl/grid/it-IT.json +8 -0
- package/src/intl/grid/ja-JP.json +8 -0
- package/src/intl/grid/ko-KR.json +8 -0
- package/src/intl/grid/lt-LT.json +8 -0
- package/src/intl/grid/lv-LV.json +8 -0
- package/src/intl/grid/nb-NO.json +8 -0
- package/src/intl/grid/nl-NL.json +8 -0
- package/src/intl/grid/pl-PL.json +8 -0
- package/src/intl/grid/pt-BR.json +8 -0
- package/src/intl/grid/pt-PT.json +8 -0
- package/src/intl/grid/ro-RO.json +8 -0
- package/src/intl/grid/ru-RU.json +8 -0
- package/src/intl/grid/sk-SK.json +8 -0
- package/src/intl/grid/sl-SI.json +8 -0
- package/src/intl/grid/sr-SP.json +8 -0
- package/src/intl/grid/sv-SE.json +8 -0
- package/src/intl/grid/tr-TR.json +8 -0
- package/src/intl/grid/uk-UA.json +8 -0
- package/src/intl/grid/zh-CN.json +8 -0
- package/src/intl/grid/zh-TW.json +8 -0
- package/src/intl/gridlist/ar-AE.json +4 -0
- package/src/intl/gridlist/bg-BG.json +4 -0
- package/src/intl/gridlist/cs-CZ.json +4 -0
- package/src/intl/gridlist/da-DK.json +4 -0
- package/src/intl/gridlist/de-DE.json +4 -0
- package/src/intl/gridlist/el-GR.json +4 -0
- package/src/intl/gridlist/en-US.json +4 -0
- package/src/intl/gridlist/es-ES.json +4 -0
- package/src/intl/gridlist/et-EE.json +4 -0
- package/src/intl/gridlist/fi-FI.json +4 -0
- package/src/intl/gridlist/fr-FR.json +4 -0
- package/src/intl/gridlist/he-IL.json +4 -0
- package/src/intl/gridlist/hr-HR.json +4 -0
- package/src/intl/gridlist/hu-HU.json +4 -0
- package/src/intl/gridlist/index.ts +75 -0
- package/src/intl/gridlist/it-IT.json +4 -0
- package/src/intl/gridlist/ja-JP.json +4 -0
- package/src/intl/gridlist/ko-KR.json +4 -0
- package/src/intl/gridlist/lt-LT.json +4 -0
- package/src/intl/gridlist/lv-LV.json +4 -0
- package/src/intl/gridlist/nb-NO.json +4 -0
- package/src/intl/gridlist/nl-NL.json +4 -0
- package/src/intl/gridlist/pl-PL.json +4 -0
- package/src/intl/gridlist/pt-BR.json +4 -0
- package/src/intl/gridlist/pt-PT.json +4 -0
- package/src/intl/gridlist/ro-RO.json +4 -0
- package/src/intl/gridlist/ru-RU.json +4 -0
- package/src/intl/gridlist/sk-SK.json +4 -0
- package/src/intl/gridlist/sl-SI.json +4 -0
- package/src/intl/gridlist/sr-SP.json +4 -0
- package/src/intl/gridlist/sv-SE.json +4 -0
- package/src/intl/gridlist/tr-TR.json +4 -0
- package/src/intl/gridlist/uk-UA.json +4 -0
- package/src/intl/gridlist/zh-CN.json +4 -0
- package/src/intl/gridlist/zh-TW.json +4 -0
- package/src/intl/menu/ar-AE.json +3 -0
- package/src/intl/menu/bg-BG.json +3 -0
- package/src/intl/menu/cs-CZ.json +3 -0
- package/src/intl/menu/da-DK.json +3 -0
- package/src/intl/menu/de-DE.json +3 -0
- package/src/intl/menu/el-GR.json +3 -0
- package/src/intl/menu/en-US.json +3 -0
- package/src/intl/menu/es-ES.json +3 -0
- package/src/intl/menu/et-EE.json +3 -0
- package/src/intl/menu/fi-FI.json +3 -0
- package/src/intl/menu/fr-FR.json +3 -0
- package/src/intl/menu/he-IL.json +3 -0
- package/src/intl/menu/hr-HR.json +3 -0
- package/src/intl/menu/hu-HU.json +3 -0
- package/src/intl/menu/index.ts +75 -0
- package/src/intl/menu/it-IT.json +3 -0
- package/src/intl/menu/ja-JP.json +3 -0
- package/src/intl/menu/ko-KR.json +3 -0
- package/src/intl/menu/lt-LT.json +3 -0
- package/src/intl/menu/lv-LV.json +3 -0
- package/src/intl/menu/nb-NO.json +3 -0
- package/src/intl/menu/nl-NL.json +3 -0
- package/src/intl/menu/pl-PL.json +3 -0
- package/src/intl/menu/pt-BR.json +3 -0
- package/src/intl/menu/pt-PT.json +3 -0
- package/src/intl/menu/ro-RO.json +3 -0
- package/src/intl/menu/ru-RU.json +3 -0
- package/src/intl/menu/sk-SK.json +3 -0
- package/src/intl/menu/sl-SI.json +3 -0
- package/src/intl/menu/sr-SP.json +3 -0
- package/src/intl/menu/sv-SE.json +3 -0
- package/src/intl/menu/tr-TR.json +3 -0
- package/src/intl/menu/uk-UA.json +3 -0
- package/src/intl/menu/zh-CN.json +3 -0
- package/src/intl/menu/zh-TW.json +3 -0
- package/src/intl/numberfield/ar-AE.json +5 -0
- package/src/intl/numberfield/bg-BG.json +5 -0
- package/src/intl/numberfield/cs-CZ.json +5 -0
- package/src/intl/numberfield/da-DK.json +5 -0
- package/src/intl/numberfield/de-DE.json +5 -0
- package/src/intl/numberfield/el-GR.json +5 -0
- package/src/intl/numberfield/en-US.json +5 -0
- package/src/intl/numberfield/es-ES.json +5 -0
- package/src/intl/numberfield/et-EE.json +5 -0
- package/src/intl/numberfield/fi-FI.json +5 -0
- package/src/intl/numberfield/fr-FR.json +5 -0
- package/src/intl/numberfield/he-IL.json +5 -0
- package/src/intl/numberfield/hr-HR.json +5 -0
- package/src/intl/numberfield/hu-HU.json +5 -0
- package/src/intl/numberfield/index.ts +75 -0
- package/src/intl/numberfield/it-IT.json +5 -0
- package/src/intl/numberfield/ja-JP.json +5 -0
- package/src/intl/numberfield/ko-KR.json +5 -0
- package/src/intl/numberfield/lt-LT.json +5 -0
- package/src/intl/numberfield/lv-LV.json +5 -0
- package/src/intl/numberfield/nb-NO.json +5 -0
- package/src/intl/numberfield/nl-NL.json +5 -0
- package/src/intl/numberfield/pl-PL.json +5 -0
- package/src/intl/numberfield/pt-BR.json +5 -0
- package/src/intl/numberfield/pt-PT.json +5 -0
- package/src/intl/numberfield/ro-RO.json +5 -0
- package/src/intl/numberfield/ru-RU.json +5 -0
- package/src/intl/numberfield/sk-SK.json +5 -0
- package/src/intl/numberfield/sl-SI.json +5 -0
- package/src/intl/numberfield/sr-SP.json +5 -0
- package/src/intl/numberfield/sv-SE.json +5 -0
- package/src/intl/numberfield/tr-TR.json +5 -0
- package/src/intl/numberfield/uk-UA.json +5 -0
- package/src/intl/numberfield/zh-CN.json +5 -0
- package/src/intl/numberfield/zh-TW.json +5 -0
- package/src/intl/overlays/ar-AE.json +3 -0
- package/src/intl/overlays/bg-BG.json +3 -0
- package/src/intl/overlays/cs-CZ.json +3 -0
- package/src/intl/overlays/da-DK.json +3 -0
- package/src/intl/overlays/de-DE.json +3 -0
- package/src/intl/overlays/el-GR.json +3 -0
- package/src/intl/overlays/en-US.json +3 -0
- package/src/intl/overlays/es-ES.json +3 -0
- package/src/intl/overlays/et-EE.json +3 -0
- package/src/intl/overlays/fi-FI.json +3 -0
- package/src/intl/overlays/fr-FR.json +3 -0
- package/src/intl/overlays/he-IL.json +3 -0
- package/src/intl/overlays/hr-HR.json +3 -0
- package/src/intl/overlays/hu-HU.json +3 -0
- package/src/intl/overlays/index.ts +75 -0
- package/src/intl/overlays/it-IT.json +3 -0
- package/src/intl/overlays/ja-JP.json +3 -0
- package/src/intl/overlays/ko-KR.json +3 -0
- package/src/intl/overlays/lt-LT.json +3 -0
- package/src/intl/overlays/lv-LV.json +3 -0
- package/src/intl/overlays/nb-NO.json +3 -0
- package/src/intl/overlays/nl-NL.json +3 -0
- package/src/intl/overlays/pl-PL.json +3 -0
- package/src/intl/overlays/pt-BR.json +3 -0
- package/src/intl/overlays/pt-PT.json +3 -0
- package/src/intl/overlays/ro-RO.json +3 -0
- package/src/intl/overlays/ru-RU.json +3 -0
- package/src/intl/overlays/sk-SK.json +3 -0
- package/src/intl/overlays/sl-SI.json +3 -0
- package/src/intl/overlays/sr-SP.json +3 -0
- package/src/intl/overlays/sv-SE.json +3 -0
- package/src/intl/overlays/tr-TR.json +3 -0
- package/src/intl/overlays/uk-UA.json +3 -0
- package/src/intl/overlays/zh-CN.json +3 -0
- package/src/intl/overlays/zh-TW.json +3 -0
- package/src/intl/searchfield/ar-AE.json +3 -0
- package/src/intl/searchfield/bg-BG.json +3 -0
- package/src/intl/searchfield/cs-CZ.json +3 -0
- package/src/intl/searchfield/da-DK.json +3 -0
- package/src/intl/searchfield/de-DE.json +3 -0
- package/src/intl/searchfield/el-GR.json +3 -0
- package/src/intl/searchfield/en-US.json +3 -0
- package/src/intl/searchfield/es-ES.json +3 -0
- package/src/intl/searchfield/et-EE.json +3 -0
- package/src/intl/searchfield/fi-FI.json +3 -0
- package/src/intl/searchfield/fr-FR.json +3 -0
- package/src/intl/searchfield/he-IL.json +3 -0
- package/src/intl/searchfield/hr-HR.json +3 -0
- package/src/intl/searchfield/hu-HU.json +3 -0
- package/src/intl/searchfield/index.ts +75 -0
- package/src/intl/searchfield/it-IT.json +3 -0
- package/src/intl/searchfield/ja-JP.json +3 -0
- package/src/intl/searchfield/ko-KR.json +3 -0
- package/src/intl/searchfield/lt-LT.json +3 -0
- package/src/intl/searchfield/lv-LV.json +3 -0
- package/src/intl/searchfield/nb-NO.json +3 -0
- package/src/intl/searchfield/nl-NL.json +3 -0
- package/src/intl/searchfield/pl-PL.json +3 -0
- package/src/intl/searchfield/pt-BR.json +3 -0
- package/src/intl/searchfield/pt-PT.json +3 -0
- package/src/intl/searchfield/ro-RO.json +3 -0
- package/src/intl/searchfield/ru-RU.json +3 -0
- package/src/intl/searchfield/sk-SK.json +3 -0
- package/src/intl/searchfield/sl-SI.json +3 -0
- package/src/intl/searchfield/sr-SP.json +3 -0
- package/src/intl/searchfield/sv-SE.json +3 -0
- package/src/intl/searchfield/tr-TR.json +3 -0
- package/src/intl/searchfield/uk-UA.json +3 -0
- package/src/intl/searchfield/zh-CN.json +3 -0
- package/src/intl/searchfield/zh-TW.json +3 -0
- package/src/intl/spinbutton/ar-AE.json +3 -0
- package/src/intl/spinbutton/bg-BG.json +3 -0
- package/src/intl/spinbutton/cs-CZ.json +3 -0
- package/src/intl/spinbutton/da-DK.json +3 -0
- package/src/intl/spinbutton/de-DE.json +3 -0
- package/src/intl/spinbutton/el-GR.json +3 -0
- package/src/intl/spinbutton/en-US.json +3 -0
- package/src/intl/spinbutton/es-ES.json +3 -0
- package/src/intl/spinbutton/et-EE.json +3 -0
- package/src/intl/spinbutton/fi-FI.json +3 -0
- package/src/intl/spinbutton/fr-FR.json +3 -0
- package/src/intl/spinbutton/he-IL.json +3 -0
- package/src/intl/spinbutton/hr-HR.json +3 -0
- package/src/intl/spinbutton/hu-HU.json +3 -0
- package/src/intl/spinbutton/index.ts +75 -0
- package/src/intl/spinbutton/it-IT.json +3 -0
- package/src/intl/spinbutton/ja-JP.json +3 -0
- package/src/intl/spinbutton/ko-KR.json +3 -0
- package/src/intl/spinbutton/lt-LT.json +3 -0
- package/src/intl/spinbutton/lv-LV.json +3 -0
- package/src/intl/spinbutton/nb-NO.json +3 -0
- package/src/intl/spinbutton/nl-NL.json +3 -0
- package/src/intl/spinbutton/pl-PL.json +3 -0
- package/src/intl/spinbutton/pt-BR.json +3 -0
- package/src/intl/spinbutton/pt-PT.json +3 -0
- package/src/intl/spinbutton/ro-RO.json +3 -0
- package/src/intl/spinbutton/ru-RU.json +3 -0
- package/src/intl/spinbutton/sk-SK.json +3 -0
- package/src/intl/spinbutton/sl-SI.json +3 -0
- package/src/intl/spinbutton/sr-SP.json +3 -0
- package/src/intl/spinbutton/sv-SE.json +3 -0
- package/src/intl/spinbutton/tr-TR.json +3 -0
- package/src/intl/spinbutton/uk-UA.json +3 -0
- package/src/intl/spinbutton/zh-CN.json +3 -0
- package/src/intl/spinbutton/zh-TW.json +3 -0
- package/src/intl/tag/ar-AE.json +4 -0
- package/src/intl/tag/bg-BG.json +4 -0
- package/src/intl/tag/cs-CZ.json +4 -0
- package/src/intl/tag/da-DK.json +4 -0
- package/src/intl/tag/de-DE.json +4 -0
- package/src/intl/tag/el-GR.json +4 -0
- package/src/intl/tag/en-US.json +4 -0
- package/src/intl/tag/es-ES.json +4 -0
- package/src/intl/tag/et-EE.json +4 -0
- package/src/intl/tag/fi-FI.json +4 -0
- package/src/intl/tag/fr-FR.json +4 -0
- package/src/intl/tag/he-IL.json +4 -0
- package/src/intl/tag/hr-HR.json +4 -0
- package/src/intl/tag/hu-HU.json +4 -0
- package/src/intl/tag/index.ts +75 -0
- package/src/intl/tag/it-IT.json +4 -0
- package/src/intl/tag/ja-JP.json +4 -0
- package/src/intl/tag/ko-KR.json +4 -0
- package/src/intl/tag/lt-LT.json +4 -0
- package/src/intl/tag/lv-LV.json +4 -0
- package/src/intl/tag/nb-NO.json +4 -0
- package/src/intl/tag/nl-NL.json +4 -0
- package/src/intl/tag/pl-PL.json +4 -0
- package/src/intl/tag/pt-BR.json +4 -0
- package/src/intl/tag/pt-PT.json +4 -0
- package/src/intl/tag/ro-RO.json +4 -0
- package/src/intl/tag/ru-RU.json +4 -0
- package/src/intl/tag/sk-SK.json +4 -0
- package/src/intl/tag/sl-SI.json +4 -0
- package/src/intl/tag/sr-SP.json +4 -0
- package/src/intl/tag/sv-SE.json +4 -0
- package/src/intl/tag/tr-TR.json +4 -0
- package/src/intl/tag/uk-UA.json +4 -0
- package/src/intl/tag/zh-CN.json +4 -0
- package/src/intl/tag/zh-TW.json +4 -0
- package/src/label/useField.ts +67 -0
- package/src/label/useLabel.ts +78 -0
- package/src/link/useLink.ts +108 -0
- package/src/listbox/useListBox.ts +224 -0
- package/src/listbox/useListBoxSection.ts +74 -0
- package/src/listbox/useOption.ts +212 -0
- package/src/listbox/utils.ts +38 -0
- package/src/live-announcer/LiveAnnouncer.ts +172 -0
- package/src/menu/useMenu.ts +139 -0
- package/src/menu/useMenuItem.ts +453 -0
- package/src/menu/useMenuSection.ts +70 -0
- package/src/menu/useMenuTrigger.ts +189 -0
- package/src/menu/useSafelyMouseToSubmenu.ts +236 -0
- package/src/menu/useSubmenuTrigger.ts +357 -0
- package/src/menu/utils.ts +16 -0
- package/src/meter/useMeter.ts +43 -0
- package/src/numberfield/useNumberField.ts +572 -0
- package/src/overlays/DismissButton.ts +50 -0
- package/src/overlays/Overlay.ts +106 -0
- package/src/overlays/PortalProvider.ts +37 -0
- package/src/overlays/ariaHideOutside.ts +299 -0
- package/src/overlays/calculatePosition.ts +856 -0
- package/src/overlays/useCloseOnScroll.ts +75 -0
- package/src/overlays/useModal.ts +224 -0
- package/src/overlays/useModalOverlay.ts +103 -0
- package/src/overlays/useOverlay.ts +199 -0
- package/src/overlays/useOverlayPosition.ts +462 -0
- package/src/overlays/useOverlayTrigger.ts +94 -0
- package/src/overlays/usePopover.ts +170 -0
- package/src/overlays/usePreventScroll.ts +316 -0
- package/src/progress/useProgressBar.ts +115 -0
- package/src/radio/useRadio.ts +219 -0
- package/src/radio/useRadioGroup.ts +184 -0
- package/src/radio/utils.ts +15 -0
- package/src/searchfield/useSearchField.ts +156 -0
- package/src/select/HiddenSelect.ts +261 -0
- package/src/select/useSelect.ts +332 -0
- package/src/selection/DOMLayoutDelegate.ts +51 -0
- package/src/selection/ListKeyboardDelegate.ts +392 -0
- package/src/selection/useSelectableCollection.ts +750 -0
- package/src/selection/useSelectableItem.ts +499 -0
- package/src/selection/useSelectableList.ts +132 -0
- package/src/selection/useTypeSelect.ts +192 -0
- package/src/selection/utils.ts +50 -0
- package/src/separator/useSeparator.ts +41 -0
- package/src/slider/useSlider.ts +277 -0
- package/src/slider/useSliderThumb.ts +375 -0
- package/src/slider/utils.ts +20 -0
- package/src/spinbutton/useSpinButton.ts +380 -0
- package/src/stately/checkbox/useCheckboxGroupState.ts +177 -0
- package/src/stately/collections/CollectionBuilder.ts +332 -0
- package/src/stately/collections/Item.ts +78 -0
- package/src/stately/collections/Section.ts +52 -0
- package/src/stately/collections/getChildNodes.ts +94 -0
- package/src/stately/collections/getItemCount.ts +29 -0
- package/src/stately/collections/types.ts +20 -0
- package/src/stately/collections/useCollection.ts +54 -0
- package/src/stately/combobox/useComboBoxState.ts +763 -0
- package/src/stately/disclosure/useDisclosureGroupState.ts +108 -0
- package/src/stately/disclosure/useDisclosureState.ts +84 -0
- package/src/stately/form/useFormValidationState.ts +331 -0
- package/src/stately/index.ts +111 -0
- package/src/stately/list/ListCollection.ts +104 -0
- package/src/stately/list/useListState.ts +178 -0
- package/src/stately/list/useSingleSelectListState.ts +101 -0
- package/src/stately/menu/useMenuTriggerState.ts +120 -0
- package/src/stately/menu/useSubmenuTriggerState.ts +116 -0
- package/src/stately/numberfield/useNumberFieldState.ts +430 -0
- package/src/stately/overlays/useOverlayTriggerState.ts +85 -0
- package/src/stately/radio/useRadioGroupState.ts +150 -0
- package/src/stately/searchfield/useSearchFieldState.ts +79 -0
- package/src/stately/select/useSelectState.ts +322 -0
- package/src/stately/selection/Selection.ts +23 -0
- package/src/stately/selection/SelectionManager.ts +541 -0
- package/src/stately/selection/types.ts +117 -0
- package/src/stately/selection/useMultipleSelectionState.ts +178 -0
- package/src/stately/slider/useSliderState.ts +458 -0
- package/src/stately/tabs/useTabListState.ts +149 -0
- package/src/stately/toggle/useToggleGroupState.ts +109 -0
- package/src/stately/toggle/useToggleState.ts +100 -0
- package/src/stately/tooltip/useTooltipTriggerState.ts +218 -0
- package/src/stately/tree/TreeCollection.ts +92 -0
- package/src/stately/tree/useTreeState.ts +121 -0
- package/src/stately/utils/useControlledState.ts +7 -0
- package/src/switch/useSwitch.ts +77 -0
- package/src/tabs/TabsKeyboardDelegate.ts +99 -0
- package/src/tabs/useTab.ts +117 -0
- package/src/tabs/useTabList.ts +105 -0
- package/src/tabs/useTabPanel.ts +75 -0
- package/src/tabs/utils.ts +32 -0
- package/src/tag/useTag.ts +162 -0
- package/src/tag/useTagGroup.ts +192 -0
- package/src/textfield/useFormattedTextField.ts +203 -0
- package/src/textfield/useTextField.ts +248 -0
- package/src/toggle/useToggle.ts +265 -0
- package/src/toolbar/useToolbar.ts +147 -0
- package/src/tooltip/useTooltip.ts +64 -0
- package/src/tooltip/useTooltipTrigger.ts +187 -0
- package/src/utils/filterDOMProps.ts +121 -0
- package/src/utils/getScrollParent.ts +16 -0
- package/src/utils/getScrollParents.ts +20 -0
- package/src/utils/keyboard.ts +38 -0
- package/src/utils/scrollIntoView.ts +178 -0
- package/src/utils/useDeepMemo.ts +30 -0
- package/src/utils/useFormReset.ts +54 -0
- package/src/utils/useId.ts +5 -0
- package/src/utils/useLabels.ts +53 -0
- package/src/utils/useResizeObserver.ts +70 -0
- package/src/utils/useSlot.ts +78 -0
- package/src/utils/useUpdateEffect.ts +54 -0
- package/src/utils/useUpdateLayoutEffect.ts +58 -0
- package/src/visually-hidden/VisuallyHidden.ts +100 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// Ported from react-stately (source: .react-spectrum/packages/react-stately/src/tree/useTreeState.ts).
|
|
2
|
+
// octane adaptations: public-hook slot threading (splitSlot/subSlot) per the binding
|
|
3
|
+
// convention; explicit dependency arrays are kept verbatim — including upstream's
|
|
4
|
+
// eslint-suppressed `[tree, selectionState.focusedKey]` effect array (they retain React's
|
|
5
|
+
// exact behavior in octane).
|
|
6
|
+
import type {
|
|
7
|
+
Collection,
|
|
8
|
+
CollectionStateBase,
|
|
9
|
+
DisabledBehavior,
|
|
10
|
+
Expandable,
|
|
11
|
+
Key,
|
|
12
|
+
MultipleSelection,
|
|
13
|
+
Node,
|
|
14
|
+
} from '@react-types/shared';
|
|
15
|
+
import { useCallback, useEffect, useMemo } from 'octane';
|
|
16
|
+
|
|
17
|
+
import { S, splitSlot, subSlot } from '../../internal';
|
|
18
|
+
import { SelectionManager } from '../selection/SelectionManager';
|
|
19
|
+
import { TreeCollection } from './TreeCollection';
|
|
20
|
+
import { useCollection } from '../collections/useCollection';
|
|
21
|
+
import { useControlledState } from '../utils/useControlledState';
|
|
22
|
+
import { useMultipleSelectionState } from '../selection/useMultipleSelectionState';
|
|
23
|
+
|
|
24
|
+
export interface TreeProps<T> extends CollectionStateBase<T>, Expandable, MultipleSelection {
|
|
25
|
+
/** Whether `disabledKeys` applies to all interactions, or only selection. */
|
|
26
|
+
disabledBehavior?: DisabledBehavior;
|
|
27
|
+
}
|
|
28
|
+
export interface TreeState<T> {
|
|
29
|
+
/** A collection of items in the tree. */
|
|
30
|
+
readonly collection: Collection<Node<T>>;
|
|
31
|
+
|
|
32
|
+
/** A set of keys for items that are disabled. */
|
|
33
|
+
readonly disabledKeys: Set<Key>;
|
|
34
|
+
|
|
35
|
+
/** A set of keys for items that are expanded. */
|
|
36
|
+
readonly expandedKeys: Set<Key>;
|
|
37
|
+
|
|
38
|
+
/** Toggles the expanded state for an item by its key. */
|
|
39
|
+
toggleKey(key: Key): void;
|
|
40
|
+
|
|
41
|
+
/** Replaces the set of expanded keys. */
|
|
42
|
+
setExpandedKeys(keys: Set<Key>): void;
|
|
43
|
+
|
|
44
|
+
/** A selection manager to read and update multiple selection state. */
|
|
45
|
+
readonly selectionManager: SelectionManager;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Provides state management for tree-like components. Handles building a collection
|
|
50
|
+
* of items from props, item expanded state, and manages multiple selection state.
|
|
51
|
+
*/
|
|
52
|
+
export function useTreeState<T>(props: TreeProps<T>): TreeState<T>;
|
|
53
|
+
// Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
|
|
54
|
+
export function useTreeState<T>(props: TreeProps<T>, slot: symbol | undefined): TreeState<T>;
|
|
55
|
+
export function useTreeState(...args: any[]): TreeState<any> {
|
|
56
|
+
const [user, slotArg] = splitSlot(args);
|
|
57
|
+
const slot = slotArg ?? S('useTreeState');
|
|
58
|
+
const props = user[0] as TreeProps<any>;
|
|
59
|
+
|
|
60
|
+
let { onExpandedChange } = props;
|
|
61
|
+
|
|
62
|
+
let [expandedKeys, setExpandedKeys] = useControlledState(
|
|
63
|
+
props.expandedKeys ? new Set(props.expandedKeys) : undefined,
|
|
64
|
+
props.defaultExpandedKeys ? new Set(props.defaultExpandedKeys) : new Set<Key>(),
|
|
65
|
+
onExpandedChange,
|
|
66
|
+
subSlot(slot, 'expanded'),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
let selectionState = useMultipleSelectionState(props, subSlot(slot, 'selection'));
|
|
70
|
+
let disabledKeys = useMemo(
|
|
71
|
+
() => (props.disabledKeys ? new Set(props.disabledKeys) : new Set<Key>()),
|
|
72
|
+
[props.disabledKeys],
|
|
73
|
+
subSlot(slot, 'disabled'),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
let tree = useCollection(
|
|
77
|
+
props,
|
|
78
|
+
useCallback(
|
|
79
|
+
(nodes: Iterable<Node<any>>) => new TreeCollection(nodes, { expandedKeys }),
|
|
80
|
+
[expandedKeys],
|
|
81
|
+
subSlot(slot, 'factory'),
|
|
82
|
+
),
|
|
83
|
+
null,
|
|
84
|
+
subSlot(slot, 'collection'),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// Reset focused key if that item is deleted from the collection.
|
|
88
|
+
useEffect(
|
|
89
|
+
() => {
|
|
90
|
+
if (selectionState.focusedKey != null && !tree.getItem(selectionState.focusedKey)) {
|
|
91
|
+
selectionState.setFocusedKey(null);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
[tree, selectionState.focusedKey],
|
|
95
|
+
subSlot(slot, 'focusReset'),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
let onToggle = (key: Key) => {
|
|
99
|
+
setExpandedKeys(toggleKey(expandedKeys, key));
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
collection: tree,
|
|
104
|
+
expandedKeys,
|
|
105
|
+
disabledKeys,
|
|
106
|
+
toggleKey: onToggle,
|
|
107
|
+
setExpandedKeys,
|
|
108
|
+
selectionManager: new SelectionManager(tree, selectionState),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function toggleKey(set: Set<Key>, key: Key): Set<Key> {
|
|
113
|
+
let res = new Set(set);
|
|
114
|
+
if (res.has(key)) {
|
|
115
|
+
res.delete(key);
|
|
116
|
+
} else {
|
|
117
|
+
res.add(key);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return res;
|
|
121
|
+
}
|
|
@@ -23,6 +23,13 @@ export function useControlledState<T, C = T>(
|
|
|
23
23
|
defaultValue: Exclude<T, undefined>,
|
|
24
24
|
onChange?: (v: C, ...args: any[]) => void,
|
|
25
25
|
): [T, (value: SetStateAction<T>, ...args: any[]) => void];
|
|
26
|
+
// Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
|
|
27
|
+
export function useControlledState<T, C = T>(
|
|
28
|
+
value: Exclude<T, undefined> | undefined,
|
|
29
|
+
defaultValue: Exclude<T, undefined> | undefined,
|
|
30
|
+
onChange: ((v: C, ...args: any[]) => void) | undefined,
|
|
31
|
+
slot: symbol | undefined,
|
|
32
|
+
): [T, (value: SetStateAction<T>, ...args: any[]) => void];
|
|
26
33
|
export function useControlledState(...args: any[]): any {
|
|
27
34
|
const [user, slotArg] = splitSlot(args);
|
|
28
35
|
const slot = slotArg ?? S('useControlledState');
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Ported from react-aria (source: .react-spectrum/packages/react-aria/src/switch/useSwitch.ts).
|
|
2
|
+
// octane adaptations: React's per-element attribute types → the structural bags the
|
|
3
|
+
// ported useToggle returns; public-hook slot threading.
|
|
4
|
+
import type { InputDOMProps, RefObject, ValidationResult } from '@react-types/shared';
|
|
5
|
+
|
|
6
|
+
import { S, splitSlot, subSlot } from '../internal';
|
|
7
|
+
import { AriaToggleProps, useToggle } from '../toggle/useToggle';
|
|
8
|
+
import type { ToggleProps, ToggleState } from '../stately/toggle/useToggleState';
|
|
9
|
+
|
|
10
|
+
type DOMAttributes = Record<string, any>;
|
|
11
|
+
|
|
12
|
+
export interface SwitchProps extends ToggleProps {}
|
|
13
|
+
|
|
14
|
+
export interface AriaSwitchProps extends SwitchProps, InputDOMProps, AriaToggleProps {
|
|
15
|
+
/**
|
|
16
|
+
* Identifies the element (or elements) whose contents or presence are controlled by the current
|
|
17
|
+
* element.
|
|
18
|
+
*/
|
|
19
|
+
'aria-controls'?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SwitchAria extends ValidationResult {
|
|
23
|
+
/** Props for the label wrapper element. */
|
|
24
|
+
labelProps: DOMAttributes;
|
|
25
|
+
/** Props for the input element. */
|
|
26
|
+
inputProps: DOMAttributes;
|
|
27
|
+
/** Props for the switch description element, if any. */
|
|
28
|
+
descriptionProps: DOMAttributes;
|
|
29
|
+
/** Props for the switch error message element, if any. */
|
|
30
|
+
errorMessageProps: DOMAttributes;
|
|
31
|
+
/** Whether the switch is selected. */
|
|
32
|
+
isSelected: boolean;
|
|
33
|
+
/** Whether the switch is in a pressed state. */
|
|
34
|
+
isPressed: boolean;
|
|
35
|
+
/** Whether the switch is disabled. */
|
|
36
|
+
isDisabled: boolean;
|
|
37
|
+
/** Whether the switch is read only. */
|
|
38
|
+
isReadOnly: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function useSwitch(
|
|
42
|
+
props: AriaSwitchProps,
|
|
43
|
+
state: ToggleState,
|
|
44
|
+
ref: RefObject<HTMLInputElement | null>,
|
|
45
|
+
): SwitchAria;
|
|
46
|
+
// Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
|
|
47
|
+
export function useSwitch(
|
|
48
|
+
props: AriaSwitchProps,
|
|
49
|
+
state: ToggleState,
|
|
50
|
+
ref: RefObject<HTMLInputElement | null>,
|
|
51
|
+
slot: symbol | undefined,
|
|
52
|
+
): SwitchAria;
|
|
53
|
+
export function useSwitch(...args: any[]): SwitchAria {
|
|
54
|
+
const [user, slotArg] = splitSlot(args);
|
|
55
|
+
const slot = slotArg ?? S('useSwitch');
|
|
56
|
+
const props = user[0] as AriaSwitchProps;
|
|
57
|
+
const state = user[1] as ToggleState;
|
|
58
|
+
const ref = user[2] as RefObject<HTMLInputElement | null>;
|
|
59
|
+
|
|
60
|
+
let { labelProps, inputProps, isSelected, ...states } = useToggle(
|
|
61
|
+
props,
|
|
62
|
+
state,
|
|
63
|
+
ref,
|
|
64
|
+
subSlot(slot, 'toggle'),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
labelProps,
|
|
69
|
+
inputProps: {
|
|
70
|
+
...inputProps,
|
|
71
|
+
role: 'switch',
|
|
72
|
+
checked: isSelected,
|
|
73
|
+
},
|
|
74
|
+
isSelected,
|
|
75
|
+
...states,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Ported from react-aria (source: .react-spectrum/packages/react-aria/src/tabs/TabsKeyboardDelegate.ts).
|
|
2
|
+
// No octane adaptations required: a plain class over @react-types/shared types.
|
|
3
|
+
import type {
|
|
4
|
+
Collection,
|
|
5
|
+
Direction,
|
|
6
|
+
Key,
|
|
7
|
+
KeyboardDelegate,
|
|
8
|
+
Node,
|
|
9
|
+
Orientation,
|
|
10
|
+
} from '@react-types/shared';
|
|
11
|
+
|
|
12
|
+
export class TabsKeyboardDelegate<T> implements KeyboardDelegate {
|
|
13
|
+
private collection: Collection<Node<T>>;
|
|
14
|
+
private flipDirection: boolean;
|
|
15
|
+
private disabledKeys: Set<Key>;
|
|
16
|
+
private tabDirection: boolean;
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
collection: Collection<Node<T>>,
|
|
20
|
+
direction: Direction,
|
|
21
|
+
orientation: Orientation,
|
|
22
|
+
disabledKeys: Set<Key> = new Set(),
|
|
23
|
+
) {
|
|
24
|
+
this.collection = collection;
|
|
25
|
+
this.flipDirection = direction === 'rtl' && orientation === 'horizontal';
|
|
26
|
+
this.disabledKeys = disabledKeys;
|
|
27
|
+
this.tabDirection = orientation === 'horizontal';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getKeyLeftOf(key: Key): Key | null {
|
|
31
|
+
if (this.flipDirection) {
|
|
32
|
+
return this.getNextKey(key);
|
|
33
|
+
}
|
|
34
|
+
return this.getPreviousKey(key);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getKeyRightOf(key: Key): Key | null {
|
|
38
|
+
if (this.flipDirection) {
|
|
39
|
+
return this.getPreviousKey(key);
|
|
40
|
+
}
|
|
41
|
+
return this.getNextKey(key);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private isDisabled(key: Key) {
|
|
45
|
+
return this.disabledKeys.has(key) || !!this.collection.getItem(key)?.props?.isDisabled;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getFirstKey(): Key | null {
|
|
49
|
+
let key = this.collection.getFirstKey();
|
|
50
|
+
if (key != null && this.isDisabled(key)) {
|
|
51
|
+
key = this.getNextKey(key);
|
|
52
|
+
}
|
|
53
|
+
return key;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getLastKey(): Key | null {
|
|
57
|
+
let key = this.collection.getLastKey();
|
|
58
|
+
if (key != null && this.isDisabled(key)) {
|
|
59
|
+
key = this.getPreviousKey(key);
|
|
60
|
+
}
|
|
61
|
+
return key;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getKeyAbove(key: Key): Key | null {
|
|
65
|
+
if (this.tabDirection) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return this.getPreviousKey(key);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getKeyBelow(key: Key): Key | null {
|
|
72
|
+
if (this.tabDirection) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return this.getNextKey(key);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getNextKey(startKey: Key): Key | null {
|
|
79
|
+
let key: Key | null = startKey;
|
|
80
|
+
do {
|
|
81
|
+
key = this.collection.getKeyAfter(key);
|
|
82
|
+
if (key == null) {
|
|
83
|
+
key = this.collection.getFirstKey();
|
|
84
|
+
}
|
|
85
|
+
} while (key != null && this.isDisabled(key) && key !== startKey);
|
|
86
|
+
return key;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getPreviousKey(startKey: Key): Key | null {
|
|
90
|
+
let key: Key | null = startKey;
|
|
91
|
+
do {
|
|
92
|
+
key = this.collection.getKeyBefore(key);
|
|
93
|
+
if (key == null) {
|
|
94
|
+
key = this.collection.getLastKey();
|
|
95
|
+
}
|
|
96
|
+
} while (key != null && this.isDisabled(key) && key !== startKey);
|
|
97
|
+
return key;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Ported from react-aria (source: .react-spectrum/packages/react-aria/src/tabs/useTab.ts).
|
|
2
|
+
// octane adaptations:
|
|
3
|
+
// - `DOMAttributes` is a local structural prop-bag alias (upstream's is typed over React's
|
|
4
|
+
// synthetic handlers); `TabListState` from the ported stately tabs state.
|
|
5
|
+
// - Public-hook slot threading (splitSlot/subSlot) per the binding convention
|
|
6
|
+
// (`useLinkProps` composes only context-reading hooks and takes no slot, matching the
|
|
7
|
+
// ported useLink).
|
|
8
|
+
import type { AriaLabelingProps, FocusableElement, Key, RefObject } from '@react-types/shared';
|
|
9
|
+
import { filterDOMProps } from '../utils/filterDOMProps';
|
|
10
|
+
import { generateId } from './utils';
|
|
11
|
+
import { mergeProps } from '../utils/mergeProps';
|
|
12
|
+
import type { TabListState } from '../stately/tabs/useTabListState';
|
|
13
|
+
import { useFocusable } from '../interactions/useFocusable';
|
|
14
|
+
import { useLinkProps } from '../utils/openLink';
|
|
15
|
+
import { useSelectableItem } from '../selection/useSelectableItem';
|
|
16
|
+
|
|
17
|
+
import { S, splitSlot, subSlot } from '../internal';
|
|
18
|
+
|
|
19
|
+
// octane adaptation: minimal structural DOMAttributes (upstream's drags React's synthetic
|
|
20
|
+
// handler types along).
|
|
21
|
+
type DOMAttributes = Record<string, any>;
|
|
22
|
+
|
|
23
|
+
export interface AriaTabProps extends AriaLabelingProps {
|
|
24
|
+
/** The key of the tab. */
|
|
25
|
+
key: Key;
|
|
26
|
+
/** Whether the tab should be disabled. */
|
|
27
|
+
isDisabled?: boolean;
|
|
28
|
+
/** Whether the tab selection should occur on press up instead of press down. */
|
|
29
|
+
shouldSelectOnPressUp?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface TabAria {
|
|
33
|
+
/** Props for the tab element. */
|
|
34
|
+
tabProps: DOMAttributes;
|
|
35
|
+
/** Whether the tab is currently selected. */
|
|
36
|
+
isSelected: boolean;
|
|
37
|
+
/** Whether the tab is disabled. */
|
|
38
|
+
isDisabled: boolean;
|
|
39
|
+
/** Whether the tab is currently in a pressed state. */
|
|
40
|
+
isPressed: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Provides the behavior and accessibility implementation for a tab.
|
|
45
|
+
* When selected, the associated tab panel is shown.
|
|
46
|
+
*/
|
|
47
|
+
export function useTab<T>(
|
|
48
|
+
props: AriaTabProps,
|
|
49
|
+
state: TabListState<T>,
|
|
50
|
+
ref: RefObject<FocusableElement | null>,
|
|
51
|
+
): TabAria;
|
|
52
|
+
// Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
|
|
53
|
+
export function useTab<T>(
|
|
54
|
+
props: AriaTabProps,
|
|
55
|
+
state: TabListState<T>,
|
|
56
|
+
ref: RefObject<FocusableElement | null>,
|
|
57
|
+
slot: symbol | undefined,
|
|
58
|
+
): TabAria;
|
|
59
|
+
export function useTab(...args: any[]): TabAria {
|
|
60
|
+
const [user, slotArg] = splitSlot(args);
|
|
61
|
+
const slot = slotArg ?? S('useTab');
|
|
62
|
+
const props = user[0] as AriaTabProps;
|
|
63
|
+
const state = user[1] as TabListState<unknown>;
|
|
64
|
+
const ref = user[2] as RefObject<FocusableElement | null>;
|
|
65
|
+
|
|
66
|
+
let { key, isDisabled: propsDisabled, shouldSelectOnPressUp } = props;
|
|
67
|
+
let { selectionManager: manager, selectedKey } = state;
|
|
68
|
+
|
|
69
|
+
let isSelected = key === selectedKey;
|
|
70
|
+
|
|
71
|
+
let isDisabled = propsDisabled || state.isDisabled || state.selectionManager.isDisabled(key);
|
|
72
|
+
let item = state.collection.getItem(key);
|
|
73
|
+
let { itemProps, isPressed } = useSelectableItem(
|
|
74
|
+
{
|
|
75
|
+
selectionManager: manager,
|
|
76
|
+
key,
|
|
77
|
+
ref,
|
|
78
|
+
isDisabled,
|
|
79
|
+
// Link tabs should behave like native anchors (navigate on press up)
|
|
80
|
+
// This avoids reopening beforeunload dialogs when browsers replay
|
|
81
|
+
// queued pointer enter/leave events after cancellation.
|
|
82
|
+
shouldSelectOnPressUp: shouldSelectOnPressUp ?? item?.props.href != null,
|
|
83
|
+
linkBehavior: 'selection',
|
|
84
|
+
},
|
|
85
|
+
subSlot(slot, 'item'),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
let tabId = generateId(state, key, 'tab');
|
|
89
|
+
let tabPanelId = generateId(state, key, 'tabpanel');
|
|
90
|
+
let { tabIndex } = itemProps;
|
|
91
|
+
|
|
92
|
+
let domProps = filterDOMProps(item?.props, { labelable: true });
|
|
93
|
+
delete domProps.id;
|
|
94
|
+
let linkProps = useLinkProps(item?.props);
|
|
95
|
+
let { focusableProps } = useFocusable(
|
|
96
|
+
{
|
|
97
|
+
...item?.props,
|
|
98
|
+
isDisabled,
|
|
99
|
+
},
|
|
100
|
+
ref,
|
|
101
|
+
subSlot(slot, 'focusable'),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
tabProps: mergeProps(domProps, focusableProps, linkProps, itemProps, {
|
|
106
|
+
id: tabId,
|
|
107
|
+
'aria-selected': isSelected,
|
|
108
|
+
'aria-disabled': isDisabled || undefined,
|
|
109
|
+
'aria-controls': isSelected ? tabPanelId : undefined,
|
|
110
|
+
tabIndex: isDisabled ? undefined : tabIndex,
|
|
111
|
+
role: 'tab',
|
|
112
|
+
}),
|
|
113
|
+
isSelected,
|
|
114
|
+
isDisabled,
|
|
115
|
+
isPressed,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Ported from react-aria (source: .react-spectrum/packages/react-aria/src/tabs/useTabList.ts).
|
|
2
|
+
// octane adaptations:
|
|
3
|
+
// - `DOMAttributes` is a local structural prop-bag alias (upstream's is typed over React's
|
|
4
|
+
// synthetic handlers); `TabListProps`/`TabListState` from the ported stately tabs state.
|
|
5
|
+
// - Public-hook slot threading (splitSlot/subSlot) per the binding convention; the
|
|
6
|
+
// explicit `useMemo` dependency array is kept verbatim.
|
|
7
|
+
import type { AriaLabelingProps, DOMProps, Orientation, RefObject } from '@react-types/shared';
|
|
8
|
+
import { mergeProps } from '../utils/mergeProps';
|
|
9
|
+
import type { TabListProps, TabListState } from '../stately/tabs/useTabListState';
|
|
10
|
+
import { tabsIds } from './utils';
|
|
11
|
+
import { TabsKeyboardDelegate } from './TabsKeyboardDelegate';
|
|
12
|
+
import { useId } from '../utils/useId';
|
|
13
|
+
import { useLabels } from '../utils/useLabels';
|
|
14
|
+
import { useLocale } from '../i18n/I18nProvider';
|
|
15
|
+
import { useMemo } from 'octane';
|
|
16
|
+
import { useSelectableCollection } from '../selection/useSelectableCollection';
|
|
17
|
+
|
|
18
|
+
import { S, splitSlot, subSlot } from '../internal';
|
|
19
|
+
|
|
20
|
+
// octane adaptation: minimal structural DOMAttributes (upstream's drags React's synthetic
|
|
21
|
+
// handler types along).
|
|
22
|
+
type DOMAttributes = Record<string, any>;
|
|
23
|
+
|
|
24
|
+
export interface AriaTabListProps<T> extends TabListProps<T>, DOMProps, AriaLabelingProps {
|
|
25
|
+
/**
|
|
26
|
+
* Whether tabs are activated automatically on focus or manually.
|
|
27
|
+
*
|
|
28
|
+
* @default 'automatic'
|
|
29
|
+
*/
|
|
30
|
+
keyboardActivation?: 'automatic' | 'manual';
|
|
31
|
+
/**
|
|
32
|
+
* The orientation of the tabs.
|
|
33
|
+
*
|
|
34
|
+
* @default 'horizontal'
|
|
35
|
+
*/
|
|
36
|
+
orientation?: Orientation;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface AriaTabListOptions<T> extends Omit<AriaTabListProps<T>, 'children'> {}
|
|
40
|
+
|
|
41
|
+
export interface TabListAria {
|
|
42
|
+
/** Props for the tablist container. */
|
|
43
|
+
tabListProps: DOMAttributes;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Provides the behavior and accessibility implementation for a tab list.
|
|
48
|
+
* Tabs organize content into multiple sections and allow users to navigate between them.
|
|
49
|
+
*/
|
|
50
|
+
export function useTabList<T>(
|
|
51
|
+
props: AriaTabListOptions<T>,
|
|
52
|
+
state: TabListState<T>,
|
|
53
|
+
ref: RefObject<HTMLElement | null>,
|
|
54
|
+
): TabListAria;
|
|
55
|
+
// Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
|
|
56
|
+
export function useTabList<T>(
|
|
57
|
+
props: AriaTabListOptions<T>,
|
|
58
|
+
state: TabListState<T>,
|
|
59
|
+
ref: RefObject<HTMLElement | null>,
|
|
60
|
+
slot: symbol | undefined,
|
|
61
|
+
): TabListAria;
|
|
62
|
+
export function useTabList(...args: any[]): TabListAria {
|
|
63
|
+
const [user, slotArg] = splitSlot(args);
|
|
64
|
+
const slot = slotArg ?? S('useTabList');
|
|
65
|
+
const props = user[0] as AriaTabListOptions<unknown>;
|
|
66
|
+
const state = user[1] as TabListState<unknown>;
|
|
67
|
+
const ref = user[2] as RefObject<HTMLElement | null>;
|
|
68
|
+
|
|
69
|
+
let { orientation = 'horizontal', keyboardActivation = 'automatic' } = props;
|
|
70
|
+
let { collection, selectionManager: manager, disabledKeys } = state;
|
|
71
|
+
let { direction } = useLocale(subSlot(slot, 'locale'));
|
|
72
|
+
let delegate = useMemo(
|
|
73
|
+
() => new TabsKeyboardDelegate(collection, direction, orientation, disabledKeys),
|
|
74
|
+
[collection, disabledKeys, orientation, direction],
|
|
75
|
+
subSlot(slot, 'delegate'),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
let { collectionProps } = useSelectableCollection(
|
|
79
|
+
{
|
|
80
|
+
ref,
|
|
81
|
+
selectionManager: manager,
|
|
82
|
+
keyboardDelegate: delegate,
|
|
83
|
+
selectOnFocus: keyboardActivation === 'automatic',
|
|
84
|
+
disallowEmptySelection: true,
|
|
85
|
+
scrollRef: ref,
|
|
86
|
+
linkBehavior: 'selection',
|
|
87
|
+
},
|
|
88
|
+
subSlot(slot, 'collection'),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Compute base id for all tabs
|
|
92
|
+
let tabsId = useId(subSlot(slot, 'tabsId'));
|
|
93
|
+
tabsIds.set(state, tabsId);
|
|
94
|
+
|
|
95
|
+
let tabListLabelProps = useLabels({ ...props, id: tabsId }, undefined, subSlot(slot, 'labels'));
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
tabListProps: {
|
|
99
|
+
...mergeProps(collectionProps, tabListLabelProps),
|
|
100
|
+
role: 'tablist',
|
|
101
|
+
'aria-orientation': orientation,
|
|
102
|
+
tabIndex: undefined,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Ported from react-aria (source: .react-spectrum/packages/react-aria/src/tabs/useTabPanel.ts).
|
|
2
|
+
// octane adaptations: `DOMAttributes` is a local structural prop-bag alias (upstream's is
|
|
3
|
+
// typed over React's synthetic handlers); `TabListState` from the ported stately tabs state;
|
|
4
|
+
// public-hook slot threading (splitSlot/subSlot) per the binding convention.
|
|
5
|
+
import type { AriaLabelingProps, DOMProps, Key, RefObject } from '@react-types/shared';
|
|
6
|
+
import { generateId } from './utils';
|
|
7
|
+
import { mergeProps } from '../utils/mergeProps';
|
|
8
|
+
import type { TabListState } from '../stately/tabs/useTabListState';
|
|
9
|
+
import { useHasTabbableChild } from '../focus/useHasTabbableChild';
|
|
10
|
+
import { useLabels } from '../utils/useLabels';
|
|
11
|
+
|
|
12
|
+
import { S, splitSlot, subSlot } from '../internal';
|
|
13
|
+
|
|
14
|
+
// octane adaptation: minimal structural DOMAttributes (upstream's drags React's synthetic
|
|
15
|
+
// handler types along).
|
|
16
|
+
type DOMAttributes = Record<string, any>;
|
|
17
|
+
|
|
18
|
+
export interface AriaTabPanelProps extends Omit<DOMProps, 'id'>, AriaLabelingProps {
|
|
19
|
+
/** The unique id of the tab. */
|
|
20
|
+
id?: Key;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TabPanelAria {
|
|
24
|
+
/** Props for the tab panel element. */
|
|
25
|
+
tabPanelProps: DOMAttributes;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Provides the behavior and accessibility implementation for a tab panel. A tab panel is a
|
|
30
|
+
* container for the contents of a tab, and is shown when the tab is selected.
|
|
31
|
+
*/
|
|
32
|
+
export function useTabPanel<T>(
|
|
33
|
+
props: AriaTabPanelProps,
|
|
34
|
+
state: TabListState<T> | null,
|
|
35
|
+
ref: RefObject<Element | null>,
|
|
36
|
+
): TabPanelAria;
|
|
37
|
+
// Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
|
|
38
|
+
export function useTabPanel<T>(
|
|
39
|
+
props: AriaTabPanelProps,
|
|
40
|
+
state: TabListState<T> | null,
|
|
41
|
+
ref: RefObject<Element | null>,
|
|
42
|
+
slot: symbol | undefined,
|
|
43
|
+
): TabPanelAria;
|
|
44
|
+
export function useTabPanel(...args: any[]): TabPanelAria {
|
|
45
|
+
const [user, slotArg] = splitSlot(args);
|
|
46
|
+
const slot = slotArg ?? S('useTabPanel');
|
|
47
|
+
const props = user[0] as AriaTabPanelProps;
|
|
48
|
+
const state = user[1] as TabListState<unknown> | null;
|
|
49
|
+
const ref = user[2] as RefObject<Element | null>;
|
|
50
|
+
|
|
51
|
+
// The tabpanel should have tabIndex=0 when there are no tabbable elements within it.
|
|
52
|
+
// Otherwise, tabbing from the focused tab should go directly to the first tabbable element
|
|
53
|
+
// within the tabpanel.
|
|
54
|
+
let tabIndex = useHasTabbableChild(ref, undefined, subSlot(slot, 'tabbable')) ? undefined : 0;
|
|
55
|
+
|
|
56
|
+
const id = generateId(state, props.id ?? state?.selectedKey, 'tabpanel');
|
|
57
|
+
const tabPanelProps = useLabels(
|
|
58
|
+
{
|
|
59
|
+
...props,
|
|
60
|
+
id,
|
|
61
|
+
'aria-labelledby': generateId(state, state?.selectedKey, 'tab'),
|
|
62
|
+
},
|
|
63
|
+
undefined,
|
|
64
|
+
subSlot(slot, 'labels'),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
tabPanelProps: mergeProps(tabPanelProps, {
|
|
69
|
+
tabIndex,
|
|
70
|
+
role: 'tabpanel',
|
|
71
|
+
'aria-describedby': props['aria-describedby'],
|
|
72
|
+
'aria-details': props['aria-details'],
|
|
73
|
+
}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Ported from react-aria (source: .react-spectrum/packages/react-aria/src/tabs/utils.ts).
|
|
2
|
+
// octane adaptations: `TabListState` type from the ported stately tabs state (upstream:
|
|
3
|
+
// 'react-stately/useTabListState').
|
|
4
|
+
import type { Key } from '@react-types/shared';
|
|
5
|
+
import type { TabListState } from '../stately/tabs/useTabListState';
|
|
6
|
+
|
|
7
|
+
export const tabsIds: WeakMap<TabListState<unknown>, string> = new WeakMap<
|
|
8
|
+
TabListState<unknown>,
|
|
9
|
+
string
|
|
10
|
+
>();
|
|
11
|
+
|
|
12
|
+
export function generateId<T>(
|
|
13
|
+
state: TabListState<T> | null,
|
|
14
|
+
key: Key | null | undefined,
|
|
15
|
+
role: string,
|
|
16
|
+
): string {
|
|
17
|
+
if (!state) {
|
|
18
|
+
// this case should only happen in the first render before the tabs are registered
|
|
19
|
+
return '';
|
|
20
|
+
}
|
|
21
|
+
if (typeof key === 'string') {
|
|
22
|
+
key = key.replace(/\s+/g, '');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let baseId = tabsIds.get(state);
|
|
26
|
+
if (process.env.NODE_ENV !== 'production' && !baseId) {
|
|
27
|
+
console.error(
|
|
28
|
+
'There is no tab id, please check if you have rendered the tab panel before the tab list.',
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return `${baseId}-${role}-${key}`;
|
|
32
|
+
}
|