@astryxdesign/core 0.4.7 → 0.5.0-canary.009bcb3
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 +49 -15
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +62 -20
- 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 +7 -3
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +21 -23
- 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 +12 -12
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +17 -9
- package/dist/Card/index.d.ts +35 -1
- package/dist/Card/index.d.ts.map +1 -1
- package/dist/Card/index.js +21 -1
- 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/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +1 -3
- 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/DateRangeInput/DateRangeInput.d.ts +4 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- 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/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +4 -13
- 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/Field/InputClearButton.d.ts +9 -3
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +14 -3
- 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 -3
- 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/gestureCounter.d.ts +8 -0
- package/dist/Layer/gestureCounter.d.ts.map +1 -0
- package/dist/Layer/gestureCounter.js +53 -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/useLayer.d.ts +23 -13
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +128 -8
- 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/List/List.d.ts +1 -1
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +15 -4
- package/dist/Markdown/Markdown.d.ts +1 -1
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +20 -7
- 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/MetadataList/MetadataListItem.d.ts +1 -1
- package/dist/MetadataList/MetadataListItem.d.ts.map +1 -1
- package/dist/MetadataList/MetadataListItem.js +4 -1
- 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 +73 -15
- package/dist/MultiSelector/hooks.d.ts +7 -1
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +3 -2
- 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 +1 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +9 -5
- 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/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +1 -9
- package/dist/Popover/usePopover.d.ts +7 -41
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +40 -21
- 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 +12 -3
- package/dist/Selector/Selector.d.ts +18 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +91 -18
- package/dist/Selector/hooks.d.ts +7 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +3 -2
- 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 +26 -0
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +54 -11
- 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 +43 -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 -3
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +16 -10
- 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 +1 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +15 -21
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +22 -7
- package/dist/Toast/ToastViewport.d.ts +1 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +71 -18
- package/dist/Token/Token.d.ts +1 -1
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +20 -9
- package/dist/Token/TokenLink.d.ts +1 -1
- package/dist/Token/TokenLink.d.ts.map +1 -1
- package/dist/Token/TokenLink.js +7 -4
- package/dist/Tokenizer/Tokenizer.d.ts +14 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +33 -21
- 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 +1 -1
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +31 -11
- package/dist/TopNav/TopNavMenu.d.ts +1 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +22 -7
- package/dist/TreeList/TreeList.d.ts +1 -1
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +7 -2
- package/dist/Typeahead/BaseTypeahead.d.ts +35 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +119 -37
- package/dist/Typeahead/Typeahead.d.ts +8 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +5 -2
- package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
- package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
- package/dist/Typeahead/TypeaheadItem.js +7 -2
- package/dist/astryx.css +113 -11
- 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/Theme.d.ts.map +1 -1
- package/dist/theme/Theme.js +46 -10
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +24 -4
- package/dist/theme/generateThemeRules.d.ts +21 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +26 -0
- 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/af-ZA.json +6 -6
- package/locales/ar-SA.json +6 -6
- package/locales/ca-ES.json +5 -5
- package/locales/cs-CZ.json +6 -6
- package/locales/da-DK.json +6 -6
- package/locales/de-DE.json +6 -6
- package/locales/el-GR.json +6 -6
- package/locales/en.json +163 -11
- package/locales/es-ES.json +5 -5
- package/locales/fi-FI.json +6 -6
- package/locales/fr-FR.json +6 -6
- package/locales/he-IL.json +6 -6
- package/locales/hu-HU.json +6 -6
- package/locales/it-IT.json +6 -6
- package/locales/ja-JP.json +6 -6
- package/locales/ko-KR.json +6 -6
- package/locales/nl-NL.json +6 -6
- package/locales/no-NO.json +6 -6
- package/locales/pl-PL.json +6 -6
- package/locales/pseudo.json +114 -0
- package/locales/pt-BR.json +6 -6
- package/locales/pt-PT.json +6 -6
- package/locales/ro-RO.json +6 -6
- package/locales/ru-RU.json +6 -6
- package/locales/sr-SP.json +6 -6
- package/locales/sv-SE.json +6 -6
- package/locales/tr-TR.json +6 -6
- package/locales/uk-UA.json +6 -6
- package/locales/vi-VN.json +6 -6
- package/locales/zh-CN.json +6 -6
- package/locales/zh-TW.json +6 -6
- 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 +22 -11
- package/src/Banner/Banner.test.tsx +177 -25
- package/src/Banner/Banner.tsx +93 -27
- 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 +7 -6
- package/src/Calendar/Calendar.test.tsx +143 -0
- package/src/Calendar/Calendar.tsx +30 -26
- 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 +113 -19
- package/src/Card/Card.tsx +67 -89
- package/src/Card/index.ts +36 -1
- 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/ComplexSelector/ComplexSelector.test.tsx +32 -0
- package/src/ComplexSelector/ComplexSelector.tsx +1 -3
- 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/DateRangeInput/DateRangeInput.doc.mjs +2 -2
- package/src/DateRangeInput/DateRangeInput.test.tsx +22 -0
- package/src/DateRangeInput/DateRangeInput.tsx +4 -2
- 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/DropdownMenu.test.tsx +44 -10
- package/src/DropdownMenu/DropdownMenu.tsx +4 -13
- 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/Field/InputClearButton.test.tsx +15 -1
- package/src/Field/InputClearButton.tsx +28 -4
- package/src/FileInput/FileInput.tsx +3 -2
- package/src/Heading/Heading.test.tsx +23 -1
- package/src/Heading/Heading.tsx +6 -3
- 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/gestureCounter.ts +57 -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 +324 -15
- package/src/Layer/useLayer.tsx +164 -8
- 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/Layout/__tests__/edgeCompensation.test.tsx +1 -1
- 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/List/List.test.tsx +38 -0
- package/src/List/List.tsx +8 -1
- package/src/Markdown/Markdown.doc.mjs +5 -0
- package/src/Markdown/Markdown.test.tsx +37 -0
- package/src/Markdown/Markdown.tsx +16 -5
- 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/MetadataList/MetadataList.test.tsx +75 -2
- package/src/MetadataList/MetadataListItem.tsx +5 -2
- 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 +311 -0
- package/src/MultiSelector/MultiSelector.tsx +151 -15
- package/src/MultiSelector/hooks.ts +9 -2
- 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.test.tsx +30 -0
- package/src/NavMenu/NavHeadingMenu.tsx +9 -5
- 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/Popover.test.tsx +14 -0
- package/src/Popover/Popover.tsx +1 -9
- package/src/Popover/usePopover.tsx +57 -32
- 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.doc.mjs +3 -0
- package/src/SelectableCard/SelectableCard.tsx +19 -2
- package/src/Selector/Selector.doc.mjs +26 -1
- package/src/Selector/Selector.test.tsx +346 -1
- package/src/Selector/Selector.tsx +148 -21
- package/src/Selector/hooks.ts +17 -2
- 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 +67 -12
- 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 +138 -0
- package/src/Table/plugins/selection/useTableSelection.tsx +63 -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 +67 -1
- package/src/Text/Text.tsx +6 -3
- package/src/TextArea/TextArea.doc.mjs +12 -2
- package/src/TextArea/TextArea.test.tsx +11 -0
- package/src/TextArea/TextArea.tsx +37 -24
- 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 +58 -0
- package/src/Timestamp/Timestamp.tsx +12 -10
- package/src/Toast/Toast.doc.mjs +26 -12
- package/src/Toast/Toast.tsx +28 -4
- package/src/Toast/ToastViewport.test.tsx +536 -8
- package/src/Toast/ToastViewport.tsx +81 -12
- package/src/Token/Token.test.tsx +95 -0
- package/src/Token/Token.tsx +15 -10
- package/src/Token/TokenLink.tsx +14 -5
- package/src/Tokenizer/Tokenizer.doc.mjs +43 -3
- package/src/Tokenizer/Tokenizer.test.tsx +161 -0
- package/src/Tokenizer/Tokenizer.tsx +53 -24
- 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.test.tsx +104 -0
- package/src/TopNav/TopNavMegaMenu.tsx +47 -5
- package/src/TopNav/TopNavMenu.test.tsx +133 -1
- package/src/TopNav/TopNavMenu.tsx +38 -7
- package/src/TreeList/TreeList.test.tsx +49 -0
- package/src/TreeList/TreeList.tsx +7 -2
- package/src/Typeahead/BaseTypeahead.doc.mjs +24 -0
- package/src/Typeahead/BaseTypeahead.tsx +181 -39
- package/src/Typeahead/Typeahead.doc.mjs +11 -0
- package/src/Typeahead/Typeahead.test.tsx +203 -0
- package/src/Typeahead/Typeahead.tsx +12 -2
- package/src/Typeahead/TypeaheadItem.test.tsx +43 -0
- package/src/Typeahead/TypeaheadItem.tsx +8 -1
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useAnnounce.doc.mjs +96 -0
- package/src/hooks/useContainerReveal.doc.mjs +2 -2
- package/src/hooks/useDevWarning.doc.mjs +96 -0
- 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/useIndicatorFocusRing.doc.mjs +104 -0
- package/src/hooks/useInputStatusIcon.doc.mjs +142 -0
- package/src/hooks/useInteractiveRole.doc.mjs +119 -0
- package/src/hooks/useLongPress.doc.mjs +123 -0
- 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/hooks/useTypeahead.doc.mjs +153 -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/Theme.test.tsx +104 -2
- package/src/theme/Theme.tsx +49 -14
- package/src/theme/defineTheme.test.ts +23 -0
- package/src/theme/derivedVarRegistry.test.ts +26 -3
- package/src/theme/derivedVarRegistry.ts +23 -4
- package/src/theme/generateThemeRules.test.ts +99 -1
- package/src/theme/generateThemeRules.ts +28 -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
package/src/TabList/TabList.tsx
CHANGED
|
@@ -4,11 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file TabList.tsx
|
|
7
|
-
* @input Uses React, StyleX, TabListContext, useListFocus, useKeyboardHint
|
|
8
|
-
*
|
|
9
|
-
* @
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* @input Uses React, StyleX, TabListContext, useListFocus, useKeyboardHint,
|
|
8
|
+
* useScrollOverflow, Icon
|
|
9
|
+
* @output Exports TabList component, TabListProps and TabListOverflow types
|
|
10
|
+
* @position Tab strip wrapper; provides TabListContext to Tab and TabMenu
|
|
11
|
+
* children. A `<nav>` landmark by default; speaks the WAI-ARIA tabs pattern
|
|
12
|
+
* where the caller asks for it with `role="tablist"`. Owns
|
|
13
|
+
* roving-tabindex keyboard navigation (Arrow/Home/End) across the tab
|
|
14
|
+
* strip via the shared useListFocus hook so it is a single Tab stop, and
|
|
15
|
+
* owns horizontal scrolling when the tabs are wider than the strip.
|
|
12
16
|
*
|
|
13
17
|
* SYNC: When modified, update:
|
|
14
18
|
* - /packages/core/src/TabList/TabList.doc.mjs
|
|
@@ -17,20 +21,44 @@
|
|
|
17
21
|
* - /packages/cli/assets/templates/blocks/components/TabList/ (showcase blocks)
|
|
18
22
|
*/
|
|
19
23
|
|
|
20
|
-
import React, {
|
|
24
|
+
import React, {
|
|
25
|
+
useCallback,
|
|
26
|
+
useEffect,
|
|
27
|
+
useMemo,
|
|
28
|
+
useRef,
|
|
29
|
+
type AriaRole,
|
|
30
|
+
type ReactNode,
|
|
31
|
+
} from 'react';
|
|
21
32
|
import * as stylex from '@stylexjs/stylex';
|
|
22
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
borderVars,
|
|
35
|
+
colorVars,
|
|
36
|
+
durationVars,
|
|
37
|
+
easeVars,
|
|
38
|
+
focusVars,
|
|
39
|
+
radiusVars,
|
|
40
|
+
shadowVars,
|
|
41
|
+
sizeVars,
|
|
42
|
+
spacingVars,
|
|
43
|
+
} from '../theme/tokens.stylex';
|
|
23
44
|
import type {BaseProps} from '../BaseProps';
|
|
24
45
|
import {TabListContext} from './TabListContext';
|
|
25
46
|
import type {TabListSize} from './TabListContext';
|
|
26
47
|
import {useSize} from '../SizeContext/SizeContext';
|
|
27
|
-
import {mergeProps,
|
|
48
|
+
import {mergeProps, rtlStyles} from '../utils';
|
|
28
49
|
import {useListFocus} from '../hooks/useListFocus';
|
|
29
50
|
import {useKeyboardHint} from '../hooks/useKeyboardHint';
|
|
51
|
+
import {useScrollOverflow} from '../hooks/useScrollOverflow';
|
|
52
|
+
import {isRtlElement} from '../hooks/isRtlElement';
|
|
53
|
+
import {Icon} from '../Icon';
|
|
30
54
|
import {EDGE_COMP_ATTR} from '../Layout/edgeCompensation.stylex';
|
|
31
55
|
import {themeProps} from '../utils/themeProps';
|
|
56
|
+
import {observeResize, unobserveResize} from '../utils/sharedResizeObserver';
|
|
57
|
+
import {devWarn} from '../utils/devWarning';
|
|
58
|
+
import {focusOutlineProps} from '../utils/focusOutline.stylex';
|
|
32
59
|
import {useTranslator} from '../i18n';
|
|
33
60
|
|
|
61
|
+
import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
34
62
|
/**
|
|
35
63
|
* Selector matching the focusable stops in the tab strip: every Tab
|
|
36
64
|
* (`[data-tab-value]`) and every TabMenu trigger (`[data-tab-menu]`),
|
|
@@ -38,6 +66,24 @@ import {useTranslator} from '../i18n';
|
|
|
38
66
|
*/
|
|
39
67
|
const TAB_STOP_SELECTOR = '[data-tab-value],[data-tab-menu]';
|
|
40
68
|
|
|
69
|
+
function preventFocus(e: React.MouseEvent) {
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Fraction of the visible strip an arrow press scrolls. */
|
|
74
|
+
const SCROLL_PAGE_RATIO = 0.8;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* How a strip narrower than its tabs behaves.
|
|
78
|
+
*
|
|
79
|
+
* - `'auto'` — the component picks the strategy. Today that is always
|
|
80
|
+
* `'scroll'`.
|
|
81
|
+
* - `'scroll'` — the tabs scroll horizontally. Every tab stays a tab.
|
|
82
|
+
* - `'visible'` — no overflow handling: tabs keep their intrinsic widths and
|
|
83
|
+
* spill out of the strip, as they did before overflow existed.
|
|
84
|
+
*/
|
|
85
|
+
export type TabListOverflow = 'auto' | 'scroll' | 'visible';
|
|
86
|
+
|
|
41
87
|
export interface TabListProps extends Omit<BaseProps<HTMLElement>, 'onChange'> {
|
|
42
88
|
ref?: React.Ref<HTMLElement>;
|
|
43
89
|
/**
|
|
@@ -66,12 +112,85 @@ export interface TabListProps extends Omit<BaseProps<HTMLElement>, 'onChange'> {
|
|
|
66
112
|
* @default false
|
|
67
113
|
*/
|
|
68
114
|
hasDivider?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* ARIA role for the strip.
|
|
117
|
+
*
|
|
118
|
+
* `"tablist"` asks for the WAI-ARIA tabs pattern: `role="tablist"` /
|
|
119
|
+
* `role="tab"` and `aria-selected`, with each tab pointing at the panel it
|
|
120
|
+
* controls via its `panelId`. Only tabs may live in a tablist strip, and a
|
|
121
|
+
* tab does not navigate — an `href` is ignored there.
|
|
122
|
+
*
|
|
123
|
+
* Left unset, the strip is a `<nav>` landmark marking the current tab with
|
|
124
|
+
* `aria-current`. Any other value is passed through to the element
|
|
125
|
+
* unchanged.
|
|
126
|
+
*/
|
|
127
|
+
role?: AriaRole;
|
|
128
|
+
/**
|
|
129
|
+
* What happens when the tabs are wider than the strip.
|
|
130
|
+
*
|
|
131
|
+
* `'auto'` lets the component choose; today it always scrolls. `'scroll'`
|
|
132
|
+
* scrolls the tabs horizontally, with edge fades and — for pointers that
|
|
133
|
+
* can hover — arrow affordances. `'visible'` turns overflow handling off and
|
|
134
|
+
* lets the tabs spill out of the strip.
|
|
135
|
+
*
|
|
136
|
+
* The selected tab is always scrolled back into view.
|
|
137
|
+
* @default 'auto'
|
|
138
|
+
*/
|
|
139
|
+
overflow?: TabListOverflow;
|
|
69
140
|
/**
|
|
70
141
|
* Tab and TabMenu children.
|
|
71
142
|
*/
|
|
72
143
|
children: ReactNode;
|
|
73
144
|
}
|
|
74
145
|
|
|
146
|
+
/**
|
|
147
|
+
* A scroll container clips at its padding box, and two things a tab paints sit
|
|
148
|
+
* outside its own box: the focus ring (offset + width) and the selected
|
|
149
|
+
* indicator, which `--_tab-indicator-bottom` pushes further down when a
|
|
150
|
+
* divider rail is reserved. The strip pads by that much and takes the padding
|
|
151
|
+
* straight back off with a negative margin, so nothing is clipped and the tabs
|
|
152
|
+
* stay exactly where they were.
|
|
153
|
+
*
|
|
154
|
+
* A bleed is not free, though. The padding is real geometry: the strip's
|
|
155
|
+
* border box sticks out of the TabList's, and any ancestor that scrolls counts
|
|
156
|
+
* that as something to scroll to. So the ring's share of the bleed is taken
|
|
157
|
+
* only while a ring is actually drawn inside the strip -- the same
|
|
158
|
+
* `:has(:focus-visible)` condition that draws it -- and at rest the strip is
|
|
159
|
+
* exactly as wide and as tall as the TabList, as it was before the strip could
|
|
160
|
+
* scroll. The indicator's share is always taken, because the indicator is
|
|
161
|
+
* always drawn.
|
|
162
|
+
*
|
|
163
|
+
* Turning the bleed on moves nothing: padding and negative margin cancel, so
|
|
164
|
+
* the border box grows outwards and the content stays put.
|
|
165
|
+
*/
|
|
166
|
+
const RING_BLEED = `calc(${focusVars['--focus-outline-width']} + ${focusVars['--focus-outline-offset']})`;
|
|
167
|
+
const BLEED_VAR = '--_tab-strip-bleed';
|
|
168
|
+
const BLEED = `var(${BLEED_VAR})`;
|
|
169
|
+
const INDICATOR_BLEED = 'calc(-1 * var(--_tab-indicator-bottom, -1px))';
|
|
170
|
+
const BLOCK_END_BLEED = `max(${BLEED}, ${INDICATOR_BLEED})`;
|
|
171
|
+
|
|
172
|
+
/** How far the edge fade runs; wide enough to sit under an arrow. */
|
|
173
|
+
const FADE_WIDTH = spacingVars['--spacing-8'];
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Where the fade turns fully opaque, and — the same distance, for the same
|
|
177
|
+
* reason — how far a revealed stop is kept clear of the edge. Declared as
|
|
178
|
+
* scroll-padding so the browser's own focus scrolling uses it too, and read
|
|
179
|
+
* back from the computed style so the arithmetic below has one source of
|
|
180
|
+
* truth with the CSS.
|
|
181
|
+
*/
|
|
182
|
+
const SCROLL_EDGE_INSET = `calc(${BLEED} + ${FADE_WIDTH})`;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The fade reaches transparent at the strip's *own* edge, not at the bleed
|
|
186
|
+
* edge — otherwise the scroll container paints tabs past the TabList's box,
|
|
187
|
+
* past a divider rail, and past the scroll arrow that caps that edge. Masking
|
|
188
|
+
* the bleed costs nothing: only a faded edge is masked, and a stop at a faded
|
|
189
|
+
* edge never holds focus, so the bleed is still there when the ring needs it.
|
|
190
|
+
*/
|
|
191
|
+
const FADE_FROM_START = `linear-gradient(to right, transparent ${BLEED}, black ${SCROLL_EDGE_INSET})`;
|
|
192
|
+
const FADE_FROM_END = `linear-gradient(to left, transparent ${BLEED}, black ${SCROLL_EDGE_INSET})`;
|
|
193
|
+
|
|
75
194
|
const styles = stylex.create({
|
|
76
195
|
nav: {
|
|
77
196
|
display: 'flex',
|
|
@@ -79,6 +198,7 @@ const styles = stylex.create({
|
|
|
79
198
|
gap: spacingVars['--spacing-0-5'],
|
|
80
199
|
maxWidth: '100%',
|
|
81
200
|
minWidth: 0,
|
|
201
|
+
position: 'relative',
|
|
82
202
|
},
|
|
83
203
|
fill: {
|
|
84
204
|
width: '100%',
|
|
@@ -96,6 +216,114 @@ const styles = stylex.create({
|
|
|
96
216
|
paddingBlockEnd: spacingVars['--spacing-1'],
|
|
97
217
|
'--_tab-indicator-bottom': `calc(-1 * (${spacingVars['--spacing-1']} + ${borderVars['--border-width']}))`,
|
|
98
218
|
},
|
|
219
|
+
strip: {
|
|
220
|
+
display: 'flex',
|
|
221
|
+
alignItems: 'stretch',
|
|
222
|
+
// Inherited rather than restated so an `xstyle` gap override on the
|
|
223
|
+
// TabList still reaches the tabs.
|
|
224
|
+
gap: 'inherit',
|
|
225
|
+
flexGrow: 1,
|
|
226
|
+
flexShrink: 1,
|
|
227
|
+
minWidth: 0,
|
|
228
|
+
// Content-height, not stretched: the bleed padding below is inside the
|
|
229
|
+
// strip's own height, and a stretched height would push the tabs out of
|
|
230
|
+
// the scrollport.
|
|
231
|
+
alignSelf: 'flex-start',
|
|
232
|
+
},
|
|
233
|
+
stripScroll: {
|
|
234
|
+
overflowX: 'auto',
|
|
235
|
+
overflowY: 'hidden',
|
|
236
|
+
overscrollBehaviorX: 'contain',
|
|
237
|
+
scrollPaddingInline: SCROLL_EDGE_INSET,
|
|
238
|
+
scrollbarWidth: 'none',
|
|
239
|
+
scrollBehavior: {
|
|
240
|
+
default: 'smooth',
|
|
241
|
+
'@media (prefers-reduced-motion: reduce)': 'auto',
|
|
242
|
+
},
|
|
243
|
+
[BLEED_VAR]: {
|
|
244
|
+
default: '0px',
|
|
245
|
+
':has(:focus-visible)': RING_BLEED,
|
|
246
|
+
},
|
|
247
|
+
paddingBlockStart: BLEED,
|
|
248
|
+
marginBlockStart: `calc(-1 * (${BLEED}))`,
|
|
249
|
+
paddingBlockEnd: BLOCK_END_BLEED,
|
|
250
|
+
marginBlockEnd: `calc(-1 * (${BLOCK_END_BLEED}))`,
|
|
251
|
+
paddingInline: BLEED,
|
|
252
|
+
marginInline: `calc(-1 * (${BLEED}))`,
|
|
253
|
+
maskImage: 'none',
|
|
254
|
+
transitionProperty: 'mask-image',
|
|
255
|
+
transitionDuration: {
|
|
256
|
+
default: durationVars['--duration-medium'],
|
|
257
|
+
'@media (prefers-reduced-motion: reduce)': '0ms',
|
|
258
|
+
},
|
|
259
|
+
transitionTimingFunction: easeVars['--ease-standard'],
|
|
260
|
+
},
|
|
261
|
+
fadeStart: {
|
|
262
|
+
maskImage: {
|
|
263
|
+
default: FADE_FROM_START,
|
|
264
|
+
':is([dir="rtl"] *)': FADE_FROM_END,
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
fadeEnd: {
|
|
268
|
+
maskImage: {
|
|
269
|
+
default: FADE_FROM_END,
|
|
270
|
+
':is([dir="rtl"] *)': FADE_FROM_START,
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
fadeBoth: {
|
|
274
|
+
maskImage: `linear-gradient(to right, transparent ${BLEED}, black ${SCROLL_EDGE_INSET}, black calc(100% - ${SCROLL_EDGE_INSET}), transparent calc(100% - ${BLEED}))`,
|
|
275
|
+
},
|
|
276
|
+
arrow: {
|
|
277
|
+
position: 'absolute',
|
|
278
|
+
insetBlockStart: 0,
|
|
279
|
+
// A pointer-only affordance: keyboard and assistive-technology users move
|
|
280
|
+
// through the strip with the arrow keys, which scrolls the focused tab
|
|
281
|
+
// into view on its own.
|
|
282
|
+
display: {
|
|
283
|
+
default: 'none',
|
|
284
|
+
'@media (hover: hover)': 'flex',
|
|
285
|
+
},
|
|
286
|
+
alignItems: 'center',
|
|
287
|
+
justifyContent: 'center',
|
|
288
|
+
padding: 0,
|
|
289
|
+
borderWidth: 0,
|
|
290
|
+
borderStyle: 'none',
|
|
291
|
+
borderRadius: radiusVars['--radius-full'],
|
|
292
|
+
// Opaque, because it sits over the tabs it scrolls: the strip's edge fade
|
|
293
|
+
// thins the content underneath but does not clear it.
|
|
294
|
+
backgroundColor: colorVars['--color-background-popover'],
|
|
295
|
+
boxShadow: shadowVars['--shadow-low'],
|
|
296
|
+
color: {
|
|
297
|
+
default: colorVars['--color-text-secondary'],
|
|
298
|
+
':hover:where(:not(:disabled,[aria-disabled="true"]))':
|
|
299
|
+
colorVars['--color-text-primary'],
|
|
300
|
+
},
|
|
301
|
+
cursor: {
|
|
302
|
+
default: 'pointer',
|
|
303
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
arrowStart: {
|
|
307
|
+
insetInlineStart: 0,
|
|
308
|
+
},
|
|
309
|
+
arrowEnd: {
|
|
310
|
+
insetInlineEnd: 0,
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
const arrowSizeStyles = stylex.create({
|
|
315
|
+
sm: {
|
|
316
|
+
width: sizeVars['--size-element-sm'],
|
|
317
|
+
height: sizeVars['--size-element-sm'],
|
|
318
|
+
},
|
|
319
|
+
md: {
|
|
320
|
+
width: sizeVars['--size-element-md'],
|
|
321
|
+
height: sizeVars['--size-element-md'],
|
|
322
|
+
},
|
|
323
|
+
lg: {
|
|
324
|
+
width: sizeVars['--size-element-lg'],
|
|
325
|
+
height: sizeVars['--size-element-lg'],
|
|
326
|
+
},
|
|
99
327
|
});
|
|
100
328
|
|
|
101
329
|
/**
|
|
@@ -121,6 +349,8 @@ export function TabList({
|
|
|
121
349
|
size: sizeProp,
|
|
122
350
|
layout = 'hug',
|
|
123
351
|
hasDivider = false,
|
|
352
|
+
role,
|
|
353
|
+
overflow = 'auto',
|
|
124
354
|
xstyle,
|
|
125
355
|
className,
|
|
126
356
|
style,
|
|
@@ -129,6 +359,7 @@ export function TabList({
|
|
|
129
359
|
onFocus: onFocusProp,
|
|
130
360
|
onBlur: onBlurProp,
|
|
131
361
|
'aria-label': ariaLabelFromProps,
|
|
362
|
+
'aria-labelledby': ariaLabelledBy,
|
|
132
363
|
'aria-orientation': _ariaOrientation,
|
|
133
364
|
[EDGE_COMP_ATTR]: _edgeCompAttr,
|
|
134
365
|
...restProps
|
|
@@ -136,13 +367,22 @@ export function TabList({
|
|
|
136
367
|
const t = useTranslator();
|
|
137
368
|
const ariaLabel = ariaLabelFromProps ?? t('@astryx.tabList.label');
|
|
138
369
|
const size = useSize(sizeProp, 'md');
|
|
370
|
+
const hasScroll = overflow !== 'visible';
|
|
371
|
+
|
|
372
|
+
const stripRef = useRef<HTMLDivElement | null>(null);
|
|
373
|
+
// Only an asserted `role="tablist"` switches the pattern. Left unset the
|
|
374
|
+
// strip is the `<nav>` it has always been, and every other role passes
|
|
375
|
+
// through to the element untouched.
|
|
376
|
+
const isTabList = role === 'tablist';
|
|
139
377
|
|
|
140
378
|
// Roving-tabindex keyboard navigation across the tab strip via the shared
|
|
141
|
-
// hook. `orientation: 'both'` accepts both
|
|
142
|
-
// allowance for tab strips
|
|
143
|
-
// retreat).
|
|
144
|
-
//
|
|
145
|
-
//
|
|
379
|
+
// hook. Under the navigation pattern `orientation: 'both'` accepts both
|
|
380
|
+
// arrow axes per the WAI-ARIA APG allowance for tab strips
|
|
381
|
+
// (ArrowRight/ArrowDown advance, ArrowLeft/ArrowUp retreat). A tablist
|
|
382
|
+
// reports itself as horizontal, so there the strip takes only the
|
|
383
|
+
// horizontal arrows and leaves ArrowUp and ArrowDown to scroll the page. We
|
|
384
|
+
// do not set `aria-orientation` on the `<nav>`: that attribute is invalid on
|
|
385
|
+
// the navigation role and triggers an axe `aria-allowed-attr` violation.
|
|
146
386
|
//
|
|
147
387
|
// `hasRovingTabIndex` makes the hook own the single tab stop: it stamps
|
|
148
388
|
// tabindex 0/-1, repairs the stop on mount and as stops mount/unmount or
|
|
@@ -153,7 +393,7 @@ export function TabList({
|
|
|
153
393
|
// the first enabled stop when none is tabbable.
|
|
154
394
|
const {listRef, handleKeyDown, handleFocus} = useListFocus<HTMLElement>({
|
|
155
395
|
itemSelector: TAB_STOP_SELECTOR,
|
|
156
|
-
orientation: 'both',
|
|
396
|
+
orientation: isTabList ? 'horizontal' : 'both',
|
|
157
397
|
hasRovingTabIndex: true,
|
|
158
398
|
});
|
|
159
399
|
|
|
@@ -164,9 +404,124 @@ export function TabList({
|
|
|
164
404
|
onBlur: onHintBlur,
|
|
165
405
|
} = useKeyboardHint();
|
|
166
406
|
|
|
407
|
+
const {scrollRef, overflowStart, overflowEnd} = useScrollOverflow();
|
|
408
|
+
|
|
409
|
+
const attachStrip = useCallback(
|
|
410
|
+
(el: HTMLDivElement | null) => {
|
|
411
|
+
stripRef.current = el;
|
|
412
|
+
scrollRef(hasScroll ? el : null);
|
|
413
|
+
},
|
|
414
|
+
[hasScroll, scrollRef],
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
const revealStop = useCallback(
|
|
418
|
+
(stop: HTMLElement | null) => {
|
|
419
|
+
const strip = stripRef.current;
|
|
420
|
+
if (!hasScroll || !strip || !stop) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const stripBox = strip.getBoundingClientRect();
|
|
424
|
+
const stopBox = stop.getBoundingClientRect();
|
|
425
|
+
const inset = parseFloat(getComputedStyle(strip).scrollPaddingLeft) || 0;
|
|
426
|
+
const pastEnd = stopBox.right - (stripBox.right - inset);
|
|
427
|
+
const pastStart = stopBox.left - (stripBox.left + inset);
|
|
428
|
+
// A stop wider than the space kept clear cannot be shown whole, so show
|
|
429
|
+
// its reading start, the way `scrollIntoView({inline: 'nearest'})` does.
|
|
430
|
+
const tooWide = stopBox.width > stripBox.width - 2 * inset;
|
|
431
|
+
const delta = tooWide
|
|
432
|
+
? isRtlElement(strip)
|
|
433
|
+
? pastEnd
|
|
434
|
+
: pastStart
|
|
435
|
+
: pastEnd > 0
|
|
436
|
+
? pastEnd
|
|
437
|
+
: pastStart < 0
|
|
438
|
+
? pastStart
|
|
439
|
+
: 0;
|
|
440
|
+
if (delta !== 0) {
|
|
441
|
+
// Not an animation: the strip has to arrive already showing the right
|
|
442
|
+
// tab, so this overrides the CSS smooth behaviour arrow presses use.
|
|
443
|
+
strip.scrollBy({left: delta, behavior: 'instant'});
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
[hasScroll],
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
const revealSelectedTab = useCallback(() => {
|
|
450
|
+
const strip = stripRef.current;
|
|
451
|
+
if (!strip) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
revealStop(
|
|
455
|
+
Array.from(strip.querySelectorAll<HTMLElement>('[data-tab-value]')).find(
|
|
456
|
+
el => el.dataset.tabValue === value,
|
|
457
|
+
) ?? null,
|
|
458
|
+
);
|
|
459
|
+
}, [revealStop, value]);
|
|
460
|
+
|
|
461
|
+
// Both reveals below reach the callback through a ref instead of depending
|
|
462
|
+
// on it: its identity also changes with `overflow`, and that is not a reason
|
|
463
|
+
// to scroll anything.
|
|
464
|
+
const revealSelectedTabRef = useRef(revealSelectedTab);
|
|
465
|
+
useEffect(() => {
|
|
466
|
+
revealSelectedTabRef.current = revealSelectedTab;
|
|
467
|
+
}, [revealSelectedTab]);
|
|
468
|
+
|
|
469
|
+
// The tab you are on has to be visible. Selection can move without focus —
|
|
470
|
+
// on mount, or when the host sets `value` itself — and neither scrolls the
|
|
471
|
+
// strip the way clicking or arrowing to a tab does. The check is what makes
|
|
472
|
+
// a selection change the trigger, rather than the effect happening to run.
|
|
473
|
+
const revealedValueRef = useRef<string | null>(null);
|
|
474
|
+
useEffect(() => {
|
|
475
|
+
if (revealedValueRef.current === value) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
revealedValueRef.current = value;
|
|
479
|
+
revealSelectedTabRef.current();
|
|
480
|
+
}, [value]);
|
|
481
|
+
|
|
482
|
+
// ...and it has to stay visible when the strip is what moved. A strip that
|
|
483
|
+
// fitted at one width can hide the selected tab at a narrower one, and no
|
|
484
|
+
// prop changes when that happens. This one re-reveals the same selection by
|
|
485
|
+
// design, which is why the check above sits in the effect rather than in
|
|
486
|
+
// `revealSelectedTab`.
|
|
487
|
+
//
|
|
488
|
+
// The wrapper is observed rather than the strip because the shared observer
|
|
489
|
+
// keeps one callback per element and `useScrollOverflow` already holds the
|
|
490
|
+
// strip's.
|
|
491
|
+
useEffect(() => {
|
|
492
|
+
const root = listRef.current;
|
|
493
|
+
if (!hasScroll || !root) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const onResize = () => revealSelectedTabRef.current();
|
|
497
|
+
observeResize(root, onResize);
|
|
498
|
+
return () => unobserveResize(root);
|
|
499
|
+
}, [hasScroll, listRef]);
|
|
500
|
+
|
|
501
|
+
const scrollByPage = useCallback((direction: -1 | 1) => {
|
|
502
|
+
const strip = stripRef.current;
|
|
503
|
+
if (!strip) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
// Under RTL the scroll axis is inverted, so flip the physical delta.
|
|
507
|
+
const rtlSign = isRtlElement(strip) ? -1 : 1;
|
|
508
|
+
strip.scrollBy({
|
|
509
|
+
left: rtlSign * direction * strip.clientWidth * SCROLL_PAGE_RATIO,
|
|
510
|
+
});
|
|
511
|
+
}, []);
|
|
512
|
+
|
|
513
|
+
const scrollToStart = useCallback(() => scrollByPage(-1), [scrollByPage]);
|
|
514
|
+
const scrollToEnd = useCallback(() => scrollByPage(1), [scrollByPage]);
|
|
515
|
+
|
|
167
516
|
const contextValue = useMemo(
|
|
168
|
-
() => ({
|
|
169
|
-
|
|
517
|
+
() => ({
|
|
518
|
+
value,
|
|
519
|
+
onChange,
|
|
520
|
+
size,
|
|
521
|
+
layout,
|
|
522
|
+
pattern: isTabList ? ('tabs' as const) : ('nav' as const),
|
|
523
|
+
}),
|
|
524
|
+
[value, onChange, size, layout, isTabList],
|
|
170
525
|
);
|
|
171
526
|
|
|
172
527
|
const handleRootKeyDown = useCallback(
|
|
@@ -189,8 +544,12 @@ export function TabList({
|
|
|
189
544
|
}
|
|
190
545
|
onHintFocus(e);
|
|
191
546
|
handleFocus(e);
|
|
547
|
+
// The browser scrolls a focused element into view only when it is
|
|
548
|
+
// entirely outside the scrollport, so arrowing onto a half-visible stop
|
|
549
|
+
// leaves it cut off under the fade. Finish the job it started.
|
|
550
|
+
revealStop(e.target.closest(TAB_STOP_SELECTOR));
|
|
192
551
|
},
|
|
193
|
-
[onFocusProp, onHintFocus, handleFocus],
|
|
552
|
+
[onFocusProp, onHintFocus, handleFocus, revealStop],
|
|
194
553
|
);
|
|
195
554
|
|
|
196
555
|
const handleRootBlur = useCallback(
|
|
@@ -204,12 +563,58 @@ export function TabList({
|
|
|
204
563
|
[onBlurProp, onHintBlur],
|
|
205
564
|
);
|
|
206
565
|
|
|
566
|
+
// `role="tablist"` owns only tabs, so anything else in the strip is invalid
|
|
567
|
+
// markup. Dev-only, and only under the asserted role — nothing else in the
|
|
568
|
+
// component reads the rendered DOM.
|
|
569
|
+
const hasWarnedContentRef = useRef(false);
|
|
570
|
+
useEffect(() => {
|
|
571
|
+
const strip = stripRef.current;
|
|
572
|
+
if (
|
|
573
|
+
process.env.NODE_ENV === 'production' ||
|
|
574
|
+
!isTabList ||
|
|
575
|
+
!strip ||
|
|
576
|
+
hasWarnedContentRef.current
|
|
577
|
+
) {
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
const stranger = Array.from(strip.children).find(
|
|
581
|
+
child => child.getAttribute('role') !== 'tab',
|
|
582
|
+
);
|
|
583
|
+
if (stranger) {
|
|
584
|
+
hasWarnedContentRef.current = true;
|
|
585
|
+
devWarn(
|
|
586
|
+
'TabList',
|
|
587
|
+
`role="tablist" owns only tabs, but the strip contains a <${stranger.tagName.toLowerCase()}> that is not one. ` +
|
|
588
|
+
'Render menus and other controls outside the strip, or drop the role for the navigation pattern.',
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
// No dependency list: the check is on rendered DOM, which can change
|
|
592
|
+
// without any prop this component could watch.
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
const fadeStyle = !hasScroll
|
|
596
|
+
? null
|
|
597
|
+
: overflowStart && overflowEnd
|
|
598
|
+
? styles.fadeBoth
|
|
599
|
+
: overflowStart
|
|
600
|
+
? styles.fadeStart
|
|
601
|
+
: overflowEnd
|
|
602
|
+
? styles.fadeEnd
|
|
603
|
+
: null;
|
|
604
|
+
|
|
605
|
+
// A tablist is not navigation, so the landmark element is only right under
|
|
606
|
+
// the navigation pattern. The role is fixed by a prop rather than by what
|
|
607
|
+
// the strip happens to hold, so this is settled once at the callsite.
|
|
608
|
+
const Wrapper = isTabList ? 'div' : 'nav';
|
|
609
|
+
|
|
207
610
|
return (
|
|
208
611
|
<TabListContext value={contextValue}>
|
|
209
|
-
<
|
|
210
|
-
ref={
|
|
612
|
+
<Wrapper
|
|
613
|
+
ref={useMergedRefs(ref, listRef)}
|
|
211
614
|
{...restProps}
|
|
212
|
-
|
|
615
|
+
role={isTabList ? undefined : role}
|
|
616
|
+
aria-label={isTabList ? undefined : ariaLabel}
|
|
617
|
+
aria-labelledby={isTabList ? undefined : ariaLabelledBy}
|
|
213
618
|
onKeyDown={handleRootKeyDown}
|
|
214
619
|
onFocus={handleRootFocus}
|
|
215
620
|
onBlur={handleRootBlur}
|
|
@@ -225,9 +630,72 @@ export function TabList({
|
|
|
225
630
|
className,
|
|
226
631
|
style,
|
|
227
632
|
)}>
|
|
228
|
-
|
|
633
|
+
<div
|
|
634
|
+
ref={attachStrip}
|
|
635
|
+
role={isTabList ? 'tablist' : undefined}
|
|
636
|
+
aria-label={isTabList ? ariaLabel : undefined}
|
|
637
|
+
// The name belongs to whichever element carries the widget role.
|
|
638
|
+
aria-labelledby={isTabList ? ariaLabelledBy : undefined}
|
|
639
|
+
{...mergeProps(
|
|
640
|
+
themeProps('tab-strip'),
|
|
641
|
+
stylex.props(
|
|
642
|
+
styles.strip,
|
|
643
|
+
hasScroll && styles.stripScroll,
|
|
644
|
+
fadeStyle,
|
|
645
|
+
),
|
|
646
|
+
)}>
|
|
647
|
+
{children}
|
|
648
|
+
</div>
|
|
649
|
+
{hasScroll && overflowStart && (
|
|
650
|
+
<button
|
|
651
|
+
type="button"
|
|
652
|
+
aria-hidden="true"
|
|
653
|
+
tabIndex={-1}
|
|
654
|
+
// Nothing hidden from assistive technology should end up holding
|
|
655
|
+
// focus, and a click would put it here.
|
|
656
|
+
onMouseDown={preventFocus}
|
|
657
|
+
onClick={scrollToStart}
|
|
658
|
+
{...mergeProps(
|
|
659
|
+
themeProps('tab-scroll-button'),
|
|
660
|
+
focusOutlineProps.focusVisible(
|
|
661
|
+
styles.arrow,
|
|
662
|
+
styles.arrowStart,
|
|
663
|
+
arrowSizeStyles[size],
|
|
664
|
+
),
|
|
665
|
+
)}>
|
|
666
|
+
<Icon
|
|
667
|
+
icon="chevronLeft"
|
|
668
|
+
size="sm"
|
|
669
|
+
color="inherit"
|
|
670
|
+
xstyle={rtlStyles.mirror}
|
|
671
|
+
/>
|
|
672
|
+
</button>
|
|
673
|
+
)}
|
|
674
|
+
{hasScroll && overflowEnd && (
|
|
675
|
+
<button
|
|
676
|
+
type="button"
|
|
677
|
+
aria-hidden="true"
|
|
678
|
+
tabIndex={-1}
|
|
679
|
+
onMouseDown={preventFocus}
|
|
680
|
+
onClick={scrollToEnd}
|
|
681
|
+
{...mergeProps(
|
|
682
|
+
themeProps('tab-scroll-button'),
|
|
683
|
+
focusOutlineProps.focusVisible(
|
|
684
|
+
styles.arrow,
|
|
685
|
+
styles.arrowEnd,
|
|
686
|
+
arrowSizeStyles[size],
|
|
687
|
+
),
|
|
688
|
+
)}>
|
|
689
|
+
<Icon
|
|
690
|
+
icon="chevronRight"
|
|
691
|
+
size="sm"
|
|
692
|
+
color="inherit"
|
|
693
|
+
xstyle={rtlStyles.mirror}
|
|
694
|
+
/>
|
|
695
|
+
</button>
|
|
696
|
+
)}
|
|
229
697
|
{hintElement}
|
|
230
|
-
</
|
|
698
|
+
</Wrapper>
|
|
231
699
|
</TabListContext>
|
|
232
700
|
);
|
|
233
701
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @file TabListContext.ts
|
|
7
7
|
* @input React createContext, use
|
|
8
|
-
* @output Exports TabListContext, useTabListContext
|
|
8
|
+
* @output Exports TabListContext, useTabListContext, TabListPattern
|
|
9
9
|
* @position Context provider; consumed by Tab.tsx, TabMenu.tsx
|
|
10
10
|
*
|
|
11
11
|
* SYNC: When modified, update /packages/core/src/TabList/TabList.doc.mjs
|
|
@@ -27,13 +27,24 @@ export type TabListSize = 'sm' | 'md' | 'lg';
|
|
|
27
27
|
export type TabListLayout = 'hug' | 'fill';
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* ARIA pattern the strip resolved to.
|
|
31
|
+
* - `'nav'`: a `<nav>` of links or buttons, current item marked with
|
|
32
|
+
* `aria-current`.
|
|
33
|
+
* - `'tabs'`: the WAI-ARIA tabs pattern — `role="tablist"` / `role="tab"`,
|
|
34
|
+
* `aria-selected`, and `aria-controls` for the panel each tab owns.
|
|
35
|
+
*/
|
|
36
|
+
export type TabListPattern = 'nav' | 'tabs';
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Context for communicating value/onChange/size/layout and the resolved ARIA
|
|
40
|
+
* pattern from TabList to children.
|
|
31
41
|
*/
|
|
32
42
|
export interface TabListContextValue {
|
|
33
43
|
value: string;
|
|
34
44
|
onChange: (value: string) => void;
|
|
35
45
|
size: TabListSize;
|
|
36
46
|
layout: TabListLayout;
|
|
47
|
+
pattern: TabListPattern;
|
|
37
48
|
}
|
|
38
49
|
|
|
39
50
|
export const TabListContext = createContext<TabListContextValue | null>(null);
|
package/src/TabList/TabMenu.tsx
CHANGED
|
@@ -37,7 +37,8 @@ import {useListFocus} from '../hooks/useListFocus';
|
|
|
37
37
|
import {useTabListContext} from './TabListContext';
|
|
38
38
|
import type {TabListSize} from './TabListContext';
|
|
39
39
|
import {tabScope} from './tab.markers.stylex';
|
|
40
|
-
import {mergeProps
|
|
40
|
+
import {mergeProps} from '../utils';
|
|
41
|
+
import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
41
42
|
import type {BaseProps} from '../BaseProps';
|
|
42
43
|
import {themeProps} from '../utils/themeProps';
|
|
43
44
|
|
|
@@ -336,7 +337,7 @@ export function TabMenu({
|
|
|
336
337
|
[tabListCtx, popover],
|
|
337
338
|
);
|
|
338
339
|
|
|
339
|
-
const setButtonRef =
|
|
340
|
+
const setButtonRef = useMergedRefs<HTMLButtonElement>(
|
|
340
341
|
popover.triggerRef,
|
|
341
342
|
buttonRef,
|
|
342
343
|
ref,
|