@astryxdesign/core 0.4.7 → 0.5.0-canary.055e75f
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 +161 -1
- package/dist/AlertDialog/AlertDialog.d.ts +1 -1
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +45 -20
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +3 -2
- package/dist/AspectRatio/AspectRatio.d.ts +24 -0
- package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
- package/dist/AspectRatio/AspectRatio.js +23 -4
- package/dist/Avatar/Avatar.d.ts +25 -1
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +58 -19
- package/dist/Avatar/index.d.ts +2 -2
- package/dist/Avatar/index.d.ts.map +1 -1
- package/dist/Avatar/index.js +1 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.js +8 -4
- package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
- package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +10 -6
- package/dist/Banner/Banner.d.ts +40 -15
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +51 -18
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +17 -4
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +3 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +11 -10
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +11 -6
- package/dist/ButtonGroup/ButtonGroup.d.ts +5 -1
- package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
- package/dist/ButtonGroup/ButtonGroup.js +26 -7
- package/dist/Calendar/Calendar.d.ts +3 -1
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +14 -15
- package/dist/Calendar/getInitialFocusDate.d.ts +46 -0
- package/dist/Calendar/getInitialFocusDate.d.ts.map +1 -0
- package/dist/Calendar/getInitialFocusDate.js +62 -0
- package/dist/Calendar/styles.d.ts +5 -14
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +15 -15
- package/dist/Card/Card.d.ts +6 -9
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +6 -6
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +3 -3
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +2 -3
- package/dist/Chat/ChatLayout.d.ts.map +1 -1
- package/dist/Chat/ChatLayout.js +3 -3
- package/dist/Chat/ChatMessageList.d.ts +22 -3
- package/dist/Chat/ChatMessageList.d.ts.map +1 -1
- package/dist/Chat/ChatMessageList.js +6 -3
- package/dist/Chat/ChatTokenizedText.d.ts +2 -0
- package/dist/Chat/ChatTokenizedText.d.ts.map +1 -1
- package/dist/Chat/ChatTokenizedText.js +11 -6
- package/dist/Chat/useChatComposerTokens.js +1 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +10 -3
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +3 -3
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +15 -4
- package/dist/CodeBlock/highlightRanges.js +1 -1
- package/dist/CodeBlock/highlightStyles.js +13 -13
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +3 -2
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +3 -2
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +4 -3
- package/dist/DateInput/DateInput.d.ts +43 -0
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +22 -2
- package/dist/DateInput/NativeDateField.d.ts +10 -0
- package/dist/DateInput/NativeDateField.d.ts.map +1 -0
- package/dist/DateInput/NativeDateField.js +494 -0
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +82 -23
- package/dist/DateInput/index.d.ts +1 -1
- package/dist/DateInput/index.d.ts.map +1 -1
- package/dist/DateInput/nativeDateSegments.d.ts +22 -0
- package/dist/DateInput/nativeDateSegments.d.ts.map +1 -0
- package/dist/DateInput/nativeDateSegments.js +111 -0
- package/dist/DateTimeInput/DateTimeInput.d.ts +21 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +406 -12
- package/dist/DateTimeInput/index.d.ts +1 -1
- package/dist/DateTimeInput/index.d.ts.map +1 -1
- package/dist/Dialog/Dialog.d.ts +21 -1
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +110 -58
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +6 -5
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +9 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +3 -2
- package/dist/Heading/Heading.d.ts.map +1 -1
- package/dist/Heading/Heading.js +6 -2
- package/dist/HoverCard/HoverCard.d.ts +6 -0
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +104 -3
- package/dist/HoverCard/useHoverCard.d.ts +19 -2
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +74 -26
- package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
- package/dist/Indicator/CheckboxIndicator.js +6 -2
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +4 -2
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +2 -19
- package/dist/Layer/LayerDepthContext.d.ts +52 -0
- package/dist/Layer/LayerDepthContext.d.ts.map +1 -0
- package/dist/Layer/LayerDepthContext.js +66 -0
- package/dist/Layer/index.d.ts +3 -0
- package/dist/Layer/index.d.ts.map +1 -1
- package/dist/Layer/index.js +4 -0
- package/dist/Layer/layerStack.d.ts +98 -0
- package/dist/Layer/layerStack.d.ts.map +1 -0
- package/dist/Layer/layerStack.js +306 -0
- package/dist/Layer/useLayerDismissal.d.ts +93 -0
- package/dist/Layer/useLayerDismissal.d.ts.map +1 -0
- package/dist/Layer/useLayerDismissal.js +91 -0
- package/dist/Lightbox/Lightbox.d.ts +1 -0
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +103 -81
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +9 -4
- package/dist/Markdown/index.d.ts +1 -1
- package/dist/Markdown/index.d.ts.map +1 -1
- package/dist/Markdown/parser.d.ts +38 -1
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +182 -32
- package/dist/MobileNav/MobileNav.d.ts +6 -1
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +61 -36
- package/dist/MultiSelector/MultiSelector.d.ts +32 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +63 -11
- package/dist/MultiSelector/index.d.ts +1 -1
- package/dist/MultiSelector/index.d.ts.map +1 -1
- package/dist/NavIcon/NavIcon.d.ts.map +1 -1
- package/dist/NavIcon/NavIcon.js +5 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +3 -2
- package/dist/NumberInput/NumberInput.d.ts +6 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +54 -104
- package/dist/NumberInput/numberInputCommit.d.ts +34 -0
- package/dist/NumberInput/numberInputCommit.d.ts.map +1 -0
- package/dist/NumberInput/numberInputCommit.js +71 -0
- package/dist/NumberInput/numberParser.d.ts +64 -0
- package/dist/NumberInput/numberParser.d.ts.map +1 -0
- package/dist/NumberInput/numberParser.js +350 -0
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +3 -2
- package/dist/OverflowList/OverflowList.d.ts.map +1 -1
- package/dist/OverflowList/OverflowList.js +3 -2
- package/dist/Overlay/Overlay.d.ts.map +1 -1
- package/dist/Overlay/Overlay.js +3 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +20 -17
- package/dist/PowerSearch/PowerSearch.d.ts +8 -2
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +19 -6
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts +3 -1
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +28 -6
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts +3 -1
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +110 -27
- package/dist/PowerSearch/types.d.ts +2 -0
- package/dist/PowerSearch/types.d.ts.map +1 -1
- package/dist/PowerSearch/usePowerSearchSource.d.ts +6 -1
- package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
- package/dist/PowerSearch/usePowerSearchSource.js +14 -5
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +18 -5
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +3 -2
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControl.js +3 -2
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +3 -3
- package/dist/Selector/Selector.d.ts +17 -0
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +81 -14
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +4 -3
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +8 -7
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +4 -3
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +37 -5
- package/dist/Spinner/Spinner.d.ts +3 -3
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +130 -78
- package/dist/StatusDot/StatusDot.d.ts.map +1 -1
- package/dist/StatusDot/StatusDot.js +6 -1
- package/dist/Stepper/Step.d.ts +140 -0
- package/dist/Stepper/Step.d.ts.map +1 -0
- package/dist/Stepper/Step.js +1045 -0
- package/dist/Stepper/StepStatus.d.ts +24 -0
- package/dist/Stepper/StepStatus.d.ts.map +1 -0
- package/dist/Stepper/StepStatus.js +1 -0
- package/dist/Stepper/Stepper.d.ts +93 -0
- package/dist/Stepper/Stepper.d.ts.map +1 -0
- package/dist/Stepper/Stepper.js +184 -0
- package/dist/Stepper/StepperContext.d.ts +41 -0
- package/dist/Stepper/StepperContext.d.ts.map +1 -0
- package/dist/Stepper/StepperContext.js +34 -0
- package/dist/Stepper/index.d.ts +8 -0
- package/dist/Stepper/index.d.ts.map +1 -0
- package/dist/Stepper/index.js +7 -0
- package/dist/Stepper/stepper.stylex.d.ts +15 -0
- package/dist/Stepper/stepper.stylex.d.ts.map +1 -0
- package/dist/Stepper/stepper.stylex.js +20 -0
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +8 -3
- package/dist/TabList/Tab.d.ts +15 -2
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +32 -7
- package/dist/TabList/TabList.d.ts +46 -7
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +353 -23
- package/dist/TabList/TabListContext.d.ts +11 -1
- package/dist/TabList/TabListContext.d.ts.map +1 -1
- package/dist/TabList/TabListContext.js +11 -2
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +3 -2
- package/dist/TabList/index.d.ts +2 -2
- package/dist/TabList/index.d.ts.map +1 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +10 -2
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +3 -6
- package/dist/Table/TableRow.d.ts +16 -5
- package/dist/Table/TableRow.d.ts.map +1 -1
- package/dist/Table/TableRow.js +16 -5
- package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
- package/dist/Table/plugins/filtering/useTableFiltering.js +73 -4
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +20 -8
- package/dist/Table/plugins/pagination/useTablePagination.d.ts +3 -0
- package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/useTablePagination.js +21 -4
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +7 -2
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -1
- package/dist/Table/plugins/rowStatus/useTableRowStatus.js +10 -3
- package/dist/Table/plugins/selection/useTableSelection.d.ts +16 -0
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +19 -5
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
- package/dist/Table/types.d.ts +22 -4
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +5 -0
- package/dist/Text/Text.d.ts.map +1 -1
- package/dist/Text/Text.js +6 -2
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +9 -3
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +3 -2
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +3 -2
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +5 -3
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +27 -8
- package/dist/Token/TokenLink.d.ts.map +1 -1
- package/dist/Token/TokenLink.js +2 -2
- package/dist/Tokenizer/Tokenizer.d.ts +3 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +2 -0
- package/dist/Tooltip/Tooltip.d.ts +5 -0
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.d.ts +5 -0
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +39 -24
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +5 -4
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +3 -3
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +4 -3
- package/dist/Typeahead/BaseTypeahead.d.ts +2 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +68 -29
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +3 -2
- package/dist/astryx.css +98 -7
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useFocusTrap.d.ts +7 -4
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +60 -95
- package/dist/hooks/useHotkeys.d.ts.map +1 -1
- package/dist/hooks/useHotkeys.js +3 -18
- package/dist/hooks/useMergedRefs.d.ts +18 -0
- package/dist/hooks/useMergedRefs.d.ts.map +1 -0
- package/dist/hooks/useMergedRefs.js +25 -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/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +24 -4
- package/dist/theme/syntax/tokens.d.ts +1 -1
- package/dist/theme/syntax/tokens.d.ts.map +1 -1
- package/dist/theme/syntax/tokens.js +5 -2
- package/dist/utils/groupItems.d.ts +5 -1
- package/dist/utils/groupItems.d.ts.map +1 -1
- package/dist/utils/groupItems.js +9 -9
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/isApplePlatform.d.ts +18 -0
- package/dist/utils/isApplePlatform.d.ts.map +1 -0
- package/dist/utils/isApplePlatform.js +37 -0
- package/dist/utils/sharedResizeObserver.d.ts.map +1 -1
- package/dist/utils/sharedResizeObserver.js +10 -1
- package/dist/utils/timeParser.d.ts +1 -1
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +26 -12
- package/locales/en.json +154 -10
- package/locales/pseudo.json +108 -0
- package/package.json +8 -3
- package/src/AlertDialog/AlertDialog.doc.mjs +114 -30
- package/src/AlertDialog/AlertDialog.test.tsx +211 -2
- package/src/AlertDialog/AlertDialog.tsx +62 -20
- package/src/AppShell/AppShell.tsx +3 -2
- package/src/AspectRatio/AspectRatio.doc.mjs +6 -3
- package/src/AspectRatio/AspectRatio.test.tsx +57 -10
- package/src/AspectRatio/AspectRatio.tsx +40 -1
- package/src/Avatar/Avatar.doc.mjs +14 -3
- package/src/Avatar/Avatar.test.tsx +97 -0
- package/src/Avatar/Avatar.tsx +125 -52
- package/src/Avatar/index.ts +2 -2
- package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
- package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
- package/src/AvatarGroup/AvatarGroup.tsx +15 -6
- package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +10 -4
- package/src/Banner/Banner.doc.mjs +13 -11
- package/src/Banner/Banner.test.tsx +102 -15
- package/src/Banner/Banner.tsx +72 -25
- package/src/BottomSheet/BottomSheet.test.tsx +123 -0
- package/src/BottomSheet/BottomSheet.tsx +17 -4
- package/src/BottomSheet/BottomSheetSwitcher.tsx +3 -2
- package/src/Breadcrumbs/BreadcrumbItem.tsx +9 -5
- package/src/Button/Button.doc.mjs +24 -1
- package/src/Button/Button.test.tsx +32 -4
- package/src/Button/Button.tsx +12 -5
- package/src/ButtonGroup/ButtonGroup.doc.mjs +10 -1
- package/src/ButtonGroup/ButtonGroup.test.tsx +404 -1
- package/src/ButtonGroup/ButtonGroup.tsx +23 -5
- package/src/Calendar/Calendar.doc.mjs +4 -3
- package/src/Calendar/Calendar.test.tsx +103 -0
- package/src/Calendar/Calendar.tsx +19 -16
- package/src/Calendar/getInitialFocusDate.test.ts +94 -0
- package/src/Calendar/getInitialFocusDate.ts +93 -0
- package/src/Calendar/styles.ts +49 -31
- package/src/Card/Card.doc.mjs +10 -7
- package/src/Card/Card.test.tsx +44 -19
- package/src/Card/Card.tsx +12 -32
- package/src/Carousel/Carousel.tsx +3 -2
- package/src/Chat/ChatComposerInput.tsx +5 -1
- package/src/Chat/ChatLayout.tsx +3 -2
- package/src/Chat/ChatMessageList.doc.mjs +9 -1
- package/src/Chat/ChatMessageList.test.tsx +46 -0
- package/src/Chat/ChatMessageList.tsx +28 -4
- package/src/Chat/ChatTokenizedText.tsx +17 -10
- package/src/Chat/useChatComposerTokens.ts +1 -1
- package/src/CheckboxInput/CheckboxInput.doc.mjs +2 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
- package/src/CheckboxInput/CheckboxInput.tsx +8 -2
- package/src/ClickableCard/ClickableCard.tsx +3 -2
- package/src/CodeBlock/CodeBlock.doc.mjs +16 -4
- package/src/CodeBlock/CodeBlock.test.tsx +37 -0
- package/src/CodeBlock/CodeBlock.tsx +20 -4
- package/src/CodeBlock/highlightRanges.ts +1 -1
- package/src/CodeBlock/highlightStyles.ts +13 -13
- package/src/CommandPalette/CommandPaletteInput.tsx +3 -2
- package/src/CommandPalette/CommandPaletteItem.tsx +3 -2
- package/src/ContextMenu/ContextMenu.doc.mjs +5 -0
- package/src/ContextMenu/ContextMenu.tsx +4 -3
- package/src/DateInput/DateInput.doc.mjs +16 -0
- package/src/DateInput/DateInput.tsx +55 -2
- package/src/DateInput/DateInputTouch.test.tsx +146 -32
- package/src/DateInput/NativeDateField.test.tsx +635 -0
- package/src/DateInput/NativeDateField.tsx +641 -0
- package/src/DateInput/TouchDateField.tsx +108 -24
- package/src/DateInput/index.ts +1 -0
- package/src/DateInput/nativeDateSegments.ts +127 -0
- package/src/DateTimeInput/DateTimeInput.doc.mjs +18 -0
- package/src/DateTimeInput/DateTimeInput.test.tsx +1088 -0
- package/src/DateTimeInput/DateTimeInput.tsx +556 -24
- package/src/DateTimeInput/index.ts +1 -0
- package/src/Dialog/Dialog.doc.mjs +8 -3
- package/src/Dialog/Dialog.test.tsx +429 -2
- package/src/Dialog/Dialog.tsx +133 -58
- package/src/DropdownMenu/DropdownMenu.doc.mjs +6 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +8 -5
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +8 -11
- package/src/Field/Field.doc.mjs +13 -2
- package/src/Field/FieldLabel.test.tsx +29 -0
- package/src/Field/FieldLabel.tsx +7 -0
- package/src/FileInput/FileInput.tsx +3 -2
- package/src/Heading/Heading.test.tsx +23 -1
- package/src/Heading/Heading.tsx +6 -2
- package/src/HoverCard/HoverCard.doc.mjs +13 -2
- package/src/HoverCard/HoverCard.test.tsx +154 -4
- package/src/HoverCard/HoverCard.tsx +143 -3
- package/src/HoverCard/useHoverCard.tsx +104 -33
- package/src/Indicator/CheckboxIndicator.tsx +14 -8
- package/src/Indicator/Indicator.doc.mjs +2 -0
- package/src/Item/Item.tsx +5 -4
- package/src/Kbd/Kbd.tsx +2 -19
- package/src/Layer/LayerDepthContext.tsx +62 -0
- package/src/Layer/index.ts +9 -0
- package/src/Layer/layerDismissalFamilies.test.tsx +359 -0
- package/src/Layer/layerDismissalInvariants.test.tsx +417 -0
- package/src/Layer/layerStack.ts +362 -0
- package/src/Layer/useLayer.test.tsx +62 -14
- package/src/Layer/useLayerDismissal.test.tsx +469 -0
- package/src/Layer/useLayerDismissal.ts +173 -0
- package/src/Layout/Layout.doc.mjs +2 -2
- package/src/Lightbox/Lightbox.doc.mjs +12 -0
- package/src/Lightbox/Lightbox.tsx +124 -102
- package/src/Link/Link.doc.mjs +39 -0
- package/src/Markdown/Markdown.doc.mjs +5 -0
- package/src/Markdown/Markdown.tsx +9 -4
- package/src/Markdown/incremental.test.ts +16 -2
- package/src/Markdown/index.ts +1 -0
- package/src/Markdown/parser.perf.test.ts +96 -1
- package/src/Markdown/parser.test.ts +178 -2
- package/src/Markdown/parser.ts +253 -32
- package/src/MobileNav/MobileNav.tsx +62 -36
- package/src/MoreMenu/MoreMenu.doc.mjs +7 -1
- package/src/MultiSelector/MultiSelector.doc.mjs +49 -1
- package/src/MultiSelector/MultiSelector.test.tsx +277 -0
- package/src/MultiSelector/MultiSelector.tsx +142 -11
- package/src/MultiSelector/index.ts +1 -0
- package/src/NavIcon/NavIcon.doc.mjs +8 -2
- package/src/NavIcon/NavIcon.test.tsx +9 -0
- package/src/NavIcon/NavIcon.tsx +5 -1
- package/src/NavMenu/NavHeadingMenu.tsx +3 -2
- package/src/NumberInput/NumberInput.doc.mjs +31 -7
- package/src/NumberInput/NumberInput.test.tsx +436 -8
- package/src/NumberInput/NumberInput.tsx +62 -114
- package/src/NumberInput/numberInputCommit.test.ts +72 -0
- package/src/NumberInput/numberInputCommit.ts +103 -0
- package/src/NumberInput/numberParser.docblock.test.ts +234 -0
- package/src/NumberInput/numberParser.test.ts +222 -0
- package/src/NumberInput/numberParser.ts +403 -0
- package/src/Outline/Outline.tsx +3 -2
- package/src/OverflowList/OverflowList.tsx +3 -2
- package/src/Overlay/Overlay.tsx +3 -2
- package/src/Pagination/Pagination.test.tsx +3 -2
- package/src/Popover/usePopover.tsx +31 -28
- package/src/PowerSearch/PowerSearch.doc.mjs +160 -28
- package/src/PowerSearch/PowerSearch.test.tsx +240 -1
- package/src/PowerSearch/PowerSearch.tsx +34 -5
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +288 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +29 -2
- package/src/PowerSearch/PowerSearchValueEditor.test.tsx +111 -1
- package/src/PowerSearch/PowerSearchValueEditor.tsx +124 -10
- package/src/PowerSearch/types.ts +2 -0
- package/src/PowerSearch/usePowerSearchSource.test.ts +82 -2
- package/src/PowerSearch/usePowerSearchSource.ts +13 -3
- package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
- package/src/ProgressBar/ProgressBar.test.tsx +24 -0
- package/src/ProgressBar/ProgressBar.tsx +28 -8
- package/src/Resizable/ResizeHandle.tsx +3 -2
- package/src/SegmentedControl/SegmentedControl.tsx +3 -2
- package/src/SelectableCard/SelectableCard.tsx +3 -2
- package/src/Selector/Selector.doc.mjs +26 -1
- package/src/Selector/Selector.test.tsx +311 -1
- package/src/Selector/Selector.tsx +139 -16
- package/src/SideNav/SideNav.doc.mjs +6 -6
- package/src/SideNav/SideNav.tsx +4 -2
- package/src/SideNav/SideNavHeading.tsx +12 -12
- package/src/SideNav/SideNavItem.tsx +4 -2
- package/src/Slider/Slider.test.tsx +106 -1
- package/src/Slider/Slider.tsx +55 -3
- package/src/Spinner/Spinner.test.tsx +147 -1
- package/src/Spinner/Spinner.tsx +120 -101
- package/src/StatusDot/StatusDot.doc.mjs +8 -2
- package/src/StatusDot/StatusDot.test.tsx +9 -0
- package/src/StatusDot/StatusDot.tsx +7 -1
- package/src/Stepper/Step.doc.mjs +98 -0
- package/src/Stepper/Step.tsx +1638 -0
- package/src/Stepper/StepStatus.ts +26 -0
- package/src/Stepper/Stepper.doc.mjs +370 -0
- package/src/Stepper/Stepper.test.tsx +1024 -0
- package/src/Stepper/Stepper.tsx +258 -0
- package/src/Stepper/StepperContext.ts +71 -0
- package/src/Stepper/index.ts +18 -0
- package/src/Stepper/stepper.stylex.ts +19 -0
- package/src/Switch/Switch.doc.mjs +2 -0
- package/src/Switch/Switch.test.tsx +10 -0
- package/src/Switch/Switch.tsx +6 -2
- package/src/TabList/Tab.doc.mjs +13 -1
- package/src/TabList/Tab.tsx +67 -7
- package/src/TabList/TabList.doc.mjs +22 -6
- package/src/TabList/TabList.test.tsx +559 -0
- package/src/TabList/TabList.tsx +490 -22
- package/src/TabList/TabListContext.ts +13 -2
- package/src/TabList/TabMenu.tsx +3 -2
- package/src/TabList/index.ts +6 -2
- package/src/Table/BaseTable.tsx +12 -4
- package/src/Table/Table.doc.mjs +9 -2
- package/src/Table/Table.test.tsx +132 -14
- package/src/Table/Table.tsx +3 -8
- package/src/Table/TableBody.doc.mjs +40 -0
- package/src/Table/TableFooter.doc.mjs +40 -0
- package/src/Table/TableHeader.doc.mjs +40 -0
- package/src/Table/TableRow.tsx +16 -5
- package/src/Table/plugins/filtering/useTableFiltering.test.tsx +44 -6
- package/src/Table/plugins/filtering/useTableFiltering.tsx +100 -4
- package/src/Table/plugins/groupedRows/useTableGroupedRows-perf.test.tsx +112 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +100 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +17 -8
- package/src/Table/plugins/pagination/useTablePagination.test.tsx +34 -4
- package/src/Table/plugins/pagination/useTablePagination.tsx +35 -3
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +9 -2
- package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +13 -7
- package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +12 -3
- package/src/Table/plugins/selection/useTableSelection.test.tsx +76 -0
- package/src/Table/plugins/selection/useTableSelection.tsx +40 -7
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
- package/src/Table/types.ts +22 -4
- package/src/Table/useBaseTablePlugins.ts +5 -0
- package/src/Table/useTableGroupedRows.doc.mjs +5 -4
- package/src/Table/useTablePagination.doc.mjs +7 -0
- package/src/Table/useTableRowStatus.doc.mjs +1 -1
- package/src/Table/useTableSelection.doc.mjs +31 -0
- package/src/Text/Text.test.tsx +23 -1
- package/src/Text/Text.tsx +6 -2
- package/src/TextArea/TextArea.doc.mjs +8 -2
- package/src/TextArea/TextArea.test.tsx +11 -0
- package/src/TextArea/TextArea.tsx +15 -8
- package/src/TextInput/TextInput.doc.mjs +10 -0
- package/src/TextInput/TextInput.tsx +3 -2
- package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
- package/src/TimeInput/TimeInput.tsx +2 -2
- package/src/Timestamp/Timestamp.test.tsx +18 -0
- package/src/Timestamp/Timestamp.tsx +4 -2
- package/src/Toast/Toast.doc.mjs +6 -0
- package/src/Toast/ToastViewport.tsx +17 -1
- package/src/Token/TokenLink.tsx +2 -2
- package/src/Tokenizer/Tokenizer.doc.mjs +27 -0
- package/src/Tokenizer/Tokenizer.tsx +4 -0
- package/src/Toolbar/Toolbar.doc.mjs +5 -0
- package/src/Tooltip/Tooltip.doc.mjs +5 -0
- package/src/Tooltip/Tooltip.test.tsx +32 -0
- package/src/Tooltip/Tooltip.tsx +5 -0
- package/src/Tooltip/useTooltip.tsx +47 -24
- package/src/TopNav/TopNavHeading.tsx +5 -4
- package/src/TopNav/TopNavMegaMenu.tsx +3 -2
- package/src/TopNav/TopNavMenu.tsx +4 -3
- package/src/Typeahead/BaseTypeahead.doc.mjs +11 -0
- package/src/Typeahead/BaseTypeahead.tsx +85 -33
- package/src/Typeahead/Typeahead.doc.mjs +5 -0
- package/src/Typeahead/Typeahead.test.tsx +49 -0
- package/src/Typeahead/Typeahead.tsx +3 -2
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useContainerReveal.doc.mjs +2 -2
- package/src/hooks/useFocusTrap.test.tsx +14 -0
- package/src/hooks/useFocusTrap.ts +62 -111
- package/src/hooks/useFocusTrapEscapeShim.test.tsx +165 -0
- package/src/hooks/useHotkeys.ts +3 -18
- package/src/hooks/useMergedRefs.doc.mjs +79 -0
- package/src/hooks/useMergedRefs.test.tsx +62 -0
- package/src/hooks/useMergedRefs.ts +36 -0
- package/src/index.ts +1 -0
- package/src/raw-import.d.ts +14 -0
- package/src/theme/MediaTheme.doc.mjs +5 -5
- package/src/theme/derivedVarRegistry.test.ts +19 -3
- package/src/theme/derivedVarRegistry.ts +23 -4
- package/src/theme/generateThemeRules.test.ts +37 -0
- package/src/theme/syntax/tokens.ts +5 -2
- package/src/utils/groupItems.ts +12 -6
- package/src/utils/index.ts +1 -1
- package/src/utils/isApplePlatform.test.ts +61 -0
- package/src/utils/isApplePlatform.ts +37 -0
- package/src/utils/sharedResizeObserver.ts +10 -2
- package/src/utils/timeParser.test.ts +6 -1
- package/src/utils/timeParser.ts +35 -13
- package/src/__tests__/inputWidthContract.test.tsx +0 -69
|
@@ -648,6 +648,25 @@ interface SelectorPropsBase<
|
|
|
648
648
|
*/
|
|
649
649
|
searchPlaceholder?: string;
|
|
650
650
|
|
|
651
|
+
/**
|
|
652
|
+
* Content shown in the panel when there are no options to show, and
|
|
653
|
+
* announced in a polite live region when the panel opens. Not shown while
|
|
654
|
+
* `isLoading` — the options have not arrived yet.
|
|
655
|
+
* @default 'No options'
|
|
656
|
+
*/
|
|
657
|
+
emptyText?: ReactNode;
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Content shown in the panel when a search query matches no options, and
|
|
661
|
+
* announced in a polite live region at the same time.
|
|
662
|
+
*
|
|
663
|
+
* The panel message is `role="presentation"`, so the live region is the only
|
|
664
|
+
* route to assistive tech: a string is announced verbatim, a richer node
|
|
665
|
+
* falls back to the default text since it cannot be spoken.
|
|
666
|
+
* @default 'No results found'
|
|
667
|
+
*/
|
|
668
|
+
emptySearchText?: ReactNode;
|
|
669
|
+
|
|
651
670
|
/**
|
|
652
671
|
* Position placement relative to the trigger.
|
|
653
672
|
*
|
|
@@ -794,6 +813,8 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
794
813
|
indicatorPosition = 'end',
|
|
795
814
|
hasSearch = false,
|
|
796
815
|
searchPlaceholder: searchPlaceholderFromProps,
|
|
816
|
+
emptyText: emptyTextFromProps,
|
|
817
|
+
emptySearchText: emptySearchTextFromProps,
|
|
797
818
|
placement,
|
|
798
819
|
isDefaultOpen = false,
|
|
799
820
|
'data-testid': testId,
|
|
@@ -802,12 +823,16 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
802
823
|
className,
|
|
803
824
|
style,
|
|
804
825
|
hasClear: hasClearProp,
|
|
826
|
+
id,
|
|
805
827
|
...rest
|
|
806
828
|
} = props as SelectorPropsClearable<T>;
|
|
807
829
|
const isEffectivelyRequired = useResolvedRequired({isRequired, isOptional});
|
|
808
830
|
const placeholder = placeholderFromProps ?? t('@astryx.selector.placeholder');
|
|
809
831
|
const searchPlaceholder =
|
|
810
832
|
searchPlaceholderFromProps ?? t('@astryx.selector.searchPlaceholder');
|
|
833
|
+
const emptyText = emptyTextFromProps ?? t('@astryx.selector.empty');
|
|
834
|
+
const emptySearchText =
|
|
835
|
+
emptySearchTextFromProps ?? t('@astryx.selector.emptySearchResults');
|
|
811
836
|
const hasClear = hasClearProp === true;
|
|
812
837
|
const size = useSize(sizeProp, 'md');
|
|
813
838
|
const effectiveStatusVariant =
|
|
@@ -817,7 +842,10 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
817
842
|
|
|
818
843
|
// Normalize null to undefined for internal use (null is the clear sentinel)
|
|
819
844
|
const normalizedValue = value === null ? undefined : value;
|
|
820
|
-
const
|
|
845
|
+
const generatedTriggerId = useId();
|
|
846
|
+
// A caller's `id` lands on the trigger either way, so the internal identity
|
|
847
|
+
// has to be that same value or the label and listbox point at nothing.
|
|
848
|
+
const triggerId = id ?? generatedTriggerId;
|
|
821
849
|
const listboxId = useId();
|
|
822
850
|
const descriptionId = useId();
|
|
823
851
|
const statusMessageId = useId();
|
|
@@ -831,6 +859,9 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
831
859
|
const inputGroup = useInputGroup();
|
|
832
860
|
|
|
833
861
|
const [searchQuery, setSearchQuery] = useState('');
|
|
862
|
+
// Mirrors searchQuery for the seed path, which runs before focus reaches the
|
|
863
|
+
// input and so cannot read the rendered state.
|
|
864
|
+
const searchQueryRef = useRef('');
|
|
834
865
|
// A typed query shows the search row's clear (✕) button, which becomes
|
|
835
866
|
// the next tab stop after the search input.
|
|
836
867
|
const hasQuery = searchQuery.length > 0;
|
|
@@ -840,6 +871,17 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
840
871
|
const isBusy = isLoading || optimisticValue !== normalizedValue;
|
|
841
872
|
const announce = useAnnounce();
|
|
842
873
|
|
|
874
|
+
// The panel's empty message is role="presentation" and reaches assistive tech
|
|
875
|
+
// only through this live region, so the region has to speak whatever the
|
|
876
|
+
// panel shows. A ReactNode override cannot be spoken; fall back to the
|
|
877
|
+
// catalog copy for that case rather than announcing nothing.
|
|
878
|
+
const emptyAnnouncement =
|
|
879
|
+
typeof emptyText === 'string' ? emptyText : t('@astryx.selector.empty');
|
|
880
|
+
const emptySearchAnnouncement =
|
|
881
|
+
typeof emptySearchText === 'string'
|
|
882
|
+
? emptySearchText
|
|
883
|
+
: t('@astryx.selector.emptySearchResults');
|
|
884
|
+
|
|
843
885
|
// Disabled-reason tooltip. Disabled controls swallow pointer events, so the
|
|
844
886
|
// tooltip listeners attach to the trigger container (which already exists)
|
|
845
887
|
// and the trigger button stays perceivable via aria-disabled instead of the
|
|
@@ -907,6 +949,7 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
907
949
|
// Layer for dropdown positioning
|
|
908
950
|
const handleLayerHide = useCallback(() => {
|
|
909
951
|
setSearchQuery('');
|
|
952
|
+
searchQueryRef.current = '';
|
|
910
953
|
resetTypeaheadRef.current();
|
|
911
954
|
// Clear any lingering result count when the popover closes so stale status
|
|
912
955
|
// text does not linger in the a11y tree.
|
|
@@ -935,28 +978,76 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
935
978
|
// eslint-disable-next-line @eslint-react/exhaustive-deps -- mount-only: isDefaultOpen is not reactive
|
|
936
979
|
}, []);
|
|
937
980
|
|
|
938
|
-
// Announce the filtered result count from the query-change
|
|
981
|
+
// Announce the filtered result count from the query-change handlers (matching
|
|
939
982
|
// BaseTypeahead) rather than a reactive effect: computing the count for the
|
|
940
983
|
// next query here fires the announcement exactly once per keystroke and does
|
|
941
|
-
// not re-speak on unrelated re-renders.
|
|
942
|
-
|
|
984
|
+
// not re-speak on unrelated re-renders. Split out from handleSearchChange so
|
|
985
|
+
// the type-to-open seed below reaches the same live region — a query the user
|
|
986
|
+
// typed is a query however it arrived.
|
|
987
|
+
const announceSearchResults = useCallback(
|
|
943
988
|
(nextQuery: string) => {
|
|
944
|
-
setSearchQuery(nextQuery);
|
|
945
989
|
if (nextQuery.length === 0) {
|
|
946
990
|
// Emptying the query clears the region rather than announcing a count.
|
|
947
991
|
announce('');
|
|
948
992
|
return;
|
|
949
993
|
}
|
|
994
|
+
// While isLoading the panel deliberately shows nothing, so announcing a
|
|
995
|
+
// result would put a claim in the one channel the screen has gone quiet
|
|
996
|
+
// for.
|
|
997
|
+
if (isLoading) {
|
|
998
|
+
announce('');
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
950
1001
|
const count = filterOptionsByQuery(selectableItems, nextQuery).length;
|
|
951
1002
|
announce(
|
|
952
1003
|
count === 0
|
|
953
|
-
?
|
|
1004
|
+
? emptySearchAnnouncement
|
|
954
1005
|
: t('@astryx.selector.resultCount', {count}),
|
|
955
1006
|
);
|
|
956
1007
|
},
|
|
957
|
-
[announce, selectableItems, t],
|
|
1008
|
+
[announce, isLoading, selectableItems, emptySearchAnnouncement, t],
|
|
1009
|
+
);
|
|
1010
|
+
|
|
1011
|
+
const handleSearchChange = useCallback(
|
|
1012
|
+
(nextQuery: string) => {
|
|
1013
|
+
setSearchQuery(nextQuery);
|
|
1014
|
+
searchQueryRef.current = nextQuery;
|
|
1015
|
+
announceSearchResults(nextQuery);
|
|
1016
|
+
},
|
|
1017
|
+
[announceSearchResults],
|
|
958
1018
|
);
|
|
959
1019
|
|
|
1020
|
+
// The panel's empty message is role="presentation", so this region is the
|
|
1021
|
+
// only route to assistive tech. It has to watch the STATE rather than the
|
|
1022
|
+
// open event: the panel can become empty either on open or when a fetch
|
|
1023
|
+
// lands with nothing in it, and an open-only announcement leaves the second
|
|
1024
|
+
// case silent while the message sits on screen. The ref makes it fire once
|
|
1025
|
+
// per arrival at that state rather than on every re-render.
|
|
1026
|
+
const announcedEmptyRef = useRef<string | null>(null);
|
|
1027
|
+
useEffect(() => {
|
|
1028
|
+
const isPanelEmpty =
|
|
1029
|
+
popover.isOpen &&
|
|
1030
|
+
!isLoading &&
|
|
1031
|
+
searchQuery === '' &&
|
|
1032
|
+
selectableItems.length === 0;
|
|
1033
|
+
if (!isPanelEmpty) {
|
|
1034
|
+
announcedEmptyRef.current = null;
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
if (announcedEmptyRef.current === emptyAnnouncement) {
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
announcedEmptyRef.current = emptyAnnouncement;
|
|
1041
|
+
announce(emptyAnnouncement);
|
|
1042
|
+
}, [
|
|
1043
|
+
popover.isOpen,
|
|
1044
|
+
isLoading,
|
|
1045
|
+
searchQuery,
|
|
1046
|
+
selectableItems.length,
|
|
1047
|
+
emptyAnnouncement,
|
|
1048
|
+
announce,
|
|
1049
|
+
]);
|
|
1050
|
+
|
|
960
1051
|
// Calculate offset to position selected item over trigger. Explicit
|
|
961
1052
|
// placement opts out of the selector-specific overlay behavior and uses the
|
|
962
1053
|
// standard layer positioning API instead.
|
|
@@ -992,10 +1083,20 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
992
1083
|
}, [onChange, changeAction, startTransition, setOptimisticValue]);
|
|
993
1084
|
|
|
994
1085
|
// Type-to-find appends to the query rather than replacing it: characters
|
|
995
|
-
// typed before focus reaches the search input must not be dropped.
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1086
|
+
// typed before focus reaches the search input must not be dropped. The ref
|
|
1087
|
+
// is what makes that safe without a state updater — it advances
|
|
1088
|
+
// synchronously, so a second character seeded in the same tick still sees
|
|
1089
|
+
// the first, and the announcement can be computed here rather than inside a
|
|
1090
|
+
// setState callback.
|
|
1091
|
+
const appendSearchQuery = useCallback(
|
|
1092
|
+
(char: string) => {
|
|
1093
|
+
const nextQuery = searchQueryRef.current + char;
|
|
1094
|
+
searchQueryRef.current = nextQuery;
|
|
1095
|
+
setSearchQuery(nextQuery);
|
|
1096
|
+
announceSearchResults(nextQuery);
|
|
1097
|
+
},
|
|
1098
|
+
[announceSearchResults],
|
|
1099
|
+
);
|
|
999
1100
|
|
|
1000
1101
|
const commitValue = useCallback(
|
|
1001
1102
|
(newValue: string) => {
|
|
@@ -1313,8 +1414,11 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1313
1414
|
const renderOptions = useCallback(() => {
|
|
1314
1415
|
const isSearching = hasSearch && Boolean(searchQuery);
|
|
1315
1416
|
|
|
1316
|
-
// Nothing
|
|
1317
|
-
|
|
1417
|
+
// Nothing to show — either the query matched nothing, or no options were
|
|
1418
|
+
// given at all. Both render the same slot with different copy. While
|
|
1419
|
+
// isLoading the options have not arrived yet, so asserting either would be
|
|
1420
|
+
// a claim the component cannot make; the trigger's spinner covers it.
|
|
1421
|
+
if (filteredItems.length === 0 && !isLoading) {
|
|
1318
1422
|
// role="presentation" keeps the message out of the listbox's
|
|
1319
1423
|
// accessibility tree (role="listbox" only permits option/group
|
|
1320
1424
|
// children); the no-results outcome is announced via the
|
|
@@ -1327,7 +1431,7 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1327
1431
|
themeProps('selector-empty-state'),
|
|
1328
1432
|
stylex.props(styles.emptyState),
|
|
1329
1433
|
)}>
|
|
1330
|
-
|
|
1434
|
+
{isSearching ? emptySearchText : emptyText}
|
|
1331
1435
|
</div>,
|
|
1332
1436
|
];
|
|
1333
1437
|
}
|
|
@@ -1344,7 +1448,17 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1344
1448
|
if (isSearching) {
|
|
1345
1449
|
continue;
|
|
1346
1450
|
}
|
|
1347
|
-
|
|
1451
|
+
// role="listbox" only permits option/group children; the divider
|
|
1452
|
+
// carries no information the options don't, so it's hidden from the
|
|
1453
|
+
// accessibility tree entirely rather than exposing role="separator"
|
|
1454
|
+
// as a disallowed listbox child (axe aria-required-children).
|
|
1455
|
+
elements.push(
|
|
1456
|
+
<Divider
|
|
1457
|
+
key={`divider-${i}`}
|
|
1458
|
+
aria-hidden="true"
|
|
1459
|
+
xstyle={styles.divider}
|
|
1460
|
+
/>,
|
|
1461
|
+
);
|
|
1348
1462
|
} else if (isSection(option)) {
|
|
1349
1463
|
const sectionItems: ReactNode[] = [];
|
|
1350
1464
|
for (const opt of option.options) {
|
|
@@ -1391,7 +1505,16 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1391
1505
|
}
|
|
1392
1506
|
|
|
1393
1507
|
return elements;
|
|
1394
|
-
}, [
|
|
1508
|
+
}, [
|
|
1509
|
+
options,
|
|
1510
|
+
renderItem,
|
|
1511
|
+
hasSearch,
|
|
1512
|
+
searchQuery,
|
|
1513
|
+
filteredItems,
|
|
1514
|
+
isLoading,
|
|
1515
|
+
emptyText,
|
|
1516
|
+
emptySearchText,
|
|
1517
|
+
]);
|
|
1395
1518
|
|
|
1396
1519
|
// The detached message box renders its own leading status icon, so the
|
|
1397
1520
|
// on-field icon would duplicate it — keep the chevron indicator instead.
|
|
@@ -131,8 +131,8 @@ export const docs = {
|
|
|
131
131
|
bestPractices: [
|
|
132
132
|
{guidance: true, description: 'Use sections to group related navigation items and help users scan for their destination.'},
|
|
133
133
|
{guidance: true, description: 'Pair outline and filled icon variants so the selected state is visually distinct.'},
|
|
134
|
-
{guidance: true, description: 'Mark the current page with isSelected
|
|
135
|
-
{guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short
|
|
134
|
+
{guidance: true, description: 'Mark the current page with isSelected: it sets aria-current="page", so the current destination is announced rather than carried by color alone.'},
|
|
135
|
+
{guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short; they are the accessible name in both expanded and icon-only modes.'},
|
|
136
136
|
{guidance: true, description: 'While the nav is collapsed, an item with children shows them in a submenu flyout. On a device that can hover, pointing at the item opens it after a short delay and moving away closes it; a flyout opened by clicking stays open until it is dismissed. On touch, it opens on tap. Do not put an action in there that has no other route to it.'},
|
|
137
137
|
{guidance: false, description: 'Include a SideNavHeading when a TopNav is already providing app identity; this duplicates branding.'},
|
|
138
138
|
{guidance: false, description: 'Use for filtering content; use tabs or filter buttons instead.'},
|
|
@@ -153,8 +153,8 @@ export const docsZh = {
|
|
|
153
153
|
bestPractices: [
|
|
154
154
|
{guidance: true, description: 'Use sections to group related navigation items and help users scan for their destination.'},
|
|
155
155
|
{guidance: true, description: 'Pair outline and filled icon variants so the selected state is visually distinct.'},
|
|
156
|
-
{guidance: true, description: 'Mark the current page with isSelected
|
|
157
|
-
{guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short
|
|
156
|
+
{guidance: true, description: 'Mark the current page with isSelected: it sets aria-current="page", so the current destination is announced rather than carried by color alone.'},
|
|
157
|
+
{guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short; they are the accessible name in both expanded and icon-only modes.'},
|
|
158
158
|
{guidance: true, description: 'While the nav is collapsed, an item with children shows them in a submenu flyout. On a device that can hover, pointing at the item opens it after a short delay and moving away closes it; a flyout opened by clicking stays open until it is dismissed. On touch, it opens on tap. Do not put an action in there that has no other route to it.'},
|
|
159
159
|
{guidance: false, description: 'Include a SideNavHeading when a TopNav is already providing app identity; this duplicates branding.'},
|
|
160
160
|
{guidance: false, description: 'Use for filtering content; use tabs or filter buttons instead.'},
|
|
@@ -175,8 +175,8 @@ export const docsDense = {
|
|
|
175
175
|
bestPractices: [
|
|
176
176
|
{guidance: true, description: 'Use sections to group related navigation items and help users scan for their destination.'},
|
|
177
177
|
{guidance: true, description: 'Pair outline and filled icon variants so the selected state is visually distinct.'},
|
|
178
|
-
{guidance: true, description: 'Mark the current page with isSelected
|
|
179
|
-
{guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short
|
|
178
|
+
{guidance: true, description: 'Mark the current page with isSelected: it sets aria-current="page", so the current destination is announced rather than carried by color alone.'},
|
|
179
|
+
{guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short; they are the accessible name in both expanded and icon-only modes.'},
|
|
180
180
|
{guidance: true, description: 'While the nav is collapsed, an item with children shows them in a submenu flyout. On a device that can hover, pointing at the item opens it after a short delay and moving away closes it; a flyout opened by clicking stays open until it is dismissed. On touch, it opens on tap. Do not put an action in there that has no other route to it.'},
|
|
181
181
|
{guidance: false, description: 'Include a SideNavHeading when a TopNav is already providing app identity; this duplicates branding.'},
|
|
182
182
|
{guidance: false, description: 'Use for filtering content; use tabs or filter buttons instead.'},
|
package/src/SideNav/SideNav.tsx
CHANGED
|
@@ -32,7 +32,7 @@ import type {BaseProps} from '../BaseProps';
|
|
|
32
32
|
import * as stylex from '@stylexjs/stylex';
|
|
33
33
|
import type {StyleXStyles} from '@stylexjs/stylex';
|
|
34
34
|
import {spacingVars} from '../theme/tokens.stylex';
|
|
35
|
-
import {mergeProps
|
|
35
|
+
import {mergeProps} from '../utils';
|
|
36
36
|
import {
|
|
37
37
|
SideNavCollapseContext,
|
|
38
38
|
type SideNavCollapseState,
|
|
@@ -49,6 +49,7 @@ import {themeProps} from '../utils/themeProps';
|
|
|
49
49
|
import {SizeProvider} from '../SizeContext/SizeContext';
|
|
50
50
|
import {useTranslator} from '../i18n';
|
|
51
51
|
|
|
52
|
+
import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
52
53
|
// =============================================================================
|
|
53
54
|
// Constants
|
|
54
55
|
// =============================================================================
|
|
@@ -349,6 +350,7 @@ export function SideNav({
|
|
|
349
350
|
useState(defaultIsCollapsed);
|
|
350
351
|
const collapsed = isControlled ? controlledCollapsed : uncontrolledCollapsed;
|
|
351
352
|
const navRef = useRef<HTMLElement>(null);
|
|
353
|
+
const mergedNavRef = useMergedRefs(ref, navRef);
|
|
352
354
|
const collapseStateRef = useRef<SideNavCollapseState>({
|
|
353
355
|
isCollapsed: collapsed,
|
|
354
356
|
toggle: () => {},
|
|
@@ -517,7 +519,7 @@ export function SideNav({
|
|
|
517
519
|
|
|
518
520
|
const navElement = (
|
|
519
521
|
<nav
|
|
520
|
-
ref={
|
|
522
|
+
ref={mergedNavRef}
|
|
521
523
|
role="navigation"
|
|
522
524
|
aria-label={t('@astryx.sideNav.label')}
|
|
523
525
|
data-testid={testId}
|
|
@@ -40,7 +40,8 @@ import {focusOutlineProps} from '../utils/focusOutline.stylex';
|
|
|
40
40
|
import {useSideNavCollapse} from './SideNavCollapseContext';
|
|
41
41
|
import {useLinkComponent} from '../Link/useLinkComponent';
|
|
42
42
|
import type {LinkComponentType} from '../Link/types';
|
|
43
|
-
import {mergeProps
|
|
43
|
+
import {mergeProps} from '../utils';
|
|
44
|
+
import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
44
45
|
import type {BaseProps} from '../BaseProps';
|
|
45
46
|
import {useMenuHover} from '../hooks/useMenuHover';
|
|
46
47
|
import {NavHeadingCloseContext} from '../NavMenu/NavMenuContext';
|
|
@@ -59,7 +60,7 @@ const styles = stylex.create({
|
|
|
59
60
|
minHeight: spacingVars['--spacing-8'],
|
|
60
61
|
paddingInlineStart: {
|
|
61
62
|
default: spacingVars['--spacing-2'],
|
|
62
|
-
':has(.astryx-
|
|
63
|
+
':has(.astryx-nav-icon)': 0,
|
|
63
64
|
},
|
|
64
65
|
paddingInlineEnd: spacingVars['--spacing-2'],
|
|
65
66
|
paddingBlock: 0,
|
|
@@ -211,7 +212,7 @@ const styles = stylex.create({
|
|
|
211
212
|
minHeight: spacingVars['--spacing-8'],
|
|
212
213
|
paddingInlineStart: {
|
|
213
214
|
default: spacingVars['--spacing-2'],
|
|
214
|
-
':has(.astryx-
|
|
215
|
+
':has(.astryx-nav-icon)': 0,
|
|
215
216
|
},
|
|
216
217
|
paddingInlineEnd: spacingVars['--spacing-2'],
|
|
217
218
|
paddingBlock: 0,
|
|
@@ -399,11 +400,18 @@ export function SideNavHeading({
|
|
|
399
400
|
// setTriggerEl belongs on the chevron button, not this root: it is the
|
|
400
401
|
// focus-restore target and a <div> cannot take focus. triggerRef stays here
|
|
401
402
|
// because the panel anchors to the whole heading.
|
|
402
|
-
const setRef =
|
|
403
|
+
const setRef = useMergedRefs<HTMLDivElement>(
|
|
403
404
|
rootRef,
|
|
404
405
|
ref,
|
|
405
406
|
menu ? popover.triggerRef : undefined,
|
|
406
407
|
);
|
|
408
|
+
const collapsedSetRef = useMergedRefs<HTMLElement>(
|
|
409
|
+
collapsedItemRef,
|
|
410
|
+
ref,
|
|
411
|
+
// Collapsed, this button is the trigger, so it takes both roles.
|
|
412
|
+
menu ? popover.triggerRef : undefined,
|
|
413
|
+
menu ? setTriggerEl : undefined,
|
|
414
|
+
);
|
|
407
415
|
|
|
408
416
|
// In collapsed mode: hide if no icon, show icon-only if has icon
|
|
409
417
|
if (isCollapsed && !icon) {
|
|
@@ -412,14 +420,6 @@ export function SideNavHeading({
|
|
|
412
420
|
if (isCollapsed && icon) {
|
|
413
421
|
const collapsedIcon = <span {...stylex.props(styles.icon)}>{icon}</span>;
|
|
414
422
|
|
|
415
|
-
const collapsedSetRef = mergeRefs<HTMLElement>(
|
|
416
|
-
collapsedItemRef,
|
|
417
|
-
ref,
|
|
418
|
-
// Collapsed, this button is the trigger, so it takes both roles.
|
|
419
|
-
menu ? popover.triggerRef : undefined,
|
|
420
|
-
menu ? setTriggerEl : undefined,
|
|
421
|
-
);
|
|
422
|
-
|
|
423
423
|
let collapsedElement: ReactNode;
|
|
424
424
|
|
|
425
425
|
if (headingHref) {
|
|
@@ -47,7 +47,7 @@ import {useLinkComponent} from '../Link/useLinkComponent';
|
|
|
47
47
|
import type {LinkComponentType} from '../Link/types';
|
|
48
48
|
import {usePopover} from '../Popover/usePopover';
|
|
49
49
|
import {useMenuHover} from '../hooks/useMenuHover';
|
|
50
|
-
import {mergeProps
|
|
50
|
+
import {mergeProps} from '../utils';
|
|
51
51
|
import type {BaseProps} from '../BaseProps';
|
|
52
52
|
import {Tooltip} from '../Tooltip';
|
|
53
53
|
import {navItemStyles, type NavItemSize} from '../NavItem/navItemStyles.stylex';
|
|
@@ -61,6 +61,7 @@ import {useAppShellMobile} from '../AppShell/AppShellMobileContext';
|
|
|
61
61
|
import {themeProps} from '../utils/themeProps';
|
|
62
62
|
import {useTranslator} from '../i18n';
|
|
63
63
|
|
|
64
|
+
import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
64
65
|
// =============================================================================
|
|
65
66
|
// Styles
|
|
66
67
|
// =============================================================================
|
|
@@ -408,6 +409,7 @@ export function SideNavItem({
|
|
|
408
409
|
hasCloseButton: false,
|
|
409
410
|
dialogLabel: t('@astryx.sideNavItem.submenuLabel', {label}),
|
|
410
411
|
});
|
|
412
|
+
const mergedTriggerRef = useMergedRefs(ref, popover.triggerRef);
|
|
411
413
|
|
|
412
414
|
// Collapse state for items with children
|
|
413
415
|
const itemCollapsibleConfig = useMemo(
|
|
@@ -524,7 +526,7 @@ export function SideNavItem({
|
|
|
524
526
|
return (
|
|
525
527
|
<div {...stylex.props(styles.root, xstyle)}>
|
|
526
528
|
<button
|
|
527
|
-
ref={
|
|
529
|
+
ref={mergedTriggerRef}
|
|
528
530
|
type="button"
|
|
529
531
|
{...rest}
|
|
530
532
|
{...hoverTriggerProps}
|
|
@@ -13,7 +13,10 @@ import {useState} from 'react';
|
|
|
13
13
|
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
14
14
|
import {render, screen, act, fireEvent, waitFor} from '@testing-library/react';
|
|
15
15
|
import userEvent from '@testing-library/user-event';
|
|
16
|
+
import * as stylex from '@stylexjs/stylex';
|
|
16
17
|
import {Slider} from './Slider';
|
|
18
|
+
import {focusOutlineStyles} from '../utils/focusOutline.stylex';
|
|
19
|
+
import {__resetInteractionModalityForTest} from '../utils/interactionModality';
|
|
17
20
|
|
|
18
21
|
// Mock showPopover/hidePopover (not implemented in jsdom) so the tooltip layer
|
|
19
22
|
// reflects its open state via a `popover-open` attribute the tests can assert.
|
|
@@ -854,7 +857,7 @@ describe('Slider', () => {
|
|
|
854
857
|
/>,
|
|
855
858
|
);
|
|
856
859
|
const thumb = screen.getByRole('slider');
|
|
857
|
-
thumb.focus();
|
|
860
|
+
act(() => thumb.focus());
|
|
858
861
|
await user.keyboard('{ArrowRight}');
|
|
859
862
|
expect(onChange).not.toHaveBeenCalled();
|
|
860
863
|
});
|
|
@@ -902,4 +905,106 @@ describe('Slider', () => {
|
|
|
902
905
|
]).toEqual([]);
|
|
903
906
|
});
|
|
904
907
|
});
|
|
908
|
+
|
|
909
|
+
describe('focus ring modality', () => {
|
|
910
|
+
beforeEach(() => {
|
|
911
|
+
__resetInteractionModalityForTest();
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
// The ring is a stylex class, so derive it from the same source the
|
|
915
|
+
// component applies rather than hardcoding a hash.
|
|
916
|
+
const RING = stylex
|
|
917
|
+
.props(focusOutlineStyles.focusVisible)
|
|
918
|
+
.className!.split(' ');
|
|
919
|
+
const isRinged = (el: HTMLElement) =>
|
|
920
|
+
RING.every(c => el.classList.contains(c));
|
|
921
|
+
|
|
922
|
+
// The track has no layout in jsdom; pointer maths needs a real rect.
|
|
923
|
+
const grabTrack = (thumb: HTMLElement) => {
|
|
924
|
+
const track = thumb.parentElement!;
|
|
925
|
+
track.getBoundingClientRect = () => ({
|
|
926
|
+
left: 0,
|
|
927
|
+
top: 0,
|
|
928
|
+
right: 200,
|
|
929
|
+
bottom: 20,
|
|
930
|
+
width: 200,
|
|
931
|
+
height: 20,
|
|
932
|
+
x: 0,
|
|
933
|
+
y: 0,
|
|
934
|
+
toJSON: () => {},
|
|
935
|
+
});
|
|
936
|
+
fireEvent.pointerDown(track, {clientX: 100, clientY: 10, pointerId: 1});
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
it('rings when the thumb is reached with the keyboard', async () => {
|
|
940
|
+
const user = userEvent.setup();
|
|
941
|
+
render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
|
|
942
|
+
await user.tab();
|
|
943
|
+
expect(isRinged(screen.getByRole('slider'))).toBe(true);
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
it('does not ring when the thumb is grabbed with the mouse', () => {
|
|
947
|
+
render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
|
|
948
|
+
const thumb = screen.getByRole('slider');
|
|
949
|
+
grabTrack(thumb);
|
|
950
|
+
expect(thumb).toHaveFocus();
|
|
951
|
+
expect(isRinged(thumb)).toBe(false);
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
it('drops the ring when the mouse grabs a thumb that already had it', async () => {
|
|
955
|
+
const user = userEvent.setup();
|
|
956
|
+
render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
|
|
957
|
+
await user.tab();
|
|
958
|
+
const thumb = screen.getByRole('slider');
|
|
959
|
+
expect(isRinged(thumb)).toBe(true);
|
|
960
|
+
// Already focused, so focus() fires no focus event.
|
|
961
|
+
grabTrack(thumb);
|
|
962
|
+
expect(isRinged(thumb)).toBe(false);
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
it('brings the ring back when an arrow key follows a mouse drag', () => {
|
|
966
|
+
render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
|
|
967
|
+
const thumb = screen.getByRole('slider');
|
|
968
|
+
grabTrack(thumb);
|
|
969
|
+
expect(isRinged(thumb)).toBe(false);
|
|
970
|
+
fireEvent.keyDown(thumb, {key: 'ArrowRight'});
|
|
971
|
+
expect(isRinged(thumb)).toBe(true);
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
it('leaves the ring off for a modifier chord after a mouse drag', () => {
|
|
975
|
+
render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
|
|
976
|
+
const thumb = screen.getByRole('slider');
|
|
977
|
+
grabTrack(thumb);
|
|
978
|
+
// Copying or reloading is not navigation, and the mouse is still on it.
|
|
979
|
+
fireEvent.keyDown(thumb, {key: 'c', metaKey: true});
|
|
980
|
+
expect(isRinged(thumb)).toBe(false);
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
it('drops the ring on blur', async () => {
|
|
984
|
+
const user = userEvent.setup();
|
|
985
|
+
render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
|
|
986
|
+
await user.tab();
|
|
987
|
+
const thumb = screen.getByRole('slider');
|
|
988
|
+
expect(isRinged(thumb)).toBe(true);
|
|
989
|
+
act(() => thumb.blur());
|
|
990
|
+
expect(isRinged(thumb)).toBe(false);
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
it('rings the range thumb the keyboard reached, not its sibling', async () => {
|
|
994
|
+
const user = userEvent.setup();
|
|
995
|
+
render(
|
|
996
|
+
<Slider
|
|
997
|
+
label="Price"
|
|
998
|
+
value={[20, 80] as [number, number]}
|
|
999
|
+
onChange={vi.fn()}
|
|
1000
|
+
/>,
|
|
1001
|
+
);
|
|
1002
|
+
await user.tab();
|
|
1003
|
+
await user.tab();
|
|
1004
|
+
const thumbs = screen.getAllByRole('slider');
|
|
1005
|
+
expect(thumbs[1]).toHaveFocus();
|
|
1006
|
+
expect(isRinged(thumbs[1])).toBe(true);
|
|
1007
|
+
expect(isRinged(thumbs[0])).toBe(false);
|
|
1008
|
+
});
|
|
1009
|
+
});
|
|
905
1010
|
});
|