@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
|
@@ -14,6 +14,12 @@ export const docs = {
|
|
|
14
14
|
type: 'ReactNode',
|
|
15
15
|
description: 'Content.',
|
|
16
16
|
},
|
|
17
|
+
{
|
|
18
|
+
name: 'padding',
|
|
19
|
+
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
20
|
+
description:
|
|
21
|
+
'Internal padding using the spacing scale. Overrides the default padding from the layout container.',
|
|
22
|
+
},
|
|
17
23
|
{
|
|
18
24
|
name: 'isScrollable',
|
|
19
25
|
type: 'boolean',
|
|
@@ -44,6 +50,11 @@ export const docsZh = {
|
|
|
44
50
|
type: 'ReactNode',
|
|
45
51
|
description: '内容。',
|
|
46
52
|
},
|
|
53
|
+
{
|
|
54
|
+
name: 'padding',
|
|
55
|
+
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
56
|
+
description: '使用间距比例的内边距。覆盖布局容器的默认内边距。',
|
|
57
|
+
},
|
|
47
58
|
{
|
|
48
59
|
name: 'isScrollable',
|
|
49
60
|
type: 'boolean',
|
|
@@ -70,6 +81,7 @@ export const docsDense = {
|
|
|
70
81
|
description: 'Scrollable main content area.',
|
|
71
82
|
propDescriptions: {
|
|
72
83
|
children: 'Content.',
|
|
84
|
+
padding: 'Internal padding on spacing scale. Overrides layout container default.',
|
|
73
85
|
isScrollable: 'Enable scrollable overflow.',
|
|
74
86
|
label: 'Accessible label for landmark element.',
|
|
75
87
|
role: 'ARIA landmark role.',
|
|
@@ -20,6 +20,12 @@ export const docs = {
|
|
|
20
20
|
description: 'Border on the appropriate edge.',
|
|
21
21
|
default: 'false',
|
|
22
22
|
},
|
|
23
|
+
{
|
|
24
|
+
name: 'padding',
|
|
25
|
+
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
26
|
+
description:
|
|
27
|
+
'Internal padding using the spacing scale. Overrides the default padding from the layout container.',
|
|
28
|
+
},
|
|
23
29
|
{
|
|
24
30
|
name: 'isScrollable',
|
|
25
31
|
type: 'boolean',
|
|
@@ -36,6 +42,18 @@ export const docs = {
|
|
|
36
42
|
type: 'AriaRole',
|
|
37
43
|
description: 'ARIA landmark role.',
|
|
38
44
|
},
|
|
45
|
+
{
|
|
46
|
+
name: 'width',
|
|
47
|
+
type: 'number | string',
|
|
48
|
+
description:
|
|
49
|
+
'Width of the panel. Numbers are treated as pixels, strings are used as-is. Ignored when resizable is provided; the hook controls width.',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'resizable',
|
|
53
|
+
type: 'ResizableProps',
|
|
54
|
+
description:
|
|
55
|
+
'Resize props from useResizable(). When provided, the hook drives the panel width and a ResizeHandle should be placed adjacent to the panel.',
|
|
56
|
+
},
|
|
39
57
|
],
|
|
40
58
|
};
|
|
41
59
|
|
|
@@ -56,6 +74,11 @@ export const docsZh = {
|
|
|
56
74
|
description: '相应边缘的边框。',
|
|
57
75
|
default: 'false',
|
|
58
76
|
},
|
|
77
|
+
{
|
|
78
|
+
name: 'padding',
|
|
79
|
+
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
80
|
+
description: '使用间距比例的内边距。覆盖布局容器的默认内边距。',
|
|
81
|
+
},
|
|
59
82
|
{
|
|
60
83
|
name: 'isScrollable',
|
|
61
84
|
type: 'boolean',
|
|
@@ -72,6 +95,18 @@ export const docsZh = {
|
|
|
72
95
|
type: 'AriaRole',
|
|
73
96
|
description: 'ARIA 地标角色。',
|
|
74
97
|
},
|
|
98
|
+
{
|
|
99
|
+
name: 'width',
|
|
100
|
+
type: 'number | string',
|
|
101
|
+
description:
|
|
102
|
+
'面板宽度。数字按像素处理,字符串按原样使用。提供 resizable 时忽略,宽度由 hook 控制。',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'resizable',
|
|
106
|
+
type: 'ResizableProps',
|
|
107
|
+
description:
|
|
108
|
+
'来自 useResizable() 的调整大小属性。提供时面板宽度由 hook 驱动,应在面板旁放置 ResizeHandle。',
|
|
109
|
+
},
|
|
75
110
|
],
|
|
76
111
|
};
|
|
77
112
|
|
|
@@ -83,8 +118,13 @@ export const docsDense = {
|
|
|
83
118
|
propDescriptions: {
|
|
84
119
|
children: 'Panel content.',
|
|
85
120
|
hasDivider: 'Border on appropriate edge.',
|
|
121
|
+
padding: 'Internal padding on spacing scale. Overrides layout container default.',
|
|
86
122
|
isScrollable: 'Enable scrollable overflow.',
|
|
87
123
|
label: 'Accessible label for landmark element.',
|
|
88
124
|
role: 'ARIA landmark role.',
|
|
125
|
+
width:
|
|
126
|
+
'Panel width. Numbers = pixels, strings as-is. Ignored when resizable provided; hook controls width.',
|
|
127
|
+
resizable:
|
|
128
|
+
'Resize props from useResizable(). Hook drives panel width; place ResizeHandle adjacent.',
|
|
89
129
|
},
|
|
90
130
|
};
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file LayoutSlots.test.tsx
|
|
5
|
+
* @input Uses vitest, @testing-library/react, Layout slot components
|
|
6
|
+
* @output Characterization tests for LayoutHeader, LayoutFooter,
|
|
7
|
+
* LayoutContent and LayoutPanel
|
|
8
|
+
* @position Testing; validates the slot primitives' rendering, landmark roles,
|
|
9
|
+
* divider reflection, sizing and context-driven behavior
|
|
10
|
+
*
|
|
11
|
+
* SYNC: When LayoutHeader/LayoutFooter/LayoutContent/LayoutPanel change,
|
|
12
|
+
* update tests to match new behavior
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {describe, it, expect} from 'vitest';
|
|
16
|
+
import {render, screen} from '@testing-library/react';
|
|
17
|
+
import {createRef} from 'react';
|
|
18
|
+
import {Layout} from './Layout';
|
|
19
|
+
import {LayoutHeader} from './LayoutHeader';
|
|
20
|
+
import {LayoutFooter} from './LayoutFooter';
|
|
21
|
+
import {LayoutContent} from './LayoutContent';
|
|
22
|
+
import {LayoutPanel} from './LayoutPanel';
|
|
23
|
+
import {LayoutDividerContext} from './LayoutDividerContext';
|
|
24
|
+
import {useResizable} from '../Resizable/useResizable';
|
|
25
|
+
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// LayoutHeader
|
|
28
|
+
// =============================================================================
|
|
29
|
+
|
|
30
|
+
describe('LayoutHeader', () => {
|
|
31
|
+
it('renders its children', () => {
|
|
32
|
+
render(<LayoutHeader>Page title</LayoutHeader>);
|
|
33
|
+
expect(screen.getByText('Page title')).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('carries the astryx-layout-header class', () => {
|
|
37
|
+
const {container} = render(<LayoutHeader>H</LayoutHeader>);
|
|
38
|
+
expect(
|
|
39
|
+
container.querySelector('.astryx-layout-header'),
|
|
40
|
+
).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('exposes a landmark role and accessible name', () => {
|
|
44
|
+
render(
|
|
45
|
+
<LayoutHeader role="banner" label="Site header">
|
|
46
|
+
H
|
|
47
|
+
</LayoutHeader>,
|
|
48
|
+
);
|
|
49
|
+
expect(
|
|
50
|
+
screen.getByRole('banner', {name: 'Site header'}),
|
|
51
|
+
).toBeInTheDocument();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('omits data-divider by default', () => {
|
|
55
|
+
const {container} = render(<LayoutHeader>H</LayoutHeader>);
|
|
56
|
+
expect(
|
|
57
|
+
container
|
|
58
|
+
.querySelector('.astryx-layout-header')
|
|
59
|
+
?.hasAttribute('data-divider'),
|
|
60
|
+
).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('reflects hasDivider as data-divider="true"', () => {
|
|
64
|
+
const {container} = render(<LayoutHeader hasDivider>H</LayoutHeader>);
|
|
65
|
+
expect(
|
|
66
|
+
container
|
|
67
|
+
.querySelector('.astryx-layout-header')
|
|
68
|
+
?.getAttribute('data-divider'),
|
|
69
|
+
).toBe('true');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('inherits the divider default from LayoutDividerContext', () => {
|
|
73
|
+
const {container} = render(
|
|
74
|
+
<LayoutDividerContext value={{defaultHasDividers: true}}>
|
|
75
|
+
<LayoutHeader>H</LayoutHeader>
|
|
76
|
+
</LayoutDividerContext>,
|
|
77
|
+
);
|
|
78
|
+
expect(
|
|
79
|
+
container
|
|
80
|
+
.querySelector('.astryx-layout-header')
|
|
81
|
+
?.getAttribute('data-divider'),
|
|
82
|
+
).toBe('true');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('an explicit hasDivider={false} overrides an inherited true default', () => {
|
|
86
|
+
const {container} = render(
|
|
87
|
+
<LayoutDividerContext value={{defaultHasDividers: true}}>
|
|
88
|
+
<LayoutHeader hasDivider={false}>H</LayoutHeader>
|
|
89
|
+
</LayoutDividerContext>,
|
|
90
|
+
);
|
|
91
|
+
expect(
|
|
92
|
+
container
|
|
93
|
+
.querySelector('.astryx-layout-header')
|
|
94
|
+
?.hasAttribute('data-divider'),
|
|
95
|
+
).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('applies a numeric height to the element style', () => {
|
|
99
|
+
const {container} = render(<LayoutHeader height={64}>H</LayoutHeader>);
|
|
100
|
+
const el = container.querySelector('.astryx-layout-header') as HTMLElement;
|
|
101
|
+
expect(el.getAttribute('style') ?? '').toContain('64px');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('forwards ref to the outer element', () => {
|
|
105
|
+
const ref = createRef<HTMLDivElement>();
|
|
106
|
+
render(<LayoutHeader ref={ref}>H</LayoutHeader>);
|
|
107
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement);
|
|
108
|
+
expect(ref.current?.className).toContain('astryx-layout-header');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('merges a caller className', () => {
|
|
112
|
+
const {container} = render(
|
|
113
|
+
<LayoutHeader className="hdr-custom">H</LayoutHeader>,
|
|
114
|
+
);
|
|
115
|
+
const el = container.querySelector('.astryx-layout-header') as HTMLElement;
|
|
116
|
+
expect(el.className).toContain('hdr-custom');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('renders children in an inner wrapper (padding owner), not directly on the root', () => {
|
|
120
|
+
const {container} = render(<LayoutHeader>Inner</LayoutHeader>);
|
|
121
|
+
const root = container.querySelector(
|
|
122
|
+
'.astryx-layout-header',
|
|
123
|
+
) as HTMLElement;
|
|
124
|
+
// Children live in a nested inner wrapper (the padding owner), not on the
|
|
125
|
+
// divider-owning root itself.
|
|
126
|
+
const inner = screen.getByText('Inner');
|
|
127
|
+
expect(inner).not.toBe(root);
|
|
128
|
+
expect(inner.parentElement).toBe(root);
|
|
129
|
+
expect(root).toContainElement(inner);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// =============================================================================
|
|
134
|
+
// LayoutFooter
|
|
135
|
+
// =============================================================================
|
|
136
|
+
|
|
137
|
+
describe('LayoutFooter', () => {
|
|
138
|
+
it('renders its children', () => {
|
|
139
|
+
render(<LayoutFooter>Actions</LayoutFooter>);
|
|
140
|
+
expect(screen.getByText('Actions')).toBeInTheDocument();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('carries the astryx-layout-footer class', () => {
|
|
144
|
+
const {container} = render(<LayoutFooter>F</LayoutFooter>);
|
|
145
|
+
expect(
|
|
146
|
+
container.querySelector('.astryx-layout-footer'),
|
|
147
|
+
).toBeInTheDocument();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('exposes a landmark role and accessible name', () => {
|
|
151
|
+
render(
|
|
152
|
+
<LayoutFooter role="contentinfo" label="Page footer">
|
|
153
|
+
F
|
|
154
|
+
</LayoutFooter>,
|
|
155
|
+
);
|
|
156
|
+
expect(
|
|
157
|
+
screen.getByRole('contentinfo', {name: 'Page footer'}),
|
|
158
|
+
).toBeInTheDocument();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('omits data-divider by default and reflects hasDivider when set', () => {
|
|
162
|
+
const {container, rerender} = render(<LayoutFooter>F</LayoutFooter>);
|
|
163
|
+
const sel = '.astryx-layout-footer';
|
|
164
|
+
expect(container.querySelector(sel)?.hasAttribute('data-divider')).toBe(
|
|
165
|
+
false,
|
|
166
|
+
);
|
|
167
|
+
rerender(<LayoutFooter hasDivider>F</LayoutFooter>);
|
|
168
|
+
expect(container.querySelector(sel)?.getAttribute('data-divider')).toBe(
|
|
169
|
+
'true',
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('inherits the divider default from context', () => {
|
|
174
|
+
const {container} = render(
|
|
175
|
+
<LayoutDividerContext value={{defaultHasDividers: true}}>
|
|
176
|
+
<LayoutFooter>F</LayoutFooter>
|
|
177
|
+
</LayoutDividerContext>,
|
|
178
|
+
);
|
|
179
|
+
expect(
|
|
180
|
+
container
|
|
181
|
+
.querySelector('.astryx-layout-footer')
|
|
182
|
+
?.getAttribute('data-divider'),
|
|
183
|
+
).toBe('true');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('forwards ref to the outer element', () => {
|
|
187
|
+
const ref = createRef<HTMLDivElement>();
|
|
188
|
+
render(<LayoutFooter ref={ref}>F</LayoutFooter>);
|
|
189
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement);
|
|
190
|
+
expect(ref.current?.className).toContain('astryx-layout-footer');
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// =============================================================================
|
|
195
|
+
// LayoutContent
|
|
196
|
+
// =============================================================================
|
|
197
|
+
|
|
198
|
+
describe('LayoutContent', () => {
|
|
199
|
+
it('renders its children', () => {
|
|
200
|
+
render(<LayoutContent>Body</LayoutContent>);
|
|
201
|
+
expect(screen.getByText('Body')).toBeInTheDocument();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('carries the astryx-layout-content class', () => {
|
|
205
|
+
const {container} = render(<LayoutContent>C</LayoutContent>);
|
|
206
|
+
expect(
|
|
207
|
+
container.querySelector('.astryx-layout-content'),
|
|
208
|
+
).toBeInTheDocument();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('exposes the main landmark role with an accessible name', () => {
|
|
212
|
+
render(
|
|
213
|
+
<LayoutContent role="main" label="Main content">
|
|
214
|
+
C
|
|
215
|
+
</LayoutContent>,
|
|
216
|
+
);
|
|
217
|
+
expect(
|
|
218
|
+
screen.getByRole('main', {name: 'Main content'}),
|
|
219
|
+
).toBeInTheDocument();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('forwards ref to the element', () => {
|
|
223
|
+
const ref = createRef<HTMLDivElement>();
|
|
224
|
+
render(<LayoutContent ref={ref}>C</LayoutContent>);
|
|
225
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement);
|
|
226
|
+
expect(ref.current?.className).toContain('astryx-layout-content');
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('merges caller className and inline style', () => {
|
|
230
|
+
const {container} = render(
|
|
231
|
+
<LayoutContent className="body-custom" style={{color: 'rgb(1, 2, 3)'}}>
|
|
232
|
+
C
|
|
233
|
+
</LayoutContent>,
|
|
234
|
+
);
|
|
235
|
+
const el = container.querySelector('.astryx-layout-content') as HTMLElement;
|
|
236
|
+
expect(el.className).toContain('body-custom');
|
|
237
|
+
expect(el.style.color).toBe('rgb(1, 2, 3)');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('renders correctly as the content slot of a Layout (reads slot context)', () => {
|
|
241
|
+
render(
|
|
242
|
+
<Layout
|
|
243
|
+
header={<LayoutHeader>H</LayoutHeader>}
|
|
244
|
+
content={<LayoutContent role="main">Main</LayoutContent>}
|
|
245
|
+
/>,
|
|
246
|
+
);
|
|
247
|
+
expect(screen.getByRole('main')).toHaveTextContent('Main');
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('accepts padding={0} (full bleed) and a numeric padding without crashing', () => {
|
|
251
|
+
const {rerender, container} = render(
|
|
252
|
+
<LayoutContent padding={0}>C</LayoutContent>,
|
|
253
|
+
);
|
|
254
|
+
expect(
|
|
255
|
+
container.querySelector('.astryx-layout-content'),
|
|
256
|
+
).toBeInTheDocument();
|
|
257
|
+
rerender(<LayoutContent padding={6}>C</LayoutContent>);
|
|
258
|
+
expect(
|
|
259
|
+
container.querySelector('.astryx-layout-content'),
|
|
260
|
+
).toBeInTheDocument();
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// =============================================================================
|
|
265
|
+
// LayoutPanel
|
|
266
|
+
// =============================================================================
|
|
267
|
+
|
|
268
|
+
describe('LayoutPanel', () => {
|
|
269
|
+
it('renders its children', () => {
|
|
270
|
+
render(<LayoutPanel>Nav</LayoutPanel>);
|
|
271
|
+
expect(screen.getByText('Nav')).toBeInTheDocument();
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('carries the astryx-layout-panel class', () => {
|
|
275
|
+
const {container} = render(<LayoutPanel>P</LayoutPanel>);
|
|
276
|
+
expect(container.querySelector('.astryx-layout-panel')).toBeInTheDocument();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('exposes a navigation landmark with an accessible name', () => {
|
|
280
|
+
render(
|
|
281
|
+
<LayoutPanel role="navigation" label="Primary">
|
|
282
|
+
P
|
|
283
|
+
</LayoutPanel>,
|
|
284
|
+
);
|
|
285
|
+
expect(
|
|
286
|
+
screen.getByRole('navigation', {name: 'Primary'}),
|
|
287
|
+
).toBeInTheDocument();
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('applies a numeric width to the element style', () => {
|
|
291
|
+
const {container} = render(<LayoutPanel width={240}>P</LayoutPanel>);
|
|
292
|
+
const el = container.querySelector('.astryx-layout-panel') as HTMLElement;
|
|
293
|
+
expect(el.getAttribute('style') ?? '').toContain('240px');
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('applies a string width to the element style', () => {
|
|
297
|
+
const {container} = render(<LayoutPanel width="18rem">P</LayoutPanel>);
|
|
298
|
+
const el = container.querySelector('.astryx-layout-panel') as HTMLElement;
|
|
299
|
+
expect(el.getAttribute('style') ?? '').toContain('18rem');
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('resizable._size overrides the width prop', () => {
|
|
303
|
+
function Harness() {
|
|
304
|
+
const region = useResizable({defaultSize: 300});
|
|
305
|
+
return (
|
|
306
|
+
<LayoutPanel width={100} resizable={region.props}>
|
|
307
|
+
P
|
|
308
|
+
</LayoutPanel>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
const {container} = render(<Harness />);
|
|
312
|
+
const el = container.querySelector('.astryx-layout-panel') as HTMLElement;
|
|
313
|
+
const style = el.getAttribute('style') ?? '';
|
|
314
|
+
expect(style).toContain('300px');
|
|
315
|
+
expect(style).not.toContain('100px');
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('forwards ref to the element', () => {
|
|
319
|
+
const ref = createRef<HTMLDivElement>();
|
|
320
|
+
render(<LayoutPanel ref={ref}>P</LayoutPanel>);
|
|
321
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement);
|
|
322
|
+
expect(ref.current?.className).toContain('astryx-layout-panel');
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('renders as a start-slot panel inside a Layout without crashing', () => {
|
|
326
|
+
render(
|
|
327
|
+
<Layout
|
|
328
|
+
start={
|
|
329
|
+
<LayoutPanel hasDivider role="navigation" label="Side">
|
|
330
|
+
Sidebar
|
|
331
|
+
</LayoutPanel>
|
|
332
|
+
}
|
|
333
|
+
content={<LayoutContent>Main</LayoutContent>}
|
|
334
|
+
/>,
|
|
335
|
+
);
|
|
336
|
+
expect(screen.getByRole('navigation', {name: 'Side'})).toHaveTextContent(
|
|
337
|
+
'Sidebar',
|
|
338
|
+
);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it('renders as an end-slot panel inside a Layout without crashing', () => {
|
|
342
|
+
render(
|
|
343
|
+
<Layout
|
|
344
|
+
end={
|
|
345
|
+
<LayoutPanel hasDivider role="complementary" label="Inspector">
|
|
346
|
+
Details
|
|
347
|
+
</LayoutPanel>
|
|
348
|
+
}
|
|
349
|
+
content={<LayoutContent>Main</LayoutContent>}
|
|
350
|
+
/>,
|
|
351
|
+
);
|
|
352
|
+
expect(
|
|
353
|
+
screen.getByRole('complementary', {name: 'Inspector'}),
|
|
354
|
+
).toHaveTextContent('Details');
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('merges a caller className', () => {
|
|
358
|
+
const {container} = render(
|
|
359
|
+
<LayoutPanel className="panel-custom">P</LayoutPanel>,
|
|
360
|
+
);
|
|
361
|
+
const el = container.querySelector('.astryx-layout-panel') as HTMLElement;
|
|
362
|
+
expect(el.className).toContain('panel-custom');
|
|
363
|
+
});
|
|
364
|
+
});
|
|
@@ -64,8 +64,13 @@ export const docs = {
|
|
|
64
64
|
{ guidance: false, description: 'Nest interactive content inside captions; keep them plain text.' },
|
|
65
65
|
],
|
|
66
66
|
},
|
|
67
|
+
// The lightbox opens via showModal() and renders nothing while closed —
|
|
68
|
+
// overlay mode gives the Properties preview an open trigger instead of an
|
|
69
|
+
// empty stage, mirroring MobileNav (#3616).
|
|
67
70
|
playground: {
|
|
71
|
+
overlay: true,
|
|
68
72
|
defaults: {
|
|
73
|
+
isOpen: false,
|
|
69
74
|
media: {
|
|
70
75
|
src: 'https://lookaside.facebook.com/assets/astryx/light-scene-horizontal-1.png',
|
|
71
76
|
alt: 'Coastal shoreline with ocean waves',
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
-
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
4
|
-
import {render, screen, fireEvent} from '@testing-library/react';
|
|
3
|
+
import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
|
|
4
|
+
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
5
5
|
import {Lightbox} from './Lightbox';
|
|
6
|
+
import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
|
|
6
7
|
|
|
7
8
|
// Mock showModal/close for jsdom
|
|
8
9
|
beforeEach(() => {
|
|
@@ -16,6 +17,16 @@ beforeEach(() => {
|
|
|
16
17
|
});
|
|
17
18
|
});
|
|
18
19
|
|
|
20
|
+
// useAnnounce mounts singleton live regions on <body>; reset between tests so
|
|
21
|
+
// stale announcements from one test don't leak into the next.
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
__resetLiveRegionsForTest();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
function politeRegion(): HTMLElement | null {
|
|
27
|
+
return document.querySelector('[data-astryx-live-region="polite"]');
|
|
28
|
+
}
|
|
29
|
+
|
|
19
30
|
describe('Lightbox', () => {
|
|
20
31
|
it('renders as a dialog element', () => {
|
|
21
32
|
render(
|
|
@@ -300,6 +311,116 @@ describe('Lightbox', () => {
|
|
|
300
311
|
});
|
|
301
312
|
});
|
|
302
313
|
|
|
314
|
+
describe('screen-reader announcements', () => {
|
|
315
|
+
const media = [
|
|
316
|
+
{src: '/a.jpg', alt: 'Image A', caption: 'First'},
|
|
317
|
+
{src: '/b.jpg', alt: 'Image B', caption: 'Second'},
|
|
318
|
+
{src: '/c.jpg', alt: 'Image C'},
|
|
319
|
+
];
|
|
320
|
+
|
|
321
|
+
it('announces the new image and position when navigating next via button', async () => {
|
|
322
|
+
render(
|
|
323
|
+
<Lightbox
|
|
324
|
+
isOpen={true}
|
|
325
|
+
onOpenChange={() => {}}
|
|
326
|
+
media={media}
|
|
327
|
+
defaultIndex={0}
|
|
328
|
+
/>,
|
|
329
|
+
);
|
|
330
|
+
fireEvent.click(screen.getByLabelText('Next'));
|
|
331
|
+
await waitFor(() => {
|
|
332
|
+
expect(politeRegion()).toHaveTextContent('Image B, 2 of 3');
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('announces the new image and position when navigating via arrow keys', async () => {
|
|
337
|
+
render(
|
|
338
|
+
<Lightbox
|
|
339
|
+
isOpen={true}
|
|
340
|
+
onOpenChange={() => {}}
|
|
341
|
+
media={media}
|
|
342
|
+
defaultIndex={1}
|
|
343
|
+
/>,
|
|
344
|
+
);
|
|
345
|
+
const dialog = document.querySelector('dialog')!;
|
|
346
|
+
fireEvent.keyDown(dialog, {key: 'ArrowRight'});
|
|
347
|
+
await waitFor(() => {
|
|
348
|
+
expect(politeRegion()).toHaveTextContent('Image C, 3 of 3');
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('announces the new image and position when navigating prev', async () => {
|
|
353
|
+
render(
|
|
354
|
+
<Lightbox
|
|
355
|
+
isOpen={true}
|
|
356
|
+
onOpenChange={() => {}}
|
|
357
|
+
media={media}
|
|
358
|
+
defaultIndex={2}
|
|
359
|
+
/>,
|
|
360
|
+
);
|
|
361
|
+
fireEvent.click(screen.getByLabelText('Previous'));
|
|
362
|
+
await waitFor(() => {
|
|
363
|
+
expect(politeRegion()).toHaveTextContent('Image B, 2 of 3');
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('falls back to a positional label when the image has no alt', async () => {
|
|
368
|
+
const unlabeled = [
|
|
369
|
+
{src: '/a.jpg', alt: 'Image A'},
|
|
370
|
+
{src: '/b.jpg', alt: ''},
|
|
371
|
+
];
|
|
372
|
+
render(
|
|
373
|
+
<Lightbox
|
|
374
|
+
isOpen={true}
|
|
375
|
+
onOpenChange={() => {}}
|
|
376
|
+
media={unlabeled}
|
|
377
|
+
defaultIndex={0}
|
|
378
|
+
/>,
|
|
379
|
+
);
|
|
380
|
+
fireEvent.click(screen.getByLabelText('Next'));
|
|
381
|
+
await waitFor(() => {
|
|
382
|
+
expect(politeRegion()).toHaveTextContent('Image 2 of 2');
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('does not announce on initial open', async () => {
|
|
387
|
+
render(
|
|
388
|
+
<Lightbox
|
|
389
|
+
isOpen={true}
|
|
390
|
+
onOpenChange={() => {}}
|
|
391
|
+
media={media}
|
|
392
|
+
defaultIndex={1}
|
|
393
|
+
/>,
|
|
394
|
+
);
|
|
395
|
+
// Allow any scheduled rAF to flush; nothing should have been announced.
|
|
396
|
+
await new Promise(resolve => requestAnimationFrame(() => resolve(null)));
|
|
397
|
+
// The dialog's aria-label already names the current image on open, so no
|
|
398
|
+
// live region is created (announce is never called).
|
|
399
|
+
expect(politeRegion()).toBeNull();
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('does not announce when the lightbox opens at a new index', async () => {
|
|
403
|
+
const {rerender} = render(
|
|
404
|
+
<Lightbox
|
|
405
|
+
isOpen={false}
|
|
406
|
+
onOpenChange={() => {}}
|
|
407
|
+
media={media}
|
|
408
|
+
index={0}
|
|
409
|
+
/>,
|
|
410
|
+
);
|
|
411
|
+
rerender(
|
|
412
|
+
<Lightbox
|
|
413
|
+
isOpen={true}
|
|
414
|
+
onOpenChange={() => {}}
|
|
415
|
+
media={media}
|
|
416
|
+
index={2}
|
|
417
|
+
/>,
|
|
418
|
+
);
|
|
419
|
+
await new Promise(resolve => requestAnimationFrame(() => resolve(null)));
|
|
420
|
+
expect(politeRegion()).toBeNull();
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
303
424
|
describe('video support', () => {
|
|
304
425
|
it('renders a video element when type is video', () => {
|
|
305
426
|
const {container} = render(
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import {
|
|
20
20
|
useCallback,
|
|
21
21
|
useEffect,
|
|
22
|
+
useMemo,
|
|
22
23
|
useRef,
|
|
23
24
|
useState,
|
|
24
25
|
type MouseEvent as ReactMouseEvent,
|
|
@@ -28,6 +29,7 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
28
29
|
import {colorVars, spacingVars, typeScaleVars} from '../theme/tokens.stylex';
|
|
29
30
|
import {Icon} from '../Icon';
|
|
30
31
|
import {IconButton} from '../IconButton';
|
|
32
|
+
import {useAnnounce} from '../hooks/useAnnounce';
|
|
31
33
|
import {useScrollLock} from '../hooks/useScrollLock';
|
|
32
34
|
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
33
35
|
import {mergeProps, mergeRefs} from '../utils';
|
|
@@ -306,7 +308,10 @@ export function Lightbox({
|
|
|
306
308
|
const dragStartRef = useRef({x: 0, y: 0, panX: 0, panY: 0});
|
|
307
309
|
|
|
308
310
|
// Resolve current media item
|
|
309
|
-
const mediaArray =
|
|
311
|
+
const mediaArray = useMemo(
|
|
312
|
+
() => (Array.isArray(media) ? media : [media]),
|
|
313
|
+
[media],
|
|
314
|
+
);
|
|
310
315
|
const isGallery = mediaArray.length > 1;
|
|
311
316
|
const currentItem =
|
|
312
317
|
mediaArray.length > 0
|
|
@@ -329,6 +334,29 @@ export function Lightbox({
|
|
|
329
334
|
setPan({x: 0, y: 0});
|
|
330
335
|
}, [index, currentItem?.src]);
|
|
331
336
|
|
|
337
|
+
// Announce gallery navigation to screen readers. Moving between images only
|
|
338
|
+
// updates the visual counter, which is silent to assistive tech, so mirror
|
|
339
|
+
// each change in a polite live region ("<alt>, 3 of 12", or "Image 3 of 12"
|
|
340
|
+
// when the image has no alt). Announce only when the image changes during an
|
|
341
|
+
// already-open session — not on mount, not when opening (even at a new
|
|
342
|
+
// index, since the dialog's aria-label already names the current image), and
|
|
343
|
+
// not on close.
|
|
344
|
+
const announce = useAnnounce();
|
|
345
|
+
const prevIndexRef = useRef(index);
|
|
346
|
+
const wasOpenRef = useRef(isOpen);
|
|
347
|
+
useEffect(() => {
|
|
348
|
+
const indexChanged = prevIndexRef.current !== index;
|
|
349
|
+
const wasOpen = wasOpenRef.current;
|
|
350
|
+
prevIndexRef.current = index;
|
|
351
|
+
wasOpenRef.current = isOpen;
|
|
352
|
+
if (!indexChanged || !isOpen || !wasOpen) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const item = mediaArray[Math.min(index, mediaArray.length - 1)];
|
|
356
|
+
const position = `${index + 1} of ${mediaArray.length}`;
|
|
357
|
+
announce(item?.alt ? `${item.alt}, ${position}` : `Image ${position}`);
|
|
358
|
+
}, [index, isOpen, announce, mediaArray]);
|
|
359
|
+
|
|
332
360
|
// Open/close dialog
|
|
333
361
|
useIsomorphicLayoutEffect(() => {
|
|
334
362
|
const dialog = dialogRef.current;
|