@astryxdesign/core 0.4.6 → 0.4.7-canary.019ae5a
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 +37 -1
- 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.map +1 -1
- package/dist/Avatar/Avatar.js +15 -10
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.js +3 -2
- 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 +1 -0
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +54 -15
- package/dist/BottomSheet/BottomSheetEdgeTint.d.ts +6 -0
- package/dist/BottomSheet/BottomSheetEdgeTint.d.ts.map +1 -0
- package/dist/BottomSheet/BottomSheetEdgeTint.js +62 -0
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +1 -0
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts +1 -0
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +13 -6
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +23 -5
- 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 +5 -4
- 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 +13 -14
- 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/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 +3 -2
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +3 -3
- 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.map +1 -1
- package/dist/DateInput/DateInput.js +3 -2
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +38 -4
- 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 +7 -1
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +89 -58
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +6 -5
- 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/useHoverCard.d.ts +5 -0
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +67 -25
- 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 +10 -3
- 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/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 +177 -29
- 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 +15 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +17 -6
- package/dist/MultiSelector/index.d.ts +1 -1
- package/dist/MultiSelector/index.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +3 -2
- 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 +19 -9
- 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/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.map +1 -1
- package/dist/Selector/Selector.js +5 -0
- 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 +6 -5
- 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 +3 -3
- 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/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 +3 -2
- package/dist/TabList/Tab.d.ts +15 -2
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +32 -3
- 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 +4 -1
- 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/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/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 +3 -2
- 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/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 +3 -2
- 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 +72 -2
- 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 +10 -3
- package/dist/hooks/useListFocus.d.ts +5 -2
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +12 -6
- 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/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/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 +31 -7
- package/locales/pseudo.json +18 -0
- package/package.json +8 -3
- 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 +2 -1
- package/src/Avatar/Avatar.test.tsx +17 -0
- package/src/Avatar/Avatar.tsx +61 -38
- package/src/AvatarGroup/AvatarGroup.tsx +3 -2
- 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 +36 -4
- package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +225 -0
- package/src/BottomSheet/BottomSheetEdgeTint.tsx +82 -0
- package/src/BottomSheet/BottomSheetPanel.test.tsx +66 -0
- package/src/BottomSheet/BottomSheetPanel.tsx +19 -0
- package/src/BottomSheet/BottomSheetSwitcher.tsx +16 -2
- package/src/BottomSheet/useSheetGestures.test.ts +27 -0
- package/src/BottomSheet/useSheetGestures.ts +25 -5
- package/src/Breadcrumbs/BreadcrumbItem.tsx +9 -5
- package/src/Button/Button.doc.mjs +22 -0
- package/src/Button/Button.test.tsx +13 -0
- package/src/Button/Button.tsx +5 -4
- package/src/ButtonGroup/ButtonGroup.doc.mjs +10 -1
- package/src/ButtonGroup/ButtonGroup.test.tsx +391 -1
- package/src/ButtonGroup/ButtonGroup.tsx +23 -5
- package/src/Calendar/Calendar.doc.mjs +4 -3
- package/src/Calendar/Calendar.test.tsx +52 -0
- package/src/Calendar/Calendar.tsx +18 -15
- package/src/Calendar/getInitialFocusDate.test.ts +94 -0
- package/src/Calendar/getInitialFocusDate.ts +93 -0
- 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.tsx +3 -2
- package/src/ClickableCard/ClickableCard.tsx +3 -2
- package/src/CodeBlock/CodeBlock.doc.mjs +6 -0
- 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.tsx +3 -2
- package/src/DateInput/DateInputTouch.test.tsx +36 -0
- package/src/DateInput/TouchDateField.tsx +38 -4
- 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 +261 -1
- package/src/Dialog/Dialog.tsx +109 -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/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 +5 -0
- package/src/HoverCard/HoverCard.tsx +6 -0
- package/src/HoverCard/useHoverCard.tsx +81 -30
- package/src/Item/Item.tsx +5 -4
- package/src/Kbd/Kbd.test.tsx +17 -0
- package/src/Kbd/Kbd.tsx +10 -3
- 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/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/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 +145 -2
- package/src/Markdown/parser.ts +244 -29
- package/src/MobileNav/MobileNav.tsx +62 -36
- package/src/MoreMenu/MoreMenu.doc.mjs +7 -1
- package/src/MultiSelector/MultiSelector.doc.mjs +27 -0
- package/src/MultiSelector/MultiSelector.test.tsx +106 -0
- package/src/MultiSelector/MultiSelector.tsx +50 -6
- package/src/MultiSelector/index.ts +1 -0
- package/src/NavMenu/NavHeadingMenu.tsx +3 -2
- package/src/NumberInput/NumberInput.doc.mjs +5 -0
- package/src/Outline/Outline.tsx +3 -2
- package/src/OverflowList/OverflowList.tsx +3 -2
- package/src/Overlay/Overlay.tsx +3 -2
- package/src/Popover/Popover.test.tsx +27 -1
- 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 +201 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +29 -2
- package/src/PowerSearch/PowerSearchValueEditor.test.tsx +47 -1
- package/src/PowerSearch/PowerSearchValueEditor.tsx +15 -0
- package/src/PowerSearch/types.ts +2 -0
- package/src/PowerSearch/usePowerSearchSource.test.ts +82 -2
- package/src/PowerSearch/usePowerSearchSource.ts +13 -3
- 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 +12 -1
- package/src/Selector/Selector.test.tsx +45 -1
- package/src/Selector/Selector.tsx +11 -1
- package/src/SideNav/SideNav.doc.mjs +6 -6
- package/src/SideNav/SideNav.tsx +4 -2
- package/src/SideNav/SideNavHeading.tsx +10 -10
- package/src/SideNav/SideNavItem.tsx +4 -2
- package/src/Slider/Slider.tsx +3 -2
- package/src/Spinner/Spinner.test.tsx +147 -1
- package/src/Spinner/Spinner.tsx +120 -101
- 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.tsx +3 -2
- package/src/TabList/Tab.doc.mjs +13 -1
- package/src/TabList/Tab.tsx +67 -3
- package/src/TabList/TabList.doc.mjs +22 -6
- package/src/TabList/TabList.test.tsx +580 -4
- 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 +6 -3
- package/src/Table/Table.doc.mjs +6 -1
- package/src/Table/Table.test.tsx +132 -14
- 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/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/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.tsx +3 -2
- 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.tsx +4 -2
- package/src/Toast/Toast.doc.mjs +6 -0
- 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 +3 -2
- 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.test.ts +18 -0
- package/src/hooks/useHotkeys.ts +10 -3
- package/src/hooks/useListFocus.doc.mjs +2 -2
- package/src/hooks/useListFocus.test.tsx +65 -3
- package/src/hooks/useListFocus.ts +15 -7
- 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/theme/MediaTheme.doc.mjs +5 -5
- package/src/utils/groupItems.ts +12 -6
- package/src/utils/index.ts +1 -1
- 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
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file Stepper.tsx
|
|
7
|
+
* @input Uses React, stylex, theme tokens, StepperContext
|
|
8
|
+
* @output Exports Stepper component and StepperProps
|
|
9
|
+
* @position Core container component; consumed by index.ts
|
|
10
|
+
*
|
|
11
|
+
* Besides the props it is given, this component tracks the `activeStep` it
|
|
12
|
+
* last rendered with and publishes it on the context. Steps need the distance
|
|
13
|
+
* and direction of a change to choreograph their connector fill; see the
|
|
14
|
+
* CONNECTOR FILL block in Step.tsx.
|
|
15
|
+
*
|
|
16
|
+
* SYNC: When modified, update these files to stay in sync:
|
|
17
|
+
* - /packages/core/src/Stepper/Stepper.doc.mjs (props table, features, implementation notes)
|
|
18
|
+
* - /packages/core/src/Stepper/Stepper.test.tsx (tests for new/changed behavior)
|
|
19
|
+
* - /packages/core/src/Stepper/index.ts (exports if types change)
|
|
20
|
+
* - /apps/storybook/stories/Stepper.stories.tsx (storybook stories)
|
|
21
|
+
* - /packages/cli/assets/templates/blocks/components/Stepper/ (showcase blocks)
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import {useCallback, useMemo, useRef, useState, type ReactNode} from 'react';
|
|
25
|
+
import * as stylex from '@stylexjs/stylex';
|
|
26
|
+
|
|
27
|
+
import {spacingVars} from '../theme/tokens.stylex';
|
|
28
|
+
import {mergeProps} from '../utils';
|
|
29
|
+
import type {BaseProps} from '../BaseProps';
|
|
30
|
+
import {themeProps} from '../utils';
|
|
31
|
+
import {useTranslator} from '../i18n';
|
|
32
|
+
import {
|
|
33
|
+
StepperContext,
|
|
34
|
+
type StepperOrientation,
|
|
35
|
+
type StepperIndicatorPosition,
|
|
36
|
+
type StepperContextValue,
|
|
37
|
+
} from './StepperContext';
|
|
38
|
+
|
|
39
|
+
export interface StepperProps extends BaseProps<HTMLOListElement> {
|
|
40
|
+
/** Ref forwarded to the root element */
|
|
41
|
+
ref?: React.Ref<HTMLOListElement>;
|
|
42
|
+
/**
|
|
43
|
+
* Zero-based index of the active step.
|
|
44
|
+
*/
|
|
45
|
+
activeStep: number;
|
|
46
|
+
/**
|
|
47
|
+
* Step elements to render.
|
|
48
|
+
*/
|
|
49
|
+
children: ReactNode;
|
|
50
|
+
/**
|
|
51
|
+
* Layout direction of the stepper.
|
|
52
|
+
* @default 'horizontal'
|
|
53
|
+
*/
|
|
54
|
+
orientation?: StepperOrientation;
|
|
55
|
+
/**
|
|
56
|
+
* Called when a step indicator is clicked. Enables non-linear navigation.
|
|
57
|
+
* When provided, completed and current steps become clickable.
|
|
58
|
+
*/
|
|
59
|
+
onStepClick?: (index: number) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Accessible label describing the set of steps. Defaults to a translated
|
|
62
|
+
* "Progress" when unset.
|
|
63
|
+
*/
|
|
64
|
+
label?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Controls density (padding) of all steps.
|
|
67
|
+
* @default 'balanced'
|
|
68
|
+
*/
|
|
69
|
+
density?: 'compact' | 'balanced' | 'spacious';
|
|
70
|
+
/**
|
|
71
|
+
* Controls where each step's indicator sits relative to the connector track.
|
|
72
|
+
* - 'separated': indicator lives in the label row, distinct from the progress
|
|
73
|
+
* bar (the original Astryx layout).
|
|
74
|
+
* - 'on-track': indicator is slotted into the connector line as a node on the
|
|
75
|
+
* track (the on-track indicator design).
|
|
76
|
+
* @default 'separated'
|
|
77
|
+
*/
|
|
78
|
+
indicatorPosition?: StepperIndicatorPosition;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const styles = stylex.create({
|
|
82
|
+
root: {
|
|
83
|
+
display: 'flex',
|
|
84
|
+
width: '100%',
|
|
85
|
+
listStyleType: 'none',
|
|
86
|
+
margin: 0,
|
|
87
|
+
padding: 0,
|
|
88
|
+
},
|
|
89
|
+
horizontal: {
|
|
90
|
+
flexDirection: 'row',
|
|
91
|
+
alignItems: 'flex-start',
|
|
92
|
+
gap: spacingVars['--spacing-0-5'],
|
|
93
|
+
},
|
|
94
|
+
vertical: {
|
|
95
|
+
flexDirection: 'column',
|
|
96
|
+
gap: spacingVars['--spacing-0-5'],
|
|
97
|
+
},
|
|
98
|
+
// On-track: steps must abut so their connector segments form one continuous
|
|
99
|
+
// line, so the inter-step gap collapses to zero.
|
|
100
|
+
horizontalOnTrack: {
|
|
101
|
+
flexDirection: 'row',
|
|
102
|
+
alignItems: 'flex-start',
|
|
103
|
+
gap: 0,
|
|
104
|
+
},
|
|
105
|
+
verticalOnTrack: {
|
|
106
|
+
flexDirection: 'column',
|
|
107
|
+
gap: 0,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* A stepper component for multi-step workflows. Displays numbered steps
|
|
113
|
+
* with visual indicators for completed, active, and upcoming states.
|
|
114
|
+
*
|
|
115
|
+
* Each Step child must provide a `step` prop (zero-based index) so it
|
|
116
|
+
* can derive its state from the parent's activeStep. The on-track layout
|
|
117
|
+
* hides the leading connector on the first step and the trailing connector
|
|
118
|
+
* on the last step structurally, from each step's own `<li>` position, so
|
|
119
|
+
* it works regardless of how the steps are grouped.
|
|
120
|
+
*
|
|
121
|
+
* Rendered as an ordered list (`<ol>`/`<li>`) rather than a `nav`
|
|
122
|
+
* landmark: a stepper communicates *progress through a sequence*, not a
|
|
123
|
+
* set of site navigation links. The active step is marked with
|
|
124
|
+
* `aria-current="step"` (handled per-step) and the list carries an
|
|
125
|
+
* accessible `label`. This follows the WAI-ARIA pattern for steppers /
|
|
126
|
+
* progress sequences and avoids polluting the page's landmark map.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```
|
|
130
|
+
* <Stepper activeStep={1}>
|
|
131
|
+
* <Step step={0} label="Account" />
|
|
132
|
+
* <Step step={1} label="Profile" />
|
|
133
|
+
* <Step step={2} label="Review" />
|
|
134
|
+
* </Stepper>
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export function Stepper({
|
|
138
|
+
activeStep,
|
|
139
|
+
children,
|
|
140
|
+
orientation = 'horizontal',
|
|
141
|
+
onStepClick,
|
|
142
|
+
label: labelFromProps,
|
|
143
|
+
density = 'balanced',
|
|
144
|
+
indicatorPosition = 'separated',
|
|
145
|
+
xstyle,
|
|
146
|
+
className,
|
|
147
|
+
style,
|
|
148
|
+
ref,
|
|
149
|
+
...rest
|
|
150
|
+
}: StepperProps) {
|
|
151
|
+
const t = useTranslator();
|
|
152
|
+
const label = labelFromProps ?? t('@astryx.stepper.label');
|
|
153
|
+
|
|
154
|
+
// Dev-mode duplicate step index detection. Steps register on mount and
|
|
155
|
+
// deregister on unmount; a Map tracks count per index so we can warn when
|
|
156
|
+
// two Steps share the same `step` value (which breaks aria-current).
|
|
157
|
+
const stepCountsRef = useRef<Map<number, number>>(new Map());
|
|
158
|
+
const registerStep = useCallback((index: number) => {
|
|
159
|
+
const counts = stepCountsRef.current;
|
|
160
|
+
const prev = counts.get(index) ?? 0;
|
|
161
|
+
counts.set(index, prev + 1);
|
|
162
|
+
if (process.env.NODE_ENV !== 'production' && prev + 1 > 1) {
|
|
163
|
+
console.warn(
|
|
164
|
+
`[Stepper] Duplicate step index ${index}: two <Step> elements share the same \`step\` value. ` +
|
|
165
|
+
`This breaks \`aria-current="step"\` and causes both to show as active simultaneously.`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
return () => {
|
|
169
|
+
const cur = counts.get(index) ?? 1;
|
|
170
|
+
if (cur <= 1) {
|
|
171
|
+
counts.delete(index);
|
|
172
|
+
} else {
|
|
173
|
+
counts.set(index, cur - 1);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}, []);
|
|
177
|
+
|
|
178
|
+
// The step we came *from*. Steps need it to stagger their connector fill:
|
|
179
|
+
// the distance and direction of the change decide which segment moves first
|
|
180
|
+
// and how long the whole sweep may take (see Step.tsx's CONNECTOR FILL).
|
|
181
|
+
//
|
|
182
|
+
// Derived during render from state rather than written in an effect. An
|
|
183
|
+
// effect runs after paint, so the browser would already have committed the
|
|
184
|
+
// new fill states with last render's delays — the first frame of the sweep
|
|
185
|
+
// would be wrong, and on a jump of one that is the entire animation. React
|
|
186
|
+
// discards and re-runs a render that sets its own state before committing,
|
|
187
|
+
// so this costs a re-render but never a wrong frame.
|
|
188
|
+
//
|
|
189
|
+
// Seeding both halves from the current `activeStep` is what suppresses the
|
|
190
|
+
// cascade on mount: a stepper that opens on step 3 has no previous step to
|
|
191
|
+
// have travelled from, so its completed segments paint filled at once. That
|
|
192
|
+
// also makes the first render pure and identical on the server, so there is
|
|
193
|
+
// nothing for hydration to disagree about. Storing the pair in one state
|
|
194
|
+
// object keeps the update idempotent under StrictMode's double render — both
|
|
195
|
+
// invocations read the same `seen` and queue the same successor.
|
|
196
|
+
const [seen, setSeen] = useState(() => ({
|
|
197
|
+
current: activeStep,
|
|
198
|
+
previous: activeStep,
|
|
199
|
+
}));
|
|
200
|
+
if (seen.current !== activeStep) {
|
|
201
|
+
setSeen({current: activeStep, previous: seen.current});
|
|
202
|
+
}
|
|
203
|
+
const previousActiveStep =
|
|
204
|
+
seen.current === activeStep ? seen.previous : seen.current;
|
|
205
|
+
|
|
206
|
+
const ctxValue = useMemo<StepperContextValue>(
|
|
207
|
+
() => ({
|
|
208
|
+
activeStep,
|
|
209
|
+
previousActiveStep,
|
|
210
|
+
orientation,
|
|
211
|
+
isNonLinear: onStepClick != null,
|
|
212
|
+
onStepClick: onStepClick ?? null,
|
|
213
|
+
density,
|
|
214
|
+
indicatorPosition,
|
|
215
|
+
registerStep,
|
|
216
|
+
}),
|
|
217
|
+
[
|
|
218
|
+
activeStep,
|
|
219
|
+
previousActiveStep,
|
|
220
|
+
orientation,
|
|
221
|
+
onStepClick,
|
|
222
|
+
density,
|
|
223
|
+
indicatorPosition,
|
|
224
|
+
registerStep,
|
|
225
|
+
],
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const isOnTrack = indicatorPosition === 'on-track';
|
|
229
|
+
const orientationStyle =
|
|
230
|
+
orientation === 'horizontal'
|
|
231
|
+
? isOnTrack
|
|
232
|
+
? styles.horizontalOnTrack
|
|
233
|
+
: styles.horizontal
|
|
234
|
+
: isOnTrack
|
|
235
|
+
? styles.verticalOnTrack
|
|
236
|
+
: styles.vertical;
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<StepperContext value={ctxValue}>
|
|
240
|
+
<ol
|
|
241
|
+
ref={ref}
|
|
242
|
+
aria-label={label}
|
|
243
|
+
{...rest}
|
|
244
|
+
{...mergeProps(
|
|
245
|
+
themeProps('stepper', {orientation, indicatorPosition}),
|
|
246
|
+
stylex.props(styles.root, orientationStyle, xstyle),
|
|
247
|
+
className,
|
|
248
|
+
style,
|
|
249
|
+
)}>
|
|
250
|
+
{/* Each step renders its own progress bar segment; no child
|
|
251
|
+
introspection needed — steps derive state from context. */}
|
|
252
|
+
{children}
|
|
253
|
+
</ol>
|
|
254
|
+
</StepperContext>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
Stepper.displayName = 'Stepper';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file StepperContext.ts
|
|
7
|
+
* @input Uses React createContext/use
|
|
8
|
+
* @output Exports StepperContext, useStepperContext, and context types
|
|
9
|
+
* @position Context for Stepper <-> Step communication
|
|
10
|
+
*
|
|
11
|
+
* SYNC: When modified, update these files to stay in sync:
|
|
12
|
+
* - /packages/core/src/Stepper/Stepper.doc.mjs
|
|
13
|
+
* - /packages/core/src/Stepper/index.ts
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {createContext, use} from 'react';
|
|
17
|
+
|
|
18
|
+
export type StepperOrientation = 'horizontal' | 'vertical';
|
|
19
|
+
export type StepperDensity = 'compact' | 'balanced' | 'spacious';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Controls where each step's indicator sits relative to the connector track.
|
|
23
|
+
* - 'separated': indicator lives in the label row, distinct from the progress
|
|
24
|
+
* bar (Astryx's original layout).
|
|
25
|
+
* - 'on-track': indicator is slotted *into* the connector line as a node on the
|
|
26
|
+
* track, with the label beside (vertical) or below (horizontal). Aligns with
|
|
27
|
+
* the on-track stepper design.
|
|
28
|
+
*/
|
|
29
|
+
export type StepperIndicatorPosition = 'separated' | 'on-track';
|
|
30
|
+
|
|
31
|
+
export interface StepperContextValue {
|
|
32
|
+
activeStep: number;
|
|
33
|
+
/**
|
|
34
|
+
* The `activeStep` this stepper last rendered with, so a Step can tell
|
|
35
|
+
* whether the change it is reacting to was a single step forward — the one
|
|
36
|
+
* change that animates the connector fill — and which span that change
|
|
37
|
+
* crossed (see the CONNECTOR FILL block in Step.tsx). Equal to `activeStep`
|
|
38
|
+
* on the first render, which is what keeps a stepper that mounts mid-flow
|
|
39
|
+
* from animating its way to the step it opened on.
|
|
40
|
+
*
|
|
41
|
+
* Internal: not part of the public API, and deliberately not a Stepper prop.
|
|
42
|
+
* When the connector animates is behaviour the stepper owns, not something a
|
|
43
|
+
* consumer configures.
|
|
44
|
+
*/
|
|
45
|
+
previousActiveStep: number;
|
|
46
|
+
orientation: StepperOrientation;
|
|
47
|
+
isNonLinear: boolean;
|
|
48
|
+
onStepClick: ((index: number) => void) | null;
|
|
49
|
+
density: StepperDensity;
|
|
50
|
+
indicatorPosition: StepperIndicatorPosition;
|
|
51
|
+
/**
|
|
52
|
+
* Dev-mode index registration. Each Step calls this on mount with its `step`
|
|
53
|
+
* index. The Stepper tracks the set and warns if two Steps share the same
|
|
54
|
+
* index. Returns a cleanup function to call on unmount.
|
|
55
|
+
*/
|
|
56
|
+
registerStep: (index: number) => () => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const StepperContext = createContext<StepperContextValue | null>(null);
|
|
60
|
+
StepperContext.displayName = 'StepperContext';
|
|
61
|
+
|
|
62
|
+
export function useStepperContext(): StepperContextValue {
|
|
63
|
+
const ctx = use(StepperContext);
|
|
64
|
+
if (ctx == null) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
'useStepperContext must be used within Stepper. ' +
|
|
67
|
+
'Wrap your Step in <Stepper>.',
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
return ctx;
|
|
71
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
export {Stepper} from './Stepper';
|
|
6
|
+
export type {StepperProps} from './Stepper';
|
|
7
|
+
|
|
8
|
+
export {Step} from './Step';
|
|
9
|
+
export type {StepProps, StepIndicatorPreset} from './Step';
|
|
10
|
+
|
|
11
|
+
export type {StepStatus} from './StepStatus';
|
|
12
|
+
|
|
13
|
+
export {useStepperContext} from './StepperContext';
|
|
14
|
+
export type {
|
|
15
|
+
StepperContextValue,
|
|
16
|
+
StepperOrientation,
|
|
17
|
+
StepperIndicatorPosition,
|
|
18
|
+
} from './StepperContext';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file stepper.stylex.ts
|
|
5
|
+
* @input StyleX marker system
|
|
6
|
+
* @output stepMarker — a scoped marker applied to each Step's <li>
|
|
7
|
+
* @position Shared StyleX marker consumed by Step for structural selectors
|
|
8
|
+
*
|
|
9
|
+
* Applied to each Step's root `<li>` so the on-track connector segments can
|
|
10
|
+
* key their first/last-node visibility off `stylex.when.ancestor(':first-child'
|
|
11
|
+
* | ':last-child', stepMarker)` — matching only the parent step row, never the
|
|
12
|
+
* outer `<ol>`. This replaces counting children in the parent, so steps behave
|
|
13
|
+
* correctly regardless of how the consumer groups them (arrays, fragments).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import * as stylex from '@stylexjs/stylex';
|
|
17
|
+
|
|
18
|
+
export const stepMarker: ReturnType<typeof stylex.defineMarker> =
|
|
19
|
+
stylex.defineMarker();
|
package/src/Switch/Switch.tsx
CHANGED
|
@@ -41,7 +41,7 @@ import type {IconType} from '../Icon';
|
|
|
41
41
|
import type {InputStatus} from '../Field/types';
|
|
42
42
|
import {Spinner} from '../Spinner';
|
|
43
43
|
import {useTooltip} from '../Tooltip';
|
|
44
|
-
import {mergeProps
|
|
44
|
+
import {mergeProps} from '../utils';
|
|
45
45
|
import {switchScope} from './switch.markers.stylex';
|
|
46
46
|
import type {BaseProps} from '../BaseProps';
|
|
47
47
|
import type {SizeValue} from '../utils/types';
|
|
@@ -49,6 +49,7 @@ import {themeProps} from '../utils/themeProps';
|
|
|
49
49
|
import {VisuallyHidden} from '../VisuallyHidden';
|
|
50
50
|
import {useResolvedRequired} from '../hooks/useResolvedRequired';
|
|
51
51
|
|
|
52
|
+
import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
52
53
|
const wrapperSizeStyles = stylex.create({
|
|
53
54
|
sm: {
|
|
54
55
|
width: 32,
|
|
@@ -551,7 +552,7 @@ export function Switch({
|
|
|
551
552
|
const switchElement = (
|
|
552
553
|
<div {...stylex.props(styles.switchWrapper, wrapperSizeStyles[size])}>
|
|
553
554
|
<input
|
|
554
|
-
ref={
|
|
555
|
+
ref={useMergedRefs(ref, disabledMessageTooltip.positionRef)}
|
|
555
556
|
id={id}
|
|
556
557
|
type="checkbox"
|
|
557
558
|
role="switch"
|
package/src/TabList/Tab.doc.mjs
CHANGED
|
@@ -40,7 +40,13 @@ export const docs = {
|
|
|
40
40
|
name: 'href',
|
|
41
41
|
type: 'string',
|
|
42
42
|
description:
|
|
43
|
-
'URL to navigate to; when provided, the tab renders as an anchor element.',
|
|
43
|
+
'URL to navigate to; when provided, the tab renders as an anchor element. Ignored in a TabList given an explicit role="tablist".',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'panelId',
|
|
47
|
+
type: 'string',
|
|
48
|
+
description:
|
|
49
|
+
'Id of the panel this tab controls, wired up as aria-controls where the TabList speaks the tabs pattern. Put the same id on the panel element. No effect under the navigation pattern, and a development warning says so.',
|
|
44
50
|
},
|
|
45
51
|
{
|
|
46
52
|
name: 'as',
|
|
@@ -138,6 +144,12 @@ export const docsZh = {
|
|
|
138
144
|
type: 'string',
|
|
139
145
|
description: '要导航到的 URL;提供时,标签渲染为锚点元素。',
|
|
140
146
|
},
|
|
147
|
+
{
|
|
148
|
+
name: 'panelId',
|
|
149
|
+
type: 'string',
|
|
150
|
+
description:
|
|
151
|
+
'Id of the panel this tab controls, wired up as aria-controls where the TabList speaks the tabs pattern. Put the same id on the panel element. No effect under the navigation pattern, and a development warning says so.',
|
|
152
|
+
},
|
|
141
153
|
{
|
|
142
154
|
name: 'as',
|
|
143
155
|
type: 'LinkComponentType',
|
package/src/TabList/Tab.tsx
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* @input Uses React, StyleX, TabListContext
|
|
8
8
|
* @output Exports Tab component and TabProps type
|
|
9
9
|
* @position Core tab item; renders as button or anchor in navigation with a
|
|
10
|
-
* divider-overlay selected indicator
|
|
10
|
+
* divider-overlay selected indicator. Where the TabList speaks the tabs
|
|
11
|
+
* pattern it is a button with role="tab".
|
|
11
12
|
*
|
|
12
13
|
* SYNC: When modified, update:
|
|
13
14
|
* - /packages/core/src/TabList/TabList.doc.mjs
|
|
@@ -35,6 +36,7 @@ import {tabScope} from './tab.markers.stylex';
|
|
|
35
36
|
import {useLinkComponent} from '../Link/useLinkComponent';
|
|
36
37
|
import type {LinkComponentType} from '../Link/types';
|
|
37
38
|
import {mergeProps} from '../utils';
|
|
39
|
+
import {useDevWarning} from '../hooks/useDevWarning';
|
|
38
40
|
import {EDGE_COMP_ATTR} from '../Layout/edgeCompensation.stylex';
|
|
39
41
|
import {themeProps} from '../utils/themeProps';
|
|
40
42
|
import {focusOutlineProps} from '../utils/focusOutline.stylex';
|
|
@@ -64,8 +66,20 @@ export interface TabProps extends BaseProps<HTMLButtonElement> {
|
|
|
64
66
|
isLabelHidden?: boolean;
|
|
65
67
|
/**
|
|
66
68
|
* URL to navigate to. When provided, renders as an anchor element.
|
|
69
|
+
*
|
|
70
|
+
* Ignored in a TabList given an explicit `role="tablist"`: activating a tab
|
|
71
|
+
* there swaps a panel in place, so a tab that navigates would be a false
|
|
72
|
+
* statement.
|
|
67
73
|
*/
|
|
68
74
|
href?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Id of the panel this tab controls, wired up as `aria-controls` where the
|
|
77
|
+
* TabList speaks the tabs pattern. Put the same id on the panel element.
|
|
78
|
+
*
|
|
79
|
+
* Has no effect under the navigation pattern, where there is no panel to
|
|
80
|
+
* associate — a development warning says so.
|
|
81
|
+
*/
|
|
82
|
+
panelId?: string;
|
|
69
83
|
/**
|
|
70
84
|
* Icon element shown when tab is not selected.
|
|
71
85
|
*/
|
|
@@ -228,6 +242,7 @@ export function Tab({
|
|
|
228
242
|
label,
|
|
229
243
|
isLabelHidden = false,
|
|
230
244
|
href,
|
|
245
|
+
panelId,
|
|
231
246
|
icon,
|
|
232
247
|
selectedIcon,
|
|
233
248
|
endContent,
|
|
@@ -242,6 +257,9 @@ export function Tab({
|
|
|
242
257
|
const isSelected = tabListCtx.value === value;
|
|
243
258
|
const size: TabListSize = tabListCtx.size;
|
|
244
259
|
const isFill = tabListCtx.layout === 'fill';
|
|
260
|
+
const isTabsPattern = tabListCtx.pattern === 'tabs';
|
|
261
|
+
const isLink = href != null && !isTabsPattern;
|
|
262
|
+
const isTabRole = isTabsPattern && !isLink;
|
|
245
263
|
const displayIcon = isSelected && selectedIcon ? selectedIcon : icon;
|
|
246
264
|
const hasVisibleLabel = !isLabelHidden && label !== '';
|
|
247
265
|
|
|
@@ -249,6 +267,34 @@ export function Tab({
|
|
|
249
267
|
tabListCtx.onChange(value);
|
|
250
268
|
}, [tabListCtx, value]);
|
|
251
269
|
|
|
270
|
+
useDevWarning(
|
|
271
|
+
'Tab',
|
|
272
|
+
'href is ignored in a role="tablist" TabList — a tab swaps a panel in ' +
|
|
273
|
+
'place rather than navigating. Drop the href, or drop the role for the ' +
|
|
274
|
+
'navigation pattern.',
|
|
275
|
+
isTabRole && href != null,
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
// A consumer who wired aria-controls by hand already said which panel this
|
|
279
|
+
// is, so panelId is the sugar, not the only way in.
|
|
280
|
+
const controls = panelId ?? restProps['aria-controls'];
|
|
281
|
+
|
|
282
|
+
useDevWarning(
|
|
283
|
+
'Tab',
|
|
284
|
+
'a tab in a role="tablist" TabList controls nothing: pass panelId with ' +
|
|
285
|
+
'the id of the panel it opens, so assistive technology can associate ' +
|
|
286
|
+
'the two.',
|
|
287
|
+
isTabRole && controls == null,
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
useDevWarning(
|
|
291
|
+
'Tab',
|
|
292
|
+
'panelId does nothing outside a role="tablist" TabList — the navigation ' +
|
|
293
|
+
'pattern has no panel to associate. Give the TabList role="tablist", ' +
|
|
294
|
+
'or drop the panelId.',
|
|
295
|
+
!isTabsPattern && panelId != null,
|
|
296
|
+
);
|
|
297
|
+
|
|
252
298
|
const iconElement = displayIcon ? (
|
|
253
299
|
<span {...stylex.props(styles.icon, iconSizeStyles[size])}>
|
|
254
300
|
{displayIcon}
|
|
@@ -260,7 +306,25 @@ export function Tab({
|
|
|
260
306
|
...(isLabelHidden ? {'aria-label': label} : {}),
|
|
261
307
|
[EDGE_COMP_ATTR]: '',
|
|
262
308
|
'data-tab-value': value,
|
|
263
|
-
|
|
309
|
+
...(isTabRole
|
|
310
|
+
? {
|
|
311
|
+
role: 'tab' as const,
|
|
312
|
+
'aria-selected': isSelected,
|
|
313
|
+
// Only when there is a panel to point at: an aria-controls whose
|
|
314
|
+
// target does not exist is an invalid attribute value, which is a
|
|
315
|
+
// worse state than saying nothing. The dev warning above asks for
|
|
316
|
+
// the id instead.
|
|
317
|
+
'aria-controls': controls,
|
|
318
|
+
}
|
|
319
|
+
: {
|
|
320
|
+
// Generic `true` ("the current item within a set"), not `page`: the
|
|
321
|
+
// strip switches views in place at least as often as it navigates,
|
|
322
|
+
// and claiming "current page" when no page changed is a false
|
|
323
|
+
// statement to a screen reader. Stays truthful for the `href` case
|
|
324
|
+
// too, just less specific. A tab role states this with
|
|
325
|
+
// aria-selected instead.
|
|
326
|
+
'aria-current': isSelected ? ('true' as const) : undefined,
|
|
327
|
+
}),
|
|
264
328
|
// Roving tabindex: the tab strip is a single Tab stop. The selected tab is
|
|
265
329
|
// the tabbable one; the rest are reachable via arrow keys (handled by
|
|
266
330
|
// TabList's onKeyDown). When no tab is selected, TabList's repair effect
|
|
@@ -317,7 +381,7 @@ export function Tab({
|
|
|
317
381
|
<span {...stylex.props(styles.endContentWrapper)}>{endContent}</span>
|
|
318
382
|
) : null;
|
|
319
383
|
|
|
320
|
-
if (
|
|
384
|
+
if (isLink) {
|
|
321
385
|
return (
|
|
322
386
|
<LinkComponent
|
|
323
387
|
ref={ref}
|
|
@@ -16,6 +16,8 @@ export const docs = {
|
|
|
16
16
|
theming: {
|
|
17
17
|
targets: [
|
|
18
18
|
{className: 'astryx-tab-list', visualProps: ['size']},
|
|
19
|
+
{className: 'astryx-tab-strip'},
|
|
20
|
+
{className: 'astryx-tab-scroll-button'},
|
|
19
21
|
{className: 'astryx-tab', states: ['selected']},
|
|
20
22
|
{className: 'astryx-tab-indicator', states: ['selected']},
|
|
21
23
|
{className: 'astryx-tab-menu'},
|
|
@@ -26,7 +28,7 @@ export const docs = {
|
|
|
26
28
|
{name: '--_tab-indicator-bottom', description: 'Vertical offset of the selected-tab indicator from the tab bottom edge. A host that draws its own bottom divider (Toolbar) sets this so the indicator sits on the divider instead of above it.', default: '-1px', private: true},
|
|
27
29
|
],
|
|
28
30
|
},
|
|
29
|
-
description: '
|
|
31
|
+
description: 'Tab strip that provides TabListContext (value, onChange, size) to Tab and TabMenu children; a nav landmark, or the WAI-ARIA tabs pattern where role="tablist" asks for it.',
|
|
30
32
|
props: [
|
|
31
33
|
{
|
|
32
34
|
name: 'value',
|
|
@@ -58,10 +60,21 @@ export const docs = {
|
|
|
58
60
|
description: 'Whether to show a bottom border divider under the tab list.',
|
|
59
61
|
default: 'false',
|
|
60
62
|
},
|
|
63
|
+
{
|
|
64
|
+
name: 'role',
|
|
65
|
+
type: 'AriaRole',
|
|
66
|
+
description: "ARIA role for the strip. 'tablist' asks for the WAI-ARIA tabs pattern: role=\"tablist\" / role=\"tab\" and aria-selected, with each tab pointing at the panel it controls via its panelId; only tabs may live in a tablist strip, and an href on a tab is ignored there. Left unset, the strip is a nav landmark marking the current tab with aria-current. Any other value is passed through to the element unchanged.",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'overflow',
|
|
70
|
+
type: "'auto' | 'scroll' | 'visible'",
|
|
71
|
+
description: "What happens when the tabs are wider than the strip. 'auto' lets the component choose, which today always scrolls. 'scroll' scrolls the tabs horizontally, with edge fades and arrow affordances for pointers that can hover. 'visible' turns overflow handling off and lets the tabs spill out of the strip. The selected tab is always scrolled back into view.",
|
|
72
|
+
default: "'auto'",
|
|
73
|
+
},
|
|
61
74
|
{
|
|
62
75
|
name: 'children',
|
|
63
76
|
type: 'ReactNode',
|
|
64
|
-
description: 'Tab and TabMenu items to render inside the
|
|
77
|
+
description: 'Tab and TabMenu items to render inside the strip.',
|
|
65
78
|
slotElements: [
|
|
66
79
|
{
|
|
67
80
|
__element: 'Tab',
|
|
@@ -88,8 +101,9 @@ export const docs = {
|
|
|
88
101
|
'TabList provides tab-style navigation for organizing content into categorized sections. Use it to let users switch between related views without leaving the page, with overflow items handled by a built-in "more" menu.',
|
|
89
102
|
bestPractices: [
|
|
90
103
|
{ guidance: true, description: 'Keep tab labels short and descriptive so users can quickly scan available sections.' },
|
|
91
|
-
{ guidance: true, description: 'Use TabMenu
|
|
104
|
+
{ guidance: true, description: 'Leave overflow handling on: a strip narrower than its tabs scrolls, and the selected tab is kept in view. Use TabMenu when you want a curated group of extra options rather than a scrolling strip.' },
|
|
92
105
|
{ guidance: true, description: 'When using hasDivider with action buttons alongside tabs, match the Button size to the TabList size (both md, both sm); the divided tab strip reserves space so tabs and same-size buttons align to a shared baseline above the rail.' },
|
|
106
|
+
{ guidance: true, description: 'Reach for role="tablist" when the strip switches panels in place, and give each tab a panelId pointing at the panel it opens: that link is how a screen reader gets from a tab to its content. Leave it off for navigation between views.' },
|
|
93
107
|
{ guidance: false, description: 'Use tabs for sequential steps or workflows; use a stepper or wizard pattern instead.' },
|
|
94
108
|
{ guidance: false, description: 'Place more than 6–8 visible tabs before the overflow menu; prioritize the most important categories.' },
|
|
95
109
|
{ guidance: false, description: 'Confuse TabList with SegmentedControl or ToggleButton. TabList is for navigation between views. SegmentedControl and ToggleButton are input controls: SegmentedControl always has exactly one selected option, while ToggleButton can be toggled on or off.' },
|
|
@@ -109,8 +123,9 @@ export const docsZh = {
|
|
|
109
123
|
'TabList provides tab-style navigation for organizing content into categorized sections. Use it to let users switch between related views without leaving the page, with overflow items handled by a built-in "more" menu.',
|
|
110
124
|
bestPractices: [
|
|
111
125
|
{ guidance: true, description: 'Keep tab labels short and descriptive so users can quickly scan available sections.' },
|
|
112
|
-
{ guidance: true, description: 'Use TabMenu
|
|
126
|
+
{ guidance: true, description: 'Leave overflow handling on: a strip narrower than its tabs scrolls, and the selected tab is kept in view. Use TabMenu when you want a curated group of extra options rather than a scrolling strip.' },
|
|
113
127
|
{ guidance: true, description: 'When using hasDivider with action buttons alongside tabs, match the Button size to the TabList size (both md, both sm); the divided tab strip reserves space so tabs and same-size buttons align to a shared baseline above the rail.' },
|
|
128
|
+
{ guidance: true, description: 'Reach for role="tablist" when the strip switches panels in place, and give each tab a panelId pointing at the panel it opens: that link is how a screen reader gets from a tab to its content. Leave it off for navigation between views.' },
|
|
114
129
|
{ guidance: false, description: 'Use tabs for sequential steps or workflows; use a stepper or wizard pattern instead.' },
|
|
115
130
|
{ guidance: false, description: 'Place more than 6–8 visible tabs before the overflow menu; prioritize the most important categories.' },
|
|
116
131
|
{ guidance: false, description: 'Confuse TabList with SegmentedControl or ToggleButton. TabList is for navigation between views. SegmentedControl and ToggleButton are input controls: SegmentedControl always has exactly one selected option, while ToggleButton can be toggled on or off.' },
|
|
@@ -125,14 +140,15 @@ export const docsZh = {
|
|
|
125
140
|
|
|
126
141
|
/** @type {import('@astryxdesign/cli/authoring').ComponentTranslationDoc} */
|
|
127
142
|
export const docsDense = {
|
|
128
|
-
description: 'Tab
|
|
143
|
+
description: 'Tab strip w/ overflow scrolling; nav landmark by default, WAI-ARIA tabs pattern under role="tablist".',
|
|
129
144
|
usage: {
|
|
130
145
|
description:
|
|
131
146
|
'TabList provides tab-style navigation for organizing content into categorized sections. Use it to let users switch between related views without leaving the page, with overflow items handled by a built-in "more" menu.',
|
|
132
147
|
bestPractices: [
|
|
133
148
|
{ guidance: true, description: 'Keep tab labels short and descriptive so users can quickly scan available sections.' },
|
|
134
|
-
{ guidance: true, description: 'Use TabMenu
|
|
149
|
+
{ guidance: true, description: 'Leave overflow handling on: a strip narrower than its tabs scrolls, and the selected tab is kept in view. Use TabMenu when you want a curated group of extra options rather than a scrolling strip.' },
|
|
135
150
|
{ guidance: true, description: 'When using hasDivider with action buttons alongside tabs, match the Button size to the TabList size (both md, both sm); the divided tab strip reserves space so tabs and same-size buttons align to a shared baseline above the rail.' },
|
|
151
|
+
{ guidance: true, description: 'Reach for role="tablist" when the strip switches panels in place, and give each tab a panelId pointing at the panel it opens: that link is how a screen reader gets from a tab to its content. Leave it off for navigation between views.' },
|
|
136
152
|
{ guidance: false, description: 'Use tabs for sequential steps or workflows; use a stepper or wizard pattern instead.' },
|
|
137
153
|
{ guidance: false, description: 'Place more than 6–8 visible tabs before the overflow menu; prioritize the most important categories.' },
|
|
138
154
|
{ guidance: false, description: 'Confuse TabList with SegmentedControl or ToggleButton. TabList is for navigation between views. SegmentedControl and ToggleButton are input controls: SegmentedControl always has exactly one selected option, while ToggleButton can be toggled on or off.' },
|