@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
|
@@ -476,20 +476,17 @@ export function DropdownMenuSubMenu(
|
|
|
476
476
|
);
|
|
477
477
|
|
|
478
478
|
const endAffordance = hasSpinner ? (
|
|
479
|
-
<span
|
|
480
|
-
{...mergeProps(
|
|
481
|
-
themeProps('dropdown-menu-indicator-icon'),
|
|
482
|
-
stylex.props(triggerStyles.caret),
|
|
483
|
-
)}>
|
|
479
|
+
<span {...stylex.props(triggerStyles.caret)}>
|
|
484
480
|
<Spinner size="sm" />
|
|
485
481
|
</span>
|
|
486
482
|
) : (
|
|
487
|
-
<span
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
483
|
+
<span {...stylex.props(triggerStyles.caret)}>
|
|
484
|
+
<Icon
|
|
485
|
+
icon="chevronRight"
|
|
486
|
+
size="sm"
|
|
487
|
+
color="secondary"
|
|
488
|
+
{...themeProps('dropdown-menu-indicator-icon')}
|
|
489
|
+
/>
|
|
493
490
|
</span>
|
|
494
491
|
);
|
|
495
492
|
|
package/src/Field/Field.doc.mjs
CHANGED
|
@@ -39,8 +39,8 @@ export const docs = {
|
|
|
39
39
|
],
|
|
40
40
|
vars: [
|
|
41
41
|
{name: '--_field-radius', description: 'Border radius of input fields', default: 'var(--radius-element)', private: true},
|
|
42
|
-
{name: '--_input-clear-hit-inset', description: 'Outset of the clear (\u2715) button\
|
|
43
|
-
{name: '--_input-clear-hit-content', description: 'Whether the clear (\u2715) button\
|
|
42
|
+
{name: '--_input-clear-hit-inset', description: 'Outset of the clear (\u2715) button\'s invisible hit area, applied to a ::after overlay. 0 on a fine pointer; negative on a coarse one, which grows the 20px button to the 24px touch target without changing what is drawn.', default: '0px', private: true},
|
|
43
|
+
{name: '--_input-clear-hit-content', description: 'Whether the clear (\u2715) button\'s invisible hit overlay exists. `none` on a fine pointer, so no ::after is generated and hover still reaches the glyph; `""` on a coarse one, where the overlay provides the 24px touch target.', default: 'none', private: true},
|
|
44
44
|
],
|
|
45
45
|
derived: [
|
|
46
46
|
{property: 'borderRadius', vars: ['--_field-radius']},
|
|
@@ -60,6 +60,17 @@ export const docs = {
|
|
|
60
60
|
description: 'ID for the input element (used for the label htmlFor attribute).',
|
|
61
61
|
required: true,
|
|
62
62
|
},
|
|
63
|
+
{
|
|
64
|
+
name: 'labelID',
|
|
65
|
+
type: 'string',
|
|
66
|
+
description: 'ID applied to the label element itself for group accessibility.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'isGroupLabel',
|
|
70
|
+
type: 'boolean',
|
|
71
|
+
description: 'Renders the label as a span for control groups (radiogroup, checkbox list).',
|
|
72
|
+
default: 'false',
|
|
73
|
+
},
|
|
63
74
|
{
|
|
64
75
|
name: 'children',
|
|
65
76
|
type: 'ReactNode',
|
|
@@ -54,13 +54,14 @@ export type {
|
|
|
54
54
|
InputStatus as FileInputStatus,
|
|
55
55
|
InputStatusType as FileInputStatusType,
|
|
56
56
|
} from '../Field';
|
|
57
|
-
import {mergeProps
|
|
57
|
+
import {mergeProps} from '../utils';
|
|
58
58
|
import type {BaseProps} from '../BaseProps';
|
|
59
59
|
import type {SizeValue} from '../utils/types';
|
|
60
60
|
import {themeProps} from '../utils/themeProps';
|
|
61
61
|
import {useTranslator} from '../i18n';
|
|
62
62
|
import type {TranslatorFn} from '../i18n';
|
|
63
63
|
|
|
64
|
+
import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
64
65
|
function formatFileSize(bytes: number): string {
|
|
65
66
|
if (bytes < 1024) {
|
|
66
67
|
return `${bytes} B`;
|
|
@@ -827,7 +828,7 @@ export function FileInput({
|
|
|
827
828
|
</VisuallyHidden>
|
|
828
829
|
<input
|
|
829
830
|
{...rest}
|
|
830
|
-
ref={
|
|
831
|
+
ref={useMergedRefs(ref, inputRef)}
|
|
831
832
|
id={id}
|
|
832
833
|
type="file"
|
|
833
834
|
accept={accept}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {render, screen} from '@testing-library/react';
|
|
9
|
-
import {describe, it, expect} from 'vitest';
|
|
9
|
+
import {describe, it, expect, vi} from 'vitest';
|
|
10
10
|
import {Heading} from './Heading';
|
|
11
11
|
|
|
12
12
|
describe('Heading', () => {
|
|
@@ -16,6 +16,28 @@ describe('Heading', () => {
|
|
|
16
16
|
expect(screen.getByText('Page Title')).toBeInTheDocument();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
+
it('keeps a forwarded ref attached across rerenders', () => {
|
|
20
|
+
const ref = vi.fn();
|
|
21
|
+
const {rerender} = render(
|
|
22
|
+
<Heading ref={ref} level={1}>
|
|
23
|
+
Before
|
|
24
|
+
</Heading>,
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const element = screen.getByText('Before');
|
|
28
|
+
expect(ref).toHaveBeenLastCalledWith(element);
|
|
29
|
+
ref.mockClear();
|
|
30
|
+
|
|
31
|
+
rerender(
|
|
32
|
+
<Heading ref={ref} level={1}>
|
|
33
|
+
After
|
|
34
|
+
</Heading>,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
expect(ref).not.toHaveBeenCalled();
|
|
38
|
+
expect(screen.getByText('After')).toBe(element);
|
|
39
|
+
});
|
|
40
|
+
|
|
19
41
|
it('renders h1 for level 1', () => {
|
|
20
42
|
render(<Heading level={1}>H1</Heading>);
|
|
21
43
|
const element = screen.getByText('H1');
|
package/src/Heading/Heading.tsx
CHANGED
|
@@ -43,7 +43,8 @@ import {
|
|
|
43
43
|
import {useTruncation} from '../Text/useTruncation';
|
|
44
44
|
import {resolveStyleColor} from '../Text/Text';
|
|
45
45
|
import type {LayerPlacement} from '../Layer';
|
|
46
|
-
import {mergeProps
|
|
46
|
+
import {mergeProps} from '../utils';
|
|
47
|
+
import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
47
48
|
import type {BaseProps} from '../BaseProps';
|
|
48
49
|
import {themeProps} from '../utils/themeProps';
|
|
49
50
|
|
|
@@ -242,13 +243,16 @@ export function Heading({
|
|
|
242
243
|
// Ref for the heading element (used as tooltip anchor)
|
|
243
244
|
const headingRef = useRef<HTMLHeadingElement>(null);
|
|
244
245
|
|
|
246
|
+
// Keep the merged ref stable across rerenders.
|
|
247
|
+
const mergedRef = useMergedRefs(ref, truncation.ref, headingRef);
|
|
248
|
+
|
|
245
249
|
// Build inline style for -webkit-line-clamp (dynamic value)
|
|
246
250
|
const inlineStyle = maxLines > 1 ? {WebkitLineClamp: maxLines} : undefined;
|
|
247
251
|
|
|
248
252
|
return (
|
|
249
253
|
<>
|
|
250
254
|
<Component
|
|
251
|
-
ref={
|
|
255
|
+
ref={mergedRef}
|
|
252
256
|
{...mergeProps(
|
|
253
257
|
themeProps('heading', {level, color, ...(type && {type})}),
|
|
254
258
|
stylex.props(
|
|
@@ -109,6 +109,11 @@ export const docs = {
|
|
|
109
109
|
type: 'boolean',
|
|
110
110
|
description: 'Whether the hover card should be shown on mount. Still dismissible.',
|
|
111
111
|
},
|
|
112
|
+
{
|
|
113
|
+
name: 'isOpen',
|
|
114
|
+
type: 'boolean',
|
|
115
|
+
description: 'Controlled open state for the hover card.',
|
|
116
|
+
},
|
|
112
117
|
],
|
|
113
118
|
},
|
|
114
119
|
],
|
|
@@ -144,6 +144,12 @@ export interface HoverCardProps extends Pick<
|
|
|
144
144
|
* - `true`: force-show the hover card (hover/focus hide is suppressed)
|
|
145
145
|
* - `false`: force-hide the hover card
|
|
146
146
|
* - `undefined`: uncontrolled — hover/focus triggers manage visibility
|
|
147
|
+
*
|
|
148
|
+
* A controlled hover card still takes Escape when it is the top-most layer,
|
|
149
|
+
* and answers by calling `onOpenChange(false)` without hiding itself —
|
|
150
|
+
* closing is your update's decision, exactly as for a controlled Dialog.
|
|
151
|
+
* Ignore the call and the card stays, and so does the press: nothing
|
|
152
|
+
* underneath dismisses.
|
|
147
153
|
*/
|
|
148
154
|
isOpen?: boolean;
|
|
149
155
|
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
type LayerTouchTrigger,
|
|
32
32
|
} from '../Layer/useTouchTrigger';
|
|
33
33
|
import {layerAnimations} from '../Layer/layerAnimations.stylex';
|
|
34
|
+
import {useLayerDismissal} from '../Layer/useLayerDismissal';
|
|
34
35
|
import {
|
|
35
36
|
colorVars,
|
|
36
37
|
shadowVars,
|
|
@@ -135,6 +136,11 @@ export interface HoverCardOptions {
|
|
|
135
136
|
* - `true`: force-show the hover card (hover/focus hide is suppressed)
|
|
136
137
|
* - `false`: force-hide the hover card
|
|
137
138
|
* - `undefined`: uncontrolled — hover/focus triggers manage visibility
|
|
139
|
+
*
|
|
140
|
+
* A controlled hover card still takes Escape when it is the top-most layer,
|
|
141
|
+
* and answers by calling `onHide` without hiding itself — closing is your
|
|
142
|
+
* update's decision, exactly as for a controlled Dialog. Ignore the call and
|
|
143
|
+
* the card stays, and so does the press: nothing underneath dismisses.
|
|
138
144
|
*/
|
|
139
145
|
isOpen?: boolean;
|
|
140
146
|
|
|
@@ -409,19 +415,71 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
|
|
|
409
415
|
[layer.id, scheduleHide],
|
|
410
416
|
);
|
|
411
417
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
418
|
+
// Escape dismissal (WCAG 1.4.13) goes through the shared layer stack: a
|
|
419
|
+
// visible card is the top-most layer, so it takes the press and consumes it.
|
|
420
|
+
//
|
|
421
|
+
// This replaces a keydown listener on the TRIGGER that called
|
|
422
|
+
// stopPropagation() on any Escape while the trigger merely had focus — open
|
|
423
|
+
// card or not — so focusing a HoverCard trigger inside a Dialog silently ate
|
|
424
|
+
// the press that should have closed the Dialog. Presence is now answered from
|
|
425
|
+
// the DOM, so a closed card never claims a press.
|
|
426
|
+
// A controlled hover card stays on the stack and takes the press like any
|
|
427
|
+
// other layer, but answers it by reporting instead of hiding: `isOpen` is
|
|
428
|
+
// the consumer's value, so only their update may change it. Same contract as
|
|
429
|
+
// a controlled Dialog.
|
|
430
|
+
useLayerDismissal({
|
|
431
|
+
// Registered for the hook's lifetime rather than gated on `layer.isOpen`:
|
|
432
|
+
// that state can lag a frame behind the DOM, so a press arriving right after
|
|
433
|
+
// the layer appears would find nothing registered. Because this layer
|
|
434
|
+
// CONSUMES the press, a stale registration would be worse than a missed one
|
|
435
|
+
// — it would silently eat Escapes meant for the dialog underneath — so
|
|
436
|
+
// presence is answered from the DOM at press time instead of from state.
|
|
437
|
+
isActive: true,
|
|
438
|
+
isPresent: () => {
|
|
439
|
+
const el =
|
|
440
|
+
typeof document === 'undefined'
|
|
441
|
+
? null
|
|
442
|
+
: document.getElementById(layer.id);
|
|
443
|
+
if (el == null) {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
try {
|
|
447
|
+
return el.matches(':popover-open');
|
|
448
|
+
} catch {
|
|
449
|
+
// Browsers without the Popover API (and some test environments) cannot
|
|
450
|
+
// answer the selector; fall back to the hook's own state.
|
|
451
|
+
return layer.isOpen;
|
|
421
452
|
}
|
|
422
453
|
},
|
|
423
|
-
|
|
424
|
-
|
|
454
|
+
onDismiss: () => {
|
|
455
|
+
clearTimeouts();
|
|
456
|
+
touch.clearTapOpen();
|
|
457
|
+
// Controlled: report and stop. The close — and the focus restore that
|
|
458
|
+
// goes with it — happens in the controlled effect if and when the
|
|
459
|
+
// consumer flips `isOpen`.
|
|
460
|
+
if (isOpen !== undefined) {
|
|
461
|
+
onHide?.();
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
// Only when the card itself held focus, which is the one case the
|
|
465
|
+
// content-level handler this replaced could run in. Refocusing
|
|
466
|
+
// unconditionally would drag the caret out of a field the user was
|
|
467
|
+
// typing in while a hover card happened to be up; arming the re-show
|
|
468
|
+
// guard unconditionally would swallow their next focus on the trigger,
|
|
469
|
+
// because a focus() on the already-focused trigger fires no focusin to
|
|
470
|
+
// clear it.
|
|
471
|
+
const card =
|
|
472
|
+
typeof document === 'undefined'
|
|
473
|
+
? null
|
|
474
|
+
: document.getElementById(layer.id);
|
|
475
|
+
const hadFocus = card?.contains(document.activeElement) ?? false;
|
|
476
|
+
layer.hide();
|
|
477
|
+
if (hadFocus) {
|
|
478
|
+
isEscapeDismissingRef.current = true;
|
|
479
|
+
triggerRef.current?.focus();
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
});
|
|
425
483
|
|
|
426
484
|
// Interaction ref that handles event listeners only
|
|
427
485
|
const {handlePointerEnter} = touch;
|
|
@@ -436,7 +494,6 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
|
|
|
436
494
|
'focusout',
|
|
437
495
|
handleFocusOut as EventListener,
|
|
438
496
|
);
|
|
439
|
-
triggerRef.current.removeEventListener('keydown', handleKeyDown);
|
|
440
497
|
triggerRef.current.removeEventListener(
|
|
441
498
|
'pointerenter',
|
|
442
499
|
handlePointerEnter,
|
|
@@ -465,9 +522,6 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
|
|
|
465
522
|
el.addEventListener('focusin', handleFocusIn);
|
|
466
523
|
el.addEventListener('focusout', handleFocusOut as EventListener);
|
|
467
524
|
}
|
|
468
|
-
|
|
469
|
-
// Attach keydown for Escape handling
|
|
470
|
-
el.addEventListener('keydown', handleKeyDown);
|
|
471
525
|
}
|
|
472
526
|
|
|
473
527
|
triggerRef.current = el;
|
|
@@ -478,7 +532,6 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
|
|
|
478
532
|
handleMouseLeave,
|
|
479
533
|
handleFocusIn,
|
|
480
534
|
handleFocusOut,
|
|
481
|
-
handleKeyDown,
|
|
482
535
|
handlePointerEnter,
|
|
483
536
|
handlePointerDown,
|
|
484
537
|
],
|
|
@@ -518,7 +571,19 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
|
|
|
518
571
|
layer.show();
|
|
519
572
|
} else {
|
|
520
573
|
clearTimeouts();
|
|
574
|
+
// A consumer closing the card while it holds focus would strand focus on
|
|
575
|
+
// <body>. Arming the re-show guard is what keeps the refocus from
|
|
576
|
+
// reopening the card through `handleFocusIn`, which shows on any focusin.
|
|
577
|
+
const card =
|
|
578
|
+
typeof document === 'undefined'
|
|
579
|
+
? null
|
|
580
|
+
: document.getElementById(layer.id);
|
|
581
|
+
const hadFocus = card?.contains(document.activeElement) ?? false;
|
|
521
582
|
layer.hide();
|
|
583
|
+
if (hadFocus) {
|
|
584
|
+
isEscapeDismissingRef.current = true;
|
|
585
|
+
triggerRef.current?.focus();
|
|
586
|
+
}
|
|
522
587
|
}
|
|
523
588
|
}, [isOpen, clearTimeouts, layer]);
|
|
524
589
|
|
|
@@ -576,20 +641,6 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
|
|
|
576
641
|
isHoveringContentRef.current = false;
|
|
577
642
|
scheduleHide();
|
|
578
643
|
}}
|
|
579
|
-
onKeyDown={e => {
|
|
580
|
-
if (e.key === 'Escape') {
|
|
581
|
-
// Stop propagation so parent components don't react to the same Escape
|
|
582
|
-
e.stopPropagation();
|
|
583
|
-
// Set flag to prevent re-show when we refocus trigger
|
|
584
|
-
isEscapeDismissingRef.current = true;
|
|
585
|
-
// Hide immediately
|
|
586
|
-
clearTimeouts();
|
|
587
|
-
touch.clearTapOpen();
|
|
588
|
-
layer.hide();
|
|
589
|
-
// Refocus the trigger
|
|
590
|
-
triggerRef.current?.focus();
|
|
591
|
-
}
|
|
592
|
-
}}
|
|
593
644
|
onBlur={e => {
|
|
594
645
|
// Check if focus is moving back to the trigger or staying within content
|
|
595
646
|
const relatedTarget = e.relatedTarget as HTMLElement | null;
|
package/src/Item/Item.tsx
CHANGED
|
@@ -27,7 +27,8 @@ import {
|
|
|
27
27
|
typeScaleVars,
|
|
28
28
|
} from '../theme/tokens.stylex';
|
|
29
29
|
import type {BaseProps} from '../BaseProps';
|
|
30
|
-
import {mergeProps
|
|
30
|
+
import {mergeProps} from '../utils';
|
|
31
|
+
import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
31
32
|
import {computeTargetAndRel} from '../Link/computeTargetAndRel';
|
|
32
33
|
import {useLinkComponent} from '../Link/useLinkComponent';
|
|
33
34
|
import {useClickableContainer} from '../hooks/useClickableContainer';
|
|
@@ -579,11 +580,11 @@ export function Item({
|
|
|
579
580
|
</>
|
|
580
581
|
);
|
|
581
582
|
|
|
583
|
+
const mergedRef = useMergedRefs(ref, containerRef);
|
|
584
|
+
|
|
582
585
|
return (
|
|
583
586
|
<Component
|
|
584
|
-
ref={
|
|
585
|
-
(isDelegate ? mergeRefs(ref, containerRef) : ref) as React.Ref<never>
|
|
586
|
-
}
|
|
587
|
+
ref={(isDelegate ? mergedRef : ref) as React.Ref<never>}
|
|
587
588
|
{...restProps}
|
|
588
589
|
aria-selected={(allowsAriaSelected && isSelected) || undefined}
|
|
589
590
|
// aria-selected is invalid on roles that don't permit it (listitem, a
|
package/src/Kbd/Kbd.test.tsx
CHANGED
|
@@ -23,6 +23,7 @@ describe('Kbd', () => {
|
|
|
23
23
|
value: originalPlatform,
|
|
24
24
|
configurable: true,
|
|
25
25
|
});
|
|
26
|
+
delete (navigator as {userAgentData?: unknown}).userAgentData;
|
|
26
27
|
});
|
|
27
28
|
|
|
28
29
|
it('renders a single key', () => {
|
|
@@ -54,6 +55,22 @@ describe('Kbd', () => {
|
|
|
54
55
|
expect(screen.getByText('\u2318')).toBeInTheDocument(); // \u2318
|
|
55
56
|
});
|
|
56
57
|
|
|
58
|
+
it('reads a blank userAgentData.platform as unknown, not as non-Mac', () => {
|
|
59
|
+
// Builds that rewrite their client-hints identity expose the key with an
|
|
60
|
+
// empty value; navigator.platform is the only surface left that answers.
|
|
61
|
+
Object.defineProperty(navigator, 'userAgentData', {
|
|
62
|
+
value: {platform: ''},
|
|
63
|
+
configurable: true,
|
|
64
|
+
});
|
|
65
|
+
Object.defineProperty(navigator, 'platform', {
|
|
66
|
+
value: 'MacIntel',
|
|
67
|
+
configurable: true,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
render(<Kbd keys="mod" />);
|
|
71
|
+
expect(screen.getByText('\u2318')).toBeInTheDocument();
|
|
72
|
+
});
|
|
73
|
+
|
|
57
74
|
it('maps modifier keys to symbols', () => {
|
|
58
75
|
render(<Kbd keys="ctrl+alt+shift+k" />);
|
|
59
76
|
expect(screen.getByText('\u2303')).toBeInTheDocument(); // \u2303
|
package/src/Kbd/Kbd.tsx
CHANGED
|
@@ -124,8 +124,9 @@ function getServerPlatformSnapshot(): boolean {
|
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
126
|
* Detects whether the current platform is macOS/iOS.
|
|
127
|
-
* Prefers the User-Agent Client Hints API when
|
|
128
|
-
* falls back to navigator.platform (deprecated but universally
|
|
127
|
+
* Prefers the User-Agent Client Hints API when it names a platform (modern
|
|
128
|
+
* Chrome/Edge), falls back to navigator.platform (deprecated but universally
|
|
129
|
+
* supported) when it is absent or blank.
|
|
129
130
|
*/
|
|
130
131
|
function detectMac(): boolean {
|
|
131
132
|
if (typeof navigator === 'undefined') {
|
|
@@ -134,7 +135,13 @@ function detectMac(): boolean {
|
|
|
134
135
|
// Prefer User-Agent Client Hints API (not deprecated)
|
|
135
136
|
const uaData = 'userAgentData' in navigator ? navigator.userAgentData : null;
|
|
136
137
|
if (uaData && typeof uaData === 'object' && 'platform' in uaData) {
|
|
137
|
-
|
|
138
|
+
const uaPlatform = (uaData as {platform?: unknown}).platform;
|
|
139
|
+
// A blank platform is no answer, not a negative one. Builds that rewrite
|
|
140
|
+
// their client-hints identity ship '', so fall through rather than
|
|
141
|
+
// reading it as "not Apple".
|
|
142
|
+
if (typeof uaPlatform === 'string' && uaPlatform.trim() !== '') {
|
|
143
|
+
return /mac/i.test(uaPlatform);
|
|
144
|
+
}
|
|
138
145
|
}
|
|
139
146
|
// Fallback: navigator.platform (deprecated but still shipped everywhere)
|
|
140
147
|
return /Mac|iPhone|iPad|iPod/.test(navigator.platform ?? '');
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file LayerDepthContext.tsx
|
|
7
|
+
* @input React context
|
|
8
|
+
* @output Exports LayerDepthContext, useLayerDepth, LayerDepthProvider
|
|
9
|
+
* @position Layer system; how the dismissal stack learns which layer is nested
|
|
10
|
+
* inside which.
|
|
11
|
+
*
|
|
12
|
+
* SYNC: When modified, update:
|
|
13
|
+
* - /packages/core/src/Layer/index.ts
|
|
14
|
+
* - /packages/core/src/Layer/useLayerDismissal.ts
|
|
15
|
+
*
|
|
16
|
+
* Nesting is read from the React tree rather than the DOM. Two reasons:
|
|
17
|
+
*
|
|
18
|
+
* - **Portals.** A nested overlay routinely renders into `document.body` or the
|
|
19
|
+
* native top layer, so DOM containment reports it as a sibling of the layer
|
|
20
|
+
* it is logically inside. React context flows through `createPortal`, so the
|
|
21
|
+
* tree keeps the relationship the DOM loses.
|
|
22
|
+
* - **Same-commit mounts.** Depth is fixed during render. Effect order is not
|
|
23
|
+
* available then and is misleading anyway: React runs child effects before
|
|
24
|
+
* parent effects, so an inner layer registers first and looks "older" than
|
|
25
|
+
* the outer layer that contains it.
|
|
26
|
+
*
|
|
27
|
+
* There is nothing to mount at the app root: the context defaults to 0, and
|
|
28
|
+
* each layer provides depth for its OWN content, so nesting composes on its own.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import {createContext, use, type ReactNode} from 'react';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* How many layers deep the current subtree is. 0 at the app root; each layer
|
|
35
|
+
* increments it for its own content.
|
|
36
|
+
*/
|
|
37
|
+
export const LayerDepthContext = createContext(0);
|
|
38
|
+
LayerDepthContext.displayName = 'LayerDepthContext';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Read the current nesting depth. A layer calls this to learn its OWN depth —
|
|
42
|
+
* the depth of the subtree it is rendered into, before it pushes its content
|
|
43
|
+
* one level deeper.
|
|
44
|
+
*/
|
|
45
|
+
export function useLayerDepth(): number {
|
|
46
|
+
return use(LayerDepthContext);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Wrap a layer's content so any layer opened from inside it registers as
|
|
51
|
+
* nested. Takes no depth prop on purpose: it reads the ambient depth and adds
|
|
52
|
+
* one, so nesting composes without anyone tracking absolute numbers.
|
|
53
|
+
*
|
|
54
|
+
* Renders no DOM element — it is a context boundary only, which is why it takes
|
|
55
|
+
* no `xstyle`/`ref` and exposes no props interface.
|
|
56
|
+
*/
|
|
57
|
+
export function LayerDepthProvider({children}: {children: ReactNode}) {
|
|
58
|
+
const depth = use(LayerDepthContext);
|
|
59
|
+
return <LayerDepthContext value={depth + 1}>{children}</LayerDepthContext>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
LayerDepthProvider.displayName = 'LayerDepthProvider';
|
package/src/Layer/index.ts
CHANGED
|
@@ -29,6 +29,15 @@ export type {
|
|
|
29
29
|
FixedLayerReturn,
|
|
30
30
|
} from './useLayer';
|
|
31
31
|
|
|
32
|
+
// Layer dismissal stack — one Escape owner for every overlay family
|
|
33
|
+
export {useLayerDismissal} from './useLayerDismissal';
|
|
34
|
+
export type {
|
|
35
|
+
LayerEscapeBehavior,
|
|
36
|
+
UseLayerDismissalOptions,
|
|
37
|
+
UseLayerDismissalReturn,
|
|
38
|
+
} from './useLayerDismissal';
|
|
39
|
+
export {LayerDepthProvider} from './LayerDepthContext';
|
|
40
|
+
|
|
32
41
|
// Shared touch behavior for the hover layers
|
|
33
42
|
export {useTouchTrigger, isActionTrigger} from './useTouchTrigger';
|
|
34
43
|
export type {
|