@astryxdesign/core 0.1.4 → 0.1.5-canary.76e6697
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 +141 -0
- package/dist/AlertDialog/AlertDialog.d.ts +1 -1
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +20 -18
- package/dist/AlertDialog/useImperativeAlertDialog.d.ts +0 -2
- package/dist/AlertDialog/useImperativeAlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/useImperativeAlertDialog.js +3 -5
- package/dist/AppShell/AppShell.d.ts +1 -1
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +55 -53
- package/dist/AspectRatio/AspectRatio.d.ts +48 -10
- package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
- package/dist/AspectRatio/AspectRatio.js +33 -12
- package/dist/AspectRatio/index.d.ts +1 -1
- package/dist/AspectRatio/index.d.ts.map +1 -1
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +28 -26
- package/dist/Avatar/AvatarStatusDot.js +6 -6
- package/dist/AvatarGroup/AvatarGroup.js +6 -6
- package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -7
- package/dist/Badge/Badge.js +3 -3
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +32 -25
- package/dist/Blockquote/Blockquote.js +7 -7
- package/dist/Breadcrumbs/BreadcrumbItem.js +17 -17
- package/dist/Breadcrumbs/Breadcrumbs.js +7 -7
- package/dist/Button/Button.js +19 -19
- package/dist/ButtonGroup/ButtonGroup.js +7 -7
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +68 -48
- package/dist/Calendar/dayCellUtils.d.ts.map +1 -1
- package/dist/Calendar/styles.d.ts +2 -2
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +2 -2
- package/dist/Card/Card.d.ts +4 -2
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +18 -10
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +24 -21
- package/dist/Center/Center.js +3 -3
- package/dist/Chat/ChatComposer.js +23 -23
- package/dist/Chat/ChatComposerDrawer.js +14 -14
- package/dist/Chat/ChatComposerInput.d.ts +1 -1
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +27 -15
- package/dist/Chat/ChatDictationButton.d.ts +1 -1
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +13 -11
- package/dist/Chat/ChatLayout.js +17 -17
- package/dist/Chat/ChatLayoutScrollButton.d.ts +1 -1
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +12 -10
- package/dist/Chat/ChatMessage.js +12 -12
- package/dist/Chat/ChatMessageBubble.js +7 -7
- package/dist/Chat/ChatMessageList.js +14 -14
- package/dist/Chat/ChatMessageMetadata.d.ts +1 -1
- package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
- package/dist/Chat/ChatMessageMetadata.js +14 -12
- package/dist/Chat/ChatPastedTextToken.js +13 -13
- package/dist/Chat/ChatSendButton.js +3 -3
- package/dist/Chat/ChatSystemMessage.d.ts +1 -1
- package/dist/Chat/ChatSystemMessage.d.ts.map +1 -1
- package/dist/Chat/ChatSystemMessage.js +17 -17
- package/dist/Chat/ChatTokenizedText.d.ts +1 -1
- package/dist/Chat/ChatTokenizedText.d.ts.map +1 -1
- package/dist/Chat/ChatTokenizedText.js +24 -15
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +81 -74
- package/dist/Chat/index.d.ts +1 -1
- package/dist/Chat/index.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +15 -15
- package/dist/CheckboxInput/CheckboxInput.d.ts +1 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +25 -23
- package/dist/CheckboxList/CheckboxList.js +9 -9
- package/dist/CheckboxList/CheckboxListItem.d.ts +1 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +8 -6
- package/dist/Citation/Citation.js +10 -10
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +32 -9
- package/dist/Code/Code.js +3 -3
- package/dist/CodeBlock/CodeBlock.d.ts +10 -1
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +88 -52
- package/dist/Collapsible/Collapsible.d.ts +9 -3
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +109 -22
- package/dist/Collapsible/CollapsibleGroup.d.ts +37 -7
- package/dist/Collapsible/CollapsibleGroup.d.ts.map +1 -1
- package/dist/Collapsible/CollapsibleGroup.js +64 -12
- package/dist/Collapsible/CollapsibleGroupContext.d.ts +24 -0
- package/dist/Collapsible/CollapsibleGroupContext.d.ts.map +1 -1
- package/dist/Collapsible/CollapsibleGroupContext.js +26 -3
- package/dist/Collapsible/index.d.ts +1 -0
- package/dist/Collapsible/index.d.ts.map +1 -1
- package/dist/Collapsible/useCollapsible.d.ts +4 -1
- package/dist/Collapsible/useCollapsible.d.ts.map +1 -1
- package/dist/Collapsible/useCollapsible.js +20 -6
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +36 -34
- package/dist/CommandPalette/CommandPaletteEmpty.js +3 -3
- package/dist/CommandPalette/CommandPaletteFooter.js +16 -16
- package/dist/CommandPalette/CommandPaletteGroup.js +5 -5
- package/dist/CommandPalette/CommandPaletteInput.js +13 -13
- package/dist/CommandPalette/CommandPaletteItem.js +3 -3
- package/dist/CommandPalette/CommandPaletteList.js +3 -3
- package/dist/ContextMenu/ContextMenu.d.ts +7 -2
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +76 -43
- package/dist/DateInput/DateInput.js +18 -18
- package/dist/DateRangeInput/DateRangeInput.js +21 -21
- package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +30 -26
- package/dist/DateTimeInput/index.d.ts +1 -1
- package/dist/DateTimeInput/index.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +9 -9
- package/dist/Dialog/DialogHeader.js +16 -16
- package/dist/Dialog/useImperativeDialog.js +3 -3
- package/dist/Divider/Divider.js +7 -7
- package/dist/DropdownMenu/DropdownMenu.js +10 -10
- package/dist/DropdownMenu/DropdownMenuItem.d.ts +2 -17
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +3 -3
- package/dist/DropdownMenu/renderDropdownItems.js +10 -10
- package/dist/EmptyState/EmptyState.js +9 -9
- package/dist/Field/Field.js +17 -17
- package/dist/Field/FieldLabel.js +15 -15
- package/dist/Field/InputClearButton.js +5 -5
- package/dist/FieldStatus/FieldStatus.js +3 -3
- package/dist/FileInput/FileInput.js +29 -29
- package/dist/FormLayout/FormLayout.js +5 -5
- package/dist/Grid/Grid.d.ts +4 -3
- package/dist/Grid/Grid.d.ts.map +1 -1
- package/dist/Grid/Grid.js +29 -12
- package/dist/Grid/GridSpan.js +3 -3
- package/dist/HStack/HStack.js +3 -3
- package/dist/Heading/Heading.js +10 -10
- package/dist/HoverCard/HoverCard.js +9 -9
- package/dist/HoverCard/useHoverCard.d.ts +5 -1
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +3 -3
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +16 -12
- package/dist/Icon/defaultIcons.js +116 -116
- package/dist/IconButton/IconButton.js +3 -3
- package/dist/InputGroup/InputGroup.js +11 -11
- package/dist/InputGroup/InputGroupText.js +3 -3
- package/dist/Item/Item.js +18 -18
- package/dist/Kbd/Kbd.js +5 -5
- package/dist/Layer/LayerProvider.js +7 -7
- package/dist/Layer/useLayer.d.ts +29 -2
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +44 -31
- package/dist/Layout/Layout.js +21 -21
- package/dist/Layout/LayoutContent.js +3 -3
- package/dist/Layout/LayoutFooter.js +5 -5
- package/dist/Layout/LayoutHeader.js +5 -5
- package/dist/Layout/LayoutPanel.js +3 -3
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +55 -31
- package/dist/Lightbox/useLightbox.d.ts +0 -1
- package/dist/Lightbox/useLightbox.d.ts.map +1 -1
- package/dist/Lightbox/useLightbox.js +3 -4
- package/dist/Link/Link.d.ts +0 -2
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +15 -17
- package/dist/Link/LinkProvider.js +3 -3
- package/dist/Link/useLinkify.js +3 -3
- package/dist/List/List.js +11 -11
- package/dist/List/ListItem.js +11 -11
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +102 -102
- package/dist/MetadataList/MetadataList.js +10 -10
- package/dist/MetadataList/MetadataListItem.js +15 -15
- package/dist/MobileNav/MobileNav.d.ts +1 -1
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +26 -23
- package/dist/MobileNav/MobileNavToggle.js +5 -5
- package/dist/MoreMenu/MoreMenu.js +3 -3
- package/dist/MultiSelector/MultiSelector.js +56 -56
- package/dist/NavIcon/NavIcon.js +3 -3
- package/dist/NavMenu/NavHeadingMenu.js +5 -5
- package/dist/NavMenu/NavHeadingMenuItem.js +8 -8
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +48 -32
- package/dist/Outline/Outline.js +15 -15
- package/dist/OverflowList/OverflowList.js +8 -8
- package/dist/Overlay/Overlay.js +3 -3
- package/dist/Overlay/OverlayScrim.js +5 -5
- package/dist/Overlay/useOverlay.d.ts +0 -3
- package/dist/Overlay/useOverlay.d.ts.map +1 -1
- package/dist/Overlay/useOverlay.js +3 -6
- package/dist/Pagination/Pagination.d.ts +1 -1
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +125 -72
- package/dist/Popover/Popover.js +16 -16
- package/dist/Popover/usePopover.js +7 -7
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +110 -92
- package/dist/PowerSearch/PowerSearchEditPopover.js +84 -84
- package/dist/PowerSearch/PowerSearchFilterEditor.js +3 -3
- package/dist/PowerSearch/PowerSearchToken.js +5 -5
- package/dist/PowerSearch/PowerSearchValueEditor.js +54 -54
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +25 -18
- package/dist/RadioList/RadioList.js +7 -7
- package/dist/RadioList/RadioListItem.d.ts +1 -1
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +24 -21
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +28 -10
- package/dist/Section/Section.js +5 -5
- package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControl.js +32 -10
- package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +18 -12
- package/dist/SelectableCard/SelectableCard.js +5 -5
- package/dist/Selector/Selector.js +46 -46
- package/dist/Selector/SelectorOption.js +3 -3
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +38 -34
- package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavCollapseButton.js +8 -6
- package/dist/SideNav/SideNavHeading.js +87 -87
- package/dist/SideNav/SideNavItem.js +42 -42
- package/dist/SideNav/SideNavSection.d.ts +1 -1
- package/dist/SideNav/SideNavSection.d.ts.map +1 -1
- package/dist/SideNav/SideNavSection.js +18 -16
- package/dist/Skeleton/Skeleton.js +3 -3
- package/dist/Slider/Slider.js +23 -23
- package/dist/Spinner/Spinner.js +9 -9
- package/dist/StatusDot/StatusDot.js +5 -5
- package/dist/Switch/Switch.d.ts +8 -4
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +34 -29
- package/dist/TabList/Tab.js +18 -18
- package/dist/TabList/TabList.js +5 -5
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +57 -30
- package/dist/TabList/tab.markers.stylex.d.ts +1 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +50 -39
- package/dist/Table/Table.js +7 -7
- package/dist/Table/TableBody.d.ts +1 -1
- package/dist/Table/TableBody.d.ts.map +1 -1
- package/dist/Table/TableBody.js +9 -5
- package/dist/Table/TableCell.js +3 -3
- package/dist/Table/TableFooter.d.ts +1 -1
- package/dist/Table/TableFooter.d.ts.map +1 -1
- package/dist/Table/TableFooter.js +9 -5
- package/dist/Table/TableHeader.d.ts +1 -1
- package/dist/Table/TableHeader.d.ts.map +1 -1
- package/dist/Table/TableHeader.js +9 -5
- package/dist/Table/TableHeaderCell.js +3 -3
- package/dist/Table/TableRow.js +5 -5
- package/dist/Table/index.d.ts +2 -0
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +1 -0
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +14 -11
- package/dist/Table/plugins/filtering/useTableFiltering.js +71 -71
- package/dist/Table/plugins/groupedRows/index.d.ts +3 -0
- package/dist/Table/plugins/groupedRows/index.d.ts.map +1 -0
- package/dist/Table/plugins/groupedRows/index.js +3 -0
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +78 -0
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -0
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +250 -0
- package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/paginateData.js +5 -1
- package/dist/Table/plugins/pagination/useTablePagination.js +7 -7
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +23 -23
- package/dist/Table/plugins/selection/useTableSelection.js +18 -18
- package/dist/Table/plugins/selection/useTableSelectionState.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelectionState.js +11 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +17 -17
- package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortableState.js +8 -4
- package/dist/Table/tableContextMenu.js +9 -9
- package/dist/Text/Text.js +10 -10
- package/dist/TextArea/TextArea.js +14 -14
- package/dist/TextInput/TextInput.js +15 -15
- package/dist/Thumbnail/Thumbnail.d.ts +3 -2
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +30 -29
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +26 -21
- package/dist/Timestamp/Timestamp.d.ts +1 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +37 -26
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +25 -17
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +23 -11
- package/dist/Toast/useToast.d.ts.map +1 -1
- package/dist/Toast/useToast.js +44 -4
- package/dist/ToggleButton/ToggleButton.js +12 -12
- package/dist/ToggleButton/ToggleButtonGroup.js +5 -5
- package/dist/Token/Token.js +21 -21
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +36 -34
- package/dist/Toolbar/Toolbar.js +18 -18
- package/dist/Tooltip/Tooltip.js +11 -11
- package/dist/Tooltip/useTooltip.d.ts +5 -1
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +3 -3
- package/dist/TopNav/TopNav.js +32 -32
- package/dist/TopNav/TopNavHeading.js +67 -67
- package/dist/TopNav/TopNavItem.js +5 -5
- package/dist/TopNav/TopNavMegaMenu.js +30 -30
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +1 -1
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +25 -14
- package/dist/TopNav/TopNavMegaMenuItem.js +16 -16
- package/dist/TopNav/TopNavMenu.js +32 -32
- package/dist/TreeList/TreeList.js +8 -8
- package/dist/TreeList/TreeListBranches.js +11 -11
- package/dist/TreeList/TreeListItem.js +30 -30
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +23 -20
- package/dist/Typeahead/Typeahead.js +12 -12
- package/dist/Typeahead/TypeaheadItem.js +10 -10
- package/dist/VStack/VStack.js +3 -3
- package/dist/VisuallyHidden/VisuallyHidden.d.ts +0 -3
- package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -1
- package/dist/VisuallyHidden/VisuallyHidden.js +0 -3
- package/dist/astryx.css +7 -0
- package/dist/astryx.umd.js +63 -63
- package/dist/astryx.umd.js.map +4 -4
- package/dist/docs-types.d.ts +8 -2
- package/dist/docs-types.d.ts.map +1 -1
- package/dist/hooks/focusableSelector.d.ts +1 -1
- package/dist/hooks/focusableSelector.d.ts.map +1 -1
- package/dist/hooks/focusableSelector.js +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useFocusTrap.d.ts +3 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +38 -1
- package/dist/hooks/useHotkeys.d.ts +51 -0
- package/dist/hooks/useHotkeys.d.ts.map +1 -0
- package/dist/hooks/useHotkeys.js +160 -0
- package/dist/hooks/useInteractiveRole.d.ts +6 -2
- package/dist/hooks/useInteractiveRole.d.ts.map +1 -1
- package/dist/hooks/useInteractiveRole.js +6 -2
- package/dist/hooks/useKeyboardHint.js +9 -9
- package/dist/hooks/useStreamingText.d.ts +3 -1
- package/dist/hooks/useStreamingText.d.ts.map +1 -1
- package/dist/hooks/useStreamingText.js +14 -5
- package/dist/theme/MediaTheme.js +3 -3
- package/dist/theme/Theme.js +7 -7
- package/dist/theme/defineTheme.d.ts +1 -1
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/expandColorScale.d.ts.map +1 -1
- package/dist/theme/expandColorScale.js +10 -3
- package/dist/theme/hct.d.ts +0 -15
- package/dist/theme/hct.d.ts.map +1 -1
- package/dist/theme/hct.js +9 -9
- package/dist/theme/syntax/SyntaxTheme.js +5 -5
- package/dist/theme/tokens.d.ts +10 -2
- package/dist/theme/tokens.d.ts.map +1 -1
- package/dist/theme/tokens.js +220 -4
- package/dist/theme/useTheme.d.ts +3 -2
- package/dist/theme/useTheme.d.ts.map +1 -1
- package/dist/theme/useTheme.js +73 -6
- package/dist/utils/color.d.ts +42 -0
- package/dist/utils/color.d.ts.map +1 -0
- package/dist/utils/color.js +150 -0
- package/dist/utils/composeEventHandlers.d.ts +30 -0
- package/dist/utils/composeEventHandlers.d.ts.map +1 -0
- package/dist/utils/composeEventHandlers.js +40 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +8 -5
- package/package.json +4 -4
- package/src/AlertDialog/AlertDialog.doc.mjs +4 -0
- package/src/AlertDialog/AlertDialog.tsx +2 -0
- package/src/AlertDialog/useImperativeAlertDialog.tsx +0 -2
- package/src/AppShell/AppShell.tsx +2 -0
- package/src/AspectRatio/AspectRatio.doc.mjs +28 -1
- package/src/AspectRatio/AspectRatio.test.tsx +142 -1
- package/src/AspectRatio/AspectRatio.tsx +70 -10
- package/src/AspectRatio/index.ts +5 -1
- package/src/Avatar/Avatar.doc.mjs +11 -0
- package/src/Avatar/Avatar.test.tsx +32 -1
- package/src/Avatar/Avatar.tsx +14 -22
- package/src/Avatar/AvatarStatusDot.tsx +2 -2
- package/src/AvatarGroup/AvatarGroup.doc.mjs +1 -0
- package/src/AvatarGroup/AvatarGroup.tsx +2 -2
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -2
- package/src/Banner/Banner.doc.mjs +8 -0
- package/src/Banner/Banner.test.tsx +38 -0
- package/src/Banner/Banner.tsx +8 -1
- package/src/Calendar/Calendar.doc.mjs +1 -1
- package/src/Calendar/Calendar.test.tsx +122 -17
- package/src/Calendar/Calendar.tsx +26 -5
- package/src/Calendar/dayCellUtils.ts +3 -1
- package/src/Calendar/styles.ts +12 -2
- package/src/Card/Card.doc.mjs +1 -1
- package/src/Card/Card.tsx +16 -6
- package/src/Carousel/Carousel.doc.mjs +12 -12
- package/src/Carousel/Carousel.test.tsx +13 -0
- package/src/Carousel/Carousel.tsx +4 -2
- package/src/Chat/Chat.doc.mjs +1 -1
- package/src/Chat/ChatComposerInput.test.tsx +27 -1
- package/src/Chat/ChatComposerInput.tsx +20 -15
- package/src/Chat/ChatDictationButton.test.tsx +43 -0
- package/src/Chat/ChatDictationButton.tsx +4 -4
- package/src/Chat/ChatLayoutScrollButton.test.tsx +33 -0
- package/src/Chat/ChatLayoutScrollButton.tsx +3 -1
- package/src/Chat/ChatMessageMetadata.test.tsx +32 -0
- package/src/Chat/ChatMessageMetadata.tsx +4 -6
- package/src/Chat/ChatSystemMessage.test.tsx +26 -11
- package/src/Chat/ChatSystemMessage.tsx +7 -7
- package/src/Chat/ChatTokenizedText.test.tsx +29 -16
- package/src/Chat/ChatTokenizedText.tsx +15 -8
- package/src/Chat/ChatToolCalls.test.tsx +55 -0
- package/src/Chat/ChatToolCalls.tsx +10 -12
- package/src/Chat/index.ts +1 -4
- package/src/Chat/useTriggerMenu.tsx +1 -4
- package/src/CheckboxInput/CheckboxInput.doc.mjs +3 -3
- package/src/CheckboxInput/CheckboxInput.test.tsx +71 -4
- package/src/CheckboxInput/CheckboxInput.tsx +2 -0
- package/src/CheckboxList/CheckboxList.test.tsx +19 -0
- package/src/CheckboxList/CheckboxListItem.tsx +11 -2
- package/src/Citation/Citation.doc.mjs +5 -0
- package/src/ClickableCard/ClickableCard.tsx +45 -2
- package/src/CodeBlock/CodeBlock.doc.mjs +7 -2
- package/src/CodeBlock/CodeBlock.test.tsx +122 -3
- package/src/CodeBlock/CodeBlock.tsx +62 -4
- package/src/Collapsible/Collapsible.doc.mjs +8 -4
- package/src/Collapsible/Collapsible.test.tsx +403 -0
- package/src/Collapsible/Collapsible.tsx +85 -10
- package/src/Collapsible/CollapsibleGroup.doc.mjs +27 -3
- package/src/Collapsible/CollapsibleGroup.test.tsx +314 -0
- package/src/Collapsible/CollapsibleGroup.tsx +97 -9
- package/src/Collapsible/CollapsibleGroupContext.tsx +34 -2
- package/src/Collapsible/index.ts +1 -0
- package/src/Collapsible/useCollapsible.ts +20 -6
- package/src/CommandPalette/CommandPalette.doc.mjs +5 -0
- package/src/CommandPalette/CommandPalette.tsx +5 -3
- package/src/CommandPalette/CommandPaletteEmpty.doc.mjs +5 -0
- package/src/CommandPalette/CommandPaletteGroup.doc.mjs +10 -0
- package/src/CommandPalette/CommandPaletteInput.doc.mjs +6 -0
- package/src/CommandPalette/CommandPaletteItem.doc.mjs +6 -0
- package/src/CommandPalette/CommandPaletteList.doc.mjs +9 -0
- package/src/ContextMenu/ContextMenu.doc.mjs +15 -0
- package/src/ContextMenu/ContextMenu.test.tsx +87 -0
- package/src/ContextMenu/ContextMenu.tsx +87 -28
- package/src/ContextMenu/ContextMenuItem.doc.mjs +6 -0
- package/src/DateInput/DateInput.test.tsx +11 -20
- package/src/DateRangeInput/DateRangeInput.doc.mjs +9 -6
- package/src/DateRangeInput/DateRangeInput.test.tsx +31 -44
- package/src/DateTimeInput/DateTimeInput.doc.mjs +3 -2
- package/src/DateTimeInput/DateTimeInput.test.tsx +118 -16
- package/src/DateTimeInput/DateTimeInput.tsx +8 -2
- package/src/DateTimeInput/index.ts +1 -0
- package/src/Dialog/Dialog.doc.mjs +4 -0
- package/src/Dialog/DialogHeader.doc.mjs +45 -0
- package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -1
- package/src/DropdownMenu/DropdownMenu.test.tsx +22 -2
- package/src/DropdownMenu/DropdownMenuItem.tsx +5 -17
- package/src/EmptyState/EmptyState.doc.mjs +1 -1
- package/src/Field/Field.test.tsx +1 -4
- package/src/Field/FieldLabel.test.tsx +2 -2
- package/src/FieldStatus/FieldStatus.test.tsx +282 -0
- package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +0 -3
- package/src/Grid/Grid.test.tsx +43 -18
- package/src/Grid/Grid.tsx +26 -9
- package/src/HoverCard/HoverCard.doc.mjs +6 -6
- package/src/HoverCard/useHoverCard.doc.mjs +5 -5
- package/src/HoverCard/useHoverCard.tsx +9 -2
- package/src/Icon/Icon.test.tsx +41 -29
- package/src/Icon/Icon.tsx +6 -2
- package/src/InputGroup/InputGroup.doc.mjs +1 -0
- package/src/InputGroup/InputGroup.tsx +2 -2
- package/src/InteractiveRoleContext/InteractiveRoleContext.test.tsx +185 -0
- package/src/Item/Item.tsx +1 -1
- package/src/Layer/useLayer.doc.mjs +2 -2
- package/src/Layer/useLayer.test.tsx +221 -2
- package/src/Layer/useLayer.tsx +69 -30
- package/src/Layout/Layout.test.tsx +285 -0
- package/src/Layout/LayoutContent.doc.mjs +12 -0
- package/src/Layout/LayoutPanel.doc.mjs +40 -0
- package/src/Layout/LayoutSlots.test.tsx +364 -0
- package/src/Lightbox/Lightbox.doc.mjs +5 -0
- package/src/Lightbox/Lightbox.test.tsx +123 -2
- package/src/Lightbox/Lightbox.tsx +29 -1
- package/src/Lightbox/useLightbox.tsx +0 -1
- package/src/Link/Link.tsx +0 -2
- package/src/Markdown/Markdown.tsx +9 -7
- package/src/Markdown/parser.perf.test.ts +34 -12
- package/src/MobileNav/MobileNav.test.tsx +56 -0
- package/src/MobileNav/MobileNav.tsx +13 -8
- package/src/NavMenu/NavMenu.doc.mjs +15 -0
- package/src/NumberInput/NumberInput.test.tsx +48 -3
- package/src/NumberInput/NumberInput.tsx +32 -15
- package/src/Outline/Outline.doc.mjs +2 -0
- package/src/Outline/parseOutlineFromMarkdown.test.ts +80 -0
- package/src/OverflowList/OverflowList.test.tsx +416 -0
- package/src/Overlay/Overlay.doc.mjs +6 -0
- package/src/Overlay/Overlay.test.tsx +356 -0
- package/src/Overlay/useOverlay.tsx +0 -3
- package/src/Pagination/Pagination.test.tsx +162 -0
- package/src/Pagination/Pagination.tsx +80 -26
- package/src/Popover/Popover.doc.mjs +6 -6
- package/src/Popover/Popover.test.tsx +65 -0
- package/src/Popover/usePopover.doc.mjs +1 -1
- package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
- package/src/PowerSearch/PowerSearch.test.tsx +109 -1
- package/src/PowerSearch/PowerSearch.tsx +37 -16
- package/src/ProgressBar/ProgressBar.doc.mjs +2 -0
- package/src/ProgressBar/ProgressBar.test.tsx +30 -0
- package/src/ProgressBar/ProgressBar.tsx +12 -5
- package/src/RadioList/RadioList.test.tsx +19 -0
- package/src/RadioList/RadioListItem.tsx +9 -4
- package/src/Resizable/ResizeHandle.test.tsx +218 -0
- package/src/Resizable/ResizeHandle.tsx +22 -4
- package/src/SegmentedControl/SegmentedControl.doc.mjs +1 -1
- package/src/SegmentedControl/SegmentedControl.test.tsx +192 -0
- package/src/SegmentedControl/SegmentedControl.tsx +27 -5
- package/src/SegmentedControl/SegmentedControlItem.tsx +9 -4
- package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
- package/src/Selector/Selector.test.tsx +27 -1
- package/src/SideNav/SideNav.doc.mjs +7 -1
- package/src/SideNav/SideNav.test.tsx +66 -0
- package/src/SideNav/SideNav.tsx +6 -2
- package/src/SideNav/SideNavCollapseButton.tsx +4 -3
- package/src/SideNav/SideNavSection.tsx +6 -4
- package/src/SizeContext/SizeContext.test.tsx +226 -0
- package/src/Switch/Switch.doc.mjs +7 -7
- package/src/Switch/Switch.test.tsx +102 -3
- package/src/Switch/Switch.tsx +20 -7
- package/src/TabList/TabList.test.tsx +185 -1
- package/src/TabList/TabMenu.tsx +45 -9
- package/src/Table/BaseTable.tsx +13 -2
- package/src/Table/Table.doc.mjs +6 -1
- package/src/Table/Table.test.tsx +87 -0
- package/src/Table/TableBody.tsx +15 -2
- package/src/Table/TableFooter.tsx +15 -2
- package/src/Table/TableHeader.tsx +15 -2
- package/src/Table/index.ts +5 -0
- package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +13 -0
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +3 -1
- package/src/Table/plugins/groupedRows/index.ts +7 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +231 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +349 -0
- package/src/Table/plugins/pagination/paginateData.ts +5 -1
- package/src/Table/plugins/pagination/useTablePagination.test.tsx +13 -0
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +1 -1
- package/src/Table/plugins/selection/useTableSelectionState.test.tsx +23 -0
- package/src/Table/plugins/selection/useTableSelectionState.tsx +11 -6
- package/src/Table/plugins/sortable/useTableSortableState.test.tsx +35 -1
- package/src/Table/plugins/sortable/useTableSortableState.tsx +8 -4
- package/src/Table/useTableGroupedRows.doc.mjs +71 -0
- package/src/TextArea/TextArea.test.tsx +3 -3
- package/src/TextInput/TextInput.test.tsx +3 -3
- package/src/Thumbnail/Thumbnail.test.tsx +36 -2
- package/src/Thumbnail/Thumbnail.tsx +4 -2
- package/src/TimeInput/TimeInput.test.tsx +37 -0
- package/src/TimeInput/TimeInput.tsx +11 -1
- package/src/Timestamp/Timestamp.doc.mjs +1 -1
- package/src/Timestamp/Timestamp.test.tsx +52 -0
- package/src/Timestamp/Timestamp.tsx +30 -16
- package/src/Toast/Toast.tsx +11 -3
- package/src/Toast/ToastViewport.test.tsx +64 -0
- package/src/Toast/ToastViewport.tsx +12 -0
- package/src/Toast/useToast.test.tsx +258 -0
- package/src/Toast/useToast.tsx +41 -0
- package/src/ToggleButton/ToggleButton.doc.mjs +1 -0
- package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
- package/src/Tokenizer/Tokenizer.test.tsx +54 -0
- package/src/Tokenizer/Tokenizer.tsx +5 -4
- package/src/Tooltip/Tooltip.doc.mjs +6 -6
- package/src/Tooltip/useTooltip.doc.mjs +5 -5
- package/src/Tooltip/useTooltip.tsx +12 -2
- package/src/TopNav/TopNav.doc.mjs +1 -1
- package/src/TopNav/TopNav.test.tsx +23 -7
- package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +9 -2
- package/src/TreeList/TreeList.doc.mjs +2 -2
- package/src/Typeahead/BaseTypeahead.doc.mjs +19 -0
- package/src/Typeahead/BaseTypeahead.tsx +5 -2
- package/src/Typeahead/Typeahead.doc.mjs +1 -1
- package/src/Typeahead/Typeahead.test.tsx +45 -1
- package/src/VisuallyHidden/VisuallyHidden.tsx +0 -3
- package/src/__tests__/TestIcon.tsx +26 -0
- package/src/__tests__/fastRoleQueries.ts +66 -0
- package/src/docPropReferences.test.ts +178 -0
- package/src/docs-types.ts +9 -1
- package/src/hooks/focusableSelector.ts +1 -1
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useFocusTrap.doc.mjs +4 -2
- package/src/hooks/useFocusTrap.test.tsx +149 -1
- package/src/hooks/useFocusTrap.ts +50 -1
- package/src/hooks/useHotkeys.doc.mjs +52 -0
- package/src/hooks/useHotkeys.test.ts +245 -0
- package/src/hooks/useHotkeys.ts +203 -0
- package/src/hooks/useInteractiveRole.ts +12 -4
- package/src/hooks/useStreamingText.test.ts +54 -19
- package/src/hooks/useStreamingText.ts +16 -5
- package/src/hooks/useTreeFocus.test.tsx +1 -3
- package/src/reset.css +29 -0
- package/src/theme/SyntaxTheme.doc.mjs +4 -4
- package/src/theme/defineTheme.ts +4 -13
- package/src/theme/derivedVarRegistry.test.ts +2 -2
- package/src/theme/expandColorScale.test.ts +29 -0
- package/src/theme/expandColorScale.ts +11 -6
- package/src/theme/hct.ts +9 -17
- package/src/theme/themingTargets.test.ts +353 -0
- package/src/theme/tokens.test.ts +182 -9
- package/src/theme/tokens.ts +239 -4
- package/src/theme/useTheme.test.tsx +126 -2
- package/src/theme/useTheme.ts +87 -6
- package/src/utils/color.test.ts +133 -0
- package/src/utils/color.ts +148 -0
- package/src/utils/composeEventHandlers.test.ts +71 -0
- package/src/utils/composeEventHandlers.ts +44 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/mergeProps.test.ts +166 -0
- package/src/utils/sharedResizeObserver.test.ts +2 -2
- package/src/utils/timeParser.test.ts +13 -0
- package/src/utils/timeParser.ts +8 -5
- package/dist/Carousel/carousel.markers.stylex.d.ts +0 -7
- package/dist/Carousel/carousel.markers.stylex.d.ts.map +0 -1
- package/dist/Carousel/carousel.markers.stylex.js +0 -12
- package/src/Carousel/carousel.markers.stylex.ts +0 -10
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file ResizeHandle.test.tsx
|
|
5
|
+
* @input Uses vitest, @testing-library/react, useResizable, ResizeHandle
|
|
6
|
+
* @output Unit tests for ResizeHandle keyboard operability and ARIA state
|
|
7
|
+
* @position Testing; validates ResizeHandle.tsx implementation
|
|
8
|
+
*
|
|
9
|
+
* SYNC: When ResizeHandle.tsx changes, update tests to match new behavior
|
|
10
|
+
*
|
|
11
|
+
* These tests guard the WAI-ARIA window-splitter keyboard contract: the
|
|
12
|
+
* keydown handler must live on the focusable `role="separator"` element.
|
|
13
|
+
* Keyboard resizing is pure state math in useResizable (no layout
|
|
14
|
+
* measurement), so the observable effect asserted here is aria-valuenow,
|
|
15
|
+
* which is bound to the region's `_size`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import {describe, it, expect, vi} from 'vitest';
|
|
19
|
+
import {render, screen, fireEvent, act} from '@testing-library/react';
|
|
20
|
+
import {ResizeHandle} from './ResizeHandle';
|
|
21
|
+
import type {ResizeHandleProps} from './ResizeHandle';
|
|
22
|
+
import {useResizable} from './useResizable';
|
|
23
|
+
import type {ResizableProps, UseResizableSingleConfig} from './useResizable';
|
|
24
|
+
|
|
25
|
+
const KEYBOARD_STEP = 10;
|
|
26
|
+
const KEYBOARD_LARGE_STEP = 50;
|
|
27
|
+
|
|
28
|
+
function Harness({
|
|
29
|
+
config,
|
|
30
|
+
handleProps,
|
|
31
|
+
}: {
|
|
32
|
+
config?: UseResizableSingleConfig;
|
|
33
|
+
handleProps?: Partial<ResizeHandleProps>;
|
|
34
|
+
}) {
|
|
35
|
+
const region = useResizable(
|
|
36
|
+
config ?? {defaultSize: 200, minSizePx: 100, maxSizePx: 400},
|
|
37
|
+
);
|
|
38
|
+
return (
|
|
39
|
+
<ResizeHandle resizable={region.props} label="Resize" {...handleProps} />
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getSeparator(): HTMLElement {
|
|
44
|
+
return screen.getByRole('separator');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
describe('ResizeHandle', () => {
|
|
48
|
+
// --- ARIA wiring ---
|
|
49
|
+
|
|
50
|
+
it('exposes the region size and bounds via ARIA', () => {
|
|
51
|
+
render(<Harness />);
|
|
52
|
+
const separator = getSeparator();
|
|
53
|
+
expect(separator).toHaveAttribute('aria-valuenow', '200');
|
|
54
|
+
expect(separator).toHaveAttribute('aria-valuemin', '100');
|
|
55
|
+
expect(separator).toHaveAttribute('aria-valuemax', '400');
|
|
56
|
+
// Horizontal layout splits along the vertical axis.
|
|
57
|
+
expect(separator).toHaveAttribute('aria-orientation', 'vertical');
|
|
58
|
+
expect(separator).toHaveAttribute('aria-label', 'Resize');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('makes the separator focusable', () => {
|
|
62
|
+
render(<Harness />);
|
|
63
|
+
const separator = getSeparator();
|
|
64
|
+
expect(separator).toHaveAttribute('tabindex', '0');
|
|
65
|
+
act(() => separator.focus());
|
|
66
|
+
expect(separator).toHaveFocus();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// --- Keyboard resizing (the fix: handler lives on the focused separator) ---
|
|
70
|
+
|
|
71
|
+
it('grows the panel by a step on ArrowRight', () => {
|
|
72
|
+
render(<Harness />);
|
|
73
|
+
const separator = getSeparator();
|
|
74
|
+
act(() => separator.focus());
|
|
75
|
+
fireEvent.keyDown(separator, {key: 'ArrowRight'});
|
|
76
|
+
expect(separator).toHaveAttribute(
|
|
77
|
+
'aria-valuenow',
|
|
78
|
+
String(200 + KEYBOARD_STEP),
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('shrinks the panel by a step on ArrowLeft', () => {
|
|
83
|
+
render(<Harness />);
|
|
84
|
+
const separator = getSeparator();
|
|
85
|
+
act(() => separator.focus());
|
|
86
|
+
fireEvent.keyDown(separator, {key: 'ArrowLeft'});
|
|
87
|
+
expect(separator).toHaveAttribute(
|
|
88
|
+
'aria-valuenow',
|
|
89
|
+
String(200 - KEYBOARD_STEP),
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('uses the large step when Shift is held', () => {
|
|
94
|
+
render(<Harness />);
|
|
95
|
+
const separator = getSeparator();
|
|
96
|
+
act(() => separator.focus());
|
|
97
|
+
fireEvent.keyDown(separator, {key: 'ArrowRight', shiftKey: true});
|
|
98
|
+
expect(separator).toHaveAttribute(
|
|
99
|
+
'aria-valuenow',
|
|
100
|
+
String(200 + KEYBOARD_LARGE_STEP),
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('jumps to the minimum on Home', () => {
|
|
105
|
+
render(<Harness />);
|
|
106
|
+
const separator = getSeparator();
|
|
107
|
+
act(() => separator.focus());
|
|
108
|
+
fireEvent.keyDown(separator, {key: 'Home'});
|
|
109
|
+
expect(separator).toHaveAttribute('aria-valuenow', '100');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('jumps to the maximum on End', () => {
|
|
113
|
+
render(<Harness />);
|
|
114
|
+
const separator = getSeparator();
|
|
115
|
+
act(() => separator.focus());
|
|
116
|
+
fireEvent.keyDown(separator, {key: 'End'});
|
|
117
|
+
expect(separator).toHaveAttribute('aria-valuenow', '400');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('resizes along the block axis for a vertical handle', () => {
|
|
121
|
+
render(
|
|
122
|
+
<Harness
|
|
123
|
+
config={{defaultSize: 200, minSizePx: 100, maxSizePx: 400}}
|
|
124
|
+
handleProps={{direction: 'vertical'}}
|
|
125
|
+
/>,
|
|
126
|
+
);
|
|
127
|
+
const separator = getSeparator();
|
|
128
|
+
expect(separator).toHaveAttribute('aria-orientation', 'horizontal');
|
|
129
|
+
act(() => separator.focus());
|
|
130
|
+
fireEvent.keyDown(separator, {key: 'ArrowDown'});
|
|
131
|
+
expect(separator).toHaveAttribute(
|
|
132
|
+
'aria-valuenow',
|
|
133
|
+
String(200 + KEYBOARD_STEP),
|
|
134
|
+
);
|
|
135
|
+
fireEvent.keyDown(separator, {key: 'ArrowUp'});
|
|
136
|
+
expect(separator).toHaveAttribute('aria-valuenow', '200');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('collapses on Enter when the region is collapsible', () => {
|
|
140
|
+
render(
|
|
141
|
+
<Harness
|
|
142
|
+
config={{
|
|
143
|
+
defaultSize: 200,
|
|
144
|
+
minSizePx: 100,
|
|
145
|
+
maxSizePx: 400,
|
|
146
|
+
collapsible: true,
|
|
147
|
+
}}
|
|
148
|
+
/>,
|
|
149
|
+
);
|
|
150
|
+
const separator = getSeparator();
|
|
151
|
+
act(() => separator.focus());
|
|
152
|
+
fireEvent.keyDown(separator, {key: 'Enter'});
|
|
153
|
+
expect(separator).toHaveAttribute('aria-valuenow', '0');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// --- Disabled guard ---
|
|
157
|
+
|
|
158
|
+
it('ignores keyboard input when disabled', () => {
|
|
159
|
+
render(<Harness handleProps={{isDisabled: true}} />);
|
|
160
|
+
const separator = getSeparator();
|
|
161
|
+
expect(separator).toHaveAttribute('tabindex', '-1');
|
|
162
|
+
fireEvent.keyDown(separator, {key: 'ArrowRight'});
|
|
163
|
+
expect(separator).toHaveAttribute('aria-valuenow', '200');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// --- Drag listener lifecycle ---
|
|
167
|
+
|
|
168
|
+
it('stops driving the region and releases window listeners when unmounted mid-drag', () => {
|
|
169
|
+
const resizable: ResizableProps = {
|
|
170
|
+
_size: 200,
|
|
171
|
+
_isCollapsed: false,
|
|
172
|
+
_onResizeStart: vi.fn(),
|
|
173
|
+
_onResizeMove: vi.fn(),
|
|
174
|
+
_onResizeEnd: vi.fn(),
|
|
175
|
+
_minSizePx: 100,
|
|
176
|
+
_maxSizePx: 400,
|
|
177
|
+
_snaps: [],
|
|
178
|
+
_collapsedSize: 40,
|
|
179
|
+
_collapsible: false,
|
|
180
|
+
_isResizableProps: true,
|
|
181
|
+
};
|
|
182
|
+
const {unmount} = render(
|
|
183
|
+
<ResizeHandle resizable={resizable} label="Resize" />,
|
|
184
|
+
);
|
|
185
|
+
const separator = screen.getByRole('separator');
|
|
186
|
+
const hitArea = separator.firstElementChild as HTMLElement;
|
|
187
|
+
|
|
188
|
+
// Start a drag and confirm moves reach the region.
|
|
189
|
+
fireEvent.pointerDown(hitArea, {clientX: 0, clientY: 0});
|
|
190
|
+
expect(resizable._onResizeStart).toHaveBeenCalledTimes(1);
|
|
191
|
+
fireEvent.pointerMove(window, {clientX: 10, clientY: 0});
|
|
192
|
+
expect(resizable._onResizeMove).toHaveBeenCalledTimes(1);
|
|
193
|
+
|
|
194
|
+
// Unmount mid-drag: the window listeners must be torn down, so further
|
|
195
|
+
// pointer moves no longer resize the (still-mounted) region, and the
|
|
196
|
+
// body cursor/user-select overrides are released.
|
|
197
|
+
unmount();
|
|
198
|
+
fireEvent.pointerMove(window, {clientX: 50, clientY: 0});
|
|
199
|
+
expect(resizable._onResizeMove).toHaveBeenCalledTimes(1);
|
|
200
|
+
expect(document.body.style.cursor).toBe('');
|
|
201
|
+
expect(document.body.style.userSelect).toBe('');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// --- Prop composition (ordering choice: handler sits after {...props}) ---
|
|
205
|
+
|
|
206
|
+
it('runs a consumer onKeyDown alongside keyboard resizing', () => {
|
|
207
|
+
const onKeyDown = vi.fn();
|
|
208
|
+
render(<Harness handleProps={{onKeyDown}} />);
|
|
209
|
+
const separator = getSeparator();
|
|
210
|
+
act(() => separator.focus());
|
|
211
|
+
fireEvent.keyDown(separator, {key: 'ArrowRight'});
|
|
212
|
+
expect(onKeyDown).toHaveBeenCalledTimes(1);
|
|
213
|
+
expect(separator).toHaveAttribute(
|
|
214
|
+
'aria-valuenow',
|
|
215
|
+
String(200 + KEYBOARD_STEP),
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
@@ -316,6 +316,9 @@ export function ResizeHandle({
|
|
|
316
316
|
...props
|
|
317
317
|
}: ResizeHandleProps) {
|
|
318
318
|
const handleRef = useRef<HTMLDivElement>(null);
|
|
319
|
+
// Removes the in-flight drag's window listeners (and resets body styles).
|
|
320
|
+
// Held in a ref so unmount can tear down a drag that never got a pointerup.
|
|
321
|
+
const dragCleanupRef = useRef<(() => void) | null>(null);
|
|
319
322
|
const [isDragging, setIsDragging] = useState(false);
|
|
320
323
|
const [isHovered, setIsHovered] = useState(false);
|
|
321
324
|
const [isFocused, setIsFocused] = useState(false);
|
|
@@ -375,10 +378,12 @@ export function ResizeHandle({
|
|
|
375
378
|
window.removeEventListener('pointermove', onMove);
|
|
376
379
|
window.removeEventListener('pointerup', onUp);
|
|
377
380
|
window.removeEventListener('pointercancel', onCancel);
|
|
381
|
+
dragCleanupRef.current = null;
|
|
378
382
|
}
|
|
379
383
|
window.addEventListener('pointermove', onMove);
|
|
380
384
|
window.addEventListener('pointerup', onUp);
|
|
381
385
|
window.addEventListener('pointercancel', onCancel);
|
|
386
|
+
dragCleanupRef.current = cleanup;
|
|
382
387
|
},
|
|
383
388
|
[isDisabled, resizable, isHorizontal, getRTLMultiplier, sign],
|
|
384
389
|
);
|
|
@@ -454,14 +459,19 @@ export function ResizeHandle({
|
|
|
454
459
|
}, [isDisabled, resizable]);
|
|
455
460
|
|
|
456
461
|
// --- Cleanup on unmount ---
|
|
462
|
+
// A drag in flight when the handle unmounts never gets its pointerup, so
|
|
463
|
+
// tear down the window listeners here too — otherwise every pointermove
|
|
464
|
+
// keeps driving the (still-mounted) region's resize state after the handle
|
|
465
|
+
// is gone, and the body cursor/user-select overrides stick.
|
|
457
466
|
useEffect(() => {
|
|
458
467
|
return () => {
|
|
459
|
-
if (
|
|
468
|
+
if (dragCleanupRef.current) {
|
|
469
|
+
dragCleanupRef.current();
|
|
460
470
|
document.body.style.cursor = '';
|
|
461
471
|
document.body.style.userSelect = '';
|
|
462
472
|
}
|
|
463
473
|
};
|
|
464
|
-
}, [
|
|
474
|
+
}, []);
|
|
465
475
|
|
|
466
476
|
// --- ARIA ---
|
|
467
477
|
const ariaValueNow = resizable ? resizable._size : undefined;
|
|
@@ -510,7 +520,16 @@ export function ResizeHandle({
|
|
|
510
520
|
),
|
|
511
521
|
className,
|
|
512
522
|
)}
|
|
513
|
-
{...props}
|
|
523
|
+
{...props}
|
|
524
|
+
// Keyboard resizing must fire from the focusable separator, not a child:
|
|
525
|
+
// keydown fires on the focused element and bubbles up, so a handler on a
|
|
526
|
+
// descendant never runs (per the WAI-ARIA window-splitter pattern).
|
|
527
|
+
// Placed after {...props} and composed with any consumer onKeyDown so
|
|
528
|
+
// this accessibility-critical handler can't be clobbered by a passed prop.
|
|
529
|
+
onKeyDown={e => {
|
|
530
|
+
props.onKeyDown?.(e);
|
|
531
|
+
handleKeyDown(e);
|
|
532
|
+
}}>
|
|
514
533
|
{/* Wider invisible hit area for pointer interaction */}
|
|
515
534
|
<div
|
|
516
535
|
{...stylex.props(
|
|
@@ -528,7 +547,6 @@ export function ResizeHandle({
|
|
|
528
547
|
setIsHovered(false);
|
|
529
548
|
}
|
|
530
549
|
}}
|
|
531
|
-
onKeyDown={handleKeyDown}
|
|
532
550
|
/>
|
|
533
551
|
{/* Pill grip indicator — themed via .astryx-resize-handle-pill */}
|
|
534
552
|
{children ?? (
|
|
@@ -16,7 +16,7 @@ export const docs = {
|
|
|
16
16
|
theming: {
|
|
17
17
|
targets: [
|
|
18
18
|
{className: 'astryx-segmented-control', visualProps: ['size']},
|
|
19
|
-
{className: 'astryx-segmented-control-item'},
|
|
19
|
+
{className: 'astryx-segmented-control-item', visualProps: ['size'], states: ['selected', 'disabled']},
|
|
20
20
|
],
|
|
21
21
|
vars: [
|
|
22
22
|
{name: '--_segmented-control-radius', description: 'Border radius of the segmented control', default: 'var(--radius-element)', private: true},
|
|
@@ -259,6 +259,56 @@ describe('SegmentedControl', () => {
|
|
|
259
259
|
});
|
|
260
260
|
|
|
261
261
|
describe('SegmentedControl keyboard navigation', () => {
|
|
262
|
+
describe('tab-through is a pure focus move (#3597)', () => {
|
|
263
|
+
it('does not fire onChange when tabbing in with an unmatched value', async () => {
|
|
264
|
+
const user = userEvent.setup();
|
|
265
|
+
const onChange = vi.fn();
|
|
266
|
+
render(
|
|
267
|
+
<>
|
|
268
|
+
<button type="button">before</button>
|
|
269
|
+
<SegmentedControl label="View" value="archived" onChange={onChange}>
|
|
270
|
+
<SegmentedControlItem value="grid" label="Grid" />
|
|
271
|
+
<SegmentedControlItem value="list" label="List" />
|
|
272
|
+
</SegmentedControl>
|
|
273
|
+
</>,
|
|
274
|
+
);
|
|
275
|
+
screen.getByText('before').focus();
|
|
276
|
+
await user.tab();
|
|
277
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('does not fire onChange when tabbing in while the selected item is disabled', async () => {
|
|
281
|
+
const user = userEvent.setup();
|
|
282
|
+
const onChange = vi.fn();
|
|
283
|
+
render(
|
|
284
|
+
<>
|
|
285
|
+
<button type="button">before</button>
|
|
286
|
+
<SegmentedControl label="View" value="list" onChange={onChange}>
|
|
287
|
+
<SegmentedControlItem value="grid" label="Grid" />
|
|
288
|
+
<SegmentedControlItem value="list" label="List" isDisabled />
|
|
289
|
+
</SegmentedControl>
|
|
290
|
+
</>,
|
|
291
|
+
);
|
|
292
|
+
screen.getByText('before').focus();
|
|
293
|
+
await user.tab();
|
|
294
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('still selects on arrow-key navigation within the group', async () => {
|
|
298
|
+
const user = userEvent.setup();
|
|
299
|
+
const onChange = vi.fn();
|
|
300
|
+
render(
|
|
301
|
+
<SegmentedControl label="View" value="grid" onChange={onChange}>
|
|
302
|
+
<SegmentedControlItem value="grid" label="Grid" />
|
|
303
|
+
<SegmentedControlItem value="list" label="List" />
|
|
304
|
+
</SegmentedControl>,
|
|
305
|
+
);
|
|
306
|
+
screen.getByRole('radio', {name: 'Grid'}).focus();
|
|
307
|
+
await user.keyboard('{ArrowRight}');
|
|
308
|
+
expect(onChange).toHaveBeenCalledWith('list');
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
262
312
|
it('navigates with ArrowRight and selects', async () => {
|
|
263
313
|
const user = userEvent.setup();
|
|
264
314
|
const handleChange = vi.fn();
|
|
@@ -588,3 +638,145 @@ describe('SegmentedControl disabled state', () => {
|
|
|
588
638
|
});
|
|
589
639
|
});
|
|
590
640
|
});
|
|
641
|
+
|
|
642
|
+
describe('SegmentedControl data-testid forwarding', () => {
|
|
643
|
+
it('forwards data-testid to the radiogroup', () => {
|
|
644
|
+
render(
|
|
645
|
+
<SegmentedControl
|
|
646
|
+
value="grid"
|
|
647
|
+
onChange={() => {}}
|
|
648
|
+
label="View mode"
|
|
649
|
+
data-testid="view-toggle">
|
|
650
|
+
<SegmentedControlItem value="grid" label="Grid" />
|
|
651
|
+
<SegmentedControlItem value="list" label="List" />
|
|
652
|
+
</SegmentedControl>,
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
expect(screen.getByTestId('view-toggle')).toBe(
|
|
656
|
+
screen.getByRole('radiogroup'),
|
|
657
|
+
);
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
it('forwards data-testid to an individual item button', () => {
|
|
661
|
+
render(
|
|
662
|
+
<SegmentedControl value="grid" onChange={() => {}} label="View mode">
|
|
663
|
+
<SegmentedControlItem
|
|
664
|
+
value="grid"
|
|
665
|
+
label="Grid"
|
|
666
|
+
data-testid="opt-grid"
|
|
667
|
+
/>
|
|
668
|
+
<SegmentedControlItem
|
|
669
|
+
value="list"
|
|
670
|
+
label="List"
|
|
671
|
+
data-testid="opt-list"
|
|
672
|
+
/>
|
|
673
|
+
</SegmentedControl>,
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
expect(screen.getByTestId('opt-grid')).toBe(
|
|
677
|
+
screen.getByRole('radio', {name: 'Grid'}),
|
|
678
|
+
);
|
|
679
|
+
expect(screen.getByTestId('opt-list')).toBe(
|
|
680
|
+
screen.getByRole('radio', {name: 'List'}),
|
|
681
|
+
);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
it('does not let a forwarded prop override the computed role', () => {
|
|
685
|
+
render(
|
|
686
|
+
// A consumer-supplied role must not clobber the component's own
|
|
687
|
+
// radiogroup role (the computed role is applied after {...rest}).
|
|
688
|
+
<SegmentedControl
|
|
689
|
+
value="grid"
|
|
690
|
+
onChange={() => {}}
|
|
691
|
+
label="View mode"
|
|
692
|
+
role="tablist"
|
|
693
|
+
data-testid="view-toggle">
|
|
694
|
+
<SegmentedControlItem value="grid" label="Grid" />
|
|
695
|
+
</SegmentedControl>,
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
expect(screen.getByTestId('view-toggle')).toHaveAttribute(
|
|
699
|
+
'role',
|
|
700
|
+
'radiogroup',
|
|
701
|
+
);
|
|
702
|
+
});
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
describe('SegmentedControlItem onClick composition', () => {
|
|
706
|
+
it('calls a consumer onClick in addition to selecting the item', () => {
|
|
707
|
+
const onChange = vi.fn();
|
|
708
|
+
const onClick = vi.fn();
|
|
709
|
+
render(
|
|
710
|
+
<SegmentedControl value="grid" onChange={onChange} label="View mode">
|
|
711
|
+
<SegmentedControlItem value="list" label="List" onClick={onClick} />
|
|
712
|
+
</SegmentedControl>,
|
|
713
|
+
);
|
|
714
|
+
|
|
715
|
+
fireEvent.click(screen.getByRole('radio', {name: 'List'}));
|
|
716
|
+
|
|
717
|
+
expect(onClick).toHaveBeenCalledTimes(1);
|
|
718
|
+
expect(onChange).toHaveBeenCalledWith('list');
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
it('lets a consumer onClick opt out of selection via preventDefault', () => {
|
|
722
|
+
const onChange = vi.fn();
|
|
723
|
+
render(
|
|
724
|
+
<SegmentedControl value="grid" onChange={onChange} label="View mode">
|
|
725
|
+
<SegmentedControlItem
|
|
726
|
+
value="list"
|
|
727
|
+
label="List"
|
|
728
|
+
onClick={e => e.preventDefault()}
|
|
729
|
+
/>
|
|
730
|
+
</SegmentedControl>,
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
fireEvent.click(screen.getByRole('radio', {name: 'List'}));
|
|
734
|
+
|
|
735
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
describe('SegmentedControl container handler forwarding', () => {
|
|
740
|
+
it('forwards a consumer onKeyDown while keeping arrow-key navigation', async () => {
|
|
741
|
+
const user = userEvent.setup();
|
|
742
|
+
const onKeyDown = vi.fn();
|
|
743
|
+
const onChange = vi.fn();
|
|
744
|
+
render(
|
|
745
|
+
<SegmentedControl
|
|
746
|
+
value="grid"
|
|
747
|
+
onChange={onChange}
|
|
748
|
+
label="View mode"
|
|
749
|
+
onKeyDown={onKeyDown}>
|
|
750
|
+
<SegmentedControlItem value="grid" label="Grid" />
|
|
751
|
+
<SegmentedControlItem value="list" label="List" />
|
|
752
|
+
</SegmentedControl>,
|
|
753
|
+
);
|
|
754
|
+
|
|
755
|
+
screen.getByRole('radio', {name: 'Grid'}).focus();
|
|
756
|
+
await user.keyboard('{ArrowRight}');
|
|
757
|
+
|
|
758
|
+
expect(onKeyDown).toHaveBeenCalled();
|
|
759
|
+
// Built-in navigation still ran.
|
|
760
|
+
expect(onChange).toHaveBeenCalledWith('list');
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
it('lets a consumer onKeyDown opt out of built-in navigation via preventDefault', async () => {
|
|
764
|
+
const user = userEvent.setup();
|
|
765
|
+
const onChange = vi.fn();
|
|
766
|
+
render(
|
|
767
|
+
<SegmentedControl
|
|
768
|
+
value="grid"
|
|
769
|
+
onChange={onChange}
|
|
770
|
+
label="View mode"
|
|
771
|
+
onKeyDown={e => e.preventDefault()}>
|
|
772
|
+
<SegmentedControlItem value="grid" label="Grid" />
|
|
773
|
+
<SegmentedControlItem value="list" label="List" />
|
|
774
|
+
</SegmentedControl>,
|
|
775
|
+
);
|
|
776
|
+
|
|
777
|
+
screen.getByRole('radio', {name: 'Grid'}).focus();
|
|
778
|
+
await user.keyboard('{ArrowRight}');
|
|
779
|
+
|
|
780
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
781
|
+
});
|
|
782
|
+
});
|
|
@@ -26,7 +26,7 @@ import type {
|
|
|
26
26
|
SegmentedControlSize,
|
|
27
27
|
SegmentedControlLayout,
|
|
28
28
|
} from './SegmentedControlContext';
|
|
29
|
-
import {mergeProps, mergeRefs} from '../utils';
|
|
29
|
+
import {mergeProps, mergeRefs, composeEventHandlers} from '../utils';
|
|
30
30
|
import {useSize} from '../SizeContext/SizeContext';
|
|
31
31
|
import type {BaseProps} from '../BaseProps';
|
|
32
32
|
import {themeProps} from '../utils/themeProps';
|
|
@@ -152,6 +152,10 @@ export function SegmentedControl({
|
|
|
152
152
|
xstyle,
|
|
153
153
|
className,
|
|
154
154
|
style,
|
|
155
|
+
onKeyDown: onKeyDownProp,
|
|
156
|
+
onFocus: onFocusProp,
|
|
157
|
+
onBlur: onBlurProp,
|
|
158
|
+
...rest
|
|
155
159
|
}: SegmentedControlProps) {
|
|
156
160
|
const size = useSize(sizeProp, 'md');
|
|
157
161
|
|
|
@@ -188,10 +192,14 @@ export function SegmentedControl({
|
|
|
188
192
|
|
|
189
193
|
const handleContainerKeyDown = useCallback(
|
|
190
194
|
(e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
195
|
+
onKeyDownProp?.(e);
|
|
196
|
+
if (e.defaultPrevented) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
191
199
|
hint.onKeyDown(e);
|
|
192
200
|
handleKeyDown(e);
|
|
193
201
|
},
|
|
194
|
-
[hint, handleKeyDown],
|
|
202
|
+
[onKeyDownProp, hint, handleKeyDown],
|
|
195
203
|
);
|
|
196
204
|
|
|
197
205
|
// Selection-follows-focus (APG radiogroup): useListFocus only *moves* focus,
|
|
@@ -202,12 +210,25 @@ export function SegmentedControl({
|
|
|
202
210
|
// and the already-selected value is skipped so an initial Tab-in (or a click
|
|
203
211
|
// on the current segment) is a no-op, matching click behavior.
|
|
204
212
|
const handleContainerFocus = useCallback(
|
|
205
|
-
(e: React.FocusEvent) => {
|
|
213
|
+
(e: React.FocusEvent<HTMLDivElement>) => {
|
|
214
|
+
onFocusProp?.(e);
|
|
215
|
+
if (e.defaultPrevented) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
206
218
|
hint.onFocus(e);
|
|
207
219
|
handleFocus(e);
|
|
208
220
|
if (isDisabled) {
|
|
209
221
|
return;
|
|
210
222
|
}
|
|
223
|
+
// Only select when focus moved WITHIN the group (arrow/Home/End — APG
|
|
224
|
+
// selection-follows-focus). When focus is entering from outside, Tab
|
|
225
|
+
// must stay a pure focus move: with an unmatched or disabled-selected
|
|
226
|
+
// value the roving tab stop falls back to the first enabled radio, and
|
|
227
|
+
// selecting it here would rewrite the form value on mere traversal.
|
|
228
|
+
// Clicks are unaffected: the item's own handleClick selects.
|
|
229
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
211
232
|
const focused = (e.target as HTMLElement | null)?.closest<HTMLElement>(
|
|
212
233
|
'[role="radio"][data-value]',
|
|
213
234
|
);
|
|
@@ -219,7 +240,7 @@ export function SegmentedControl({
|
|
|
219
240
|
onChange(nextValue);
|
|
220
241
|
}
|
|
221
242
|
},
|
|
222
|
-
[hint, handleFocus, isDisabled, onChange, value],
|
|
243
|
+
[onFocusProp, hint, handleFocus, isDisabled, onChange, value],
|
|
223
244
|
);
|
|
224
245
|
|
|
225
246
|
const contextValue = useMemo(
|
|
@@ -238,6 +259,7 @@ export function SegmentedControl({
|
|
|
238
259
|
<SegmentedControlContext value={contextValue}>
|
|
239
260
|
<div
|
|
240
261
|
ref={mergeRefs(ref, listRef, disabledMessageTooltip.ref)}
|
|
262
|
+
{...rest}
|
|
241
263
|
role="radiogroup"
|
|
242
264
|
aria-label={label}
|
|
243
265
|
aria-disabled={isDisabled || undefined}
|
|
@@ -246,7 +268,7 @@ export function SegmentedControl({
|
|
|
246
268
|
}
|
|
247
269
|
onKeyDown={handleContainerKeyDown}
|
|
248
270
|
onFocus={handleContainerFocus}
|
|
249
|
-
onBlur={hint.onBlur}
|
|
271
|
+
onBlur={composeEventHandlers(onBlurProp, hint.onBlur)}
|
|
250
272
|
{...mergeProps(
|
|
251
273
|
themeProps('segmented-control', {size}),
|
|
252
274
|
stylex.props(
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* - /packages/cli/templates/blocks/components/SegmentedControl/ (showcase blocks)
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import React, {
|
|
18
|
+
import React, {type ReactNode} from 'react';
|
|
19
19
|
import * as stylex from '@stylexjs/stylex';
|
|
20
20
|
import {
|
|
21
21
|
colorVars,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
} from '../theme/tokens.stylex';
|
|
30
30
|
import {useSegmentedControlContext} from './SegmentedControlContext';
|
|
31
31
|
import type {SegmentedControlSize} from './SegmentedControlContext';
|
|
32
|
-
import {mergeProps} from '../utils';
|
|
32
|
+
import {mergeProps, composeEventHandlers} from '../utils';
|
|
33
33
|
import type {BaseProps} from '../BaseProps';
|
|
34
34
|
import {themeProps} from '../utils/themeProps';
|
|
35
35
|
|
|
@@ -168,6 +168,8 @@ export function SegmentedControlItem({
|
|
|
168
168
|
isLabelHidden = false,
|
|
169
169
|
icon,
|
|
170
170
|
isDisabled = false,
|
|
171
|
+
onClick: onClickProp,
|
|
172
|
+
...rest
|
|
171
173
|
}: SegmentedControlItemProps) {
|
|
172
174
|
const ctx = useSegmentedControlContext();
|
|
173
175
|
|
|
@@ -182,11 +184,13 @@ export function SegmentedControlItem({
|
|
|
182
184
|
const size: SegmentedControlSize = ctx.size;
|
|
183
185
|
const isFill = ctx.layout === 'fill';
|
|
184
186
|
|
|
185
|
-
|
|
187
|
+
// Consumer-first: a consumer onClick can call preventDefault() to opt out of
|
|
188
|
+
// selection; otherwise selection proceeds when enabled and not selected.
|
|
189
|
+
const handleClick = composeEventHandlers(onClickProp, () => {
|
|
186
190
|
if (!isItemDisabled && !isSelected) {
|
|
187
191
|
ctx.onChange(value);
|
|
188
192
|
}
|
|
189
|
-
}
|
|
193
|
+
});
|
|
190
194
|
|
|
191
195
|
const iconElement = icon ? (
|
|
192
196
|
<span {...stylex.props(styles.icon, iconSizeStyles[size])}>{icon}</span>
|
|
@@ -195,6 +199,7 @@ export function SegmentedControlItem({
|
|
|
195
199
|
return (
|
|
196
200
|
<button
|
|
197
201
|
ref={ref}
|
|
202
|
+
{...rest}
|
|
198
203
|
type="button"
|
|
199
204
|
role="radio"
|
|
200
205
|
aria-checked={isSelected}
|
|
@@ -34,7 +34,7 @@ export const docs = {
|
|
|
34
34
|
],
|
|
35
35
|
theming: {
|
|
36
36
|
container: true,
|
|
37
|
-
targets: [{className: 'astryx-selectable-card', visualProps: ['selected']}],
|
|
37
|
+
targets: [{className: 'astryx-selectable-card', visualProps: ['selected', 'variant']}],
|
|
38
38
|
},
|
|
39
39
|
playground: {
|
|
40
40
|
defaults: {
|
|
@@ -186,7 +186,33 @@ describe('Selector', () => {
|
|
|
186
186
|
.getByRole('listbox', {hidden: true})
|
|
187
187
|
.closest('[popover]');
|
|
188
188
|
expect(popover?.getAttribute('style')).toContain(
|
|
189
|
-
'position-area:
|
|
189
|
+
'position-area: self-block-start span-self-inline-end',
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('emits the direction-independent logical mapping under an RTL ancestor (#3389)', async () => {
|
|
194
|
+
// The self-* position-area keywords resolve against the popover's own
|
|
195
|
+
// inherited direction in the browser, so RTL emits the same string as
|
|
196
|
+
// LTR and the mirroring is pure CSS — jsdom can only assert the string.
|
|
197
|
+
const user = userEvent.setup();
|
|
198
|
+
render(
|
|
199
|
+
<div style={{direction: 'rtl'}}>
|
|
200
|
+
<Selector
|
|
201
|
+
label="Fruit"
|
|
202
|
+
options={OPTIONS}
|
|
203
|
+
value="Banana"
|
|
204
|
+
onChange={() => {}}
|
|
205
|
+
/>
|
|
206
|
+
</div>,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
await user.click(screen.getByRole('combobox'));
|
|
210
|
+
|
|
211
|
+
const popover = screen
|
|
212
|
+
.getByRole('listbox', {hidden: true})
|
|
213
|
+
.closest('[popover]');
|
|
214
|
+
expect(popover?.getAttribute('style')).toContain(
|
|
215
|
+
'position-area: self-block-end span-self-inline-end',
|
|
190
216
|
);
|
|
191
217
|
});
|
|
192
218
|
|