@astryxdesign/core 0.1.1 → 0.1.2-canary.04e71b2
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/CHANGELOG.md +105 -0
- package/README.md +131 -13
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +11 -5
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
- package/dist/Banner/Banner.d.ts +7 -0
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +9 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +24 -5
- package/dist/Button/Button.d.ts +12 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +53 -17
- package/dist/Calendar/Calendar.d.ts +5 -4
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +82 -43
- package/dist/Calendar/hooks/index.d.ts +0 -2
- package/dist/Calendar/hooks/index.d.ts.map +1 -1
- package/dist/Calendar/hooks/index.js +1 -2
- package/dist/Calendar/index.d.ts +3 -3
- package/dist/Calendar/index.d.ts.map +1 -1
- package/dist/Calendar/index.js +1 -1
- package/dist/Calendar/styles.d.ts +3 -9
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +3 -11
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +17 -3
- package/dist/Center/Center.d.ts +11 -1
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +9 -3
- package/dist/Chat/ChatMessageList.d.ts +14 -1
- package/dist/Chat/ChatMessageList.d.ts.map +1 -1
- package/dist/Chat/ChatMessageList.js +2 -0
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +4 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts +23 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +51 -9
- package/dist/CheckboxList/CheckboxList.d.ts +13 -1
- package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxList.js +39 -9
- package/dist/CheckboxList/CheckboxListContext.d.ts +7 -0
- package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +3 -3
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +49 -37
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +5 -5
- package/dist/ContextMenu/ContextMenu.d.ts +4 -5
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +93 -11
- package/dist/DateInput/DateInput.d.ts +23 -1
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +59 -8
- package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +42 -9
- package/dist/DateTimeInput/DateTimeInput.d.ts +35 -2
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +78 -15
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +12 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts +1 -8
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +42 -14
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +7 -1
- package/dist/Field/Field.d.ts +19 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +4 -0
- package/dist/Field/FieldLabel.d.ts +21 -2
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +41 -26
- package/dist/FileInput/FileInput.d.ts +22 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +56 -10
- package/dist/Grid/Grid.d.ts +11 -1
- package/dist/Grid/Grid.d.ts.map +1 -1
- package/dist/Grid/Grid.js +8 -0
- package/dist/HoverCard/HoverCard.d.ts +2 -2
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +18 -6
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +7 -3
- package/dist/InputGroup/InputGroup.d.ts +2 -2
- package/dist/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/InputGroup/InputGroup.js +14 -5
- package/dist/InputGroup/InputGroupContext.d.ts +4 -0
- package/dist/InputGroup/InputGroupContext.d.ts.map +1 -1
- package/dist/InputGroup/InputGroupContext.js +2 -2
- package/dist/InputGroup/index.d.ts +1 -0
- package/dist/InputGroup/index.d.ts.map +1 -1
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +34 -2
- package/dist/Layer/anchorName.d.ts +20 -0
- package/dist/Layer/anchorName.d.ts.map +1 -0
- package/dist/Layer/anchorName.js +36 -0
- package/dist/Layer/layerAnimations.stylex.d.ts +4 -0
- package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
- package/dist/Layer/layerAnimations.stylex.js +8 -4
- package/dist/Layer/useLayer.d.ts +29 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +55 -11
- package/dist/Layout/Layout.d.ts +4 -11
- package/dist/Layout/Layout.d.ts.map +1 -1
- package/dist/Layout/Layout.js +10 -11
- package/dist/Layout/LayoutFooter.d.ts +2 -2
- package/dist/Layout/LayoutFooter.d.ts.map +1 -1
- package/dist/Layout/LayoutHeader.d.ts +2 -2
- package/dist/Layout/LayoutHeader.d.ts.map +1 -1
- package/dist/Layout/LayoutPanel.d.ts +2 -2
- package/dist/Layout/LayoutPanel.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.d.ts +51 -0
- package/dist/Layout/padding.stylex.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.js +63 -0
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +4 -2
- package/dist/Link/Link.d.ts +17 -2
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +20 -9
- package/dist/Link/LinkProvider.d.ts +1 -0
- package/dist/Link/LinkProvider.d.ts.map +1 -1
- package/dist/Link/LinkProvider.js +1 -0
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +18 -3
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +13 -0
- package/dist/MoreMenu/MoreMenu.d.ts +1 -7
- package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
- package/dist/MoreMenu/MoreMenu.js +0 -2
- package/dist/MultiSelector/MultiSelector.d.ts +25 -2
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +103 -22
- package/dist/MultiSelector/hooks.d.ts +12 -1
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +14 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +34 -3
- package/dist/NumberInput/NumberInput.d.ts +23 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +62 -12
- package/dist/Pagination/Pagination.d.ts +1 -1
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +46 -28
- package/dist/Popover/usePopover.d.ts +25 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +18 -6
- package/dist/PowerSearch/PowerSearch.d.ts +11 -1
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +6 -1
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +3 -5
- package/dist/RadioList/RadioList.d.ts +20 -2
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +105 -9
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +13 -2
- package/dist/SegmentedControl/SegmentedControl.d.ts +13 -2
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControl.js +78 -44
- package/dist/SegmentedControl/SegmentedControlContext.d.ts +7 -0
- package/dist/SegmentedControl/SegmentedControlContext.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +13 -2
- package/dist/Selector/Selector.d.ts +22 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +84 -23
- package/dist/Selector/hooks.d.ts +8 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +14 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +1 -1
- package/dist/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton/Skeleton.js +8 -2
- package/dist/Slider/Slider.d.ts +21 -0
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +38 -11
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +1 -1
- package/dist/Stack/Stack.d.ts +38 -23
- package/dist/Stack/Stack.d.ts.map +1 -1
- package/dist/Stack/Stack.js +25 -1
- package/dist/Stack/StackItem.d.ts +12 -23
- package/dist/Stack/StackItem.d.ts.map +1 -1
- package/dist/Stack/StackItem.js +8 -1
- package/dist/Switch/Switch.d.ts +23 -2
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +41 -11
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +6 -0
- package/dist/TabList/TabList.d.ts +16 -4
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +86 -10
- package/dist/TabList/TabListContext.d.ts +5 -0
- package/dist/TabList/TabListContext.d.ts.map +1 -1
- package/dist/TabList/TabListContext.js +5 -0
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +6 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +38 -16
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +36 -7
- package/dist/Table/TableCell.d.ts +8 -1
- package/dist/Table/TableCell.d.ts.map +1 -1
- package/dist/Table/TableCell.js +10 -10
- package/dist/Table/TableHeaderCell.d.ts +8 -1
- package/dist/Table/TableHeaderCell.d.ts.map +1 -1
- package/dist/Table/TableHeaderCell.js +16 -16
- package/dist/Table/TableRow.d.ts +6 -1
- package/dist/Table/TableRow.d.ts.map +1 -1
- package/dist/Table/TableRow.js +15 -7
- package/dist/Table/index.d.ts +4 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +3 -2
- package/dist/Table/plugins/pagination/paginateData.d.ts +2 -1
- package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/paginateData.js +8 -3
- package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/useTablePagination.js +6 -1
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
- package/dist/Table/plugins/stickyColumns/index.d.ts +3 -0
- package/dist/Table/plugins/stickyColumns/index.d.ts.map +1 -0
- package/dist/Table/plugins/stickyColumns/index.js +3 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts +25 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +369 -0
- package/dist/Table/tableContextMenu.d.ts +33 -0
- package/dist/Table/tableContextMenu.d.ts.map +1 -0
- package/dist/Table/tableContextMenu.js +133 -0
- package/dist/Table/types.d.ts +161 -5
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +1 -1
- package/dist/Text/text.stylex.d.ts +2 -2
- package/dist/Text/text.stylex.js +2 -2
- package/dist/TextArea/TextArea.d.ts +22 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +41 -9
- package/dist/TextInput/TextInput.d.ts +23 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +55 -10
- package/dist/TimeInput/TimeInput.d.ts +23 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +53 -10
- package/dist/Timestamp/Timestamp.d.ts +1 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +28 -3
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +14 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +132 -3
- package/dist/ToggleButton/ToggleButton.d.ts +7 -9
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +34 -57
- package/dist/Tokenizer/Tokenizer.d.ts +12 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +27 -5
- package/dist/Toolbar/Toolbar.d.ts +3 -3
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +51 -7
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +57 -9
- package/dist/TreeList/TreeList.d.ts +1 -1
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +72 -2
- package/dist/TreeList/TreeListItem.d.ts +11 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +51 -12
- package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
- package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
- package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
- package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +67 -6
- package/dist/Typeahead/Typeahead.d.ts +24 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +29 -5
- package/dist/VisuallyHidden/VisuallyHidden.d.ts +61 -0
- package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
- package/dist/VisuallyHidden/VisuallyHidden.js +65 -0
- package/dist/VisuallyHidden/index.d.ts +11 -0
- package/dist/VisuallyHidden/index.d.ts.map +1 -0
- package/dist/VisuallyHidden/index.js +13 -0
- package/dist/astryx.css +40 -1
- package/dist/astryx.umd.js +147 -0
- package/dist/astryx.umd.js.map +7 -0
- package/dist/hooks/focusableSelector.d.ts +22 -0
- package/dist/hooks/focusableSelector.d.ts.map +1 -0
- package/dist/hooks/focusableSelector.js +24 -0
- package/dist/hooks/index.d.ts +12 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +7 -2
- package/dist/hooks/useAnnounce.d.ts +40 -0
- package/dist/hooks/useAnnounce.d.ts.map +1 -0
- package/dist/hooks/useAnnounce.js +142 -0
- package/dist/hooks/useClickableContainer.d.ts +16 -1
- package/dist/hooks/useClickableContainer.d.ts.map +1 -1
- package/dist/hooks/useClickableContainer.js +16 -4
- package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
- package/dist/hooks/useEntryAnimation.js +4 -4
- package/dist/hooks/useFocusTrap.d.ts +18 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +87 -3
- package/dist/hooks/useGridFocus.d.ts +88 -1
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +261 -62
- package/dist/hooks/useKeyboardHint.d.ts +82 -0
- package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
- package/dist/hooks/useKeyboardHint.js +220 -0
- package/dist/hooks/useListFocus.d.ts +78 -7
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +305 -52
- package/dist/hooks/useLongPress.d.ts +21 -0
- package/dist/hooks/useLongPress.d.ts.map +1 -0
- package/dist/hooks/useLongPress.js +89 -0
- package/dist/hooks/useTreeFocus.d.ts +157 -0
- package/dist/hooks/useTreeFocus.d.ts.map +1 -0
- package/dist/hooks/useTreeFocus.js +337 -0
- package/dist/hooks/useTypeahead.d.ts +63 -0
- package/dist/hooks/useTypeahead.d.ts.map +1 -0
- package/dist/hooks/useTypeahead.js +117 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/generateThemeRules.js +1 -1
- package/dist/theme/syntax/SyntaxTheme.d.ts +1 -1
- package/dist/theme/syntax/SyntaxTheme.js +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.js +2 -2
- package/dist/theme/syntax/presets.d.ts +1 -1
- package/dist/theme/syntax/presets.d.ts.map +1 -1
- package/dist/theme/syntax/presets.js +1 -1
- package/dist/theme/syntax/tokens.d.ts +1 -1
- package/dist/theme/syntax/tokens.js +1 -1
- package/dist/theme/types.d.ts +1 -1
- package/dist/utils/dateTypes.d.ts +12 -0
- package/dist/utils/dateTypes.d.ts.map +1 -1
- package/dist/utils/dateTypes.js +41 -1
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/inputAria.d.ts +29 -0
- package/dist/utils/inputAria.d.ts.map +1 -0
- package/dist/utils/inputAria.js +30 -0
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +5 -2
- package/package.json +15 -5
- package/src/Avatar/Avatar.test.tsx +37 -0
- package/src/Avatar/Avatar.tsx +10 -5
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +3 -0
- package/src/Banner/Banner.doc.mjs +8 -0
- package/src/Banner/Banner.test.tsx +16 -7
- package/src/Banner/Banner.tsx +9 -2
- package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
- package/src/Button/Button.doc.mjs +6 -0
- package/src/Button/Button.test.tsx +105 -11
- package/src/Button/Button.tsx +76 -21
- package/src/Calendar/Calendar.doc.mjs +4 -4
- package/src/Calendar/Calendar.test.tsx +168 -30
- package/src/Calendar/Calendar.tsx +121 -66
- package/src/Calendar/hooks/index.ts +0 -6
- package/src/Calendar/index.ts +1 -3
- package/src/Calendar/styles.ts +4 -9
- package/src/Carousel/Carousel.doc.mjs +7 -1
- package/src/Carousel/Carousel.test.tsx +20 -0
- package/src/Carousel/Carousel.tsx +16 -1
- package/src/Center/Center.doc.mjs +12 -2
- package/src/Center/Center.tsx +28 -3
- package/src/Chat/ChatComposer.doc.mjs +3 -0
- package/src/Chat/ChatComposerDrawer.doc.mjs +12 -0
- package/src/Chat/ChatMessageList.doc.mjs +8 -0
- package/src/Chat/ChatMessageList.test.tsx +18 -0
- package/src/Chat/ChatMessageList.tsx +16 -0
- package/src/Chat/useTriggerMenu.tsx +3 -0
- package/src/CheckboxInput/CheckboxInput.doc.mjs +18 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +172 -27
- package/src/CheckboxInput/CheckboxInput.tsx +78 -6
- package/src/CheckboxList/CheckboxList.doc.mjs +9 -0
- package/src/CheckboxList/CheckboxList.test.tsx +169 -16
- package/src/CheckboxList/CheckboxList.tsx +56 -3
- package/src/CheckboxList/CheckboxListContext.tsx +7 -0
- package/src/Citation/Citation.doc.mjs +10 -0
- package/src/Citation/Citation.test.tsx +117 -0
- package/src/Citation/Citation.tsx +9 -1
- package/src/ClickableCard/ClickableCard.doc.mjs +15 -0
- package/src/CodeBlock/CodeBlock.test.tsx +115 -0
- package/src/CodeBlock/CodeBlock.tsx +61 -33
- package/src/CommandPalette/CommandPalette.test.tsx +47 -1
- package/src/CommandPalette/CommandPalette.tsx +9 -21
- package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
- package/src/ContextMenu/ContextMenu.test.tsx +155 -1
- package/src/ContextMenu/ContextMenu.tsx +113 -16
- package/src/DateInput/DateInput.doc.mjs +281 -56
- package/src/DateInput/DateInput.test.tsx +188 -2
- package/src/DateInput/DateInput.tsx +89 -10
- package/src/DateRangeInput/DateRangeInput.doc.mjs +251 -46
- package/src/DateRangeInput/DateRangeInput.test.tsx +182 -20
- package/src/DateRangeInput/DateRangeInput.tsx +63 -5
- package/src/DateTimeInput/DateTimeInput.doc.mjs +368 -67
- package/src/DateTimeInput/DateTimeInput.test.tsx +279 -11
- package/src/DateTimeInput/DateTimeInput.tsx +125 -17
- package/src/Dialog/Dialog.doc.mjs +2 -2
- package/src/Dialog/Dialog.tsx +12 -0
- package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
- package/src/DropdownMenu/DropdownMenu.test.tsx +56 -42
- package/src/DropdownMenu/DropdownMenu.tsx +52 -18
- package/src/EmptyState/EmptyState.test.tsx +4 -2
- package/src/EmptyState/EmptyState.tsx +6 -2
- package/src/Field/Field.test.tsx +32 -0
- package/src/Field/Field.tsx +23 -5
- package/src/Field/FieldLabel.tsx +55 -17
- package/src/FileInput/FileInput.doc.mjs +17 -0
- package/src/FileInput/FileInput.test.tsx +283 -49
- package/src/FileInput/FileInput.tsx +76 -4
- package/src/Grid/Grid.doc.mjs +14 -4
- package/src/Grid/Grid.tsx +20 -0
- package/src/HoverCard/HoverCard.doc.mjs +3 -0
- package/src/HoverCard/HoverCard.test.tsx +189 -2
- package/src/HoverCard/HoverCard.tsx +20 -16
- package/src/HoverCard/useHoverCard.tsx +13 -10
- package/src/Icon/Icon.doc.mjs +8 -0
- package/src/InputGroup/InputGroup.doc.mjs +2 -2
- package/src/InputGroup/InputGroup.test.tsx +98 -60
- package/src/InputGroup/InputGroup.tsx +21 -4
- package/src/InputGroup/InputGroupContext.ts +9 -4
- package/src/InputGroup/index.ts +1 -0
- package/src/Kbd/Kbd.test.tsx +22 -4
- package/src/Kbd/Kbd.tsx +37 -12
- package/src/Layer/anchorName.test.ts +146 -0
- package/src/Layer/anchorName.ts +46 -0
- package/src/Layer/layerAnimations.stylex.ts +20 -4
- package/src/Layer/useLayer.doc.mjs +12 -2
- package/src/Layer/useLayer.tsx +100 -15
- package/src/Layout/Layout.doc.mjs +1 -1
- package/src/Layout/Layout.tsx +8 -16
- package/src/Layout/LayoutFooter.doc.mjs +4 -4
- package/src/Layout/LayoutFooter.tsx +3 -3
- package/src/Layout/LayoutHeader.doc.mjs +4 -4
- package/src/Layout/LayoutHeader.tsx +3 -3
- package/src/Layout/LayoutPanel.tsx +3 -3
- package/src/Layout/padding.stylex.ts +52 -0
- package/src/Lightbox/Lightbox.doc.mjs +9 -2
- package/src/Lightbox/Lightbox.test.tsx +53 -5
- package/src/Lightbox/Lightbox.tsx +9 -4
- package/src/Link/Link.doc.mjs +14 -0
- package/src/Link/Link.test.tsx +52 -2
- package/src/Link/Link.tsx +42 -7
- package/src/Link/LinkProvider.tsx +1 -0
- package/src/List/List.doc.mjs +7 -0
- package/src/Markdown/Markdown.doc.mjs +2 -0
- package/src/Markdown/Markdown.test.tsx +28 -26
- package/src/Markdown/Markdown.tsx +21 -6
- package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
- package/src/MobileNav/MobileNav.doc.mjs +8 -8
- package/src/MobileNav/MobileNav.tsx +13 -0
- package/src/MobileNav/MobileNavReopen.test.tsx +118 -0
- package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
- package/src/MoreMenu/MoreMenu.tsx +0 -9
- package/src/MultiSelector/MultiSelector.doc.mjs +25 -0
- package/src/MultiSelector/MultiSelector.test.tsx +375 -8
- package/src/MultiSelector/MultiSelector.tsx +145 -21
- package/src/MultiSelector/hooks.ts +27 -0
- package/src/NavMenu/NavHeadingMenu.test.tsx +77 -1
- package/src/NavMenu/NavHeadingMenu.tsx +50 -3
- package/src/NumberInput/NumberInput.doc.mjs +17 -0
- package/src/NumberInput/NumberInput.test.tsx +242 -40
- package/src/NumberInput/NumberInput.tsx +89 -11
- package/src/OverflowList/OverflowList.doc.mjs +17 -0
- package/src/Pagination/Pagination.doc.mjs +3 -3
- package/src/Pagination/Pagination.test.tsx +250 -14
- package/src/Pagination/Pagination.tsx +54 -29
- package/src/Popover/usePopover.doc.mjs +7 -3
- package/src/Popover/usePopover.tsx +49 -6
- package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
- package/src/PowerSearch/PowerSearch.test.tsx +97 -1
- package/src/PowerSearch/PowerSearch.tsx +16 -3
- package/src/ProgressBar/ProgressBar.test.tsx +45 -27
- package/src/ProgressBar/ProgressBar.tsx +3 -4
- package/src/RadioList/RadioList.doc.mjs +9 -0
- package/src/RadioList/RadioList.test.tsx +252 -16
- package/src/RadioList/RadioList.tsx +166 -10
- package/src/RadioList/RadioListItem.tsx +14 -2
- package/src/Resizable/Resizable.doc.mjs +1 -1
- package/src/Section/Section.doc.mjs +11 -0
- package/src/SegmentedControl/SegmentedControl.doc.mjs +9 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +214 -42
- package/src/SegmentedControl/SegmentedControl.tsx +102 -54
- package/src/SegmentedControl/SegmentedControlContext.ts +7 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +14 -1
- package/src/SelectableCard/SelectableCard.doc.mjs +15 -0
- package/src/Selector/Selector.doc.mjs +25 -0
- package/src/Selector/Selector.test.tsx +322 -15
- package/src/Selector/Selector.tsx +126 -40
- package/src/Selector/hooks.ts +23 -0
- package/src/SideNav/SideNav.test.tsx +16 -0
- package/src/SideNav/SideNavItem.tsx +2 -4
- package/src/Skeleton/Skeleton.doc.mjs +11 -1
- package/src/Skeleton/Skeleton.test.tsx +25 -0
- package/src/Skeleton/Skeleton.tsx +11 -1
- package/src/Slider/Slider.doc.mjs +19 -0
- package/src/Slider/Slider.test.tsx +158 -18
- package/src/Slider/Slider.tsx +54 -6
- package/src/Spinner/Spinner.tsx +7 -1
- package/src/Stack/Stack.doc.mjs +77 -0
- package/src/Stack/Stack.test.tsx +55 -5
- package/src/Stack/Stack.tsx +73 -24
- package/src/Stack/StackItem.test.tsx +23 -0
- package/src/Stack/StackItem.tsx +20 -23
- package/src/Switch/Switch.doc.mjs +15 -0
- package/src/Switch/Switch.test.tsx +162 -27
- package/src/Switch/Switch.tsx +61 -21
- package/src/TabList/Tab.tsx +6 -0
- package/src/TabList/TabList.doc.mjs +12 -0
- package/src/TabList/TabList.test.tsx +208 -0
- package/src/TabList/TabList.tsx +102 -12
- package/src/TabList/TabListContext.ts +7 -3
- package/src/TabList/TabMenu.tsx +6 -3
- package/src/Table/BaseTable.tsx +72 -41
- package/src/Table/Table.doc.mjs +14 -0
- package/src/Table/Table.test.tsx +39 -30
- package/src/Table/Table.tsx +27 -1
- package/src/Table/TableCell.tsx +25 -23
- package/src/Table/TableHeaderCell.tsx +28 -29
- package/src/Table/TableRow.tsx +37 -7
- package/src/Table/index.ts +6 -2
- package/src/Table/plugins/pagination/paginateData.ts +10 -3
- package/src/Table/plugins/pagination/useTablePagination.test.tsx +16 -0
- package/src/Table/plugins/pagination/useTablePagination.tsx +8 -1
- package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
- package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
- package/src/Table/plugins/stickyColumns/index.ts +4 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +163 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +407 -0
- package/src/Table/tableContextMenu.test.tsx +157 -0
- package/src/Table/tableContextMenu.tsx +142 -0
- package/src/Table/types.ts +175 -4
- package/src/Table/useBaseTablePlugins.ts +1 -0
- package/src/Table/useTableColumnResize.doc.mjs +96 -0
- package/src/Table/useTableStickyColumns.doc.mjs +59 -0
- package/src/Text/Heading.doc.mjs +15 -2
- package/src/Text/Text.doc.mjs +7 -1
- package/src/Text/text.stylex.ts +2 -2
- package/src/TextArea/TextArea.doc.mjs +17 -0
- package/src/TextArea/TextArea.test.tsx +167 -35
- package/src/TextArea/TextArea.tsx +62 -15
- package/src/TextInput/TextInput.doc.mjs +17 -0
- package/src/TextInput/TextInput.test.tsx +168 -34
- package/src/TextInput/TextInput.tsx +77 -9
- package/src/TimeInput/TimeInput.doc.mjs +335 -60
- package/src/TimeInput/TimeInput.test.tsx +144 -7
- package/src/TimeInput/TimeInput.tsx +74 -5
- package/src/Timestamp/Timestamp.doc.mjs +9 -0
- package/src/Timestamp/Timestamp.test.tsx +44 -18
- package/src/Timestamp/Timestamp.tsx +30 -10
- package/src/Toast/Toast.tsx +14 -0
- package/src/Toast/ToastViewport.test.tsx +204 -0
- package/src/Toast/ToastViewport.tsx +167 -21
- package/src/ToggleButton/ToggleButton.doc.mjs +9 -3
- package/src/ToggleButton/ToggleButton.test.tsx +39 -18
- package/src/ToggleButton/ToggleButton.tsx +46 -83
- package/src/Tokenizer/Tokenizer.doc.mjs +15 -0
- package/src/Tokenizer/Tokenizer.test.tsx +105 -1
- package/src/Tokenizer/Tokenizer.tsx +41 -2
- package/src/Toolbar/Toolbar.doc.mjs +65 -5
- package/src/Toolbar/Toolbar.test.tsx +109 -6
- package/src/Toolbar/Toolbar.tsx +59 -5
- package/src/Tooltip/Tooltip.test.tsx +81 -0
- package/src/Tooltip/useTooltip.tsx +57 -11
- package/src/TreeList/TreeList.test.tsx +295 -6
- package/src/TreeList/TreeList.tsx +73 -1
- package/src/TreeList/TreeListItem.tsx +51 -5
- package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
- package/src/Typeahead/BaseTypeahead.tsx +86 -9
- package/src/Typeahead/Typeahead.doc.mjs +136 -30
- package/src/Typeahead/Typeahead.test.tsx +331 -1
- package/src/Typeahead/Typeahead.tsx +52 -1
- package/src/VisuallyHidden/VisuallyHidden.doc.mjs +80 -0
- package/src/VisuallyHidden/VisuallyHidden.test.tsx +76 -0
- package/src/VisuallyHidden/VisuallyHidden.tsx +113 -0
- package/src/VisuallyHidden/index.ts +15 -0
- package/src/hooks/focusableSelector.ts +25 -0
- package/src/hooks/index.ts +28 -2
- package/src/hooks/useAnnounce.test.tsx +101 -0
- package/src/hooks/useAnnounce.ts +168 -0
- package/src/hooks/useClickableContainer.ts +16 -4
- package/src/hooks/useEntryAnimation.ts +16 -4
- package/src/hooks/useFocusTrap.test.tsx +132 -0
- package/src/hooks/useFocusTrap.ts +98 -4
- package/src/hooks/useGridFocus.doc.mjs +40 -2
- package/src/hooks/useGridFocus.test.tsx +132 -0
- package/src/hooks/useGridFocus.ts +343 -67
- package/src/hooks/useImageMode.test.ts +133 -0
- package/src/hooks/useKeyboardHint.doc.mjs +101 -0
- package/src/hooks/useKeyboardHint.test.tsx +70 -0
- package/src/hooks/useKeyboardHint.tsx +332 -0
- package/src/hooks/useListFocus.doc.mjs +50 -10
- package/src/hooks/useListFocus.test.tsx +375 -0
- package/src/hooks/useListFocus.ts +395 -57
- package/src/hooks/useLongPress.test.tsx +134 -0
- package/src/hooks/useLongPress.ts +119 -0
- package/src/hooks/useTreeFocus.doc.mjs +140 -0
- package/src/hooks/useTreeFocus.test.tsx +214 -0
- package/src/hooks/useTreeFocus.ts +559 -0
- package/src/hooks/useTypeahead.test.tsx +109 -0
- package/src/hooks/useTypeahead.ts +183 -0
- package/src/index.ts +1 -0
- package/src/theme/derivedVarRegistry.test.ts +4 -0
- package/src/theme/generateThemeRules.test.ts +7 -8
- package/src/theme/generateThemeRules.ts +1 -1
- package/src/theme/syntax/SyntaxTheme.tsx +1 -1
- package/src/theme/syntax/defineSyntaxTheme.ts +20 -11
- package/src/theme/syntax/presets.ts +5 -2
- package/src/theme/syntax/tokens.ts +1 -1
- package/src/theme/types.ts +1 -1
- package/src/utils/dateTypes.test.ts +40 -0
- package/src/utils/dateTypes.ts +40 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/inputAria.test.ts +39 -0
- package/src/utils/inputAria.ts +58 -0
- package/src/utils/timeParser.test.ts +10 -0
- package/src/utils/timeParser.ts +5 -2
- package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
- package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
- package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
- package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
|
@@ -9,7 +9,15 @@
|
|
|
9
9
|
* SYNC: When Typeahead components change, update tests to match
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
describe,
|
|
14
|
+
it,
|
|
15
|
+
expect,
|
|
16
|
+
vi,
|
|
17
|
+
beforeAll,
|
|
18
|
+
afterAll,
|
|
19
|
+
beforeEach,
|
|
20
|
+
} from 'vitest';
|
|
13
21
|
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
14
22
|
import userEvent from '@testing-library/user-event';
|
|
15
23
|
import {Typeahead} from './Typeahead';
|
|
@@ -122,6 +130,47 @@ describe('BaseTypeahead', () => {
|
|
|
122
130
|
});
|
|
123
131
|
});
|
|
124
132
|
|
|
133
|
+
it('announces the result count to a live region (comboboxes-6)', async () => {
|
|
134
|
+
render(
|
|
135
|
+
<BaseTypeahead
|
|
136
|
+
searchSource={fruitSource}
|
|
137
|
+
value={null}
|
|
138
|
+
onChange={() => {}}
|
|
139
|
+
debounceMs={0}
|
|
140
|
+
/>,
|
|
141
|
+
);
|
|
142
|
+
const input = screen.getByRole('combobox');
|
|
143
|
+
fireEvent.change(input, {target: {value: 'Ap'}});
|
|
144
|
+
|
|
145
|
+
await waitFor(() => {
|
|
146
|
+
const region = document.querySelector(
|
|
147
|
+
'[data-astryx-live-region="polite"]',
|
|
148
|
+
);
|
|
149
|
+
expect(region?.textContent).toMatch(/\d+ results?/);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('announces "no results found" when the search is empty (comboboxes-6)', async () => {
|
|
154
|
+
render(
|
|
155
|
+
<BaseTypeahead
|
|
156
|
+
searchSource={fruitSource}
|
|
157
|
+
value={null}
|
|
158
|
+
onChange={() => {}}
|
|
159
|
+
debounceMs={0}
|
|
160
|
+
emptySearchResultsText="No results found"
|
|
161
|
+
/>,
|
|
162
|
+
);
|
|
163
|
+
const input = screen.getByRole('combobox');
|
|
164
|
+
fireEvent.change(input, {target: {value: 'zzzzz'}});
|
|
165
|
+
|
|
166
|
+
await waitFor(() => {
|
|
167
|
+
const region = document.querySelector(
|
|
168
|
+
'[data-astryx-live-region="polite"]',
|
|
169
|
+
);
|
|
170
|
+
expect(region).toHaveTextContent('No results found');
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
125
174
|
it('disables input when isDisabled', () => {
|
|
126
175
|
render(
|
|
127
176
|
<BaseTypeahead
|
|
@@ -180,6 +229,90 @@ describe('BaseTypeahead', () => {
|
|
|
180
229
|
});
|
|
181
230
|
});
|
|
182
231
|
|
|
232
|
+
describe('BaseTypeahead focus-out', () => {
|
|
233
|
+
it('closes the dropdown when focus leaves the input', async () => {
|
|
234
|
+
render(
|
|
235
|
+
<>
|
|
236
|
+
<BaseTypeahead
|
|
237
|
+
searchSource={fruitSource}
|
|
238
|
+
value={null}
|
|
239
|
+
onChange={() => {}}
|
|
240
|
+
debounceMs={0}
|
|
241
|
+
/>
|
|
242
|
+
<button type="button">Outside</button>
|
|
243
|
+
</>,
|
|
244
|
+
);
|
|
245
|
+
const input = screen.getByRole('combobox');
|
|
246
|
+
fireEvent.change(input, {target: {value: 'App'}});
|
|
247
|
+
|
|
248
|
+
await waitFor(() => {
|
|
249
|
+
expect(input).toHaveAttribute('aria-expanded', 'true');
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Focus moves to an element outside the field/dropdown → menu closes.
|
|
253
|
+
const outside = screen.getByRole('button', {name: 'Outside'});
|
|
254
|
+
fireEvent.blur(input, {relatedTarget: outside});
|
|
255
|
+
|
|
256
|
+
await waitFor(() => {
|
|
257
|
+
expect(input).toHaveAttribute('aria-expanded', 'false');
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('keeps the dropdown open when focus moves into the anchor wrapper', async () => {
|
|
262
|
+
const anchor = document.createElement('div');
|
|
263
|
+
document.body.appendChild(anchor);
|
|
264
|
+
const anchorRef = {current: anchor};
|
|
265
|
+
render(
|
|
266
|
+
<BaseTypeahead
|
|
267
|
+
searchSource={fruitSource}
|
|
268
|
+
value={null}
|
|
269
|
+
onChange={() => {}}
|
|
270
|
+
anchorRef={anchorRef}
|
|
271
|
+
debounceMs={0}
|
|
272
|
+
/>,
|
|
273
|
+
);
|
|
274
|
+
const input = screen.getByRole('combobox');
|
|
275
|
+
// The input lives inside the wrapper we hand to anchorRef.
|
|
276
|
+
anchor.appendChild(input.closest('div') ?? input);
|
|
277
|
+
fireEvent.change(input, {target: {value: 'App'}});
|
|
278
|
+
|
|
279
|
+
await waitFor(() => {
|
|
280
|
+
expect(input).toHaveAttribute('aria-expanded', 'true');
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// A sibling control inside the field (e.g. a clear button) receives focus.
|
|
284
|
+
const sibling = document.createElement('button');
|
|
285
|
+
anchor.appendChild(sibling);
|
|
286
|
+
fireEvent.blur(input, {relatedTarget: sibling});
|
|
287
|
+
|
|
288
|
+
// Menu stays open because focus is still within the field.
|
|
289
|
+
expect(input).toHaveAttribute('aria-expanded', 'true');
|
|
290
|
+
document.body.removeChild(anchor);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('does not close when a dropdown option receives focus', async () => {
|
|
294
|
+
render(
|
|
295
|
+
<BaseTypeahead
|
|
296
|
+
searchSource={fruitSource}
|
|
297
|
+
value={null}
|
|
298
|
+
onChange={() => {}}
|
|
299
|
+
debounceMs={0}
|
|
300
|
+
/>,
|
|
301
|
+
);
|
|
302
|
+
const input = screen.getByRole('combobox');
|
|
303
|
+
fireEvent.change(input, {target: {value: 'App'}});
|
|
304
|
+
|
|
305
|
+
await waitFor(() => {
|
|
306
|
+
expect(input).toHaveAttribute('aria-expanded', 'true');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const option = screen.getByRole('option', {hidden: true});
|
|
310
|
+
fireEvent.blur(input, {relatedTarget: option});
|
|
311
|
+
|
|
312
|
+
expect(input).toHaveAttribute('aria-expanded', 'true');
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
183
316
|
describe('Typeahead', () => {
|
|
184
317
|
it('renders with label', () => {
|
|
185
318
|
render(
|
|
@@ -573,4 +706,201 @@ describe('BaseTypeahead paste behavior', () => {
|
|
|
573
706
|
expect(screen.getByText('No results found')).toBeInTheDocument();
|
|
574
707
|
});
|
|
575
708
|
});
|
|
709
|
+
|
|
710
|
+
it('scrolls the highlighted option into view during arrow navigation', async () => {
|
|
711
|
+
const scrollIntoView = vi.fn();
|
|
712
|
+
Object.defineProperty(HTMLElement.prototype, 'scrollIntoView', {
|
|
713
|
+
configurable: true,
|
|
714
|
+
value: scrollIntoView,
|
|
715
|
+
});
|
|
716
|
+
try {
|
|
717
|
+
const user = userEvent.setup();
|
|
718
|
+
render(
|
|
719
|
+
<BaseTypeahead
|
|
720
|
+
searchSource={fruitSource}
|
|
721
|
+
value={null}
|
|
722
|
+
onChange={() => {}}
|
|
723
|
+
debounceMs={0}
|
|
724
|
+
/>,
|
|
725
|
+
);
|
|
726
|
+
|
|
727
|
+
const input = screen.getByRole('combobox');
|
|
728
|
+
await user.click(input);
|
|
729
|
+
await user.paste('e'); // matches multiple fruits, opens listbox
|
|
730
|
+
await waitFor(() => {
|
|
731
|
+
expect(screen.getByRole('listbox', {hidden: true})).toBeInTheDocument();
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
scrollIntoView.mockClear();
|
|
735
|
+
await user.keyboard('{ArrowDown}');
|
|
736
|
+
await user.keyboard('{ArrowDown}');
|
|
737
|
+
|
|
738
|
+
expect(scrollIntoView).toHaveBeenCalledWith({block: 'nearest'});
|
|
739
|
+
} finally {
|
|
740
|
+
delete (HTMLElement.prototype as unknown as {scrollIntoView?: unknown})
|
|
741
|
+
.scrollIntoView;
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
describe('Typeahead disabledMessage', () => {
|
|
747
|
+
// jsdom does not implement the Popover API used by the tooltip, so mock
|
|
748
|
+
// showPopover/hidePopover to toggle a `popover-open` attribute the tests
|
|
749
|
+
// can assert on.
|
|
750
|
+
beforeEach(() => {
|
|
751
|
+
HTMLElement.prototype.showPopover = vi.fn(function (this: HTMLElement) {
|
|
752
|
+
this.setAttribute('popover-open', '');
|
|
753
|
+
});
|
|
754
|
+
HTMLElement.prototype.hidePopover = vi.fn(function (this: HTMLElement) {
|
|
755
|
+
this.removeAttribute('popover-open');
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
// jsdom popover content is in the DOM but not "visible" in the
|
|
760
|
+
// accessibility tree; use hidden: true to find it.
|
|
761
|
+
const h = {hidden: true} as const;
|
|
762
|
+
|
|
763
|
+
it('shows the reason tooltip on hover when disabled with a reason', async () => {
|
|
764
|
+
render(
|
|
765
|
+
<Typeahead
|
|
766
|
+
label="Assignee"
|
|
767
|
+
searchSource={fruitSource}
|
|
768
|
+
value={null}
|
|
769
|
+
onChange={() => {}}
|
|
770
|
+
isDisabled
|
|
771
|
+
disabledMessage="You need the Editor role"
|
|
772
|
+
/>,
|
|
773
|
+
);
|
|
774
|
+
|
|
775
|
+
const container = screen.getByRole('combobox').parentElement as HTMLElement;
|
|
776
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
777
|
+
expect(tooltip).toHaveTextContent('You need the Editor role');
|
|
778
|
+
|
|
779
|
+
fireEvent.mouseEnter(container);
|
|
780
|
+
await waitFor(() => {
|
|
781
|
+
expect(tooltip).toHaveAttribute('popover-open');
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
fireEvent.mouseLeave(container);
|
|
785
|
+
await waitFor(() => {
|
|
786
|
+
expect(tooltip).not.toHaveAttribute('popover-open');
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
it('shows the reason tooltip on keyboard focus', async () => {
|
|
791
|
+
const user = userEvent.setup();
|
|
792
|
+
render(
|
|
793
|
+
<Typeahead
|
|
794
|
+
label="Assignee"
|
|
795
|
+
searchSource={fruitSource}
|
|
796
|
+
value={null}
|
|
797
|
+
onChange={() => {}}
|
|
798
|
+
isDisabled
|
|
799
|
+
disabledMessage="You need the Editor role"
|
|
800
|
+
/>,
|
|
801
|
+
);
|
|
802
|
+
|
|
803
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
804
|
+
await user.tab();
|
|
805
|
+
expect(screen.getByRole('combobox')).toHaveFocus();
|
|
806
|
+
await waitFor(() => {
|
|
807
|
+
expect(tooltip).toHaveAttribute('popover-open');
|
|
808
|
+
});
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
it('does not render a tooltip when not disabled', () => {
|
|
812
|
+
render(
|
|
813
|
+
<Typeahead
|
|
814
|
+
label="Assignee"
|
|
815
|
+
searchSource={fruitSource}
|
|
816
|
+
value={null}
|
|
817
|
+
onChange={() => {}}
|
|
818
|
+
disabledMessage="You need the Editor role"
|
|
819
|
+
/>,
|
|
820
|
+
);
|
|
821
|
+
expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
it('does not render a tooltip when disabled without a reason', () => {
|
|
825
|
+
render(
|
|
826
|
+
<Typeahead
|
|
827
|
+
label="Assignee"
|
|
828
|
+
searchSource={fruitSource}
|
|
829
|
+
value={null}
|
|
830
|
+
onChange={() => {}}
|
|
831
|
+
isDisabled
|
|
832
|
+
/>,
|
|
833
|
+
);
|
|
834
|
+
expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
it('keeps the input focusable via aria-disabled when a reason is provided', () => {
|
|
838
|
+
render(
|
|
839
|
+
<Typeahead
|
|
840
|
+
label="Assignee"
|
|
841
|
+
searchSource={fruitSource}
|
|
842
|
+
value={null}
|
|
843
|
+
onChange={() => {}}
|
|
844
|
+
isDisabled
|
|
845
|
+
disabledMessage="You need the Editor role"
|
|
846
|
+
/>,
|
|
847
|
+
);
|
|
848
|
+
const input = screen.getByRole('combobox');
|
|
849
|
+
expect(input).not.toBeDisabled();
|
|
850
|
+
expect(input).toHaveAttribute('aria-disabled', 'true');
|
|
851
|
+
expect(input).toHaveAttribute('readonly');
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
it('links the reason tooltip from the input via aria-describedby', () => {
|
|
855
|
+
render(
|
|
856
|
+
<Typeahead
|
|
857
|
+
label="Assignee"
|
|
858
|
+
searchSource={fruitSource}
|
|
859
|
+
value={null}
|
|
860
|
+
onChange={() => {}}
|
|
861
|
+
isDisabled
|
|
862
|
+
disabledMessage="You need the Editor role"
|
|
863
|
+
/>,
|
|
864
|
+
);
|
|
865
|
+
const input = screen.getByRole('combobox');
|
|
866
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
867
|
+
expect(input.getAttribute('aria-describedby')).toContain(tooltip.id);
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
it('blocks typing and selection while focusable-disabled', async () => {
|
|
871
|
+
const user = userEvent.setup();
|
|
872
|
+
const onChange = vi.fn();
|
|
873
|
+
render(
|
|
874
|
+
<Typeahead
|
|
875
|
+
label="Assignee"
|
|
876
|
+
searchSource={fruitSource}
|
|
877
|
+
value={null}
|
|
878
|
+
onChange={onChange}
|
|
879
|
+
isDisabled
|
|
880
|
+
disabledMessage="You need the Editor role"
|
|
881
|
+
/>,
|
|
882
|
+
);
|
|
883
|
+
|
|
884
|
+
const input = screen.getByRole('combobox');
|
|
885
|
+
await user.click(input);
|
|
886
|
+
await user.type(input, 'App');
|
|
887
|
+
expect(input).toHaveValue('');
|
|
888
|
+
expect(input).toHaveAttribute('aria-expanded', 'false');
|
|
889
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
it('remains natively disabled when disabled without a reason', () => {
|
|
893
|
+
render(
|
|
894
|
+
<Typeahead
|
|
895
|
+
label="Assignee"
|
|
896
|
+
searchSource={fruitSource}
|
|
897
|
+
value={null}
|
|
898
|
+
onChange={() => {}}
|
|
899
|
+
isDisabled
|
|
900
|
+
/>,
|
|
901
|
+
);
|
|
902
|
+
const input = screen.getByRole('combobox');
|
|
903
|
+
expect(input).toBeDisabled();
|
|
904
|
+
expect(input).not.toHaveAttribute('aria-disabled');
|
|
905
|
+
});
|
|
576
906
|
});
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
inputStatusFocusWithinStyles,
|
|
39
39
|
} from '../Field';
|
|
40
40
|
import {Token} from '../Token';
|
|
41
|
+
import {useTooltip} from '../Tooltip';
|
|
41
42
|
import {renderIconSlot, type IconType} from '../Icon';
|
|
42
43
|
import {spacingVars, sizeVars} from '../theme/tokens.stylex';
|
|
43
44
|
import {mergeProps} from '../utils';
|
|
@@ -101,6 +102,29 @@ export interface TypeaheadProps<T extends SearchableItem> extends Omit<
|
|
|
101
102
|
emptySearchResultsText?: string;
|
|
102
103
|
/** Whether the input is disabled. @default false */
|
|
103
104
|
isDisabled?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Explains why the input is disabled. When set together with `isDisabled`,
|
|
107
|
+
* the input shows a tooltip with this text on hover and keyboard focus, and
|
|
108
|
+
* the field stays focusable (via `aria-disabled`) so the reason is
|
|
109
|
+
* discoverable by keyboard and assistive technology. Editing and selection
|
|
110
|
+
* stay blocked.
|
|
111
|
+
*
|
|
112
|
+
* Use this instead of wrapping a disabled input in `Tooltip` — disabled
|
|
113
|
+
* controls don't emit the pointer events an external tooltip needs.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```
|
|
117
|
+
* <Typeahead
|
|
118
|
+
* label="Assignee"
|
|
119
|
+
* searchSource={userSource}
|
|
120
|
+
* value={assignee}
|
|
121
|
+
* onChange={setAssignee}
|
|
122
|
+
* isDisabled
|
|
123
|
+
* disabledMessage="You need the Editor role to change this"
|
|
124
|
+
* />
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
disabledMessage?: string;
|
|
104
128
|
/** Show clear button. @default true */
|
|
105
129
|
hasClear?: boolean;
|
|
106
130
|
/** Auto-focus on mount. @default false */
|
|
@@ -209,6 +233,7 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
209
233
|
maxMenuItems,
|
|
210
234
|
emptySearchResultsText,
|
|
211
235
|
isDisabled = false,
|
|
236
|
+
disabledMessage,
|
|
212
237
|
hasClear = true,
|
|
213
238
|
hasAutoFocus,
|
|
214
239
|
size: sizeProp,
|
|
@@ -230,6 +255,21 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
230
255
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
231
256
|
const tokenRef = useRef<HTMLElement>(null);
|
|
232
257
|
|
|
258
|
+
// Disabled-reason tooltip. Disabled controls swallow pointer events, so the
|
|
259
|
+
// tooltip listeners attach to the input wrapper (which already exists) and
|
|
260
|
+
// the input stays perceivable via aria-disabled + readOnly instead of the
|
|
261
|
+
// disabled attribute. Editing and selection stay blocked by the isDisabled
|
|
262
|
+
// guards (handleWrapperClick, handleEnterEditMode, and BaseTypeahead's own
|
|
263
|
+
// focus/change guards).
|
|
264
|
+
const showsDisabledMessage = isDisabled && !!disabledMessage;
|
|
265
|
+
const disabledMessageTooltip = useTooltip({
|
|
266
|
+
placement: 'above',
|
|
267
|
+
// The wrapper div is not naturally focusable; focusin bubbles up from the
|
|
268
|
+
// input, so always attach focus listeners.
|
|
269
|
+
focusTrigger: 'always',
|
|
270
|
+
isEnabled: showsDisabledMessage,
|
|
271
|
+
});
|
|
272
|
+
|
|
233
273
|
// Edit mode: when the user clicks the token to edit the selected value
|
|
234
274
|
const [isEditing, setIsEditing] = useState(false);
|
|
235
275
|
const [editingValue, setEditingValue] = useState<T | null>(null);
|
|
@@ -339,6 +379,7 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
339
379
|
[
|
|
340
380
|
description ? descriptionId : null,
|
|
341
381
|
status?.message ? statusMessageId : null,
|
|
382
|
+
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
342
383
|
]
|
|
343
384
|
.filter(Boolean)
|
|
344
385
|
.join(' ') || undefined;
|
|
@@ -371,7 +412,13 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
371
412
|
className={className}
|
|
372
413
|
style={style}>
|
|
373
414
|
<div
|
|
374
|
-
ref={
|
|
415
|
+
ref={el => {
|
|
416
|
+
wrapperRef.current = el;
|
|
417
|
+
// Anchor + hover/focus listeners for the disabled-message tooltip.
|
|
418
|
+
// Handlers are gated internally by isEnabled, so attaching
|
|
419
|
+
// unconditionally is safe.
|
|
420
|
+
disabledMessageTooltip.ref(el);
|
|
421
|
+
}}
|
|
375
422
|
data-testid={testId}
|
|
376
423
|
onClick={handleWrapperClick}
|
|
377
424
|
onBlur={handleBlur}
|
|
@@ -411,6 +458,7 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
411
458
|
emptySearchResultsText={emptySearchResultsText}
|
|
412
459
|
isDisabled={isDisabled}
|
|
413
460
|
hasAutoFocus={hasAutoFocus}
|
|
461
|
+
isFocusableDisabled={showsDisabledMessage}
|
|
414
462
|
inputId={inputId}
|
|
415
463
|
ariaDescribedBy={ariaDescribedBy}
|
|
416
464
|
onChangeQuery={onChangeQuery}
|
|
@@ -432,6 +480,9 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
432
480
|
/>
|
|
433
481
|
)}
|
|
434
482
|
</div>
|
|
483
|
+
|
|
484
|
+
{showsDisabledMessage &&
|
|
485
|
+
disabledMessageTooltip.renderTooltip(disabledMessage)}
|
|
435
486
|
</Field>
|
|
436
487
|
);
|
|
437
488
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/** @type {import('../docs-types').ComponentDoc} */
|
|
6
|
+
|
|
7
|
+
export const docs = {
|
|
8
|
+
name: 'VisuallyHidden',
|
|
9
|
+
displayName: 'VisuallyHidden',
|
|
10
|
+
category: 'Utility',
|
|
11
|
+
keywords: ["visually hidden","sr-only","screen reader","accessibility","a11y","aria-live","hidden label","assistive technology"],
|
|
12
|
+
props: [
|
|
13
|
+
{
|
|
14
|
+
name: 'children',
|
|
15
|
+
type: 'ReactNode',
|
|
16
|
+
description: 'Content exposed to assistive technology while hidden from sight.',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'as',
|
|
20
|
+
type: 'ElementType',
|
|
21
|
+
description: 'HTML tag to render as. Use a block element for live regions.',
|
|
22
|
+
default: "'span'",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
usage: {
|
|
26
|
+
description: 'Renders content in the accessibility tree while hiding it visually. Use for accessible names on icon-only controls, aria-live announcement regions, and supplementary screen-reader context. Deliberately has no styling props; the whole point is to stay invisible.',
|
|
27
|
+
bestPractices: [
|
|
28
|
+
{ guidance: true, description: 'Use to give icon-only buttons and controls an accessible name that screen readers announce.' },
|
|
29
|
+
{ guidance: true, description: 'Render as a block element (as="div") with aria-live to announce dynamic updates like drag-and-drop or result counts.' },
|
|
30
|
+
{ guidance: false, description: 'Use it to hide content from everyone; it stays in the accessibility tree; use conditional rendering or `hidden` to remove content entirely.' },
|
|
31
|
+
{ guidance: false, description: 'Put interactive controls inside it; the content is not visible and cannot receive pointer input.' },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** @type {import('../docs-types').ComponentDoc} */
|
|
37
|
+
export const docsZh = {
|
|
38
|
+
name: 'VisuallyHidden',
|
|
39
|
+
displayName: 'VisuallyHidden',
|
|
40
|
+
props: [
|
|
41
|
+
{
|
|
42
|
+
name: 'children',
|
|
43
|
+
type: 'ReactNode',
|
|
44
|
+
description: '对辅助技术公开但对视觉隐藏的内容。',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'as',
|
|
48
|
+
type: 'ElementType',
|
|
49
|
+
description: '要渲染的 HTML 标签。实时区域请使用块级元素。',
|
|
50
|
+
default: "'span'",
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
usage: {
|
|
54
|
+
description: 'Renders content in the accessibility tree while hiding it visually. Use for accessible names on icon-only controls, aria-live announcement regions, and supplementary screen-reader context.',
|
|
55
|
+
bestPractices: [
|
|
56
|
+
{ guidance: true, description: 'Use to give icon-only buttons and controls an accessible name that screen readers announce.' },
|
|
57
|
+
{ guidance: true, description: 'Render as a block element (as="div") with aria-live to announce dynamic updates like drag-and-drop or result counts.' },
|
|
58
|
+
{ guidance: false, description: 'Use it to hide content from everyone; it stays in the accessibility tree; use conditional rendering or `hidden` to remove content entirely.' },
|
|
59
|
+
{ guidance: false, description: 'Put interactive controls inside it; the content is not visible and cannot receive pointer input.' },
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** @type {import('../docs-types').TranslationDoc} */
|
|
65
|
+
export const docsDense = {
|
|
66
|
+
description: 'renders content in the a11y tree while hiding it visually (sr-only)',
|
|
67
|
+
usage: {
|
|
68
|
+
description: 'Renders content in the accessibility tree while hiding it visually. Use for accessible names on icon-only controls, aria-live announcement regions, and supplementary screen-reader context.',
|
|
69
|
+
bestPractices: [
|
|
70
|
+
{ guidance: true, description: 'Use to give icon-only buttons and controls an accessible name that screen readers announce.' },
|
|
71
|
+
{ guidance: true, description: 'Render as a block element (as="div") with aria-live to announce dynamic updates like drag-and-drop or result counts.' },
|
|
72
|
+
{ guidance: false, description: 'Use it to hide content from everyone; it stays in the accessibility tree; use conditional rendering or `hidden` to remove content entirely.' },
|
|
73
|
+
{ guidance: false, description: 'Put interactive controls inside it; the content is not visible and cannot receive pointer input.' },
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
propDescriptions: {
|
|
77
|
+
children: 'content exposed to AT while visually hidden',
|
|
78
|
+
as: 'HTML tag to render as; block element for live regions',
|
|
79
|
+
},
|
|
80
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file VisuallyHidden.test.tsx
|
|
5
|
+
* @input Uses vitest, @testing-library/react, VisuallyHidden component
|
|
6
|
+
* @output Unit tests for VisuallyHidden rendering + a11y behavior
|
|
7
|
+
* @position Testing; validates VisuallyHidden.tsx implementation
|
|
8
|
+
*
|
|
9
|
+
* SYNC: When VisuallyHidden.tsx changes, update tests to match new behavior
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {describe, it, expect} from 'vitest';
|
|
13
|
+
import {render, screen} from '@testing-library/react';
|
|
14
|
+
import {createRef} from 'react';
|
|
15
|
+
import {VisuallyHidden} from './VisuallyHidden';
|
|
16
|
+
|
|
17
|
+
describe('VisuallyHidden', () => {
|
|
18
|
+
it('renders its children in the accessibility tree', () => {
|
|
19
|
+
render(<VisuallyHidden>Delete incident</VisuallyHidden>);
|
|
20
|
+
// Present in the a11y tree (getByText finds it — it is not display:none).
|
|
21
|
+
expect(screen.getByText('Delete incident')).toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('renders a <span> by default', () => {
|
|
25
|
+
render(<VisuallyHidden>Label</VisuallyHidden>);
|
|
26
|
+
expect(screen.getByText('Label').tagName).toBe('SPAN');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('renders a custom element via the `as` prop', () => {
|
|
30
|
+
render(
|
|
31
|
+
<VisuallyHidden as="div" aria-live="polite">
|
|
32
|
+
Moved task to Done
|
|
33
|
+
</VisuallyHidden>,
|
|
34
|
+
);
|
|
35
|
+
const el = screen.getByText('Moved task to Done');
|
|
36
|
+
expect(el.tagName).toBe('DIV');
|
|
37
|
+
expect(el).toHaveAttribute('aria-live', 'polite');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('applies the clip styles that hide it visually', () => {
|
|
41
|
+
render(<VisuallyHidden>Hidden</VisuallyHidden>);
|
|
42
|
+
const el = screen.getByText('Hidden');
|
|
43
|
+
// jsdom does not apply the stylesheet, but the StyleX class is attached.
|
|
44
|
+
expect(el.getAttribute('class')).toBeTruthy();
|
|
45
|
+
// It must NOT be display:none / hidden — it stays in the a11y tree.
|
|
46
|
+
expect(el).not.toHaveAttribute('hidden');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('forwards a ref to the rendered element', () => {
|
|
50
|
+
const ref = createRef<HTMLElement>();
|
|
51
|
+
render(<VisuallyHidden ref={ref}>Ref target</VisuallyHidden>);
|
|
52
|
+
expect(ref.current).toBeInstanceOf(HTMLElement);
|
|
53
|
+
expect(ref.current?.textContent).toBe('Ref target');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('passes through arbitrary BaseProps (id, role, data-*)', () => {
|
|
57
|
+
render(
|
|
58
|
+
<VisuallyHidden id="announcer" role="status" data-testid="vh">
|
|
59
|
+
Status
|
|
60
|
+
</VisuallyHidden>,
|
|
61
|
+
);
|
|
62
|
+
const el = screen.getByTestId('vh');
|
|
63
|
+
expect(el).toHaveAttribute('id', 'announcer');
|
|
64
|
+
expect(el).toHaveAttribute('role', 'status');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('gives an icon-only control an accessible name', () => {
|
|
68
|
+
render(
|
|
69
|
+
<button type="button">
|
|
70
|
+
<span aria-hidden="true">🗑️</span>
|
|
71
|
+
<VisuallyHidden>Delete</VisuallyHidden>
|
|
72
|
+
</button>,
|
|
73
|
+
);
|
|
74
|
+
expect(screen.getByRole('button', {name: 'Delete'})).toBeInTheDocument();
|
|
75
|
+
});
|
|
76
|
+
});
|