@astryxdesign/core 0.1.8 → 0.1.9-canary.08c278e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +100 -0
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +6 -2
- package/dist/AppShell/AppShellMobileContext.d.ts +8 -0
- package/dist/AppShell/AppShellMobileContext.d.ts.map +1 -1
- package/dist/Avatar/Avatar.d.ts +53 -3
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +203 -49
- package/dist/Avatar/AvatarStatusDot.d.ts +33 -5
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- package/dist/Avatar/AvatarStatusDot.js +144 -19
- package/dist/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.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +1 -0
- package/dist/Banner/Banner.d.ts +9 -1
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +33 -4
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +31 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +208 -6
- package/dist/Breadcrumbs/index.d.ts +5 -0
- package/dist/Breadcrumbs/index.d.ts.map +1 -1
- package/dist/Breadcrumbs/index.js +9 -1
- package/dist/Button/Button.d.ts +8 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +33 -4
- package/dist/ButtonGroup/ButtonGroup.d.ts +9 -1
- package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
- package/dist/ButtonGroup/ButtonGroup.js +30 -1
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +30 -2
- package/dist/Calendar/dayCellUtils.js +1 -1
- package/dist/Card/Card.d.ts +8 -2
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +28 -2
- package/dist/Carousel/Carousel.d.ts +4 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +24 -4
- package/dist/Chat/ChatComposer.d.ts +8 -0
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +46 -7
- package/dist/Chat/ChatComposerDrawer.d.ts +2 -0
- package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
- package/dist/Chat/ChatComposerDrawer.js +11 -1
- package/dist/Chat/ChatComposerInput.d.ts +20 -3
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +36 -4
- package/dist/Chat/ChatContext.d.ts +33 -0
- package/dist/Chat/ChatContext.d.ts.map +1 -1
- package/dist/Chat/ChatContext.js +16 -2
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +1 -1
- package/dist/Chat/ChatLayout.d.ts.map +1 -1
- package/dist/Chat/ChatLayout.js +4 -4
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +4 -4
- package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.js +7 -1
- package/dist/Chat/ChatToolCalls.d.ts +5 -1
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +18 -9
- package/dist/Chat/index.d.ts +2 -1
- package/dist/Chat/index.d.ts.map +1 -1
- package/dist/Chat/index.js +1 -1
- package/dist/Chat/useChatStreamScroll.d.ts +2 -1
- package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
- package/dist/Chat/useChatStreamScroll.js +22 -8
- package/dist/Chat/useSpeechRecognition.d.ts +0 -1
- package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.js +1 -1
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +2 -2
- package/dist/CheckboxInput/CheckboxInput.js +1 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts +20 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +11 -1
- package/dist/ClickableCard/ClickableCard.d.ts +9 -2
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +5 -2
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +9 -2
- package/dist/CommandPalette/CommandPalette.d.ts +1 -1
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +3 -1
- package/dist/CommandPalette/CommandPaletteGroup.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteGroup.js +9 -2
- package/dist/CommandPalette/CommandPaletteInput.d.ts +7 -1
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +6 -1
- package/dist/CommandPalette/CommandPaletteItem.js +1 -1
- package/dist/DateInput/DateInput.d.ts +55 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +28 -2
- package/dist/DateInput/index.d.ts +1 -1
- package/dist/DateInput/index.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +3 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +18 -3
- package/dist/Dialog/Dialog.d.ts +3 -0
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +57 -6
- package/dist/Dialog/DialogContext.d.ts +7 -0
- package/dist/Dialog/DialogContext.d.ts.map +1 -1
- package/dist/Dialog/DialogContext.js +2 -2
- package/dist/Dialog/DialogHeader.d.ts +5 -2
- package/dist/Dialog/DialogHeader.d.ts.map +1 -1
- package/dist/Dialog/DialogHeader.js +6 -1
- package/dist/Divider/Divider.js +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -2
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +1 -2
- package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +1 -2
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +1 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +2 -3
- package/dist/Field/FieldLabel.d.ts +1 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +43 -16
- package/dist/FieldStatus/FieldStatus.d.ts +15 -0
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +58 -6
- package/dist/FileInput/FileInput.d.ts +9 -2
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +42 -20
- package/dist/HoverCard/HoverCard.d.ts +9 -1
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +2 -0
- package/dist/HoverCard/useHoverCard.d.ts +8 -0
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +7 -2
- package/dist/Icon/Icon.d.ts +7 -2
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Item/Item.d.ts +6 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +22 -1
- package/dist/Layer/useLayer.d.ts +6 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +2 -0
- package/dist/Lightbox/Lightbox.js +4 -4
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +6 -1
- package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
- package/dist/MobileNav/MobileNavToggle.js +4 -0
- package/dist/MultiSelector/MultiSelector.d.ts +9 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +41 -12
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +16 -0
- package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
- package/dist/NumberInput/NumberInput.d.ts +9 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +8 -1
- package/dist/Outline/Outline.d.ts +0 -1
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +0 -1
- package/dist/OverflowList/OverflowList.d.ts +20 -3
- package/dist/OverflowList/OverflowList.d.ts.map +1 -1
- package/dist/OverflowList/OverflowList.js +29 -4
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +11 -3
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +3 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +3 -9
- package/dist/PowerSearch/PowerSearch.d.ts +9 -2
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +2 -0
- package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
- package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.d.ts +9 -2
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +16 -13
- package/dist/Selector/Selector.d.ts +8 -0
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +7 -3
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +16 -0
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +21 -8
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +19 -2
- package/dist/Stack/stack.stylex.d.ts +9 -9
- package/dist/TabList/Tab.js +2 -2
- package/dist/TabList/TabMenu.js +1 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +3 -2
- package/dist/Table/TableCell.js +3 -3
- package/dist/Table/TableHeaderCell.js +3 -3
- package/dist/Table/index.d.ts +2 -0
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +1 -0
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/rowStatus/index.d.ts +3 -0
- package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -0
- package/dist/Table/plugins/rowStatus/index.js +3 -0
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +60 -0
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -0
- package/dist/Table/plugins/rowStatus/useTableRowStatus.js +145 -0
- package/dist/Table/plugins/selection/useTableSelection.d.ts +13 -0
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +4 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.d.ts +16 -0
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +87 -0
- package/dist/Table/plugins/tree/useTableTreeState.d.ts +6 -0
- package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeState.js +22 -1
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +5 -3
- package/dist/TextArea/TextArea.d.ts +9 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +2 -0
- package/dist/TextInput/TextInput.d.ts +9 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +6 -1
- package/dist/Thumbnail/Thumbnail.d.ts +26 -5
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +97 -54
- package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +9 -0
- package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +1 -0
- package/dist/Thumbnail/thumbnail.markers.stylex.js +14 -0
- package/dist/TimeInput/TimeInput.d.ts +9 -2
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +17 -4
- package/dist/Timestamp/Timestamp.d.ts +3 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +8 -6
- package/dist/Toast/useToast.d.ts.map +1 -1
- package/dist/Toast/useToast.js +2 -5
- package/dist/ToggleButton/ToggleButtonGroup.d.ts +0 -1
- package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButtonGroup.js +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts +10 -3
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +18 -4
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +18 -8
- package/dist/TopNav/TopNavMegaMenu.js +10 -4
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +9 -1
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +8 -1
- package/dist/TopNav/TopNavMenu.d.ts +2 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +68 -6
- package/dist/TreeList/TreeList.d.ts +12 -3
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +2 -0
- package/dist/TreeList/TreeListBranches.d.ts +5 -0
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +10 -4
- package/dist/TreeList/TreeListItem.d.ts +8 -2
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +28 -8
- package/dist/TreeList/TreeListTypes.d.ts +25 -1
- package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
- package/dist/TreeList/index.d.ts +2 -2
- package/dist/TreeList/index.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +1 -1
- package/dist/Typeahead/Typeahead.d.ts +9 -2
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +2 -0
- package/dist/astryx.css +41 -31
- package/dist/astryx.umd.js +51 -51
- package/dist/astryx.umd.js.map +4 -4
- package/dist/authoring/doc.d.ts.map +1 -1
- package/dist/docs-types.d.ts +8 -0
- package/dist/docs-types.d.ts.map +1 -1
- package/dist/hooks/computeOverflow.d.ts +47 -0
- package/dist/hooks/computeOverflow.d.ts.map +1 -0
- package/dist/hooks/computeOverflow.js +213 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -1
- package/dist/hooks/isRtlElement.d.ts +18 -0
- package/dist/hooks/isRtlElement.d.ts.map +1 -0
- package/dist/hooks/isRtlElement.js +27 -0
- package/dist/hooks/useDevWarning.d.ts +18 -0
- package/dist/hooks/useDevWarning.d.ts.map +1 -0
- package/dist/hooks/useDevWarning.js +49 -0
- package/dist/hooks/useGridFocus.d.ts +6 -1
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +12 -9
- package/dist/hooks/useListFocus.d.ts +6 -1
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +12 -4
- package/dist/hooks/useOverflow.d.ts +19 -0
- package/dist/hooks/useOverflow.d.ts.map +1 -1
- package/dist/hooks/useOverflow.js +36 -25
- package/dist/i18n/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/resolve.d.ts.map +1 -1
- package/dist/i18n/resolve.js +7 -18
- 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/Theme.d.ts.map +1 -1
- package/dist/theme/Theme.js +2 -7
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +13 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +51 -0
- package/dist/theme/hct.d.ts +0 -1
- package/dist/theme/hct.d.ts.map +1 -1
- package/dist/theme/hct.js +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.js +2 -1
- package/dist/utils/devWarning.d.ts +42 -0
- package/dist/utils/devWarning.d.ts.map +1 -0
- package/dist/utils/devWarning.js +88 -0
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -2
- package/dist/utils/plainDate.d.ts +30 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +53 -0
- package/dist/utils/types.d.ts +13 -0
- package/dist/utils/types.d.ts.map +1 -1
- package/locales/en.json +32 -0
- package/locales/fr-FR.json +14 -0
- package/locales/pseudo.json +24 -0
- package/package.json +1 -1
- package/src/AppShell/AppShell.tsx +6 -0
- package/src/AppShell/AppShellMobileContext.tsx +8 -0
- package/src/AppShell/useAppShellMobile.doc.mjs +8 -0
- package/src/Avatar/Avatar.doc.mjs +60 -3
- package/src/Avatar/Avatar.test.tsx +281 -1
- package/src/Avatar/Avatar.tsx +324 -64
- package/src/Avatar/AvatarStatusDot.doc.mjs +23 -12
- package/src/Avatar/AvatarStatusDot.test.tsx +284 -0
- package/src/Avatar/AvatarStatusDot.tsx +178 -21
- package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
- package/src/AvatarGroup/AvatarGroup.test.tsx +125 -0
- package/src/AvatarGroup/AvatarGroup.tsx +58 -3
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +1 -0
- package/src/Banner/Banner.doc.mjs +9 -0
- package/src/Banner/Banner.test.tsx +30 -0
- package/src/Banner/Banner.tsx +53 -9
- package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +26 -0
- package/src/Breadcrumbs/BreadcrumbItem.tsx +333 -14
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -0
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +284 -2
- package/src/Breadcrumbs/index.ts +27 -0
- package/src/Button/Button.doc.mjs +9 -0
- package/src/Button/Button.test.tsx +49 -0
- package/src/Button/Button.tsx +27 -3
- package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -0
- package/src/ButtonGroup/ButtonGroup.test.tsx +37 -0
- package/src/ButtonGroup/ButtonGroup.tsx +32 -0
- package/src/Calendar/Calendar.doc.mjs +12 -1
- package/src/Calendar/Calendar.test.tsx +193 -0
- package/src/Calendar/Calendar.tsx +38 -16
- package/src/Calendar/dayCellUtils.test.ts +5 -0
- package/src/Calendar/dayCellUtils.ts +1 -1
- package/src/Card/Card.doc.mjs +9 -0
- package/src/Card/Card.test.tsx +21 -3
- package/src/Card/Card.tsx +35 -2
- package/src/Carousel/Carousel.doc.mjs +1 -0
- package/src/Carousel/Carousel.test.tsx +53 -0
- package/src/Carousel/Carousel.tsx +34 -4
- package/src/Chat/ChatComposer.doc.mjs +12 -3
- package/src/Chat/ChatComposer.test.tsx +115 -0
- package/src/Chat/ChatComposer.tsx +73 -9
- package/src/Chat/ChatComposerDrawer.test.tsx +61 -0
- package/src/Chat/ChatComposerDrawer.tsx +11 -1
- package/src/Chat/ChatComposerInput.doc.mjs +7 -0
- package/src/Chat/ChatComposerInput.test.tsx +103 -0
- package/src/Chat/ChatComposerInput.tsx +51 -5
- package/src/Chat/ChatContext.tsx +37 -10
- package/src/Chat/ChatDictationButton.tsx +4 -1
- package/src/Chat/ChatLayout.tsx +7 -5
- package/src/Chat/ChatLayoutScrollButton.tsx +7 -2
- package/src/Chat/ChatMessageMetadata.tsx +1 -2
- package/src/Chat/ChatSendButton.tsx +11 -1
- package/src/Chat/ChatToolCalls.test.tsx +64 -0
- package/src/Chat/ChatToolCalls.tsx +25 -4
- package/src/Chat/index.ts +5 -1
- package/src/Chat/useChatStreamScroll.test.tsx +49 -0
- package/src/Chat/useChatStreamScroll.ts +27 -10
- package/src/Chat/useSpeechRecognition.ts +1 -1
- package/src/Chat/useTriggerMenu.tsx +4 -2
- package/src/CheckboxInput/CheckboxInput.test.tsx +32 -1
- package/src/CheckboxInput/CheckboxInput.tsx +1 -1
- package/src/CheckboxList/CheckboxList.test.tsx +81 -3
- package/src/CheckboxList/CheckboxListItem.doc.mjs +33 -5
- package/src/CheckboxList/CheckboxListItem.tsx +41 -5
- package/src/ClickableCard/ClickableCard.doc.mjs +2 -0
- package/src/ClickableCard/ClickableCard.test.tsx +34 -0
- package/src/ClickableCard/ClickableCard.tsx +13 -3
- package/src/CodeBlock/CodeBlock.test.tsx +56 -0
- package/src/CodeBlock/CodeBlock.tsx +10 -2
- package/src/CommandPalette/CommandPalette.doc.mjs +1 -0
- package/src/CommandPalette/CommandPalette.tsx +3 -1
- package/src/CommandPalette/CommandPaletteGroup.test.tsx +71 -0
- package/src/CommandPalette/CommandPaletteGroup.tsx +12 -1
- package/src/CommandPalette/CommandPaletteInput.doc.mjs +26 -9
- package/src/CommandPalette/CommandPaletteInput.test.tsx +34 -0
- package/src/CommandPalette/CommandPaletteInput.tsx +11 -0
- package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
- package/src/ContextMenu/ContextMenu.test.tsx +193 -0
- package/src/DateInput/DateInput.doc.mjs +31 -0
- package/src/DateInput/DateInput.test.tsx +131 -0
- package/src/DateInput/DateInput.tsx +78 -3
- package/src/DateInput/index.ts +1 -0
- package/src/DateRangeInput/DateRangeInput.doc.mjs +8 -0
- package/src/DateRangeInput/DateRangeInput.test.tsx +23 -0
- package/src/DateRangeInput/DateRangeInput.tsx +13 -3
- package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -1
- package/src/DateTimeInput/DateTimeInput.test.tsx +147 -0
- package/src/DateTimeInput/DateTimeInput.tsx +42 -18
- package/src/Dialog/Dialog.doc.mjs +2 -2
- package/src/Dialog/Dialog.test.tsx +77 -4
- package/src/Dialog/Dialog.tsx +89 -5
- package/src/Dialog/DialogContext.ts +9 -2
- package/src/Dialog/DialogHeader.doc.mjs +2 -2
- package/src/Dialog/DialogHeader.tsx +9 -2
- package/src/Divider/Divider.tsx +2 -2
- package/src/DropdownMenu/DropdownMenu.test.tsx +169 -0
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -2
- package/src/DropdownMenu/DropdownMenuItem.tsx +1 -1
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +1 -2
- package/src/Field/Field.test.tsx +57 -12
- package/src/Field/Field.tsx +6 -5
- package/src/Field/FieldLabel.tsx +9 -1
- package/src/FieldStatus/FieldStatus.doc.mjs +17 -5
- package/src/FieldStatus/FieldStatus.test.tsx +150 -40
- package/src/FieldStatus/FieldStatus.tsx +63 -5
- package/src/FileInput/FileInput.doc.mjs +17 -2
- package/src/FileInput/FileInput.test.tsx +135 -12
- package/src/FileInput/FileInput.tsx +53 -28
- package/src/HoverCard/HoverCard.doc.mjs +13 -0
- package/src/HoverCard/HoverCard.test.tsx +21 -2
- package/src/HoverCard/HoverCard.tsx +11 -0
- package/src/HoverCard/useHoverCard.doc.mjs +2 -0
- package/src/HoverCard/useHoverCard.tsx +24 -2
- package/src/Icon/Icon.doc.mjs +3 -2
- package/src/Icon/Icon.tsx +7 -2
- package/src/IconButton/IconButton.doc.mjs +8 -0
- package/src/IconButton/IconButton.test.tsx +15 -18
- package/src/Item/Item.test.tsx +40 -18
- package/src/Item/Item.tsx +38 -2
- package/src/Layer/useLayer.tsx +8 -0
- package/src/Lightbox/Lightbox.tsx +4 -4
- package/src/List/List.test.tsx +9 -8
- package/src/MobileNav/MobileNav.tsx +12 -1
- package/src/MobileNav/MobileNavToggle.test.tsx +116 -0
- package/src/MobileNav/MobileNavToggle.tsx +9 -1
- package/src/MultiSelector/MultiSelector.doc.mjs +13 -2
- package/src/MultiSelector/MultiSelector.test.tsx +195 -3
- package/src/MultiSelector/MultiSelector.tsx +65 -12
- package/src/MultiSelector/hooks.ts +17 -0
- package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
- package/src/NumberInput/NumberInput.doc.mjs +15 -0
- package/src/NumberInput/NumberInput.test.tsx +82 -7
- package/src/NumberInput/NumberInput.tsx +21 -4
- package/src/Outline/Outline.tsx +0 -1
- package/src/OverflowList/OverflowList.doc.mjs +39 -6
- package/src/OverflowList/OverflowList.test.tsx +111 -0
- package/src/OverflowList/OverflowList.tsx +48 -8
- package/src/Pagination/Pagination.tsx +11 -3
- package/src/Popover/Popover.tsx +7 -4
- package/src/Popover/usePopover.tsx +9 -13
- package/src/PowerSearch/PowerSearch.doc.mjs +29 -0
- package/src/PowerSearch/PowerSearch.test.tsx +43 -0
- package/src/PowerSearch/PowerSearch.tsx +10 -1
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +67 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
- package/src/PowerSearch/usePowerSearchSource.ts +1 -2
- package/src/SelectableCard/SelectableCard.doc.mjs +2 -0
- package/src/SelectableCard/SelectableCard.test.tsx +46 -4
- package/src/SelectableCard/SelectableCard.tsx +29 -16
- package/src/Selector/Selector.doc.mjs +7 -0
- package/src/Selector/Selector.test.tsx +92 -0
- package/src/Selector/Selector.tsx +16 -2
- package/src/Selector/hooks.ts +17 -0
- package/src/SideNav/SideNav.test.tsx +119 -3
- package/src/SideNav/SideNavCollapseButton.tsx +6 -1
- package/src/SideNav/SideNavHeading.tsx +24 -8
- package/src/SideNav/SideNavItem.tsx +5 -1
- package/src/Slider/Slider.test.tsx +75 -2
- package/src/Slider/Slider.tsx +21 -5
- package/src/Switch/Switch.test.tsx +32 -1
- package/src/TabList/Tab.tsx +2 -2
- package/src/TabList/TabMenu.tsx +2 -2
- package/src/Table/BaseTable.tsx +3 -5
- package/src/Table/TableCell.tsx +3 -3
- package/src/Table/TableHeaderCell.tsx +3 -3
- package/src/Table/index.ts +5 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +6 -2
- package/src/Table/plugins/rowStatus/index.ts +7 -0
- package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +138 -0
- package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +189 -0
- package/src/Table/plugins/selection/useTableSelection.test.tsx +16 -0
- package/src/Table/plugins/selection/useTableSelection.tsx +19 -1
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -1
- package/src/Table/plugins/tree/useTableTreeData.test.tsx +135 -3
- package/src/Table/plugins/tree/useTableTreeData.tsx +128 -1
- package/src/Table/plugins/tree/useTableTreeState.test.tsx +104 -0
- package/src/Table/plugins/tree/useTableTreeState.tsx +46 -2
- package/src/Table/useBaseTablePlugins.ts +10 -6
- package/src/Table/useTableRowStatus.doc.mjs +30 -0
- package/src/Table/useTableSelection.doc.mjs +65 -14
- package/src/Table/useTableTreeData.doc.mjs +29 -0
- package/src/Table/useTableTreeState.doc.mjs +2 -2
- package/src/TextArea/TextArea.doc.mjs +15 -0
- package/src/TextArea/TextArea.test.tsx +32 -1
- package/src/TextArea/TextArea.tsx +10 -0
- package/src/TextInput/TextInput.doc.mjs +15 -0
- package/src/TextInput/TextInput.test.tsx +44 -0
- package/src/TextInput/TextInput.tsx +13 -1
- package/src/Thumbnail/Thumbnail.doc.mjs +19 -10
- package/src/Thumbnail/Thumbnail.test.tsx +98 -7
- package/src/Thumbnail/Thumbnail.tsx +142 -42
- package/src/Thumbnail/thumbnail.markers.stylex.ts +12 -0
- package/src/TimeInput/TimeInput.doc.mjs +15 -0
- package/src/TimeInput/TimeInput.test.tsx +99 -1
- package/src/TimeInput/TimeInput.tsx +29 -6
- package/src/Timestamp/Timestamp.doc.mjs +4 -4
- package/src/Timestamp/Timestamp.test.tsx +32 -0
- package/src/Timestamp/Timestamp.tsx +28 -8
- package/src/Toast/useToast.tsx +7 -8
- package/src/ToggleButton/ToggleButtonGroup.tsx +1 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +30 -1
- package/src/Tokenizer/Tokenizer.test.tsx +206 -2
- package/src/Tokenizer/Tokenizer.tsx +26 -4
- package/src/TopNav/TopNav.test.tsx +125 -1
- package/src/TopNav/TopNavHeading.tsx +24 -8
- package/src/TopNav/TopNavMegaMenu.test.tsx +149 -1
- package/src/TopNav/TopNavMegaMenu.tsx +10 -4
- package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +3 -3
- package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +19 -2
- package/src/TopNav/TopNavMenu.test.tsx +118 -4
- package/src/TopNav/TopNavMenu.tsx +83 -5
- package/src/TreeList/TreeList.doc.mjs +22 -0
- package/src/TreeList/TreeList.test.tsx +232 -0
- package/src/TreeList/TreeList.tsx +18 -2
- package/src/TreeList/TreeListBranches.tsx +16 -2
- package/src/TreeList/TreeListItem.tsx +52 -12
- package/src/TreeList/TreeListTypes.ts +27 -1
- package/src/TreeList/index.ts +2 -2
- package/src/Typeahead/BaseTypeahead.tsx +1 -1
- package/src/Typeahead/Typeahead.doc.mjs +7 -0
- package/src/Typeahead/Typeahead.test.tsx +23 -0
- package/src/Typeahead/Typeahead.tsx +10 -0
- package/src/authoring/doc.ts +1 -3
- package/src/docs-types.ts +5 -0
- package/src/hooks/computeOverflow.test.ts +422 -0
- package/src/hooks/computeOverflow.ts +290 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/isRtlElement.ts +27 -0
- package/src/hooks/useDevWarning.test.tsx +45 -0
- package/src/hooks/useDevWarning.ts +54 -0
- 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/useListFocus.doc.mjs +3 -3
- package/src/hooks/useListFocus.test.tsx +67 -1
- package/src/hooks/useListFocus.ts +21 -5
- package/src/hooks/useOverflow.test.ts +96 -4
- package/src/hooks/useOverflow.ts +74 -33
- package/src/i18n/InternationalizationContext.ts +4 -0
- package/src/i18n/InternationalizationProvider.doc.mjs +99 -2
- 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/resolve.ts +9 -21
- package/src/i18n/useDirection.ts +29 -0
- package/src/reset.css +0 -26
- package/src/reset.test.ts +60 -0
- package/src/theme/Theme.tsx +11 -14
- package/src/theme/derivedVarRegistry.test.ts +1 -0
- package/src/theme/derivedVarRegistry.ts +6 -0
- package/src/theme/generateThemeRules.test.ts +107 -0
- package/src/theme/generateThemeRules.ts +56 -0
- package/src/theme/hct.ts +1 -1
- package/src/theme/syntax/defineSyntaxTheme.ts +5 -6
- package/src/utils/devWarning.test.ts +56 -0
- package/src/utils/devWarning.ts +102 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/plainDate.test.ts +22 -0
- package/src/utils/plainDate.ts +61 -0
- package/src/utils/types.ts +14 -0
|
@@ -8,7 +8,7 @@ export const docs = {
|
|
|
8
8
|
category: 'Data Input',
|
|
9
9
|
isHiddenFromOverview: true,
|
|
10
10
|
description:
|
|
11
|
-
'Status message component for form field validation feedback.',
|
|
11
|
+
'Status message component for form field validation feedback. Messages are announced to screen readers through persistent live regions (assertive for errors, polite otherwise), so conditional mounting is safe.',
|
|
12
12
|
theming: {
|
|
13
13
|
targets: [
|
|
14
14
|
{className: 'astryx-field-status', visualProps: ['type', 'variant']},
|
|
@@ -66,12 +66,24 @@ export const docs = {
|
|
|
66
66
|
/** @type {import('../docs-types').TranslationDoc} */
|
|
67
67
|
export const docsDense = {
|
|
68
68
|
description:
|
|
69
|
-
'Validation feedback message for fields/custom controls. Supports error, warning, success and attached/detached variants.',
|
|
69
|
+
'Validation feedback message for fields/custom controls. Supports error, warning, success and attached/detached variants. Announced via persistent live regions (assertive for errors, polite otherwise).',
|
|
70
70
|
usage: {
|
|
71
71
|
bestPractices: [
|
|
72
|
-
{
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
{
|
|
73
|
+
guidance: true,
|
|
74
|
+
description:
|
|
75
|
+
'Use attached status below bordered inputs when message belongs to that input.',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
guidance: true,
|
|
79
|
+
description:
|
|
80
|
+
'Use detached status for checkboxes, switches, and custom controls where overlap is visually awkward.',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
guidance: false,
|
|
84
|
+
description:
|
|
85
|
+
'Use FieldStatus for general alerts or page-level notices; use Banner or Toast instead.',
|
|
86
|
+
},
|
|
75
87
|
],
|
|
76
88
|
},
|
|
77
89
|
propDescriptions: {
|
|
@@ -9,15 +9,27 @@
|
|
|
9
9
|
* SYNC: When FieldStatus.tsx changes, update tests to match new behavior
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {describe, it, expect, vi} from 'vitest';
|
|
13
|
-
import {render, screen} from '@testing-library/react';
|
|
12
|
+
import {describe, it, expect, vi, afterEach} from 'vitest';
|
|
13
|
+
import {render, screen, waitFor} from '@testing-library/react';
|
|
14
14
|
import * as stylex from '@stylexjs/stylex';
|
|
15
15
|
import {FieldStatus} from './FieldStatus';
|
|
16
|
+
import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
|
|
16
17
|
|
|
17
18
|
const testStyles = stylex.create({
|
|
18
19
|
custom: {color: 'rebeccapurple'},
|
|
19
20
|
});
|
|
20
21
|
|
|
22
|
+
function politeRegion(): HTMLElement | null {
|
|
23
|
+
return document.querySelector('[data-astryx-live-region="polite"]');
|
|
24
|
+
}
|
|
25
|
+
function assertiveRegion(): HTMLElement | null {
|
|
26
|
+
return document.querySelector('[data-astryx-live-region="assertive"]');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
__resetLiveRegionsForTest();
|
|
31
|
+
});
|
|
32
|
+
|
|
21
33
|
describe('FieldStatus', () => {
|
|
22
34
|
it('renders the message text', () => {
|
|
23
35
|
render(<FieldStatus type="error" message="This field is required" />);
|
|
@@ -29,47 +41,75 @@ describe('FieldStatus', () => {
|
|
|
29
41
|
expect(screen.getByTestId('fs').tagName).toBe('DIV');
|
|
30
42
|
});
|
|
31
43
|
|
|
32
|
-
describe('
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
describe('screen-reader announcements', () => {
|
|
45
|
+
// The rendered element is NOT itself a live region: FieldStatus is
|
|
46
|
+
// conditionally mounted by every caller, and live regions born together
|
|
47
|
+
// with their content are not reliably announced. Announcements go through
|
|
48
|
+
// the persistent useAnnounce singletons instead.
|
|
49
|
+
it('does not carry role or aria-live on the rendered element', () => {
|
|
50
|
+
render(<FieldStatus type="error" message="msg" data-testid="fs" />);
|
|
51
|
+
const el = screen.getByTestId('fs');
|
|
52
|
+
expect(el).not.toHaveAttribute('role');
|
|
53
|
+
expect(el).not.toHaveAttribute('aria-live');
|
|
37
54
|
});
|
|
38
55
|
|
|
39
|
-
//
|
|
40
|
-
it('
|
|
41
|
-
render(<FieldStatus type="
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
// Errors are urgent — they interrupt via the assertive channel.
|
|
57
|
+
it('announces error messages assertively, including on first mount', async () => {
|
|
58
|
+
render(<FieldStatus type="error" message="This field is required" />);
|
|
59
|
+
await waitFor(() => {
|
|
60
|
+
expect(assertiveRegion()).toHaveTextContent('This field is required');
|
|
61
|
+
});
|
|
62
|
+
expect(politeRegion()).toHaveTextContent('');
|
|
44
63
|
});
|
|
45
64
|
|
|
46
|
-
it('
|
|
47
|
-
render(<FieldStatus type="
|
|
48
|
-
|
|
65
|
+
it('announces warning messages politely', async () => {
|
|
66
|
+
render(<FieldStatus type="warning" message="Check this value" />);
|
|
67
|
+
await waitFor(() => {
|
|
68
|
+
expect(politeRegion()).toHaveTextContent('Check this value');
|
|
69
|
+
});
|
|
70
|
+
expect(assertiveRegion()).toHaveTextContent('');
|
|
49
71
|
});
|
|
50
|
-
});
|
|
51
72
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
'aria-live',
|
|
58
|
-
'assertive',
|
|
59
|
-
);
|
|
73
|
+
it('announces success messages politely', async () => {
|
|
74
|
+
render(<FieldStatus type="success" message="Looks good" />);
|
|
75
|
+
await waitFor(() => {
|
|
76
|
+
expect(politeRegion()).toHaveTextContent('Looks good');
|
|
77
|
+
});
|
|
60
78
|
});
|
|
61
79
|
|
|
62
|
-
it('
|
|
63
|
-
render(<FieldStatus type="
|
|
64
|
-
|
|
80
|
+
it('announces message changes', async () => {
|
|
81
|
+
const {rerender} = render(<FieldStatus type="error" message="First" />);
|
|
82
|
+
await waitFor(() => {
|
|
83
|
+
expect(assertiveRegion()).toHaveTextContent('First');
|
|
84
|
+
});
|
|
85
|
+
rerender(<FieldStatus type="error" message="Second" />);
|
|
86
|
+
await waitFor(() => {
|
|
87
|
+
expect(assertiveRegion()).toHaveTextContent('Second');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Severity changes re-route the announcement to the matching channel.
|
|
92
|
+
it('re-routes to the polite channel when type changes from error', async () => {
|
|
93
|
+
const {rerender} = render(<FieldStatus type="error" message="msg" />);
|
|
94
|
+
await waitFor(() => {
|
|
95
|
+
expect(assertiveRegion()).toHaveTextContent('msg');
|
|
96
|
+
});
|
|
97
|
+
rerender(<FieldStatus type="success" message="msg" />);
|
|
98
|
+
await waitFor(() => {
|
|
99
|
+
expect(politeRegion()).toHaveTextContent('msg');
|
|
100
|
+
});
|
|
65
101
|
});
|
|
66
102
|
|
|
67
|
-
it('
|
|
68
|
-
render(<FieldStatus type="
|
|
69
|
-
|
|
103
|
+
it('does not announce an empty message', () => {
|
|
104
|
+
render(<FieldStatus type="error" message="" />);
|
|
105
|
+
// The live regions are created lazily on first announce; an empty
|
|
106
|
+
// message must not trigger one.
|
|
107
|
+
expect(assertiveRegion()).toBeNull();
|
|
108
|
+
expect(politeRegion()).toBeNull();
|
|
70
109
|
});
|
|
71
110
|
|
|
72
|
-
// The
|
|
111
|
+
// The visible message stays perceivable by assistive tech (it is the
|
|
112
|
+
// aria-describedby target for the input).
|
|
73
113
|
it('does not mark itself aria-hidden', () => {
|
|
74
114
|
render(<FieldStatus type="error" message="msg" data-testid="fs" />);
|
|
75
115
|
expect(screen.getByTestId('fs')).not.toHaveAttribute('aria-hidden');
|
|
@@ -245,20 +285,90 @@ describe('FieldStatus', () => {
|
|
|
245
285
|
expect(screen.getByTestId('fs')).toHaveTextContent('Second');
|
|
246
286
|
});
|
|
247
287
|
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
it('
|
|
288
|
+
// The element must never regain live-region semantics when the type
|
|
289
|
+
// changes — announcements always flow through the persistent regions.
|
|
290
|
+
it('keeps the element role-free when type changes from error', () => {
|
|
251
291
|
const {rerender} = render(
|
|
252
292
|
<FieldStatus type="error" message="msg" data-testid="fs" />,
|
|
253
293
|
);
|
|
254
|
-
|
|
255
|
-
expect(el).toHaveAttribute('role', 'alert');
|
|
256
|
-
expect(el).toHaveAttribute('aria-live', 'assertive');
|
|
294
|
+
expect(screen.getByTestId('fs')).not.toHaveAttribute('role');
|
|
257
295
|
|
|
258
296
|
rerender(<FieldStatus type="success" message="msg" data-testid="fs" />);
|
|
259
|
-
el = screen.getByTestId('fs');
|
|
260
|
-
expect(el).toHaveAttribute('role'
|
|
261
|
-
expect(el).toHaveAttribute('aria-live'
|
|
297
|
+
const el = screen.getByTestId('fs');
|
|
298
|
+
expect(el).not.toHaveAttribute('role');
|
|
299
|
+
expect(el).not.toHaveAttribute('aria-live');
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// The detached message must convey status by more than color/position:
|
|
304
|
+
// a leading status glyph precedes the message text (WCAG 1.4.1). The glyph
|
|
305
|
+
// is decorative for AT (aria-hidden) because the message text already names
|
|
306
|
+
// the status in words and it is announced via the live region.
|
|
307
|
+
describe('detached leading status icon (use-of-color a11y)', () => {
|
|
308
|
+
it('renders a leading status icon before the message for the detached variant', () => {
|
|
309
|
+
render(
|
|
310
|
+
<FieldStatus
|
|
311
|
+
type="error"
|
|
312
|
+
message="Something went wrong"
|
|
313
|
+
variant="detached"
|
|
314
|
+
data-testid="fs"
|
|
315
|
+
/>,
|
|
316
|
+
);
|
|
317
|
+
const el = screen.getByTestId('fs');
|
|
318
|
+
const icon = el.querySelector('[aria-hidden="true"]');
|
|
319
|
+
const text = screen.getByText('Something went wrong');
|
|
320
|
+
expect(icon).toBeInTheDocument();
|
|
321
|
+
// Icon comes before the message text in document order.
|
|
322
|
+
expect(
|
|
323
|
+
icon!.compareDocumentPosition(text) & Node.DOCUMENT_POSITION_FOLLOWING,
|
|
324
|
+
).toBeTruthy();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('marks the status icon aria-hidden (visual redundancy, not a second announcement)', () => {
|
|
328
|
+
render(
|
|
329
|
+
<FieldStatus
|
|
330
|
+
type="warning"
|
|
331
|
+
message="Heads up"
|
|
332
|
+
variant="detached"
|
|
333
|
+
data-testid="fs"
|
|
334
|
+
/>,
|
|
335
|
+
);
|
|
336
|
+
const icon = screen
|
|
337
|
+
.getByTestId('fs')
|
|
338
|
+
.querySelector('[aria-hidden="true"]');
|
|
339
|
+
expect(icon).toBeInTheDocument();
|
|
340
|
+
expect(icon).toHaveAttribute('aria-hidden', 'true');
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('renders a status icon for each status type in the detached variant', () => {
|
|
344
|
+
for (const type of ['error', 'warning', 'success'] as const) {
|
|
345
|
+
const {unmount} = render(
|
|
346
|
+
<FieldStatus
|
|
347
|
+
type={type}
|
|
348
|
+
message="msg"
|
|
349
|
+
variant="detached"
|
|
350
|
+
data-testid="fs"
|
|
351
|
+
/>,
|
|
352
|
+
);
|
|
353
|
+
expect(
|
|
354
|
+
screen.getByTestId('fs').querySelector('[aria-hidden="true"]'),
|
|
355
|
+
).toBeInTheDocument();
|
|
356
|
+
unmount();
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('does not render a leading status icon for the attached variant', () => {
|
|
361
|
+
render(
|
|
362
|
+
<FieldStatus
|
|
363
|
+
type="error"
|
|
364
|
+
message="msg"
|
|
365
|
+
variant="attached"
|
|
366
|
+
data-testid="fs"
|
|
367
|
+
/>,
|
|
368
|
+
);
|
|
369
|
+
expect(
|
|
370
|
+
screen.getByTestId('fs').querySelector('[aria-hidden="true"]'),
|
|
371
|
+
).toBeNull();
|
|
262
372
|
});
|
|
263
373
|
});
|
|
264
374
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @file FieldStatus.tsx
|
|
5
|
-
* @input Uses React, stylex, theme tokens
|
|
5
|
+
* @input Uses React, stylex, theme tokens, useAnnounce, Icon
|
|
6
6
|
* @output Exports FieldStatus component, FieldStatusProps
|
|
7
7
|
* @position Core implementation; consumed by Field, Switch, CheckboxInput, and the FieldStatus entrypoint
|
|
8
8
|
*
|
|
@@ -16,9 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
'use client';
|
|
18
18
|
|
|
19
|
-
import React from 'react';
|
|
19
|
+
import React, {useEffect} from 'react';
|
|
20
20
|
import * as stylex from '@stylexjs/stylex';
|
|
21
21
|
import type {BaseProps} from '../BaseProps';
|
|
22
|
+
import {useAnnounce} from '../hooks/useAnnounce';
|
|
22
23
|
import {mergeProps} from '../utils';
|
|
23
24
|
import {
|
|
24
25
|
colorVars,
|
|
@@ -30,6 +31,19 @@ import {
|
|
|
30
31
|
import type {InputStatusType} from '../Field/types';
|
|
31
32
|
import {useEntryAnimation} from '../hooks/useEntryAnimation';
|
|
32
33
|
import {themeProps} from '../utils/themeProps';
|
|
34
|
+
import {Icon} from '../Icon';
|
|
35
|
+
import type {IconName} from '../Icon';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Maps each status type to its status glyph. Mirrors the mapping the input
|
|
39
|
+
* controls already use for the on-field status affordance, so the detached
|
|
40
|
+
* message shows the same icon a consumer sees elsewhere for that status.
|
|
41
|
+
*/
|
|
42
|
+
const statusIconMap: Record<InputStatusType, IconName> = {
|
|
43
|
+
warning: 'warning',
|
|
44
|
+
error: 'error',
|
|
45
|
+
success: 'success',
|
|
46
|
+
};
|
|
33
47
|
|
|
34
48
|
const styles = stylex.create({
|
|
35
49
|
base: {
|
|
@@ -51,6 +65,17 @@ const styles = stylex.create({
|
|
|
51
65
|
paddingInline: spacingVars['--spacing-2'],
|
|
52
66
|
borderRadius: radiusVars['--radius-element'],
|
|
53
67
|
},
|
|
68
|
+
detachedContent: {
|
|
69
|
+
display: 'flex',
|
|
70
|
+
alignItems: 'flex-start',
|
|
71
|
+
gap: spacingVars['--spacing-1'],
|
|
72
|
+
},
|
|
73
|
+
detachedIcon: {
|
|
74
|
+
// Match the height of the first text line so the glyph top-aligns to it
|
|
75
|
+
// (rather than to the flex box) when the message wraps to multiple lines.
|
|
76
|
+
lineHeight: typeScaleVars['--text-supporting-leading'],
|
|
77
|
+
flexShrink: 0,
|
|
78
|
+
},
|
|
54
79
|
});
|
|
55
80
|
|
|
56
81
|
const colorStyles = stylex.create({
|
|
@@ -113,6 +138,21 @@ export interface FieldStatusProps extends BaseProps<HTMLDivElement> {
|
|
|
113
138
|
/**
|
|
114
139
|
* A status message component for form fields.
|
|
115
140
|
*
|
|
141
|
+
* The `detached` variant renders a leading status icon before the message so
|
|
142
|
+
* status is not conveyed by color or position alone (WCAG 1.4.1). The icon is
|
|
143
|
+
* decorative for assistive tech (`aria-hidden`): the message text already names
|
|
144
|
+
* the status in words and is announced through the live region. The `attached`
|
|
145
|
+
* variant keeps its status affordance on the bordered input, so it renders no
|
|
146
|
+
* icon here to avoid a duplicate.
|
|
147
|
+
*
|
|
148
|
+
* Screen-reader announcements go through the persistent `useAnnounce` live
|
|
149
|
+
* regions (assertive for errors, polite otherwise) rather than `role`/
|
|
150
|
+
* `aria-live` on the rendered element. Live regions that mount together with
|
|
151
|
+
* their content are not reliably announced by assistive technology, and
|
|
152
|
+
* FieldStatus is almost always conditionally rendered by its callers. The
|
|
153
|
+
* message is announced whenever it appears — including on first mount — and
|
|
154
|
+
* whenever it changes.
|
|
155
|
+
*
|
|
116
156
|
* @example
|
|
117
157
|
* ```
|
|
118
158
|
* <FieldStatus
|
|
@@ -138,13 +178,22 @@ export function FieldStatus({
|
|
|
138
178
|
...rest
|
|
139
179
|
}: FieldStatusProps) {
|
|
140
180
|
const entryStyle = useEntryAnimation('slideDown');
|
|
181
|
+
const announce = useAnnounce();
|
|
182
|
+
|
|
183
|
+
// Announce the message through the persistently-mounted live regions.
|
|
184
|
+
// Announce-on-mount is intentional: callers conditionally mount FieldStatus
|
|
185
|
+
// when a status appears (and whole forms can mount with a server-side
|
|
186
|
+
// validation error already present), and both cases must be heard.
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
if (message) {
|
|
189
|
+
announce(message, type === 'error' ? 'assertive' : 'polite');
|
|
190
|
+
}
|
|
191
|
+
}, [announce, message, type]);
|
|
141
192
|
|
|
142
193
|
return (
|
|
143
194
|
<div
|
|
144
195
|
ref={ref}
|
|
145
196
|
id={id}
|
|
146
|
-
role={type === 'error' ? 'alert' : 'status'}
|
|
147
|
-
aria-live={type === 'error' ? 'assertive' : 'polite'}
|
|
148
197
|
{...rest}
|
|
149
198
|
{...mergeProps(
|
|
150
199
|
themeProps('field-status', {type, variant}),
|
|
@@ -158,7 +207,16 @@ export function FieldStatus({
|
|
|
158
207
|
className,
|
|
159
208
|
style,
|
|
160
209
|
)}>
|
|
161
|
-
{
|
|
210
|
+
{variant === 'detached' ? (
|
|
211
|
+
<span {...stylex.props(styles.detachedContent)}>
|
|
212
|
+
<span {...stylex.props(styles.detachedIcon)}>
|
|
213
|
+
<Icon icon={statusIconMap[type]} size="sm" color="inherit" />
|
|
214
|
+
</span>
|
|
215
|
+
<span>{message}</span>
|
|
216
|
+
</span>
|
|
217
|
+
) : (
|
|
218
|
+
message
|
|
219
|
+
)}
|
|
162
220
|
</div>
|
|
163
221
|
);
|
|
164
222
|
}
|
|
@@ -78,7 +78,7 @@ export const docs = {
|
|
|
78
78
|
name: 'isRequired',
|
|
79
79
|
type: 'boolean',
|
|
80
80
|
description:
|
|
81
|
-
'Displays a "Required" indicator next to the label and
|
|
81
|
+
'Displays a "Required" indicator next to the label and adds a screen-reader-only "Required" description to the trigger (aria-required is not supported on role="button"). Mutually exclusive with isOptional.',
|
|
82
82
|
default: 'false',
|
|
83
83
|
},
|
|
84
84
|
{
|
|
@@ -119,6 +119,13 @@ export const docs = {
|
|
|
119
119
|
description:
|
|
120
120
|
'Validation status: applies a colored border. If message is provided, displays a floating message below the input. Error type also sets aria-invalid.',
|
|
121
121
|
},
|
|
122
|
+
{
|
|
123
|
+
name: 'statusVariant',
|
|
124
|
+
type: "'attached' | 'detached'",
|
|
125
|
+
description:
|
|
126
|
+
'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.',
|
|
127
|
+
default: "'attached'",
|
|
128
|
+
},
|
|
122
129
|
{
|
|
123
130
|
name: 'labelTooltip',
|
|
124
131
|
type: 'string',
|
|
@@ -246,6 +253,13 @@ export const docsZh = {
|
|
|
246
253
|
type: "{type: 'error' | 'warning' | 'success', message?: string}",
|
|
247
254
|
description: '验证状态。',
|
|
248
255
|
},
|
|
256
|
+
{
|
|
257
|
+
name: 'statusVariant',
|
|
258
|
+
type: "'attached' | 'detached'",
|
|
259
|
+
description:
|
|
260
|
+
'状态消息相对于输入框的放置方式。attached 直接叠加在输入框下方(带边框处理);detached 作为独立元素浮于下方并留有间距。',
|
|
261
|
+
default: "'attached'",
|
|
262
|
+
},
|
|
249
263
|
],
|
|
250
264
|
theming: {
|
|
251
265
|
targets: [
|
|
@@ -308,7 +322,7 @@ export const docsDense = {
|
|
|
308
322
|
isLabelHidden: 'Visually hides label; keeps screen reader access.',
|
|
309
323
|
description: 'Description text between label+input.',
|
|
310
324
|
isOptional: 'Shows "Optional" indicator.',
|
|
311
|
-
isRequired: 'Shows "Required" indicator+
|
|
325
|
+
isRequired: 'Shows "Required" indicator+SR-only trigger description.',
|
|
312
326
|
isDisabled: 'Disables input, prevents interaction.',
|
|
313
327
|
disabledMessage:
|
|
314
328
|
'Explains why input is disabled. With isDisabled, shows tooltip on hover/focus + keeps trigger focusable via aria-disabled (opening picker stays blocked). Use instead of wrapping a disabled FileInput in Tooltip.',
|
|
@@ -316,6 +330,7 @@ export const docsDense = {
|
|
|
316
330
|
placeholder: 'Placeholder when no files selected.',
|
|
317
331
|
mode: "Visual mode: 'input' (compact) or 'dropzone' (drag-and-drop).",
|
|
318
332
|
status: 'Validation status; colored border. Message floats below.',
|
|
333
|
+
statusVariant: 'How status message is placed: attached overlaps below input; detached floats below w/ spacing.',
|
|
319
334
|
labelTooltip: 'Tooltip in info icon at label end.',
|
|
320
335
|
},
|
|
321
336
|
};
|
|
@@ -147,16 +147,33 @@ describe('FileInput', () => {
|
|
|
147
147
|
expect(screen.getByText('Upload')).toBeInTheDocument();
|
|
148
148
|
});
|
|
149
149
|
|
|
150
|
-
it('
|
|
150
|
+
it('conveys required state through the accessible description', () => {
|
|
151
151
|
render(
|
|
152
152
|
<FileInput label="Resume" isRequired value={null} onChange={() => {}} />,
|
|
153
153
|
);
|
|
154
|
-
|
|
154
|
+
const trigger = screen.getByRole('button', {name: 'Resume'});
|
|
155
|
+
// Required is conveyed via a visually hidden "Required" node referenced
|
|
156
|
+
// from aria-describedby on the focusable role="button" trigger — not the
|
|
155
157
|
// hidden file input (forms-6).
|
|
156
|
-
expect(
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
expect(trigger).toHaveAccessibleDescription(/Required/);
|
|
159
|
+
// aria-required is not a supported property of role="button" in
|
|
160
|
+
// WAI-ARIA 1.2 (AT does not announce it), so it must never appear.
|
|
161
|
+
expect(trigger).not.toHaveAttribute('aria-required');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('combines required with the description in the accessible description', () => {
|
|
165
|
+
render(
|
|
166
|
+
<FileInput
|
|
167
|
+
label="Resume"
|
|
168
|
+
description="PDF only"
|
|
169
|
+
isRequired
|
|
170
|
+
value={null}
|
|
171
|
+
onChange={() => {}}
|
|
172
|
+
/>,
|
|
159
173
|
);
|
|
174
|
+
const trigger = screen.getByRole('button', {name: 'Resume'});
|
|
175
|
+
expect(trigger).toHaveAccessibleDescription(/PDF only/);
|
|
176
|
+
expect(trigger).toHaveAccessibleDescription(/Required/);
|
|
160
177
|
});
|
|
161
178
|
|
|
162
179
|
it('places aria-describedby on the focusable button, not the hidden input (forms-6)', () => {
|
|
@@ -176,11 +193,11 @@ describe('FileInput', () => {
|
|
|
176
193
|
expect(input).toHaveAttribute('aria-hidden', 'true');
|
|
177
194
|
});
|
|
178
195
|
|
|
179
|
-
it('does not
|
|
196
|
+
it('does not mention required without isRequired', () => {
|
|
180
197
|
render(<FileInput label="Resume" value={null} onChange={() => {}} />);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
);
|
|
198
|
+
const trigger = screen.getByRole('button', {name: 'Resume'});
|
|
199
|
+
expect(trigger).not.toHaveAccessibleDescription(/Required/);
|
|
200
|
+
expect(trigger).not.toHaveAttribute('aria-required');
|
|
184
201
|
});
|
|
185
202
|
|
|
186
203
|
it('sets disabled attribute when isDisabled is true', () => {
|
|
@@ -348,9 +365,44 @@ describe('FileInput', () => {
|
|
|
348
365
|
fireEvent.change(fileInputEl(), {
|
|
349
366
|
target: {files: [createFile('note.txt', 100)]},
|
|
350
367
|
});
|
|
351
|
-
// A rejected selection
|
|
352
|
-
// the
|
|
353
|
-
|
|
368
|
+
// A rejected selection announces nothing politely. (The region pair may
|
|
369
|
+
// exist because the validation error itself is announced assertively via
|
|
370
|
+
// FieldStatus, but the polite channel must stay empty.)
|
|
371
|
+
expect(politeRegion()?.textContent ?? '').toBe('');
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('announces a validation error exactly once across live regions', async () => {
|
|
375
|
+
render(
|
|
376
|
+
<FileInput
|
|
377
|
+
label="Upload"
|
|
378
|
+
value={null}
|
|
379
|
+
onChange={() => {}}
|
|
380
|
+
accept=".pdf"
|
|
381
|
+
/>,
|
|
382
|
+
);
|
|
383
|
+
fireEvent.change(fileInputEl(), {
|
|
384
|
+
target: {files: [createFile('note.txt', 100)]},
|
|
385
|
+
});
|
|
386
|
+
const errorText = '"note.txt" is not an accepted file type';
|
|
387
|
+
// The error lands in the assertive announce region (via the FieldStatus
|
|
388
|
+
// the derived error status mounts)…
|
|
389
|
+
await waitFor(() => {
|
|
390
|
+
expect(
|
|
391
|
+
document.querySelector('[data-astryx-live-region="assertive"]'),
|
|
392
|
+
).toHaveTextContent(errorText);
|
|
393
|
+
});
|
|
394
|
+
// …and in exactly one live region overall. FileInput's own role="status"
|
|
395
|
+
// region used to duplicate the FieldStatus announcement, so the same
|
|
396
|
+
// error was read twice (assertively, then politely).
|
|
397
|
+
const liveRegions = Array.from(
|
|
398
|
+
document.querySelectorAll(
|
|
399
|
+
'[role="status"], [role="alert"], [aria-live]',
|
|
400
|
+
),
|
|
401
|
+
);
|
|
402
|
+
const regionsWithError = liveRegions.filter(el =>
|
|
403
|
+
(el.textContent ?? '').includes(errorText),
|
|
404
|
+
);
|
|
405
|
+
expect(regionsWithError).toHaveLength(1);
|
|
354
406
|
});
|
|
355
407
|
});
|
|
356
408
|
|
|
@@ -641,6 +693,54 @@ describe('FileInput', () => {
|
|
|
641
693
|
});
|
|
642
694
|
});
|
|
643
695
|
|
|
696
|
+
describe('trigger accessible name', () => {
|
|
697
|
+
it('includes the selected file name in the trigger name', () => {
|
|
698
|
+
const file = createFile('report.pdf', 1024, 'application/pdf');
|
|
699
|
+
render(<FileInput label="Document" value={file} onChange={() => {}} />);
|
|
700
|
+
expect(
|
|
701
|
+
screen.getByRole('button', {name: 'Document, report.pdf'}),
|
|
702
|
+
).toBeInTheDocument();
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
it('includes all selected file names when multiple files are selected', () => {
|
|
706
|
+
const files = [createFile('a.txt', 100), createFile('b.txt', 200)];
|
|
707
|
+
render(
|
|
708
|
+
<FileInput
|
|
709
|
+
label="Files"
|
|
710
|
+
value={files}
|
|
711
|
+
onChange={() => {}}
|
|
712
|
+
isMultiple
|
|
713
|
+
/>,
|
|
714
|
+
);
|
|
715
|
+
expect(
|
|
716
|
+
screen.getByRole('button', {name: 'Files, a.txt, b.txt'}),
|
|
717
|
+
).toBeInTheDocument();
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
it('uses exactly the label when no files are selected', () => {
|
|
721
|
+
render(<FileInput label="Document" value={null} onChange={() => {}} />);
|
|
722
|
+
expect(screen.getByRole('button', {name: 'Document'})).toHaveAttribute(
|
|
723
|
+
'aria-label',
|
|
724
|
+
'Document',
|
|
725
|
+
);
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
it('includes the selected file name in dropzone mode', () => {
|
|
729
|
+
const file = createFile('doc.pdf', 100, 'application/pdf');
|
|
730
|
+
render(
|
|
731
|
+
<FileInput
|
|
732
|
+
label="Upload"
|
|
733
|
+
value={file}
|
|
734
|
+
onChange={() => {}}
|
|
735
|
+
mode="dropzone"
|
|
736
|
+
/>,
|
|
737
|
+
);
|
|
738
|
+
expect(
|
|
739
|
+
screen.getByRole('button', {name: 'Upload, doc.pdf'}),
|
|
740
|
+
).toBeInTheDocument();
|
|
741
|
+
});
|
|
742
|
+
});
|
|
743
|
+
|
|
644
744
|
describe('data-testid', () => {
|
|
645
745
|
it('passes data-testid to native input', () => {
|
|
646
746
|
render(
|
|
@@ -800,3 +900,26 @@ describe('FileInput', () => {
|
|
|
800
900
|
});
|
|
801
901
|
});
|
|
802
902
|
});
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
describe('FileInput statusVariant forwarding', () => {
|
|
906
|
+
it('defaults to attached (status renders with data-variant="attached")', () => {
|
|
907
|
+
const {container} = render(
|
|
908
|
+
<FileInput label="Upload" value={null} onChange={() => {}} status={{type: 'error', message: 'Something went wrong'}} />,
|
|
909
|
+
);
|
|
910
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
911
|
+
'data-variant',
|
|
912
|
+
'attached',
|
|
913
|
+
);
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
it('forwards statusVariant="detached" to the underlying Field status', () => {
|
|
917
|
+
const {container} = render(
|
|
918
|
+
<FileInput label="Upload" value={null} onChange={() => {}} status={{type: 'error', message: 'Something went wrong'}} statusVariant="detached" />,
|
|
919
|
+
);
|
|
920
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
921
|
+
'data-variant',
|
|
922
|
+
'detached',
|
|
923
|
+
);
|
|
924
|
+
});
|
|
925
|
+
});
|