@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
|
@@ -157,6 +157,16 @@ export interface BaseTypeaheadProps<T extends SearchableItem> extends Omit<
|
|
|
157
157
|
*/
|
|
158
158
|
inputXStyle?: StyleXStyles;
|
|
159
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Tab-order override for the input element. Typeahead passes `-1` while
|
|
162
|
+
* its selected-value token is shown: the input is visually collapsed
|
|
163
|
+
* (width 0 / opacity 0) but must stay programmatically focusable for
|
|
164
|
+
* token edit/clear interactions, so removing it from the Tab order is
|
|
165
|
+
* what prevents an invisible tab stop (WCAG 2.4.3 / 2.4.7). The input
|
|
166
|
+
* remains focusable via `.focus()` regardless of this value.
|
|
167
|
+
*/
|
|
168
|
+
inputTabIndex?: number;
|
|
169
|
+
|
|
160
170
|
/**
|
|
161
171
|
* Ref to the anchor element for dropdown positioning.
|
|
162
172
|
* The dropdown will be positioned relative to this element.
|
|
@@ -230,7 +240,7 @@ const styles = stylex.create({
|
|
|
230
240
|
outline: 'none',
|
|
231
241
|
backgroundColor: 'transparent',
|
|
232
242
|
border: 'none',
|
|
233
|
-
textAlign: '
|
|
243
|
+
textAlign: 'start',
|
|
234
244
|
},
|
|
235
245
|
itemHighlighted: {
|
|
236
246
|
backgroundColor: colorVars['--color-overlay-hover'],
|
|
@@ -316,6 +326,7 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
316
326
|
ariaDescribedBy,
|
|
317
327
|
ariaLabelledBy,
|
|
318
328
|
inputXStyle,
|
|
329
|
+
inputTabIndex,
|
|
319
330
|
anchorRef,
|
|
320
331
|
onKeyDown: externalOnKeyDown,
|
|
321
332
|
debounceMs = 150,
|
|
@@ -431,7 +442,7 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
431
442
|
resultsGenRef.current = gen;
|
|
432
443
|
const shown = searchResults.slice(0, maxMenuItems);
|
|
433
444
|
setResults(shown);
|
|
434
|
-
setHighlightedIndex(
|
|
445
|
+
setHighlightedIndex(shown.length > 0 ? 0 : -1);
|
|
435
446
|
if (searchResults.length > 0 || searchQuery.length > 0) {
|
|
436
447
|
showLayer();
|
|
437
448
|
}
|
|
@@ -469,8 +480,9 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
469
480
|
return;
|
|
470
481
|
}
|
|
471
482
|
resultsGenRef.current = gen;
|
|
472
|
-
|
|
473
|
-
|
|
483
|
+
const shown = bootstrapResults.slice(0, maxMenuItems);
|
|
484
|
+
setResults(shown);
|
|
485
|
+
setHighlightedIndex(shown.length > 0 ? 0 : -1);
|
|
474
486
|
if (bootstrapResults.length > 0) {
|
|
475
487
|
showLayer();
|
|
476
488
|
}
|
|
@@ -637,15 +649,19 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
637
649
|
switch (e.key) {
|
|
638
650
|
case 'ArrowDown':
|
|
639
651
|
e.preventDefault();
|
|
640
|
-
|
|
641
|
-
prev
|
|
642
|
-
|
|
652
|
+
if (results.length > 0) {
|
|
653
|
+
setHighlightedIndex(prev =>
|
|
654
|
+
prev < results.length - 1 ? prev + 1 : 0,
|
|
655
|
+
);
|
|
656
|
+
}
|
|
643
657
|
break;
|
|
644
658
|
case 'ArrowUp':
|
|
645
659
|
e.preventDefault();
|
|
646
|
-
|
|
647
|
-
prev
|
|
648
|
-
|
|
660
|
+
if (results.length > 0) {
|
|
661
|
+
setHighlightedIndex(prev =>
|
|
662
|
+
prev > 0 ? prev - 1 : results.length - 1,
|
|
663
|
+
);
|
|
664
|
+
}
|
|
649
665
|
break;
|
|
650
666
|
case 'Enter':
|
|
651
667
|
e.preventDefault();
|
|
@@ -660,13 +676,17 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
660
676
|
case 'Home':
|
|
661
677
|
if (popover.isOpen) {
|
|
662
678
|
e.preventDefault();
|
|
663
|
-
|
|
679
|
+
if (results.length > 0) {
|
|
680
|
+
setHighlightedIndex(0);
|
|
681
|
+
}
|
|
664
682
|
}
|
|
665
683
|
break;
|
|
666
684
|
case 'End':
|
|
667
685
|
if (popover.isOpen) {
|
|
668
686
|
e.preventDefault();
|
|
669
|
-
|
|
687
|
+
if (results.length > 0) {
|
|
688
|
+
setHighlightedIndex(results.length - 1);
|
|
689
|
+
}
|
|
670
690
|
}
|
|
671
691
|
break;
|
|
672
692
|
}
|
|
@@ -694,13 +714,17 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
694
714
|
// cursor walks off-screen once navigation passes the visible window. Mirrors
|
|
695
715
|
// CommandPaletteItem's scrollIntoView({block: 'nearest'}) behavior.
|
|
696
716
|
useEffect(() => {
|
|
697
|
-
if (
|
|
717
|
+
if (
|
|
718
|
+
!popover.isOpen ||
|
|
719
|
+
highlightedIndex < 0 ||
|
|
720
|
+
highlightedIndex >= results.length
|
|
721
|
+
) {
|
|
698
722
|
return;
|
|
699
723
|
}
|
|
700
724
|
document
|
|
701
725
|
.getElementById(getItemId(highlightedIndex))
|
|
702
726
|
?.scrollIntoView?.({block: 'nearest'});
|
|
703
|
-
}, [popover.isOpen, highlightedIndex, getItemId]);
|
|
727
|
+
}, [popover.isOpen, highlightedIndex, getItemId, results.length]);
|
|
704
728
|
|
|
705
729
|
const selectedKey =
|
|
706
730
|
value == null ? null : getKey(value.id, () => results.indexOf(value));
|
|
@@ -725,7 +749,9 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
725
749
|
aria-expanded={popover.isOpen}
|
|
726
750
|
aria-controls={listboxId}
|
|
727
751
|
aria-activedescendant={
|
|
728
|
-
popover.isOpen &&
|
|
752
|
+
popover.isOpen &&
|
|
753
|
+
highlightedIndex >= 0 &&
|
|
754
|
+
highlightedIndex < results.length
|
|
729
755
|
? getItemId(highlightedIndex)
|
|
730
756
|
: undefined
|
|
731
757
|
}
|
|
@@ -733,6 +759,7 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
733
759
|
aria-describedby={ariaDescribedBy}
|
|
734
760
|
aria-labelledby={ariaLabelledBy}
|
|
735
761
|
aria-disabled={isFocusableDisabled ? 'true' : undefined}
|
|
762
|
+
tabIndex={inputTabIndex}
|
|
736
763
|
value={query}
|
|
737
764
|
onChange={handleInputChange}
|
|
738
765
|
onPointerDown={() => {
|
|
@@ -89,6 +89,13 @@ export const docs = {
|
|
|
89
89
|
description:
|
|
90
90
|
'Validation status object with type and message for error/warning/success states.',
|
|
91
91
|
},
|
|
92
|
+
{
|
|
93
|
+
name: 'statusVariant',
|
|
94
|
+
type: "'attached' | 'detached'",
|
|
95
|
+
description:
|
|
96
|
+
'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.',
|
|
97
|
+
default: "'attached'",
|
|
98
|
+
},
|
|
92
99
|
{
|
|
93
100
|
name: 'renderItem',
|
|
94
101
|
type: '(item: T) => ReactNode',
|
|
@@ -158,6 +165,12 @@ export const docs = {
|
|
|
158
165
|
type: '(isOpen: boolean) => void',
|
|
159
166
|
description: 'Callback when the dropdown opens or closes.',
|
|
160
167
|
},
|
|
168
|
+
{
|
|
169
|
+
name: 'width',
|
|
170
|
+
type: 'SizeValue',
|
|
171
|
+
description:
|
|
172
|
+
'Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned.',
|
|
173
|
+
},
|
|
161
174
|
{
|
|
162
175
|
name: 'xstyle',
|
|
163
176
|
type: 'StyleXStyles',
|
|
@@ -171,6 +171,33 @@ describe('BaseTypeahead', () => {
|
|
|
171
171
|
});
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
+
describe('empty results active descendant (#4059)', () => {
|
|
175
|
+
it('does not set aria-activedescendant when search has 0 results', async () => {
|
|
176
|
+
render(
|
|
177
|
+
<BaseTypeahead
|
|
178
|
+
searchSource={fruitSource}
|
|
179
|
+
value={null}
|
|
180
|
+
onChange={() => {}}
|
|
181
|
+
debounceMs={0}
|
|
182
|
+
/>,
|
|
183
|
+
);
|
|
184
|
+
const input = screen.getByRole('combobox');
|
|
185
|
+
fireEvent.change(input, {target: {value: 'zzzzz'}});
|
|
186
|
+
|
|
187
|
+
await waitFor(() => {
|
|
188
|
+
expect(input).not.toHaveAttribute('aria-activedescendant');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Press ArrowDown — should NOT set aria-activedescendant to option-0
|
|
192
|
+
fireEvent.keyDown(input, {key: 'ArrowDown'});
|
|
193
|
+
expect(input).not.toHaveAttribute('aria-activedescendant');
|
|
194
|
+
|
|
195
|
+
// Press Home — should NOT set aria-activedescendant
|
|
196
|
+
fireEvent.keyDown(input, {key: 'Home'});
|
|
197
|
+
expect(input).not.toHaveAttribute('aria-activedescendant');
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
174
201
|
it('disables input when isDisabled', () => {
|
|
175
202
|
render(
|
|
176
203
|
<BaseTypeahead
|
|
@@ -710,6 +737,68 @@ describe('Typeahead edit mode', () => {
|
|
|
710
737
|
});
|
|
711
738
|
});
|
|
712
739
|
|
|
740
|
+
describe('Typeahead collapsed input tab order', () => {
|
|
741
|
+
it('removes the invisible input from the Tab order while a token is shown', () => {
|
|
742
|
+
render(
|
|
743
|
+
<Typeahead
|
|
744
|
+
label="Fruit"
|
|
745
|
+
searchSource={fruitSource}
|
|
746
|
+
value={fruits[0]}
|
|
747
|
+
onChange={() => {}}
|
|
748
|
+
/>,
|
|
749
|
+
);
|
|
750
|
+
// While the token is shown the input is collapsed (width 0 / opacity 0);
|
|
751
|
+
// it must stay programmatically focusable for token interactions but must
|
|
752
|
+
// not be an invisible Tab stop (WCAG 2.4.3 / 2.4.7).
|
|
753
|
+
expect(screen.getByRole('combobox')).toHaveAttribute('tabindex', '-1');
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
it('Tab from the token skips the invisible input', async () => {
|
|
757
|
+
const user = userEvent.setup();
|
|
758
|
+
render(
|
|
759
|
+
<Typeahead
|
|
760
|
+
label="Fruit"
|
|
761
|
+
searchSource={fruitSource}
|
|
762
|
+
value={fruits[0]}
|
|
763
|
+
onChange={() => {}}
|
|
764
|
+
/>,
|
|
765
|
+
);
|
|
766
|
+
// Focus the token's internal button, then Tab away — focus must not land
|
|
767
|
+
// on the visually hidden combobox input.
|
|
768
|
+
const tokenButton = screen.getByRole('button', {name: fruits[0].label});
|
|
769
|
+
tokenButton.focus();
|
|
770
|
+
await user.tab();
|
|
771
|
+
expect(screen.getByRole('combobox')).not.toHaveFocus();
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
it('keeps the input in the Tab order when no token is shown', () => {
|
|
775
|
+
render(
|
|
776
|
+
<Typeahead
|
|
777
|
+
label="Fruit"
|
|
778
|
+
searchSource={fruitSource}
|
|
779
|
+
value={null}
|
|
780
|
+
onChange={() => {}}
|
|
781
|
+
/>,
|
|
782
|
+
);
|
|
783
|
+
expect(screen.getByRole('combobox')).not.toHaveAttribute('tabindex');
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
it('restores the input to the Tab order in edit mode', () => {
|
|
787
|
+
render(
|
|
788
|
+
<Typeahead
|
|
789
|
+
label="Fruit"
|
|
790
|
+
searchSource={fruitSource}
|
|
791
|
+
value={fruits[0]}
|
|
792
|
+
onChange={() => {}}
|
|
793
|
+
/>,
|
|
794
|
+
);
|
|
795
|
+
// Entering edit mode removes the token and uncollapses the input
|
|
796
|
+
const tokenText = screen.getByText(fruits[0].label);
|
|
797
|
+
fireEvent.click(tokenText.closest('div')!);
|
|
798
|
+
expect(screen.getByRole('combobox')).not.toHaveAttribute('tabindex');
|
|
799
|
+
});
|
|
800
|
+
});
|
|
801
|
+
|
|
713
802
|
describe('BaseTypeahead paste behavior', () => {
|
|
714
803
|
it('pasting text triggers search results like typing', async () => {
|
|
715
804
|
const user = userEvent.setup();
|
|
@@ -948,3 +1037,26 @@ describe('Typeahead disabledMessage', () => {
|
|
|
948
1037
|
expect(input).not.toHaveAttribute('aria-disabled');
|
|
949
1038
|
});
|
|
950
1039
|
});
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
describe('Typeahead statusVariant forwarding', () => {
|
|
1043
|
+
it('defaults to attached (status renders with data-variant="attached")', () => {
|
|
1044
|
+
const {container} = render(
|
|
1045
|
+
<Typeahead label="Fruit" searchSource={fruitSource} value={null} onChange={() => {}} status={{type: 'error', message: 'Required'}} />,
|
|
1046
|
+
);
|
|
1047
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
1048
|
+
'data-variant',
|
|
1049
|
+
'attached',
|
|
1050
|
+
);
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
it('forwards statusVariant="detached" to the underlying Field status', () => {
|
|
1054
|
+
const {container} = render(
|
|
1055
|
+
<Typeahead label="Fruit" searchSource={fruitSource} value={null} onChange={() => {}} status={{type: 'error', message: 'Required'}} statusVariant="detached" />,
|
|
1056
|
+
);
|
|
1057
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
1058
|
+
'data-variant',
|
|
1059
|
+
'detached',
|
|
1060
|
+
);
|
|
1061
|
+
});
|
|
1062
|
+
});
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
inputStatusBorderStyles,
|
|
37
37
|
inputStatusHoverShadowStyles,
|
|
38
38
|
inputStatusFocusWithinStyles,
|
|
39
|
+
type FieldStatusVariant,
|
|
39
40
|
} from '../Field';
|
|
40
41
|
import {Token} from '../Token';
|
|
41
42
|
import {useTooltip} from '../Tooltip';
|
|
@@ -75,6 +76,13 @@ export interface TypeaheadProps<T extends SearchableItem> extends Omit<
|
|
|
75
76
|
isOptional?: boolean;
|
|
76
77
|
/** Validation status. */
|
|
77
78
|
status?: InputStatus;
|
|
79
|
+
/**
|
|
80
|
+
* How the status message is placed relative to the input.
|
|
81
|
+
* - 'attached': message overlaps directly below the input (bordered treatment)
|
|
82
|
+
* - 'detached': message floats below as a separate element with spacing
|
|
83
|
+
* @default 'attached'
|
|
84
|
+
*/
|
|
85
|
+
statusVariant?: FieldStatusVariant;
|
|
78
86
|
/**
|
|
79
87
|
* Icon to display at the start of the input.
|
|
80
88
|
* Accepts a ReactNode (e.g. `<Icon icon={SearchIcon} />`) or an SVG icon component directly.
|
|
@@ -226,6 +234,7 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
226
234
|
isRequired = false,
|
|
227
235
|
isOptional = false,
|
|
228
236
|
status,
|
|
237
|
+
statusVariant = 'attached',
|
|
229
238
|
startIcon,
|
|
230
239
|
labelTooltip,
|
|
231
240
|
searchSource,
|
|
@@ -412,7 +421,7 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
412
421
|
styles.wrapper,
|
|
413
422
|
sizeStyle,
|
|
414
423
|
status && inputStatusBorderStyles[status.type],
|
|
415
|
-
status && inputStatusHoverShadowStyles[status.type],
|
|
424
|
+
status && !isDisabled && inputStatusHoverShadowStyles[status.type],
|
|
416
425
|
status && inputStatusFocusWithinStyles[status.type],
|
|
417
426
|
isDisabled && inputWrapperStyles.disabled,
|
|
418
427
|
inputGroup && groupStyles.inGroup,
|
|
@@ -458,6 +467,12 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
458
467
|
anchorRef={wrapperRef}
|
|
459
468
|
onKeyDown={handleKeyDown}
|
|
460
469
|
inputXStyle={showToken ? styles.inputHidden : undefined}
|
|
470
|
+
// While the token is shown the input is collapsed (width 0 /
|
|
471
|
+
// opacity 0) — take it out of the Tab order so keyboard users
|
|
472
|
+
// don't hit an invisible stop (WCAG 2.4.3 / 2.4.7). It stays
|
|
473
|
+
// programmatically focusable: entering edit mode and clearing
|
|
474
|
+
// both refocus it after it uncollapses.
|
|
475
|
+
inputTabIndex={showToken ? -1 : undefined}
|
|
461
476
|
size={size}
|
|
462
477
|
/>
|
|
463
478
|
{hasClear && value && !isDisabled && (
|
|
@@ -500,6 +515,7 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
500
515
|
}
|
|
501
516
|
: undefined
|
|
502
517
|
}
|
|
518
|
+
statusVariant={statusVariant}
|
|
503
519
|
labelTooltip={labelTooltip}
|
|
504
520
|
width={width}
|
|
505
521
|
xstyle={xstyle}
|
|
@@ -132,6 +132,7 @@ export function TypeaheadItem<T extends SearchableItem>({
|
|
|
132
132
|
icon,
|
|
133
133
|
description,
|
|
134
134
|
isDisabled = false,
|
|
135
|
+
xstyle,
|
|
135
136
|
}: TypeaheadItemProps<T>) {
|
|
136
137
|
// If item has a pre-rendered element, use it
|
|
137
138
|
if (item.element) {
|
|
@@ -143,7 +144,7 @@ export function TypeaheadItem<T extends SearchableItem>({
|
|
|
143
144
|
ref={ref}
|
|
144
145
|
{...mergeProps(
|
|
145
146
|
themeProps('typeahead-item'),
|
|
146
|
-
stylex.props(styles.container, isDisabled && styles.disabled),
|
|
147
|
+
stylex.props(styles.container, isDisabled && styles.disabled, xstyle),
|
|
147
148
|
)}>
|
|
148
149
|
{icon}
|
|
149
150
|
<div {...stylex.props(styles.content)}>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file forcedColors.ts
|
|
5
|
+
* @input Uses the jsdom document (StyleX dev runtime injects rules into it)
|
|
6
|
+
* @output Exports getForcedColorsRules, getAllInjectedCss test helpers
|
|
7
|
+
* @position Shared test utility for asserting forced-colors style output
|
|
8
|
+
*
|
|
9
|
+
* jsdom cannot emulate `@media (forced-colors: active)` rendering, so
|
|
10
|
+
* component tests assert the next-best thing: that the StyleX dev runtime
|
|
11
|
+
* (runtimeInjection in vitest.config.ts) actually injected the forced-colors
|
|
12
|
+
* rules a component relies on for Windows High Contrast support (WCAG 1.4.11).
|
|
13
|
+
* Visual behavior needs manual verification in a forced-colors environment.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Collects the cssText of every injected CSS rule scoped to
|
|
18
|
+
* `@media (forced-colors: active)`, including rules nested in other
|
|
19
|
+
* conditions. Returns one string for substring assertions.
|
|
20
|
+
*/
|
|
21
|
+
export function getForcedColorsRules(): string {
|
|
22
|
+
const chunks: string[] = [];
|
|
23
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
24
|
+
let rules: CSSRule[];
|
|
25
|
+
try {
|
|
26
|
+
rules = Array.from(sheet.cssRules);
|
|
27
|
+
} catch {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
for (const rule of rules) {
|
|
31
|
+
if (rule.cssText.includes('forced-colors: active')) {
|
|
32
|
+
chunks.push(rule.cssText);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return chunks.join('\n');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Collects the cssText of every injected CSS rule, regardless of condition.
|
|
41
|
+
* Use to assert declarations that live OUTSIDE `@media (forced-colors: active)`
|
|
42
|
+
* yet still exist for forced-colors support — e.g. `forced-color-adjust: none`
|
|
43
|
+
* (an unconditional declaration) or a hover tint gated behind
|
|
44
|
+
* `(forced-colors: none)` so it cannot override the forced-colors state.
|
|
45
|
+
*/
|
|
46
|
+
export function getAllInjectedCss(): string {
|
|
47
|
+
const chunks: string[] = [];
|
|
48
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
49
|
+
let rules: CSSRule[];
|
|
50
|
+
try {
|
|
51
|
+
rules = Array.from(sheet.cssRules);
|
|
52
|
+
} catch {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
for (const rule of rules) {
|
|
56
|
+
chunks.push(rule.cssText);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return chunks.join('\n');
|
|
60
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import {describe, it, expect} from 'vitest';
|
|
4
|
+
|
|
5
|
+
import {docs as CheckboxInputDocs} from '../CheckboxInput/CheckboxInput.doc.mjs';
|
|
6
|
+
import {docs as CheckboxListDocs} from '../CheckboxList/CheckboxList.doc.mjs';
|
|
7
|
+
import {docs as DateInputDocs} from '../DateInput/DateInput.doc.mjs';
|
|
8
|
+
import {docs as DateRangeInputDocs} from '../DateRangeInput/DateRangeInput.doc.mjs';
|
|
9
|
+
import {docs as DateTimeInputDocs} from '../DateTimeInput/DateTimeInput.doc.mjs';
|
|
10
|
+
import {docs as FileInputDocs} from '../FileInput/FileInput.doc.mjs';
|
|
11
|
+
import {docs as MultiSelectorDocs} from '../MultiSelector/MultiSelector.doc.mjs';
|
|
12
|
+
import {docs as NumberInputDocs} from '../NumberInput/NumberInput.doc.mjs';
|
|
13
|
+
import {docs as RadioListDocs} from '../RadioList/RadioList.doc.mjs';
|
|
14
|
+
import {docs as SelectorDocs} from '../Selector/Selector.doc.mjs';
|
|
15
|
+
import {docs as SliderDocs} from '../Slider/Slider.doc.mjs';
|
|
16
|
+
import {docs as SwitchDocs} from '../Switch/Switch.doc.mjs';
|
|
17
|
+
import {docs as TextAreaDocs} from '../TextArea/TextArea.doc.mjs';
|
|
18
|
+
import {docs as TextInputDocs} from '../TextInput/TextInput.doc.mjs';
|
|
19
|
+
import {docs as TimeInputDocs} from '../TimeInput/TimeInput.doc.mjs';
|
|
20
|
+
import {docs as TokenizerDocs} from '../Tokenizer/Tokenizer.doc.mjs';
|
|
21
|
+
import {docs as TypeaheadDocs} from '../Typeahead/Typeahead.doc.mjs';
|
|
22
|
+
|
|
23
|
+
const inputDocsSuite = [
|
|
24
|
+
{name: 'CheckboxInput', docs: CheckboxInputDocs},
|
|
25
|
+
{name: 'CheckboxList', docs: CheckboxListDocs},
|
|
26
|
+
{name: 'DateInput', docs: DateInputDocs},
|
|
27
|
+
{name: 'DateRangeInput', docs: DateRangeInputDocs},
|
|
28
|
+
{name: 'DateTimeInput', docs: DateTimeInputDocs},
|
|
29
|
+
{name: 'FileInput', docs: FileInputDocs},
|
|
30
|
+
{name: 'MultiSelector', docs: MultiSelectorDocs},
|
|
31
|
+
{name: 'NumberInput', docs: NumberInputDocs},
|
|
32
|
+
{name: 'RadioList', docs: RadioListDocs},
|
|
33
|
+
{name: 'Selector', docs: SelectorDocs},
|
|
34
|
+
{name: 'Slider', docs: SliderDocs},
|
|
35
|
+
{name: 'Switch', docs: SwitchDocs},
|
|
36
|
+
{name: 'TextArea', docs: TextAreaDocs},
|
|
37
|
+
{name: 'TextInput', docs: TextInputDocs},
|
|
38
|
+
{name: 'TimeInput', docs: TimeInputDocs},
|
|
39
|
+
{name: 'Tokenizer', docs: TokenizerDocs},
|
|
40
|
+
{name: 'Typeahead', docs: TypeaheadDocs},
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
describe('Input Family width Prop Contract (#4163)', () => {
|
|
44
|
+
inputDocsSuite.forEach(({name, docs}) => {
|
|
45
|
+
it(`documents the width prop for ${name}`, () => {
|
|
46
|
+
const propsList = (docs.props || docs.components?.[0]?.props) as {
|
|
47
|
+
name: string;
|
|
48
|
+
type: string;
|
|
49
|
+
}[];
|
|
50
|
+
expect(
|
|
51
|
+
propsList,
|
|
52
|
+
`${name}.doc.mjs must expose a props array`,
|
|
53
|
+
).toBeDefined();
|
|
54
|
+
const widthProp = propsList.find(p => p.name === 'width');
|
|
55
|
+
expect(
|
|
56
|
+
widthProp,
|
|
57
|
+
`${name}.doc.mjs must document the width prop`,
|
|
58
|
+
).toBeDefined();
|
|
59
|
+
expect(widthProp?.type).toBe('SizeValue');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
package/src/doc-mjs.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Ambient module declaration for `*.doc.mjs` imports.
|
|
5
|
+
*
|
|
6
|
+
* Component contract tests (packages/core/src/__tests__/*Contract.test.tsx)
|
|
7
|
+
* import `{Name}.doc.mjs` files directly to assert their documented props
|
|
8
|
+
* stay in sync with the component's real API. Without this declaration,
|
|
9
|
+
* TypeScript has no way to type a `.mjs` import and fails with
|
|
10
|
+
* TS7016 ("Could not find a declaration file for module").
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
declare module '*.doc.mjs' {
|
|
14
|
+
import type {ComponentDoc, TranslationDoc} from './docs-types';
|
|
15
|
+
|
|
16
|
+
export const docs: ComponentDoc;
|
|
17
|
+
export const docsZh: ComponentDoc;
|
|
18
|
+
export const docsDense: TranslationDoc;
|
|
19
|
+
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -76,6 +76,12 @@ export type {
|
|
|
76
76
|
export {useInputContainer} from './useInputContainer';
|
|
77
77
|
export type {UseInputContainerOptions} from './useInputContainer';
|
|
78
78
|
|
|
79
|
+
export {useInputStatusIcon} from './useInputStatusIcon';
|
|
80
|
+
export type {
|
|
81
|
+
UseInputStatusIconOptions,
|
|
82
|
+
UseInputStatusIconReturn,
|
|
83
|
+
} from './useInputStatusIcon';
|
|
84
|
+
|
|
79
85
|
export {useInteractiveRole} from './useInteractiveRole';
|
|
80
86
|
export type {
|
|
81
87
|
InteractiveRole,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file isRtlElement.ts
|
|
7
|
+
* @input DOM element (nullable)
|
|
8
|
+
* @output Exports isRtlElement helper resolving an element's computed text
|
|
9
|
+
* direction
|
|
10
|
+
* @position Internal hook utility; used by useListFocus and useGridFocus to
|
|
11
|
+
* auto-detect RTL for arrow-key navigation (same getComputedStyle precedent
|
|
12
|
+
* as Resizable's ResizeHandle drag deltas).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Whether `el` renders right-to-left, per its computed `direction`.
|
|
17
|
+
*
|
|
18
|
+
* SSR-safe: returns false when `el` is null or no DOM is available. Callers
|
|
19
|
+
* should invoke this lazily (on keydown, not on render) so getComputedStyle
|
|
20
|
+
* runs only when a horizontal arrow key is actually handled.
|
|
21
|
+
*/
|
|
22
|
+
export function isRtlElement(el: HTMLElement | null): boolean {
|
|
23
|
+
if (!el || typeof window === 'undefined') {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return window.getComputedStyle(el).direction === 'rtl';
|
|
27
|
+
}
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* SYNC: When useAnnounce.ts changes, update tests to match new behavior
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {describe, it, expect, afterEach} from 'vitest';
|
|
13
|
-
import {renderHook, waitFor} from '@testing-library/react';
|
|
12
|
+
import {describe, it, expect, afterEach, vi} from 'vitest';
|
|
13
|
+
import {act, renderHook, waitFor} from '@testing-library/react';
|
|
14
14
|
import {useAnnounce, __resetLiveRegionsForTest} from './useAnnounce';
|
|
15
15
|
|
|
16
16
|
afterEach(() => {
|
|
@@ -82,6 +82,79 @@ describe('useAnnounce', () => {
|
|
|
82
82
|
expect(politeRegion()).toBeNull();
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
+
it('clears the region after the clear delay, but not before', () => {
|
|
86
|
+
vi.useFakeTimers();
|
|
87
|
+
try {
|
|
88
|
+
const {result} = renderHook(() => useAnnounce());
|
|
89
|
+
result.current('Saved');
|
|
90
|
+
// Flush the rAF that re-sets the message.
|
|
91
|
+
act(() => {
|
|
92
|
+
vi.advanceTimersByTime(50);
|
|
93
|
+
});
|
|
94
|
+
expect(politeRegion()?.textContent).toBe('Saved');
|
|
95
|
+
|
|
96
|
+
// The message survives long enough for AT to finish reading it.
|
|
97
|
+
act(() => {
|
|
98
|
+
vi.advanceTimersByTime(1000);
|
|
99
|
+
});
|
|
100
|
+
expect(politeRegion()?.textContent).toBe('Saved');
|
|
101
|
+
|
|
102
|
+
// After the clear delay, stale status text is removed from the DOM.
|
|
103
|
+
act(() => {
|
|
104
|
+
vi.advanceTimersByTime(10_000);
|
|
105
|
+
});
|
|
106
|
+
expect(politeRegion()?.textContent).toBe('');
|
|
107
|
+
} finally {
|
|
108
|
+
vi.useRealTimers();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('resets the clear timer on each announce', () => {
|
|
113
|
+
vi.useFakeTimers();
|
|
114
|
+
try {
|
|
115
|
+
const {result} = renderHook(() => useAnnounce());
|
|
116
|
+
result.current('first');
|
|
117
|
+
act(() => {
|
|
118
|
+
vi.advanceTimersByTime(1500);
|
|
119
|
+
});
|
|
120
|
+
// Announcing again must reset the pending clear, not inherit it.
|
|
121
|
+
result.current('second');
|
|
122
|
+
act(() => {
|
|
123
|
+
vi.advanceTimersByTime(1900);
|
|
124
|
+
});
|
|
125
|
+
// 3.4s after 'first' (past its clear point) but only 1.9s after
|
|
126
|
+
// 'second' — the newer message must still be present.
|
|
127
|
+
expect(politeRegion()?.textContent).toBe('second');
|
|
128
|
+
act(() => {
|
|
129
|
+
vi.advanceTimersByTime(10_000);
|
|
130
|
+
});
|
|
131
|
+
expect(politeRegion()?.textContent).toBe('');
|
|
132
|
+
} finally {
|
|
133
|
+
vi.useRealTimers();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('re-announces normally after a clear', () => {
|
|
138
|
+
vi.useFakeTimers();
|
|
139
|
+
try {
|
|
140
|
+
const {result} = renderHook(() => useAnnounce());
|
|
141
|
+
result.current('gone soon');
|
|
142
|
+
act(() => {
|
|
143
|
+
vi.advanceTimersByTime(10_000);
|
|
144
|
+
});
|
|
145
|
+
expect(politeRegion()?.textContent).toBe('');
|
|
146
|
+
|
|
147
|
+
// The clear-then-rAF re-announce pattern still works after a clear.
|
|
148
|
+
result.current('back again');
|
|
149
|
+
act(() => {
|
|
150
|
+
vi.advanceTimersByTime(50);
|
|
151
|
+
});
|
|
152
|
+
expect(politeRegion()?.textContent).toBe('back again');
|
|
153
|
+
} finally {
|
|
154
|
+
vi.useRealTimers();
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
85
158
|
it('reuses the same singleton regions across hook instances', async () => {
|
|
86
159
|
const {result: a} = renderHook(() => useAnnounce());
|
|
87
160
|
a.current('first');
|