@proyecto-viviana/solidaria 0.3.0 → 0.4.1
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/dist/_chunk/DragManager.js +627 -0
- package/dist/_chunk/DragManager.js.map +1 -0
- package/dist/_chunk/DragManager.jsx +627 -0
- package/dist/_chunk/DragManager.jsx.map +1 -0
- package/dist/_chunk/FocusScope.js +400 -0
- package/dist/_chunk/FocusScope.js.map +1 -0
- package/dist/_chunk/FocusScope.jsx +375 -0
- package/dist/_chunk/FocusScope.jsx.map +1 -0
- package/dist/_chunk/actiongroup.js +141 -0
- package/dist/_chunk/actiongroup.js.map +1 -0
- package/dist/_chunk/actiongroup.jsx +141 -0
- package/dist/_chunk/actiongroup.jsx.map +1 -0
- package/dist/_chunk/announce.js +207 -0
- package/dist/_chunk/announce.js.map +1 -0
- package/dist/_chunk/announce.jsx +207 -0
- package/dist/_chunk/announce.jsx.map +1 -0
- package/dist/_chunk/ariaHideOutside.js +122 -0
- package/dist/_chunk/ariaHideOutside.js.map +1 -0
- package/dist/_chunk/ariaHideOutside.jsx +122 -0
- package/dist/_chunk/ariaHideOutside.jsx.map +1 -0
- package/dist/_chunk/autocomplete.js +244 -0
- package/dist/_chunk/autocomplete.js.map +1 -0
- package/dist/_chunk/autocomplete.jsx +244 -0
- package/dist/_chunk/autocomplete.jsx.map +1 -0
- package/dist/_chunk/breadcrumbs.js +121 -0
- package/dist/_chunk/breadcrumbs.js.map +1 -0
- package/dist/_chunk/breadcrumbs.jsx +121 -0
- package/dist/_chunk/breadcrumbs.jsx.map +1 -0
- package/dist/_chunk/button.js +275 -0
- package/dist/_chunk/button.js.map +1 -0
- package/dist/_chunk/button.jsx +275 -0
- package/dist/_chunk/button.jsx.map +1 -0
- package/dist/_chunk/calendar.js +1037 -0
- package/dist/_chunk/calendar.js.map +1 -0
- package/dist/_chunk/calendar.jsx +1037 -0
- package/dist/_chunk/calendar.jsx.map +1 -0
- package/dist/_chunk/checkbox.js +235 -0
- package/dist/_chunk/checkbox.js.map +1 -0
- package/dist/_chunk/checkbox.jsx +235 -0
- package/dist/_chunk/checkbox.jsx.map +1 -0
- package/dist/_chunk/color.js +1458 -0
- package/dist/_chunk/color.js.map +1 -0
- package/dist/_chunk/color.jsx +1458 -0
- package/dist/_chunk/color.jsx.map +1 -0
- package/dist/_chunk/combobox.js +1062 -0
- package/dist/_chunk/combobox.js.map +1 -0
- package/dist/_chunk/combobox.jsx +1062 -0
- package/dist/_chunk/combobox.jsx.map +1 -0
- package/dist/_chunk/constants.js +19 -0
- package/dist/_chunk/constants.js.map +1 -0
- package/dist/_chunk/constants.jsx +19 -0
- package/dist/_chunk/constants.jsx.map +1 -0
- package/dist/_chunk/createCollator.js +61 -0
- package/dist/_chunk/createCollator.js.map +1 -0
- package/dist/_chunk/createCollator.jsx +61 -0
- package/dist/_chunk/createCollator.jsx.map +1 -0
- package/dist/_chunk/createCollectionRowInteraction.js +133 -0
- package/dist/_chunk/createCollectionRowInteraction.js.map +1 -0
- package/dist/_chunk/createCollectionRowInteraction.jsx +133 -0
- package/dist/_chunk/createCollectionRowInteraction.jsx.map +1 -0
- package/dist/_chunk/createField.js +55 -0
- package/dist/_chunk/createField.js.map +1 -0
- package/dist/_chunk/createField.jsx +55 -0
- package/dist/_chunk/createField.jsx.map +1 -0
- package/dist/_chunk/createFocus.js +105 -0
- package/dist/_chunk/createFocus.js.map +1 -0
- package/dist/_chunk/createFocus.jsx +105 -0
- package/dist/_chunk/createFocus.jsx.map +1 -0
- package/dist/_chunk/createFocusRing.js +54 -0
- package/dist/_chunk/createFocusRing.js.map +1 -0
- package/dist/_chunk/createFocusRing.jsx +54 -0
- package/dist/_chunk/createFocusRing.jsx.map +1 -0
- package/dist/_chunk/createFocusWithin.js +120 -0
- package/dist/_chunk/createFocusWithin.js.map +1 -0
- package/dist/_chunk/createFocusWithin.jsx +120 -0
- package/dist/_chunk/createFocusWithin.jsx.map +1 -0
- package/dist/_chunk/createFocusable.js +131 -0
- package/dist/_chunk/createFocusable.js.map +1 -0
- package/dist/_chunk/createFocusable.jsx +131 -0
- package/dist/_chunk/createFocusable.jsx.map +1 -0
- package/dist/_chunk/createFormReset.js +39 -0
- package/dist/_chunk/createFormReset.js.map +1 -0
- package/dist/_chunk/createFormReset.jsx +39 -0
- package/dist/_chunk/createFormReset.jsx.map +1 -0
- package/dist/_chunk/createFormValidation.js +135 -0
- package/dist/_chunk/createFormValidation.js.map +1 -0
- package/dist/_chunk/createFormValidation.jsx +135 -0
- package/dist/_chunk/createFormValidation.jsx.map +1 -0
- package/dist/_chunk/createHover.js +131 -0
- package/dist/_chunk/createHover.js.map +1 -0
- package/dist/_chunk/createHover.jsx +131 -0
- package/dist/_chunk/createHover.jsx.map +1 -0
- package/dist/_chunk/createInteractionModality.js +268 -0
- package/dist/_chunk/createInteractionModality.js.map +1 -0
- package/dist/_chunk/createInteractionModality.jsx +268 -0
- package/dist/_chunk/createInteractionModality.jsx.map +1 -0
- package/dist/_chunk/createLabel.js +47 -0
- package/dist/_chunk/createLabel.js.map +1 -0
- package/dist/_chunk/createLabel.jsx +47 -0
- package/dist/_chunk/createLabel.jsx.map +1 -0
- package/dist/_chunk/createLabels.js +32 -0
- package/dist/_chunk/createLabels.js.map +1 -0
- package/dist/_chunk/createLabels.jsx +32 -0
- package/dist/_chunk/createLabels.jsx.map +1 -0
- package/dist/_chunk/createLandmark.js +198 -0
- package/dist/_chunk/createLandmark.js.map +1 -0
- package/dist/_chunk/createLandmark.jsx +198 -0
- package/dist/_chunk/createLandmark.jsx.map +1 -0
- package/dist/_chunk/createOverlay.js +327 -0
- package/dist/_chunk/createOverlay.js.map +1 -0
- package/dist/_chunk/createOverlay.jsx +327 -0
- package/dist/_chunk/createOverlay.jsx.map +1 -0
- package/dist/_chunk/createPress.js +526 -0
- package/dist/_chunk/createPress.js.map +1 -0
- package/dist/_chunk/createPress.jsx +526 -0
- package/dist/_chunk/createPress.jsx.map +1 -0
- package/dist/_chunk/createProgressBar.js +82 -0
- package/dist/_chunk/createProgressBar.js.map +1 -0
- package/dist/_chunk/createProgressBar.jsx +82 -0
- package/dist/_chunk/createProgressBar.jsx.map +1 -0
- package/dist/_chunk/createSelectableItem.js +302 -0
- package/dist/_chunk/createSelectableItem.js.map +1 -0
- package/dist/_chunk/createSelectableItem.jsx +302 -0
- package/dist/_chunk/createSelectableItem.jsx.map +1 -0
- package/dist/_chunk/createStringFormatter.js +61 -0
- package/dist/_chunk/createStringFormatter.js.map +1 -0
- package/dist/_chunk/createStringFormatter.jsx +61 -0
- package/dist/_chunk/createStringFormatter.jsx.map +1 -0
- package/dist/_chunk/createToggle.js +159 -0
- package/dist/_chunk/createToggle.js.map +1 -0
- package/dist/_chunk/createToggle.jsx +159 -0
- package/dist/_chunk/createToggle.jsx.map +1 -0
- package/dist/_chunk/createTypeSelect.js +125 -0
- package/dist/_chunk/createTypeSelect.js.map +1 -0
- package/dist/_chunk/createTypeSelect.jsx +125 -0
- package/dist/_chunk/createTypeSelect.jsx.map +1 -0
- package/dist/_chunk/datepicker.js +1706 -0
- package/dist/_chunk/datepicker.js.map +1 -0
- package/dist/_chunk/datepicker.jsx +1706 -0
- package/dist/_chunk/datepicker.jsx.map +1 -0
- package/dist/_chunk/dialog.js +62 -0
- package/dist/_chunk/dialog.js.map +1 -0
- package/dist/_chunk/dialog.jsx +62 -0
- package/dist/_chunk/dialog.jsx.map +1 -0
- package/dist/_chunk/disclosure.js +185 -0
- package/dist/_chunk/disclosure.js.map +1 -0
- package/dist/_chunk/disclosure.jsx +185 -0
- package/dist/_chunk/disclosure.jsx.map +1 -0
- package/dist/_chunk/dnd.js +2395 -0
- package/dist/_chunk/dnd.js.map +1 -0
- package/dist/_chunk/dnd.jsx +2395 -0
- package/dist/_chunk/dnd.jsx.map +1 -0
- package/dist/_chunk/env.js +87 -0
- package/dist/_chunk/env.js.map +1 -0
- package/dist/_chunk/env.jsx +87 -0
- package/dist/_chunk/env.jsx.map +1 -0
- package/dist/_chunk/filterDOMProps.js +82 -0
- package/dist/_chunk/filterDOMProps.js.map +1 -0
- package/dist/_chunk/filterDOMProps.jsx +82 -0
- package/dist/_chunk/filterDOMProps.jsx.map +1 -0
- package/dist/_chunk/focus.js +399 -0
- package/dist/_chunk/focus.js.map +1 -0
- package/dist/_chunk/focus.jsx +399 -0
- package/dist/_chunk/focus.jsx.map +1 -0
- package/dist/_chunk/focus2.js +631 -0
- package/dist/_chunk/focus2.js.map +1 -0
- package/dist/_chunk/focus2.jsx +631 -0
- package/dist/_chunk/focus2.jsx.map +1 -0
- package/dist/_chunk/grid.js +623 -0
- package/dist/_chunk/grid.js.map +1 -0
- package/dist/_chunk/grid.jsx +623 -0
- package/dist/_chunk/grid.jsx.map +1 -0
- package/dist/_chunk/gridlist.js +369 -0
- package/dist/_chunk/gridlist.js.map +1 -0
- package/dist/_chunk/gridlist.jsx +369 -0
- package/dist/_chunk/gridlist.jsx.map +1 -0
- package/dist/_chunk/i18n.js +199 -0
- package/dist/_chunk/i18n.js.map +1 -0
- package/dist/_chunk/i18n.jsx +199 -0
- package/dist/_chunk/i18n.jsx.map +1 -0
- package/dist/_chunk/interactions.js +331 -0
- package/dist/_chunk/interactions.js.map +1 -0
- package/dist/_chunk/interactions.jsx +325 -0
- package/dist/_chunk/interactions.jsx.map +1 -0
- package/dist/_chunk/link.js +97 -0
- package/dist/_chunk/link.js.map +1 -0
- package/dist/_chunk/link.jsx +97 -0
- package/dist/_chunk/link.jsx.map +1 -0
- package/dist/_chunk/listbox.js +356 -0
- package/dist/_chunk/listbox.js.map +1 -0
- package/dist/_chunk/listbox.jsx +356 -0
- package/dist/_chunk/listbox.jsx.map +1 -0
- package/dist/_chunk/locale.js +173 -0
- package/dist/_chunk/locale.js.map +1 -0
- package/dist/_chunk/locale.jsx +167 -0
- package/dist/_chunk/locale.jsx.map +1 -0
- package/dist/_chunk/menu.js +519 -0
- package/dist/_chunk/menu.js.map +1 -0
- package/dist/_chunk/menu.jsx +519 -0
- package/dist/_chunk/menu.jsx.map +1 -0
- package/dist/_chunk/meter.js +33 -0
- package/dist/_chunk/meter.js.map +1 -0
- package/dist/_chunk/meter.jsx +33 -0
- package/dist/_chunk/meter.jsx.map +1 -0
- package/dist/_chunk/numberfield.js +259 -0
- package/dist/_chunk/numberfield.js.map +1 -0
- package/dist/_chunk/numberfield.jsx +259 -0
- package/dist/_chunk/numberfield.jsx.map +1 -0
- package/dist/_chunk/overlays.js +186 -0
- package/dist/_chunk/overlays.js.map +1 -0
- package/dist/_chunk/overlays.jsx +162 -0
- package/dist/_chunk/overlays.jsx.map +1 -0
- package/dist/_chunk/popover.js +574 -0
- package/dist/_chunk/popover.js.map +1 -0
- package/dist/_chunk/popover.jsx +574 -0
- package/dist/_chunk/popover.jsx.map +1 -0
- package/dist/_chunk/radio.js +320 -0
- package/dist/_chunk/radio.js.map +1 -0
- package/dist/_chunk/radio.jsx +320 -0
- package/dist/_chunk/radio.jsx.map +1 -0
- package/dist/_chunk/reactivity.js +21 -0
- package/dist/_chunk/reactivity.js.map +1 -0
- package/dist/_chunk/reactivity.jsx +21 -0
- package/dist/_chunk/reactivity.jsx.map +1 -0
- package/dist/_chunk/searchfield.js +210 -0
- package/dist/_chunk/searchfield.js.map +1 -0
- package/dist/_chunk/searchfield.jsx +210 -0
- package/dist/_chunk/searchfield.jsx.map +1 -0
- package/dist/_chunk/select.js +406 -0
- package/dist/_chunk/select.js.map +1 -0
- package/dist/_chunk/select.jsx +397 -0
- package/dist/_chunk/select.jsx.map +1 -0
- package/dist/_chunk/selection.js +666 -0
- package/dist/_chunk/selection.js.map +1 -0
- package/dist/_chunk/selection.jsx +666 -0
- package/dist/_chunk/selection.jsx.map +1 -0
- package/dist/_chunk/separator.js +29 -0
- package/dist/_chunk/separator.js.map +1 -0
- package/dist/_chunk/separator.jsx +29 -0
- package/dist/_chunk/separator.jsx.map +1 -0
- package/dist/_chunk/slider.js +256 -0
- package/dist/_chunk/slider.js.map +1 -0
- package/dist/_chunk/slider.jsx +256 -0
- package/dist/_chunk/slider.jsx.map +1 -0
- package/dist/_chunk/spinbutton.js +153 -0
- package/dist/_chunk/spinbutton.js.map +1 -0
- package/dist/_chunk/spinbutton.jsx +153 -0
- package/dist/_chunk/spinbutton.jsx.map +1 -0
- package/dist/_chunk/steplist.js +66 -0
- package/dist/_chunk/steplist.js.map +1 -0
- package/dist/_chunk/steplist.jsx +66 -0
- package/dist/_chunk/steplist.jsx.map +1 -0
- package/dist/_chunk/switch.js +34 -0
- package/dist/_chunk/switch.js.map +1 -0
- package/dist/_chunk/switch.jsx +34 -0
- package/dist/_chunk/switch.jsx.map +1 -0
- package/dist/_chunk/table.js +1088 -0
- package/dist/_chunk/table.js.map +1 -0
- package/dist/_chunk/table.jsx +1088 -0
- package/dist/_chunk/table.jsx.map +1 -0
- package/dist/_chunk/tabs.js +263 -0
- package/dist/_chunk/tabs.js.map +1 -0
- package/dist/_chunk/tabs.jsx +263 -0
- package/dist/_chunk/tabs.jsx.map +1 -0
- package/dist/_chunk/tag.js +322 -0
- package/dist/_chunk/tag.js.map +1 -0
- package/dist/_chunk/tag.jsx +322 -0
- package/dist/_chunk/tag.jsx.map +1 -0
- package/dist/_chunk/textfield.js +110 -0
- package/dist/_chunk/textfield.js.map +1 -0
- package/dist/_chunk/textfield.jsx +110 -0
- package/dist/_chunk/textfield.jsx.map +1 -0
- package/dist/_chunk/toast.js +250 -0
- package/dist/_chunk/toast.js.map +1 -0
- package/dist/_chunk/toast.jsx +250 -0
- package/dist/_chunk/toast.jsx.map +1 -0
- package/dist/_chunk/toolbar.js +226 -0
- package/dist/_chunk/toolbar.js.map +1 -0
- package/dist/_chunk/toolbar.jsx +226 -0
- package/dist/_chunk/toolbar.jsx.map +1 -0
- package/dist/_chunk/tooltip.js +185 -0
- package/dist/_chunk/tooltip.js.map +1 -0
- package/dist/_chunk/tooltip.jsx +185 -0
- package/dist/_chunk/tooltip.jsx.map +1 -0
- package/dist/_chunk/tree.js +452 -0
- package/dist/_chunk/tree.js.map +1 -0
- package/dist/_chunk/tree.jsx +452 -0
- package/dist/_chunk/tree.jsx.map +1 -0
- package/dist/_chunk/utils.js +705 -0
- package/dist/_chunk/utils.js.map +1 -0
- package/dist/_chunk/utils.jsx +705 -0
- package/dist/_chunk/utils.jsx.map +1 -0
- package/dist/_chunk/visually-hidden.js +93 -0
- package/dist/_chunk/visually-hidden.js.map +1 -0
- package/dist/_chunk/visually-hidden.jsx +93 -0
- package/dist/_chunk/visually-hidden.jsx.map +1 -0
- package/dist/actiongroup/createActionGroup.d.ts.map +1 -1
- package/dist/actiongroup/index.js +2 -0
- package/dist/actiongroup/index.jsx +2 -0
- package/dist/autocomplete/createAutocomplete.d.ts +12 -7
- package/dist/autocomplete/createAutocomplete.d.ts.map +1 -1
- package/dist/autocomplete/index.js +2 -0
- package/dist/autocomplete/index.jsx +2 -0
- package/dist/breadcrumbs/createBreadcrumbs.d.ts.map +1 -1
- package/dist/breadcrumbs/index.js +2 -0
- package/dist/breadcrumbs/index.jsx +2 -0
- package/dist/button/createToggleButtonGroup.d.ts.map +1 -1
- package/dist/button/index.js +2 -0
- package/dist/button/index.jsx +2 -0
- package/dist/calendar/createCalendar.d.ts.map +1 -1
- package/dist/calendar/createCalendarCell.d.ts.map +1 -1
- package/dist/calendar/createCalendarGrid.d.ts.map +1 -1
- package/dist/calendar/createCalendarMonthPicker.d.ts +41 -0
- package/dist/calendar/createCalendarMonthPicker.d.ts.map +1 -0
- package/dist/calendar/createCalendarYearPicker.d.ts +49 -0
- package/dist/calendar/createCalendarYearPicker.d.ts.map +1 -0
- package/dist/calendar/createRangeCalendar.d.ts.map +1 -1
- package/dist/calendar/createRangeCalendarCell.d.ts.map +1 -1
- package/dist/calendar/index.d.ts +2 -0
- package/dist/calendar/index.d.ts.map +1 -1
- package/dist/calendar/index.js +2 -0
- package/dist/calendar/index.jsx +2 -0
- package/dist/calendar/intl/index.d.ts +1 -1
- package/dist/calendar/intl/index.d.ts.map +1 -1
- package/dist/calendar/utils.d.ts +4 -0
- package/dist/calendar/utils.d.ts.map +1 -1
- package/dist/checkbox/createCheckbox.d.ts +4 -0
- package/dist/checkbox/createCheckbox.d.ts.map +1 -1
- package/dist/checkbox/createCheckboxGroupItem.d.ts.map +1 -1
- package/dist/checkbox/index.js +2 -0
- package/dist/checkbox/index.jsx +2 -0
- package/dist/collections/index.js +160 -0
- package/dist/collections/index.js.map +1 -0
- package/dist/collections/index.jsx +160 -0
- package/dist/collections/index.jsx.map +1 -0
- package/dist/color/createColorArea.d.ts.map +1 -1
- package/dist/color/createColorField.d.ts.map +1 -1
- package/dist/color/createColorSlider.d.ts.map +1 -1
- package/dist/color/createColorSwatch.d.ts.map +1 -1
- package/dist/color/createColorWheel.d.ts.map +1 -1
- package/dist/color/index.js +2 -0
- package/dist/color/index.jsx +2 -0
- package/dist/color/intl/index.d.ts +30 -0
- package/dist/color/intl/index.d.ts.map +1 -0
- package/dist/combobox/createComboBox.d.ts.map +1 -1
- package/dist/combobox/index.js +2 -0
- package/dist/combobox/index.jsx +2 -0
- package/dist/combobox/intl/generated-locales.d.ts +16 -0
- package/dist/combobox/intl/generated-locales.d.ts.map +1 -0
- package/dist/combobox/intl/index.d.ts +2 -2
- package/dist/combobox/intl/index.d.ts.map +1 -1
- package/dist/datepicker/createDateField.d.ts +45 -23
- package/dist/datepicker/createDateField.d.ts.map +1 -1
- package/dist/datepicker/createDatePicker.d.ts +34 -6
- package/dist/datepicker/createDatePicker.d.ts.map +1 -1
- package/dist/datepicker/createDatePickerGroup.d.ts +13 -13
- package/dist/datepicker/createDatePickerGroup.d.ts.map +1 -1
- package/dist/datepicker/createDateRangePicker.d.ts +55 -7
- package/dist/datepicker/createDateRangePicker.d.ts.map +1 -1
- package/dist/datepicker/createDateSegment.d.ts +6 -15
- package/dist/datepicker/createDateSegment.d.ts.map +1 -1
- package/dist/datepicker/createDisplayNames.d.ts +17 -0
- package/dist/datepicker/createDisplayNames.d.ts.map +1 -0
- package/dist/datepicker/createTimeField.d.ts +12 -49
- package/dist/datepicker/createTimeField.d.ts.map +1 -1
- package/dist/datepicker/index.d.ts +3 -3
- package/dist/datepicker/index.d.ts.map +1 -1
- package/dist/datepicker/index.js +2 -0
- package/dist/datepicker/index.jsx +2 -0
- package/dist/datepicker/intl.d.ts +12 -0
- package/dist/datepicker/intl.d.ts.map +1 -0
- package/dist/dialog/index.js +2 -0
- package/dist/dialog/index.jsx +2 -0
- package/dist/disclosure/index.js +2 -0
- package/dist/disclosure/index.jsx +2 -0
- package/dist/dnd/DragManager.d.ts +86 -0
- package/dist/dnd/DragManager.d.ts.map +1 -0
- package/dist/dnd/DropTargetKeyboardNavigation.d.ts +42 -0
- package/dist/dnd/DropTargetKeyboardNavigation.d.ts.map +1 -0
- package/dist/dnd/createDrag.d.ts.map +1 -1
- package/dist/dnd/createDraggableCollection.d.ts.map +1 -1
- package/dist/dnd/createDraggableItem.d.ts +12 -7
- package/dist/dnd/createDraggableItem.d.ts.map +1 -1
- package/dist/dnd/createDroppableCollection.d.ts +7 -15
- package/dist/dnd/createDroppableCollection.d.ts.map +1 -1
- package/dist/dnd/index.d.ts +5 -1
- package/dist/dnd/index.d.ts.map +1 -1
- package/dist/dnd/index.js +3 -0
- package/dist/dnd/index.jsx +3 -0
- package/dist/dnd/intl/index.d.ts +39 -0
- package/dist/dnd/intl/index.d.ts.map +1 -0
- package/dist/dnd/utils.d.ts +7 -2
- package/dist/dnd/utils.d.ts.map +1 -1
- package/dist/focus/FocusScope.d.ts +7 -0
- package/dist/focus/FocusScope.d.ts.map +1 -1
- package/dist/focus/index.d.ts +2 -1
- package/dist/focus/index.d.ts.map +1 -1
- package/dist/focus/index.js +3 -0
- package/dist/focus/index.jsx +3 -0
- package/dist/focus/virtualFocus.d.ts +26 -0
- package/dist/focus/virtualFocus.d.ts.map +1 -0
- package/dist/form/createFormValidation.d.ts.map +1 -1
- package/dist/form/index.js +3 -0
- package/dist/form/index.jsx +3 -0
- package/dist/grid/index.js +2 -0
- package/dist/grid/index.jsx +2 -0
- package/dist/gridlist/createGridList.d.ts +7 -1
- package/dist/gridlist/createGridList.d.ts.map +1 -1
- package/dist/gridlist/createGridListItem.d.ts +1 -1
- package/dist/gridlist/createGridListItem.d.ts.map +1 -1
- package/dist/gridlist/createGridListSection.d.ts +15 -0
- package/dist/gridlist/createGridListSection.d.ts.map +1 -0
- package/dist/gridlist/index.d.ts +2 -1
- package/dist/gridlist/index.d.ts.map +1 -1
- package/dist/gridlist/index.js +2 -0
- package/dist/gridlist/index.jsx +2 -0
- package/dist/gridlist/types.d.ts +50 -0
- package/dist/gridlist/types.d.ts.map +1 -1
- package/dist/i18n/index.js +5 -0
- package/dist/i18n/index.jsx +5 -0
- package/dist/index.d.ts +10 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +77 -18311
- package/dist/index.jsx +77 -18242
- package/dist/interactions/FocusableProvider.d.ts.map +1 -1
- package/dist/interactions/PressEvent.d.ts +11 -0
- package/dist/interactions/PressEvent.d.ts.map +1 -1
- package/dist/interactions/createFocus.d.ts.map +1 -1
- package/dist/interactions/createFocusWithin.d.ts.map +1 -1
- package/dist/interactions/createInteractionModality.d.ts +0 -1
- package/dist/interactions/createInteractionModality.d.ts.map +1 -1
- package/dist/interactions/createKeyboard.d.ts.map +1 -1
- package/dist/interactions/createPress.d.ts.map +1 -1
- package/dist/interactions/index.js +9 -0
- package/dist/interactions/index.jsx +9 -0
- package/dist/label/createLabels.d.ts.map +1 -1
- package/dist/label/index.js +4 -0
- package/dist/label/index.jsx +4 -0
- package/dist/landmark/index.js +2 -0
- package/dist/landmark/index.jsx +2 -0
- package/dist/link/index.js +2 -0
- package/dist/link/index.jsx +2 -0
- package/dist/listbox/createListBox.d.ts +37 -0
- package/dist/listbox/createListBox.d.ts.map +1 -1
- package/dist/listbox/createOption.d.ts +7 -1
- package/dist/listbox/createOption.d.ts.map +1 -1
- package/dist/listbox/index.js +2 -0
- package/dist/listbox/index.jsx +2 -0
- package/dist/live-announcer/index.js +2 -0
- package/dist/live-announcer/index.jsx +2 -0
- package/dist/menu/createMenu.d.ts +7 -4
- package/dist/menu/createMenu.d.ts.map +1 -1
- package/dist/menu/createMenuItem.d.ts +9 -1
- package/dist/menu/createMenuItem.d.ts.map +1 -1
- package/dist/menu/index.js +2 -0
- package/dist/menu/index.jsx +2 -0
- package/dist/meter/index.js +2 -0
- package/dist/meter/index.jsx +2 -0
- package/dist/numberfield/createNumberField.d.ts.map +1 -1
- package/dist/numberfield/index.js +2 -0
- package/dist/numberfield/index.jsx +2 -0
- package/dist/overlays/index.js +4 -0
- package/dist/overlays/index.jsx +4 -0
- package/dist/popover/calculatePosition.d.ts +2 -0
- package/dist/popover/calculatePosition.d.ts.map +1 -1
- package/dist/popover/createOverlayPosition.d.ts +8 -0
- package/dist/popover/createOverlayPosition.d.ts.map +1 -1
- package/dist/popover/index.js +2 -0
- package/dist/popover/index.jsx +2 -0
- package/dist/progress/index.js +2 -0
- package/dist/progress/index.jsx +2 -0
- package/dist/radio/createRadio.d.ts +2 -0
- package/dist/radio/createRadio.d.ts.map +1 -1
- package/dist/radio/index.js +2 -0
- package/dist/radio/index.jsx +2 -0
- package/dist/searchfield/index.js +2 -0
- package/dist/searchfield/index.jsx +2 -0
- package/dist/select/createSelect.d.ts +2 -0
- package/dist/select/createSelect.d.ts.map +1 -1
- package/dist/select/index.js +2 -0
- package/dist/select/index.jsx +2 -0
- package/dist/selection/DOMLayoutDelegate.d.ts +58 -0
- package/dist/selection/DOMLayoutDelegate.d.ts.map +1 -0
- package/dist/selection/ListKeyboardDelegate.d.ts +95 -0
- package/dist/selection/ListKeyboardDelegate.d.ts.map +1 -0
- package/dist/selection/constants.d.ts +15 -0
- package/dist/selection/constants.d.ts.map +1 -0
- package/dist/selection/createCollectionRowInteraction.d.ts +13 -0
- package/dist/selection/createCollectionRowInteraction.d.ts.map +1 -0
- package/dist/selection/createScrollIntoViewOnFocus.d.ts +31 -0
- package/dist/selection/createScrollIntoViewOnFocus.d.ts.map +1 -0
- package/dist/selection/createSelectableCollection.d.ts +69 -0
- package/dist/selection/createSelectableCollection.d.ts.map +1 -0
- package/dist/selection/createSelectableItem.d.ts +154 -0
- package/dist/selection/createSelectableItem.d.ts.map +1 -0
- package/dist/selection/createSelectableList.d.ts +43 -0
- package/dist/selection/createSelectableList.d.ts.map +1 -0
- package/dist/selection/createTypeSelect.d.ts.map +1 -1
- package/dist/selection/index.d.ts +9 -0
- package/dist/selection/index.d.ts.map +1 -1
- package/dist/selection/index.js +5 -0
- package/dist/selection/index.jsx +5 -0
- package/dist/selection/selectItem.d.ts +29 -0
- package/dist/selection/selectItem.d.ts.map +1 -0
- package/dist/selection/utils.d.ts +40 -0
- package/dist/selection/utils.d.ts.map +1 -0
- package/dist/separator/index.js +2 -0
- package/dist/separator/index.jsx +2 -0
- package/dist/slider/createSlider.d.ts.map +1 -1
- package/dist/slider/index.js +2 -0
- package/dist/slider/index.jsx +2 -0
- package/dist/spinbutton/createSpinButton.d.ts +41 -0
- package/dist/spinbutton/createSpinButton.d.ts.map +1 -0
- package/dist/spinbutton/index.d.ts +3 -0
- package/dist/spinbutton/index.d.ts.map +1 -0
- package/dist/spinbutton/index.js +2 -0
- package/dist/spinbutton/index.jsx +2 -0
- package/dist/spinbutton/intl.d.ts +5 -0
- package/dist/spinbutton/intl.d.ts.map +1 -0
- package/dist/ssr/index.d.ts +17 -0
- package/dist/ssr/index.d.ts.map +1 -1
- package/dist/ssr/index.js +299 -0
- package/dist/ssr/index.js.map +1 -0
- package/dist/ssr/index.jsx +292 -0
- package/dist/ssr/index.jsx.map +1 -0
- package/dist/steplist/index.js +2 -0
- package/dist/steplist/index.jsx +2 -0
- package/dist/switch/createSwitch.d.ts +4 -0
- package/dist/switch/createSwitch.d.ts.map +1 -1
- package/dist/switch/index.js +2 -0
- package/dist/switch/index.jsx +2 -0
- package/dist/table/createTable.d.ts.map +1 -1
- package/dist/table/createTableColumnHeader.d.ts.map +1 -1
- package/dist/table/createTableRow.d.ts +1 -1
- package/dist/table/createTableRow.d.ts.map +1 -1
- package/dist/table/createTableSelectAllCheckbox.d.ts.map +1 -1
- package/dist/table/createTableSelectionCheckbox.d.ts.map +1 -1
- package/dist/table/index.js +2 -0
- package/dist/table/index.jsx +2 -0
- package/dist/table/types.d.ts +35 -1
- package/dist/table/types.d.ts.map +1 -1
- package/dist/table/utils.d.ts +15 -0
- package/dist/table/utils.d.ts.map +1 -0
- package/dist/tabs/createTabs.d.ts +5 -3
- package/dist/tabs/createTabs.d.ts.map +1 -1
- package/dist/tabs/index.js +2 -0
- package/dist/tabs/index.jsx +2 -0
- package/dist/tag/createTag.d.ts +2 -0
- package/dist/tag/createTag.d.ts.map +1 -1
- package/dist/tag/createTagGroup.d.ts +7 -0
- package/dist/tag/createTagGroup.d.ts.map +1 -1
- package/dist/tag/index.js +2 -0
- package/dist/tag/index.jsx +2 -0
- package/dist/textfield/index.js +2 -0
- package/dist/textfield/index.jsx +2 -0
- package/dist/toast/createToast.d.ts.map +1 -1
- package/dist/toast/index.js +2 -0
- package/dist/toast/index.jsx +2 -0
- package/dist/toggle/createToggle.d.ts +4 -0
- package/dist/toggle/createToggle.d.ts.map +1 -1
- package/dist/toggle/index.js +3 -0
- package/dist/toggle/index.jsx +3 -0
- package/dist/toolbar/createToolbar.d.ts +1 -1
- package/dist/toolbar/createToolbar.d.ts.map +1 -1
- package/dist/toolbar/index.js +2 -0
- package/dist/toolbar/index.jsx +2 -0
- package/dist/tooltip/index.js +2 -0
- package/dist/tooltip/index.jsx +2 -0
- package/dist/tree/createTree.d.ts +5 -1
- package/dist/tree/createTree.d.ts.map +1 -1
- package/dist/tree/createTreeItem.d.ts +1 -1
- package/dist/tree/createTreeItem.d.ts.map +1 -1
- package/dist/tree/createTreeSelectionCheckbox.d.ts.map +1 -1
- package/dist/tree/index.js +2 -0
- package/dist/tree/index.jsx +2 -0
- package/dist/tree/types.d.ts +10 -0
- package/dist/tree/types.d.ts.map +1 -1
- package/dist/utils/animation.d.ts +60 -0
- package/dist/utils/animation.d.ts.map +1 -0
- package/dist/utils/dom.d.ts +49 -2
- package/dist/utils/dom.d.ts.map +1 -1
- package/dist/utils/index.d.ts +4 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.jsx +6 -0
- package/dist/utils/keyboard.d.ts +17 -0
- package/dist/utils/keyboard.d.ts.map +1 -0
- package/dist/utils/mergeProps.d.ts.map +1 -1
- package/dist/utils/scrollIntoView.d.ts +30 -0
- package/dist/utils/scrollIntoView.d.ts.map +1 -0
- package/dist/visually-hidden/index.js +2 -0
- package/dist/visually-hidden/index.jsx +2 -0
- package/package.json +304 -3
- package/src/actiongroup/createActionGroup.ts +26 -109
- package/src/autocomplete/createAutocomplete.ts +202 -35
- package/src/breadcrumbs/createBreadcrumbs.ts +12 -4
- package/src/button/createToggleButtonGroup.ts +19 -14
- package/src/calendar/createCalendar.ts +5 -4
- package/src/calendar/createCalendarCell.ts +36 -5
- package/src/calendar/createCalendarGrid.ts +47 -12
- package/src/calendar/createCalendarMonthPicker.ts +105 -0
- package/src/calendar/createCalendarYearPicker.ts +144 -0
- package/src/calendar/createRangeCalendar.ts +27 -15
- package/src/calendar/createRangeCalendarCell.ts +17 -3
- package/src/calendar/index.ts +17 -0
- package/src/calendar/intl/index.ts +8 -0
- package/src/calendar/utils.ts +4 -0
- package/src/checkbox/createCheckbox.ts +10 -0
- package/src/checkbox/createCheckboxGroupItem.ts +12 -16
- package/src/color/createColorArea.ts +17 -10
- package/src/color/createColorField.ts +8 -1
- package/src/color/createColorSlider.ts +1 -2
- package/src/color/createColorSwatch.ts +4 -2
- package/src/color/createColorWheel.ts +0 -6
- package/src/color/intl/index.ts +316 -0
- package/src/combobox/createComboBox.ts +35 -4
- package/src/combobox/intl/generated-locales.ts +635 -0
- package/src/combobox/intl/index.ts +8 -2
- package/src/datepicker/createDateField.ts +228 -213
- package/src/datepicker/createDatePicker.ts +157 -146
- package/src/datepicker/createDatePickerGroup.ts +88 -82
- package/src/datepicker/createDateRangePicker.ts +230 -179
- package/src/datepicker/createDateSegment.ts +386 -384
- package/src/datepicker/createDisplayNames.ts +45 -0
- package/src/datepicker/createTimeField.ts +36 -129
- package/src/datepicker/index.ts +13 -14
- package/src/datepicker/intl.ts +633 -0
- package/src/dnd/DragManager.ts +693 -0
- package/src/dnd/DropTargetKeyboardNavigation.ts +337 -0
- package/src/dnd/createDrag.ts +31 -5
- package/src/dnd/createDraggableCollection.ts +33 -15
- package/src/dnd/createDraggableItem.ts +92 -5
- package/src/dnd/createDroppableCollection.ts +488 -371
- package/src/dnd/index.ts +11 -0
- package/src/dnd/intl/ar-AE.json +29 -0
- package/src/dnd/intl/bg-BG.json +29 -0
- package/src/dnd/intl/cs-CZ.json +29 -0
- package/src/dnd/intl/da-DK.json +29 -0
- package/src/dnd/intl/de-DE.json +29 -0
- package/src/dnd/intl/el-GR.json +29 -0
- package/src/dnd/intl/en-US.json +29 -0
- package/src/dnd/intl/es-ES.json +29 -0
- package/src/dnd/intl/et-EE.json +29 -0
- package/src/dnd/intl/fi-FI.json +29 -0
- package/src/dnd/intl/fr-FR.json +29 -0
- package/src/dnd/intl/he-IL.json +29 -0
- package/src/dnd/intl/hr-HR.json +29 -0
- package/src/dnd/intl/hu-HU.json +29 -0
- package/src/dnd/intl/index.ts +139 -0
- package/src/dnd/intl/it-IT.json +29 -0
- package/src/dnd/intl/ja-JP.json +29 -0
- package/src/dnd/intl/ko-KR.json +29 -0
- package/src/dnd/intl/lt-LT.json +29 -0
- package/src/dnd/intl/lv-LV.json +29 -0
- package/src/dnd/intl/nb-NO.json +29 -0
- package/src/dnd/intl/nl-NL.json +29 -0
- package/src/dnd/intl/pl-PL.json +29 -0
- package/src/dnd/intl/pt-BR.json +29 -0
- package/src/dnd/intl/pt-PT.json +29 -0
- package/src/dnd/intl/ro-RO.json +29 -0
- package/src/dnd/intl/ru-RU.json +29 -0
- package/src/dnd/intl/sk-SK.json +29 -0
- package/src/dnd/intl/sl-SI.json +29 -0
- package/src/dnd/intl/sr-SP.json +29 -0
- package/src/dnd/intl/sv-SE.json +29 -0
- package/src/dnd/intl/tr-TR.json +29 -0
- package/src/dnd/intl/uk-UA.json +29 -0
- package/src/dnd/intl/zh-CN.json +29 -0
- package/src/dnd/intl/zh-TW.json +29 -0
- package/src/dnd/utils.ts +63 -3
- package/src/focus/FocusScope.tsx +266 -24
- package/src/focus/index.ts +8 -0
- package/src/focus/virtualFocus.ts +55 -0
- package/src/form/createFormValidation.ts +8 -1
- package/src/gridlist/createGridList.ts +187 -48
- package/src/gridlist/createGridListItem.ts +87 -155
- package/src/gridlist/createGridListSection.ts +54 -0
- package/src/gridlist/index.ts +3 -0
- package/src/gridlist/types.ts +47 -0
- package/src/index.ts +51 -3
- package/src/interactions/FocusableProvider.tsx +11 -6
- package/src/interactions/PressEvent.ts +14 -0
- package/src/interactions/createFocus.ts +26 -21
- package/src/interactions/createFocusWithin.ts +23 -24
- package/src/interactions/createInteractionModality.ts +26 -15
- package/src/interactions/createKeyboard.ts +10 -0
- package/src/interactions/createPress.ts +29 -6
- package/src/label/createLabels.ts +7 -4
- package/src/listbox/createListBox.ts +203 -10
- package/src/listbox/createOption.ts +84 -74
- package/src/menu/createMenu.ts +93 -16
- package/src/menu/createMenuItem.ts +253 -41
- package/src/numberfield/createNumberField.ts +82 -14
- package/src/popover/calculatePosition.ts +19 -7
- package/src/popover/createOverlayPosition.ts +9 -0
- package/src/radio/createRadio.ts +19 -2
- package/src/select/createSelect.ts +41 -4
- package/src/selection/DOMLayoutDelegate.ts +102 -0
- package/src/selection/ListKeyboardDelegate.ts +398 -0
- package/src/selection/constants.ts +16 -0
- package/src/selection/createCollectionRowInteraction.ts +209 -0
- package/src/selection/createScrollIntoViewOnFocus.ts +65 -0
- package/src/selection/createSelectableCollection.ts +645 -0
- package/src/selection/createSelectableItem.ts +512 -0
- package/src/selection/createSelectableList.ts +93 -0
- package/src/selection/createTypeSelect.ts +112 -51
- package/src/selection/index.ts +31 -0
- package/src/selection/selectItem.ts +80 -0
- package/src/selection/utils.ts +82 -0
- package/src/slider/createSlider.ts +48 -1
- package/src/spinbutton/createSpinButton.ts +163 -0
- package/src/spinbutton/index.ts +10 -0
- package/src/spinbutton/intl.ts +115 -0
- package/src/ssr/index.tsx +31 -0
- package/src/switch/createSwitch.ts +10 -0
- package/src/table/createTable.ts +82 -27
- package/src/table/createTableColumnHeader.ts +10 -0
- package/src/table/createTableRow.ts +208 -203
- package/src/table/createTableSelectAllCheckbox.ts +3 -4
- package/src/table/createTableSelectionCheckbox.ts +24 -1
- package/src/table/types.ts +37 -1
- package/src/table/utils.ts +41 -0
- package/src/tabs/createTabs.ts +95 -24
- package/src/tag/createTag.ts +30 -36
- package/src/tag/createTagGroup.ts +92 -0
- package/src/toast/createToast.ts +1 -0
- package/src/toggle/createToggle.ts +20 -0
- package/src/toolbar/createToolbar.ts +43 -94
- package/src/tree/createTree.ts +165 -52
- package/src/tree/createTreeItem.ts +105 -120
- package/src/tree/createTreeSelectionCheckbox.ts +14 -1
- package/src/tree/types.ts +10 -0
- package/src/utils/animation.ts +243 -0
- package/src/utils/dom.ts +216 -25
- package/src/utils/index.ts +10 -0
- package/src/utils/keyboard.ts +25 -0
- package/src/utils/mergeProps.ts +8 -1
- package/src/utils/scrollIntoView.ts +181 -0
- package/dist/datepicker/createTimeSegment.d.ts +0 -29
- package/dist/datepicker/createTimeSegment.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.jsx.map +0 -1
- package/src/datepicker/createTimeSegment.ts +0 -352
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { i as mergeProps$1 } from "./env.jsx";
|
|
2
|
+
import { t as filterDOMProps } from "./filterDOMProps.jsx";
|
|
3
|
+
import { a as getEventTarget, p as isFocusable, t as focusSafely, y as nodeContains } from "./focus.jsx";
|
|
4
|
+
import { i as createButton } from "./button.jsx";
|
|
5
|
+
import { i as useLocale } from "./locale.jsx";
|
|
6
|
+
import { onCleanup } from "solid-js";
|
|
7
|
+
//#region src/actiongroup/createActionGroup.ts
|
|
8
|
+
const actionGroupData = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
const GROUP_ROLE_BY_MODE = {
|
|
10
|
+
none: "toolbar",
|
|
11
|
+
single: "radiogroup",
|
|
12
|
+
multiple: "toolbar"
|
|
13
|
+
};
|
|
14
|
+
const ITEM_ROLE_BY_MODE = {
|
|
15
|
+
none: void 0,
|
|
16
|
+
single: "radio",
|
|
17
|
+
multiple: "checkbox"
|
|
18
|
+
};
|
|
19
|
+
function isActionGroupDisabled(props, state) {
|
|
20
|
+
if (props.isDisabled) return true;
|
|
21
|
+
const keys = [...state.collection().getKeys()];
|
|
22
|
+
if (keys.length === 0) return true;
|
|
23
|
+
return !keys.some((key) => !state.isDisabled(key));
|
|
24
|
+
}
|
|
25
|
+
function createActionGroup(props, state, _ref) {
|
|
26
|
+
const locale = useLocale();
|
|
27
|
+
let groupRef;
|
|
28
|
+
const applyRoleAttributes = () => {
|
|
29
|
+
if (!groupRef) return;
|
|
30
|
+
const mappedRole = GROUP_ROLE_BY_MODE[state.selectionMode()];
|
|
31
|
+
const nestedToolbar = Boolean(groupRef.parentElement?.closest("[role=\"toolbar\"]"));
|
|
32
|
+
const role = mappedRole === "toolbar" && nestedToolbar ? "group" : mappedRole;
|
|
33
|
+
groupRef.setAttribute("role", role);
|
|
34
|
+
if (mappedRole === "toolbar" && !nestedToolbar) groupRef.setAttribute("aria-orientation", props.orientation ?? "horizontal");
|
|
35
|
+
else groupRef.removeAttribute("aria-orientation");
|
|
36
|
+
};
|
|
37
|
+
const getFocusableItems = (root) => {
|
|
38
|
+
const out = [];
|
|
39
|
+
const pushIfFocusable = (el) => {
|
|
40
|
+
if (!el || !(el instanceof HTMLElement)) return;
|
|
41
|
+
if (isFocusable(el) && el.getAttribute("aria-disabled") !== "true") out.push(el);
|
|
42
|
+
};
|
|
43
|
+
pushIfFocusable(root);
|
|
44
|
+
for (const node of root.querySelectorAll("*")) pushIfFocusable(node);
|
|
45
|
+
return out;
|
|
46
|
+
};
|
|
47
|
+
const focusRelative = (root, direction) => {
|
|
48
|
+
const focusables = getFocusableItems(root);
|
|
49
|
+
if (focusables.length === 0) return null;
|
|
50
|
+
const active = root.ownerDocument.activeElement;
|
|
51
|
+
const currentIndex = active ? focusables.indexOf(active) : -1;
|
|
52
|
+
const next = focusables[currentIndex === -1 ? direction === "next" ? 0 : focusables.length - 1 : (currentIndex + (direction === "next" ? 1 : -1) + focusables.length) % focusables.length];
|
|
53
|
+
focusSafely(next);
|
|
54
|
+
return next;
|
|
55
|
+
};
|
|
56
|
+
const onKeyDown = (e) => {
|
|
57
|
+
const root = groupRef;
|
|
58
|
+
if (!root || isActionGroupDisabled(props, state)) return;
|
|
59
|
+
if (!nodeContains(e.currentTarget, getEventTarget(e))) return;
|
|
60
|
+
const orientation = props.orientation ?? "horizontal";
|
|
61
|
+
const flipDirection = locale().direction === "rtl" && orientation === "horizontal";
|
|
62
|
+
switch (e.key) {
|
|
63
|
+
case "ArrowRight":
|
|
64
|
+
case "ArrowDown":
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
e.stopPropagation();
|
|
67
|
+
if (e.key === "ArrowRight" && flipDirection) focusRelative(root, "previous");
|
|
68
|
+
else focusRelative(root, "next");
|
|
69
|
+
return;
|
|
70
|
+
case "ArrowLeft":
|
|
71
|
+
case "ArrowUp":
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
e.stopPropagation();
|
|
74
|
+
if (e.key === "ArrowLeft" && flipDirection) focusRelative(root, "next");
|
|
75
|
+
else focusRelative(root, "previous");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const actionGroupProps = mergeProps$1(filterDOMProps(props, { labelable: true }), {
|
|
80
|
+
ref: (el) => {
|
|
81
|
+
groupRef = el;
|
|
82
|
+
applyRoleAttributes();
|
|
83
|
+
queueMicrotask(() => {
|
|
84
|
+
if (!groupRef) return;
|
|
85
|
+
applyRoleAttributes();
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
onKeyDown,
|
|
89
|
+
get "aria-label"() {
|
|
90
|
+
return props["aria-label"];
|
|
91
|
+
},
|
|
92
|
+
get "aria-labelledby"() {
|
|
93
|
+
return props["aria-label"] ? void 0 : props["aria-labelledby"];
|
|
94
|
+
},
|
|
95
|
+
get "aria-disabled"() {
|
|
96
|
+
return isActionGroupDisabled(props, state) || void 0;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
actionGroupData.set(state, { get onAction() {
|
|
100
|
+
return props.onAction;
|
|
101
|
+
} });
|
|
102
|
+
onCleanup(() => {
|
|
103
|
+
actionGroupData.delete(state);
|
|
104
|
+
});
|
|
105
|
+
return { actionGroupProps };
|
|
106
|
+
}
|
|
107
|
+
function createActionGroupItem(props, state) {
|
|
108
|
+
const button = createButton({
|
|
109
|
+
elementType: "button",
|
|
110
|
+
isDisabled: state.isDisabled(props.key),
|
|
111
|
+
onPress: () => {
|
|
112
|
+
state.setFocusedKey(props.key);
|
|
113
|
+
actionGroupData.get(state)?.onAction?.(props.key);
|
|
114
|
+
if (state.selectionMode() !== "none") state.select(props.key);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
const isFocused = () => props.key === state.focusedKey();
|
|
118
|
+
onCleanup(() => {
|
|
119
|
+
if (isFocused()) state.setFocusedKey(null);
|
|
120
|
+
});
|
|
121
|
+
return { buttonProps: mergeProps$1(button.buttonProps, {
|
|
122
|
+
get role() {
|
|
123
|
+
return ITEM_ROLE_BY_MODE[state.selectionMode()];
|
|
124
|
+
},
|
|
125
|
+
get "aria-checked"() {
|
|
126
|
+
if (state.selectionMode() === "none") return void 0;
|
|
127
|
+
return state.isSelected(props.key);
|
|
128
|
+
},
|
|
129
|
+
get tabIndex() {
|
|
130
|
+
return isFocused() || state.focusedKey() == null ? 0 : -1;
|
|
131
|
+
},
|
|
132
|
+
"data-key": String(props.key),
|
|
133
|
+
onFocus: () => {
|
|
134
|
+
state.setFocusedKey(props.key);
|
|
135
|
+
}
|
|
136
|
+
}) };
|
|
137
|
+
}
|
|
138
|
+
//#endregion
|
|
139
|
+
export { createActionGroupItem as n, createActionGroup as t };
|
|
140
|
+
|
|
141
|
+
//# sourceMappingURL=actiongroup.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actiongroup.jsx","names":["mergeProps"],"sources":["../../src/actiongroup/createActionGroup.ts"],"sourcesContent":["import { onCleanup, type JSX, type Accessor } from \"solid-js\";\nimport { createButton } from \"../button\";\nimport {\n filterDOMProps,\n getEventTarget,\n mergeProps,\n nodeContains,\n isFocusable,\n focusSafely,\n} from \"../utils\";\nimport { useLocale } from \"../i18n\";\nimport type { Orientation } from \"../toolbar\";\nimport type { Key, ListState } from \"@proyecto-viviana/solid-stately\";\n\nexport interface AriaActionGroupProps<T = unknown> {\n /** List items (optional, parity with React Aria prop shape). */\n items?: T[];\n /** Whether the whole action group is disabled. */\n isDisabled?: boolean;\n /** Group orientation. */\n orientation?: Orientation;\n /** Accessible label. */\n \"aria-label\"?: string;\n /** Labelled-by id. */\n \"aria-labelledby\"?: string;\n /** Handler called when an item action is triggered. */\n onAction?: (key: Key) => void;\n}\n\nexport interface ActionGroupAria {\n actionGroupProps: JSX.HTMLAttributes<HTMLElement>;\n}\n\nexport interface AriaActionGroupItemProps {\n key: Key;\n}\n\nexport interface ActionGroupItemAria {\n buttonProps: JSX.HTMLAttributes<HTMLElement>;\n}\n\ninterface ActionGroupData {\n onAction?: (key: Key) => void;\n}\n\nconst actionGroupData = new WeakMap<object, ActionGroupData>();\n\nconst GROUP_ROLE_BY_MODE = {\n none: \"toolbar\",\n single: \"radiogroup\",\n multiple: \"toolbar\",\n} as const;\n\nconst ITEM_ROLE_BY_MODE = {\n none: undefined,\n single: \"radio\",\n multiple: \"checkbox\",\n} as const;\n\nfunction isActionGroupDisabled<T>(props: AriaActionGroupProps<T>, state: ListState<T>): boolean {\n if (props.isDisabled) return true;\n const keys = [...state.collection().getKeys()];\n if (keys.length === 0) return true;\n return !keys.some((key) => !state.isDisabled(key));\n}\n\nexport function createActionGroup<T>(\n props: AriaActionGroupProps<T>,\n state: ListState<T>,\n _ref?: Accessor<HTMLElement | null>,\n): ActionGroupAria {\n const locale = useLocale();\n let groupRef: HTMLElement | undefined;\n const applyRoleAttributes = (): void => {\n if (!groupRef) return;\n const selectionMode = state.selectionMode();\n const mappedRole = GROUP_ROLE_BY_MODE[selectionMode];\n const nestedToolbar = Boolean(groupRef.parentElement?.closest('[role=\"toolbar\"]'));\n const role = mappedRole === \"toolbar\" && nestedToolbar ? \"group\" : mappedRole;\n groupRef.setAttribute(\"role\", role);\n if (mappedRole === \"toolbar\" && !nestedToolbar) {\n groupRef.setAttribute(\"aria-orientation\", props.orientation ?? \"horizontal\");\n } else {\n groupRef.removeAttribute(\"aria-orientation\");\n }\n };\n\n const getFocusableItems = (root: HTMLElement): HTMLElement[] => {\n const out: HTMLElement[] = [];\n const pushIfFocusable = (el: Element | null | undefined): void => {\n if (!el || !(el instanceof HTMLElement)) return;\n if (isFocusable(el) && el.getAttribute(\"aria-disabled\") !== \"true\") {\n out.push(el);\n }\n };\n\n pushIfFocusable(root);\n for (const node of root.querySelectorAll(\"*\")) {\n pushIfFocusable(node);\n }\n return out;\n };\n\n const focusRelative = (\n root: HTMLElement,\n direction: \"next\" | \"previous\",\n ): HTMLElement | null => {\n const focusables = getFocusableItems(root);\n if (focusables.length === 0) return null;\n\n const active = root.ownerDocument.activeElement as HTMLElement | null;\n const currentIndex = active ? focusables.indexOf(active) : -1;\n const delta = direction === \"next\" ? 1 : -1;\n const nextIndex =\n currentIndex === -1\n ? direction === \"next\"\n ? 0\n : focusables.length - 1\n : (currentIndex + delta + focusables.length) % focusables.length;\n const next = focusables[nextIndex];\n focusSafely(next);\n return next;\n };\n\n // Mirrors react-aria `useActionGroup.onKeyDown` (3.50.0): only the four arrows\n // are handled and they are ORIENTATION-AGNOSTIC — ArrowRight/ArrowDown always\n // move next, ArrowLeft/ArrowUp always move previous (orientation only drives\n // `aria-orientation`). `flipDirection` swaps ArrowRight/ArrowLeft under RTL for\n // horizontal groups. No Home/End (they fall through to the browser). Focus\n // moves via `focusRelative` → `focusSafely` → the item's own `onFocus`, which\n // sets the focused key — so there is no selection-follows-focus here.\n const onKeyDown: JSX.EventHandler<HTMLElement, KeyboardEvent> = (e) => {\n const root = groupRef;\n if (!root || isActionGroupDisabled(props, state)) return;\n if (!nodeContains(e.currentTarget, getEventTarget(e))) return;\n\n const orientation = props.orientation ?? \"horizontal\";\n const flipDirection = locale().direction === \"rtl\" && orientation === \"horizontal\";\n\n switch (e.key) {\n case \"ArrowRight\":\n case \"ArrowDown\": {\n e.preventDefault();\n e.stopPropagation();\n if (e.key === \"ArrowRight\" && flipDirection) {\n focusRelative(root, \"previous\");\n } else {\n focusRelative(root, \"next\");\n }\n return;\n }\n case \"ArrowLeft\":\n case \"ArrowUp\": {\n e.preventDefault();\n e.stopPropagation();\n if (e.key === \"ArrowLeft\" && flipDirection) {\n focusRelative(root, \"next\");\n } else {\n focusRelative(root, \"previous\");\n }\n return;\n }\n }\n };\n\n const actionGroupProps: JSX.HTMLAttributes<HTMLElement> = mergeProps(\n filterDOMProps(props as Record<string, unknown>, { labelable: true }),\n {\n ref: (el: HTMLElement) => {\n groupRef = el;\n applyRoleAttributes();\n queueMicrotask(() => {\n if (!groupRef) return;\n applyRoleAttributes();\n });\n },\n onKeyDown,\n get \"aria-label\"() {\n return props[\"aria-label\"];\n },\n get \"aria-labelledby\"() {\n return props[\"aria-label\"] ? undefined : props[\"aria-labelledby\"];\n },\n get \"aria-disabled\"() {\n return isActionGroupDisabled(props, state) || undefined;\n },\n },\n );\n\n actionGroupData.set(state, {\n get onAction() {\n return props.onAction;\n },\n });\n\n onCleanup(() => {\n actionGroupData.delete(state);\n });\n\n return { actionGroupProps };\n}\n\nexport function createActionGroupItem<T>(\n props: AriaActionGroupItemProps,\n state: ListState<T>,\n): ActionGroupItemAria {\n const button = createButton({\n elementType: \"button\",\n isDisabled: state.isDisabled(props.key),\n onPress: () => {\n state.setFocusedKey(props.key);\n actionGroupData.get(state)?.onAction?.(props.key);\n if (state.selectionMode() !== \"none\") {\n state.select(props.key);\n }\n },\n });\n\n const isFocused = () => props.key === state.focusedKey();\n\n onCleanup(() => {\n if (isFocused()) {\n state.setFocusedKey(null);\n }\n });\n\n const buttonProps: JSX.HTMLAttributes<HTMLElement> = mergeProps(button.buttonProps, {\n get role() {\n return ITEM_ROLE_BY_MODE[state.selectionMode()];\n },\n get \"aria-checked\"() {\n const mode = state.selectionMode();\n if (mode === \"none\") return undefined;\n return state.isSelected(props.key);\n },\n // Mirrors react-aria `useActionGroupItem` (3.50.0): every enabled item is\n // tabbable until focus engages the group, then the roving stop follows the\n // focused key. There is NO single default tab stop and NO selection bias —\n // disabled items are made non-tabbable by their native `disabled` attribute\n // (via createButton), not by this getter.\n get tabIndex() {\n return isFocused() || state.focusedKey() == null ? 0 : -1;\n },\n \"data-key\": String(props.key),\n onFocus: () => {\n state.setFocusedKey(props.key);\n },\n });\n\n return { buttonProps };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { createEffect } from "solid-js";
|
|
2
|
+
import { isServer } from "solid-js/web";
|
|
3
|
+
//#region src/live-announcer/announce.ts
|
|
4
|
+
/**
|
|
5
|
+
* Live announcer for solidaria
|
|
6
|
+
*
|
|
7
|
+
* Provides functions to make announcements to screen readers using
|
|
8
|
+
* ARIA live regions. Useful for announcing dynamic content changes.
|
|
9
|
+
*
|
|
10
|
+
* Port of react-aria's @react-aria/live-announcer.
|
|
11
|
+
*
|
|
12
|
+
* SSR Safety: All functions are safe to call during SSR. The announcer
|
|
13
|
+
* will only be created when running in the browser.
|
|
14
|
+
*/
|
|
15
|
+
const LIVEREGION_TIMEOUT_DELAY = 7e3;
|
|
16
|
+
/**
|
|
17
|
+
* Singleton class that manages live region announcements.
|
|
18
|
+
* Implemented using vanilla DOM for simplicity and framework independence.
|
|
19
|
+
*/
|
|
20
|
+
var LiveAnnouncer = class {
|
|
21
|
+
node = null;
|
|
22
|
+
assertiveLog = null;
|
|
23
|
+
politeLog = null;
|
|
24
|
+
constructor() {
|
|
25
|
+
if (typeof document !== "undefined") {
|
|
26
|
+
this.node = document.createElement("div");
|
|
27
|
+
this.node.dataset.liveAnnouncer = "true";
|
|
28
|
+
Object.assign(this.node.style, {
|
|
29
|
+
border: "0",
|
|
30
|
+
clip: "rect(0 0 0 0)",
|
|
31
|
+
clipPath: "inset(50%)",
|
|
32
|
+
height: "1px",
|
|
33
|
+
margin: "-1px",
|
|
34
|
+
overflow: "hidden",
|
|
35
|
+
padding: "0",
|
|
36
|
+
position: "absolute",
|
|
37
|
+
width: "1px",
|
|
38
|
+
whiteSpace: "nowrap"
|
|
39
|
+
});
|
|
40
|
+
this.assertiveLog = this.createLog("assertive");
|
|
41
|
+
this.node.appendChild(this.assertiveLog);
|
|
42
|
+
this.politeLog = this.createLog("polite");
|
|
43
|
+
this.node.appendChild(this.politeLog);
|
|
44
|
+
document.body.prepend(this.node);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
isAttached() {
|
|
48
|
+
return this.node?.isConnected ?? false;
|
|
49
|
+
}
|
|
50
|
+
createLog(ariaLive) {
|
|
51
|
+
const node = document.createElement("div");
|
|
52
|
+
node.setAttribute("role", "log");
|
|
53
|
+
node.setAttribute("aria-live", ariaLive);
|
|
54
|
+
node.setAttribute("aria-relevant", "additions");
|
|
55
|
+
return node;
|
|
56
|
+
}
|
|
57
|
+
destroy() {
|
|
58
|
+
if (!this.node) return;
|
|
59
|
+
document.body.removeChild(this.node);
|
|
60
|
+
this.node = null;
|
|
61
|
+
}
|
|
62
|
+
announce(message, assertiveness = "assertive", timeout = LIVEREGION_TIMEOUT_DELAY) {
|
|
63
|
+
if (!this.node) return;
|
|
64
|
+
const node = document.createElement("div");
|
|
65
|
+
if (typeof message === "object") {
|
|
66
|
+
node.setAttribute("role", "img");
|
|
67
|
+
node.setAttribute("aria-labelledby", message["aria-labelledby"]);
|
|
68
|
+
} else node.textContent = message;
|
|
69
|
+
if (assertiveness === "assertive") this.assertiveLog?.appendChild(node);
|
|
70
|
+
else this.politeLog?.appendChild(node);
|
|
71
|
+
if (message !== "") setTimeout(() => {
|
|
72
|
+
node.remove();
|
|
73
|
+
}, timeout);
|
|
74
|
+
}
|
|
75
|
+
clear(assertiveness) {
|
|
76
|
+
if (!this.node) return;
|
|
77
|
+
if ((!assertiveness || assertiveness === "assertive") && this.assertiveLog) this.assertiveLog.innerHTML = "";
|
|
78
|
+
if ((!assertiveness || assertiveness === "polite") && this.politeLog) this.politeLog.innerHTML = "";
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
let liveAnnouncer = null;
|
|
82
|
+
/**
|
|
83
|
+
* Announces a message to screen readers using ARIA live regions.
|
|
84
|
+
*
|
|
85
|
+
* @param message - The message to announce, or an object with aria-labelledby
|
|
86
|
+
* @param assertiveness - 'assertive' interrupts, 'polite' waits for a pause
|
|
87
|
+
* @param timeout - How long to keep the message in the DOM (default 7000ms)
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```tsx
|
|
91
|
+
* // Simple announcement
|
|
92
|
+
* announce('Item added to cart');
|
|
93
|
+
*
|
|
94
|
+
* // Polite announcement (won't interrupt)
|
|
95
|
+
* announce('3 results found', 'polite');
|
|
96
|
+
*
|
|
97
|
+
* // Using aria-labelledby for complex content
|
|
98
|
+
* announce({ 'aria-labelledby': 'my-element-id' });
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
function announce(message, assertiveness = "assertive", timeout = LIVEREGION_TIMEOUT_DELAY) {
|
|
102
|
+
if (!liveAnnouncer) {
|
|
103
|
+
liveAnnouncer = new LiveAnnouncer();
|
|
104
|
+
if (!(typeof globalThis.IS_SOLIDARIA_TEST === "boolean" ? globalThis.IS_SOLIDARIA_TEST : typeof globalThis.vitest !== "undefined")) setTimeout(() => {
|
|
105
|
+
if (liveAnnouncer?.isAttached()) liveAnnouncer?.announce(message, assertiveness, timeout);
|
|
106
|
+
}, 100);
|
|
107
|
+
else liveAnnouncer.announce(message, assertiveness, timeout);
|
|
108
|
+
} else liveAnnouncer.announce(message, assertiveness, timeout);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Clears all queued announcements for the given assertiveness level.
|
|
112
|
+
*
|
|
113
|
+
* @param assertiveness - Which log to clear ('assertive' or 'polite')
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```tsx
|
|
117
|
+
* // Clear assertive announcements
|
|
118
|
+
* clearAnnouncer('assertive');
|
|
119
|
+
*
|
|
120
|
+
* // Clear polite announcements
|
|
121
|
+
* clearAnnouncer('polite');
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
function clearAnnouncer(assertiveness) {
|
|
125
|
+
if (liveAnnouncer) liveAnnouncer.clear(assertiveness);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Removes the live announcer from the DOM entirely.
|
|
129
|
+
* Call this when unmounting your app or when announcements are no longer needed.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```tsx
|
|
133
|
+
* // Clean up on app unmount
|
|
134
|
+
* onCleanup(() => {
|
|
135
|
+
* destroyAnnouncer();
|
|
136
|
+
* });
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
function destroyAnnouncer() {
|
|
140
|
+
if (liveAnnouncer) {
|
|
141
|
+
liveAnnouncer.destroy();
|
|
142
|
+
liveAnnouncer = null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Hook that provides access to the live announcer with automatic cleanup.
|
|
147
|
+
*
|
|
148
|
+
* This is the recommended way to use the announcer in SolidJS components.
|
|
149
|
+
* It ensures the announcer is created only on the client and provides
|
|
150
|
+
* type-safe methods for announcing and clearing messages.
|
|
151
|
+
*
|
|
152
|
+
* SSR Safety: Returns no-op functions during SSR. The announcer is only
|
|
153
|
+
* created when the component mounts on the client.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```tsx
|
|
157
|
+
* function SearchResults(props) {
|
|
158
|
+
* const announcer = useAnnouncer();
|
|
159
|
+
*
|
|
160
|
+
* createEffect(() => {
|
|
161
|
+
* const count = props.results.length;
|
|
162
|
+
* announcer.announce(`${count} results found`, 'polite');
|
|
163
|
+
* });
|
|
164
|
+
*
|
|
165
|
+
* return <ul>...</ul>;
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```tsx
|
|
171
|
+
* function Form() {
|
|
172
|
+
* const announcer = useAnnouncer();
|
|
173
|
+
*
|
|
174
|
+
* const onSubmit = async () => {
|
|
175
|
+
* try {
|
|
176
|
+
* await submitForm();
|
|
177
|
+
* announcer.announce('Form submitted successfully');
|
|
178
|
+
* } catch (error) {
|
|
179
|
+
* announcer.announce('Error submitting form', 'assertive');
|
|
180
|
+
* }
|
|
181
|
+
* };
|
|
182
|
+
*
|
|
183
|
+
* return <form onSubmit={onSubmit}>...</form>;
|
|
184
|
+
* }
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
function useAnnouncer() {
|
|
188
|
+
if (isServer) return {
|
|
189
|
+
announce: () => {},
|
|
190
|
+
clear: () => {}
|
|
191
|
+
};
|
|
192
|
+
createEffect(() => {
|
|
193
|
+
if (!liveAnnouncer) liveAnnouncer = new LiveAnnouncer();
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
announce: (message, assertiveness = "assertive", timeout = LIVEREGION_TIMEOUT_DELAY) => {
|
|
197
|
+
announce(message, assertiveness, timeout);
|
|
198
|
+
},
|
|
199
|
+
clear: (assertiveness) => {
|
|
200
|
+
clearAnnouncer(assertiveness);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
//#endregion
|
|
205
|
+
export { useAnnouncer as i, clearAnnouncer as n, destroyAnnouncer as r, announce as t };
|
|
206
|
+
|
|
207
|
+
//# sourceMappingURL=announce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"announce.js","names":[],"sources":["../../src/live-announcer/announce.ts"],"sourcesContent":["/**\n * Live announcer for solidaria\n *\n * Provides functions to make announcements to screen readers using\n * ARIA live regions. Useful for announcing dynamic content changes.\n *\n * Port of react-aria's @react-aria/live-announcer.\n *\n * SSR Safety: All functions are safe to call during SSR. The announcer\n * will only be created when running in the browser.\n */\n\nimport { onCleanup, createEffect } from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\n\nexport type Assertiveness = \"assertive\" | \"polite\";\n\nexport type Message = string | { \"aria-labelledby\": string };\n\nconst LIVEREGION_TIMEOUT_DELAY = 7000;\n\n/**\n * Singleton class that manages live region announcements.\n * Implemented using vanilla DOM for simplicity and framework independence.\n */\nclass LiveAnnouncer {\n node: HTMLElement | null = null;\n assertiveLog: HTMLElement | null = null;\n politeLog: HTMLElement | null = null;\n\n constructor() {\n if (typeof document !== \"undefined\") {\n this.node = document.createElement(\"div\");\n this.node.dataset.liveAnnouncer = \"true\";\n // Visually hidden styles\n Object.assign(this.node.style, {\n border: \"0\",\n clip: \"rect(0 0 0 0)\",\n clipPath: \"inset(50%)\",\n height: \"1px\",\n margin: \"-1px\",\n overflow: \"hidden\",\n padding: \"0\",\n position: \"absolute\",\n width: \"1px\",\n whiteSpace: \"nowrap\",\n });\n\n this.assertiveLog = this.createLog(\"assertive\");\n this.node.appendChild(this.assertiveLog);\n\n this.politeLog = this.createLog(\"polite\");\n this.node.appendChild(this.politeLog);\n\n document.body.prepend(this.node);\n }\n }\n\n isAttached(): boolean {\n return this.node?.isConnected ?? false;\n }\n\n createLog(ariaLive: string): HTMLElement {\n const node = document.createElement(\"div\");\n node.setAttribute(\"role\", \"log\");\n node.setAttribute(\"aria-live\", ariaLive);\n node.setAttribute(\"aria-relevant\", \"additions\");\n return node;\n }\n\n destroy(): void {\n if (!this.node) {\n return;\n }\n\n document.body.removeChild(this.node);\n this.node = null;\n }\n\n announce(\n message: Message,\n assertiveness: Assertiveness = \"assertive\",\n timeout: number = LIVEREGION_TIMEOUT_DELAY,\n ): void {\n if (!this.node) {\n return;\n }\n\n const node = document.createElement(\"div\");\n if (typeof message === \"object\") {\n // To read an aria-labelledby, the element must have an appropriate role, such as img.\n node.setAttribute(\"role\", \"img\");\n node.setAttribute(\"aria-labelledby\", message[\"aria-labelledby\"]);\n } else {\n node.textContent = message;\n }\n\n if (assertiveness === \"assertive\") {\n this.assertiveLog?.appendChild(node);\n } else {\n this.politeLog?.appendChild(node);\n }\n\n if (message !== \"\") {\n setTimeout(() => {\n node.remove();\n }, timeout);\n }\n }\n\n clear(assertiveness?: Assertiveness): void {\n if (!this.node) {\n return;\n }\n\n if ((!assertiveness || assertiveness === \"assertive\") && this.assertiveLog) {\n this.assertiveLog.innerHTML = \"\";\n }\n\n if ((!assertiveness || assertiveness === \"polite\") && this.politeLog) {\n this.politeLog.innerHTML = \"\";\n }\n }\n}\n\nlet liveAnnouncer: LiveAnnouncer | null = null;\n\n/**\n * Announces a message to screen readers using ARIA live regions.\n *\n * @param message - The message to announce, or an object with aria-labelledby\n * @param assertiveness - 'assertive' interrupts, 'polite' waits for a pause\n * @param timeout - How long to keep the message in the DOM (default 7000ms)\n *\n * @example\n * ```tsx\n * // Simple announcement\n * announce('Item added to cart');\n *\n * // Polite announcement (won't interrupt)\n * announce('3 results found', 'polite');\n *\n * // Using aria-labelledby for complex content\n * announce({ 'aria-labelledby': 'my-element-id' });\n * ```\n */\nexport function announce(\n message: Message,\n assertiveness: Assertiveness = \"assertive\",\n timeout: number = LIVEREGION_TIMEOUT_DELAY,\n): void {\n if (!liveAnnouncer) {\n liveAnnouncer = new LiveAnnouncer();\n // Wait for the live announcer regions to be added to the DOM, then announce.\n // Otherwise Safari won't announce the message if it's added too quickly.\n // Found most times less than 100ms were not consistent when announcing with Safari.\n\n // Check for test environment\n const isTestEnv =\n typeof (globalThis as Record<string, unknown>).IS_SOLIDARIA_TEST === \"boolean\"\n ? (globalThis as Record<string, unknown>).IS_SOLIDARIA_TEST\n : typeof (globalThis as Record<string, unknown>).vitest !== \"undefined\";\n\n if (!isTestEnv) {\n setTimeout(() => {\n if (liveAnnouncer?.isAttached()) {\n liveAnnouncer?.announce(message, assertiveness, timeout);\n }\n }, 100);\n } else {\n liveAnnouncer.announce(message, assertiveness, timeout);\n }\n } else {\n liveAnnouncer.announce(message, assertiveness, timeout);\n }\n}\n\n/**\n * Clears all queued announcements for the given assertiveness level.\n *\n * @param assertiveness - Which log to clear ('assertive' or 'polite')\n *\n * @example\n * ```tsx\n * // Clear assertive announcements\n * clearAnnouncer('assertive');\n *\n * // Clear polite announcements\n * clearAnnouncer('polite');\n * ```\n */\nexport function clearAnnouncer(assertiveness?: Assertiveness): void {\n if (liveAnnouncer) {\n liveAnnouncer.clear(assertiveness);\n }\n}\n\n/**\n * Removes the live announcer from the DOM entirely.\n * Call this when unmounting your app or when announcements are no longer needed.\n *\n * @example\n * ```tsx\n * // Clean up on app unmount\n * onCleanup(() => {\n * destroyAnnouncer();\n * });\n * ```\n */\nexport function destroyAnnouncer(): void {\n if (liveAnnouncer) {\n liveAnnouncer.destroy();\n liveAnnouncer = null;\n }\n}\n\nexport interface UseAnnouncerResult {\n /** Announce a message to screen readers. */\n announce: (message: Message, assertiveness?: Assertiveness, timeout?: number) => void;\n /** Clear announcements for the given assertiveness level. */\n clear: (assertiveness?: Assertiveness) => void;\n}\n\n/**\n * Hook that provides access to the live announcer with automatic cleanup.\n *\n * This is the recommended way to use the announcer in SolidJS components.\n * It ensures the announcer is created only on the client and provides\n * type-safe methods for announcing and clearing messages.\n *\n * SSR Safety: Returns no-op functions during SSR. The announcer is only\n * created when the component mounts on the client.\n *\n * @example\n * ```tsx\n * function SearchResults(props) {\n * const announcer = useAnnouncer();\n *\n * createEffect(() => {\n * const count = props.results.length;\n * announcer.announce(`${count} results found`, 'polite');\n * });\n *\n * return <ul>...</ul>;\n * }\n * ```\n *\n * @example\n * ```tsx\n * function Form() {\n * const announcer = useAnnouncer();\n *\n * const onSubmit = async () => {\n * try {\n * await submitForm();\n * announcer.announce('Form submitted successfully');\n * } catch (error) {\n * announcer.announce('Error submitting form', 'assertive');\n * }\n * };\n *\n * return <form onSubmit={onSubmit}>...</form>;\n * }\n * ```\n */\nexport function useAnnouncer(): UseAnnouncerResult {\n // During SSR, return no-op functions\n if (isServer) {\n return {\n announce: () => {},\n clear: () => {},\n };\n }\n\n // Ensure the announcer is initialized\n createEffect(() => {\n // Initialize on first use\n if (!liveAnnouncer) {\n liveAnnouncer = new LiveAnnouncer();\n }\n });\n\n return {\n announce: (\n message: Message,\n assertiveness: Assertiveness = \"assertive\",\n timeout: number = LIVEREGION_TIMEOUT_DELAY,\n ) => {\n announce(message, assertiveness, timeout);\n },\n clear: (assertiveness?: Assertiveness) => {\n clearAnnouncer(assertiveness);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAmBA,MAAM,2BAA2B;;;;;AAMjC,IAAM,gBAAN,MAAoB;CAClB,OAA2B;CAC3B,eAAmC;CACnC,YAAgC;CAEhC,cAAc;EACZ,IAAI,OAAO,aAAa,aAAa;GACnC,KAAK,OAAO,SAAS,cAAc,KAAK;GACxC,KAAK,KAAK,QAAQ,gBAAgB;GAElC,OAAO,OAAO,KAAK,KAAK,OAAO;IAC7B,QAAQ;IACR,MAAM;IACN,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,SAAS;IACT,UAAU;IACV,OAAO;IACP,YAAY;GACd,CAAC;GAED,KAAK,eAAe,KAAK,UAAU,WAAW;GAC9C,KAAK,KAAK,YAAY,KAAK,YAAY;GAEvC,KAAK,YAAY,KAAK,UAAU,QAAQ;GACxC,KAAK,KAAK,YAAY,KAAK,SAAS;GAEpC,SAAS,KAAK,QAAQ,KAAK,IAAI;EACjC;CACF;CAEA,aAAsB;EACpB,OAAO,KAAK,MAAM,eAAe;CACnC;CAEA,UAAU,UAA+B;EACvC,MAAM,OAAO,SAAS,cAAc,KAAK;EACzC,KAAK,aAAa,QAAQ,KAAK;EAC/B,KAAK,aAAa,aAAa,QAAQ;EACvC,KAAK,aAAa,iBAAiB,WAAW;EAC9C,OAAO;CACT;CAEA,UAAgB;EACd,IAAI,CAAC,KAAK,MACR;EAGF,SAAS,KAAK,YAAY,KAAK,IAAI;EACnC,KAAK,OAAO;CACd;CAEA,SACE,SACA,gBAA+B,aAC/B,UAAkB,0BACZ;EACN,IAAI,CAAC,KAAK,MACR;EAGF,MAAM,OAAO,SAAS,cAAc,KAAK;EACzC,IAAI,OAAO,YAAY,UAAU;GAE/B,KAAK,aAAa,QAAQ,KAAK;GAC/B,KAAK,aAAa,mBAAmB,QAAQ,kBAAkB;EACjE,OACE,KAAK,cAAc;EAGrB,IAAI,kBAAkB,aACpB,KAAK,cAAc,YAAY,IAAI;OAEnC,KAAK,WAAW,YAAY,IAAI;EAGlC,IAAI,YAAY,IACd,iBAAiB;GACf,KAAK,OAAO;EACd,GAAG,OAAO;CAEd;CAEA,MAAM,eAAqC;EACzC,IAAI,CAAC,KAAK,MACR;EAGF,KAAK,CAAC,iBAAiB,kBAAkB,gBAAgB,KAAK,cAC5D,KAAK,aAAa,YAAY;EAGhC,KAAK,CAAC,iBAAiB,kBAAkB,aAAa,KAAK,WACzD,KAAK,UAAU,YAAY;CAE/B;AACF;AAEA,IAAI,gBAAsC;;;;;;;;;;;;;;;;;;;;AAqB1C,SAAgB,SACd,SACA,gBAA+B,aAC/B,UAAkB,0BACZ;CACN,IAAI,CAAC,eAAe;EAClB,gBAAgB,IAAI,cAAc;EAWlC,IAAI,EAJF,OAAQ,WAAuC,sBAAsB,YAChE,WAAuC,oBACxC,OAAQ,WAAuC,WAAW,cAG9D,iBAAiB;GACf,IAAI,eAAe,WAAW,GAC5B,eAAe,SAAS,SAAS,eAAe,OAAO;EAE3D,GAAG,GAAG;OAEN,cAAc,SAAS,SAAS,eAAe,OAAO;CAE1D,OACE,cAAc,SAAS,SAAS,eAAe,OAAO;AAE1D;;;;;;;;;;;;;;;AAgBA,SAAgB,eAAe,eAAqC;CAClE,IAAI,eACF,cAAc,MAAM,aAAa;AAErC;;;;;;;;;;;;;AAcA,SAAgB,mBAAyB;CACvC,IAAI,eAAe;EACjB,cAAc,QAAQ;EACtB,gBAAgB;CAClB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,SAAgB,eAAmC;CAEjD,IAAI,UACF,OAAO;EACL,gBAAgB,CAAC;EACjB,aAAa,CAAC;CAChB;CAIF,mBAAmB;EAEjB,IAAI,CAAC,eACH,gBAAgB,IAAI,cAAc;CAEtC,CAAC;CAED,OAAO;EACL,WACE,SACA,gBAA+B,aAC/B,UAAkB,6BACf;GACH,SAAS,SAAS,eAAe,OAAO;EAC1C;EACA,QAAQ,kBAAkC;GACxC,eAAe,aAAa;EAC9B;CACF;AACF"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { createEffect } from "solid-js";
|
|
2
|
+
import { isServer } from "solid-js/web";
|
|
3
|
+
//#region src/live-announcer/announce.ts
|
|
4
|
+
/**
|
|
5
|
+
* Live announcer for solidaria
|
|
6
|
+
*
|
|
7
|
+
* Provides functions to make announcements to screen readers using
|
|
8
|
+
* ARIA live regions. Useful for announcing dynamic content changes.
|
|
9
|
+
*
|
|
10
|
+
* Port of react-aria's @react-aria/live-announcer.
|
|
11
|
+
*
|
|
12
|
+
* SSR Safety: All functions are safe to call during SSR. The announcer
|
|
13
|
+
* will only be created when running in the browser.
|
|
14
|
+
*/
|
|
15
|
+
const LIVEREGION_TIMEOUT_DELAY = 7e3;
|
|
16
|
+
/**
|
|
17
|
+
* Singleton class that manages live region announcements.
|
|
18
|
+
* Implemented using vanilla DOM for simplicity and framework independence.
|
|
19
|
+
*/
|
|
20
|
+
var LiveAnnouncer = class {
|
|
21
|
+
node = null;
|
|
22
|
+
assertiveLog = null;
|
|
23
|
+
politeLog = null;
|
|
24
|
+
constructor() {
|
|
25
|
+
if (typeof document !== "undefined") {
|
|
26
|
+
this.node = document.createElement("div");
|
|
27
|
+
this.node.dataset.liveAnnouncer = "true";
|
|
28
|
+
Object.assign(this.node.style, {
|
|
29
|
+
border: "0",
|
|
30
|
+
clip: "rect(0 0 0 0)",
|
|
31
|
+
clipPath: "inset(50%)",
|
|
32
|
+
height: "1px",
|
|
33
|
+
margin: "-1px",
|
|
34
|
+
overflow: "hidden",
|
|
35
|
+
padding: "0",
|
|
36
|
+
position: "absolute",
|
|
37
|
+
width: "1px",
|
|
38
|
+
whiteSpace: "nowrap"
|
|
39
|
+
});
|
|
40
|
+
this.assertiveLog = this.createLog("assertive");
|
|
41
|
+
this.node.appendChild(this.assertiveLog);
|
|
42
|
+
this.politeLog = this.createLog("polite");
|
|
43
|
+
this.node.appendChild(this.politeLog);
|
|
44
|
+
document.body.prepend(this.node);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
isAttached() {
|
|
48
|
+
return this.node?.isConnected ?? false;
|
|
49
|
+
}
|
|
50
|
+
createLog(ariaLive) {
|
|
51
|
+
const node = document.createElement("div");
|
|
52
|
+
node.setAttribute("role", "log");
|
|
53
|
+
node.setAttribute("aria-live", ariaLive);
|
|
54
|
+
node.setAttribute("aria-relevant", "additions");
|
|
55
|
+
return node;
|
|
56
|
+
}
|
|
57
|
+
destroy() {
|
|
58
|
+
if (!this.node) return;
|
|
59
|
+
document.body.removeChild(this.node);
|
|
60
|
+
this.node = null;
|
|
61
|
+
}
|
|
62
|
+
announce(message, assertiveness = "assertive", timeout = LIVEREGION_TIMEOUT_DELAY) {
|
|
63
|
+
if (!this.node) return;
|
|
64
|
+
const node = document.createElement("div");
|
|
65
|
+
if (typeof message === "object") {
|
|
66
|
+
node.setAttribute("role", "img");
|
|
67
|
+
node.setAttribute("aria-labelledby", message["aria-labelledby"]);
|
|
68
|
+
} else node.textContent = message;
|
|
69
|
+
if (assertiveness === "assertive") this.assertiveLog?.appendChild(node);
|
|
70
|
+
else this.politeLog?.appendChild(node);
|
|
71
|
+
if (message !== "") setTimeout(() => {
|
|
72
|
+
node.remove();
|
|
73
|
+
}, timeout);
|
|
74
|
+
}
|
|
75
|
+
clear(assertiveness) {
|
|
76
|
+
if (!this.node) return;
|
|
77
|
+
if ((!assertiveness || assertiveness === "assertive") && this.assertiveLog) this.assertiveLog.innerHTML = "";
|
|
78
|
+
if ((!assertiveness || assertiveness === "polite") && this.politeLog) this.politeLog.innerHTML = "";
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
let liveAnnouncer = null;
|
|
82
|
+
/**
|
|
83
|
+
* Announces a message to screen readers using ARIA live regions.
|
|
84
|
+
*
|
|
85
|
+
* @param message - The message to announce, or an object with aria-labelledby
|
|
86
|
+
* @param assertiveness - 'assertive' interrupts, 'polite' waits for a pause
|
|
87
|
+
* @param timeout - How long to keep the message in the DOM (default 7000ms)
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```tsx
|
|
91
|
+
* // Simple announcement
|
|
92
|
+
* announce('Item added to cart');
|
|
93
|
+
*
|
|
94
|
+
* // Polite announcement (won't interrupt)
|
|
95
|
+
* announce('3 results found', 'polite');
|
|
96
|
+
*
|
|
97
|
+
* // Using aria-labelledby for complex content
|
|
98
|
+
* announce({ 'aria-labelledby': 'my-element-id' });
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
function announce(message, assertiveness = "assertive", timeout = LIVEREGION_TIMEOUT_DELAY) {
|
|
102
|
+
if (!liveAnnouncer) {
|
|
103
|
+
liveAnnouncer = new LiveAnnouncer();
|
|
104
|
+
if (!(typeof globalThis.IS_SOLIDARIA_TEST === "boolean" ? globalThis.IS_SOLIDARIA_TEST : typeof globalThis.vitest !== "undefined")) setTimeout(() => {
|
|
105
|
+
if (liveAnnouncer?.isAttached()) liveAnnouncer?.announce(message, assertiveness, timeout);
|
|
106
|
+
}, 100);
|
|
107
|
+
else liveAnnouncer.announce(message, assertiveness, timeout);
|
|
108
|
+
} else liveAnnouncer.announce(message, assertiveness, timeout);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Clears all queued announcements for the given assertiveness level.
|
|
112
|
+
*
|
|
113
|
+
* @param assertiveness - Which log to clear ('assertive' or 'polite')
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```tsx
|
|
117
|
+
* // Clear assertive announcements
|
|
118
|
+
* clearAnnouncer('assertive');
|
|
119
|
+
*
|
|
120
|
+
* // Clear polite announcements
|
|
121
|
+
* clearAnnouncer('polite');
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
function clearAnnouncer(assertiveness) {
|
|
125
|
+
if (liveAnnouncer) liveAnnouncer.clear(assertiveness);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Removes the live announcer from the DOM entirely.
|
|
129
|
+
* Call this when unmounting your app or when announcements are no longer needed.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```tsx
|
|
133
|
+
* // Clean up on app unmount
|
|
134
|
+
* onCleanup(() => {
|
|
135
|
+
* destroyAnnouncer();
|
|
136
|
+
* });
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
function destroyAnnouncer() {
|
|
140
|
+
if (liveAnnouncer) {
|
|
141
|
+
liveAnnouncer.destroy();
|
|
142
|
+
liveAnnouncer = null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Hook that provides access to the live announcer with automatic cleanup.
|
|
147
|
+
*
|
|
148
|
+
* This is the recommended way to use the announcer in SolidJS components.
|
|
149
|
+
* It ensures the announcer is created only on the client and provides
|
|
150
|
+
* type-safe methods for announcing and clearing messages.
|
|
151
|
+
*
|
|
152
|
+
* SSR Safety: Returns no-op functions during SSR. The announcer is only
|
|
153
|
+
* created when the component mounts on the client.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```tsx
|
|
157
|
+
* function SearchResults(props) {
|
|
158
|
+
* const announcer = useAnnouncer();
|
|
159
|
+
*
|
|
160
|
+
* createEffect(() => {
|
|
161
|
+
* const count = props.results.length;
|
|
162
|
+
* announcer.announce(`${count} results found`, 'polite');
|
|
163
|
+
* });
|
|
164
|
+
*
|
|
165
|
+
* return <ul>...</ul>;
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```tsx
|
|
171
|
+
* function Form() {
|
|
172
|
+
* const announcer = useAnnouncer();
|
|
173
|
+
*
|
|
174
|
+
* const onSubmit = async () => {
|
|
175
|
+
* try {
|
|
176
|
+
* await submitForm();
|
|
177
|
+
* announcer.announce('Form submitted successfully');
|
|
178
|
+
* } catch (error) {
|
|
179
|
+
* announcer.announce('Error submitting form', 'assertive');
|
|
180
|
+
* }
|
|
181
|
+
* };
|
|
182
|
+
*
|
|
183
|
+
* return <form onSubmit={onSubmit}>...</form>;
|
|
184
|
+
* }
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
function useAnnouncer() {
|
|
188
|
+
if (isServer) return {
|
|
189
|
+
announce: () => {},
|
|
190
|
+
clear: () => {}
|
|
191
|
+
};
|
|
192
|
+
createEffect(() => {
|
|
193
|
+
if (!liveAnnouncer) liveAnnouncer = new LiveAnnouncer();
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
announce: (message, assertiveness = "assertive", timeout = LIVEREGION_TIMEOUT_DELAY) => {
|
|
197
|
+
announce(message, assertiveness, timeout);
|
|
198
|
+
},
|
|
199
|
+
clear: (assertiveness) => {
|
|
200
|
+
clearAnnouncer(assertiveness);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
//#endregion
|
|
205
|
+
export { useAnnouncer as i, clearAnnouncer as n, destroyAnnouncer as r, announce as t };
|
|
206
|
+
|
|
207
|
+
//# sourceMappingURL=announce.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"announce.jsx","names":[],"sources":["../../src/live-announcer/announce.ts"],"sourcesContent":["/**\n * Live announcer for solidaria\n *\n * Provides functions to make announcements to screen readers using\n * ARIA live regions. Useful for announcing dynamic content changes.\n *\n * Port of react-aria's @react-aria/live-announcer.\n *\n * SSR Safety: All functions are safe to call during SSR. The announcer\n * will only be created when running in the browser.\n */\n\nimport { onCleanup, createEffect } from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\n\nexport type Assertiveness = \"assertive\" | \"polite\";\n\nexport type Message = string | { \"aria-labelledby\": string };\n\nconst LIVEREGION_TIMEOUT_DELAY = 7000;\n\n/**\n * Singleton class that manages live region announcements.\n * Implemented using vanilla DOM for simplicity and framework independence.\n */\nclass LiveAnnouncer {\n node: HTMLElement | null = null;\n assertiveLog: HTMLElement | null = null;\n politeLog: HTMLElement | null = null;\n\n constructor() {\n if (typeof document !== \"undefined\") {\n this.node = document.createElement(\"div\");\n this.node.dataset.liveAnnouncer = \"true\";\n // Visually hidden styles\n Object.assign(this.node.style, {\n border: \"0\",\n clip: \"rect(0 0 0 0)\",\n clipPath: \"inset(50%)\",\n height: \"1px\",\n margin: \"-1px\",\n overflow: \"hidden\",\n padding: \"0\",\n position: \"absolute\",\n width: \"1px\",\n whiteSpace: \"nowrap\",\n });\n\n this.assertiveLog = this.createLog(\"assertive\");\n this.node.appendChild(this.assertiveLog);\n\n this.politeLog = this.createLog(\"polite\");\n this.node.appendChild(this.politeLog);\n\n document.body.prepend(this.node);\n }\n }\n\n isAttached(): boolean {\n return this.node?.isConnected ?? false;\n }\n\n createLog(ariaLive: string): HTMLElement {\n const node = document.createElement(\"div\");\n node.setAttribute(\"role\", \"log\");\n node.setAttribute(\"aria-live\", ariaLive);\n node.setAttribute(\"aria-relevant\", \"additions\");\n return node;\n }\n\n destroy(): void {\n if (!this.node) {\n return;\n }\n\n document.body.removeChild(this.node);\n this.node = null;\n }\n\n announce(\n message: Message,\n assertiveness: Assertiveness = \"assertive\",\n timeout: number = LIVEREGION_TIMEOUT_DELAY,\n ): void {\n if (!this.node) {\n return;\n }\n\n const node = document.createElement(\"div\");\n if (typeof message === \"object\") {\n // To read an aria-labelledby, the element must have an appropriate role, such as img.\n node.setAttribute(\"role\", \"img\");\n node.setAttribute(\"aria-labelledby\", message[\"aria-labelledby\"]);\n } else {\n node.textContent = message;\n }\n\n if (assertiveness === \"assertive\") {\n this.assertiveLog?.appendChild(node);\n } else {\n this.politeLog?.appendChild(node);\n }\n\n if (message !== \"\") {\n setTimeout(() => {\n node.remove();\n }, timeout);\n }\n }\n\n clear(assertiveness?: Assertiveness): void {\n if (!this.node) {\n return;\n }\n\n if ((!assertiveness || assertiveness === \"assertive\") && this.assertiveLog) {\n this.assertiveLog.innerHTML = \"\";\n }\n\n if ((!assertiveness || assertiveness === \"polite\") && this.politeLog) {\n this.politeLog.innerHTML = \"\";\n }\n }\n}\n\nlet liveAnnouncer: LiveAnnouncer | null = null;\n\n/**\n * Announces a message to screen readers using ARIA live regions.\n *\n * @param message - The message to announce, or an object with aria-labelledby\n * @param assertiveness - 'assertive' interrupts, 'polite' waits for a pause\n * @param timeout - How long to keep the message in the DOM (default 7000ms)\n *\n * @example\n * ```tsx\n * // Simple announcement\n * announce('Item added to cart');\n *\n * // Polite announcement (won't interrupt)\n * announce('3 results found', 'polite');\n *\n * // Using aria-labelledby for complex content\n * announce({ 'aria-labelledby': 'my-element-id' });\n * ```\n */\nexport function announce(\n message: Message,\n assertiveness: Assertiveness = \"assertive\",\n timeout: number = LIVEREGION_TIMEOUT_DELAY,\n): void {\n if (!liveAnnouncer) {\n liveAnnouncer = new LiveAnnouncer();\n // Wait for the live announcer regions to be added to the DOM, then announce.\n // Otherwise Safari won't announce the message if it's added too quickly.\n // Found most times less than 100ms were not consistent when announcing with Safari.\n\n // Check for test environment\n const isTestEnv =\n typeof (globalThis as Record<string, unknown>).IS_SOLIDARIA_TEST === \"boolean\"\n ? (globalThis as Record<string, unknown>).IS_SOLIDARIA_TEST\n : typeof (globalThis as Record<string, unknown>).vitest !== \"undefined\";\n\n if (!isTestEnv) {\n setTimeout(() => {\n if (liveAnnouncer?.isAttached()) {\n liveAnnouncer?.announce(message, assertiveness, timeout);\n }\n }, 100);\n } else {\n liveAnnouncer.announce(message, assertiveness, timeout);\n }\n } else {\n liveAnnouncer.announce(message, assertiveness, timeout);\n }\n}\n\n/**\n * Clears all queued announcements for the given assertiveness level.\n *\n * @param assertiveness - Which log to clear ('assertive' or 'polite')\n *\n * @example\n * ```tsx\n * // Clear assertive announcements\n * clearAnnouncer('assertive');\n *\n * // Clear polite announcements\n * clearAnnouncer('polite');\n * ```\n */\nexport function clearAnnouncer(assertiveness?: Assertiveness): void {\n if (liveAnnouncer) {\n liveAnnouncer.clear(assertiveness);\n }\n}\n\n/**\n * Removes the live announcer from the DOM entirely.\n * Call this when unmounting your app or when announcements are no longer needed.\n *\n * @example\n * ```tsx\n * // Clean up on app unmount\n * onCleanup(() => {\n * destroyAnnouncer();\n * });\n * ```\n */\nexport function destroyAnnouncer(): void {\n if (liveAnnouncer) {\n liveAnnouncer.destroy();\n liveAnnouncer = null;\n }\n}\n\nexport interface UseAnnouncerResult {\n /** Announce a message to screen readers. */\n announce: (message: Message, assertiveness?: Assertiveness, timeout?: number) => void;\n /** Clear announcements for the given assertiveness level. */\n clear: (assertiveness?: Assertiveness) => void;\n}\n\n/**\n * Hook that provides access to the live announcer with automatic cleanup.\n *\n * This is the recommended way to use the announcer in SolidJS components.\n * It ensures the announcer is created only on the client and provides\n * type-safe methods for announcing and clearing messages.\n *\n * SSR Safety: Returns no-op functions during SSR. The announcer is only\n * created when the component mounts on the client.\n *\n * @example\n * ```tsx\n * function SearchResults(props) {\n * const announcer = useAnnouncer();\n *\n * createEffect(() => {\n * const count = props.results.length;\n * announcer.announce(`${count} results found`, 'polite');\n * });\n *\n * return <ul>...</ul>;\n * }\n * ```\n *\n * @example\n * ```tsx\n * function Form() {\n * const announcer = useAnnouncer();\n *\n * const onSubmit = async () => {\n * try {\n * await submitForm();\n * announcer.announce('Form submitted successfully');\n * } catch (error) {\n * announcer.announce('Error submitting form', 'assertive');\n * }\n * };\n *\n * return <form onSubmit={onSubmit}>...</form>;\n * }\n * ```\n */\nexport function useAnnouncer(): UseAnnouncerResult {\n // During SSR, return no-op functions\n if (isServer) {\n return {\n announce: () => {},\n clear: () => {},\n };\n }\n\n // Ensure the announcer is initialized\n createEffect(() => {\n // Initialize on first use\n if (!liveAnnouncer) {\n liveAnnouncer = new LiveAnnouncer();\n }\n });\n\n return {\n announce: (\n message: Message,\n assertiveness: Assertiveness = \"assertive\",\n timeout: number = LIVEREGION_TIMEOUT_DELAY,\n ) => {\n announce(message, assertiveness, timeout);\n },\n clear: (assertiveness?: Assertiveness) => {\n clearAnnouncer(assertiveness);\n },\n };\n}\n"],"mappings":"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"}
|