@astryxdesign/core 0.1.2 → 0.1.3-canary.6d57c8d
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 +165 -0
- package/README.md +12 -12
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +11 -5
- 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.map +1 -1
- package/dist/Button/Button.js +2 -4
- package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
- package/dist/ButtonGroup/ButtonGroup.js +0 -1
- 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/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +0 -1
- 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 +8 -1
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +15 -3
- 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/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +0 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +9 -5
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +51 -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 +167 -99
- 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/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 +32 -6
- package/dist/InputGroup/InputGroup.d.ts +4 -3
- package/dist/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/InputGroup/InputGroup.js +16 -6
- 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/groupStyles.d.ts +1 -1
- package/dist/InputGroup/groupStyles.d.ts.map +1 -1
- package/dist/InputGroup/groupStyles.js +3 -3
- 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 +33 -1
- 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 +10 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +64 -9
- 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 +16 -1
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +18 -7
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +7 -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 +27 -2
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +141 -42
- 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 +15 -1
- package/dist/Popover/Popover.d.ts +18 -2
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +5 -2
- package/dist/Popover/usePopover.d.ts +38 -3
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +24 -9
- 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 +24 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +122 -43
- 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/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +2 -0
- 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 +36 -9
- 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 +87 -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 +11 -8
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +10 -1
- 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/index.d.ts +2 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +2 -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/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 +66 -0
- package/dist/Table/types.d.ts.map +1 -1
- 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 +147 -76
- 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 +131 -3
- package/dist/Tokenizer/Tokenizer.d.ts +12 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +26 -4
- 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 +56 -9
- package/dist/TopNav/TopNavHeading.d.ts +7 -1
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +8 -0
- 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 +13 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +69 -6
- package/dist/Typeahead/Typeahead.d.ts +26 -3
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +65 -29
- 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 +18 -0
- package/dist/astryx.umd.js +55 -55
- package/dist/astryx.umd.js.map +4 -4
- 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/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/docs.mjs +2 -2
- package/package.json +12 -8
- package/src/Avatar/Avatar.test.tsx +37 -0
- package/src/Avatar/Avatar.tsx +10 -5
- package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
- package/src/Button/Button.tsx +3 -16
- package/src/ButtonGroup/ButtonGroup.test.tsx +9 -9
- package/src/ButtonGroup/ButtonGroup.tsx +0 -1
- 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/ChatComposerInput.test.tsx +26 -7
- package/src/Chat/ChatComposerInput.tsx +0 -1
- package/src/Chat/ChatDictationButton.doc.mjs +1 -1
- 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 +22 -4
- package/src/CheckboxInput/CheckboxInput.doc.mjs +10 -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 +192 -26
- package/src/CheckboxList/CheckboxList.tsx +56 -3
- package/src/CheckboxList/CheckboxListContext.tsx +7 -0
- package/src/CheckboxList/CheckboxListItem.tsx +0 -3
- package/src/Citation/Citation.doc.mjs +10 -0
- package/src/Citation/Citation.test.tsx +121 -0
- package/src/Citation/Citation.tsx +15 -3
- package/src/CodeBlock/CodeBlock.test.tsx +115 -0
- package/src/CodeBlock/CodeBlock.tsx +63 -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 +286 -56
- package/src/DateInput/DateInput.test.tsx +248 -2
- package/src/DateInput/DateInput.tsx +196 -100
- 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/Field/Field.doc.mjs +59 -18
- 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 +17 -4
- package/src/Grid/Grid.test.tsx +43 -30
- package/src/Grid/Grid.tsx +38 -3
- package/src/Icon/Icon.doc.mjs +3 -3
- package/src/InputGroup/InputGroup.doc.mjs +111 -23
- package/src/InputGroup/InputGroup.test.tsx +257 -60
- package/src/InputGroup/InputGroup.tsx +23 -5
- package/src/InputGroup/InputGroupContext.ts +9 -4
- package/src/InputGroup/groupStyles.ts +7 -1
- package/src/InputGroup/index.ts +1 -0
- package/src/Kbd/Kbd.test.tsx +22 -4
- package/src/Kbd/Kbd.tsx +35 -3
- package/src/Layer/layerAnimations.stylex.ts +20 -4
- package/src/Layer/useLayer.doc.mjs +5 -0
- package/src/Layer/useLayer.test.tsx +111 -0
- package/src/Layer/useLayer.tsx +90 -9
- 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 -0
- 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 +50 -0
- package/src/Link/Link.tsx +39 -4
- package/src/Markdown/Markdown.test.tsx +11 -0
- package/src/Markdown/Markdown.tsx +7 -0
- package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
- package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
- package/src/MoreMenu/MoreMenu.tsx +0 -9
- package/src/MultiSelector/MultiSelector.doc.mjs +30 -0
- package/src/MultiSelector/MultiSelector.test.tsx +375 -8
- package/src/MultiSelector/MultiSelector.tsx +194 -48
- 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/Pagination/Pagination.doc.mjs +3 -3
- package/src/Pagination/Pagination.test.tsx +117 -5
- package/src/Pagination/Pagination.tsx +21 -1
- package/src/Popover/Popover.doc.mjs +26 -0
- package/src/Popover/Popover.test.tsx +121 -0
- package/src/Popover/Popover.tsx +23 -2
- package/src/Popover/usePopover.doc.mjs +9 -3
- package/src/Popover/usePopover.tsx +70 -12
- 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 +34 -26
- 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/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 +1 -1
- package/src/Selector/Selector.doc.mjs +26 -0
- package/src/Selector/Selector.test.tsx +387 -15
- package/src/Selector/Selector.tsx +175 -67
- package/src/Selector/hooks.ts +23 -0
- package/src/SideNav/SideNav.test.tsx +48 -0
- package/src/SideNav/SideNavHeading.tsx +8 -2
- package/src/SideNav/SideNavItem.tsx +2 -4
- package/src/Skeleton/Skeleton.test.tsx +25 -0
- package/src/Skeleton/Skeleton.tsx +11 -1
- package/src/Slider/Slider.doc.mjs +15 -0
- package/src/Slider/Slider.test.tsx +155 -2
- package/src/Slider/Slider.tsx +53 -5
- 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 +6 -0
- package/src/TabList/TabList.test.tsx +251 -0
- package/src/TabList/TabList.tsx +103 -12
- package/src/TabList/TabListContext.ts +7 -3
- package/src/TabList/TabMenu.tsx +6 -3
- package/src/Table/BaseTable.tsx +21 -17
- package/src/Table/Table.doc.mjs +2 -0
- package/src/Table/Table.test.tsx +10 -0
- package/src/Table/Table.tsx +8 -0
- package/src/Table/TableCell.tsx +25 -23
- package/src/Table/TableHeaderCell.tsx +28 -29
- package/src/Table/index.ts +3 -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/tableContextMenu.test.tsx +157 -0
- package/src/Table/tableContextMenu.tsx +142 -0
- package/src/Table/types.ts +74 -0
- package/src/Table/useTableColumnResize.doc.mjs +3 -3
- package/src/Table/useTableStickyColumns.doc.mjs +2 -2
- package/src/Text/Text.doc.mjs +18 -18
- 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/Thumbnail/Thumbnail.doc.mjs +4 -4
- package/src/TimeInput/TimeInput.doc.mjs +340 -60
- package/src/TimeInput/TimeInput.test.tsx +255 -7
- package/src/TimeInput/TimeInput.tsx +176 -70
- package/src/Timestamp/Timestamp.doc.mjs +19 -19
- package/src/Toast/Toast.tsx +14 -0
- package/src/Toast/ToastViewport.test.tsx +214 -0
- package/src/Toast/ToastViewport.tsx +167 -21
- package/src/Tokenizer/Tokenizer.doc.mjs +29 -14
- package/src/Tokenizer/Tokenizer.test.tsx +105 -1
- package/src/Tokenizer/Tokenizer.tsx +37 -1
- package/src/Toolbar/Toolbar.test.tsx +109 -6
- package/src/Toolbar/Toolbar.tsx +59 -5
- package/src/Tooltip/Tooltip.test.tsx +68 -0
- package/src/Tooltip/useTooltip.tsx +55 -8
- package/src/TopNav/TopNav.test.tsx +50 -0
- package/src/TopNav/TopNavHeading.tsx +17 -1
- 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 +93 -9
- package/src/Typeahead/Typeahead.doc.mjs +141 -30
- package/src/Typeahead/Typeahead.test.tsx +331 -1
- package/src/Typeahead/Typeahead.tsx +105 -33
- 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/docs-script.test.mjs +50 -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/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 +10 -5
- 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
|
@@ -86,6 +86,12 @@ export const docs = {
|
|
|
86
86
|
description: 'Disables the selector.',
|
|
87
87
|
default: 'false',
|
|
88
88
|
},
|
|
89
|
+
{
|
|
90
|
+
name: 'disabledMessage',
|
|
91
|
+
type: 'string',
|
|
92
|
+
description:
|
|
93
|
+
'Explains why the selector is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the trigger focusable via aria-disabled (activation stays blocked). Use this instead of wrapping a disabled Selector in Tooltip — disabled controls swallow the hover events an external Tooltip needs.',
|
|
94
|
+
},
|
|
89
95
|
{
|
|
90
96
|
name: 'isLabelHidden',
|
|
91
97
|
type: 'boolean',
|
|
@@ -151,6 +157,11 @@ export const docs = {
|
|
|
151
157
|
description:
|
|
152
158
|
'Set a meaningful placeholder that hints at the expected selection (e.g. "Choose a country" not "Select...").',
|
|
153
159
|
},
|
|
160
|
+
{
|
|
161
|
+
guidance: true,
|
|
162
|
+
description:
|
|
163
|
+
'Use inside InputGroup only when the selector needs a short prefix or suffix addon as part of one decorated input surface.',
|
|
164
|
+
},
|
|
154
165
|
{
|
|
155
166
|
guidance: false,
|
|
156
167
|
description:
|
|
@@ -176,6 +187,11 @@ export const docs = {
|
|
|
176
187
|
description:
|
|
177
188
|
'Put more than ~20 options without sections; consider Typeahead for large lists.',
|
|
178
189
|
},
|
|
190
|
+
{
|
|
191
|
+
guidance: false,
|
|
192
|
+
description:
|
|
193
|
+
'Wrap a disabled Selector in Tooltip to explain why it is disabled; disabled triggers swallow the hover events the wrapper needs. Use the disabledMessage prop instead.',
|
|
194
|
+
},
|
|
179
195
|
],
|
|
180
196
|
anatomy: [
|
|
181
197
|
{
|
|
@@ -263,6 +279,11 @@ export const docsZh = {
|
|
|
263
279
|
description:
|
|
264
280
|
'Put more than ~20 options without sections; consider Typeahead for large lists.',
|
|
265
281
|
},
|
|
282
|
+
{
|
|
283
|
+
guidance: false,
|
|
284
|
+
description:
|
|
285
|
+
'Wrap a disabled Selector in Tooltip to explain why it is disabled; disabled triggers swallow the hover events the wrapper needs. Use the disabledMessage prop instead.',
|
|
286
|
+
},
|
|
266
287
|
],
|
|
267
288
|
anatomy: [
|
|
268
289
|
{
|
|
@@ -350,6 +371,11 @@ export const docsDense = {
|
|
|
350
371
|
description:
|
|
351
372
|
'Put more than ~20 options without sections; consider Typeahead for large lists.',
|
|
352
373
|
},
|
|
374
|
+
{
|
|
375
|
+
guidance: false,
|
|
376
|
+
description:
|
|
377
|
+
'Wrap a disabled Selector in Tooltip to explain why it is disabled; disabled triggers swallow the hover events the wrapper needs. Use the disabledMessage prop instead.',
|
|
378
|
+
},
|
|
353
379
|
],
|
|
354
380
|
anatomy: [
|
|
355
381
|
{
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
13
|
-
import {render, screen, waitFor} from '@testing-library/react';
|
|
13
|
+
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import {Selector} from './Selector';
|
|
16
16
|
import {SelectorOption} from './SelectorOption';
|
|
17
|
+
import {InputGroup, InputGroupText} from '../InputGroup';
|
|
17
18
|
|
|
18
19
|
// Mock showPopover and hidePopover methods since they're not implemented in jsdom
|
|
19
20
|
beforeEach(() => {
|
|
@@ -83,7 +84,12 @@ function mockSelectorRects() {
|
|
|
83
84
|
'innerHeight',
|
|
84
85
|
);
|
|
85
86
|
HTMLElement.prototype.getBoundingClientRect = function () {
|
|
86
|
-
|
|
87
|
+
// The trigger is role="combobox" by default, or a plain button with
|
|
88
|
+
// aria-haspopup="listbox" in hasSearch mode — match either.
|
|
89
|
+
if (
|
|
90
|
+
this.getAttribute('role') === 'combobox' ||
|
|
91
|
+
this.getAttribute('aria-haspopup') === 'listbox'
|
|
92
|
+
) {
|
|
87
93
|
return rect({top: 160, bottom: 190, height: 30});
|
|
88
94
|
}
|
|
89
95
|
if (this.getAttribute('role') === 'listbox') {
|
|
@@ -108,9 +114,7 @@ function mockSelectorRects() {
|
|
|
108
114
|
|
|
109
115
|
describe('Selector', () => {
|
|
110
116
|
it('renders with placeholder when no value', () => {
|
|
111
|
-
render(
|
|
112
|
-
<Selector label="Fruit" options={OPTIONS} placeholder="Pick one" />,
|
|
113
|
-
);
|
|
117
|
+
render(<Selector label="Fruit" options={OPTIONS} placeholder="Pick one" />);
|
|
114
118
|
expect(screen.getByRole('combobox')).toHaveTextContent('Pick one');
|
|
115
119
|
});
|
|
116
120
|
|
|
@@ -147,6 +151,27 @@ describe('Selector', () => {
|
|
|
147
151
|
expect(screen.getByTestId('option-badge')).toHaveTextContent('Owner');
|
|
148
152
|
});
|
|
149
153
|
|
|
154
|
+
it('exposes the popup as a listbox, not a modal dialog', () => {
|
|
155
|
+
render(
|
|
156
|
+
<Selector
|
|
157
|
+
label="Fruit"
|
|
158
|
+
options={OPTIONS}
|
|
159
|
+
value="Banana"
|
|
160
|
+
onChange={() => {}}
|
|
161
|
+
/>,
|
|
162
|
+
);
|
|
163
|
+
// The combobox trigger keeps DOM focus; the popup must expose its own
|
|
164
|
+
// role="listbox" and must not be wrapped in a role="dialog" aria-modal
|
|
165
|
+
// element, which would tell AT the focused trigger is inert.
|
|
166
|
+
expect(screen.getByRole('listbox', {hidden: true})).toBeInTheDocument();
|
|
167
|
+
expect(
|
|
168
|
+
screen.queryByRole('dialog', {hidden: true}),
|
|
169
|
+
).not.toBeInTheDocument();
|
|
170
|
+
expect(
|
|
171
|
+
document.querySelector('[aria-modal="true"]'),
|
|
172
|
+
).not.toBeInTheDocument();
|
|
173
|
+
});
|
|
174
|
+
|
|
150
175
|
it('supports explicit menu placement', () => {
|
|
151
176
|
render(
|
|
152
177
|
<Selector
|
|
@@ -310,6 +335,59 @@ describe('Selector', () => {
|
|
|
310
335
|
expect(onChange).toHaveBeenCalledWith(null);
|
|
311
336
|
});
|
|
312
337
|
|
|
338
|
+
it('clears the value via Delete on the focused trigger', async () => {
|
|
339
|
+
const user = userEvent.setup();
|
|
340
|
+
const onChange = vi.fn();
|
|
341
|
+
render(
|
|
342
|
+
<Selector
|
|
343
|
+
label="Fruit"
|
|
344
|
+
options={OPTIONS}
|
|
345
|
+
value="Banana"
|
|
346
|
+
onChange={onChange}
|
|
347
|
+
hasClear
|
|
348
|
+
/>,
|
|
349
|
+
);
|
|
350
|
+
const trigger = screen.getByRole('combobox');
|
|
351
|
+
trigger.focus();
|
|
352
|
+
await user.keyboard('{Delete}');
|
|
353
|
+
expect(onChange).toHaveBeenCalledWith(null);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('clears the value via Backspace on the focused trigger', async () => {
|
|
357
|
+
const user = userEvent.setup();
|
|
358
|
+
const onChange = vi.fn();
|
|
359
|
+
render(
|
|
360
|
+
<Selector
|
|
361
|
+
label="Fruit"
|
|
362
|
+
options={OPTIONS}
|
|
363
|
+
value="Banana"
|
|
364
|
+
onChange={onChange}
|
|
365
|
+
hasClear
|
|
366
|
+
/>,
|
|
367
|
+
);
|
|
368
|
+
const trigger = screen.getByRole('combobox');
|
|
369
|
+
trigger.focus();
|
|
370
|
+
await user.keyboard('{Backspace}');
|
|
371
|
+
expect(onChange).toHaveBeenCalledWith(null);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('does not clear via Delete when hasClear is not set', async () => {
|
|
375
|
+
const user = userEvent.setup();
|
|
376
|
+
const onChange = vi.fn();
|
|
377
|
+
render(
|
|
378
|
+
<Selector
|
|
379
|
+
label="Fruit"
|
|
380
|
+
options={OPTIONS}
|
|
381
|
+
value="Banana"
|
|
382
|
+
onChange={onChange}
|
|
383
|
+
/>,
|
|
384
|
+
);
|
|
385
|
+
const trigger = screen.getByRole('combobox');
|
|
386
|
+
trigger.focus();
|
|
387
|
+
await user.keyboard('{Delete}');
|
|
388
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
389
|
+
});
|
|
390
|
+
|
|
313
391
|
it('shows placeholder after clearing', () => {
|
|
314
392
|
render(
|
|
315
393
|
<Selector
|
|
@@ -355,8 +433,33 @@ describe('Selector', () => {
|
|
|
355
433
|
hasSearch
|
|
356
434
|
/>,
|
|
357
435
|
);
|
|
358
|
-
await user.click(screen.getByRole('
|
|
359
|
-
expect(screen.getByRole('
|
|
436
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
437
|
+
expect(screen.getByRole('combobox', h)).toBeInTheDocument();
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it('wires the search input as the combobox with activedescendant (comboboxes-4)', async () => {
|
|
441
|
+
const user = userEvent.setup();
|
|
442
|
+
render(
|
|
443
|
+
<Selector
|
|
444
|
+
label="Fruit"
|
|
445
|
+
options={OPTIONS}
|
|
446
|
+
value="Apple"
|
|
447
|
+
onChange={() => {}}
|
|
448
|
+
hasSearch
|
|
449
|
+
/>,
|
|
450
|
+
);
|
|
451
|
+
const triggerBtn = screen.getByRole('button', {name: 'Fruit'});
|
|
452
|
+
// In hasSearch mode the trigger is a plain button, not a combobox.
|
|
453
|
+
expect(triggerBtn).not.toHaveAttribute('role', 'combobox');
|
|
454
|
+
await user.click(triggerBtn);
|
|
455
|
+
const search = screen.getByRole('combobox', h);
|
|
456
|
+
expect(search).toHaveAttribute('aria-autocomplete', 'list');
|
|
457
|
+
expect(search).toHaveAttribute('aria-expanded', 'true');
|
|
458
|
+
expect(search).toHaveAttribute('aria-controls');
|
|
459
|
+
// ArrowDown moves the highlight; the search input reports it via
|
|
460
|
+
// aria-activedescendant (previously silent on the trigger).
|
|
461
|
+
await user.keyboard('{ArrowDown}');
|
|
462
|
+
expect(search).toHaveAttribute('aria-activedescendant');
|
|
360
463
|
});
|
|
361
464
|
|
|
362
465
|
it('does not render search input when hasSearch is false', async () => {
|
|
@@ -369,6 +472,8 @@ describe('Selector', () => {
|
|
|
369
472
|
onChange={() => {}}
|
|
370
473
|
/>,
|
|
371
474
|
);
|
|
475
|
+
// hasSearch is false, so the trigger itself is the combobox and there is
|
|
476
|
+
// no separate search input inside the popup.
|
|
372
477
|
await user.click(screen.getByRole('combobox'));
|
|
373
478
|
expect(screen.queryByRole('searchbox', h)).not.toBeInTheDocument();
|
|
374
479
|
});
|
|
@@ -384,8 +489,8 @@ describe('Selector', () => {
|
|
|
384
489
|
hasSearch
|
|
385
490
|
/>,
|
|
386
491
|
);
|
|
387
|
-
await user.click(screen.getByRole('
|
|
388
|
-
await user.type(screen.getByRole('
|
|
492
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
493
|
+
await user.type(screen.getByRole('combobox', h), 'ban');
|
|
389
494
|
const options = screen.getAllByRole('option', h);
|
|
390
495
|
expect(options).toHaveLength(1);
|
|
391
496
|
expect(options[0]).toHaveTextContent('Banana');
|
|
@@ -402,8 +507,8 @@ describe('Selector', () => {
|
|
|
402
507
|
hasSearch
|
|
403
508
|
/>,
|
|
404
509
|
);
|
|
405
|
-
await user.click(screen.getByRole('
|
|
406
|
-
await user.type(screen.getByRole('
|
|
510
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
511
|
+
await user.type(screen.getByRole('combobox', h), 'xyz');
|
|
407
512
|
expect(screen.queryAllByRole('option', h)).toHaveLength(0);
|
|
408
513
|
expect(screen.getByText('No results found')).toBeInTheDocument();
|
|
409
514
|
});
|
|
@@ -420,8 +525,8 @@ describe('Selector', () => {
|
|
|
420
525
|
hasSearch
|
|
421
526
|
/>,
|
|
422
527
|
);
|
|
423
|
-
await user.click(screen.getByRole('
|
|
424
|
-
await user.type(screen.getByRole('
|
|
528
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
529
|
+
await user.type(screen.getByRole('combobox', h), 'ban');
|
|
425
530
|
await user.click(screen.getByRole('option', {name: /Banana/, ...h}));
|
|
426
531
|
expect(onChange).toHaveBeenCalledWith('Banana');
|
|
427
532
|
});
|
|
@@ -441,7 +546,9 @@ describe('Selector', () => {
|
|
|
441
546
|
</>,
|
|
442
547
|
);
|
|
443
548
|
|
|
444
|
-
|
|
549
|
+
// In hasSearch mode the trigger is a plain button (the popup's search
|
|
550
|
+
// input is the combobox); it still owns aria-expanded.
|
|
551
|
+
const trigger = screen.getByRole('button', {name: 'Fruit'});
|
|
445
552
|
await user.click(trigger);
|
|
446
553
|
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
447
554
|
|
|
@@ -461,10 +568,275 @@ describe('Selector', () => {
|
|
|
461
568
|
searchPlaceholder="Find a fruit..."
|
|
462
569
|
/>,
|
|
463
570
|
);
|
|
464
|
-
await user.click(screen.getByRole('
|
|
571
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
465
572
|
expect(
|
|
466
573
|
screen.getByPlaceholderText('Find a fruit...'),
|
|
467
574
|
).toBeInTheDocument();
|
|
468
575
|
});
|
|
469
576
|
});
|
|
577
|
+
|
|
578
|
+
describe('keyboard accessibility', () => {
|
|
579
|
+
it('trigger is focusable via Tab when enabled', async () => {
|
|
580
|
+
const user = userEvent.setup();
|
|
581
|
+
render(<Selector label="Fruit" options={OPTIONS} />);
|
|
582
|
+
|
|
583
|
+
await user.tab();
|
|
584
|
+
expect(screen.getByRole('combobox')).toHaveFocus();
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it('trigger is not focusable when disabled', () => {
|
|
588
|
+
render(<Selector label="Fruit" options={OPTIONS} isDisabled />);
|
|
589
|
+
expect(screen.getByRole('combobox')).toHaveAttribute('tabIndex', '-1');
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
it('opens the listbox with ArrowDown from a focused trigger', async () => {
|
|
593
|
+
const user = userEvent.setup();
|
|
594
|
+
render(<Selector label="Fruit" options={OPTIONS} />);
|
|
595
|
+
|
|
596
|
+
const trigger = screen.getByRole('combobox');
|
|
597
|
+
await user.tab();
|
|
598
|
+
expect(trigger).toHaveFocus();
|
|
599
|
+
|
|
600
|
+
await user.keyboard('{ArrowDown}');
|
|
601
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it('opens and selects an option with Enter (no mouse)', async () => {
|
|
605
|
+
const user = userEvent.setup();
|
|
606
|
+
const onChange = vi.fn();
|
|
607
|
+
render(<Selector label="Fruit" options={OPTIONS} onChange={onChange} />);
|
|
608
|
+
|
|
609
|
+
await user.tab();
|
|
610
|
+
await user.keyboard('{Enter}'); // open
|
|
611
|
+
await user.keyboard('{ArrowDown}'); // move highlight
|
|
612
|
+
await user.keyboard('{Enter}'); // select
|
|
613
|
+
|
|
614
|
+
expect(onChange).toHaveBeenCalled();
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it('clear button is reachable by keyboard', () => {
|
|
618
|
+
render(
|
|
619
|
+
<Selector
|
|
620
|
+
label="Fruit"
|
|
621
|
+
options={OPTIONS}
|
|
622
|
+
value="Apple"
|
|
623
|
+
onChange={() => {}}
|
|
624
|
+
hasClear
|
|
625
|
+
/>,
|
|
626
|
+
);
|
|
627
|
+
const clear = screen.getByRole('button', {name: 'Clear Fruit'});
|
|
628
|
+
expect(clear).not.toHaveAttribute('tabIndex', '-1');
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
it('scrolls the highlighted option into view during arrow navigation', async () => {
|
|
632
|
+
const scrollIntoView = vi.fn();
|
|
633
|
+
Object.defineProperty(HTMLElement.prototype, 'scrollIntoView', {
|
|
634
|
+
configurable: true,
|
|
635
|
+
value: scrollIntoView,
|
|
636
|
+
});
|
|
637
|
+
try {
|
|
638
|
+
const user = userEvent.setup();
|
|
639
|
+
const longOptions = Array.from(
|
|
640
|
+
{length: 20},
|
|
641
|
+
(_, i) => `Option ${i + 1}`,
|
|
642
|
+
);
|
|
643
|
+
render(<Selector label="Fruit" options={longOptions} />);
|
|
644
|
+
|
|
645
|
+
await user.tab();
|
|
646
|
+
await user.keyboard('{Enter}'); // open
|
|
647
|
+
scrollIntoView.mockClear();
|
|
648
|
+
await user.keyboard('{ArrowDown}'); // move highlight
|
|
649
|
+
await user.keyboard('{ArrowDown}');
|
|
650
|
+
|
|
651
|
+
expect(scrollIntoView).toHaveBeenCalledWith({block: 'nearest'});
|
|
652
|
+
} finally {
|
|
653
|
+
delete (HTMLElement.prototype as unknown as {scrollIntoView?: unknown})
|
|
654
|
+
.scrollIntoView;
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
describe('InputGroup integration', () => {
|
|
660
|
+
it('uses the group Field chrome and composes group and selector labels', () => {
|
|
661
|
+
render(
|
|
662
|
+
<InputGroup
|
|
663
|
+
label="Destination"
|
|
664
|
+
description="Where the alert should route"
|
|
665
|
+
status={{type: 'error', message: 'Destination is required'}}>
|
|
666
|
+
<InputGroupText>#</InputGroupText>
|
|
667
|
+
<Selector
|
|
668
|
+
label="Channel"
|
|
669
|
+
isLabelHidden
|
|
670
|
+
options={OPTIONS}
|
|
671
|
+
placeholder="Choose a channel"
|
|
672
|
+
/>
|
|
673
|
+
</InputGroup>,
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
const group = screen.getByRole('group', {name: 'Destination'});
|
|
677
|
+
const groupLabelID = group.getAttribute('aria-labelledby');
|
|
678
|
+
const trigger = screen.getByRole('combobox', {
|
|
679
|
+
name: 'Destination Channel',
|
|
680
|
+
});
|
|
681
|
+
const labelledByIDs =
|
|
682
|
+
trigger.getAttribute('aria-labelledby')?.split(' ') ?? [];
|
|
683
|
+
|
|
684
|
+
expect(labelledByIDs).toHaveLength(2);
|
|
685
|
+
expect(labelledByIDs[0]).toBe(groupLabelID);
|
|
686
|
+
expect(document.getElementById(labelledByIDs[1])).toHaveTextContent(
|
|
687
|
+
'Channel',
|
|
688
|
+
);
|
|
689
|
+
expect(trigger).toHaveAttribute(
|
|
690
|
+
'aria-describedby',
|
|
691
|
+
group.getAttribute('aria-describedby'),
|
|
692
|
+
);
|
|
693
|
+
expect(screen.getByText('#')).toBeInTheDocument();
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it('keeps disabled reasons described when grouped', () => {
|
|
697
|
+
render(
|
|
698
|
+
<InputGroup label="Destination">
|
|
699
|
+
<InputGroupText>#</InputGroupText>
|
|
700
|
+
<Selector
|
|
701
|
+
label="Channel"
|
|
702
|
+
isLabelHidden
|
|
703
|
+
options={OPTIONS}
|
|
704
|
+
isDisabled
|
|
705
|
+
disabledMessage="Choose a project first"
|
|
706
|
+
/>
|
|
707
|
+
</InputGroup>,
|
|
708
|
+
);
|
|
709
|
+
|
|
710
|
+
const trigger = screen.getByRole('combobox', {
|
|
711
|
+
name: 'Destination Channel',
|
|
712
|
+
});
|
|
713
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
714
|
+
|
|
715
|
+
expect(trigger).not.toBeDisabled();
|
|
716
|
+
expect(trigger).toHaveAttribute('aria-disabled', 'true');
|
|
717
|
+
expect(trigger.getAttribute('aria-describedby')).toContain(tooltip.id);
|
|
718
|
+
});
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
describe('disabledMessage', () => {
|
|
722
|
+
it('shows the reason tooltip on hover when disabled with a reason', async () => {
|
|
723
|
+
render(
|
|
724
|
+
<Selector
|
|
725
|
+
label="Fruit"
|
|
726
|
+
options={OPTIONS}
|
|
727
|
+
isDisabled
|
|
728
|
+
disabledMessage="You need the Editor role"
|
|
729
|
+
data-testid="fruit-selector"
|
|
730
|
+
/>,
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
const container = screen.getByTestId('fruit-selector');
|
|
734
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
735
|
+
expect(tooltip).toHaveTextContent('You need the Editor role');
|
|
736
|
+
|
|
737
|
+
fireEvent.mouseEnter(container);
|
|
738
|
+
await waitFor(() => {
|
|
739
|
+
expect(tooltip).toHaveAttribute('popover-open');
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
fireEvent.mouseLeave(container);
|
|
743
|
+
await waitFor(() => {
|
|
744
|
+
expect(tooltip).not.toHaveAttribute('popover-open');
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
it('shows the reason tooltip on keyboard focus', async () => {
|
|
749
|
+
const user = userEvent.setup();
|
|
750
|
+
render(
|
|
751
|
+
<Selector
|
|
752
|
+
label="Fruit"
|
|
753
|
+
options={OPTIONS}
|
|
754
|
+
isDisabled
|
|
755
|
+
disabledMessage="You need the Editor role"
|
|
756
|
+
/>,
|
|
757
|
+
);
|
|
758
|
+
|
|
759
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
760
|
+
await user.tab();
|
|
761
|
+
expect(screen.getByRole('combobox')).toHaveFocus();
|
|
762
|
+
await waitFor(() => {
|
|
763
|
+
expect(tooltip).toHaveAttribute('popover-open');
|
|
764
|
+
});
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
it('does not render a tooltip when not disabled', () => {
|
|
768
|
+
render(
|
|
769
|
+
<Selector
|
|
770
|
+
label="Fruit"
|
|
771
|
+
options={OPTIONS}
|
|
772
|
+
disabledMessage="You need the Editor role"
|
|
773
|
+
/>,
|
|
774
|
+
);
|
|
775
|
+
expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
it('does not render a tooltip when disabled without a reason', () => {
|
|
779
|
+
render(<Selector label="Fruit" options={OPTIONS} isDisabled />);
|
|
780
|
+
expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
it('keeps the trigger focusable via aria-disabled when a reason is provided', () => {
|
|
784
|
+
render(
|
|
785
|
+
<Selector
|
|
786
|
+
label="Fruit"
|
|
787
|
+
options={OPTIONS}
|
|
788
|
+
isDisabled
|
|
789
|
+
disabledMessage="You need the Editor role"
|
|
790
|
+
/>,
|
|
791
|
+
);
|
|
792
|
+
const trigger = screen.getByRole('combobox');
|
|
793
|
+
expect(trigger).not.toBeDisabled();
|
|
794
|
+
expect(trigger).toHaveAttribute('aria-disabled', 'true');
|
|
795
|
+
expect(trigger).toHaveAttribute('tabIndex', '0');
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
it('links the reason tooltip from the trigger via aria-describedby', () => {
|
|
799
|
+
render(
|
|
800
|
+
<Selector
|
|
801
|
+
label="Fruit"
|
|
802
|
+
options={OPTIONS}
|
|
803
|
+
isDisabled
|
|
804
|
+
disabledMessage="You need the Editor role"
|
|
805
|
+
/>,
|
|
806
|
+
);
|
|
807
|
+
const trigger = screen.getByRole('combobox');
|
|
808
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
809
|
+
expect(trigger.getAttribute('aria-describedby')).toContain(tooltip.id);
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
it('blocks activation while focusable-disabled', async () => {
|
|
813
|
+
const user = userEvent.setup();
|
|
814
|
+
const onChange = vi.fn();
|
|
815
|
+
render(
|
|
816
|
+
<Selector
|
|
817
|
+
label="Fruit"
|
|
818
|
+
options={OPTIONS}
|
|
819
|
+
onChange={onChange}
|
|
820
|
+
isDisabled
|
|
821
|
+
disabledMessage="You need the Editor role"
|
|
822
|
+
/>,
|
|
823
|
+
);
|
|
824
|
+
|
|
825
|
+
const trigger = screen.getByRole('combobox');
|
|
826
|
+
await user.click(trigger);
|
|
827
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
828
|
+
|
|
829
|
+
await user.keyboard('{Enter}');
|
|
830
|
+
await user.keyboard('{ArrowDown}');
|
|
831
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
832
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
it('remains non-focusable when disabled without a reason', () => {
|
|
836
|
+
render(<Selector label="Fruit" options={OPTIONS} isDisabled />);
|
|
837
|
+
const trigger = screen.getByRole('combobox');
|
|
838
|
+
expect(trigger).toBeDisabled();
|
|
839
|
+
expect(trigger).toHaveAttribute('tabIndex', '-1');
|
|
840
|
+
});
|
|
841
|
+
});
|
|
470
842
|
});
|