@astryxdesign/core 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file MultiSelector.tsx
|
|
7
|
-
* @input Uses React, StyleX, usePopover, CheckboxInput, Field, Badge, Icon
|
|
7
|
+
* @input Uses React, StyleX, usePopover, useTooltip, CheckboxInput, Field, Badge, Icon, InputGroupContext
|
|
8
8
|
* @output Exports MultiSelector component
|
|
9
9
|
* @position Core implementation; consumed by index.ts
|
|
10
10
|
*
|
|
11
11
|
* SYNC: When modified, update:
|
|
12
12
|
* - /packages/core/src/MultiSelector/MultiSelector.doc.mjs
|
|
13
|
+
* - /packages/core/src/MultiSelector/MultiSelector.test.tsx
|
|
13
14
|
* - /packages/core/src/MultiSelector/index.ts
|
|
15
|
+
* - /apps/storybook/stories/InputGroup.stories.tsx
|
|
14
16
|
* - /packages/cli/templates/blocks/components/MultiSelector/ (showcase blocks)
|
|
15
17
|
*/
|
|
16
18
|
|
|
@@ -27,6 +29,7 @@ import React, {
|
|
|
27
29
|
} from 'react';
|
|
28
30
|
import * as stylex from '@stylexjs/stylex';
|
|
29
31
|
import {usePopover} from '../Popover/usePopover';
|
|
32
|
+
import {useTooltip} from '../Tooltip';
|
|
30
33
|
import {Icon, renderIconSlot, type IconType} from '../Icon';
|
|
31
34
|
import type {IconName} from '../Icon';
|
|
32
35
|
import {
|
|
@@ -64,11 +67,15 @@ import {
|
|
|
64
67
|
getSelectableOptions,
|
|
65
68
|
} from '../Selector/utils';
|
|
66
69
|
import {useMultiCombobox} from './hooks';
|
|
67
|
-
import {mergeProps} from '../utils';
|
|
70
|
+
import {getInputARIA, mergeProps} from '../utils';
|
|
71
|
+
import {useAnnounce} from '../hooks/useAnnounce';
|
|
68
72
|
import type {BaseProps} from '../BaseProps';
|
|
69
73
|
import type {SizeValue} from '../utils/types';
|
|
70
74
|
import {useSize} from '../SizeContext/SizeContext';
|
|
71
75
|
import {themeProps} from '../utils/themeProps';
|
|
76
|
+
import {groupStyles} from '../InputGroup/groupStyles';
|
|
77
|
+
import {useInputGroup} from '../InputGroup/InputGroupContext';
|
|
78
|
+
import {VisuallyHidden} from '../VisuallyHidden';
|
|
72
79
|
|
|
73
80
|
// Sentinel value for the select-all item in keyboard navigation
|
|
74
81
|
const SELECT_ALL_VALUE = '__xds_select_all__';
|
|
@@ -397,6 +404,30 @@ export interface MultiSelectorProps<
|
|
|
397
404
|
*/
|
|
398
405
|
isDisabled?: boolean;
|
|
399
406
|
|
|
407
|
+
/**
|
|
408
|
+
* Explains why the selector is disabled. When set together with
|
|
409
|
+
* `isDisabled`, the selector shows a tooltip with this text on hover and
|
|
410
|
+
* keyboard focus, and the trigger stays focusable (via `aria-disabled`)
|
|
411
|
+
* so the reason is discoverable by keyboard and assistive technology.
|
|
412
|
+
* Activation stays blocked.
|
|
413
|
+
*
|
|
414
|
+
* Use this instead of wrapping a disabled selector in `Tooltip` — disabled
|
|
415
|
+
* controls don't emit the pointer events an external tooltip needs.
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```
|
|
419
|
+
* <MultiSelector
|
|
420
|
+
* label="Columns"
|
|
421
|
+
* options={columns}
|
|
422
|
+
* value={selected}
|
|
423
|
+
* onChange={setSelected}
|
|
424
|
+
* isDisabled
|
|
425
|
+
* disabledMessage="Select a table first"
|
|
426
|
+
* />
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
disabledMessage?: string;
|
|
430
|
+
|
|
400
431
|
/**
|
|
401
432
|
* The options to display in the selector.
|
|
402
433
|
* Can be strings, objects, dividers, or sections.
|
|
@@ -545,6 +576,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
545
576
|
isOptional = false,
|
|
546
577
|
isRequired = false,
|
|
547
578
|
isDisabled = false,
|
|
579
|
+
disabledMessage,
|
|
548
580
|
options,
|
|
549
581
|
value,
|
|
550
582
|
onChange,
|
|
@@ -575,9 +607,11 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
575
607
|
const listboxId = useId();
|
|
576
608
|
const descriptionId = useId();
|
|
577
609
|
const statusMessageId = useId();
|
|
610
|
+
const inputLabelId = useId();
|
|
578
611
|
const searchId = useId();
|
|
579
612
|
const triggerRef = useRef<HTMLButtonElement>(null);
|
|
580
613
|
const searchRef = useRef<HTMLInputElement>(null);
|
|
614
|
+
const inputGroup = useInputGroup();
|
|
581
615
|
|
|
582
616
|
const [searchQuery, setSearchQuery] = useState('');
|
|
583
617
|
|
|
@@ -592,14 +626,29 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
592
626
|
const [optimisticValue, setOptimisticValue] = useOptimistic(value);
|
|
593
627
|
const isBusy = isLoading || optimisticValue !== value;
|
|
594
628
|
|
|
595
|
-
//
|
|
596
|
-
|
|
629
|
+
// Disabled-reason tooltip. Disabled controls swallow pointer events, so the
|
|
630
|
+
// tooltip listeners attach to the trigger container (which already exists)
|
|
631
|
+
// and the trigger button stays perceivable via aria-disabled instead of the
|
|
632
|
+
// disabled attribute. Activation is blocked by the isDisabled guards in
|
|
633
|
+
// useMultiCombobox (onTriggerClick / onKeyDown).
|
|
634
|
+
const showsDisabledMessage = isDisabled && !!disabledMessage;
|
|
635
|
+
const disabledMessageTooltip = useTooltip({
|
|
636
|
+
placement: 'above',
|
|
637
|
+
// The container div is not naturally focusable; focusin bubbles up from
|
|
638
|
+
// the trigger button, so always attach focus listeners.
|
|
639
|
+
focusTrigger: 'always',
|
|
640
|
+
isEnabled: showsDisabledMessage,
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
const {ariaLabelledBy, ariaDescribedBy} = getInputARIA(
|
|
644
|
+
inputLabelId,
|
|
597
645
|
[
|
|
598
646
|
description ? descriptionId : null,
|
|
599
647
|
status?.message ? statusMessageId : null,
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
648
|
+
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
649
|
+
],
|
|
650
|
+
inputGroup,
|
|
651
|
+
);
|
|
603
652
|
|
|
604
653
|
// Flatten options for keyboard navigation
|
|
605
654
|
const selectableItems = useMemo(
|
|
@@ -607,6 +656,25 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
607
656
|
[options],
|
|
608
657
|
);
|
|
609
658
|
|
|
659
|
+
// Announce selection-count changes politely (comboboxes-7 announce path).
|
|
660
|
+
// Toggling options / select-all previously produced no audible feedback.
|
|
661
|
+
const announce = useAnnounce();
|
|
662
|
+
const announceSelection = useCallback(
|
|
663
|
+
(nextValue: string[]) => {
|
|
664
|
+
const total = selectableItems.length;
|
|
665
|
+
const selectableSet = new Set(selectableItems.map(item => item.value));
|
|
666
|
+
const selectedCount = nextValue.filter(v => selectableSet.has(v)).length;
|
|
667
|
+
if (selectedCount === 0) {
|
|
668
|
+
announce('Selection cleared');
|
|
669
|
+
} else if (total > 0 && selectedCount === total) {
|
|
670
|
+
announce('All selected');
|
|
671
|
+
} else {
|
|
672
|
+
announce(`${selectedCount} of ${total} selected`);
|
|
673
|
+
}
|
|
674
|
+
},
|
|
675
|
+
[announce, selectableItems],
|
|
676
|
+
);
|
|
677
|
+
|
|
610
678
|
// Filter items by search query
|
|
611
679
|
const filteredItems = useMemo(() => {
|
|
612
680
|
if (!searchQuery) {
|
|
@@ -696,7 +764,9 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
696
764
|
onHide: handleLayerHide,
|
|
697
765
|
hasCloseButton: false,
|
|
698
766
|
hasAutoFocus: false,
|
|
699
|
-
|
|
767
|
+
// The popup's own role="listbox" is the exposed semantics; the trigger
|
|
768
|
+
// keeps DOM focus, so wrapping it in a modal dialog would misrepresent it.
|
|
769
|
+
role: 'none',
|
|
700
770
|
});
|
|
701
771
|
|
|
702
772
|
// Open dropdown on mount when isDefaultOpen is true
|
|
@@ -708,19 +778,34 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
708
778
|
}, []);
|
|
709
779
|
|
|
710
780
|
// Handle toggle
|
|
711
|
-
//
|
|
781
|
+
// Clear all selected values. Shared by the clear button and the keyboard
|
|
782
|
+
// Delete/Backspace path so clearing is reachable without a mouse.
|
|
783
|
+
const clearValues = useCallback(() => {
|
|
784
|
+
onChange([]);
|
|
785
|
+
announceSelection([]);
|
|
786
|
+
if (changeAction) {
|
|
787
|
+
startTransition(async () => {
|
|
788
|
+
setOptimisticValue([]);
|
|
789
|
+
await changeAction([]);
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
}, [
|
|
793
|
+
onChange,
|
|
794
|
+
changeAction,
|
|
795
|
+
startTransition,
|
|
796
|
+
setOptimisticValue,
|
|
797
|
+
announceSelection,
|
|
798
|
+
]);
|
|
799
|
+
|
|
800
|
+
// Whether there is at least one selected value (clearing is meaningful).
|
|
801
|
+
const hasValue = optimisticValue.length > 0;
|
|
802
|
+
|
|
712
803
|
const handleClear = useCallback(
|
|
713
804
|
(e: React.MouseEvent) => {
|
|
714
805
|
e.stopPropagation(); // Don't open dropdown
|
|
715
|
-
|
|
716
|
-
if (changeAction) {
|
|
717
|
-
startTransition(async () => {
|
|
718
|
-
setOptimisticValue([]);
|
|
719
|
-
await changeAction([]);
|
|
720
|
-
});
|
|
721
|
-
}
|
|
806
|
+
clearValues();
|
|
722
807
|
},
|
|
723
|
-
[
|
|
808
|
+
[clearValues],
|
|
724
809
|
);
|
|
725
810
|
|
|
726
811
|
const handleToggle = useCallback(
|
|
@@ -730,6 +815,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
730
815
|
: [...optimisticValue, itemValue];
|
|
731
816
|
|
|
732
817
|
onChange(newValue);
|
|
818
|
+
announceSelection(newValue);
|
|
733
819
|
if (changeAction) {
|
|
734
820
|
startTransition(async () => {
|
|
735
821
|
setOptimisticValue(newValue);
|
|
@@ -743,6 +829,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
743
829
|
changeAction,
|
|
744
830
|
startTransition,
|
|
745
831
|
setOptimisticValue,
|
|
832
|
+
announceSelection,
|
|
746
833
|
],
|
|
747
834
|
);
|
|
748
835
|
|
|
@@ -788,6 +875,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
788
875
|
}
|
|
789
876
|
|
|
790
877
|
onChange(newValue);
|
|
878
|
+
announceSelection(newValue);
|
|
791
879
|
if (changeAction) {
|
|
792
880
|
startTransition(async () => {
|
|
793
881
|
setOptimisticValue(newValue);
|
|
@@ -802,6 +890,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
802
890
|
changeAction,
|
|
803
891
|
startTransition,
|
|
804
892
|
setOptimisticValue,
|
|
893
|
+
announceSelection,
|
|
805
894
|
]);
|
|
806
895
|
|
|
807
896
|
// Route toggle: select-all sentinel → handleSelectAll, everything else → handleToggle
|
|
@@ -843,9 +932,24 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
843
932
|
}, [popover, hasSearch, optimisticValue]),
|
|
844
933
|
onClose: popover.hide,
|
|
845
934
|
onToggle: handleNavigableToggle,
|
|
935
|
+
onClear: hasClear ? clearValues : undefined,
|
|
936
|
+
hasValue,
|
|
846
937
|
listboxId,
|
|
847
938
|
});
|
|
848
939
|
|
|
940
|
+
// Keep the highlighted option visible during keyboard navigation. The
|
|
941
|
+
// listbox is a fixed-height scroll container, so without this the virtual
|
|
942
|
+
// cursor walks off-screen once navigation passes the visible window. Mirrors
|
|
943
|
+
// CommandPaletteItem's scrollIntoView({block: 'nearest'}) behavior.
|
|
944
|
+
useEffect(() => {
|
|
945
|
+
if (!popover.isOpen || highlightedIndex < 0) {
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
document
|
|
949
|
+
.getElementById(getItemId(highlightedIndex))
|
|
950
|
+
?.scrollIntoView?.({block: 'nearest'});
|
|
951
|
+
}, [popover.isOpen, highlightedIndex, getItemId]);
|
|
952
|
+
|
|
849
953
|
// Build trigger display content
|
|
850
954
|
const selectedLabels = useMemo(() => {
|
|
851
955
|
return optimisticValue.map(v => {
|
|
@@ -906,17 +1010,30 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
906
1010
|
<input
|
|
907
1011
|
ref={searchRef}
|
|
908
1012
|
id={searchId}
|
|
909
|
-
|
|
1013
|
+
// When hasSearch is set, focus moves into this input on open, so it —
|
|
1014
|
+
// not the trigger — must be the combobox reporting the highlighted
|
|
1015
|
+
// option via aria-activedescendant (comboboxes-4).
|
|
1016
|
+
role="combobox"
|
|
1017
|
+
aria-expanded={popover.isOpen}
|
|
910
1018
|
aria-controls={listboxId}
|
|
1019
|
+
aria-autocomplete="list"
|
|
1020
|
+
aria-activedescendant={
|
|
1021
|
+
popover.isOpen && highlightedIndex >= 0
|
|
1022
|
+
? getItemId(highlightedIndex)
|
|
1023
|
+
: undefined
|
|
1024
|
+
}
|
|
911
1025
|
aria-label="Search options"
|
|
912
1026
|
type="text"
|
|
913
1027
|
value={searchQuery}
|
|
914
1028
|
onChange={e => setSearchQuery(e.target.value)}
|
|
915
1029
|
onKeyDown={e => {
|
|
916
|
-
//
|
|
1030
|
+
// Arrow keys navigate options; Enter toggles; Escape/Tab close.
|
|
1031
|
+
// Space and Home/End are left to the input (type a space / move
|
|
1032
|
+
// the caret), not forwarded to option navigation.
|
|
917
1033
|
if (
|
|
918
1034
|
e.key === 'ArrowDown' ||
|
|
919
1035
|
e.key === 'ArrowUp' ||
|
|
1036
|
+
e.key === 'Enter' ||
|
|
920
1037
|
e.key === 'Escape' ||
|
|
921
1038
|
e.key === 'Tab'
|
|
922
1039
|
) {
|
|
@@ -935,6 +1052,9 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
935
1052
|
searchQuery,
|
|
936
1053
|
searchPlaceholder,
|
|
937
1054
|
onKeyDown,
|
|
1055
|
+
popover.isOpen,
|
|
1056
|
+
highlightedIndex,
|
|
1057
|
+
getItemId,
|
|
938
1058
|
]);
|
|
939
1059
|
|
|
940
1060
|
// Render an individual item (index-based)
|
|
@@ -1062,9 +1182,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1062
1182
|
|
|
1063
1183
|
if (isDivider(option)) {
|
|
1064
1184
|
flushPending();
|
|
1065
|
-
elements.push(
|
|
1066
|
-
<Divider key={`divider-${i}`} xstyle={styles.divider} />,
|
|
1067
|
-
);
|
|
1185
|
+
elements.push(<Divider key={`divider-${i}`} xstyle={styles.divider} />);
|
|
1068
1186
|
} else if (isSection(option)) {
|
|
1069
1187
|
flushPending();
|
|
1070
1188
|
const count = option.options.length;
|
|
@@ -1096,30 +1214,15 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1096
1214
|
return elements;
|
|
1097
1215
|
}, [options, renderItem, sortedItems, searchQuery, hasSelectAll]);
|
|
1098
1216
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
label={label}
|
|
1102
|
-
isLabelHidden={isLabelHidden}
|
|
1103
|
-
description={description}
|
|
1104
|
-
inputID={triggerId}
|
|
1105
|
-
descriptionID={description ? descriptionId : undefined}
|
|
1106
|
-
isOptional={isOptional}
|
|
1107
|
-
isRequired={isRequired}
|
|
1108
|
-
isDisabled={isDisabled}
|
|
1109
|
-
status={
|
|
1110
|
-
status
|
|
1111
|
-
? {
|
|
1112
|
-
type: status.type,
|
|
1113
|
-
message: status.message,
|
|
1114
|
-
messageID: status.message ? statusMessageId : undefined,
|
|
1115
|
-
}
|
|
1116
|
-
: undefined
|
|
1117
|
-
}
|
|
1118
|
-
labelTooltip={labelTooltip}
|
|
1119
|
-
width={width}>
|
|
1217
|
+
const multiSelectorContent = (
|
|
1218
|
+
<>
|
|
1120
1219
|
<div
|
|
1121
1220
|
ref={el => {
|
|
1122
1221
|
popover.triggerRef(el);
|
|
1222
|
+
// Anchor + hover/focus listeners for the disabled-message tooltip.
|
|
1223
|
+
// Handlers are gated internally by isEnabled, and anchor names
|
|
1224
|
+
// compose, so attaching unconditionally is safe.
|
|
1225
|
+
disabledMessageTooltip.ref(el);
|
|
1123
1226
|
}}
|
|
1124
1227
|
onClick={onTriggerClick}
|
|
1125
1228
|
data-testid={testId}
|
|
@@ -1133,6 +1236,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1133
1236
|
optimisticValue.length === 0 && styles.triggerPlaceholder,
|
|
1134
1237
|
status && inputStatusBorderStyles[status.type],
|
|
1135
1238
|
status && inputStatusHoverShadowStyles[status.type],
|
|
1239
|
+
inputGroup && groupStyles.inGroup,
|
|
1136
1240
|
xstyle,
|
|
1137
1241
|
),
|
|
1138
1242
|
className,
|
|
@@ -1140,26 +1244,37 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1140
1244
|
)}>
|
|
1141
1245
|
{startIcon &&
|
|
1142
1246
|
renderIconSlot(startIcon, {size: 'sm', color: 'secondary'})}
|
|
1247
|
+
{inputGroup && (
|
|
1248
|
+
<VisuallyHidden id={inputLabelId}>{label}</VisuallyHidden>
|
|
1249
|
+
)}
|
|
1143
1250
|
<button
|
|
1144
1251
|
ref={triggerRef}
|
|
1145
1252
|
id={triggerId}
|
|
1146
1253
|
type="button"
|
|
1147
|
-
|
|
1254
|
+
// In hasSearch mode the popup's search input is the combobox (it owns
|
|
1255
|
+
// focus + aria-activedescendant, comboboxes-4), so the trigger is a
|
|
1256
|
+
// plain button that opens the listbox — not a second combobox.
|
|
1257
|
+
role={hasSearch ? undefined : 'combobox'}
|
|
1148
1258
|
aria-haspopup="listbox"
|
|
1149
1259
|
aria-expanded={popover.isOpen}
|
|
1150
1260
|
aria-controls={listboxId}
|
|
1151
1261
|
aria-activedescendant={
|
|
1152
|
-
popover.isOpen && highlightedIndex >= 0
|
|
1262
|
+
!hasSearch && popover.isOpen && highlightedIndex >= 0
|
|
1153
1263
|
? getItemId(highlightedIndex)
|
|
1154
1264
|
: undefined
|
|
1155
1265
|
}
|
|
1156
1266
|
aria-describedby={ariaDescribedBy}
|
|
1267
|
+
aria-labelledby={ariaLabelledBy}
|
|
1157
1268
|
aria-required={isRequired ? 'true' : undefined}
|
|
1158
1269
|
aria-invalid={status?.type === 'error' ? 'true' : undefined}
|
|
1159
1270
|
aria-busy={isBusy || undefined}
|
|
1160
|
-
|
|
1271
|
+
// With a disabledMessage the trigger keeps focusability via
|
|
1272
|
+
// aria-disabled so the reason is focus-discoverable; activation is
|
|
1273
|
+
// still blocked by the isDisabled guards in useMultiCombobox.
|
|
1274
|
+
disabled={isDisabled && !showsDisabledMessage}
|
|
1275
|
+
aria-disabled={showsDisabledMessage ? 'true' : undefined}
|
|
1161
1276
|
onKeyDown={onKeyDown}
|
|
1162
|
-
tabIndex={-1}
|
|
1277
|
+
tabIndex={isDisabled && !showsDisabledMessage ? -1 : 0}
|
|
1163
1278
|
{...stylex.props(styles.trigger)}>
|
|
1164
1279
|
<span {...stylex.props(styles.triggerContent)}>
|
|
1165
1280
|
{renderTriggerContent()}
|
|
@@ -1169,7 +1284,6 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1169
1284
|
{hasClear && value.length > 0 && !isDisabled && (
|
|
1170
1285
|
<button
|
|
1171
1286
|
type="button"
|
|
1172
|
-
tabIndex={-1}
|
|
1173
1287
|
onClick={handleClear}
|
|
1174
1288
|
aria-label={`Clear all ${label}`}
|
|
1175
1289
|
{...stylex.props(styles.clearButton)}>
|
|
@@ -1211,6 +1325,38 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1211
1325
|
xstyle: styles.popover,
|
|
1212
1326
|
},
|
|
1213
1327
|
)}
|
|
1328
|
+
|
|
1329
|
+
{showsDisabledMessage &&
|
|
1330
|
+
disabledMessageTooltip.renderTooltip(disabledMessage)}
|
|
1331
|
+
</>
|
|
1332
|
+
);
|
|
1333
|
+
|
|
1334
|
+
if (inputGroup) {
|
|
1335
|
+
return multiSelectorContent;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
return (
|
|
1339
|
+
<Field
|
|
1340
|
+
label={label}
|
|
1341
|
+
isLabelHidden={isLabelHidden}
|
|
1342
|
+
description={description}
|
|
1343
|
+
inputID={triggerId}
|
|
1344
|
+
descriptionID={description ? descriptionId : undefined}
|
|
1345
|
+
isOptional={isOptional}
|
|
1346
|
+
isRequired={isRequired}
|
|
1347
|
+
isDisabled={isDisabled}
|
|
1348
|
+
status={
|
|
1349
|
+
status
|
|
1350
|
+
? {
|
|
1351
|
+
type: status.type,
|
|
1352
|
+
message: status.message,
|
|
1353
|
+
messageID: status.message ? statusMessageId : undefined,
|
|
1354
|
+
}
|
|
1355
|
+
: undefined
|
|
1356
|
+
}
|
|
1357
|
+
labelTooltip={labelTooltip}
|
|
1358
|
+
width={width}>
|
|
1359
|
+
{multiSelectorContent}
|
|
1214
1360
|
</Field>
|
|
1215
1361
|
);
|
|
1216
1362
|
}
|
|
@@ -23,6 +23,17 @@ interface UseMultiComboboxOptions {
|
|
|
23
23
|
onOpen: () => void;
|
|
24
24
|
onClose: () => void;
|
|
25
25
|
onToggle: (itemValue: string) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Clear all selected values. When provided, pressing Delete or Backspace on
|
|
28
|
+
* the closed trigger clears the selection — a keyboard equivalent of the
|
|
29
|
+
* clear button (comboboxes-2). No-op when the popup is open or search is on.
|
|
30
|
+
*/
|
|
31
|
+
onClear?: () => void;
|
|
32
|
+
/**
|
|
33
|
+
* Whether at least one value is selected (i.e. there is something to clear).
|
|
34
|
+
* The Delete/Backspace clear path is skipped when false.
|
|
35
|
+
*/
|
|
36
|
+
hasValue?: boolean;
|
|
26
37
|
listboxId: string;
|
|
27
38
|
}
|
|
28
39
|
|
|
@@ -49,6 +60,8 @@ export function useMultiCombobox({
|
|
|
49
60
|
onOpen,
|
|
50
61
|
onClose,
|
|
51
62
|
onToggle,
|
|
63
|
+
onClear,
|
|
64
|
+
hasValue = false,
|
|
52
65
|
listboxId,
|
|
53
66
|
}: UseMultiComboboxOptions): UseMultiComboboxResult {
|
|
54
67
|
const [highlightedIndex, setHighlightedIndex] = useState<number>(-1);
|
|
@@ -179,6 +192,18 @@ export function useMultiCombobox({
|
|
|
179
192
|
}
|
|
180
193
|
break;
|
|
181
194
|
|
|
195
|
+
case 'Delete':
|
|
196
|
+
case 'Backspace':
|
|
197
|
+
// Keyboard equivalent of the clear button (comboboxes-2): clear all
|
|
198
|
+
// selected values from the closed trigger so clearing is not
|
|
199
|
+
// mouse-only. Skipped in search mode (keys edit the query) and while
|
|
200
|
+
// the popup is open (arrow navigation owns interaction).
|
|
201
|
+
if (!hasSearch && !isOpen && onClear != null && hasValue) {
|
|
202
|
+
e.preventDefault();
|
|
203
|
+
onClear();
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
|
|
182
207
|
default:
|
|
183
208
|
// Typeahead only when search is not present
|
|
184
209
|
if (!hasSearch && e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
|
|
@@ -218,6 +243,8 @@ export function useMultiCombobox({
|
|
|
218
243
|
getEnabledIndices,
|
|
219
244
|
typeahead,
|
|
220
245
|
hasSearch,
|
|
246
|
+
onClear,
|
|
247
|
+
hasValue,
|
|
221
248
|
],
|
|
222
249
|
);
|
|
223
250
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
3
|
import {describe, it, expect, vi} from 'vitest';
|
|
4
|
-
import {render, screen} from '@testing-library/react';
|
|
4
|
+
import {render, screen, fireEvent} from '@testing-library/react';
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
6
|
import {NavHeadingMenu} from './NavHeadingMenu';
|
|
7
7
|
import {NavHeadingMenuItem} from './NavHeadingMenuItem';
|
|
@@ -204,6 +204,82 @@ describe('keyboard navigation', () => {
|
|
|
204
204
|
await user.keyboard('{End}');
|
|
205
205
|
expect(document.activeElement).toBe(items[2]);
|
|
206
206
|
});
|
|
207
|
+
|
|
208
|
+
it('activates a focused onClick-only item with Enter', async () => {
|
|
209
|
+
const user = userEvent.setup();
|
|
210
|
+
const onClick = vi.fn();
|
|
211
|
+
render(
|
|
212
|
+
<NavHeadingMenu>
|
|
213
|
+
<NavHeadingMenuItem label="Action" onClick={onClick} />
|
|
214
|
+
</NavHeadingMenu>,
|
|
215
|
+
);
|
|
216
|
+
const item = screen.getByRole('menuitem');
|
|
217
|
+
item.focus();
|
|
218
|
+
|
|
219
|
+
await user.keyboard('{Enter}');
|
|
220
|
+
expect(onClick).toHaveBeenCalledOnce();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('activates a focused onClick-only item with Space', async () => {
|
|
224
|
+
const user = userEvent.setup();
|
|
225
|
+
const onClick = vi.fn();
|
|
226
|
+
render(
|
|
227
|
+
<NavHeadingMenu>
|
|
228
|
+
<NavHeadingMenuItem label="Action" onClick={onClick} />
|
|
229
|
+
</NavHeadingMenu>,
|
|
230
|
+
);
|
|
231
|
+
const item = screen.getByRole('menuitem');
|
|
232
|
+
item.focus();
|
|
233
|
+
|
|
234
|
+
await user.keyboard('{ }');
|
|
235
|
+
expect(onClick).toHaveBeenCalledOnce();
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('does not activate a disabled item with Enter', async () => {
|
|
239
|
+
const user = userEvent.setup();
|
|
240
|
+
const onClick = vi.fn();
|
|
241
|
+
render(
|
|
242
|
+
<NavHeadingMenu>
|
|
243
|
+
<NavHeadingMenuItem label="Action" onClick={onClick} isDisabled />
|
|
244
|
+
</NavHeadingMenu>,
|
|
245
|
+
);
|
|
246
|
+
const item = screen.getByRole('menuitem');
|
|
247
|
+
item.focus();
|
|
248
|
+
|
|
249
|
+
await user.keyboard('{Enter}');
|
|
250
|
+
expect(onClick).not.toHaveBeenCalled();
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('typeahead focuses the item matching the typed character (menus-11)', () => {
|
|
254
|
+
render(
|
|
255
|
+
<NavHeadingMenu>
|
|
256
|
+
<NavHeadingMenuItem label="Cut" />
|
|
257
|
+
<NavHeadingMenuItem label="Paste" />
|
|
258
|
+
</NavHeadingMenu>,
|
|
259
|
+
);
|
|
260
|
+
const menu = screen.getByRole('menu');
|
|
261
|
+
fireEvent.keyDown(menu, {key: 'p'});
|
|
262
|
+
expect(screen.getByRole('menuitem', {name: 'Paste'})).toHaveFocus();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('typeahead skips a disabled menuitem (menus-11)', () => {
|
|
266
|
+
render(
|
|
267
|
+
<NavHeadingMenu>
|
|
268
|
+
<NavHeadingMenuItem label="Cut" />
|
|
269
|
+
<NavHeadingMenuItem label="Paste (disabled)" isDisabled />
|
|
270
|
+
<NavHeadingMenuItem label="Paste special" />
|
|
271
|
+
</NavHeadingMenu>,
|
|
272
|
+
);
|
|
273
|
+
const menu = screen.getByRole('menu');
|
|
274
|
+
// Typing "p" must land on the enabled "Paste special", never the disabled
|
|
275
|
+
// "Paste (disabled)" — the disabled item is excluded from the typeahead
|
|
276
|
+
// selector entirely.
|
|
277
|
+
fireEvent.keyDown(menu, {key: 'p'});
|
|
278
|
+
expect(screen.getByRole('menuitem', {name: 'Paste special'})).toHaveFocus();
|
|
279
|
+
expect(
|
|
280
|
+
screen.getByRole('menuitem', {name: 'Paste (disabled)'}),
|
|
281
|
+
).not.toHaveFocus();
|
|
282
|
+
});
|
|
207
283
|
});
|
|
208
284
|
|
|
209
285
|
describe('context forwarding', () => {
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
* - /packages/core/src/NavMenu/index.ts
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import React, {useMemo, type ReactNode} from 'react';
|
|
15
|
+
import React, {useCallback, useMemo, type ReactNode} from 'react';
|
|
16
16
|
import * as stylex from '@stylexjs/stylex';
|
|
17
17
|
import {spacingVars} from '../theme/tokens.stylex';
|
|
18
18
|
import {mergeProps, mergeRefs} from '../utils';
|
|
19
19
|
import type {BaseProps} from '../BaseProps';
|
|
20
20
|
import {useListFocus} from '../hooks/useListFocus';
|
|
21
|
+
import {useTypeahead} from '../hooks/useTypeahead';
|
|
21
22
|
import {themeProps} from '../utils/themeProps';
|
|
22
23
|
import {
|
|
23
24
|
NavHeadingMenuContext,
|
|
@@ -98,10 +99,56 @@ export function NavHeadingMenu({
|
|
|
98
99
|
const closeCtx = useNavHeadingCloseContext();
|
|
99
100
|
const closeMenu = closeCtx?.closeMenu;
|
|
100
101
|
|
|
101
|
-
const {listRef, handleKeyDown} = useListFocus({
|
|
102
|
+
const {listRef, handleKeyDown, focusItem} = useListFocus({
|
|
103
|
+
itemSelector: '[role="menuitem"]:not([aria-disabled="true"])',
|
|
102
104
|
onEscape: closeMenu,
|
|
103
105
|
});
|
|
104
106
|
|
|
107
|
+
// First-character typeahead over the (enabled) menu items (menus-11).
|
|
108
|
+
const getMenuItems = useCallback(
|
|
109
|
+
(): HTMLElement[] =>
|
|
110
|
+
listRef.current
|
|
111
|
+
? Array.from(
|
|
112
|
+
listRef.current.querySelectorAll<HTMLElement>(
|
|
113
|
+
'[role="menuitem"]:not([aria-disabled="true"])',
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
: [],
|
|
117
|
+
[listRef],
|
|
118
|
+
);
|
|
119
|
+
const typeahead = useTypeahead({
|
|
120
|
+
getItemLabels: () => getMenuItems().map(el => el.textContent),
|
|
121
|
+
onMatch: focusItem,
|
|
122
|
+
getCurrentIndex: () =>
|
|
123
|
+
getMenuItems().findIndex(
|
|
124
|
+
el =>
|
|
125
|
+
el === document.activeElement || el.contains(document.activeElement),
|
|
126
|
+
),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Extend useListFocus with Enter/Space activation. Items rendered without an
|
|
130
|
+
// `href` are `<div role="menuitem">` elements, which have no native keyboard
|
|
131
|
+
// activation — without this, Enter/Space on a focused onClick-only item does
|
|
132
|
+
// nothing. Anchor items (with `href`) already activate on Enter natively.
|
|
133
|
+
const listKeyDown = useCallback(
|
|
134
|
+
(e: React.KeyboardEvent) => {
|
|
135
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
136
|
+
const focused = document.activeElement as HTMLElement | null;
|
|
137
|
+
if (focused?.getAttribute('role') === 'menuitem') {
|
|
138
|
+
e.preventDefault();
|
|
139
|
+
focused.click();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (typeahead.onKeyDown(e)) {
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
handleKeyDown(e);
|
|
148
|
+
},
|
|
149
|
+
[handleKeyDown, typeahead],
|
|
150
|
+
);
|
|
151
|
+
|
|
105
152
|
const ctx = useMemo(
|
|
106
153
|
() => ({
|
|
107
154
|
closeMenu: closeMenu ?? (() => {}),
|
|
@@ -117,7 +164,7 @@ export function NavHeadingMenu({
|
|
|
117
164
|
<div
|
|
118
165
|
ref={mergeRefs(ref, listRef)}
|
|
119
166
|
role="menu"
|
|
120
|
-
onKeyDown={
|
|
167
|
+
onKeyDown={listKeyDown}
|
|
121
168
|
data-testid={testId}
|
|
122
169
|
{...mergeProps(
|
|
123
170
|
themeProps('nav-heading-menu', {size}),
|