@astryxdesign/core 0.1.9 → 0.2.0-canary.0f56f82
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 +107 -0
- package/dist/Avatar/Avatar.d.ts +42 -3
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +190 -59
- package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts +7 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.js +58 -6
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -2
- package/dist/Banner/Banner.js +2 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +11 -4
- package/dist/Breadcrumbs/index.d.ts +1 -0
- package/dist/Breadcrumbs/index.d.ts.map +1 -1
- package/dist/Breadcrumbs/index.js +2 -1
- package/dist/Button/Button.d.ts +1 -1
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +6 -4
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +50 -9
- package/dist/Calendar/dayCellUtils.d.ts +4 -4
- package/dist/Calendar/dayCellUtils.js +2 -2
- package/dist/Calendar/styles.d.ts +30 -31
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +30 -31
- package/dist/Card/Card.js +1 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +22 -12
- package/dist/Chat/ChatComposerInput.js +1 -1
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +3 -1
- package/dist/Chat/ChatLayout.js +4 -4
- package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
- package/dist/Chat/ChatMessageBubble.js +8 -8
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +10 -3
- package/dist/Chat/useTriggerMenu.js +2 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +6 -6
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +19 -4
- package/dist/Citation/Citation.d.ts +22 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +20 -6
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +16 -10
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +3 -1
- package/dist/CommandPalette/CommandPalette.d.ts +1 -1
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +42 -3
- package/dist/CommandPalette/CommandPaletteItem.js +1 -1
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +23 -5
- package/dist/ContextMenu/index.d.ts +1 -0
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +3 -1
- package/dist/DateInput/DateInput.d.ts +10 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +33 -19
- package/dist/DateRangeInput/DateRangeInput.d.ts +10 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +23 -20
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +23 -18
- package/dist/Divider/Divider.d.ts +2 -2
- package/dist/Divider/Divider.d.ts.map +1 -1
- package/dist/Divider/Divider.js +13 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +22 -5
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +4 -1
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +5 -2
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +8 -11
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +3 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +5 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +427 -0
- package/dist/DropdownMenu/index.d.ts +10 -0
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +13 -0
- package/dist/DropdownMenu/menuItemHover.d.ts +23 -0
- package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
- package/dist/DropdownMenu/menuItemHover.js +33 -0
- package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
- package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
- package/dist/DropdownMenu/menuItemRoles.js +10 -1
- package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
- package/dist/DropdownMenu/renderDropdownItems.js +21 -6
- package/dist/Field/Field.d.ts +3 -1
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +4 -1
- package/dist/Field/FieldLabel.d.ts +2 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +9 -5
- package/dist/Field/inputStyles.stylex.d.ts +1 -0
- package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
- package/dist/Field/inputStyles.stylex.js +1 -0
- package/dist/FieldStatus/FieldStatus.d.ts +10 -0
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +51 -5
- package/dist/FileInput/FileInput.d.ts +10 -2
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +93 -65
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +10 -4
- package/dist/Icon/Icon.d.ts +15 -1
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +19 -3
- package/dist/Item/Item.d.ts +16 -3
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +31 -6
- package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
- package/dist/Layer/layerAnimations.stylex.js +10 -2
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +19 -13
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +6 -3
- package/dist/List/ListItem.d.ts +11 -1
- package/dist/List/ListItem.d.ts.map +1 -1
- package/dist/List/ListItem.js +2 -0
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +7 -0
- package/dist/MetadataList/MetadataList.d.ts +1 -1
- package/dist/MetadataList/MetadataList.d.ts.map +1 -1
- package/dist/MetadataList/MetadataList.js +4 -2
- package/dist/MultiSelector/MultiSelector.d.ts +9 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +80 -42
- package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
- package/dist/NumberInput/NumberInput.d.ts +10 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +22 -17
- package/dist/Outline/Outline.js +2 -2
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +11 -3
- package/dist/PowerSearch/PowerSearch.d.ts +9 -2
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +2 -0
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +6 -1
- package/dist/RadioList/RadioList.d.ts +2 -2
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +5 -5
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +49 -19
- package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +5 -3
- package/dist/Selector/Selector.d.ts +8 -0
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +66 -17
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +5 -5
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavCollapseButton.js +13 -10
- package/dist/SideNav/SideNavItem.d.ts +1 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +12 -10
- package/dist/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton/Skeleton.js +2 -2
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +87 -34
- package/dist/Spinner/Spinner.d.ts +3 -2
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +11 -2
- package/dist/Switch/Switch.d.ts +8 -1
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +171 -91
- package/dist/TabList/Tab.js +2 -2
- package/dist/TabList/TabList.d.ts +2 -11
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +5 -9
- package/dist/TabList/TabListContext.d.ts +0 -5
- package/dist/TabList/TabListContext.d.ts.map +1 -1
- package/dist/TabList/TabListContext.js +0 -5
- package/dist/TabList/TabMenu.js +1 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +30 -4
- package/dist/Table/TableCell.js +3 -3
- package/dist/Table/TableHeaderCell.js +3 -3
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +37 -27
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +3 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +15 -7
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +29 -23
- package/dist/Table/types.d.ts +32 -0
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/TextArea/TextArea.d.ts +10 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +18 -19
- package/dist/TextInput/TextInput.d.ts +10 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +20 -17
- package/dist/Thumbnail/Thumbnail.js +2 -2
- package/dist/TimeInput/TimeInput.d.ts +10 -2
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +17 -17
- package/dist/Timestamp/Timestamp.d.ts +31 -3
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +47 -76
- package/dist/Timestamp/formatInstant.d.ts +41 -0
- package/dist/Timestamp/formatInstant.d.ts.map +1 -0
- package/dist/Timestamp/formatInstant.js +177 -0
- package/dist/Timestamp/index.d.ts +1 -0
- package/dist/Timestamp/index.d.ts.map +1 -1
- package/dist/Timestamp/tooltipEntries.d.ts +56 -0
- package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
- package/dist/Timestamp/tooltipEntries.js +163 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +61 -9
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +3 -1
- package/dist/Token/Token.d.ts +34 -4
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +85 -45
- package/dist/Token/TokenLink.d.ts +62 -0
- package/dist/Token/TokenLink.d.ts.map +1 -0
- package/dist/Token/TokenLink.js +76 -0
- package/dist/Token/index.d.ts +1 -1
- package/dist/Token/index.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts +9 -2
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +4 -2
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +17 -1
- package/dist/TopNav/TopNavItem.d.ts +3 -1
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +30 -3
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +9 -3
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +1 -0
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +8 -6
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +32 -14
- package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +22 -11
- package/dist/Typeahead/Typeahead.d.ts +9 -2
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +11 -2
- package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
- package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
- package/dist/Typeahead/TypeaheadItem.js +20 -10
- package/dist/astryx.css +74 -33
- package/dist/astryx.umd.js +51 -51
- package/dist/astryx.umd.js.map +4 -4
- 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/isRtlElement.d.ts +18 -0
- package/dist/hooks/isRtlElement.d.ts.map +1 -0
- package/dist/hooks/isRtlElement.js +27 -0
- package/dist/hooks/useAnnounce.d.ts +3 -0
- package/dist/hooks/useAnnounce.d.ts.map +1 -1
- package/dist/hooks/useAnnounce.js +39 -1
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +52 -11
- package/dist/hooks/useGridFocus.d.ts +6 -1
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +12 -9
- package/dist/hooks/useHotkeys.d.ts +9 -0
- package/dist/hooks/useHotkeys.d.ts.map +1 -1
- package/dist/hooks/useHotkeys.js +9 -0
- package/dist/hooks/useInputStatusIcon.d.ts +38 -0
- package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
- package/dist/hooks/useInputStatusIcon.js +169 -0
- package/dist/hooks/useKeyboardHint.d.ts +1 -1
- package/dist/hooks/useKeyboardHint.d.ts.map +1 -1
- package/dist/hooks/useKeyboardHint.js +4 -2
- package/dist/hooks/useListFocus.d.ts +39 -1
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +54 -9
- package/dist/i18n/InternationalizationContext.d.ts +1 -0
- package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
- package/dist/i18n/InternationalizationContext.js +3 -0
- package/dist/i18n/InternationalizationProvider.d.ts +8 -1
- package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
- package/dist/i18n/InternationalizationProvider.js +5 -1
- package/dist/i18n/getLocaleDirection.d.ts +18 -0
- package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
- package/dist/i18n/getLocaleDirection.js +29 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +7 -1
- package/dist/i18n/useDirection.d.ts +2 -0
- package/dist/i18n/useDirection.d.ts.map +1 -0
- package/dist/i18n/useDirection.js +27 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +13 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/plainDate.d.ts +17 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +23 -4
- package/dist/utils/rtlStyles.d.ts +24 -0
- package/dist/utils/rtlStyles.d.ts.map +1 -0
- package/dist/utils/rtlStyles.js +27 -0
- package/locales/en.json +112 -0
- package/locales/pseudo.json +84 -0
- package/package.json +6 -1
- package/src/Avatar/Avatar.doc.mjs +50 -3
- package/src/Avatar/Avatar.test.tsx +218 -0
- package/src/Avatar/Avatar.tsx +285 -79
- package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
- package/src/Avatar/AvatarStatusDot.tsx +6 -4
- package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
- package/src/AvatarGroup/AvatarGroup.test.tsx +162 -2
- package/src/AvatarGroup/AvatarGroup.tsx +58 -3
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +5 -2
- package/src/Banner/Banner.tsx +6 -6
- package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +52 -1
- package/src/Breadcrumbs/index.ts +4 -0
- package/src/Button/Button.doc.mjs +0 -4
- package/src/Button/Button.test.tsx +16 -0
- package/src/Button/Button.tsx +6 -4
- package/src/Calendar/Calendar.test.tsx +170 -20
- package/src/Calendar/Calendar.tsx +73 -16
- package/src/Calendar/dayCellUtils.test.ts +18 -18
- package/src/Calendar/dayCellUtils.ts +2 -2
- package/src/Calendar/styles.ts +33 -39
- package/src/Card/Card.tsx +1 -1
- package/src/Carousel/Carousel.tsx +25 -6
- package/src/Chat/ChatComposer.doc.mjs +2 -2
- package/src/Chat/ChatComposerInput.doc.mjs +1 -1
- package/src/Chat/ChatComposerInput.tsx +2 -2
- package/src/Chat/ChatDictationButton.tsx +7 -1
- package/src/Chat/ChatLayout.tsx +4 -4
- package/src/Chat/ChatMessageBubble.tsx +15 -10
- package/src/Chat/ChatSystemMessage.test.tsx +5 -0
- package/src/Chat/ChatToolCalls.tsx +9 -2
- package/src/Chat/useTriggerMenu.tsx +1 -1
- package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +23 -0
- package/src/CheckboxInput/CheckboxInput.tsx +21 -6
- package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
- package/src/CheckboxList/CheckboxList.test.tsx +94 -3
- package/src/CheckboxList/CheckboxListItem.tsx +17 -10
- package/src/Citation/Citation.doc.mjs +4 -3
- package/src/Citation/Citation.test.tsx +97 -0
- package/src/Citation/Citation.tsx +43 -11
- package/src/CodeBlock/CodeBlock.test.tsx +17 -0
- package/src/CodeBlock/CodeBlock.tsx +38 -11
- package/src/Collapsible/Collapsible.doc.mjs +1 -0
- package/src/Collapsible/Collapsible.test.tsx +7 -0
- package/src/Collapsible/Collapsible.tsx +16 -6
- package/src/CommandPalette/CommandPalette.test.tsx +95 -1
- package/src/CommandPalette/CommandPalette.tsx +41 -2
- package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
- package/src/ContextMenu/ContextMenu.test.tsx +59 -2
- package/src/ContextMenu/ContextMenu.tsx +22 -11
- package/src/ContextMenu/index.ts +5 -0
- package/src/DateInput/DateInput.doc.mjs +25 -0
- package/src/DateInput/DateInput.test.tsx +230 -0
- package/src/DateInput/DateInput.tsx +51 -29
- package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
- package/src/DateRangeInput/DateRangeInput.test.tsx +140 -0
- package/src/DateRangeInput/DateRangeInput.tsx +42 -30
- package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
- package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
- package/src/DateTimeInput/DateTimeInput.tsx +44 -39
- package/src/Divider/Divider.test.tsx +32 -8
- package/src/Divider/Divider.tsx +14 -1
- package/src/DropdownMenu/DropdownMenu.test.tsx +60 -0
- package/src/DropdownMenu/DropdownMenu.tsx +31 -12
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +8 -2
- package/src/DropdownMenu/DropdownMenuItem.tsx +9 -3
- package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +4 -12
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +9 -10
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +9 -3
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +20 -2
- package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +635 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +553 -0
- package/src/DropdownMenu/index.ts +16 -0
- package/src/DropdownMenu/menuItemHover.ts +39 -0
- package/src/DropdownMenu/menuItemRoles.ts +9 -0
- package/src/DropdownMenu/renderDropdownItems.tsx +29 -15
- package/src/Field/Field.doc.mjs +4 -0
- package/src/Field/Field.tsx +14 -9
- package/src/Field/FieldLabel.test.tsx +25 -0
- package/src/Field/FieldLabel.tsx +12 -3
- package/src/Field/inputStyles.stylex.ts +2 -0
- package/src/FieldStatus/FieldStatus.doc.mjs +1 -0
- package/src/FieldStatus/FieldStatus.test.tsx +133 -0
- package/src/FieldStatus/FieldStatus.tsx +61 -4
- package/src/FileInput/FileInput.doc.mjs +23 -2
- package/src/FileInput/FileInput.test.tsx +104 -13
- package/src/FileInput/FileInput.tsx +106 -79
- package/src/HoverCard/useHoverCard.tsx +15 -3
- package/src/Icon/Icon.doc.mjs +13 -0
- package/src/Icon/Icon.test.tsx +89 -0
- package/src/Icon/Icon.tsx +51 -3
- package/src/Item/Item.doc.mjs +5 -0
- package/src/Item/Item.test.tsx +88 -0
- package/src/Item/Item.tsx +57 -11
- package/src/Layer/layerAnimations.stylex.ts +23 -0
- package/src/Lightbox/Lightbox.tsx +15 -7
- package/src/List/List.test.tsx +17 -29
- package/src/List/List.tsx +6 -1
- package/src/List/ListItem.doc.mjs +12 -0
- package/src/List/ListItem.tsx +13 -0
- package/src/Markdown/Markdown.test.tsx +21 -0
- package/src/Markdown/Markdown.tsx +4 -0
- package/src/MetadataList/MetadataList.test.tsx +24 -0
- package/src/MetadataList/MetadataList.tsx +6 -2
- package/src/MultiSelector/MultiSelector.doc.mjs +20 -0
- package/src/MultiSelector/MultiSelector.test.tsx +402 -0
- package/src/MultiSelector/MultiSelector.tsx +120 -59
- package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
- package/src/NumberInput/NumberInput.doc.mjs +21 -0
- package/src/NumberInput/NumberInput.test.tsx +71 -0
- package/src/NumberInput/NumberInput.tsx +35 -26
- package/src/Outline/Outline.test.tsx +12 -12
- package/src/Outline/Outline.tsx +2 -2
- package/src/Pagination/Pagination.tsx +11 -3
- package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
- package/src/PowerSearch/PowerSearch.test.tsx +23 -0
- package/src/PowerSearch/PowerSearch.tsx +10 -1
- package/src/ProgressBar/ProgressBar.test.tsx +34 -0
- package/src/ProgressBar/ProgressBar.tsx +16 -1
- package/src/RadioList/RadioList.doc.mjs +6 -0
- package/src/RadioList/RadioList.test.tsx +26 -4
- package/src/RadioList/RadioList.tsx +2 -2
- package/src/RadioList/RadioListItem.tsx +12 -5
- package/src/Resizable/ResizeHandle.test.tsx +94 -0
- package/src/Resizable/ResizeHandle.tsx +70 -20
- package/src/SegmentedControl/SegmentedControl.test.tsx +28 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +22 -2
- package/src/Selector/Selector.doc.mjs +15 -0
- package/src/Selector/Selector.test.tsx +370 -0
- package/src/Selector/Selector.tsx +88 -20
- package/src/SideNav/SideNav.tsx +1 -8
- package/src/SideNav/SideNavCollapseButton.tsx +9 -7
- package/src/SideNav/SideNavItem.tsx +5 -3
- package/src/Skeleton/Skeleton.test.tsx +16 -0
- package/src/Skeleton/Skeleton.tsx +13 -1
- package/src/Slider/Slider.doc.mjs +6 -0
- package/src/Slider/Slider.test.tsx +240 -12
- package/src/Slider/Slider.tsx +96 -23
- package/src/Spinner/Spinner.test.tsx +10 -8
- package/src/Spinner/Spinner.tsx +15 -5
- package/src/Switch/Switch.doc.mjs +142 -42
- package/src/Switch/Switch.test.tsx +111 -0
- package/src/Switch/Switch.tsx +149 -32
- package/src/TabList/Tab.tsx +2 -2
- package/src/TabList/TabList.doc.mjs +0 -6
- package/src/TabList/TabList.test.tsx +3 -15
- package/src/TabList/TabList.tsx +6 -17
- package/src/TabList/TabListContext.ts +0 -6
- package/src/TabList/TabMenu.tsx +2 -2
- package/src/Table/BaseTable.tsx +34 -2
- package/src/Table/Table.doc.mjs +11 -0
- package/src/Table/Table.test.tsx +85 -0
- package/src/Table/TableCell.tsx +3 -3
- package/src/Table/TableHeaderCell.tsx +3 -3
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +19 -0
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +27 -18
- package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
- package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +38 -9
- package/src/Table/plugins/tree/useTableTreeData.tsx +17 -13
- package/src/Table/types.ts +33 -0
- package/src/Table/useTableRowStatus.doc.mjs +1 -1
- package/src/TextArea/TextArea.doc.mjs +21 -0
- package/src/TextArea/TextArea.test.tsx +23 -0
- package/src/TextArea/TextArea.tsx +27 -26
- package/src/TextInput/TextInput.doc.mjs +21 -0
- package/src/TextInput/TextInput.test.tsx +150 -0
- package/src/TextInput/TextInput.tsx +28 -25
- package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
- package/src/Thumbnail/Thumbnail.tsx +1 -1
- package/src/TimeInput/TimeInput.doc.mjs +21 -0
- package/src/TimeInput/TimeInput.test.tsx +23 -0
- package/src/TimeInput/TimeInput.tsx +24 -25
- package/src/Timestamp/Timestamp.doc.mjs +32 -6
- package/src/Timestamp/Timestamp.test.tsx +371 -0
- package/src/Timestamp/Timestamp.tsx +96 -93
- package/src/Timestamp/formatInstant.ts +218 -0
- package/src/Timestamp/index.ts +4 -0
- package/src/Timestamp/tooltipEntries.test.ts +552 -0
- package/src/Timestamp/tooltipEntries.ts +210 -0
- package/src/Toast/ToastViewport.test.tsx +218 -8
- package/src/Toast/ToastViewport.tsx +71 -12
- package/src/ToggleButton/ToggleButton.test.tsx +24 -0
- package/src/ToggleButton/ToggleButton.tsx +19 -1
- package/src/Token/Token.test.tsx +166 -15
- package/src/Token/Token.tsx +104 -47
- package/src/Token/TokenLink.tsx +107 -0
- package/src/Token/index.ts +1 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +23 -1
- package/src/Tokenizer/Tokenizer.test.tsx +23 -0
- package/src/Tokenizer/Tokenizer.tsx +14 -2
- package/src/Tooltip/Tooltip.test.tsx +46 -0
- package/src/Tooltip/useTooltip.tsx +20 -0
- package/src/TopNav/TopNav.test.tsx +93 -2
- package/src/TopNav/TopNavItem.doc.mjs +3 -3
- package/src/TopNav/TopNavItem.tsx +35 -6
- package/src/TopNav/TopNavMegaMenu.tsx +26 -2
- package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
- package/src/TreeList/TreeList.doc.mjs +6 -0
- package/src/TreeList/TreeList.test.tsx +50 -10
- package/src/TreeList/TreeList.tsx +5 -0
- package/src/TreeList/TreeListBranches.tsx +8 -6
- package/src/TreeList/TreeListItem.tsx +33 -11
- package/src/Typeahead/BaseTypeahead.tsx +42 -15
- package/src/Typeahead/Typeahead.doc.mjs +13 -0
- package/src/Typeahead/Typeahead.test.tsx +112 -0
- package/src/Typeahead/Typeahead.tsx +17 -1
- package/src/Typeahead/TypeaheadItem.tsx +2 -1
- package/src/__tests__/forcedColors.ts +60 -0
- package/src/__tests__/inputWidthContract.test.tsx +62 -0
- package/src/doc-mjs.d.ts +19 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/isRtlElement.ts +27 -0
- package/src/hooks/useAnnounce.test.tsx +75 -2
- package/src/hooks/useAnnounce.ts +47 -1
- package/src/hooks/useFocusTrap.test.tsx +104 -0
- package/src/hooks/useFocusTrap.ts +61 -12
- package/src/hooks/useGridFocus.doc.mjs +3 -3
- package/src/hooks/useGridFocus.test.tsx +41 -0
- package/src/hooks/useGridFocus.ts +21 -10
- package/src/hooks/useHotkeys.ts +9 -0
- package/src/hooks/useInputStatusIcon.test.tsx +221 -0
- package/src/hooks/useInputStatusIcon.tsx +235 -0
- package/src/hooks/useKeyboardHint.test.tsx +22 -0
- package/src/hooks/useKeyboardHint.tsx +6 -2
- package/src/hooks/useListFocus.doc.mjs +25 -3
- package/src/hooks/useListFocus.test.tsx +153 -1
- package/src/hooks/useListFocus.ts +102 -9
- package/src/i18n/InternationalizationContext.ts +4 -0
- package/src/i18n/InternationalizationProvider.tsx +12 -2
- package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
- package/src/i18n/__tests__/useDirection.test.tsx +66 -0
- package/src/i18n/getLocaleDirection.ts +29 -0
- package/src/i18n/index.ts +6 -0
- package/src/i18n/useDirection.ts +29 -0
- package/src/reset.css +0 -26
- package/src/reset.test.ts +60 -0
- package/src/theme/derivedVarRegistry.test.ts +1 -0
- package/src/theme/derivedVarRegistry.ts +6 -0
- package/src/theme/generateThemeRules.test.ts +42 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/plainDate.test.ts +24 -6
- package/src/utils/plainDate.ts +18 -4
- package/src/utils/rtlStyles.ts +27 -0
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
inputStatusBorderStyles,
|
|
38
38
|
inputStatusHoverShadowStyles,
|
|
39
39
|
inputWrapperStyles,
|
|
40
|
+
type FieldStatusVariant,
|
|
40
41
|
} from '../Field';
|
|
41
42
|
import {Divider} from '../Divider';
|
|
42
43
|
import {Spinner} from '../Spinner';
|
|
@@ -479,6 +480,13 @@ export interface MultiSelectorProps<
|
|
|
479
480
|
* Status indicator for the selector.
|
|
480
481
|
*/
|
|
481
482
|
status?: MultiSelectorStatus;
|
|
483
|
+
/**
|
|
484
|
+
* How the status message is placed relative to the input.
|
|
485
|
+
* - 'attached': message overlaps directly below the input (bordered treatment)
|
|
486
|
+
* - 'detached': message floats below as a separate element with spacing
|
|
487
|
+
* @default 'attached'
|
|
488
|
+
*/
|
|
489
|
+
statusVariant?: FieldStatusVariant;
|
|
482
490
|
|
|
483
491
|
/**
|
|
484
492
|
* Width of the field. Numbers are treated as pixels, strings are used as-is
|
|
@@ -562,6 +570,21 @@ export interface MultiSelectorProps<
|
|
|
562
570
|
'data-testid'?: string;
|
|
563
571
|
}
|
|
564
572
|
|
|
573
|
+
// Case-insensitive substring match for a single option. The one predicate used
|
|
574
|
+
// by both the flat filter (count + keyboard nav) and the grouped renderer, so
|
|
575
|
+
// what is shown while searching stays in lockstep with the announced count.
|
|
576
|
+
function optionMatchesQuery(
|
|
577
|
+
option: MultiSelectorOptionData,
|
|
578
|
+
query: string,
|
|
579
|
+
): boolean {
|
|
580
|
+
if (!query) {
|
|
581
|
+
return true;
|
|
582
|
+
}
|
|
583
|
+
return (option.label ?? option.value)
|
|
584
|
+
.toLowerCase()
|
|
585
|
+
.includes(query.toLowerCase());
|
|
586
|
+
}
|
|
587
|
+
|
|
565
588
|
// Case-insensitive substring filter over the selectable options. Shared by the
|
|
566
589
|
// `filteredItems` memo (rendering) and the search-change handler, which needs
|
|
567
590
|
// the count for the *next* query synchronously to announce it exactly once per
|
|
@@ -573,10 +596,7 @@ function filterOptionsByQuery(
|
|
|
573
596
|
if (!query) {
|
|
574
597
|
return items;
|
|
575
598
|
}
|
|
576
|
-
|
|
577
|
-
return items.filter(item =>
|
|
578
|
-
(item.label ?? item.value).toLowerCase().includes(q),
|
|
579
|
-
);
|
|
599
|
+
return items.filter(item => optionMatchesQuery(item, query));
|
|
580
600
|
}
|
|
581
601
|
|
|
582
602
|
/**
|
|
@@ -610,6 +630,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
610
630
|
placeholder: placeholderFromProps,
|
|
611
631
|
size: sizeProp,
|
|
612
632
|
status,
|
|
633
|
+
statusVariant = 'attached',
|
|
613
634
|
labelTooltip,
|
|
614
635
|
startIcon,
|
|
615
636
|
hasClear = false,
|
|
@@ -716,35 +737,25 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
716
737
|
|
|
717
738
|
// Single source of truth for item order. Both the hook (keyboard navigation)
|
|
718
739
|
// and renderOptions (DOM rendering) consume this list — no independent sorting.
|
|
719
|
-
// Selected-at-open items are placed first within each group/section
|
|
740
|
+
// Selected-at-open items are placed first within each group/section, and the
|
|
741
|
+
// same walk applies while searching so group structure survives filtering
|
|
742
|
+
// (only matching items are kept; the query is empty in non-search mode).
|
|
720
743
|
const sortedItems = useMemo(() => {
|
|
721
744
|
const selectedSet = selectedAtOpen ?? new Set<string>();
|
|
722
|
-
if (searchQuery) {
|
|
723
|
-
const selected = filteredItems.filter(item =>
|
|
724
|
-
selectedSet.has(item.value),
|
|
725
|
-
);
|
|
726
|
-
const unselected = filteredItems.filter(
|
|
727
|
-
item => !selectedSet.has(item.value),
|
|
728
|
-
);
|
|
729
|
-
const items = [...selected, ...unselected];
|
|
730
|
-
if (hasSelectAll) {
|
|
731
|
-
return [{value: SELECT_ALL_VALUE, label: selectAllLabel}, ...items];
|
|
732
|
-
}
|
|
733
|
-
return items;
|
|
734
|
-
}
|
|
735
|
-
// For non-search mode, flatten options in the same order as renderOptions
|
|
736
745
|
const result: MultiSelectorOptionData[] = [];
|
|
737
746
|
let pendingFlat: MultiSelectorOptionData[] = [];
|
|
738
747
|
|
|
748
|
+
const orderSelectedFirst = (items: MultiSelectorOptionData[]) => {
|
|
749
|
+
const selected = items.filter(item => selectedSet.has(item.value));
|
|
750
|
+
const unselected = items.filter(item => !selectedSet.has(item.value));
|
|
751
|
+
return [...selected, ...unselected];
|
|
752
|
+
};
|
|
753
|
+
|
|
739
754
|
const flushFlat = () => {
|
|
740
755
|
if (pendingFlat.length === 0) {
|
|
741
756
|
return;
|
|
742
757
|
}
|
|
743
|
-
|
|
744
|
-
const unselected = pendingFlat.filter(
|
|
745
|
-
item => !selectedSet.has(item.value),
|
|
746
|
-
);
|
|
747
|
-
result.push(...selected, ...unselected);
|
|
758
|
+
result.push(...orderSelectedFirst(pendingFlat));
|
|
748
759
|
pendingFlat = [];
|
|
749
760
|
};
|
|
750
761
|
|
|
@@ -753,16 +764,15 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
753
764
|
flushFlat();
|
|
754
765
|
} else if (isSection(option)) {
|
|
755
766
|
flushFlat();
|
|
756
|
-
const sectionOptions = option.options
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
);
|
|
760
|
-
const unselected = sectionOptions.filter(
|
|
761
|
-
item => !selectedSet.has(item.value),
|
|
762
|
-
);
|
|
763
|
-
result.push(...selected, ...unselected);
|
|
767
|
+
const sectionOptions = option.options
|
|
768
|
+
.map(opt => normalizeOption(opt))
|
|
769
|
+
.filter(opt => optionMatchesQuery(opt, searchQuery));
|
|
770
|
+
result.push(...orderSelectedFirst(sectionOptions));
|
|
764
771
|
} else if (isOptionData(option)) {
|
|
765
|
-
|
|
772
|
+
const normalized = normalizeOption(option);
|
|
773
|
+
if (optionMatchesQuery(normalized, searchQuery)) {
|
|
774
|
+
pendingFlat.push(normalized);
|
|
775
|
+
}
|
|
766
776
|
}
|
|
767
777
|
}
|
|
768
778
|
flushFlat();
|
|
@@ -771,14 +781,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
771
781
|
return [{value: SELECT_ALL_VALUE, label: selectAllLabel}, ...result];
|
|
772
782
|
}
|
|
773
783
|
return result;
|
|
774
|
-
}, [
|
|
775
|
-
filteredItems,
|
|
776
|
-
searchQuery,
|
|
777
|
-
options,
|
|
778
|
-
selectedAtOpen,
|
|
779
|
-
hasSelectAll,
|
|
780
|
-
selectAllLabel,
|
|
781
|
-
]);
|
|
784
|
+
}, [searchQuery, options, selectedAtOpen, hasSelectAll, selectAllLabel]);
|
|
782
785
|
|
|
783
786
|
// Layer for dropdown positioning
|
|
784
787
|
const handleLayerHide = useCallback(() => {
|
|
@@ -1126,6 +1129,11 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1126
1129
|
? allEnabledSelected
|
|
1127
1130
|
: optimisticValue.includes(item.value);
|
|
1128
1131
|
const checkboxValue = isSelectAll ? selectAllState : isSelected;
|
|
1132
|
+
// aria-selected="mixed" is invalid on role="option", and the tri-state
|
|
1133
|
+
// checkbox is inert/decorative, so the indeterminate state must be
|
|
1134
|
+
// conveyed through the option's accessible name (WCAG 4.1.2).
|
|
1135
|
+
const isPartiallySelected =
|
|
1136
|
+
isSelectAll && selectAllState === 'indeterminate';
|
|
1129
1137
|
|
|
1130
1138
|
return (
|
|
1131
1139
|
<div
|
|
@@ -1133,6 +1141,13 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1133
1141
|
id={getItemId(flatIndex)}
|
|
1134
1142
|
role="option"
|
|
1135
1143
|
aria-selected={isSelected}
|
|
1144
|
+
aria-label={
|
|
1145
|
+
isPartiallySelected
|
|
1146
|
+
? t('@astryx.multiSelector.selectAllPartiallySelected', {
|
|
1147
|
+
label: selectAllLabel,
|
|
1148
|
+
})
|
|
1149
|
+
: undefined
|
|
1150
|
+
}
|
|
1136
1151
|
aria-disabled={item.disabled}
|
|
1137
1152
|
onClick={() => {
|
|
1138
1153
|
if (!item.disabled) {
|
|
@@ -1177,10 +1192,12 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1177
1192
|
optimisticValue,
|
|
1178
1193
|
allEnabledSelected,
|
|
1179
1194
|
selectAllState,
|
|
1195
|
+
selectAllLabel,
|
|
1180
1196
|
getItemId,
|
|
1181
1197
|
handleNavigableToggle,
|
|
1182
1198
|
onItemMouseEnter,
|
|
1183
1199
|
size,
|
|
1200
|
+
t,
|
|
1184
1201
|
],
|
|
1185
1202
|
);
|
|
1186
1203
|
|
|
@@ -1208,25 +1225,28 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1208
1225
|
cursor = 1;
|
|
1209
1226
|
}
|
|
1210
1227
|
|
|
1211
|
-
// Empty state — no real items to show
|
|
1228
|
+
// Empty state — no real items to show. role="presentation" keeps the
|
|
1229
|
+
// message out of the listbox's accessibility tree (role="listbox" only
|
|
1230
|
+
// permits option/group children); the no-results outcome is announced
|
|
1231
|
+
// via the result-count live region instead.
|
|
1212
1232
|
if (realItemCount === 0) {
|
|
1213
1233
|
elements.push(
|
|
1214
|
-
<div
|
|
1234
|
+
<div
|
|
1235
|
+
key="empty"
|
|
1236
|
+
role="presentation"
|
|
1237
|
+
{...stylex.props(styles.emptyState)}>
|
|
1215
1238
|
No results found
|
|
1216
1239
|
</div>,
|
|
1217
1240
|
);
|
|
1218
1241
|
return elements;
|
|
1219
1242
|
}
|
|
1220
1243
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
// Non-search: consume items from sortedItems in order, interleaving
|
|
1229
|
-
// structural elements (dividers, section headers) from the options prop.
|
|
1244
|
+
// Consume items from sortedItems in order, interleaving structural elements
|
|
1245
|
+
// (dividers, section headers) from the options prop. While searching, only
|
|
1246
|
+
// matching items are present in sortedItems, so a section consumes just its
|
|
1247
|
+
// matches and is skipped entirely when none match — no header left standing
|
|
1248
|
+
// over nothing, and the cursor stays aligned with the combobox indices.
|
|
1249
|
+
const isSearching = Boolean(searchQuery);
|
|
1230
1250
|
let pendingCount = 0;
|
|
1231
1251
|
|
|
1232
1252
|
const flushPending = () => {
|
|
@@ -1242,12 +1262,25 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1242
1262
|
|
|
1243
1263
|
if (isDivider(option)) {
|
|
1244
1264
|
flushPending();
|
|
1245
|
-
|
|
1265
|
+
// A standalone divider between groups would orphan itself once its
|
|
1266
|
+
// neighbors are filtered out, so skip it while searching.
|
|
1267
|
+
if (!isSearching) {
|
|
1268
|
+
elements.push(
|
|
1269
|
+
<Divider key={`divider-${i}`} xstyle={styles.divider} />,
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1246
1272
|
} else if (isSection(option)) {
|
|
1247
1273
|
flushPending();
|
|
1248
|
-
const
|
|
1274
|
+
const matchCount = isSearching
|
|
1275
|
+
? option.options.filter(opt =>
|
|
1276
|
+
optionMatchesQuery(normalizeOption(opt), searchQuery),
|
|
1277
|
+
).length
|
|
1278
|
+
: option.options.length;
|
|
1279
|
+
if (matchCount === 0) {
|
|
1280
|
+
continue;
|
|
1281
|
+
}
|
|
1249
1282
|
const sectionItems: ReactNode[] = [];
|
|
1250
|
-
for (let j = 0; j <
|
|
1283
|
+
for (let j = 0; j < matchCount; j++) {
|
|
1251
1284
|
sectionItems.push(renderItem(sortedItems[cursor], cursor));
|
|
1252
1285
|
cursor++;
|
|
1253
1286
|
}
|
|
@@ -1266,7 +1299,12 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1266
1299
|
</div>,
|
|
1267
1300
|
);
|
|
1268
1301
|
} else if (isOptionData(option)) {
|
|
1269
|
-
|
|
1302
|
+
if (
|
|
1303
|
+
!isSearching ||
|
|
1304
|
+
optionMatchesQuery(normalizeOption(option), searchQuery)
|
|
1305
|
+
) {
|
|
1306
|
+
pendingCount++;
|
|
1307
|
+
}
|
|
1270
1308
|
}
|
|
1271
1309
|
}
|
|
1272
1310
|
flushPending();
|
|
@@ -1295,7 +1333,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1295
1333
|
isDisabled && inputWrapperStyles.disabled,
|
|
1296
1334
|
optimisticValue.length === 0 && styles.triggerPlaceholder,
|
|
1297
1335
|
status && inputStatusBorderStyles[status.type],
|
|
1298
|
-
status && inputStatusHoverShadowStyles[status.type],
|
|
1336
|
+
status && !isDisabled && inputStatusHoverShadowStyles[status.type],
|
|
1299
1337
|
inputGroup && groupStyles.inGroup,
|
|
1300
1338
|
xstyle,
|
|
1301
1339
|
),
|
|
@@ -1359,7 +1397,17 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1359
1397
|
onClick={handleClear}
|
|
1360
1398
|
aria-label={t('@astryx.multiSelector.clearAll', {label})}
|
|
1361
1399
|
{...stylex.props(styles.clearButton)}>
|
|
1362
|
-
<Icon
|
|
1400
|
+
<Icon
|
|
1401
|
+
icon="close"
|
|
1402
|
+
size="sm"
|
|
1403
|
+
color="secondary"
|
|
1404
|
+
// Stable theme target on the clear glyph itself, so a theme can
|
|
1405
|
+
// restyle just this icon (color, size, hover) via `defineTheme`.
|
|
1406
|
+
// Same-element rules in @layer astryx-theme win over the icon's
|
|
1407
|
+
// own base color/size, which a button-level target could not
|
|
1408
|
+
// reach.
|
|
1409
|
+
{...themeProps('multi-selector-clear-icon')}
|
|
1410
|
+
/>
|
|
1363
1411
|
</button>
|
|
1364
1412
|
)}
|
|
1365
1413
|
<span
|
|
@@ -1375,7 +1423,19 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1375
1423
|
color={STATUS_ICON_COLOR_MAP[status.type]}
|
|
1376
1424
|
/>
|
|
1377
1425
|
) : (
|
|
1378
|
-
<Icon
|
|
1426
|
+
<Icon
|
|
1427
|
+
icon="chevronDown"
|
|
1428
|
+
size="sm"
|
|
1429
|
+
color="inherit"
|
|
1430
|
+
// Stable theme target on the chevron glyph itself, so a theme can
|
|
1431
|
+
// restyle just this icon (color, size, hover) — and its
|
|
1432
|
+
// open/closed state — via `defineTheme`. Same-element rules in
|
|
1433
|
+
// @layer astryx-theme win over the icon's own base color/size,
|
|
1434
|
+
// which a button-level target could not reach.
|
|
1435
|
+
{...themeProps('multi-selector-indicator-icon', {
|
|
1436
|
+
state: popover.isOpen ? 'expanded' : 'collapsed',
|
|
1437
|
+
})}
|
|
1438
|
+
/>
|
|
1379
1439
|
)}
|
|
1380
1440
|
</span>
|
|
1381
1441
|
</div>
|
|
@@ -1426,6 +1486,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
|
|
|
1426
1486
|
}
|
|
1427
1487
|
: undefined
|
|
1428
1488
|
}
|
|
1489
|
+
statusVariant={statusVariant}
|
|
1429
1490
|
labelTooltip={labelTooltip}
|
|
1430
1491
|
width={width}>
|
|
1431
1492
|
{multiSelectorContent}
|
|
@@ -94,6 +94,13 @@ export const docs = {
|
|
|
94
94
|
type: "{type: 'error' | 'warning' | 'success', message?: string}",
|
|
95
95
|
description: 'Validation status with optional message.',
|
|
96
96
|
},
|
|
97
|
+
{
|
|
98
|
+
name: 'statusVariant',
|
|
99
|
+
type: "'attached' | 'detached' | 'tooltip'",
|
|
100
|
+
description:
|
|
101
|
+
'How the status message is placed relative to the input. attached overlaps directly below the input (bordered treatment); detached floats below as a separate element with spacing; tooltip hides the message box and surfaces it in a tooltip on the status icon.',
|
|
102
|
+
default: "'attached'",
|
|
103
|
+
},
|
|
97
104
|
{
|
|
98
105
|
name: 'min',
|
|
99
106
|
type: 'number | null',
|
|
@@ -138,6 +145,12 @@ export const docs = {
|
|
|
138
145
|
type: 'string',
|
|
139
146
|
description: 'HTML autocomplete attribute.',
|
|
140
147
|
},
|
|
148
|
+
{
|
|
149
|
+
name: 'width',
|
|
150
|
+
type: 'SizeValue',
|
|
151
|
+
description:
|
|
152
|
+
'Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned.',
|
|
153
|
+
},
|
|
141
154
|
{
|
|
142
155
|
name: 'hasAutoFocus',
|
|
143
156
|
type: 'boolean',
|
|
@@ -275,6 +288,13 @@ export const docsZh = {
|
|
|
275
288
|
type: "{type: 'error' | 'warning' | 'success', message?: string}",
|
|
276
289
|
description: '带可选消息的验证状态。',
|
|
277
290
|
},
|
|
291
|
+
{
|
|
292
|
+
name: 'statusVariant',
|
|
293
|
+
type: "'attached' | 'detached' | 'tooltip'",
|
|
294
|
+
description:
|
|
295
|
+
'状态消息相对于输入框的放置方式。attached 直接叠加在输入框下方(带边框处理);detached 作为独立元素浮于下方并留有间距;tooltip 隐藏消息框,并在状态图标上以提示气泡形式显示。',
|
|
296
|
+
default: "'attached'",
|
|
297
|
+
},
|
|
278
298
|
{
|
|
279
299
|
name: 'min',
|
|
280
300
|
type: 'number | null',
|
|
@@ -402,6 +422,7 @@ export const docsDense = {
|
|
|
402
422
|
startIcon: 'Icon at input start.',
|
|
403
423
|
labelIcon: 'Icon before label text.',
|
|
404
424
|
status: 'Validation status w/ optional message.',
|
|
425
|
+
statusVariant: 'How status message is placed: attached overlaps below input; detached floats below w/ spacing; tooltip hides the box and shows it on the status icon.',
|
|
405
426
|
min: 'Minimum value allowed.',
|
|
406
427
|
max: 'Maximum value allowed.',
|
|
407
428
|
step: 'Step increment.',
|
|
@@ -13,6 +13,7 @@ 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
|
+
import {InputGroup} from '../InputGroup';
|
|
16
17
|
import {NumberInput} from './NumberInput';
|
|
17
18
|
import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
|
|
18
19
|
|
|
@@ -336,6 +337,33 @@ describe('NumberInput', () => {
|
|
|
336
337
|
expect(screen.queryByText('%')).not.toBeInTheDocument();
|
|
337
338
|
expect(screen.queryByText('GB')).not.toBeInTheDocument();
|
|
338
339
|
});
|
|
340
|
+
|
|
341
|
+
it('includes the units text in the accessible description (WCAG 1.3.1)', () => {
|
|
342
|
+
render(
|
|
343
|
+
<NumberInput
|
|
344
|
+
label="Storage"
|
|
345
|
+
value={50}
|
|
346
|
+
onChange={() => {}}
|
|
347
|
+
units="GB"
|
|
348
|
+
/>,
|
|
349
|
+
);
|
|
350
|
+
expect(screen.getByRole('spinbutton')).toHaveAccessibleDescription(/GB/);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('combines units with the description in the accessible description', () => {
|
|
354
|
+
render(
|
|
355
|
+
<NumberInput
|
|
356
|
+
label="Discount"
|
|
357
|
+
value={10}
|
|
358
|
+
onChange={() => {}}
|
|
359
|
+
description="Applied at checkout"
|
|
360
|
+
units="%"
|
|
361
|
+
/>,
|
|
362
|
+
);
|
|
363
|
+
const input = screen.getByRole('spinbutton');
|
|
364
|
+
expect(input).toHaveAccessibleDescription(/Applied at checkout/);
|
|
365
|
+
expect(input).toHaveAccessibleDescription(/%/);
|
|
366
|
+
});
|
|
339
367
|
});
|
|
340
368
|
|
|
341
369
|
describe('event callbacks', () => {
|
|
@@ -463,6 +491,26 @@ describe('NumberInput', () => {
|
|
|
463
491
|
expect(screen.getByText('Value must be positive')).toBeInTheDocument();
|
|
464
492
|
});
|
|
465
493
|
|
|
494
|
+
it('has no dangling aria-describedby ids inside InputGroup (WCAG 1.3.1)', () => {
|
|
495
|
+
// Inside an InputGroup no Field renders, so the status message element
|
|
496
|
+
// does not exist; aria-describedby must not reference its id.
|
|
497
|
+
render(
|
|
498
|
+
<InputGroup label="Price">
|
|
499
|
+
<NumberInput
|
|
500
|
+
label="Amount"
|
|
501
|
+
value={null}
|
|
502
|
+
onChange={() => {}}
|
|
503
|
+
status={{type: 'error', message: 'Value must be positive'}}
|
|
504
|
+
/>
|
|
505
|
+
</InputGroup>,
|
|
506
|
+
);
|
|
507
|
+
const input = screen.getByRole('spinbutton');
|
|
508
|
+
const describedBy = input.getAttribute('aria-describedby') ?? '';
|
|
509
|
+
for (const idToken of describedBy.split(/\s+/).filter(Boolean)) {
|
|
510
|
+
expect(document.getElementById(idToken)).not.toBeNull();
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
|
|
466
514
|
it('does not render status message when not provided', () => {
|
|
467
515
|
render(
|
|
468
516
|
<NumberInput
|
|
@@ -916,3 +964,26 @@ describe('keyboard clearing with hasClear (#3599)', () => {
|
|
|
916
964
|
expect((input as HTMLInputElement).value).toBe('42');
|
|
917
965
|
});
|
|
918
966
|
});
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
describe('NumberInput statusVariant forwarding', () => {
|
|
970
|
+
it('defaults to attached (status renders with data-variant="attached")', () => {
|
|
971
|
+
const {container} = render(
|
|
972
|
+
<NumberInput label="Amount" value={null} onChange={() => {}} status={{type: 'error', message: 'Must be positive'}} />,
|
|
973
|
+
);
|
|
974
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
975
|
+
'data-variant',
|
|
976
|
+
'attached',
|
|
977
|
+
);
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
it('forwards statusVariant="detached" to the underlying Field status', () => {
|
|
981
|
+
const {container} = render(
|
|
982
|
+
<NumberInput label="Amount" value={null} onChange={() => {}} status={{type: 'error', message: 'Must be positive'}} statusVariant="detached" />,
|
|
983
|
+
);
|
|
984
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
985
|
+
'data-variant',
|
|
986
|
+
'detached',
|
|
987
|
+
);
|
|
988
|
+
});
|
|
989
|
+
});
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
type ReactNode,
|
|
28
28
|
} from 'react';
|
|
29
29
|
import * as stylex from '@stylexjs/stylex';
|
|
30
|
-
import type {IconName} from '../Icon';
|
|
31
30
|
import {
|
|
32
31
|
colorVars,
|
|
33
32
|
sizeVars,
|
|
@@ -39,11 +38,11 @@ import {
|
|
|
39
38
|
import {
|
|
40
39
|
Field,
|
|
41
40
|
type InputStatus,
|
|
42
|
-
type InputStatusType,
|
|
43
41
|
inputWrapperStyles,
|
|
44
42
|
inputStatusBorderStyles,
|
|
45
43
|
inputStatusHoverShadowStyles,
|
|
46
44
|
inputStatusFocusWithinStyles,
|
|
45
|
+
type FieldStatusVariant,
|
|
47
46
|
} from '../Field';
|
|
48
47
|
import {Icon, renderIconSlot, type IconType} from '../Icon';
|
|
49
48
|
import {VisuallyHidden} from '../VisuallyHidden';
|
|
@@ -51,6 +50,7 @@ import {useTooltip} from '../Tooltip';
|
|
|
51
50
|
import {getInputARIA} from '../utils';
|
|
52
51
|
import {useSize} from '../SizeContext/SizeContext';
|
|
53
52
|
import {useInputContainer} from '../hooks/useInputContainer';
|
|
53
|
+
import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
|
|
54
54
|
import {useInputGroup} from '../InputGroup/InputGroupContext';
|
|
55
55
|
|
|
56
56
|
const styles = stylex.create({
|
|
@@ -207,6 +207,14 @@ interface NumberInputPropsBase extends Omit<
|
|
|
207
207
|
* If message is provided, displays a floating message box below the input.
|
|
208
208
|
*/
|
|
209
209
|
status?: InputStatus;
|
|
210
|
+
/**
|
|
211
|
+
* How the status message is placed relative to the input.
|
|
212
|
+
* - 'attached': message overlaps directly below the input (bordered treatment)
|
|
213
|
+
* - 'detached': message floats below as a separate element with spacing
|
|
214
|
+
* - 'tooltip': no message box; the status icon becomes a focusable info-tip button that reveals the message on hover, keyboard focus, or tap
|
|
215
|
+
* @default 'attached'
|
|
216
|
+
*/
|
|
217
|
+
statusVariant?: FieldStatusVariant;
|
|
210
218
|
/**
|
|
211
219
|
* The size of the input.
|
|
212
220
|
* - 'sm': Compact size (28px height)
|
|
@@ -374,6 +382,7 @@ export function NumberInput({
|
|
|
374
382
|
startIcon,
|
|
375
383
|
labelIcon,
|
|
376
384
|
status,
|
|
385
|
+
statusVariant = 'attached',
|
|
377
386
|
size: sizeProp,
|
|
378
387
|
onChange,
|
|
379
388
|
value,
|
|
@@ -405,6 +414,7 @@ export function NumberInput({
|
|
|
405
414
|
const inputLabelID = useId();
|
|
406
415
|
const descriptionID = useId();
|
|
407
416
|
const statusMessageID = useId();
|
|
417
|
+
const unitsID = useId();
|
|
408
418
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
409
419
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
410
420
|
const inputGroup = useInputGroup();
|
|
@@ -426,26 +436,26 @@ export function NumberInput({
|
|
|
426
436
|
isEnabled: showsDisabledMessage,
|
|
427
437
|
});
|
|
428
438
|
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const statusIconColorMap: Record<
|
|
436
|
-
InputStatusType,
|
|
437
|
-
'warning' | 'error' | 'success'
|
|
438
|
-
> = {
|
|
439
|
-
warning: 'warning',
|
|
440
|
-
error: 'error',
|
|
441
|
-
success: 'success',
|
|
442
|
-
};
|
|
439
|
+
const {statusIcon, describedBy: statusTooltipDescribedBy} =
|
|
440
|
+
useInputStatusIcon({
|
|
441
|
+
status,
|
|
442
|
+
statusVariant,
|
|
443
|
+
isInGroup: !!inputGroup,
|
|
444
|
+
});
|
|
443
445
|
|
|
444
446
|
const {ariaLabelledBy, ariaDescribedBy} = getInputARIA(
|
|
445
447
|
inputLabelID,
|
|
446
448
|
[
|
|
447
449
|
description ? descriptionID : null,
|
|
448
|
-
status
|
|
450
|
+
// The status message element is rendered by Field, which is skipped
|
|
451
|
+
// inside an InputGroup — only reference it when it actually exists.
|
|
452
|
+
!inputGroup && statusVariant !== 'tooltip' && status?.message
|
|
453
|
+
? statusMessageID
|
|
454
|
+
: null,
|
|
455
|
+
// The tooltip variant renders no message box; describe the input by the
|
|
456
|
+
// tooltip's content instead so the status is still announced.
|
|
457
|
+
statusTooltipDescribedBy,
|
|
458
|
+
units ? unitsID : null,
|
|
449
459
|
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
450
460
|
],
|
|
451
461
|
inputGroup,
|
|
@@ -605,7 +615,7 @@ export function NumberInput({
|
|
|
605
615
|
sizeStyles[size],
|
|
606
616
|
isDisabled && inputWrapperStyles.disabled,
|
|
607
617
|
status && inputStatusBorderStyles[status.type],
|
|
608
|
-
status && inputStatusHoverShadowStyles[status.type],
|
|
618
|
+
status && !isDisabled && inputStatusHoverShadowStyles[status.type],
|
|
609
619
|
status && inputStatusFocusWithinStyles[status.type],
|
|
610
620
|
inputGroup && groupStyles.inGroup,
|
|
611
621
|
xstyle,
|
|
@@ -651,7 +661,11 @@ export function NumberInput({
|
|
|
651
661
|
!isInputValid && styles.inputInvalid,
|
|
652
662
|
)}
|
|
653
663
|
/>
|
|
654
|
-
{units &&
|
|
664
|
+
{units && (
|
|
665
|
+
<span id={unitsID} {...stylex.props(styles.units)}>
|
|
666
|
+
{units}
|
|
667
|
+
</span>
|
|
668
|
+
)}
|
|
655
669
|
{/*
|
|
656
670
|
Live region announcing invalid typed input to assistive technology.
|
|
657
671
|
The value silently reverts on blur, so without this a screen-reader
|
|
@@ -669,13 +683,7 @@ export function NumberInput({
|
|
|
669
683
|
<Icon icon="close" size="sm" color="secondary" />
|
|
670
684
|
</button>
|
|
671
685
|
)}
|
|
672
|
-
{
|
|
673
|
-
<Icon
|
|
674
|
-
icon={statusIconMap[status.type]}
|
|
675
|
-
size="md"
|
|
676
|
-
color={statusIconColorMap[status.type]}
|
|
677
|
-
/>
|
|
678
|
-
)}
|
|
686
|
+
{statusIcon}
|
|
679
687
|
</div>
|
|
680
688
|
);
|
|
681
689
|
|
|
@@ -709,6 +717,7 @@ export function NumberInput({
|
|
|
709
717
|
}
|
|
710
718
|
: undefined
|
|
711
719
|
}
|
|
720
|
+
statusVariant={statusVariant}
|
|
712
721
|
labelTooltip={labelTooltip}
|
|
713
722
|
width={width}>
|
|
714
723
|
{inputWrapper}
|