@astryxdesign/core 0.1.9 → 0.2.0-canary.136a00f
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 +39 -3
- 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/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 +70 -30
- 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 +158 -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.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.test.tsx +72 -0
- package/src/FieldStatus/FieldStatus.tsx +48 -2
- 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/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 +162 -0
- package/src/hooks/useInputStatusIcon.tsx +224 -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
|
@@ -4,7 +4,8 @@ import {render, screen} from '@testing-library/react';
|
|
|
4
4
|
import userEvent from '@testing-library/user-event';
|
|
5
5
|
import {AvatarGroup} from './AvatarGroup';
|
|
6
6
|
import {AvatarGroupOverflow} from './AvatarGroupOverflow';
|
|
7
|
-
import {Avatar} from '../Avatar';
|
|
7
|
+
import {Avatar, AvatarStatusDot} from '../Avatar';
|
|
8
|
+
import {InternationalizationProvider} from '../i18n';
|
|
8
9
|
|
|
9
10
|
describe('AvatarGroup', () => {
|
|
10
11
|
it('renders all avatar children', () => {
|
|
@@ -21,6 +22,21 @@ describe('AvatarGroup', () => {
|
|
|
21
22
|
expect(screen.getByLabelText('Charlie')).toBeInTheDocument();
|
|
22
23
|
});
|
|
23
24
|
|
|
25
|
+
it('composes a labelled status into a grouped avatar accessible name (WCAG 4.1.2)', () => {
|
|
26
|
+
render(
|
|
27
|
+
<AvatarGroup>
|
|
28
|
+
<Avatar
|
|
29
|
+
name="Alice"
|
|
30
|
+
status={<AvatarStatusDot variant="success" label="Online" />}
|
|
31
|
+
/>
|
|
32
|
+
<Avatar name="Bob" />
|
|
33
|
+
</AvatarGroup>,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
expect(screen.getByLabelText('Alice, Online')).toBeInTheDocument();
|
|
37
|
+
expect(screen.getByLabelText('Bob')).toBeInTheDocument();
|
|
38
|
+
});
|
|
39
|
+
|
|
24
40
|
it('renders with role="group" and default aria-label', () => {
|
|
25
41
|
render(
|
|
26
42
|
<AvatarGroup>
|
|
@@ -223,6 +239,150 @@ describe('AvatarGroupOverflow — hardening', () => {
|
|
|
223
239
|
);
|
|
224
240
|
|
|
225
241
|
expect(screen.getByText('+4912')).toBeInTheDocument();
|
|
226
|
-
|
|
242
|
+
// The aria-label routes through the catalog's `{count, number}` ICU
|
|
243
|
+
// argument, so the en locale adds a grouping separator.
|
|
244
|
+
expect(screen.getByLabelText('4,912 more')).toBeInTheDocument();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('localizes the overflow label through the i18n catalog', () => {
|
|
248
|
+
render(
|
|
249
|
+
<InternationalizationProvider
|
|
250
|
+
locale="fr"
|
|
251
|
+
overrides={{
|
|
252
|
+
fr: {'@astryx.avatarGroup.overflow': '{count, number} de plus'},
|
|
253
|
+
}}>
|
|
254
|
+
<AvatarGroup>
|
|
255
|
+
<Avatar name="Alice" />
|
|
256
|
+
<AvatarGroupOverflow count={3} />
|
|
257
|
+
</AvatarGroup>
|
|
258
|
+
</InternationalizationProvider>,
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
expect(screen.getByLabelText('3 de plus')).toBeInTheDocument();
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
describe('AvatarGroup — roving focus + keyboard hint', () => {
|
|
266
|
+
it('is a single tab stop over interactive avatars (one tabindex=0, rest -1)', () => {
|
|
267
|
+
render(
|
|
268
|
+
<AvatarGroup>
|
|
269
|
+
<Avatar name="Alice" href="/alice" />
|
|
270
|
+
<Avatar name="Bob" href="/bob" />
|
|
271
|
+
<Avatar name="Charlie" href="/charlie" />
|
|
272
|
+
</AvatarGroup>,
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
const alice = screen.getByRole('link', {name: 'Alice'});
|
|
276
|
+
const bob = screen.getByRole('link', {name: 'Bob'});
|
|
277
|
+
const charlie = screen.getByRole('link', {name: 'Charlie'});
|
|
278
|
+
|
|
279
|
+
expect(alice).toHaveAttribute('tabindex', '0');
|
|
280
|
+
expect(bob).toHaveAttribute('tabindex', '-1');
|
|
281
|
+
expect(charlie).toHaveAttribute('tabindex', '-1');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('roves focus with ArrowRight/ArrowLeft across interactive avatars', async () => {
|
|
285
|
+
const user = userEvent.setup();
|
|
286
|
+
render(
|
|
287
|
+
<AvatarGroup>
|
|
288
|
+
<Avatar name="Alice" href="/alice" />
|
|
289
|
+
<Avatar name="Bob" onClick={() => {}} />
|
|
290
|
+
<Avatar name="Charlie" href="/charlie" />
|
|
291
|
+
</AvatarGroup>,
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
const alice = screen.getByRole('link', {name: 'Alice'});
|
|
295
|
+
const bob = screen.getByRole('button', {name: 'Bob'});
|
|
296
|
+
const charlie = screen.getByRole('link', {name: 'Charlie'});
|
|
297
|
+
|
|
298
|
+
alice.focus();
|
|
299
|
+
expect(alice).toHaveFocus();
|
|
300
|
+
|
|
301
|
+
await user.keyboard('{ArrowRight}');
|
|
302
|
+
expect(bob).toHaveFocus();
|
|
303
|
+
expect(bob).toHaveAttribute('tabindex', '0');
|
|
304
|
+
expect(alice).toHaveAttribute('tabindex', '-1');
|
|
305
|
+
|
|
306
|
+
await user.keyboard('{ArrowRight}');
|
|
307
|
+
expect(charlie).toHaveFocus();
|
|
308
|
+
|
|
309
|
+
await user.keyboard('{ArrowLeft}');
|
|
310
|
+
expect(bob).toHaveFocus();
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('includes the overflow button as the last roving item', async () => {
|
|
314
|
+
const user = userEvent.setup();
|
|
315
|
+
render(
|
|
316
|
+
<AvatarGroup>
|
|
317
|
+
<Avatar name="Alice" href="/alice" />
|
|
318
|
+
<AvatarGroupOverflow count={3} onClick={() => {}} />
|
|
319
|
+
</AvatarGroup>,
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
const alice = screen.getByRole('link', {name: 'Alice'});
|
|
323
|
+
const overflow = screen.getByRole('button', {name: '3 more'});
|
|
324
|
+
expect(overflow).toHaveAttribute('data-avatar-item');
|
|
325
|
+
|
|
326
|
+
alice.focus();
|
|
327
|
+
await user.keyboard('{ArrowRight}');
|
|
328
|
+
expect(overflow).toHaveFocus();
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('does NOT rove over a non-avatar button in a status slot', async () => {
|
|
332
|
+
const user = userEvent.setup();
|
|
333
|
+
render(
|
|
334
|
+
<AvatarGroup>
|
|
335
|
+
<Avatar
|
|
336
|
+
name="Alice"
|
|
337
|
+
href="/alice"
|
|
338
|
+
status={<button type="button">badge</button>}
|
|
339
|
+
/>
|
|
340
|
+
<Avatar name="Bob" href="/bob" />
|
|
341
|
+
</AvatarGroup>,
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
const alice = screen.getByRole('link', {name: 'Alice'});
|
|
345
|
+
const bob = screen.getByRole('link', {name: 'Bob'});
|
|
346
|
+
const statusButton = screen.getByRole('button', {name: 'badge'});
|
|
347
|
+
|
|
348
|
+
// The status button carries no data-avatar-item marker.
|
|
349
|
+
expect(statusButton).not.toHaveAttribute('data-avatar-item');
|
|
350
|
+
|
|
351
|
+
alice.focus();
|
|
352
|
+
await user.keyboard('{ArrowRight}');
|
|
353
|
+
// Arrow moves to the next avatar, skipping the nested status button.
|
|
354
|
+
expect(bob).toHaveFocus();
|
|
355
|
+
expect(statusButton).not.toHaveFocus();
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it('attaches an aria-describedby keyboard hint when interactive children exist', () => {
|
|
359
|
+
render(
|
|
360
|
+
<AvatarGroup>
|
|
361
|
+
<Avatar name="Alice" href="/alice" />
|
|
362
|
+
<Avatar name="Bob" href="/bob" />
|
|
363
|
+
</AvatarGroup>,
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
const group = screen.getByRole('group');
|
|
367
|
+
const describedBy = group.getAttribute('aria-describedby');
|
|
368
|
+
expect(describedBy).toBeTruthy();
|
|
369
|
+
const hint = document.getElementById(describedBy!);
|
|
370
|
+
expect(hint).not.toBeNull();
|
|
371
|
+
expect(hint).toHaveTextContent('Use arrow keys to move between avatars');
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('a purely static group has no tab stop and no keyboard hint', () => {
|
|
375
|
+
render(
|
|
376
|
+
<AvatarGroup>
|
|
377
|
+
<Avatar name="Alice" data-testid="alice" />
|
|
378
|
+
<Avatar name="Bob" data-testid="bob" />
|
|
379
|
+
</AvatarGroup>,
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
const group = screen.getByRole('group');
|
|
383
|
+
expect(group).not.toHaveAttribute('aria-describedby');
|
|
384
|
+
// Static avatars are not focusable — no roving tabindex stamped.
|
|
385
|
+
expect(screen.getByTestId('alice')).not.toHaveAttribute('tabindex');
|
|
386
|
+
expect(screen.getByTestId('bob')).not.toHaveAttribute('tabindex');
|
|
227
387
|
});
|
|
228
388
|
});
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
* one AvatarGroupOverflow). The group provides overlap styling via
|
|
12
12
|
* context — no child introspection needed.
|
|
13
13
|
*
|
|
14
|
+
* When the group contains interactive avatars (rendered as links/buttons) or an
|
|
15
|
+
* interactive AvatarGroupOverflow, it becomes a single Tab stop with roving
|
|
16
|
+
* arrow-key focus (via useListFocus with hasRovingTabIndex) and exposes a
|
|
17
|
+
* screen-reader keyboard hint via aria-describedby. A purely static facepile
|
|
18
|
+
* gets neither — it stays a plain non-focusable group.
|
|
19
|
+
*
|
|
14
20
|
* SYNC: When modified, update these files to stay in sync:
|
|
15
21
|
* - /packages/core/src/AvatarGroup/AvatarGroup.doc.mjs (props table, features)
|
|
16
22
|
* - /packages/core/src/AvatarGroup/index.ts (exports if types change)
|
|
@@ -18,14 +24,18 @@
|
|
|
18
24
|
* - /packages/cli/templates/blocks/components/AvatarGroup/ (showcase blocks)
|
|
19
25
|
*/
|
|
20
26
|
|
|
21
|
-
import {useMemo, type ReactNode} from 'react';
|
|
27
|
+
import {useId, useMemo, useState, type ReactNode} from 'react';
|
|
22
28
|
import type {BaseProps} from '../BaseProps';
|
|
23
29
|
import {resolveSize, type AvatarSize} from '../Avatar';
|
|
24
30
|
import * as stylex from '@stylexjs/stylex';
|
|
25
|
-
import {mergeProps} from '../utils';
|
|
31
|
+
import {mergeProps, mergeRefs} from '../utils';
|
|
32
|
+
import {composeEventHandlers} from '../utils/composeEventHandlers';
|
|
26
33
|
import {AvatarGroupContext} from './AvatarGroupContext';
|
|
27
34
|
import {themeProps} from '../utils/themeProps';
|
|
28
35
|
import {useTranslator} from '../i18n';
|
|
36
|
+
import {useListFocus} from '../hooks/useListFocus';
|
|
37
|
+
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
38
|
+
import {VisuallyHidden} from '../VisuallyHidden';
|
|
29
39
|
|
|
30
40
|
const OVERLAP_RATIO = 0.25;
|
|
31
41
|
|
|
@@ -78,6 +88,9 @@ export function AvatarGroup({
|
|
|
78
88
|
size = 'md',
|
|
79
89
|
'data-testid': testId,
|
|
80
90
|
'aria-label': ariaLabelFromProps,
|
|
91
|
+
'aria-describedby': ariaDescribedByFromProps,
|
|
92
|
+
onKeyDown,
|
|
93
|
+
onFocus,
|
|
81
94
|
xstyle,
|
|
82
95
|
className,
|
|
83
96
|
style,
|
|
@@ -94,14 +107,51 @@ export function AvatarGroup({
|
|
|
94
107
|
[size, overlap, numericSize],
|
|
95
108
|
);
|
|
96
109
|
|
|
110
|
+
// The keyboard hint and roving tab stop only make sense once the group has
|
|
111
|
+
// interactive children. Detect their presence (and the writing direction for
|
|
112
|
+
// RTL-correct arrow navigation) from the rendered DOM after commit, matching
|
|
113
|
+
// how the codebase reads direction elsewhere (`getComputedStyle(el).direction`).
|
|
114
|
+
const [hasInteractiveItems, setHasInteractiveItems] = useState(false);
|
|
115
|
+
const [isRtl, setIsRtl] = useState(false);
|
|
116
|
+
|
|
117
|
+
// Single tab stop + roving arrow focus over the group's interactive items.
|
|
118
|
+
// `itemSelector` targets the shared `[data-avatar-item]` marker stamped on
|
|
119
|
+
// interactive avatars (their rendered <a>/<button>) and on the overflow
|
|
120
|
+
// button — NOT a tag/role selector — so roving never catches a nested button
|
|
121
|
+
// inside a custom status/badge slot (O5).
|
|
122
|
+
const {listRef, handleKeyDown, handleFocus} = useListFocus<HTMLDivElement>({
|
|
123
|
+
itemSelector: '[data-avatar-item]',
|
|
124
|
+
orientation: 'horizontal',
|
|
125
|
+
hasRovingTabIndex: true,
|
|
126
|
+
isRtl,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
useIsomorphicLayoutEffect(() => {
|
|
130
|
+
const root = listRef.current;
|
|
131
|
+
if (!root) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
setHasInteractiveItems(root.querySelector('[data-avatar-item]') != null);
|
|
135
|
+
setIsRtl(getComputedStyle(root).direction === 'rtl');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const hintId = useId();
|
|
139
|
+
const describedBy =
|
|
140
|
+
[ariaDescribedByFromProps, hasInteractiveItems ? hintId : null]
|
|
141
|
+
.filter(Boolean)
|
|
142
|
+
.join(' ') || undefined;
|
|
143
|
+
|
|
97
144
|
return (
|
|
98
145
|
<AvatarGroupContext value={contextValue}>
|
|
99
146
|
<div
|
|
100
147
|
{...props}
|
|
101
|
-
ref={ref}
|
|
148
|
+
ref={mergeRefs(ref, listRef)}
|
|
102
149
|
role="group"
|
|
103
150
|
aria-label={ariaLabel}
|
|
151
|
+
aria-describedby={describedBy}
|
|
104
152
|
data-testid={testId}
|
|
153
|
+
onKeyDown={composeEventHandlers(onKeyDown, handleKeyDown)}
|
|
154
|
+
onFocus={composeEventHandlers(onFocus, handleFocus)}
|
|
105
155
|
{...mergeProps(
|
|
106
156
|
themeProps('avatar-group', {size}),
|
|
107
157
|
stylex.props(styles.root, xstyle),
|
|
@@ -109,6 +159,11 @@ export function AvatarGroup({
|
|
|
109
159
|
style,
|
|
110
160
|
)}>
|
|
111
161
|
{children}
|
|
162
|
+
{hasInteractiveItems && (
|
|
163
|
+
<VisuallyHidden id={hintId}>
|
|
164
|
+
{t('@astryx.avatarGroup.keyboardHint')}
|
|
165
|
+
</VisuallyHidden>
|
|
166
|
+
)}
|
|
112
167
|
</div>
|
|
113
168
|
</AvatarGroupContext>
|
|
114
169
|
);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @file AvatarGroupOverflow.tsx
|
|
6
|
-
* @input Uses React, StyleX, AvatarGroupContext
|
|
6
|
+
* @input Uses React, StyleX, AvatarGroupContext, i18n (useTranslator)
|
|
7
7
|
* @output Exports AvatarGroupOverflow for overflow indicator
|
|
8
8
|
* @position Slot component used inside AvatarGroup
|
|
9
9
|
*
|
|
@@ -26,6 +26,7 @@ import {mergeProps} from '../utils';
|
|
|
26
26
|
import {useAvatarGroup} from './AvatarGroupContext';
|
|
27
27
|
import type {BaseProps} from '../BaseProps';
|
|
28
28
|
import {themeProps} from '../utils/themeProps';
|
|
29
|
+
import {useTranslator} from '../i18n';
|
|
29
30
|
|
|
30
31
|
const BORDER_WIDTH = 2;
|
|
31
32
|
const OVERFLOW_FONT_RATIO = 0.35;
|
|
@@ -150,11 +151,12 @@ export function AvatarGroupOverflow({
|
|
|
150
151
|
style,
|
|
151
152
|
...rest
|
|
152
153
|
}: AvatarGroupOverflowProps): ReactNode {
|
|
154
|
+
const t = useTranslator();
|
|
153
155
|
const group = useAvatarGroup();
|
|
154
156
|
const numericSize = group?.numericSize ?? 36;
|
|
155
157
|
const overlap = group?.overlap ?? 0;
|
|
156
158
|
|
|
157
|
-
const label =
|
|
159
|
+
const label = t('@astryx.avatarGroup.overflow', {count});
|
|
158
160
|
const content = children ?? `+${count}`;
|
|
159
161
|
|
|
160
162
|
if (onClick) {
|
|
@@ -165,6 +167,7 @@ export function AvatarGroupOverflow({
|
|
|
165
167
|
onClick={onClick}
|
|
166
168
|
{...rest}
|
|
167
169
|
aria-label={label}
|
|
170
|
+
data-avatar-item=""
|
|
168
171
|
{...mergeProps(
|
|
169
172
|
themeProps('avatar-group-overflow'),
|
|
170
173
|
stylex.props(
|
package/src/Banner/Banner.tsx
CHANGED
|
@@ -294,14 +294,14 @@ const styles = stylex.create({
|
|
|
294
294
|
backgroundColor: colorVars['--color-background-card'],
|
|
295
295
|
paddingBlock: spacingVars['--spacing-3'],
|
|
296
296
|
paddingInline: spacingVars['--spacing-4'],
|
|
297
|
-
|
|
298
|
-
|
|
297
|
+
borderInlineStartWidth: borderVars['--border-width'],
|
|
298
|
+
borderInlineEndWidth: borderVars['--border-width'],
|
|
299
299
|
borderBottomWidth: borderVars['--border-width'],
|
|
300
|
-
|
|
301
|
-
|
|
300
|
+
borderInlineStartStyle: 'solid',
|
|
301
|
+
borderInlineEndStyle: 'solid',
|
|
302
302
|
borderBottomStyle: 'solid',
|
|
303
|
-
|
|
304
|
-
|
|
303
|
+
borderInlineStartColor: colorVars['--color-border'],
|
|
304
|
+
borderInlineEndColor: colorVars['--color-border'],
|
|
305
305
|
borderBottomColor: colorVars['--color-border'],
|
|
306
306
|
},
|
|
307
307
|
contentAreaCard: {
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
import {
|
|
60
60
|
MENU_ITEM_ROLES,
|
|
61
61
|
MENU_ITEM_SELECTOR,
|
|
62
|
+
MENU_BOUNDARY_SELECTOR,
|
|
62
63
|
} from '../DropdownMenu/menuItemRoles';
|
|
63
64
|
import type {DropdownMenuOption} from '../DropdownMenu/DropdownMenu';
|
|
64
65
|
|
|
@@ -515,21 +516,15 @@ function BreadcrumbMenuTrigger({
|
|
|
515
516
|
handleKeyDown: listNavKeyDown,
|
|
516
517
|
focusFirst,
|
|
517
518
|
focusItem,
|
|
519
|
+
ownsEvent,
|
|
520
|
+
getItems: getMenuItems,
|
|
518
521
|
} = useListFocus<HTMLDivElement>({
|
|
519
522
|
itemSelector: MENU_ITEM_SELECTOR,
|
|
523
|
+
boundarySelector: MENU_BOUNDARY_SELECTOR,
|
|
520
524
|
wrap: false,
|
|
521
525
|
onEscape: closeMenu,
|
|
522
526
|
});
|
|
523
527
|
|
|
524
|
-
const getMenuItems = useCallback(
|
|
525
|
-
(): HTMLElement[] =>
|
|
526
|
-
listRef.current
|
|
527
|
-
? Array.from(
|
|
528
|
-
listRef.current.querySelectorAll<HTMLElement>(MENU_ITEM_SELECTOR),
|
|
529
|
-
)
|
|
530
|
-
: [],
|
|
531
|
-
[listRef],
|
|
532
|
-
);
|
|
533
528
|
const typeahead = useTypeahead({
|
|
534
529
|
getItemLabels: () => getMenuItems().map(el => el.textContent),
|
|
535
530
|
onMatch: focusItem,
|
|
@@ -542,6 +537,11 @@ function BreadcrumbMenuTrigger({
|
|
|
542
537
|
|
|
543
538
|
const listKeyDown = useCallback(
|
|
544
539
|
(e: React.KeyboardEvent) => {
|
|
540
|
+
// A submenu flyout renders inline inside this menu; its key events bubble
|
|
541
|
+
// up here. Let that level own them — only handle events from this level.
|
|
542
|
+
if (!ownsEvent(e)) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
545
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
546
546
|
e.preventDefault();
|
|
547
547
|
const focused = document.activeElement as HTMLElement | null;
|
|
@@ -564,7 +564,7 @@ function BreadcrumbMenuTrigger({
|
|
|
564
564
|
}
|
|
565
565
|
listNavKeyDown(e);
|
|
566
566
|
},
|
|
567
|
-
[listNavKeyDown, closeMenu, typeahead],
|
|
567
|
+
[listNavKeyDown, closeMenu, typeahead, ownsEvent],
|
|
568
568
|
);
|
|
569
569
|
|
|
570
570
|
const openAndFocus = useCallback(() => {
|
|
@@ -519,7 +519,7 @@ describe('BreadcrumbItem menu', () => {
|
|
|
519
519
|
<BreadcrumbItem
|
|
520
520
|
menu={
|
|
521
521
|
<BreadcrumbMenuRadioGroup
|
|
522
|
-
|
|
522
|
+
label="Sort by"
|
|
523
523
|
value="name"
|
|
524
524
|
onChange={onChange}>
|
|
525
525
|
<BreadcrumbMenuRadioItem value="name" label="Name" />
|
|
@@ -589,6 +589,57 @@ describe('BreadcrumbItem menu', () => {
|
|
|
589
589
|
).toHaveFocus();
|
|
590
590
|
});
|
|
591
591
|
|
|
592
|
+
it('renders a submenu from a nested items array and keyboard-reaches an item after it', async () => {
|
|
593
|
+
// Breadcrumb menus reuse the DropdownMenu item pipeline, so a nested
|
|
594
|
+
// `items` array becomes a submenu. The inline flyout must not pollute the
|
|
595
|
+
// breadcrumb menu's roving order — an item after the submenu row stays
|
|
596
|
+
// keyboard-reachable.
|
|
597
|
+
const onDelete = vi.fn();
|
|
598
|
+
render(
|
|
599
|
+
<Breadcrumbs>
|
|
600
|
+
<BreadcrumbItem
|
|
601
|
+
menu={[
|
|
602
|
+
{label: 'Rename', onClick: vi.fn()},
|
|
603
|
+
{
|
|
604
|
+
label: 'Move to',
|
|
605
|
+
items: [
|
|
606
|
+
{label: 'Folder A', onClick: vi.fn()},
|
|
607
|
+
{label: 'Folder B', onClick: vi.fn()},
|
|
608
|
+
],
|
|
609
|
+
},
|
|
610
|
+
{type: 'divider'},
|
|
611
|
+
{label: 'Delete', onClick: onDelete},
|
|
612
|
+
]}>
|
|
613
|
+
Teams
|
|
614
|
+
</BreadcrumbItem>
|
|
615
|
+
<BreadcrumbItem isCurrent>Overview</BreadcrumbItem>
|
|
616
|
+
</Breadcrumbs>,
|
|
617
|
+
);
|
|
618
|
+
const trigger = screen.getByRole('button', {name: 'Teams'});
|
|
619
|
+
trigger.focus();
|
|
620
|
+
fireEvent.keyDown(trigger, {key: 'ArrowDown'});
|
|
621
|
+
// Two role="menu" exist (the breadcrumb menu + the inline submenu flyout);
|
|
622
|
+
// the breadcrumb menu is the first in DOM order.
|
|
623
|
+
const menu = screen.getAllByRole('menu', {hidden: true})[0];
|
|
624
|
+
const submenuTrigger = screen.getByRole('menuitem', {
|
|
625
|
+
name: /Move to/,
|
|
626
|
+
hidden: true,
|
|
627
|
+
});
|
|
628
|
+
expect(submenuTrigger).toHaveAttribute('aria-haspopup', 'menu');
|
|
629
|
+
await waitFor(() => {
|
|
630
|
+
expect(
|
|
631
|
+
screen.getByRole('menuitem', {name: 'Rename', hidden: true}),
|
|
632
|
+
).toHaveFocus();
|
|
633
|
+
});
|
|
634
|
+
// Rename → Move to → Delete, one step per press.
|
|
635
|
+
fireEvent.keyDown(menu, {key: 'ArrowDown'});
|
|
636
|
+
expect(submenuTrigger).toHaveFocus();
|
|
637
|
+
fireEvent.keyDown(menu, {key: 'ArrowDown'});
|
|
638
|
+
expect(
|
|
639
|
+
screen.getByRole('menuitem', {name: 'Delete', hidden: true}),
|
|
640
|
+
).toHaveFocus();
|
|
641
|
+
});
|
|
642
|
+
|
|
592
643
|
it('allows menu together with isCurrent (both aria-current and aria-haspopup)', () => {
|
|
593
644
|
render(
|
|
594
645
|
<Breadcrumbs>
|
package/src/Breadcrumbs/index.ts
CHANGED
|
@@ -35,6 +35,10 @@ export {
|
|
|
35
35
|
DropdownMenuRadioItem as BreadcrumbMenuRadioItem,
|
|
36
36
|
type DropdownMenuRadioItemProps as BreadcrumbMenuRadioItemProps,
|
|
37
37
|
} from '../DropdownMenu/DropdownMenuRadioItem';
|
|
38
|
+
export {
|
|
39
|
+
DropdownMenuSubMenu as BreadcrumbMenuSubMenu,
|
|
40
|
+
type DropdownMenuSubMenuProps as BreadcrumbMenuSubMenuProps,
|
|
41
|
+
} from '../DropdownMenu/DropdownMenuSubMenu';
|
|
38
42
|
export type {
|
|
39
43
|
DropdownMenuOption as BreadcrumbMenuOption,
|
|
40
44
|
DropdownMenuItemData as BreadcrumbMenuItemData,
|
|
@@ -163,8 +163,6 @@ export const docs = {
|
|
|
163
163
|
],
|
|
164
164
|
vars: [
|
|
165
165
|
{name: '--_button-radius', description: 'Border radius', default: 'var(--radius-element)', private: true},
|
|
166
|
-
{name: '--button-press-scale', description: 'Active press transform', default: 'scale(0.98)'},
|
|
167
|
-
{name: '--button-disabled-opacity', description: 'Opacity when disabled', default: '0.5'},
|
|
168
166
|
{name: '--button-focus-offset', description: 'Focus ring outline offset', default: '3px'},
|
|
169
167
|
{name: '--button-icon-only-aspect', description: 'Aspect ratio for icon-only buttons', default: '1 / 1'},
|
|
170
168
|
],
|
|
@@ -247,8 +245,6 @@ export const docsZh = {
|
|
|
247
245
|
],
|
|
248
246
|
vars: [
|
|
249
247
|
{name: '--_button-radius', description: '圆角半径', default: 'var(--radius-element)', private: true},
|
|
250
|
-
{name: '--button-press-scale', description: '按下时的变换', default: 'scale(0.98)'},
|
|
251
|
-
{name: '--button-disabled-opacity', description: '禁用时的不透明度', default: '0.5'},
|
|
252
248
|
{name: '--button-focus-offset', description: '焦点环轮廓偏移', default: '3px'},
|
|
253
249
|
{name: '--button-icon-only-aspect', description: '纯图标按钮的宽高比', default: '1 / 1'},
|
|
254
250
|
],
|
|
@@ -14,6 +14,7 @@ import {render, screen, fireEvent, act} from '@testing-library/react';
|
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import {Button} from './Button';
|
|
16
16
|
import {Badge} from '../Badge/Badge';
|
|
17
|
+
import {InternationalizationProvider} from '../i18n';
|
|
17
18
|
|
|
18
19
|
describe('Button', () => {
|
|
19
20
|
it('renders label as visible text', () => {
|
|
@@ -446,6 +447,21 @@ describe('Button', () => {
|
|
|
446
447
|
expect(liveRegion).toHaveTextContent('Loading');
|
|
447
448
|
});
|
|
448
449
|
|
|
450
|
+
it('localizes the loading announcement through the i18n catalog', () => {
|
|
451
|
+
render(
|
|
452
|
+
<InternationalizationProvider
|
|
453
|
+
locale="fr"
|
|
454
|
+
overrides={{fr: {'@astryx.button.loading': 'Chargement'}}}>
|
|
455
|
+
<Button label="Submit" isLoading />
|
|
456
|
+
</InternationalizationProvider>,
|
|
457
|
+
);
|
|
458
|
+
const button = screen.getByRole('button');
|
|
459
|
+
// The Spinner also has role="status", so grab the live region explicitly.
|
|
460
|
+
const regions = button.querySelectorAll('[role="status"]');
|
|
461
|
+
const liveRegion = regions[regions.length - 1];
|
|
462
|
+
expect(liveRegion).toHaveTextContent('Chargement');
|
|
463
|
+
});
|
|
464
|
+
|
|
449
465
|
describe('elevation', () => {
|
|
450
466
|
it('renders a distinct class for each elevation level', () => {
|
|
451
467
|
const classFor = (elevation: 'none' | 'low' | 'med' | 'high') => {
|
package/src/Button/Button.tsx
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file Button.tsx
|
|
7
|
-
* @input Uses React, ButtonHTMLAttributes, ReactNode
|
|
7
|
+
* @input Uses React, ButtonHTMLAttributes, ReactNode, i18n (useTranslator)
|
|
8
8
|
* @output Exports Button component, ButtonProps, ButtonVariant types
|
|
9
9
|
* @position Core implementation; consumed by index.ts, tested by Button.test.tsx
|
|
10
10
|
*
|
|
@@ -45,6 +45,7 @@ import {mergeProps, mergeRefs} from '../utils';
|
|
|
45
45
|
import {useLinkComponent} from '../Link/useLinkComponent';
|
|
46
46
|
import type {LinkComponentType} from '../Link/types';
|
|
47
47
|
import {themeProps} from '../utils/themeProps';
|
|
48
|
+
import {useTranslator} from '../i18n';
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* Base button styles
|
|
@@ -449,8 +450,8 @@ const loadingStyles = stylex.create({
|
|
|
449
450
|
spinnerOverlay: {
|
|
450
451
|
position: 'absolute',
|
|
451
452
|
top: 0,
|
|
452
|
-
|
|
453
|
-
|
|
453
|
+
insetInlineStart: 0,
|
|
454
|
+
insetInlineEnd: 0,
|
|
454
455
|
bottom: 0,
|
|
455
456
|
display: 'grid',
|
|
456
457
|
placeItems: 'center',
|
|
@@ -611,6 +612,7 @@ export function Button({
|
|
|
611
612
|
ref,
|
|
612
613
|
...props
|
|
613
614
|
}: ButtonProps): ReactNode {
|
|
615
|
+
const t = useTranslator();
|
|
614
616
|
const size = useSize(sizeProp, 'md');
|
|
615
617
|
const buttonGroup = useButtonGroup();
|
|
616
618
|
|
|
@@ -760,7 +762,7 @@ export function Button({
|
|
|
760
762
|
</span>
|
|
761
763
|
{/* Live region for loading state announcements */}
|
|
762
764
|
<VisuallyHidden role="status" aria-live="polite">
|
|
763
|
-
{isLoadingState ? '
|
|
765
|
+
{isLoadingState ? t('@astryx.button.loading') : ''}
|
|
764
766
|
</VisuallyHidden>
|
|
765
767
|
</>
|
|
766
768
|
);
|