@astryxdesign/core 0.1.8 → 0.1.9
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 +100 -0
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +6 -2
- package/dist/AppShell/AppShellMobileContext.d.ts +8 -0
- package/dist/AppShell/AppShellMobileContext.d.ts.map +1 -1
- package/dist/Avatar/Avatar.d.ts +18 -2
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +63 -7
- package/dist/Avatar/AvatarStatusDot.d.ts +33 -5
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- package/dist/Avatar/AvatarStatusDot.js +144 -19
- package/dist/Banner/Banner.d.ts +9 -1
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +31 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +31 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +208 -6
- package/dist/Breadcrumbs/index.d.ts +5 -0
- package/dist/Breadcrumbs/index.d.ts.map +1 -1
- package/dist/Breadcrumbs/index.js +9 -1
- package/dist/Button/Button.d.ts +8 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +31 -2
- package/dist/ButtonGroup/ButtonGroup.d.ts +9 -1
- package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
- package/dist/ButtonGroup/ButtonGroup.js +30 -1
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +30 -2
- package/dist/Calendar/dayCellUtils.js +1 -1
- package/dist/Card/Card.d.ts +8 -2
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +28 -2
- package/dist/Carousel/Carousel.d.ts +4 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +24 -4
- package/dist/Chat/ChatComposer.d.ts +8 -0
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +46 -7
- package/dist/Chat/ChatComposerDrawer.d.ts +2 -0
- package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
- package/dist/Chat/ChatComposerDrawer.js +11 -1
- package/dist/Chat/ChatComposerInput.d.ts +20 -3
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +35 -3
- package/dist/Chat/ChatContext.d.ts +33 -0
- package/dist/Chat/ChatContext.d.ts.map +1 -1
- package/dist/Chat/ChatContext.js +16 -2
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +1 -1
- package/dist/Chat/ChatLayout.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +4 -4
- package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.js +7 -1
- package/dist/Chat/ChatToolCalls.d.ts +5 -1
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +18 -9
- package/dist/Chat/index.d.ts +2 -1
- package/dist/Chat/index.d.ts.map +1 -1
- package/dist/Chat/index.js +1 -1
- package/dist/Chat/useChatStreamScroll.d.ts +2 -1
- package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
- package/dist/Chat/useChatStreamScroll.js +22 -8
- package/dist/Chat/useSpeechRecognition.d.ts +0 -1
- package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.js +1 -1
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +1 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts +20 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +11 -1
- package/dist/ClickableCard/ClickableCard.d.ts +9 -2
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +5 -2
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +8 -1
- package/dist/CommandPalette/CommandPalette.d.ts +1 -1
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +3 -1
- package/dist/CommandPalette/CommandPaletteGroup.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteGroup.js +9 -2
- package/dist/CommandPalette/CommandPaletteInput.d.ts +7 -1
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +6 -1
- package/dist/DateInput/DateInput.d.ts +47 -1
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +26 -2
- package/dist/DateInput/index.d.ts +1 -1
- package/dist/DateInput/index.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +10 -1
- package/dist/Dialog/Dialog.d.ts +3 -0
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +57 -6
- package/dist/Dialog/DialogContext.d.ts +7 -0
- package/dist/Dialog/DialogContext.d.ts.map +1 -1
- package/dist/Dialog/DialogContext.js +2 -2
- package/dist/Dialog/DialogHeader.d.ts +5 -2
- package/dist/Dialog/DialogHeader.d.ts.map +1 -1
- package/dist/Dialog/DialogHeader.js +6 -1
- package/dist/Divider/Divider.js +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -2
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +1 -2
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +1 -2
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +1 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +2 -3
- package/dist/Field/FieldLabel.d.ts +1 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +42 -15
- package/dist/FieldStatus/FieldStatus.d.ts +8 -0
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +22 -4
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +10 -2
- package/dist/HoverCard/HoverCard.d.ts +9 -1
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +2 -0
- package/dist/HoverCard/useHoverCard.d.ts +8 -0
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +7 -2
- package/dist/Icon/Icon.d.ts +7 -2
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Item/Item.d.ts +6 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +22 -1
- package/dist/Layer/useLayer.d.ts +6 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +2 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +6 -1
- package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
- package/dist/MobileNav/MobileNavToggle.js +4 -0
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +39 -12
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +16 -0
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/Outline/Outline.d.ts +0 -1
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +0 -1
- package/dist/OverflowList/OverflowList.d.ts +20 -3
- package/dist/OverflowList/OverflowList.d.ts.map +1 -1
- package/dist/OverflowList/OverflowList.js +29 -4
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +3 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +3 -9
- package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
- package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.d.ts +9 -2
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +16 -13
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +4 -2
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +16 -0
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +21 -8
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +19 -2
- package/dist/Stack/stack.stylex.d.ts +9 -9
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +3 -2
- 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/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/rowStatus/index.d.ts +3 -0
- package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -0
- package/dist/Table/plugins/rowStatus/index.js +3 -0
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +60 -0
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -0
- package/dist/Table/plugins/rowStatus/useTableRowStatus.js +145 -0
- package/dist/Table/plugins/selection/useTableSelection.d.ts +13 -0
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +4 -1
- package/dist/Table/plugins/tree/useTableTreeData.d.ts +16 -0
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +87 -0
- package/dist/Table/plugins/tree/useTableTreeState.d.ts +6 -0
- package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeState.js +22 -1
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +5 -3
- package/dist/Thumbnail/Thumbnail.d.ts +26 -5
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +97 -54
- package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +9 -0
- package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +1 -0
- package/dist/Thumbnail/thumbnail.markers.stylex.js +14 -0
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +15 -4
- package/dist/Timestamp/Timestamp.d.ts +3 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +8 -6
- package/dist/Toast/useToast.d.ts.map +1 -1
- package/dist/Toast/useToast.js +2 -5
- package/dist/ToggleButton/ToggleButtonGroup.d.ts +0 -1
- package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButtonGroup.js +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +16 -4
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +18 -8
- package/dist/TopNav/TopNavMegaMenu.js +10 -4
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +9 -1
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +8 -1
- package/dist/TopNav/TopNavMenu.d.ts +2 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +68 -6
- package/dist/TreeList/TreeList.d.ts +12 -3
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +2 -0
- package/dist/TreeList/TreeListBranches.d.ts +5 -0
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +10 -4
- package/dist/TreeList/TreeListItem.d.ts +8 -2
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +27 -7
- package/dist/TreeList/TreeListTypes.d.ts +25 -1
- package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
- package/dist/TreeList/index.d.ts +2 -2
- package/dist/TreeList/index.d.ts.map +1 -1
- package/dist/astryx.css +28 -18
- package/dist/astryx.umd.js +51 -51
- package/dist/astryx.umd.js.map +4 -4
- package/dist/authoring/doc.d.ts.map +1 -1
- package/dist/docs-types.d.ts +8 -0
- package/dist/docs-types.d.ts.map +1 -1
- package/dist/hooks/computeOverflow.d.ts +47 -0
- package/dist/hooks/computeOverflow.d.ts.map +1 -0
- package/dist/hooks/computeOverflow.js +213 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -1
- package/dist/hooks/useDevWarning.d.ts +18 -0
- package/dist/hooks/useDevWarning.d.ts.map +1 -0
- package/dist/hooks/useDevWarning.js +49 -0
- package/dist/hooks/useOverflow.d.ts +19 -0
- package/dist/hooks/useOverflow.d.ts.map +1 -1
- package/dist/hooks/useOverflow.js +36 -25
- package/dist/i18n/resolve.d.ts.map +1 -1
- package/dist/i18n/resolve.js +7 -18
- package/dist/theme/Theme.d.ts.map +1 -1
- package/dist/theme/Theme.js +2 -7
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +51 -0
- package/dist/theme/hct.d.ts +0 -1
- package/dist/theme/hct.d.ts.map +1 -1
- package/dist/theme/hct.js +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.js +2 -1
- package/dist/utils/devWarning.d.ts +42 -0
- package/dist/utils/devWarning.d.ts.map +1 -0
- package/dist/utils/devWarning.js +88 -0
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -2
- package/dist/utils/plainDate.d.ts +30 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +53 -0
- package/dist/utils/types.d.ts +13 -0
- package/dist/utils/types.d.ts.map +1 -1
- package/locales/en.json +24 -0
- package/locales/fr-FR.json +14 -0
- package/locales/pseudo.json +18 -0
- package/package.json +1 -1
- package/src/AppShell/AppShell.tsx +6 -0
- package/src/AppShell/AppShellMobileContext.tsx +8 -0
- package/src/AppShell/useAppShellMobile.doc.mjs +8 -0
- package/src/Avatar/Avatar.doc.mjs +15 -3
- package/src/Avatar/Avatar.test.tsx +156 -1
- package/src/Avatar/Avatar.tsx +96 -4
- package/src/Avatar/AvatarStatusDot.doc.mjs +23 -12
- package/src/Avatar/AvatarStatusDot.test.tsx +284 -0
- package/src/Avatar/AvatarStatusDot.tsx +178 -21
- package/src/Banner/Banner.doc.mjs +9 -0
- package/src/Banner/Banner.test.tsx +30 -0
- package/src/Banner/Banner.tsx +47 -3
- package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +26 -0
- package/src/Breadcrumbs/BreadcrumbItem.tsx +333 -14
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -0
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +284 -2
- package/src/Breadcrumbs/index.ts +27 -0
- package/src/Button/Button.doc.mjs +9 -0
- package/src/Button/Button.test.tsx +49 -0
- package/src/Button/Button.tsx +25 -1
- package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -0
- package/src/ButtonGroup/ButtonGroup.test.tsx +37 -0
- package/src/ButtonGroup/ButtonGroup.tsx +32 -0
- package/src/Calendar/Calendar.doc.mjs +12 -1
- package/src/Calendar/Calendar.test.tsx +193 -0
- package/src/Calendar/Calendar.tsx +38 -16
- package/src/Calendar/dayCellUtils.test.ts +5 -0
- package/src/Calendar/dayCellUtils.ts +1 -1
- package/src/Card/Card.doc.mjs +9 -0
- package/src/Card/Card.test.tsx +21 -3
- package/src/Card/Card.tsx +35 -2
- package/src/Carousel/Carousel.doc.mjs +1 -0
- package/src/Carousel/Carousel.test.tsx +53 -0
- package/src/Carousel/Carousel.tsx +34 -4
- package/src/Chat/ChatComposer.doc.mjs +12 -3
- package/src/Chat/ChatComposer.test.tsx +115 -0
- package/src/Chat/ChatComposer.tsx +73 -9
- package/src/Chat/ChatComposerDrawer.test.tsx +61 -0
- package/src/Chat/ChatComposerDrawer.tsx +11 -1
- package/src/Chat/ChatComposerInput.doc.mjs +7 -0
- package/src/Chat/ChatComposerInput.test.tsx +103 -0
- package/src/Chat/ChatComposerInput.tsx +49 -3
- package/src/Chat/ChatContext.tsx +37 -10
- package/src/Chat/ChatDictationButton.tsx +4 -1
- package/src/Chat/ChatLayout.tsx +3 -1
- package/src/Chat/ChatLayoutScrollButton.tsx +7 -2
- package/src/Chat/ChatMessageMetadata.tsx +1 -2
- package/src/Chat/ChatSendButton.tsx +11 -1
- package/src/Chat/ChatToolCalls.test.tsx +64 -0
- package/src/Chat/ChatToolCalls.tsx +25 -4
- package/src/Chat/index.ts +5 -1
- package/src/Chat/useChatStreamScroll.test.tsx +49 -0
- package/src/Chat/useChatStreamScroll.ts +27 -10
- package/src/Chat/useSpeechRecognition.ts +1 -1
- package/src/Chat/useTriggerMenu.tsx +3 -1
- package/src/CheckboxInput/CheckboxInput.test.tsx +32 -1
- package/src/CheckboxInput/CheckboxInput.tsx +1 -1
- package/src/CheckboxList/CheckboxList.test.tsx +81 -3
- package/src/CheckboxList/CheckboxListItem.doc.mjs +33 -5
- package/src/CheckboxList/CheckboxListItem.tsx +41 -5
- package/src/ClickableCard/ClickableCard.doc.mjs +2 -0
- package/src/ClickableCard/ClickableCard.test.tsx +34 -0
- package/src/ClickableCard/ClickableCard.tsx +13 -3
- package/src/CodeBlock/CodeBlock.test.tsx +56 -0
- package/src/CodeBlock/CodeBlock.tsx +9 -1
- package/src/CommandPalette/CommandPalette.doc.mjs +1 -0
- package/src/CommandPalette/CommandPalette.tsx +3 -1
- package/src/CommandPalette/CommandPaletteGroup.test.tsx +71 -0
- package/src/CommandPalette/CommandPaletteGroup.tsx +12 -1
- package/src/CommandPalette/CommandPaletteInput.doc.mjs +26 -9
- package/src/CommandPalette/CommandPaletteInput.test.tsx +34 -0
- package/src/CommandPalette/CommandPaletteInput.tsx +11 -0
- package/src/ContextMenu/ContextMenu.test.tsx +193 -0
- package/src/DateInput/DateInput.doc.mjs +16 -0
- package/src/DateInput/DateInput.test.tsx +108 -0
- package/src/DateInput/DateInput.tsx +68 -3
- package/src/DateInput/index.ts +1 -0
- package/src/DateTimeInput/DateTimeInput.test.tsx +35 -0
- package/src/DateTimeInput/DateTimeInput.tsx +14 -2
- package/src/Dialog/Dialog.doc.mjs +2 -2
- package/src/Dialog/Dialog.test.tsx +77 -4
- package/src/Dialog/Dialog.tsx +89 -5
- package/src/Dialog/DialogContext.ts +9 -2
- package/src/Dialog/DialogHeader.doc.mjs +2 -2
- package/src/Dialog/DialogHeader.tsx +9 -2
- package/src/Divider/Divider.tsx +2 -2
- package/src/DropdownMenu/DropdownMenu.test.tsx +169 -0
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -2
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +1 -2
- package/src/Field/Field.test.tsx +57 -12
- package/src/Field/Field.tsx +6 -5
- package/src/Field/FieldLabel.tsx +8 -0
- package/src/FieldStatus/FieldStatus.doc.mjs +17 -5
- package/src/FieldStatus/FieldStatus.test.tsx +78 -40
- package/src/FieldStatus/FieldStatus.tsx +22 -4
- package/src/FileInput/FileInput.test.tsx +52 -3
- package/src/FileInput/FileInput.tsx +13 -2
- package/src/HoverCard/HoverCard.doc.mjs +13 -0
- package/src/HoverCard/HoverCard.test.tsx +21 -2
- package/src/HoverCard/HoverCard.tsx +11 -0
- package/src/HoverCard/useHoverCard.doc.mjs +2 -0
- package/src/HoverCard/useHoverCard.tsx +24 -2
- package/src/Icon/Icon.doc.mjs +3 -2
- package/src/Icon/Icon.tsx +7 -2
- package/src/IconButton/IconButton.doc.mjs +8 -0
- package/src/IconButton/IconButton.test.tsx +15 -18
- package/src/Item/Item.test.tsx +40 -18
- package/src/Item/Item.tsx +38 -2
- package/src/Layer/useLayer.tsx +8 -0
- package/src/List/List.test.tsx +9 -8
- package/src/MobileNav/MobileNav.tsx +12 -1
- package/src/MobileNav/MobileNavToggle.test.tsx +116 -0
- package/src/MobileNav/MobileNavToggle.tsx +9 -1
- package/src/MultiSelector/MultiSelector.doc.mjs +4 -2
- package/src/MultiSelector/MultiSelector.test.tsx +172 -3
- package/src/MultiSelector/MultiSelector.tsx +55 -12
- package/src/MultiSelector/hooks.ts +17 -0
- package/src/NumberInput/NumberInput.test.tsx +11 -7
- package/src/NumberInput/NumberInput.tsx +1 -2
- package/src/Outline/Outline.tsx +0 -1
- package/src/OverflowList/OverflowList.doc.mjs +39 -6
- package/src/OverflowList/OverflowList.test.tsx +111 -0
- package/src/OverflowList/OverflowList.tsx +48 -8
- package/src/Popover/Popover.tsx +7 -4
- package/src/Popover/usePopover.tsx +9 -13
- package/src/PowerSearch/PowerSearch.doc.mjs +14 -0
- package/src/PowerSearch/PowerSearch.test.tsx +20 -0
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +67 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
- package/src/PowerSearch/usePowerSearchSource.ts +1 -2
- package/src/SelectableCard/SelectableCard.doc.mjs +2 -0
- package/src/SelectableCard/SelectableCard.test.tsx +46 -4
- package/src/SelectableCard/SelectableCard.tsx +29 -16
- package/src/Selector/Selector.test.tsx +69 -0
- package/src/Selector/Selector.tsx +5 -1
- package/src/Selector/hooks.ts +17 -0
- package/src/SideNav/SideNav.test.tsx +119 -3
- package/src/SideNav/SideNavCollapseButton.tsx +6 -1
- package/src/SideNav/SideNavHeading.tsx +24 -8
- package/src/SideNav/SideNavItem.tsx +5 -1
- package/src/Slider/Slider.test.tsx +75 -2
- package/src/Slider/Slider.tsx +21 -5
- package/src/Switch/Switch.test.tsx +32 -1
- package/src/Table/BaseTable.tsx +3 -5
- package/src/Table/index.ts +5 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +6 -2
- package/src/Table/plugins/rowStatus/index.ts +7 -0
- package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +138 -0
- package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +189 -0
- package/src/Table/plugins/selection/useTableSelection.test.tsx +16 -0
- package/src/Table/plugins/selection/useTableSelection.tsx +19 -1
- package/src/Table/plugins/tree/useTableTreeData.test.tsx +135 -3
- package/src/Table/plugins/tree/useTableTreeData.tsx +128 -1
- package/src/Table/plugins/tree/useTableTreeState.test.tsx +104 -0
- package/src/Table/plugins/tree/useTableTreeState.tsx +46 -2
- package/src/Table/useBaseTablePlugins.ts +10 -6
- package/src/Table/useTableRowStatus.doc.mjs +30 -0
- package/src/Table/useTableSelection.doc.mjs +65 -14
- package/src/Table/useTableTreeData.doc.mjs +29 -0
- package/src/Table/useTableTreeState.doc.mjs +2 -2
- package/src/TextArea/TextArea.test.tsx +9 -1
- package/src/Thumbnail/Thumbnail.doc.mjs +19 -10
- package/src/Thumbnail/Thumbnail.test.tsx +98 -7
- package/src/Thumbnail/Thumbnail.tsx +141 -41
- package/src/Thumbnail/thumbnail.markers.stylex.ts +12 -0
- package/src/TimeInput/TimeInput.test.tsx +76 -1
- package/src/TimeInput/TimeInput.tsx +19 -6
- package/src/Timestamp/Timestamp.doc.mjs +4 -4
- package/src/Timestamp/Timestamp.test.tsx +32 -0
- package/src/Timestamp/Timestamp.tsx +28 -8
- package/src/Toast/useToast.tsx +7 -8
- package/src/ToggleButton/ToggleButtonGroup.tsx +1 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +15 -1
- package/src/Tokenizer/Tokenizer.test.tsx +183 -2
- package/src/Tokenizer/Tokenizer.tsx +16 -4
- package/src/TopNav/TopNav.test.tsx +125 -1
- package/src/TopNav/TopNavHeading.tsx +24 -8
- package/src/TopNav/TopNavMegaMenu.test.tsx +149 -1
- package/src/TopNav/TopNavMegaMenu.tsx +10 -4
- package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +3 -3
- package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +19 -2
- package/src/TopNav/TopNavMenu.test.tsx +118 -4
- package/src/TopNav/TopNavMenu.tsx +83 -5
- package/src/TreeList/TreeList.doc.mjs +22 -0
- package/src/TreeList/TreeList.test.tsx +232 -0
- package/src/TreeList/TreeList.tsx +18 -2
- package/src/TreeList/TreeListBranches.tsx +16 -2
- package/src/TreeList/TreeListItem.tsx +51 -11
- package/src/TreeList/TreeListTypes.ts +27 -1
- package/src/TreeList/index.ts +2 -2
- package/src/authoring/doc.ts +1 -3
- package/src/docs-types.ts +5 -0
- package/src/hooks/computeOverflow.test.ts +422 -0
- package/src/hooks/computeOverflow.ts +290 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useDevWarning.test.tsx +45 -0
- package/src/hooks/useDevWarning.ts +54 -0
- package/src/hooks/useOverflow.test.ts +96 -4
- package/src/hooks/useOverflow.ts +74 -33
- package/src/i18n/InternationalizationProvider.doc.mjs +99 -2
- package/src/i18n/resolve.ts +9 -21
- package/src/theme/Theme.tsx +11 -14
- package/src/theme/generateThemeRules.test.ts +65 -0
- package/src/theme/generateThemeRules.ts +56 -0
- package/src/theme/hct.ts +1 -1
- package/src/theme/syntax/defineSyntaxTheme.ts +5 -6
- package/src/utils/devWarning.test.ts +56 -0
- package/src/utils/devWarning.ts +102 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/plainDate.test.ts +22 -0
- package/src/utils/plainDate.ts +61 -0
- package/src/utils/types.ts +14 -0
|
@@ -562,6 +562,23 @@ export interface MultiSelectorProps<
|
|
|
562
562
|
'data-testid'?: string;
|
|
563
563
|
}
|
|
564
564
|
|
|
565
|
+
// Case-insensitive substring filter over the selectable options. Shared by the
|
|
566
|
+
// `filteredItems` memo (rendering) and the search-change handler, which needs
|
|
567
|
+
// the count for the *next* query synchronously to announce it exactly once per
|
|
568
|
+
// keystroke rather than reacting to state in an effect.
|
|
569
|
+
function filterOptionsByQuery(
|
|
570
|
+
items: MultiSelectorOptionData[],
|
|
571
|
+
query: string,
|
|
572
|
+
): MultiSelectorOptionData[] {
|
|
573
|
+
if (!query) {
|
|
574
|
+
return items;
|
|
575
|
+
}
|
|
576
|
+
const q = query.toLowerCase();
|
|
577
|
+
return items.filter(item =>
|
|
578
|
+
(item.label ?? item.value).toLowerCase().includes(q),
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
|
|
565
582
|
/**
|
|
566
583
|
* A multi-select dropdown component with checkboxes for choosing
|
|
567
584
|
* multiple items from a list of options.
|
|
@@ -692,15 +709,10 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
692
709
|
);
|
|
693
710
|
|
|
694
711
|
// Filter items by search query
|
|
695
|
-
const filteredItems = useMemo(
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
const query = searchQuery.toLowerCase();
|
|
700
|
-
return selectableItems.filter(item =>
|
|
701
|
-
(item.label ?? item.value).toLowerCase().includes(query),
|
|
702
|
-
);
|
|
703
|
-
}, [selectableItems, searchQuery]);
|
|
712
|
+
const filteredItems = useMemo(
|
|
713
|
+
() => filterOptionsByQuery(selectableItems, searchQuery),
|
|
714
|
+
[selectableItems, searchQuery],
|
|
715
|
+
);
|
|
704
716
|
|
|
705
717
|
// Single source of truth for item order. Both the hook (keyboard navigation)
|
|
706
718
|
// and renderOptions (DOM rendering) consume this list — no independent sorting.
|
|
@@ -772,8 +784,11 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
772
784
|
const handleLayerHide = useCallback(() => {
|
|
773
785
|
setSearchQuery('');
|
|
774
786
|
setSelectedAtOpen(null);
|
|
787
|
+
// Clear any lingering result count when the popover closes so stale status
|
|
788
|
+
// text does not linger in the a11y tree.
|
|
789
|
+
announce('');
|
|
775
790
|
triggerRef.current?.focus();
|
|
776
|
-
}, []);
|
|
791
|
+
}, [announce]);
|
|
777
792
|
|
|
778
793
|
const popover = usePopover({
|
|
779
794
|
hasLightDismiss: true,
|
|
@@ -793,6 +808,30 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
793
808
|
// eslint-disable-next-line @eslint-react/exhaustive-deps -- mount-only: isDefaultOpen is not reactive
|
|
794
809
|
}, []);
|
|
795
810
|
|
|
811
|
+
// Announce the filtered result count from the query-change handler (matching
|
|
812
|
+
// BaseTypeahead) rather than a reactive effect: computing the count for the
|
|
813
|
+
// next query here fires the announcement exactly once per keystroke and does
|
|
814
|
+
// not re-speak on unrelated re-renders. Reuses the announce instance shared
|
|
815
|
+
// with the selection-count announcements above.
|
|
816
|
+
const handleSearchChange = useCallback(
|
|
817
|
+
(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
818
|
+
const nextQuery = event.target.value;
|
|
819
|
+
setSearchQuery(nextQuery);
|
|
820
|
+
if (nextQuery.length === 0) {
|
|
821
|
+
// Emptying the query clears the region rather than announcing a count.
|
|
822
|
+
announce('');
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
const count = filterOptionsByQuery(selectableItems, nextQuery).length;
|
|
826
|
+
announce(
|
|
827
|
+
count === 0
|
|
828
|
+
? 'No results found'
|
|
829
|
+
: `${count} result${count === 1 ? '' : 's'}`,
|
|
830
|
+
);
|
|
831
|
+
},
|
|
832
|
+
[announce, selectableItems],
|
|
833
|
+
);
|
|
834
|
+
|
|
796
835
|
// Handle toggle
|
|
797
836
|
// Clear all selected values. Shared by the clear button and the keyboard
|
|
798
837
|
// Delete/Backspace path so clearing is reachable without a mouse.
|
|
@@ -1041,14 +1080,17 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1041
1080
|
aria-label={t('@astryx.multiSelector.searchOptions')}
|
|
1042
1081
|
type="text"
|
|
1043
1082
|
value={searchQuery}
|
|
1044
|
-
onChange={
|
|
1083
|
+
onChange={handleSearchChange}
|
|
1045
1084
|
onKeyDown={e => {
|
|
1046
1085
|
// Arrow keys navigate options; Enter toggles; Escape/Tab close.
|
|
1047
1086
|
// Space and Home/End are left to the input (type a space / move
|
|
1048
|
-
// the caret)
|
|
1087
|
+
// the caret) per the APG editable combobox; PageUp/PageDown are
|
|
1088
|
+
// the sanctioned substitute for jumping to the first/last option.
|
|
1049
1089
|
if (
|
|
1050
1090
|
e.key === 'ArrowDown' ||
|
|
1051
1091
|
e.key === 'ArrowUp' ||
|
|
1092
|
+
e.key === 'PageUp' ||
|
|
1093
|
+
e.key === 'PageDown' ||
|
|
1052
1094
|
e.key === 'Enter' ||
|
|
1053
1095
|
e.key === 'Escape' ||
|
|
1054
1096
|
e.key === 'Tab'
|
|
@@ -1067,6 +1109,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1067
1109
|
listboxId,
|
|
1068
1110
|
searchQuery,
|
|
1069
1111
|
searchPlaceholder,
|
|
1112
|
+
handleSearchChange,
|
|
1070
1113
|
onKeyDown,
|
|
1071
1114
|
popover.isOpen,
|
|
1072
1115
|
highlightedIndex,
|
|
@@ -192,6 +192,23 @@ export function useMultiCombobox({
|
|
|
192
192
|
}
|
|
193
193
|
break;
|
|
194
194
|
|
|
195
|
+
// PageUp/PageDown mirror Home/End. In search mode Home/End stay on
|
|
196
|
+
// the input for caret movement (APG editable combobox), so these are
|
|
197
|
+
// the sanctioned substitute for jumping to the first/last option.
|
|
198
|
+
case 'PageUp':
|
|
199
|
+
e.preventDefault();
|
|
200
|
+
if (isOpen && enabledIndices.length > 0) {
|
|
201
|
+
setHighlightedIndex(enabledIndices[0]);
|
|
202
|
+
}
|
|
203
|
+
break;
|
|
204
|
+
|
|
205
|
+
case 'PageDown':
|
|
206
|
+
e.preventDefault();
|
|
207
|
+
if (isOpen && enabledIndices.length > 0) {
|
|
208
|
+
setHighlightedIndex(enabledIndices[enabledIndices.length - 1]);
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
|
|
195
212
|
case 'Delete':
|
|
196
213
|
case 'Backspace':
|
|
197
214
|
// Keyboard equivalent of the clear button (comboboxes-2): clear all
|
|
@@ -9,11 +9,19 @@
|
|
|
9
9
|
* SYNC: When NumberInput.tsx changes, update tests to match new behavior
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
12
|
+
import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
|
|
13
13
|
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import {TestIcon} from '../__tests__/TestIcon';
|
|
16
16
|
import {NumberInput} from './NumberInput';
|
|
17
|
+
import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
|
|
18
|
+
|
|
19
|
+
// FieldStatus announces status messages through the persistent useAnnounce
|
|
20
|
+
// singletons; remove them between tests so role/aria-live queries in this
|
|
21
|
+
// file never match a leftover region.
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
__resetLiveRegionsForTest();
|
|
24
|
+
});
|
|
17
25
|
|
|
18
26
|
// Mock showPopover/hidePopover since jsdom does not implement them. Used by the
|
|
19
27
|
// disabledMessage tooltip.
|
|
@@ -871,9 +879,7 @@ describe('NumberInput', () => {
|
|
|
871
879
|
describe('keyboard clearing with hasClear (#3599)', () => {
|
|
872
880
|
it('commits null when the input is emptied and blurred', () => {
|
|
873
881
|
const onChange = vi.fn();
|
|
874
|
-
render(
|
|
875
|
-
<NumberInput label="Qty" hasClear value={42} onChange={onChange} />,
|
|
876
|
-
);
|
|
882
|
+
render(<NumberInput label="Qty" hasClear value={42} onChange={onChange} />);
|
|
877
883
|
const input = screen.getByLabelText('Qty');
|
|
878
884
|
fireEvent.change(input, {target: {value: ''}});
|
|
879
885
|
fireEvent.blur(input);
|
|
@@ -882,9 +888,7 @@ describe('keyboard clearing with hasClear (#3599)', () => {
|
|
|
882
888
|
|
|
883
889
|
it('commits null when the input is emptied and Enter is pressed', () => {
|
|
884
890
|
const onChange = vi.fn();
|
|
885
|
-
render(
|
|
886
|
-
<NumberInput label="Qty" hasClear value={42} onChange={onChange} />,
|
|
887
|
-
);
|
|
891
|
+
render(<NumberInput label="Qty" hasClear value={42} onChange={onChange} />);
|
|
888
892
|
const input = screen.getByLabelText('Qty');
|
|
889
893
|
fireEvent.change(input, {target: {value: ''}});
|
|
890
894
|
fireEvent.keyDown(input, {key: 'Enter'});
|
|
@@ -311,8 +311,7 @@ type NumberInputPropsClearable = NumberInputPropsBase & {
|
|
|
311
311
|
};
|
|
312
312
|
|
|
313
313
|
export type NumberInputProps =
|
|
314
|
-
|
|
|
315
|
-
| NumberInputPropsClearable;
|
|
314
|
+
NumberInputPropsNonClearable | NumberInputPropsClearable;
|
|
316
315
|
|
|
317
316
|
/**
|
|
318
317
|
* Parse and validate a string input as a number.
|
package/src/Outline/Outline.tsx
CHANGED
|
@@ -61,6 +61,20 @@ export const docs = {
|
|
|
61
61
|
description: 'Minimum number of items to always show, even when overflowing.',
|
|
62
62
|
default: '0',
|
|
63
63
|
},
|
|
64
|
+
{
|
|
65
|
+
name: 'maxVisibleItems',
|
|
66
|
+
type: 'number',
|
|
67
|
+
description:
|
|
68
|
+
'Maximum number of items to ever show, even when they all fit. The ceiling partner to minVisibleItems; extra items collapse into the overflow indicator. If less than minVisibleItems, the floor wins.',
|
|
69
|
+
default: 'undefined (no cap)',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'maxRows',
|
|
73
|
+
type: 'number',
|
|
74
|
+
description:
|
|
75
|
+
'Wrap items across up to this many rows before collapsing the rest into the overflow indicator. A number, not a boolean. Leave undefined (or set 1) for single-line behavior. Assumes uniform row height.',
|
|
76
|
+
default: 'undefined (single line)',
|
|
77
|
+
},
|
|
64
78
|
{
|
|
65
79
|
name: 'collapseFrom',
|
|
66
80
|
type: "'start' | 'end'",
|
|
@@ -91,8 +105,9 @@ export const docs = {
|
|
|
91
105
|
'A horizontal list that automatically hides items when they exceed the available width. Use OverflowList for breadcrumbs, toolbars, tag lists, or any row that needs to collapse gracefully at smaller sizes.',
|
|
92
106
|
bestPractices: [
|
|
93
107
|
{ guidance: true, description: 'Provide a meaningful overflowRenderer: a "+N more" badge, a dropdown, or a count indicator.' },
|
|
94
|
-
{ guidance: true, description: 'Set minVisibleItems to keep key items visible regardless of
|
|
95
|
-
{ guidance:
|
|
108
|
+
{ guidance: true, description: 'Set minVisibleItems to keep key items visible, and maxVisibleItems to cap the row at a fixed count regardless of available width.' },
|
|
109
|
+
{ guidance: true, description: 'Use maxRows to let items wrap onto a bounded number of rows (e.g. a two-row tag cloud) before collapsing the rest into the indicator.' },
|
|
110
|
+
{ guidance: false, description: 'Use OverflowList for a vertical stack; horizontal multi-row wrap is supported via maxRows, but items still flow left-to-right, not top-to-bottom.' },
|
|
96
111
|
],
|
|
97
112
|
},
|
|
98
113
|
};
|
|
@@ -127,6 +142,20 @@ export const docsZh = {
|
|
|
127
142
|
description: '溢出时始终显示的最小项目数。',
|
|
128
143
|
default: '0',
|
|
129
144
|
},
|
|
145
|
+
{
|
|
146
|
+
name: 'maxVisibleItems',
|
|
147
|
+
type: 'number',
|
|
148
|
+
description:
|
|
149
|
+
'始终显示的最大项目数(即使全部都能放下)。它是 minVisibleItems 的上限伙伴;多余项目会折叠进溢出指示器。若小于 minVisibleItems,则以下限为准。',
|
|
150
|
+
default: 'undefined(无上限)',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'maxRows',
|
|
154
|
+
type: 'number',
|
|
155
|
+
description:
|
|
156
|
+
'在将其余项目折叠进溢出指示器之前,允许项目换行到的最大行数。是数字而非布尔值。留空(或设为 1)表示单行。假定行高一致。',
|
|
157
|
+
default: 'undefined(单行)',
|
|
158
|
+
},
|
|
130
159
|
{
|
|
131
160
|
name: 'collapseFrom',
|
|
132
161
|
type: "'start' | 'end'",
|
|
@@ -152,8 +181,9 @@ export const docsZh = {
|
|
|
152
181
|
'A horizontal list that automatically hides items when they exceed the available width. Use OverflowList for breadcrumbs, toolbars, tag lists, or any row that needs to collapse gracefully at smaller sizes.',
|
|
153
182
|
bestPractices: [
|
|
154
183
|
{ guidance: true, description: 'Provide a meaningful overflowRenderer: a "+N more" badge, a dropdown, or a count indicator.' },
|
|
155
|
-
{ guidance: true, description: 'Set minVisibleItems to keep key items visible regardless of
|
|
156
|
-
{ guidance:
|
|
184
|
+
{ guidance: true, description: 'Set minVisibleItems to keep key items visible, and maxVisibleItems to cap the row at a fixed count regardless of available width.' },
|
|
185
|
+
{ guidance: true, description: 'Use maxRows to let items wrap onto a bounded number of rows (e.g. a two-row tag cloud) before collapsing the rest into the indicator.' },
|
|
186
|
+
{ guidance: false, description: 'Use OverflowList for a vertical stack; horizontal multi-row wrap is supported via maxRows, but items still flow left-to-right, not top-to-bottom.' },
|
|
157
187
|
],
|
|
158
188
|
},
|
|
159
189
|
};
|
|
@@ -166,8 +196,9 @@ export const docsDense = {
|
|
|
166
196
|
'A horizontal list that automatically hides items when they exceed the available width. Use OverflowList for breadcrumbs, toolbars, tag lists, or any row that needs to collapse gracefully at smaller sizes.',
|
|
167
197
|
bestPractices: [
|
|
168
198
|
{ guidance: true, description: 'Provide a meaningful overflowRenderer: a "+N more" badge, a dropdown, or a count indicator.' },
|
|
169
|
-
{ guidance: true, description: 'Set minVisibleItems to keep key items visible regardless of
|
|
170
|
-
{ guidance:
|
|
199
|
+
{ guidance: true, description: 'Set minVisibleItems to keep key items visible, and maxVisibleItems to cap the row at a fixed count regardless of available width.' },
|
|
200
|
+
{ guidance: true, description: 'Use maxRows to let items wrap onto a bounded number of rows (e.g. a two-row tag cloud) before collapsing the rest into the indicator.' },
|
|
201
|
+
{ guidance: false, description: 'Use OverflowList for a vertical stack; horizontal multi-row wrap is supported via maxRows, but items still flow left-to-right, not top-to-bottom.' },
|
|
171
202
|
],
|
|
172
203
|
},
|
|
173
204
|
propDescriptions: {
|
|
@@ -175,6 +206,8 @@ export const docsDense = {
|
|
|
175
206
|
overflowRenderer: 'renders overflow indicator, receives hidden items w/ index',
|
|
176
207
|
gap: 'item gap as spacing step',
|
|
177
208
|
minVisibleItems: 'min items always shown even when overflowing',
|
|
209
|
+
maxVisibleItems: 'max items ever shown (cap); extra items collapse to indicator; min wins if smaller',
|
|
210
|
+
maxRows: 'wrap items across up to N rows then collapse rest (number, not boolean); undefined = single line',
|
|
178
211
|
collapseFrom: 'which end to collapse from',
|
|
179
212
|
behavior: 'observeSelf (default) or observeParent for content-sized containers',
|
|
180
213
|
xstyle: 'StyleX styles, use stylex.create() values only',
|
|
@@ -413,4 +413,115 @@ describe('OverflowList', () => {
|
|
|
413
413
|
expect(OverflowList.displayName).toBe('OverflowList');
|
|
414
414
|
});
|
|
415
415
|
});
|
|
416
|
+
|
|
417
|
+
describe('maxVisibleItems (cap)', () => {
|
|
418
|
+
it('caps visible items even when they all fit', () => {
|
|
419
|
+
render(
|
|
420
|
+
<OverflowList
|
|
421
|
+
gap={0}
|
|
422
|
+
data-w="1000"
|
|
423
|
+
data-testid="ov"
|
|
424
|
+
maxVisibleItems={2}
|
|
425
|
+
overflowRenderer={indicator('more:')}>
|
|
426
|
+
<button type="button" data-w="40">
|
|
427
|
+
A
|
|
428
|
+
</button>
|
|
429
|
+
<button type="button" data-w="40">
|
|
430
|
+
B
|
|
431
|
+
</button>
|
|
432
|
+
<button type="button" data-w="40">
|
|
433
|
+
C
|
|
434
|
+
</button>
|
|
435
|
+
<button type="button" data-w="40">
|
|
436
|
+
D
|
|
437
|
+
</button>
|
|
438
|
+
</OverflowList>,
|
|
439
|
+
);
|
|
440
|
+
const vis = visibleContainer();
|
|
441
|
+
expect(within(vis).getByText('A')).toBeInTheDocument();
|
|
442
|
+
expect(within(vis).getByText('B')).toBeInTheDocument();
|
|
443
|
+
expect(within(vis).queryByText('C')).not.toBeInTheDocument();
|
|
444
|
+
expect(within(vis).getByText('more:2,3')).toBeInTheDocument();
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('min wins over a smaller cap (D1)', () => {
|
|
448
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
449
|
+
render(
|
|
450
|
+
<OverflowList
|
|
451
|
+
gap={0}
|
|
452
|
+
data-w="1000"
|
|
453
|
+
data-testid="ov"
|
|
454
|
+
minVisibleItems={3}
|
|
455
|
+
maxVisibleItems={1}
|
|
456
|
+
overflowRenderer={indicator('more:')}>
|
|
457
|
+
<button type="button" data-w="40">
|
|
458
|
+
A
|
|
459
|
+
</button>
|
|
460
|
+
<button type="button" data-w="40">
|
|
461
|
+
B
|
|
462
|
+
</button>
|
|
463
|
+
<button type="button" data-w="40">
|
|
464
|
+
C
|
|
465
|
+
</button>
|
|
466
|
+
<button type="button" data-w="40">
|
|
467
|
+
D
|
|
468
|
+
</button>
|
|
469
|
+
</OverflowList>,
|
|
470
|
+
);
|
|
471
|
+
const vis = visibleContainer();
|
|
472
|
+
expect(within(vis).getByText('A')).toBeInTheDocument();
|
|
473
|
+
expect(within(vis).getByText('B')).toBeInTheDocument();
|
|
474
|
+
expect(within(vis).getByText('C')).toBeInTheDocument();
|
|
475
|
+
expect(within(vis).queryByText('D')).not.toBeInTheDocument();
|
|
476
|
+
expect(warn).toHaveBeenCalled();
|
|
477
|
+
warn.mockRestore();
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
describe('maxRows (multi-row)', () => {
|
|
482
|
+
it('applies a different container class when maxRows enables wrapping', () => {
|
|
483
|
+
const {rerender} = render(
|
|
484
|
+
<OverflowList gap={0} data-w="1000" data-testid="ov">
|
|
485
|
+
<button type="button" data-w="40">
|
|
486
|
+
A
|
|
487
|
+
</button>
|
|
488
|
+
</OverflowList>,
|
|
489
|
+
);
|
|
490
|
+
const singleLine = visibleContainer().getAttribute('class');
|
|
491
|
+
|
|
492
|
+
rerender(
|
|
493
|
+
<OverflowList gap={0} data-w="1000" data-testid="ov" maxRows={2}>
|
|
494
|
+
<button type="button" data-w="40">
|
|
495
|
+
A
|
|
496
|
+
</button>
|
|
497
|
+
</OverflowList>,
|
|
498
|
+
);
|
|
499
|
+
const multiRow = visibleContainer().getAttribute('class');
|
|
500
|
+
expect(multiRow).not.toEqual(singleLine);
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
it('keeps single-line behavior with maxRows={1}', () => {
|
|
504
|
+
render(
|
|
505
|
+
<OverflowList
|
|
506
|
+
gap={0}
|
|
507
|
+
data-w="100"
|
|
508
|
+
data-testid="ov"
|
|
509
|
+
maxRows={1}
|
|
510
|
+
overflowRenderer={indicator('more:')}>
|
|
511
|
+
<button type="button" data-w="40">
|
|
512
|
+
A
|
|
513
|
+
</button>
|
|
514
|
+
<button type="button" data-w="40">
|
|
515
|
+
B
|
|
516
|
+
</button>
|
|
517
|
+
<button type="button" data-w="40">
|
|
518
|
+
C
|
|
519
|
+
</button>
|
|
520
|
+
</OverflowList>,
|
|
521
|
+
);
|
|
522
|
+
const vis = visibleContainer();
|
|
523
|
+
expect(within(vis).getByText('A')).toBeInTheDocument();
|
|
524
|
+
expect(within(vis).queryByText('B')).not.toBeInTheDocument();
|
|
525
|
+
});
|
|
526
|
+
});
|
|
416
527
|
});
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* @position Core implementation; consumed by index.ts
|
|
10
10
|
*
|
|
11
11
|
* Renders a horizontal list of items, hiding those that don't fit in the
|
|
12
|
-
* available width and optionally showing an overflow indicator.
|
|
13
|
-
*
|
|
12
|
+
* available width and optionally showing an overflow indicator. Supports an
|
|
13
|
+
* optional item cap (`maxVisibleItems`) and bounded multi-row wrapping
|
|
14
|
+
* (`maxRows`). Uses a hidden measurement container to avoid flickering.
|
|
14
15
|
*
|
|
15
16
|
* SYNC: When modified, update these files to stay in sync:
|
|
16
17
|
* - /packages/core/src/OverflowList/index.ts (exports if types change)
|
|
@@ -34,6 +35,14 @@ const styles = stylex.create({
|
|
|
34
35
|
whiteSpace: 'nowrap',
|
|
35
36
|
minWidth: 0,
|
|
36
37
|
},
|
|
38
|
+
containerMultiRow: {
|
|
39
|
+
display: 'flex',
|
|
40
|
+
flexWrap: 'wrap',
|
|
41
|
+
alignContent: 'flex-start',
|
|
42
|
+
overflow: 'hidden',
|
|
43
|
+
whiteSpace: 'normal',
|
|
44
|
+
minWidth: 0,
|
|
45
|
+
},
|
|
37
46
|
fillParent: {
|
|
38
47
|
width: '100%',
|
|
39
48
|
},
|
|
@@ -52,6 +61,12 @@ const styles = stylex.create({
|
|
|
52
61
|
},
|
|
53
62
|
});
|
|
54
63
|
|
|
64
|
+
const multiRowHeight = stylex.create({
|
|
65
|
+
height: (maxRows: number, rowHeight: number, gapPx: number) => ({
|
|
66
|
+
maxHeight: `calc(${rowHeight}px * ${maxRows} + ${gapPx}px * ${maxRows - 1})`,
|
|
67
|
+
}),
|
|
68
|
+
});
|
|
69
|
+
|
|
55
70
|
const gapStyles = stylex.create({
|
|
56
71
|
0: {gap: spacingVars['--spacing-0']},
|
|
57
72
|
0.5: {gap: spacingVars['--spacing-0-5']},
|
|
@@ -112,6 +127,24 @@ export interface OverflowListProps extends BaseProps<HTMLDivElement> {
|
|
|
112
127
|
*/
|
|
113
128
|
minVisibleItems?: number;
|
|
114
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Maximum number of items to ever show, even when they all fit. The ceiling
|
|
132
|
+
* partner to `minVisibleItems`; extra items collapse into the overflow
|
|
133
|
+
* indicator. Leave undefined for no cap. If it is less than
|
|
134
|
+
* `minVisibleItems`, the floor wins (and a dev-only warning is logged).
|
|
135
|
+
* @default undefined
|
|
136
|
+
*/
|
|
137
|
+
maxVisibleItems?: number;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Wrap items across up to this many rows before collapsing the remainder
|
|
141
|
+
* into the overflow indicator. Leave undefined (or set `1`) for the default
|
|
142
|
+
* single-line behavior. A number, not a boolean — unbounded wrapping is a
|
|
143
|
+
* plain flex-wrap layout, not overflow collapse. Assumes uniform row height.
|
|
144
|
+
* @default undefined
|
|
145
|
+
*/
|
|
146
|
+
maxRows?: number;
|
|
147
|
+
|
|
115
148
|
/**
|
|
116
149
|
* Which end to collapse items from.
|
|
117
150
|
* @default 'end'
|
|
@@ -180,6 +213,8 @@ export function OverflowList({
|
|
|
180
213
|
children,
|
|
181
214
|
gap = 2,
|
|
182
215
|
minVisibleItems = 0,
|
|
216
|
+
maxVisibleItems,
|
|
217
|
+
maxRows,
|
|
183
218
|
collapseFrom = 'end',
|
|
184
219
|
behavior = 'observeSelf',
|
|
185
220
|
overflowRenderer,
|
|
@@ -195,16 +230,17 @@ export function OverflowList({
|
|
|
195
230
|
const gapPx = spacingToPx[gap];
|
|
196
231
|
|
|
197
232
|
const observeParent = behavior === 'observeParent';
|
|
233
|
+
const isMultiRow = maxRows != null && maxRows > 1;
|
|
198
234
|
|
|
199
|
-
const {containerRef, measureRef, visibleCount, hasOverflow} =
|
|
200
|
-
itemCount,
|
|
201
|
-
{
|
|
235
|
+
const {containerRef, measureRef, visibleCount, hasOverflow, rowHeight} =
|
|
236
|
+
useOverflow(itemCount, {
|
|
202
237
|
gap: gapPx,
|
|
203
238
|
minVisibleItems,
|
|
239
|
+
maxVisibleItems,
|
|
240
|
+
maxRows,
|
|
204
241
|
collapseFrom,
|
|
205
242
|
behavior,
|
|
206
|
-
}
|
|
207
|
-
);
|
|
243
|
+
});
|
|
208
244
|
|
|
209
245
|
const allItems: OverflowItem[] = childArray.map((child, index) => ({
|
|
210
246
|
child,
|
|
@@ -248,8 +284,12 @@ export function OverflowList({
|
|
|
248
284
|
{...mergeProps(
|
|
249
285
|
themeProps('overflow-list'),
|
|
250
286
|
stylex.props(
|
|
251
|
-
styles.container,
|
|
287
|
+
isMultiRow ? styles.containerMultiRow : styles.container,
|
|
252
288
|
gapStyles[gap],
|
|
289
|
+
isMultiRow &&
|
|
290
|
+
rowHeight > 0 &&
|
|
291
|
+
maxRows != null &&
|
|
292
|
+
multiRowHeight.height(maxRows, rowHeight, gapPx),
|
|
253
293
|
observeParent && hasOverflow && styles.fillParent,
|
|
254
294
|
xstyle,
|
|
255
295
|
),
|
package/src/Popover/Popover.tsx
CHANGED
|
@@ -26,6 +26,7 @@ import React, {
|
|
|
26
26
|
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
27
27
|
import * as stylex from '@stylexjs/stylex';
|
|
28
28
|
import {mergeProps} from '../utils';
|
|
29
|
+
import {devWarn} from '../utils/devWarning';
|
|
29
30
|
import type {BaseProps} from '../BaseProps';
|
|
30
31
|
import {usePopover} from './usePopover';
|
|
31
32
|
import type {LayerAlignment, LayerPlacement} from '../Layer/useLayer';
|
|
@@ -410,8 +411,9 @@ export function Popover({
|
|
|
410
411
|
|
|
411
412
|
const button = findTriggerButton(el);
|
|
412
413
|
if (!button) {
|
|
413
|
-
|
|
414
|
-
'Popover
|
|
414
|
+
devWarn(
|
|
415
|
+
'Popover',
|
|
416
|
+
'anchorRef must reference a <button> or [role="button"] element. ' +
|
|
415
417
|
'The popover trigger implements the button + dialog ARIA pattern.',
|
|
416
418
|
);
|
|
417
419
|
}
|
|
@@ -453,8 +455,9 @@ export function Popover({
|
|
|
453
455
|
// Find the button inside the wrapper
|
|
454
456
|
const button = findTriggerButton(wrapper);
|
|
455
457
|
if (!button) {
|
|
456
|
-
|
|
457
|
-
'Popover
|
|
458
|
+
devWarn(
|
|
459
|
+
'Popover',
|
|
460
|
+
'children must contain a <button> or [role="button"] element. ' +
|
|
458
461
|
'The popover trigger implements the button + dialog ARIA pattern.',
|
|
459
462
|
);
|
|
460
463
|
}
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
} from '../theme/tokens.stylex';
|
|
29
29
|
import {Button} from '../Button';
|
|
30
30
|
import {useTranslator} from '../i18n';
|
|
31
|
+
import {useDevWarning} from '../hooks/useDevWarning';
|
|
31
32
|
|
|
32
33
|
const styles = stylex.create({
|
|
33
34
|
// Default popover surface — background, radius, shadow.
|
|
@@ -391,19 +392,14 @@ export function usePopover(options: UsePopoverOptions = {}): UsePopoverReturn {
|
|
|
391
392
|
'aria-controls': layer.id,
|
|
392
393
|
};
|
|
393
394
|
|
|
394
|
-
// Dev-time guardrail: a dialog popover should always be labeled.
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
'dialog. Pass `dialogLabel`, or use `role: "none"` for listbox/menu ' +
|
|
403
|
-
'popups whose content already carries its own role.',
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
}, [role, dialogLabel]);
|
|
395
|
+
// Dev-time guardrail: a dialog popover should always be labeled.
|
|
396
|
+
useDevWarning(
|
|
397
|
+
'usePopover',
|
|
398
|
+
'role="dialog" without a `dialogLabel` renders an unnamed ' +
|
|
399
|
+
'dialog. Pass `dialogLabel`, or use `role: "none"` for listbox/menu ' +
|
|
400
|
+
'popups whose content already carries its own role.',
|
|
401
|
+
role === 'dialog' && !dialogLabel,
|
|
402
|
+
);
|
|
407
403
|
|
|
408
404
|
// Wrapped render function that includes surface styles and optional hidden close button
|
|
409
405
|
const render = useCallback(
|
|
@@ -83,6 +83,13 @@ export const docs = {
|
|
|
83
83
|
description:
|
|
84
84
|
'Validation status object with type and optional message.',
|
|
85
85
|
},
|
|
86
|
+
{
|
|
87
|
+
name: 'startIcon',
|
|
88
|
+
type: 'ReactNode | IconType',
|
|
89
|
+
description:
|
|
90
|
+
'Icon to display at the start of the input, before any filter tokens. Forwarded to the internal Tokenizer. Accepts a semantic icon name, an SVG icon component, or a ReactNode directly.',
|
|
91
|
+
slotElements: [{__element: 'Icon', props: {icon: 'search', size: 'sm'}}],
|
|
92
|
+
},
|
|
86
93
|
{
|
|
87
94
|
name: 'maxTokenLength',
|
|
88
95
|
type: 'number',
|
|
@@ -235,6 +242,12 @@ export const docsZh = {
|
|
|
235
242
|
type: "{type: 'warning' | 'error' | 'success', message?: string}",
|
|
236
243
|
description: '带有类型和可选消息的验证状态对象。',
|
|
237
244
|
},
|
|
245
|
+
{
|
|
246
|
+
name: 'startIcon',
|
|
247
|
+
type: 'ReactNode | IconType',
|
|
248
|
+
description:
|
|
249
|
+
'在输入框开头(筛选 token 之前)显示的图标,转发给内部的 Tokenizer。接受语义图标名称、SVG 图标组件或直接传入 ReactNode。',
|
|
250
|
+
},
|
|
238
251
|
{
|
|
239
252
|
name: 'maxTokenLength',
|
|
240
253
|
type: 'number',
|
|
@@ -318,6 +331,7 @@ export const docsDense = {
|
|
|
318
331
|
isReadOnly: 'Prevent adding, editing, or removing filters.',
|
|
319
332
|
isDisabled: 'Disables entire component.',
|
|
320
333
|
status: 'Validation status object w/ type + optional message.',
|
|
334
|
+
startIcon: 'Icon at input start, before filter tokens. Forwarded to internal Tokenizer.',
|
|
321
335
|
maxTokenLength: 'Max char length for filter value display in tokens.',
|
|
322
336
|
popoverSaveButtonLabel: 'Label for save button in edit popover.',
|
|
323
337
|
timezoneID: 'Timezone ID for date formatting (e.g. "America/New_York").',
|
|
@@ -16,6 +16,7 @@ import userEvent from '@testing-library/user-event';
|
|
|
16
16
|
import {PowerSearch} from './PowerSearch';
|
|
17
17
|
import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
|
|
18
18
|
import type {PowerSearchConfig, PowerSearchFilter} from './types';
|
|
19
|
+
import {TestIcon} from '../__tests__/TestIcon';
|
|
19
20
|
|
|
20
21
|
// =============================================================================
|
|
21
22
|
// Test infrastructure
|
|
@@ -157,6 +158,25 @@ describe('PowerSearch', () => {
|
|
|
157
158
|
expect(screen.getByRole('combobox')).toHaveFocus();
|
|
158
159
|
});
|
|
159
160
|
|
|
161
|
+
describe('startIcon', () => {
|
|
162
|
+
it('does not render a start icon when omitted', () => {
|
|
163
|
+
render(<PowerSearch config={config} filters={[]} onChange={() => {}} />);
|
|
164
|
+
expect(document.querySelector('svg')).not.toBeInTheDocument();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('forwards startIcon to the internal Tokenizer', () => {
|
|
168
|
+
render(
|
|
169
|
+
<PowerSearch
|
|
170
|
+
config={config}
|
|
171
|
+
filters={[]}
|
|
172
|
+
onChange={() => {}}
|
|
173
|
+
startIcon={<TestIcon data-testid="start-icon" />}
|
|
174
|
+
/>,
|
|
175
|
+
);
|
|
176
|
+
expect(screen.getByTestId('start-icon')).toBeInTheDocument();
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
160
180
|
describe('paste behavior', () => {
|
|
161
181
|
it('pasting a field name shows matching field suggestions', async () => {
|
|
162
182
|
const user = userEvent.setup();
|