@astryxdesign/core 0.1.1 → 0.1.2-canary.04e71b2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +105 -0
- package/README.md +131 -13
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +11 -5
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
- package/dist/Banner/Banner.d.ts +7 -0
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +9 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +24 -5
- package/dist/Button/Button.d.ts +12 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +53 -17
- package/dist/Calendar/Calendar.d.ts +5 -4
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +82 -43
- package/dist/Calendar/hooks/index.d.ts +0 -2
- package/dist/Calendar/hooks/index.d.ts.map +1 -1
- package/dist/Calendar/hooks/index.js +1 -2
- package/dist/Calendar/index.d.ts +3 -3
- package/dist/Calendar/index.d.ts.map +1 -1
- package/dist/Calendar/index.js +1 -1
- package/dist/Calendar/styles.d.ts +3 -9
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +3 -11
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +17 -3
- package/dist/Center/Center.d.ts +11 -1
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +9 -3
- package/dist/Chat/ChatMessageList.d.ts +14 -1
- package/dist/Chat/ChatMessageList.d.ts.map +1 -1
- package/dist/Chat/ChatMessageList.js +2 -0
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +4 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts +23 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +51 -9
- package/dist/CheckboxList/CheckboxList.d.ts +13 -1
- package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxList.js +39 -9
- package/dist/CheckboxList/CheckboxListContext.d.ts +7 -0
- package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +3 -3
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +49 -37
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +5 -5
- package/dist/ContextMenu/ContextMenu.d.ts +4 -5
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +93 -11
- package/dist/DateInput/DateInput.d.ts +23 -1
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +59 -8
- package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +42 -9
- package/dist/DateTimeInput/DateTimeInput.d.ts +35 -2
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +78 -15
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +12 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts +1 -8
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +42 -14
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +7 -1
- package/dist/Field/Field.d.ts +19 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +4 -0
- package/dist/Field/FieldLabel.d.ts +21 -2
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +41 -26
- package/dist/FileInput/FileInput.d.ts +22 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +56 -10
- package/dist/Grid/Grid.d.ts +11 -1
- package/dist/Grid/Grid.d.ts.map +1 -1
- package/dist/Grid/Grid.js +8 -0
- package/dist/HoverCard/HoverCard.d.ts +2 -2
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +18 -6
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +7 -3
- package/dist/InputGroup/InputGroup.d.ts +2 -2
- package/dist/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/InputGroup/InputGroup.js +14 -5
- package/dist/InputGroup/InputGroupContext.d.ts +4 -0
- package/dist/InputGroup/InputGroupContext.d.ts.map +1 -1
- package/dist/InputGroup/InputGroupContext.js +2 -2
- package/dist/InputGroup/index.d.ts +1 -0
- package/dist/InputGroup/index.d.ts.map +1 -1
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +34 -2
- package/dist/Layer/anchorName.d.ts +20 -0
- package/dist/Layer/anchorName.d.ts.map +1 -0
- package/dist/Layer/anchorName.js +36 -0
- package/dist/Layer/layerAnimations.stylex.d.ts +4 -0
- package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
- package/dist/Layer/layerAnimations.stylex.js +8 -4
- package/dist/Layer/useLayer.d.ts +29 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +55 -11
- package/dist/Layout/Layout.d.ts +4 -11
- package/dist/Layout/Layout.d.ts.map +1 -1
- package/dist/Layout/Layout.js +10 -11
- package/dist/Layout/LayoutFooter.d.ts +2 -2
- package/dist/Layout/LayoutFooter.d.ts.map +1 -1
- package/dist/Layout/LayoutHeader.d.ts +2 -2
- package/dist/Layout/LayoutHeader.d.ts.map +1 -1
- package/dist/Layout/LayoutPanel.d.ts +2 -2
- package/dist/Layout/LayoutPanel.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.d.ts +51 -0
- package/dist/Layout/padding.stylex.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.js +63 -0
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +4 -2
- package/dist/Link/Link.d.ts +17 -2
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +20 -9
- package/dist/Link/LinkProvider.d.ts +1 -0
- package/dist/Link/LinkProvider.d.ts.map +1 -1
- package/dist/Link/LinkProvider.js +1 -0
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +18 -3
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +13 -0
- package/dist/MoreMenu/MoreMenu.d.ts +1 -7
- package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
- package/dist/MoreMenu/MoreMenu.js +0 -2
- package/dist/MultiSelector/MultiSelector.d.ts +25 -2
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +103 -22
- package/dist/MultiSelector/hooks.d.ts +12 -1
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +14 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +34 -3
- package/dist/NumberInput/NumberInput.d.ts +23 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +62 -12
- package/dist/Pagination/Pagination.d.ts +1 -1
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +46 -28
- package/dist/Popover/usePopover.d.ts +25 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +18 -6
- package/dist/PowerSearch/PowerSearch.d.ts +11 -1
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +6 -1
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +3 -5
- package/dist/RadioList/RadioList.d.ts +20 -2
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +105 -9
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +13 -2
- package/dist/SegmentedControl/SegmentedControl.d.ts +13 -2
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControl.js +78 -44
- package/dist/SegmentedControl/SegmentedControlContext.d.ts +7 -0
- package/dist/SegmentedControl/SegmentedControlContext.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +13 -2
- package/dist/Selector/Selector.d.ts +22 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +84 -23
- package/dist/Selector/hooks.d.ts +8 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +14 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +1 -1
- package/dist/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton/Skeleton.js +8 -2
- package/dist/Slider/Slider.d.ts +21 -0
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +38 -11
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +1 -1
- package/dist/Stack/Stack.d.ts +38 -23
- package/dist/Stack/Stack.d.ts.map +1 -1
- package/dist/Stack/Stack.js +25 -1
- package/dist/Stack/StackItem.d.ts +12 -23
- package/dist/Stack/StackItem.d.ts.map +1 -1
- package/dist/Stack/StackItem.js +8 -1
- package/dist/Switch/Switch.d.ts +23 -2
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +41 -11
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +6 -0
- package/dist/TabList/TabList.d.ts +16 -4
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +86 -10
- package/dist/TabList/TabListContext.d.ts +5 -0
- package/dist/TabList/TabListContext.d.ts.map +1 -1
- package/dist/TabList/TabListContext.js +5 -0
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +6 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +38 -16
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +36 -7
- package/dist/Table/TableCell.d.ts +8 -1
- package/dist/Table/TableCell.d.ts.map +1 -1
- package/dist/Table/TableCell.js +10 -10
- package/dist/Table/TableHeaderCell.d.ts +8 -1
- package/dist/Table/TableHeaderCell.d.ts.map +1 -1
- package/dist/Table/TableHeaderCell.js +16 -16
- package/dist/Table/TableRow.d.ts +6 -1
- package/dist/Table/TableRow.d.ts.map +1 -1
- package/dist/Table/TableRow.js +15 -7
- package/dist/Table/index.d.ts +4 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +3 -2
- package/dist/Table/plugins/pagination/paginateData.d.ts +2 -1
- package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/paginateData.js +8 -3
- package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/useTablePagination.js +6 -1
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
- package/dist/Table/plugins/stickyColumns/index.d.ts +3 -0
- package/dist/Table/plugins/stickyColumns/index.d.ts.map +1 -0
- package/dist/Table/plugins/stickyColumns/index.js +3 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts +25 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +369 -0
- package/dist/Table/tableContextMenu.d.ts +33 -0
- package/dist/Table/tableContextMenu.d.ts.map +1 -0
- package/dist/Table/tableContextMenu.js +133 -0
- package/dist/Table/types.d.ts +161 -5
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +1 -1
- package/dist/Text/text.stylex.d.ts +2 -2
- package/dist/Text/text.stylex.js +2 -2
- package/dist/TextArea/TextArea.d.ts +22 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +41 -9
- package/dist/TextInput/TextInput.d.ts +23 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +55 -10
- package/dist/TimeInput/TimeInput.d.ts +23 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +53 -10
- package/dist/Timestamp/Timestamp.d.ts +1 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +28 -3
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +14 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +132 -3
- package/dist/ToggleButton/ToggleButton.d.ts +7 -9
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +34 -57
- package/dist/Tokenizer/Tokenizer.d.ts +12 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +27 -5
- package/dist/Toolbar/Toolbar.d.ts +3 -3
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +51 -7
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +57 -9
- package/dist/TreeList/TreeList.d.ts +1 -1
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +72 -2
- package/dist/TreeList/TreeListItem.d.ts +11 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +51 -12
- package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
- package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
- package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
- package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +67 -6
- package/dist/Typeahead/Typeahead.d.ts +24 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +29 -5
- package/dist/VisuallyHidden/VisuallyHidden.d.ts +61 -0
- package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
- package/dist/VisuallyHidden/VisuallyHidden.js +65 -0
- package/dist/VisuallyHidden/index.d.ts +11 -0
- package/dist/VisuallyHidden/index.d.ts.map +1 -0
- package/dist/VisuallyHidden/index.js +13 -0
- package/dist/astryx.css +40 -1
- package/dist/astryx.umd.js +147 -0
- package/dist/astryx.umd.js.map +7 -0
- package/dist/hooks/focusableSelector.d.ts +22 -0
- package/dist/hooks/focusableSelector.d.ts.map +1 -0
- package/dist/hooks/focusableSelector.js +24 -0
- package/dist/hooks/index.d.ts +12 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +7 -2
- package/dist/hooks/useAnnounce.d.ts +40 -0
- package/dist/hooks/useAnnounce.d.ts.map +1 -0
- package/dist/hooks/useAnnounce.js +142 -0
- package/dist/hooks/useClickableContainer.d.ts +16 -1
- package/dist/hooks/useClickableContainer.d.ts.map +1 -1
- package/dist/hooks/useClickableContainer.js +16 -4
- package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
- package/dist/hooks/useEntryAnimation.js +4 -4
- package/dist/hooks/useFocusTrap.d.ts +18 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +87 -3
- package/dist/hooks/useGridFocus.d.ts +88 -1
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +261 -62
- package/dist/hooks/useKeyboardHint.d.ts +82 -0
- package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
- package/dist/hooks/useKeyboardHint.js +220 -0
- package/dist/hooks/useListFocus.d.ts +78 -7
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +305 -52
- package/dist/hooks/useLongPress.d.ts +21 -0
- package/dist/hooks/useLongPress.d.ts.map +1 -0
- package/dist/hooks/useLongPress.js +89 -0
- package/dist/hooks/useTreeFocus.d.ts +157 -0
- package/dist/hooks/useTreeFocus.d.ts.map +1 -0
- package/dist/hooks/useTreeFocus.js +337 -0
- package/dist/hooks/useTypeahead.d.ts +63 -0
- package/dist/hooks/useTypeahead.d.ts.map +1 -0
- package/dist/hooks/useTypeahead.js +117 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/generateThemeRules.js +1 -1
- package/dist/theme/syntax/SyntaxTheme.d.ts +1 -1
- package/dist/theme/syntax/SyntaxTheme.js +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.js +2 -2
- package/dist/theme/syntax/presets.d.ts +1 -1
- package/dist/theme/syntax/presets.d.ts.map +1 -1
- package/dist/theme/syntax/presets.js +1 -1
- package/dist/theme/syntax/tokens.d.ts +1 -1
- package/dist/theme/syntax/tokens.js +1 -1
- package/dist/theme/types.d.ts +1 -1
- package/dist/utils/dateTypes.d.ts +12 -0
- package/dist/utils/dateTypes.d.ts.map +1 -1
- package/dist/utils/dateTypes.js +41 -1
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/inputAria.d.ts +29 -0
- package/dist/utils/inputAria.d.ts.map +1 -0
- package/dist/utils/inputAria.js +30 -0
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +5 -2
- package/package.json +15 -5
- package/src/Avatar/Avatar.test.tsx +37 -0
- package/src/Avatar/Avatar.tsx +10 -5
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +3 -0
- package/src/Banner/Banner.doc.mjs +8 -0
- package/src/Banner/Banner.test.tsx +16 -7
- package/src/Banner/Banner.tsx +9 -2
- package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
- package/src/Button/Button.doc.mjs +6 -0
- package/src/Button/Button.test.tsx +105 -11
- package/src/Button/Button.tsx +76 -21
- package/src/Calendar/Calendar.doc.mjs +4 -4
- package/src/Calendar/Calendar.test.tsx +168 -30
- package/src/Calendar/Calendar.tsx +121 -66
- package/src/Calendar/hooks/index.ts +0 -6
- package/src/Calendar/index.ts +1 -3
- package/src/Calendar/styles.ts +4 -9
- package/src/Carousel/Carousel.doc.mjs +7 -1
- package/src/Carousel/Carousel.test.tsx +20 -0
- package/src/Carousel/Carousel.tsx +16 -1
- package/src/Center/Center.doc.mjs +12 -2
- package/src/Center/Center.tsx +28 -3
- package/src/Chat/ChatComposer.doc.mjs +3 -0
- package/src/Chat/ChatComposerDrawer.doc.mjs +12 -0
- package/src/Chat/ChatMessageList.doc.mjs +8 -0
- package/src/Chat/ChatMessageList.test.tsx +18 -0
- package/src/Chat/ChatMessageList.tsx +16 -0
- package/src/Chat/useTriggerMenu.tsx +3 -0
- package/src/CheckboxInput/CheckboxInput.doc.mjs +18 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +172 -27
- package/src/CheckboxInput/CheckboxInput.tsx +78 -6
- package/src/CheckboxList/CheckboxList.doc.mjs +9 -0
- package/src/CheckboxList/CheckboxList.test.tsx +169 -16
- package/src/CheckboxList/CheckboxList.tsx +56 -3
- package/src/CheckboxList/CheckboxListContext.tsx +7 -0
- package/src/Citation/Citation.doc.mjs +10 -0
- package/src/Citation/Citation.test.tsx +117 -0
- package/src/Citation/Citation.tsx +9 -1
- package/src/ClickableCard/ClickableCard.doc.mjs +15 -0
- package/src/CodeBlock/CodeBlock.test.tsx +115 -0
- package/src/CodeBlock/CodeBlock.tsx +61 -33
- package/src/CommandPalette/CommandPalette.test.tsx +47 -1
- package/src/CommandPalette/CommandPalette.tsx +9 -21
- package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
- package/src/ContextMenu/ContextMenu.test.tsx +155 -1
- package/src/ContextMenu/ContextMenu.tsx +113 -16
- package/src/DateInput/DateInput.doc.mjs +281 -56
- package/src/DateInput/DateInput.test.tsx +188 -2
- package/src/DateInput/DateInput.tsx +89 -10
- package/src/DateRangeInput/DateRangeInput.doc.mjs +251 -46
- package/src/DateRangeInput/DateRangeInput.test.tsx +182 -20
- package/src/DateRangeInput/DateRangeInput.tsx +63 -5
- package/src/DateTimeInput/DateTimeInput.doc.mjs +368 -67
- package/src/DateTimeInput/DateTimeInput.test.tsx +279 -11
- package/src/DateTimeInput/DateTimeInput.tsx +125 -17
- package/src/Dialog/Dialog.doc.mjs +2 -2
- package/src/Dialog/Dialog.tsx +12 -0
- package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
- package/src/DropdownMenu/DropdownMenu.test.tsx +56 -42
- package/src/DropdownMenu/DropdownMenu.tsx +52 -18
- package/src/EmptyState/EmptyState.test.tsx +4 -2
- package/src/EmptyState/EmptyState.tsx +6 -2
- package/src/Field/Field.test.tsx +32 -0
- package/src/Field/Field.tsx +23 -5
- package/src/Field/FieldLabel.tsx +55 -17
- package/src/FileInput/FileInput.doc.mjs +17 -0
- package/src/FileInput/FileInput.test.tsx +283 -49
- package/src/FileInput/FileInput.tsx +76 -4
- package/src/Grid/Grid.doc.mjs +14 -4
- package/src/Grid/Grid.tsx +20 -0
- package/src/HoverCard/HoverCard.doc.mjs +3 -0
- package/src/HoverCard/HoverCard.test.tsx +189 -2
- package/src/HoverCard/HoverCard.tsx +20 -16
- package/src/HoverCard/useHoverCard.tsx +13 -10
- package/src/Icon/Icon.doc.mjs +8 -0
- package/src/InputGroup/InputGroup.doc.mjs +2 -2
- package/src/InputGroup/InputGroup.test.tsx +98 -60
- package/src/InputGroup/InputGroup.tsx +21 -4
- package/src/InputGroup/InputGroupContext.ts +9 -4
- package/src/InputGroup/index.ts +1 -0
- package/src/Kbd/Kbd.test.tsx +22 -4
- package/src/Kbd/Kbd.tsx +37 -12
- package/src/Layer/anchorName.test.ts +146 -0
- package/src/Layer/anchorName.ts +46 -0
- package/src/Layer/layerAnimations.stylex.ts +20 -4
- package/src/Layer/useLayer.doc.mjs +12 -2
- package/src/Layer/useLayer.tsx +100 -15
- package/src/Layout/Layout.doc.mjs +1 -1
- package/src/Layout/Layout.tsx +8 -16
- package/src/Layout/LayoutFooter.doc.mjs +4 -4
- package/src/Layout/LayoutFooter.tsx +3 -3
- package/src/Layout/LayoutHeader.doc.mjs +4 -4
- package/src/Layout/LayoutHeader.tsx +3 -3
- package/src/Layout/LayoutPanel.tsx +3 -3
- package/src/Layout/padding.stylex.ts +52 -0
- package/src/Lightbox/Lightbox.doc.mjs +9 -2
- package/src/Lightbox/Lightbox.test.tsx +53 -5
- package/src/Lightbox/Lightbox.tsx +9 -4
- package/src/Link/Link.doc.mjs +14 -0
- package/src/Link/Link.test.tsx +52 -2
- package/src/Link/Link.tsx +42 -7
- package/src/Link/LinkProvider.tsx +1 -0
- package/src/List/List.doc.mjs +7 -0
- package/src/Markdown/Markdown.doc.mjs +2 -0
- package/src/Markdown/Markdown.test.tsx +28 -26
- package/src/Markdown/Markdown.tsx +21 -6
- package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
- package/src/MobileNav/MobileNav.doc.mjs +8 -8
- package/src/MobileNav/MobileNav.tsx +13 -0
- package/src/MobileNav/MobileNavReopen.test.tsx +118 -0
- package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
- package/src/MoreMenu/MoreMenu.tsx +0 -9
- package/src/MultiSelector/MultiSelector.doc.mjs +25 -0
- package/src/MultiSelector/MultiSelector.test.tsx +375 -8
- package/src/MultiSelector/MultiSelector.tsx +145 -21
- package/src/MultiSelector/hooks.ts +27 -0
- package/src/NavMenu/NavHeadingMenu.test.tsx +77 -1
- package/src/NavMenu/NavHeadingMenu.tsx +50 -3
- package/src/NumberInput/NumberInput.doc.mjs +17 -0
- package/src/NumberInput/NumberInput.test.tsx +242 -40
- package/src/NumberInput/NumberInput.tsx +89 -11
- package/src/OverflowList/OverflowList.doc.mjs +17 -0
- package/src/Pagination/Pagination.doc.mjs +3 -3
- package/src/Pagination/Pagination.test.tsx +250 -14
- package/src/Pagination/Pagination.tsx +54 -29
- package/src/Popover/usePopover.doc.mjs +7 -3
- package/src/Popover/usePopover.tsx +49 -6
- package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
- package/src/PowerSearch/PowerSearch.test.tsx +97 -1
- package/src/PowerSearch/PowerSearch.tsx +16 -3
- package/src/ProgressBar/ProgressBar.test.tsx +45 -27
- package/src/ProgressBar/ProgressBar.tsx +3 -4
- package/src/RadioList/RadioList.doc.mjs +9 -0
- package/src/RadioList/RadioList.test.tsx +252 -16
- package/src/RadioList/RadioList.tsx +166 -10
- package/src/RadioList/RadioListItem.tsx +14 -2
- package/src/Resizable/Resizable.doc.mjs +1 -1
- package/src/Section/Section.doc.mjs +11 -0
- package/src/SegmentedControl/SegmentedControl.doc.mjs +9 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +214 -42
- package/src/SegmentedControl/SegmentedControl.tsx +102 -54
- package/src/SegmentedControl/SegmentedControlContext.ts +7 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +14 -1
- package/src/SelectableCard/SelectableCard.doc.mjs +15 -0
- package/src/Selector/Selector.doc.mjs +25 -0
- package/src/Selector/Selector.test.tsx +322 -15
- package/src/Selector/Selector.tsx +126 -40
- package/src/Selector/hooks.ts +23 -0
- package/src/SideNav/SideNav.test.tsx +16 -0
- package/src/SideNav/SideNavItem.tsx +2 -4
- package/src/Skeleton/Skeleton.doc.mjs +11 -1
- package/src/Skeleton/Skeleton.test.tsx +25 -0
- package/src/Skeleton/Skeleton.tsx +11 -1
- package/src/Slider/Slider.doc.mjs +19 -0
- package/src/Slider/Slider.test.tsx +158 -18
- package/src/Slider/Slider.tsx +54 -6
- package/src/Spinner/Spinner.tsx +7 -1
- package/src/Stack/Stack.doc.mjs +77 -0
- package/src/Stack/Stack.test.tsx +55 -5
- package/src/Stack/Stack.tsx +73 -24
- package/src/Stack/StackItem.test.tsx +23 -0
- package/src/Stack/StackItem.tsx +20 -23
- package/src/Switch/Switch.doc.mjs +15 -0
- package/src/Switch/Switch.test.tsx +162 -27
- package/src/Switch/Switch.tsx +61 -21
- package/src/TabList/Tab.tsx +6 -0
- package/src/TabList/TabList.doc.mjs +12 -0
- package/src/TabList/TabList.test.tsx +208 -0
- package/src/TabList/TabList.tsx +102 -12
- package/src/TabList/TabListContext.ts +7 -3
- package/src/TabList/TabMenu.tsx +6 -3
- package/src/Table/BaseTable.tsx +72 -41
- package/src/Table/Table.doc.mjs +14 -0
- package/src/Table/Table.test.tsx +39 -30
- package/src/Table/Table.tsx +27 -1
- package/src/Table/TableCell.tsx +25 -23
- package/src/Table/TableHeaderCell.tsx +28 -29
- package/src/Table/TableRow.tsx +37 -7
- package/src/Table/index.ts +6 -2
- package/src/Table/plugins/pagination/paginateData.ts +10 -3
- package/src/Table/plugins/pagination/useTablePagination.test.tsx +16 -0
- package/src/Table/plugins/pagination/useTablePagination.tsx +8 -1
- package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
- package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
- package/src/Table/plugins/stickyColumns/index.ts +4 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +163 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +407 -0
- package/src/Table/tableContextMenu.test.tsx +157 -0
- package/src/Table/tableContextMenu.tsx +142 -0
- package/src/Table/types.ts +175 -4
- package/src/Table/useBaseTablePlugins.ts +1 -0
- package/src/Table/useTableColumnResize.doc.mjs +96 -0
- package/src/Table/useTableStickyColumns.doc.mjs +59 -0
- package/src/Text/Heading.doc.mjs +15 -2
- package/src/Text/Text.doc.mjs +7 -1
- package/src/Text/text.stylex.ts +2 -2
- package/src/TextArea/TextArea.doc.mjs +17 -0
- package/src/TextArea/TextArea.test.tsx +167 -35
- package/src/TextArea/TextArea.tsx +62 -15
- package/src/TextInput/TextInput.doc.mjs +17 -0
- package/src/TextInput/TextInput.test.tsx +168 -34
- package/src/TextInput/TextInput.tsx +77 -9
- package/src/TimeInput/TimeInput.doc.mjs +335 -60
- package/src/TimeInput/TimeInput.test.tsx +144 -7
- package/src/TimeInput/TimeInput.tsx +74 -5
- package/src/Timestamp/Timestamp.doc.mjs +9 -0
- package/src/Timestamp/Timestamp.test.tsx +44 -18
- package/src/Timestamp/Timestamp.tsx +30 -10
- package/src/Toast/Toast.tsx +14 -0
- package/src/Toast/ToastViewport.test.tsx +204 -0
- package/src/Toast/ToastViewport.tsx +167 -21
- package/src/ToggleButton/ToggleButton.doc.mjs +9 -3
- package/src/ToggleButton/ToggleButton.test.tsx +39 -18
- package/src/ToggleButton/ToggleButton.tsx +46 -83
- package/src/Tokenizer/Tokenizer.doc.mjs +15 -0
- package/src/Tokenizer/Tokenizer.test.tsx +105 -1
- package/src/Tokenizer/Tokenizer.tsx +41 -2
- package/src/Toolbar/Toolbar.doc.mjs +65 -5
- package/src/Toolbar/Toolbar.test.tsx +109 -6
- package/src/Toolbar/Toolbar.tsx +59 -5
- package/src/Tooltip/Tooltip.test.tsx +81 -0
- package/src/Tooltip/useTooltip.tsx +57 -11
- package/src/TreeList/TreeList.test.tsx +295 -6
- package/src/TreeList/TreeList.tsx +73 -1
- package/src/TreeList/TreeListItem.tsx +51 -5
- package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
- package/src/Typeahead/BaseTypeahead.tsx +86 -9
- package/src/Typeahead/Typeahead.doc.mjs +136 -30
- package/src/Typeahead/Typeahead.test.tsx +331 -1
- package/src/Typeahead/Typeahead.tsx +52 -1
- package/src/VisuallyHidden/VisuallyHidden.doc.mjs +80 -0
- package/src/VisuallyHidden/VisuallyHidden.test.tsx +76 -0
- package/src/VisuallyHidden/VisuallyHidden.tsx +113 -0
- package/src/VisuallyHidden/index.ts +15 -0
- package/src/hooks/focusableSelector.ts +25 -0
- package/src/hooks/index.ts +28 -2
- package/src/hooks/useAnnounce.test.tsx +101 -0
- package/src/hooks/useAnnounce.ts +168 -0
- package/src/hooks/useClickableContainer.ts +16 -4
- package/src/hooks/useEntryAnimation.ts +16 -4
- package/src/hooks/useFocusTrap.test.tsx +132 -0
- package/src/hooks/useFocusTrap.ts +98 -4
- package/src/hooks/useGridFocus.doc.mjs +40 -2
- package/src/hooks/useGridFocus.test.tsx +132 -0
- package/src/hooks/useGridFocus.ts +343 -67
- package/src/hooks/useImageMode.test.ts +133 -0
- package/src/hooks/useKeyboardHint.doc.mjs +101 -0
- package/src/hooks/useKeyboardHint.test.tsx +70 -0
- package/src/hooks/useKeyboardHint.tsx +332 -0
- package/src/hooks/useListFocus.doc.mjs +50 -10
- package/src/hooks/useListFocus.test.tsx +375 -0
- package/src/hooks/useListFocus.ts +395 -57
- package/src/hooks/useLongPress.test.tsx +134 -0
- package/src/hooks/useLongPress.ts +119 -0
- package/src/hooks/useTreeFocus.doc.mjs +140 -0
- package/src/hooks/useTreeFocus.test.tsx +214 -0
- package/src/hooks/useTreeFocus.ts +559 -0
- package/src/hooks/useTypeahead.test.tsx +109 -0
- package/src/hooks/useTypeahead.ts +183 -0
- package/src/index.ts +1 -0
- package/src/theme/derivedVarRegistry.test.ts +4 -0
- package/src/theme/generateThemeRules.test.ts +7 -8
- package/src/theme/generateThemeRules.ts +1 -1
- package/src/theme/syntax/SyntaxTheme.tsx +1 -1
- package/src/theme/syntax/defineSyntaxTheme.ts +20 -11
- package/src/theme/syntax/presets.ts +5 -2
- package/src/theme/syntax/tokens.ts +1 -1
- package/src/theme/types.ts +1 -1
- package/src/utils/dateTypes.test.ts +40 -0
- package/src/utils/dateTypes.ts +40 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/inputAria.test.ts +39 -0
- package/src/utils/inputAria.ts +58 -0
- package/src/utils/timeParser.test.ts +10 -0
- package/src/utils/timeParser.ts +5 -2
- package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
- package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
- package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
- package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import {describe, it, expect, vi, beforeAll, afterAll} from 'vitest';
|
|
13
|
-
import {render, screen, fireEvent, act} from '@testing-library/react';
|
|
13
|
+
import {render, screen, fireEvent, act, waitFor} from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import {Tokenizer} from './Tokenizer';
|
|
16
16
|
import type {SearchSource, SearchableItem} from '../Typeahead/types';
|
|
@@ -763,4 +763,108 @@ describe('Tokenizer', () => {
|
|
|
763
763
|
expect(screen.getByText('Create "NewTag"')).toBeInTheDocument();
|
|
764
764
|
});
|
|
765
765
|
});
|
|
766
|
+
|
|
767
|
+
describe('disabledMessage', () => {
|
|
768
|
+
const h = {hidden: true} as const;
|
|
769
|
+
const isOpen = (el: Element) => el.matches(':popover-open');
|
|
770
|
+
|
|
771
|
+
function renderTokenizer(props?: {onChange?: () => void}) {
|
|
772
|
+
return render(
|
|
773
|
+
<Tokenizer
|
|
774
|
+
label="Members"
|
|
775
|
+
searchSource={userSource}
|
|
776
|
+
value={[]}
|
|
777
|
+
onChange={props?.onChange ?? (() => {})}
|
|
778
|
+
isDisabled
|
|
779
|
+
disabledMessage="You need edit access to change members"
|
|
780
|
+
/>,
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
it('shows the reason tooltip on hover when disabled with a reason', async () => {
|
|
785
|
+
renderTokenizer();
|
|
786
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
787
|
+
expect(tooltip).toHaveTextContent(
|
|
788
|
+
'You need edit access to change members',
|
|
789
|
+
);
|
|
790
|
+
const wrapper = screen.getByRole('group', {name: 'Members'});
|
|
791
|
+
fireEvent.mouseEnter(wrapper);
|
|
792
|
+
await waitFor(() => expect(isOpen(tooltip)).toBe(true));
|
|
793
|
+
fireEvent.mouseLeave(wrapper);
|
|
794
|
+
await waitFor(() => expect(isOpen(tooltip)).toBe(false));
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
it('shows the reason tooltip on keyboard focus', async () => {
|
|
798
|
+
const user = userEvent.setup();
|
|
799
|
+
renderTokenizer();
|
|
800
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
801
|
+
await user.tab();
|
|
802
|
+
expect(screen.getByRole('combobox')).toHaveFocus();
|
|
803
|
+
await waitFor(() => expect(isOpen(tooltip)).toBe(true));
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
it('does not render a tooltip when not disabled', () => {
|
|
807
|
+
render(
|
|
808
|
+
<Tokenizer
|
|
809
|
+
label="Members"
|
|
810
|
+
searchSource={userSource}
|
|
811
|
+
value={[]}
|
|
812
|
+
onChange={() => {}}
|
|
813
|
+
disabledMessage="You need edit access to change members"
|
|
814
|
+
/>,
|
|
815
|
+
);
|
|
816
|
+
expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
it('does not render a tooltip when disabled without a reason', () => {
|
|
820
|
+
render(
|
|
821
|
+
<Tokenizer
|
|
822
|
+
label="Members"
|
|
823
|
+
searchSource={userSource}
|
|
824
|
+
value={[]}
|
|
825
|
+
onChange={() => {}}
|
|
826
|
+
isDisabled
|
|
827
|
+
/>,
|
|
828
|
+
);
|
|
829
|
+
expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
it('keeps the input focusable via aria-disabled when a reason is provided', () => {
|
|
833
|
+
renderTokenizer();
|
|
834
|
+
const input = screen.getByRole('combobox');
|
|
835
|
+
expect(input).not.toBeDisabled();
|
|
836
|
+
expect(input).toHaveAttribute('aria-disabled', 'true');
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
it('links the reason tooltip via aria-describedby', () => {
|
|
840
|
+
renderTokenizer();
|
|
841
|
+
const input = screen.getByRole('combobox');
|
|
842
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
843
|
+
expect(input.getAttribute('aria-describedby')).toContain(tooltip.id);
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
it('blocks input while focusable-disabled', async () => {
|
|
847
|
+
const user = userEvent.setup();
|
|
848
|
+
const onChange = vi.fn();
|
|
849
|
+
renderTokenizer({onChange});
|
|
850
|
+
const input = screen.getByRole('combobox');
|
|
851
|
+
input.focus();
|
|
852
|
+
await user.keyboard('Ali');
|
|
853
|
+
expect((input as HTMLInputElement).value).toBe('');
|
|
854
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
it('keeps the input natively disabled when disabled without a reason', () => {
|
|
858
|
+
render(
|
|
859
|
+
<Tokenizer
|
|
860
|
+
label="Members"
|
|
861
|
+
searchSource={userSource}
|
|
862
|
+
value={[]}
|
|
863
|
+
onChange={() => {}}
|
|
864
|
+
isDisabled
|
|
865
|
+
/>,
|
|
866
|
+
);
|
|
867
|
+
expect(screen.getByRole('combobox')).toBeDisabled();
|
|
868
|
+
});
|
|
869
|
+
});
|
|
766
870
|
});
|
|
@@ -42,6 +42,7 @@ import {Token} from '../Token';
|
|
|
42
42
|
import {renderIconSlot, type IconType} from '../Icon';
|
|
43
43
|
import {OverflowList} from '../OverflowList';
|
|
44
44
|
import {useLayer} from '../Layer/useLayer';
|
|
45
|
+
import {useTooltip} from '../Tooltip';
|
|
45
46
|
import {
|
|
46
47
|
colorVars,
|
|
47
48
|
spacingVars,
|
|
@@ -145,6 +146,17 @@ export interface TokenizerProps<T extends SearchableItem> extends Omit<
|
|
|
145
146
|
emptySearchResultsText?: string;
|
|
146
147
|
/** Whether the input is disabled. @default false */
|
|
147
148
|
isDisabled?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Explains why the tokenizer is disabled. When set together with
|
|
151
|
+
* `isDisabled`, the tokenizer shows a tooltip with this text on hover and
|
|
152
|
+
* keyboard focus, and the input stays focusable (via `aria-disabled`) so the
|
|
153
|
+
* reason is discoverable by keyboard and assistive technology. Input stays
|
|
154
|
+
* blocked.
|
|
155
|
+
*
|
|
156
|
+
* Use this instead of wrapping a disabled tokenizer in `Tooltip` — disabled
|
|
157
|
+
* controls don't emit the pointer events an external tooltip needs.
|
|
158
|
+
*/
|
|
159
|
+
disabledMessage?: string;
|
|
148
160
|
/** Show clear button (clears all tokens). @default false */
|
|
149
161
|
hasClear?: boolean;
|
|
150
162
|
/**
|
|
@@ -222,7 +234,10 @@ const styles = stylex.create({
|
|
|
222
234
|
},
|
|
223
235
|
endSection: {
|
|
224
236
|
position: 'absolute',
|
|
225
|
-
|
|
237
|
+
// Match the field's inline padding (inputWrapperStyles.base uses
|
|
238
|
+
// spacing-2) so end content (clear button, resultCount) lines up with
|
|
239
|
+
// the text/start-icon inset instead of hugging the border at ~3px.
|
|
240
|
+
insetInlineEnd: spacingVars['--spacing-2'],
|
|
226
241
|
display: 'flex',
|
|
227
242
|
alignItems: 'center',
|
|
228
243
|
gap: spacingVars['--spacing-2'],
|
|
@@ -362,6 +377,7 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
362
377
|
maxMenuItems,
|
|
363
378
|
emptySearchResultsText,
|
|
364
379
|
isDisabled = false,
|
|
380
|
+
disabledMessage,
|
|
365
381
|
hasClear = false,
|
|
366
382
|
endContent,
|
|
367
383
|
hasAutoFocus,
|
|
@@ -387,6 +403,19 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
387
403
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
388
404
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
389
405
|
|
|
406
|
+
// Disabled-reason tooltip. Disabled controls swallow pointer events, so the
|
|
407
|
+
// tooltip listeners attach to the input wrapper and the typeahead input stays
|
|
408
|
+
// perceivable via aria-disabled instead of the disabled attribute. Input is
|
|
409
|
+
// blocked by the isDisabled guards in BaseTypeahead and handleWrapperClick.
|
|
410
|
+
const showsDisabledMessage = isDisabled && !!disabledMessage;
|
|
411
|
+
const disabledMessageTooltip = useTooltip({
|
|
412
|
+
placement: 'above',
|
|
413
|
+
// The wrapper is not naturally focusable; focusin bubbles up from the
|
|
414
|
+
// input, so always attach focus listeners.
|
|
415
|
+
focusTrigger: 'always',
|
|
416
|
+
isEnabled: showsDisabledMessage,
|
|
417
|
+
});
|
|
418
|
+
|
|
390
419
|
useImperativeHandle(handleRef, () => ({
|
|
391
420
|
focus() {
|
|
392
421
|
inputRef.current?.focus();
|
|
@@ -617,6 +646,7 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
617
646
|
[
|
|
618
647
|
description ? descriptionId : null,
|
|
619
648
|
status?.message ? statusMessageId : null,
|
|
649
|
+
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
620
650
|
]
|
|
621
651
|
.filter(Boolean)
|
|
622
652
|
.join(' ') || undefined;
|
|
@@ -656,7 +686,13 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
656
686
|
|
|
657
687
|
const wrapperContent = (
|
|
658
688
|
<div
|
|
659
|
-
ref={
|
|
689
|
+
ref={el => {
|
|
690
|
+
wrapperRef.current = el;
|
|
691
|
+
// Anchor + hover/focus listeners for the disabled-message tooltip.
|
|
692
|
+
// Handlers are gated internally by isEnabled, so attaching
|
|
693
|
+
// unconditionally is safe.
|
|
694
|
+
disabledMessageTooltip.ref(el);
|
|
695
|
+
}}
|
|
660
696
|
role="group"
|
|
661
697
|
aria-label={label}
|
|
662
698
|
onClick={handleWrapperClick}
|
|
@@ -707,6 +743,7 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
707
743
|
maxMenuItems={maxMenuItems}
|
|
708
744
|
emptySearchResultsText={emptySearchResultsText}
|
|
709
745
|
isDisabled={isDisabled}
|
|
746
|
+
isFocusableDisabled={showsDisabledMessage}
|
|
710
747
|
hasAutoFocus={hasAutoFocus}
|
|
711
748
|
inputId={inputId}
|
|
712
749
|
ariaDescribedBy={ariaDescribedBy}
|
|
@@ -828,6 +865,8 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
828
865
|
className={className}
|
|
829
866
|
style={style}>
|
|
830
867
|
{tokenizerContent}
|
|
868
|
+
{showsDisabledMessage &&
|
|
869
|
+
disabledMessageTooltip.renderTooltip(disabledMessage)}
|
|
831
870
|
</Field>
|
|
832
871
|
);
|
|
833
872
|
}
|
|
@@ -7,6 +7,25 @@ export const docs = {
|
|
|
7
7
|
displayName: 'Toolbar',
|
|
8
8
|
category: 'Action',
|
|
9
9
|
keywords: ['toolbar', 'nav', 'bar', 'actions', 'buttonbar', 'header', 'footer', 'action-bar', 'control-bar'],
|
|
10
|
+
playground: {
|
|
11
|
+
defaults: {
|
|
12
|
+
label: 'Table actions',
|
|
13
|
+
size: 'sm',
|
|
14
|
+
dividers: ['bottom'],
|
|
15
|
+
startContent: {
|
|
16
|
+
__element: 'TabList',
|
|
17
|
+
props: {value: 'overview'},
|
|
18
|
+
children: [
|
|
19
|
+
{__element: 'Tab', props: {label: 'Overview', value: 'overview'}},
|
|
20
|
+
{__element: 'Tab', props: {label: 'Activity', value: 'activity'}},
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
endContent: [
|
|
24
|
+
{__element: 'Selector', props: {label: 'Status', isLabelHidden: true, placeholder: 'Status', size: 'sm', options: ['Open', 'In progress', 'Done']}},
|
|
25
|
+
{__element: 'Button', props: {label: 'New item', variant: 'primary', size: 'sm'}},
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
10
29
|
theming: {
|
|
11
30
|
targets: [
|
|
12
31
|
{className: 'astryx-toolbar', states: ['size']},
|
|
@@ -29,21 +48,62 @@ export const docs = {
|
|
|
29
48
|
name: 'startContent',
|
|
30
49
|
type: 'ReactNode',
|
|
31
50
|
description: 'Content aligned to the start (left in LTR).',
|
|
32
|
-
slotElements: [
|
|
51
|
+
slotElements: [
|
|
52
|
+
{__element: 'Text', props: {type: 'body', weight: 'bold'}, children: 'Title'},
|
|
53
|
+
{__element: 'Button', props: {label: 'Back', variant: 'ghost', size: 'sm'}},
|
|
54
|
+
{__element: 'IconButton', props: {label: 'Filter', icon: {__element: 'Icon', props: {icon: 'check', size: 'sm'}}, variant: 'ghost', size: 'sm'}},
|
|
55
|
+
{
|
|
56
|
+
__element: 'TabList',
|
|
57
|
+
props: {value: 'overview'},
|
|
58
|
+
children: [
|
|
59
|
+
{__element: 'Tab', props: {label: 'Overview', value: 'overview'}},
|
|
60
|
+
{__element: 'Tab', props: {label: 'Activity', value: 'activity'}},
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
__element: 'SegmentedControl',
|
|
65
|
+
props: {label: 'View', value: 'list'},
|
|
66
|
+
children: [
|
|
67
|
+
{__element: 'SegmentedControlItem', props: {label: 'List', value: 'list'}},
|
|
68
|
+
{__element: 'SegmentedControlItem', props: {label: 'Grid', value: 'grid'}},
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{__element: 'Selector', props: {label: 'Status', isLabelHidden: true, placeholder: 'Status', size: 'sm', options: ['Open', 'In progress', 'Done']}},
|
|
72
|
+
],
|
|
33
73
|
},
|
|
34
74
|
{
|
|
35
75
|
name: 'centerContent',
|
|
36
76
|
type: 'ReactNode',
|
|
37
77
|
description:
|
|
38
78
|
'Centered content. Switches layout to CSS grid (1fr auto 1fr).',
|
|
39
|
-
slotElements: [
|
|
79
|
+
slotElements: [
|
|
80
|
+
{__element: 'Text', props: {type: 'body', weight: 'bold'}, children: 'Center'},
|
|
81
|
+
{
|
|
82
|
+
__element: 'SegmentedControl',
|
|
83
|
+
props: {label: 'View', value: 'list'},
|
|
84
|
+
children: [
|
|
85
|
+
{__element: 'SegmentedControlItem', props: {label: 'List', value: 'list'}},
|
|
86
|
+
{__element: 'SegmentedControlItem', props: {label: 'Grid', value: 'grid'}},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
__element: 'TabList',
|
|
91
|
+
props: {value: 'overview'},
|
|
92
|
+
children: [
|
|
93
|
+
{__element: 'Tab', props: {label: 'Overview', value: 'overview'}},
|
|
94
|
+
{__element: 'Tab', props: {label: 'Activity', value: 'activity'}},
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
],
|
|
40
98
|
},
|
|
41
99
|
{
|
|
42
100
|
name: 'endContent',
|
|
43
101
|
type: 'ReactNode',
|
|
44
102
|
description: 'Content aligned to the end (right in LTR).',
|
|
45
103
|
slotElements: [
|
|
46
|
-
{__element: '
|
|
104
|
+
{__element: 'Button', props: {label: 'Save', variant: 'primary', size: 'sm'}},
|
|
105
|
+
{__element: 'IconButton', props: {label: 'More', icon: {__element: 'Icon', props: {icon: 'chevronDown', size: 'sm'}}, variant: 'ghost', size: 'sm'}},
|
|
106
|
+
{__element: 'Selector', props: {label: 'Sort', isLabelHidden: true, placeholder: 'Sort by', size: 'sm', options: ['Newest', 'Oldest', 'A–Z']}},
|
|
47
107
|
{__element: 'Badge', props: {label: '3'}},
|
|
48
108
|
],
|
|
49
109
|
},
|
|
@@ -51,14 +111,14 @@ export const docs = {
|
|
|
51
111
|
name: 'size',
|
|
52
112
|
type: "'sm' | 'md' | 'lg'",
|
|
53
113
|
description:
|
|
54
|
-
'Size of the toolbar. Controls minimum height and coordinates with Button, TextInput, TabList, and Selector
|
|
114
|
+
'Size of the toolbar. Controls minimum height and coordinates with Button, TextInput, TabList, and Selector; children inherit this size as their default via SizeContext.',
|
|
55
115
|
default: "'md'",
|
|
56
116
|
},
|
|
57
117
|
{
|
|
58
118
|
name: 'gap',
|
|
59
119
|
type: 'SpacingStep',
|
|
60
120
|
description: 'Gap between items within each slot.',
|
|
61
|
-
default: '
|
|
121
|
+
default: '1',
|
|
62
122
|
},
|
|
63
123
|
{
|
|
64
124
|
name: 'orientation',
|
|
@@ -71,9 +71,12 @@ describe('Toolbar', () => {
|
|
|
71
71
|
expect(screen.getByTestId('center')).toBeInTheDocument();
|
|
72
72
|
expect(screen.getByTestId('end')).toBeInTheDocument();
|
|
73
73
|
|
|
74
|
-
// Three-slot layout produces 3 child divs
|
|
74
|
+
// Three-slot layout produces 3 child divs (plus the aria-hidden
|
|
75
|
+
// keyboard-hint popover, which is excluded here as an implementation detail)
|
|
75
76
|
const toolbar = screen.getByRole('toolbar');
|
|
76
|
-
expect(toolbar.
|
|
77
|
+
expect(toolbar.querySelectorAll(':scope > :not([popover])')).toHaveLength(
|
|
78
|
+
3,
|
|
79
|
+
);
|
|
77
80
|
});
|
|
78
81
|
|
|
79
82
|
it('renders two-slot layout without centerContent', () => {
|
|
@@ -87,9 +90,12 @@ describe('Toolbar', () => {
|
|
|
87
90
|
expect(screen.getByTestId('start')).toBeInTheDocument();
|
|
88
91
|
expect(screen.getByTestId('end')).toBeInTheDocument();
|
|
89
92
|
|
|
90
|
-
// Two-slot layout produces 2 child divs
|
|
93
|
+
// Two-slot layout produces 2 child divs (plus the aria-hidden
|
|
94
|
+
// keyboard-hint popover, excluded here)
|
|
91
95
|
const toolbar = screen.getByRole('toolbar');
|
|
92
|
-
expect(toolbar.
|
|
96
|
+
expect(toolbar.querySelectorAll(':scope > :not([popover])')).toHaveLength(
|
|
97
|
+
2,
|
|
98
|
+
);
|
|
93
99
|
});
|
|
94
100
|
|
|
95
101
|
it('renders start-only layout', () => {
|
|
@@ -101,7 +107,9 @@ describe('Toolbar', () => {
|
|
|
101
107
|
);
|
|
102
108
|
expect(screen.getByTestId('start')).toBeInTheDocument();
|
|
103
109
|
const toolbar = screen.getByRole('toolbar');
|
|
104
|
-
expect(toolbar.
|
|
110
|
+
expect(toolbar.querySelectorAll(':scope > :not([popover])')).toHaveLength(
|
|
111
|
+
1,
|
|
112
|
+
);
|
|
105
113
|
});
|
|
106
114
|
|
|
107
115
|
it('renders end-only layout', () => {
|
|
@@ -113,7 +121,9 @@ describe('Toolbar', () => {
|
|
|
113
121
|
);
|
|
114
122
|
expect(screen.getByTestId('end')).toBeInTheDocument();
|
|
115
123
|
const toolbar = screen.getByRole('toolbar');
|
|
116
|
-
expect(toolbar.
|
|
124
|
+
expect(toolbar.querySelectorAll(':scope > :not([popover])')).toHaveLength(
|
|
125
|
+
1,
|
|
126
|
+
);
|
|
117
127
|
});
|
|
118
128
|
|
|
119
129
|
it('sets aria-orientation to horizontal by default', () => {
|
|
@@ -256,4 +266,97 @@ describe('Toolbar', () => {
|
|
|
256
266
|
render(<Toolbar label="Actions" data-testid="my-toolbar" />);
|
|
257
267
|
expect(screen.getByTestId('my-toolbar')).toBe(screen.getByRole('toolbar'));
|
|
258
268
|
});
|
|
269
|
+
|
|
270
|
+
it('is a single tab stop — only one item is tabbable (navigation-3)', () => {
|
|
271
|
+
render(
|
|
272
|
+
<Toolbar
|
|
273
|
+
label="Actions"
|
|
274
|
+
startContent={
|
|
275
|
+
<>
|
|
276
|
+
<button type="button">Cut</button>
|
|
277
|
+
<button type="button">Copy</button>
|
|
278
|
+
<button type="button">Paste</button>
|
|
279
|
+
</>
|
|
280
|
+
}
|
|
281
|
+
/>,
|
|
282
|
+
);
|
|
283
|
+
const buttons = screen.getAllByRole('button');
|
|
284
|
+
const tabbable = buttons.filter(b => b.getAttribute('tabindex') === '0');
|
|
285
|
+
expect(tabbable).toHaveLength(1);
|
|
286
|
+
expect(buttons[0]).toHaveAttribute('tabindex', '0');
|
|
287
|
+
expect(buttons[1]).toHaveAttribute('tabindex', '-1');
|
|
288
|
+
expect(buttons[2]).toHaveAttribute('tabindex', '-1');
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('does not steal caret keys from a text input mid-line (navigation-4)', async () => {
|
|
292
|
+
const user = userEvent.setup();
|
|
293
|
+
render(
|
|
294
|
+
<Toolbar
|
|
295
|
+
label="Search"
|
|
296
|
+
startContent={
|
|
297
|
+
<>
|
|
298
|
+
<input type="text" aria-label="Query" defaultValue="hello" />
|
|
299
|
+
<button type="button">Go</button>
|
|
300
|
+
</>
|
|
301
|
+
}
|
|
302
|
+
/>,
|
|
303
|
+
);
|
|
304
|
+
const inputEl = screen.getByLabelText('Query');
|
|
305
|
+
if (!(inputEl instanceof HTMLInputElement)) {
|
|
306
|
+
throw new Error('expected an input');
|
|
307
|
+
}
|
|
308
|
+
inputEl.focus();
|
|
309
|
+
inputEl.setSelectionRange(1, 1); // caret mid-line
|
|
310
|
+
await user.keyboard('{ArrowRight}');
|
|
311
|
+
// Caret movement stays in the input; focus is not stolen by the toolbar.
|
|
312
|
+
expect(document.activeElement).toBe(inputEl);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('composes consumer onKeyDown with internal arrow navigation', async () => {
|
|
316
|
+
const user = userEvent.setup();
|
|
317
|
+
const onKeyDown = vi.fn();
|
|
318
|
+
|
|
319
|
+
render(
|
|
320
|
+
<Toolbar
|
|
321
|
+
label="Actions"
|
|
322
|
+
onKeyDown={onKeyDown}
|
|
323
|
+
startContent={
|
|
324
|
+
<>
|
|
325
|
+
<button type="button">Cut</button>
|
|
326
|
+
<button type="button">Copy</button>
|
|
327
|
+
</>
|
|
328
|
+
}
|
|
329
|
+
/>,
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
const buttons = screen.getAllByRole('button');
|
|
333
|
+
buttons[0].focus();
|
|
334
|
+
await user.keyboard('{ArrowRight}');
|
|
335
|
+
|
|
336
|
+
expect(onKeyDown).toHaveBeenCalled();
|
|
337
|
+
expect(buttons[1]).toHaveFocus();
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('respects preventDefault from consumer onKeyDown', async () => {
|
|
341
|
+
const user = userEvent.setup();
|
|
342
|
+
|
|
343
|
+
render(
|
|
344
|
+
<Toolbar
|
|
345
|
+
label="Actions"
|
|
346
|
+
onKeyDown={e => e.preventDefault()}
|
|
347
|
+
startContent={
|
|
348
|
+
<>
|
|
349
|
+
<button type="button">Cut</button>
|
|
350
|
+
<button type="button">Copy</button>
|
|
351
|
+
</>
|
|
352
|
+
}
|
|
353
|
+
/>,
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
const buttons = screen.getAllByRole('button');
|
|
357
|
+
buttons[0].focus();
|
|
358
|
+
await user.keyboard('{ArrowRight}');
|
|
359
|
+
|
|
360
|
+
expect(buttons[0]).toHaveFocus();
|
|
361
|
+
});
|
|
259
362
|
});
|
package/src/Toolbar/Toolbar.tsx
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file Toolbar.tsx
|
|
7
|
-
* @input Uses Section, SizeContext, useListFocus, StyleX, spacingVars, sizeVars
|
|
7
|
+
* @input Uses Section, SizeContext, useListFocus, useKeyboardHint, StyleX, spacingVars, sizeVars
|
|
8
8
|
* @output Exports Toolbar component and ToolbarProps
|
|
9
9
|
* @position Core implementation; consumed by index.ts
|
|
10
10
|
*
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* - /packages/cli/templates/blocks/components/Toolbar/ (showcase blocks)
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import type
|
|
19
|
+
import {useCallback, type ReactNode} from 'react';
|
|
20
20
|
import type {BaseProps} from '../BaseProps';
|
|
21
21
|
import type {SectionVariant} from '../Section/Section';
|
|
22
22
|
import type {SpacingStep} from '../utils/types';
|
|
@@ -26,6 +26,7 @@ import {spacingVars, sizeVars} from '../theme/tokens.stylex';
|
|
|
26
26
|
import {mergeProps} from '../utils';
|
|
27
27
|
import {Section} from '../Section/Section';
|
|
28
28
|
import {useListFocus} from '../hooks/useListFocus';
|
|
29
|
+
import {useKeyboardHint} from '../hooks/useKeyboardHint';
|
|
29
30
|
import {SizeProvider} from '../SizeContext/SizeContext';
|
|
30
31
|
import {edgeCompSlot} from '../Layout/edgeCompensation.stylex';
|
|
31
32
|
import {themeProps} from '../utils/themeProps';
|
|
@@ -227,6 +228,12 @@ export function Toolbar({
|
|
|
227
228
|
className,
|
|
228
229
|
style,
|
|
229
230
|
ref,
|
|
231
|
+
onKeyDown: onKeyDownProp,
|
|
232
|
+
onFocus: onFocusProp,
|
|
233
|
+
onBlur: onBlurProp,
|
|
234
|
+
role: _role,
|
|
235
|
+
'aria-label': _ariaLabel,
|
|
236
|
+
'aria-orientation': _ariaOrientation,
|
|
230
237
|
...props
|
|
231
238
|
}: ToolbarProps) {
|
|
232
239
|
const hasCenterContent = centerContent != null;
|
|
@@ -235,11 +242,55 @@ export function Toolbar({
|
|
|
235
242
|
|
|
236
243
|
const gapVar = spacingVars[spacingStepToVar[gap]] as string;
|
|
237
244
|
|
|
238
|
-
const {listRef, handleKeyDown} = useListFocus<HTMLDivElement>({
|
|
239
|
-
itemSelector: 'button, input, [tabindex
|
|
245
|
+
const {listRef, handleKeyDown, handleFocus} = useListFocus<HTMLDivElement>({
|
|
246
|
+
itemSelector: 'button, input, [tabindex]',
|
|
240
247
|
orientation,
|
|
248
|
+
hasRovingTabIndex: true,
|
|
249
|
+
hasCaretGuard: true,
|
|
241
250
|
});
|
|
242
251
|
|
|
252
|
+
const {
|
|
253
|
+
hintElement,
|
|
254
|
+
onKeyDown: onHintKeyDown,
|
|
255
|
+
onFocus: onHintFocus,
|
|
256
|
+
onBlur: onHintBlur,
|
|
257
|
+
} = useKeyboardHint({orientation});
|
|
258
|
+
|
|
259
|
+
const handleToolbarKeyDown = useCallback(
|
|
260
|
+
(e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
261
|
+
onKeyDownProp?.(e);
|
|
262
|
+
if (e.defaultPrevented) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
onHintKeyDown(e);
|
|
266
|
+
handleKeyDown(e);
|
|
267
|
+
},
|
|
268
|
+
[onKeyDownProp, onHintKeyDown, handleKeyDown],
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const handleToolbarFocus = useCallback(
|
|
272
|
+
(e: React.FocusEvent<HTMLDivElement>) => {
|
|
273
|
+
onFocusProp?.(e);
|
|
274
|
+
if (e.defaultPrevented) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
onHintFocus(e);
|
|
278
|
+
handleFocus(e);
|
|
279
|
+
},
|
|
280
|
+
[onFocusProp, onHintFocus, handleFocus],
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
const handleToolbarBlur = useCallback(
|
|
284
|
+
(e: React.FocusEvent<HTMLDivElement>) => {
|
|
285
|
+
onBlurProp?.(e);
|
|
286
|
+
if (e.defaultPrevented) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
onHintBlur(e);
|
|
290
|
+
},
|
|
291
|
+
[onBlurProp, onHintBlur],
|
|
292
|
+
);
|
|
293
|
+
|
|
243
294
|
return (
|
|
244
295
|
<SizeProvider value={size}>
|
|
245
296
|
<Section
|
|
@@ -255,7 +306,9 @@ export function Toolbar({
|
|
|
255
306
|
role="toolbar"
|
|
256
307
|
aria-label={label}
|
|
257
308
|
aria-orientation={orientation}
|
|
258
|
-
onKeyDown={
|
|
309
|
+
onKeyDown={handleToolbarKeyDown}
|
|
310
|
+
onFocus={handleToolbarFocus}
|
|
311
|
+
onBlur={handleToolbarBlur}
|
|
259
312
|
{...mergeProps(
|
|
260
313
|
themeProps('toolbar', {size}),
|
|
261
314
|
stylex.props(
|
|
@@ -320,6 +373,7 @@ export function Toolbar({
|
|
|
320
373
|
)}
|
|
321
374
|
</>
|
|
322
375
|
)}
|
|
376
|
+
{hintElement}
|
|
323
377
|
</div>
|
|
324
378
|
</Section>
|
|
325
379
|
</SizeProvider>
|
|
@@ -55,6 +55,19 @@ describe('Tooltip', () => {
|
|
|
55
55
|
expect(screen.getByRole('button', {name: 'Trigger'})).toBeInTheDocument();
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
+
it('gives the tooltip layer role="tooltip" linked from the trigger', () => {
|
|
59
|
+
render(
|
|
60
|
+
<Tooltip content="Tooltip text">
|
|
61
|
+
<button type="button">Trigger</button>
|
|
62
|
+
</Tooltip>,
|
|
63
|
+
);
|
|
64
|
+
const layer = screen.getByRole('tooltip', {hidden: true});
|
|
65
|
+
expect(layer).toHaveTextContent('Tooltip text');
|
|
66
|
+
// ARIA tooltip pattern: trigger references the layer via aria-describedby.
|
|
67
|
+
const trigger = screen.getByRole('button', {name: 'Trigger'});
|
|
68
|
+
expect(trigger.getAttribute('aria-describedby')).toBe(layer.id);
|
|
69
|
+
});
|
|
70
|
+
|
|
58
71
|
it('calls onOpenChange(true) when shown via hover', async () => {
|
|
59
72
|
const onOpenChange = vi.fn();
|
|
60
73
|
render(
|
|
@@ -140,4 +153,72 @@ describe('Tooltip', () => {
|
|
|
140
153
|
});
|
|
141
154
|
});
|
|
142
155
|
});
|
|
156
|
+
|
|
157
|
+
describe('WCAG 1.4.13 — content on hover or focus', () => {
|
|
158
|
+
it('dismisses on Escape while visible (dismissible)', async () => {
|
|
159
|
+
const onOpenChange = vi.fn();
|
|
160
|
+
render(
|
|
161
|
+
<Tooltip content="Dismiss me" onOpenChange={onOpenChange} delay={0}>
|
|
162
|
+
<button type="button">Trigger</button>
|
|
163
|
+
</Tooltip>,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const trigger = screen.getByRole('button', {name: 'Trigger'});
|
|
167
|
+
fireEvent.mouseEnter(trigger);
|
|
168
|
+
await waitFor(() => {
|
|
169
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
fireEvent.keyDown(document, {key: 'Escape'});
|
|
173
|
+
await waitFor(() => {
|
|
174
|
+
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('ignores Escape during IME composition', async () => {
|
|
179
|
+
const onOpenChange = vi.fn();
|
|
180
|
+
render(
|
|
181
|
+
<Tooltip content="Stay" onOpenChange={onOpenChange} delay={0}>
|
|
182
|
+
<button type="button">Trigger</button>
|
|
183
|
+
</Tooltip>,
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const trigger = screen.getByRole('button', {name: 'Trigger'});
|
|
187
|
+
fireEvent.mouseEnter(trigger);
|
|
188
|
+
await waitFor(() => {
|
|
189
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
190
|
+
});
|
|
191
|
+
onOpenChange.mockClear();
|
|
192
|
+
|
|
193
|
+
fireEvent.keyDown(document, {key: 'Escape', isComposing: true});
|
|
194
|
+
// Give any (incorrect) async hide a chance to run.
|
|
195
|
+
await new Promise(r => setTimeout(r, 20));
|
|
196
|
+
expect(onOpenChange).not.toHaveBeenCalledWith(false);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('stays open when the pointer moves onto the tooltip surface (hoverable)', async () => {
|
|
200
|
+
const onOpenChange = vi.fn();
|
|
201
|
+
render(
|
|
202
|
+
<Tooltip content="Hover me" onOpenChange={onOpenChange} delay={0}>
|
|
203
|
+
<button type="button">Trigger</button>
|
|
204
|
+
</Tooltip>,
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
const trigger = screen.getByRole('button', {name: 'Trigger'});
|
|
208
|
+
fireEvent.mouseEnter(trigger);
|
|
209
|
+
await waitFor(() => {
|
|
210
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
211
|
+
});
|
|
212
|
+
onOpenChange.mockClear();
|
|
213
|
+
|
|
214
|
+
// Pointer leaves the trigger but enters the tooltip surface before the
|
|
215
|
+
// hover-bridge grace period elapses — the tooltip must not hide.
|
|
216
|
+
fireEvent.mouseLeave(trigger);
|
|
217
|
+
const layer = screen.getByRole('tooltip', {hidden: true});
|
|
218
|
+
fireEvent.mouseEnter(layer);
|
|
219
|
+
|
|
220
|
+
await new Promise(r => setTimeout(r, 150));
|
|
221
|
+
expect(onOpenChange).not.toHaveBeenCalledWith(false);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
143
224
|
});
|