@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
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
type ReactNode,
|
|
28
28
|
} from 'react';
|
|
29
29
|
import * as stylex from '@stylexjs/stylex';
|
|
30
|
-
import type {IconName} from '../Icon';
|
|
31
30
|
import {
|
|
32
31
|
colorVars,
|
|
33
32
|
spacingVars,
|
|
@@ -40,14 +39,16 @@ import {
|
|
|
40
39
|
inputStatusBorderStyles,
|
|
41
40
|
inputStatusHoverShadowStyles,
|
|
42
41
|
inputStatusFocusWithinStyles,
|
|
42
|
+
type FieldStatusVariant,
|
|
43
43
|
} from '../Field';
|
|
44
|
-
import {
|
|
44
|
+
import {renderIconSlot, type IconType} from '../Icon';
|
|
45
45
|
import {Spinner} from '../Spinner';
|
|
46
46
|
import {useTooltip} from '../Tooltip';
|
|
47
47
|
import {mergeProps, mergeRefs} from '../utils';
|
|
48
48
|
import type {BaseProps} from '../BaseProps';
|
|
49
49
|
import type {SizeValue} from '../utils/types';
|
|
50
50
|
import {useInputContainer} from '../hooks/useInputContainer';
|
|
51
|
+
import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
|
|
51
52
|
import {useSize} from '../SizeContext/SizeContext';
|
|
52
53
|
import {themeProps} from '../utils/themeProps';
|
|
53
54
|
import {VisuallyHidden} from '../VisuallyHidden';
|
|
@@ -217,6 +218,14 @@ export interface TextAreaProps extends Omit<
|
|
|
217
218
|
* If message is provided, displays a floating message box below the textarea.
|
|
218
219
|
*/
|
|
219
220
|
status?: TextAreaStatus;
|
|
221
|
+
/**
|
|
222
|
+
* How the status message is placed relative to the input.
|
|
223
|
+
* - 'attached': message overlaps directly below the input (bordered treatment)
|
|
224
|
+
* - 'detached': message floats below as a separate element with spacing
|
|
225
|
+
* - 'tooltip': no message box; the status icon becomes a focusable info-tip button that reveals the message on hover, keyboard focus, or tap
|
|
226
|
+
* @default 'attached'
|
|
227
|
+
*/
|
|
228
|
+
statusVariant?: FieldStatusVariant;
|
|
220
229
|
/**
|
|
221
230
|
* Width of the field. Numbers are treated as pixels, strings are used as-is
|
|
222
231
|
* (e.g. `'100%'`). Sizes the whole field (label, control, and status) so they
|
|
@@ -298,6 +307,7 @@ export function TextArea({
|
|
|
298
307
|
isDisabled = false,
|
|
299
308
|
disabledMessage,
|
|
300
309
|
status,
|
|
310
|
+
statusVariant = 'attached',
|
|
301
311
|
labelTooltip,
|
|
302
312
|
startIcon,
|
|
303
313
|
hasSpellCheck = true,
|
|
@@ -341,25 +351,19 @@ export function TextArea({
|
|
|
341
351
|
isEnabled: showsDisabledMessage,
|
|
342
352
|
});
|
|
343
353
|
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const statusIconColorMap: Record<
|
|
351
|
-
TextAreaStatusType,
|
|
352
|
-
'warning' | 'error' | 'success'
|
|
353
|
-
> = {
|
|
354
|
-
warning: 'warning',
|
|
355
|
-
error: 'error',
|
|
356
|
-
success: 'success',
|
|
357
|
-
};
|
|
354
|
+
const {statusIcon, describedBy: statusTooltipDescribedBy} =
|
|
355
|
+
useInputStatusIcon({
|
|
356
|
+
status,
|
|
357
|
+
statusVariant,
|
|
358
|
+
});
|
|
358
359
|
|
|
359
360
|
const ariaDescribedBy =
|
|
360
361
|
[
|
|
361
362
|
description ? descriptionID : null,
|
|
362
|
-
status?.message ? statusMessageID : null,
|
|
363
|
+
statusVariant !== 'tooltip' && status?.message ? statusMessageID : null,
|
|
364
|
+
// The tooltip variant renders no message box; describe the input by the
|
|
365
|
+
// tooltip's content instead so the status is still announced.
|
|
366
|
+
statusTooltipDescribedBy,
|
|
363
367
|
maxLength != null ? counterID : null,
|
|
364
368
|
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
365
369
|
]
|
|
@@ -412,6 +416,7 @@ export function TextArea({
|
|
|
412
416
|
}
|
|
413
417
|
: undefined
|
|
414
418
|
}
|
|
419
|
+
statusVariant={statusVariant}
|
|
415
420
|
labelTooltip={labelTooltip}
|
|
416
421
|
width={width}>
|
|
417
422
|
<div
|
|
@@ -432,7 +437,9 @@ export function TextArea({
|
|
|
432
437
|
textareaSizeStyles[size],
|
|
433
438
|
effectivelyDisabled && inputWrapperStyles.disabled,
|
|
434
439
|
status && inputStatusBorderStyles[status.type],
|
|
435
|
-
status &&
|
|
440
|
+
status &&
|
|
441
|
+
!effectivelyDisabled &&
|
|
442
|
+
inputStatusHoverShadowStyles[status.type],
|
|
436
443
|
status && inputStatusFocusWithinStyles[status.type],
|
|
437
444
|
xstyle,
|
|
438
445
|
),
|
|
@@ -478,14 +485,8 @@ export function TextArea({
|
|
|
478
485
|
)}
|
|
479
486
|
/>
|
|
480
487
|
{isBusy && <Spinner size="sm" />}
|
|
481
|
-
{
|
|
482
|
-
<span {...stylex.props(styles.statusIcon)}>
|
|
483
|
-
<Icon
|
|
484
|
-
icon={statusIconMap[status.type]}
|
|
485
|
-
size="md"
|
|
486
|
-
color={statusIconColorMap[status.type]}
|
|
487
|
-
/>
|
|
488
|
-
</span>
|
|
488
|
+
{statusIcon && (
|
|
489
|
+
<span {...stylex.props(styles.statusIcon)}>{statusIcon}</span>
|
|
489
490
|
)}
|
|
490
491
|
</div>
|
|
491
492
|
{maxLength != null && (
|
|
@@ -114,6 +114,13 @@ export const docs = {
|
|
|
114
114
|
description:
|
|
115
115
|
'Validation status: applies a colored border and status icon. If message is provided, displays a floating message below the input. Error type also sets aria-invalid.',
|
|
116
116
|
},
|
|
117
|
+
{
|
|
118
|
+
name: 'statusVariant',
|
|
119
|
+
type: "'attached' | 'detached' | 'tooltip'",
|
|
120
|
+
description:
|
|
121
|
+
'How the status message is placed relative to the input. attached overlaps directly below the input (bordered treatment); detached floats below as a separate element with spacing; tooltip hides the message box and surfaces it in a tooltip on the status icon.',
|
|
122
|
+
default: "'attached'",
|
|
123
|
+
},
|
|
117
124
|
{
|
|
118
125
|
name: 'hasClear',
|
|
119
126
|
type: 'boolean',
|
|
@@ -133,6 +140,12 @@ export const docs = {
|
|
|
133
140
|
description:
|
|
134
141
|
'The HTML name attribute for the input, useful for form submissions.',
|
|
135
142
|
},
|
|
143
|
+
{
|
|
144
|
+
name: 'width',
|
|
145
|
+
type: 'SizeValue',
|
|
146
|
+
description:
|
|
147
|
+
'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.',
|
|
148
|
+
},
|
|
136
149
|
],
|
|
137
150
|
theming: {
|
|
138
151
|
targets: [
|
|
@@ -274,6 +287,13 @@ export const docsZh = {
|
|
|
274
287
|
description:
|
|
275
288
|
'验证状态:应用彩色边框和状态图标。如果提供了 message,在输入框下方显示浮动消息。错误类型还会设置 aria-invalid。',
|
|
276
289
|
},
|
|
290
|
+
{
|
|
291
|
+
name: 'statusVariant',
|
|
292
|
+
type: "'attached' | 'detached' | 'tooltip'",
|
|
293
|
+
description:
|
|
294
|
+
'状态消息相对于输入框的放置方式。attached 直接叠加在输入框下方(带边框处理);detached 作为独立元素浮于下方并留有间距;tooltip 隐藏消息框,并在状态图标上以提示气泡形式显示。',
|
|
295
|
+
default: "'attached'",
|
|
296
|
+
},
|
|
277
297
|
{
|
|
278
298
|
name: 'hasClear',
|
|
279
299
|
type: 'boolean',
|
|
@@ -368,6 +388,7 @@ export const docsDense = {
|
|
|
368
388
|
labelTooltip: 'Tooltip in info icon at label end.',
|
|
369
389
|
startIcon: 'SVG icon at input start (e.g. heroicons or lucide).',
|
|
370
390
|
status: 'Validation status; colored border+icon. Message floats below. Error sets aria-invalid.',
|
|
391
|
+
statusVariant: 'How status message is placed: attached overlaps below input; detached floats below w/ spacing; tooltip hides the box and shows it on the status icon.',
|
|
371
392
|
hasClear: 'Shows clear button when input has value. Clears value on click.',
|
|
372
393
|
hasAutoFocus: 'Auto-focus input on mount.',
|
|
373
394
|
htmlName: 'HTML name attr for form submissions.',
|
|
@@ -13,6 +13,7 @@ import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
|
13
13
|
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import {TestIcon} from '../__tests__/TestIcon';
|
|
16
|
+
import {InputGroup} from '../InputGroup';
|
|
16
17
|
import {TextInput} from './TextInput';
|
|
17
18
|
|
|
18
19
|
// Mock showPopover/hidePopover since jsdom does not implement them. Used by the
|
|
@@ -229,6 +230,26 @@ describe('TextInput', () => {
|
|
|
229
230
|
expect(screen.getByText('Invalid email address')).toBeInTheDocument();
|
|
230
231
|
});
|
|
231
232
|
|
|
233
|
+
it('has no dangling aria-describedby ids inside InputGroup (WCAG 1.3.1)', () => {
|
|
234
|
+
// Inside an InputGroup no Field renders, so the status message element
|
|
235
|
+
// does not exist; aria-describedby must not reference its id.
|
|
236
|
+
render(
|
|
237
|
+
<InputGroup label="Contact">
|
|
238
|
+
<TextInput
|
|
239
|
+
label="Email"
|
|
240
|
+
value=""
|
|
241
|
+
onChange={() => {}}
|
|
242
|
+
status={{type: 'error', message: 'Invalid email address'}}
|
|
243
|
+
/>
|
|
244
|
+
</InputGroup>,
|
|
245
|
+
);
|
|
246
|
+
const input = screen.getByRole('textbox');
|
|
247
|
+
const describedBy = input.getAttribute('aria-describedby') ?? '';
|
|
248
|
+
for (const idToken of describedBy.split(/\s+/).filter(Boolean)) {
|
|
249
|
+
expect(document.getElementById(idToken)).not.toBeNull();
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
232
253
|
it('does not render status message when not provided', () => {
|
|
233
254
|
render(
|
|
234
255
|
<TextInput
|
|
@@ -659,3 +680,132 @@ describe('TextInput', () => {
|
|
|
659
680
|
});
|
|
660
681
|
});
|
|
661
682
|
});
|
|
683
|
+
|
|
684
|
+
describe('TextInput statusVariant forwarding', () => {
|
|
685
|
+
it('defaults to attached (status renders with data-variant="attached")', () => {
|
|
686
|
+
const {container} = render(
|
|
687
|
+
<TextInput
|
|
688
|
+
label="Email"
|
|
689
|
+
value=""
|
|
690
|
+
onChange={() => {}}
|
|
691
|
+
status={{type: 'error', message: 'Invalid email'}}
|
|
692
|
+
/>,
|
|
693
|
+
);
|
|
694
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
695
|
+
'data-variant',
|
|
696
|
+
'attached',
|
|
697
|
+
);
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
it('forwards statusVariant="detached" to the underlying Field status', () => {
|
|
701
|
+
const {container} = render(
|
|
702
|
+
<TextInput
|
|
703
|
+
label="Email"
|
|
704
|
+
value=""
|
|
705
|
+
onChange={() => {}}
|
|
706
|
+
status={{type: 'error', message: 'Invalid email'}}
|
|
707
|
+
statusVariant="detached"
|
|
708
|
+
/>,
|
|
709
|
+
);
|
|
710
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
711
|
+
'data-variant',
|
|
712
|
+
'detached',
|
|
713
|
+
);
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
it('renders no message box for statusVariant="tooltip"', () => {
|
|
717
|
+
const {container} = render(
|
|
718
|
+
<TextInput
|
|
719
|
+
label="Email"
|
|
720
|
+
value=""
|
|
721
|
+
onChange={() => {}}
|
|
722
|
+
status={{type: 'error', message: 'Invalid email'}}
|
|
723
|
+
statusVariant="tooltip"
|
|
724
|
+
/>,
|
|
725
|
+
);
|
|
726
|
+
expect(
|
|
727
|
+
container.querySelector('.astryx-field-status'),
|
|
728
|
+
).not.toBeInTheDocument();
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
it('surfaces the status message in a tooltip for statusVariant="tooltip"', () => {
|
|
732
|
+
render(
|
|
733
|
+
<TextInput
|
|
734
|
+
label="Email"
|
|
735
|
+
value=""
|
|
736
|
+
onChange={() => {}}
|
|
737
|
+
status={{type: 'error', message: 'Invalid email'}}
|
|
738
|
+
statusVariant="tooltip"
|
|
739
|
+
/>,
|
|
740
|
+
);
|
|
741
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
742
|
+
expect(tooltip).toHaveTextContent('Invalid email');
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
it('describes the input by the status tooltip for statusVariant="tooltip"', () => {
|
|
746
|
+
render(
|
|
747
|
+
<TextInput
|
|
748
|
+
label="Email"
|
|
749
|
+
value=""
|
|
750
|
+
onChange={() => {}}
|
|
751
|
+
status={{type: 'error', message: 'Invalid email'}}
|
|
752
|
+
statusVariant="tooltip"
|
|
753
|
+
/>,
|
|
754
|
+
);
|
|
755
|
+
const input = screen.getByRole('textbox');
|
|
756
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
757
|
+
expect(input.getAttribute('aria-describedby')).toContain(tooltip.id);
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
it('renders the tooltip status affordance as a focusable button (WCAG 2.1.1)', () => {
|
|
761
|
+
render(
|
|
762
|
+
<TextInput
|
|
763
|
+
label="Email"
|
|
764
|
+
value=""
|
|
765
|
+
onChange={() => {}}
|
|
766
|
+
status={{type: 'error', message: 'Invalid email'}}
|
|
767
|
+
statusVariant="tooltip"
|
|
768
|
+
/>,
|
|
769
|
+
);
|
|
770
|
+
// The status affordance is a real button with an accessible name naming
|
|
771
|
+
// the status type (WCAG 4.1.2), so keyboard-only users (no AT) can reach it.
|
|
772
|
+
const statusButton = screen.getByRole('button', {name: /error details/i});
|
|
773
|
+
expect(statusButton).toBeInTheDocument();
|
|
774
|
+
expect(statusButton).toHaveAttribute('type', 'button');
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
it('opens the status tooltip on keyboard focus for statusVariant="tooltip"', async () => {
|
|
778
|
+
const user = userEvent.setup();
|
|
779
|
+
render(
|
|
780
|
+
<TextInput
|
|
781
|
+
label="Email"
|
|
782
|
+
value=""
|
|
783
|
+
onChange={() => {}}
|
|
784
|
+
status={{type: 'error', message: 'Invalid email'}}
|
|
785
|
+
statusVariant="tooltip"
|
|
786
|
+
/>,
|
|
787
|
+
);
|
|
788
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
789
|
+
// Tab from the input to the status button; keyboard focus reveals the tip.
|
|
790
|
+
await user.tab();
|
|
791
|
+
await user.tab();
|
|
792
|
+
await waitFor(() => {
|
|
793
|
+
expect(tooltip).toHaveAttribute('popover-open');
|
|
794
|
+
});
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
it('describes the status button by the tooltip content for statusVariant="tooltip"', () => {
|
|
798
|
+
render(
|
|
799
|
+
<TextInput
|
|
800
|
+
label="Email"
|
|
801
|
+
value=""
|
|
802
|
+
onChange={() => {}}
|
|
803
|
+
status={{type: 'error', message: 'Invalid email'}}
|
|
804
|
+
statusVariant="tooltip"
|
|
805
|
+
/>,
|
|
806
|
+
);
|
|
807
|
+
const statusButton = screen.getByRole('button', {name: /error details/i});
|
|
808
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
809
|
+
expect(statusButton.getAttribute('aria-describedby')).toContain(tooltip.id);
|
|
810
|
+
});
|
|
811
|
+
});
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
type ReactNode,
|
|
28
28
|
} from 'react';
|
|
29
29
|
import * as stylex from '@stylexjs/stylex';
|
|
30
|
-
import type {IconName} from '../Icon';
|
|
31
30
|
import {
|
|
32
31
|
colorVars,
|
|
33
32
|
sizeVars,
|
|
@@ -39,11 +38,11 @@ import {
|
|
|
39
38
|
import {
|
|
40
39
|
Field,
|
|
41
40
|
type InputStatus,
|
|
42
|
-
type InputStatusType,
|
|
43
41
|
inputWrapperStyles,
|
|
44
42
|
inputStatusBorderStyles,
|
|
45
43
|
inputStatusHoverShadowStyles,
|
|
46
44
|
inputStatusFocusWithinStyles,
|
|
45
|
+
type FieldStatusVariant,
|
|
47
46
|
} from '../Field';
|
|
48
47
|
import {Icon, renderIconSlot, type IconType} from '../Icon';
|
|
49
48
|
import {Spinner} from '../Spinner';
|
|
@@ -119,6 +118,7 @@ export type {
|
|
|
119
118
|
import {mergeProps, mergeRefs} from '../utils';
|
|
120
119
|
import {useSize} from '../SizeContext/SizeContext';
|
|
121
120
|
import {useInputContainer} from '../hooks/useInputContainer';
|
|
121
|
+
import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
|
|
122
122
|
import {useInputGroup} from '../InputGroup/InputGroupContext';
|
|
123
123
|
import type {BaseProps} from '../BaseProps';
|
|
124
124
|
import type {SizeValue} from '../utils/types';
|
|
@@ -198,6 +198,14 @@ export interface TextInputProps extends Omit<
|
|
|
198
198
|
* If message is provided, displays a floating message box below the input.
|
|
199
199
|
*/
|
|
200
200
|
status?: InputStatus;
|
|
201
|
+
/**
|
|
202
|
+
* How the status message is placed relative to the input.
|
|
203
|
+
* - 'attached': message overlaps directly below the input (bordered treatment)
|
|
204
|
+
* - 'detached': message floats below as a separate element with spacing
|
|
205
|
+
* - 'tooltip': no message box; the status icon becomes a focusable info-tip button that reveals the message on hover, keyboard focus, or tap
|
|
206
|
+
* @default 'attached'
|
|
207
|
+
*/
|
|
208
|
+
statusVariant?: FieldStatusVariant;
|
|
201
209
|
/**
|
|
202
210
|
* The size of the input.
|
|
203
211
|
* - 'sm': Compact size (18px height)
|
|
@@ -280,6 +288,7 @@ export function TextInput({
|
|
|
280
288
|
disabledMessage,
|
|
281
289
|
startIcon,
|
|
282
290
|
status,
|
|
291
|
+
statusVariant = 'attached',
|
|
283
292
|
size: sizeProp,
|
|
284
293
|
onChange,
|
|
285
294
|
changeAction,
|
|
@@ -328,26 +337,25 @@ export function TextInput({
|
|
|
328
337
|
isEnabled: showsDisabledMessage,
|
|
329
338
|
});
|
|
330
339
|
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const statusIconColorMap: Record<
|
|
338
|
-
InputStatusType,
|
|
339
|
-
'warning' | 'error' | 'success'
|
|
340
|
-
> = {
|
|
341
|
-
warning: 'warning',
|
|
342
|
-
error: 'error',
|
|
343
|
-
success: 'success',
|
|
344
|
-
};
|
|
340
|
+
const {statusIcon, describedBy: statusTooltipDescribedBy} =
|
|
341
|
+
useInputStatusIcon({
|
|
342
|
+
status,
|
|
343
|
+
statusVariant,
|
|
344
|
+
isInGroup: !!inputGroup,
|
|
345
|
+
});
|
|
345
346
|
|
|
346
347
|
const {ariaLabelledBy, ariaDescribedBy} = getInputARIA(
|
|
347
348
|
inputLabelID,
|
|
348
349
|
[
|
|
349
350
|
description ? descriptionID : null,
|
|
350
|
-
status
|
|
351
|
+
// The status message element is rendered by Field, which is skipped
|
|
352
|
+
// inside an InputGroup — only reference it when it actually exists.
|
|
353
|
+
!inputGroup && statusVariant !== 'tooltip' && status?.message
|
|
354
|
+
? statusMessageID
|
|
355
|
+
: null,
|
|
356
|
+
// The tooltip variant renders no message box; describe the input by the
|
|
357
|
+
// tooltip's content instead so the status is still announced.
|
|
358
|
+
statusTooltipDescribedBy,
|
|
351
359
|
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
352
360
|
],
|
|
353
361
|
inputGroup,
|
|
@@ -402,7 +410,7 @@ export function TextInput({
|
|
|
402
410
|
sizeStyles[size],
|
|
403
411
|
isDisabled && inputWrapperStyles.disabled,
|
|
404
412
|
status && inputStatusBorderStyles[status.type],
|
|
405
|
-
status && inputStatusHoverShadowStyles[status.type],
|
|
413
|
+
status && !isDisabled && inputStatusHoverShadowStyles[status.type],
|
|
406
414
|
status && inputStatusFocusWithinStyles[status.type],
|
|
407
415
|
inputGroup && groupStyles.inGroup,
|
|
408
416
|
xstyle,
|
|
@@ -456,13 +464,7 @@ export function TextInput({
|
|
|
456
464
|
</button>
|
|
457
465
|
)}
|
|
458
466
|
{isBusy && <Spinner size="sm" />}
|
|
459
|
-
{
|
|
460
|
-
<Icon
|
|
461
|
-
icon={statusIconMap[status.type]}
|
|
462
|
-
size="md"
|
|
463
|
-
color={statusIconColorMap[status.type]}
|
|
464
|
-
/>
|
|
465
|
-
)}
|
|
467
|
+
{statusIcon}
|
|
466
468
|
</div>
|
|
467
469
|
);
|
|
468
470
|
|
|
@@ -495,6 +497,7 @@ export function TextInput({
|
|
|
495
497
|
}
|
|
496
498
|
: undefined
|
|
497
499
|
}
|
|
500
|
+
statusVariant={statusVariant}
|
|
498
501
|
labelTooltip={labelTooltip}
|
|
499
502
|
width={width}>
|
|
500
503
|
{inputWrapper}
|
|
@@ -149,7 +149,7 @@ export const docsDense = {
|
|
|
149
149
|
onClick: '(e) => void. Adds button semantics + hover overlay.',
|
|
150
150
|
isLoading: 'Skeleton (no src) or upload overlay (with src). Default: false.',
|
|
151
151
|
isDisabled: 'Disabled state. Default: false.',
|
|
152
|
-
showRemoveOn: "When remove button shows: hover (default
|
|
152
|
+
showRemoveOn: "When remove button shows: hover (default: reveal on hover/focus, stays visible on touch) | always. Only when onRemove set.",
|
|
153
153
|
xstyle: 'stylex.create() for layout.',
|
|
154
154
|
className: 'CSS class. Prefer xstyle.',
|
|
155
155
|
style: 'Inline styles. Prefer xstyle.',
|
|
@@ -229,12 +229,25 @@ export const docs = {
|
|
|
229
229
|
description:
|
|
230
230
|
'Status indicator that colors the border and displays an icon. When a message is provided it is rendered below the input.',
|
|
231
231
|
},
|
|
232
|
+
{
|
|
233
|
+
name: 'statusVariant',
|
|
234
|
+
type: "'attached' | 'detached' | 'tooltip'",
|
|
235
|
+
description:
|
|
236
|
+
'How the status message is placed relative to the input. attached overlaps directly below the input (bordered treatment); detached floats below as a separate element with spacing; tooltip hides the message box and surfaces it in a tooltip on the status icon.',
|
|
237
|
+
default: "'attached'",
|
|
238
|
+
},
|
|
232
239
|
{
|
|
233
240
|
name: 'labelTooltip',
|
|
234
241
|
type: 'string',
|
|
235
242
|
description:
|
|
236
243
|
'Tooltip text rendered as an info icon at the end of the label row.',
|
|
237
244
|
},
|
|
245
|
+
{
|
|
246
|
+
name: 'width',
|
|
247
|
+
type: 'SizeValue',
|
|
248
|
+
description:
|
|
249
|
+
'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.',
|
|
250
|
+
},
|
|
238
251
|
{
|
|
239
252
|
name: 'xstyle',
|
|
240
253
|
type: 'StyleXStyles',
|
|
@@ -372,6 +385,13 @@ export const docsZh = {
|
|
|
372
385
|
description:
|
|
373
386
|
'为边框着色并显示图标的状态指示器。当提供消息时,消息渲染在输入框下方。',
|
|
374
387
|
},
|
|
388
|
+
{
|
|
389
|
+
name: 'statusVariant',
|
|
390
|
+
type: "'attached' | 'detached' | 'tooltip'",
|
|
391
|
+
description:
|
|
392
|
+
'状态消息相对于输入框的放置方式。attached 直接叠加在输入框下方(带边框处理);detached 作为独立元素浮于下方并留有间距;tooltip 隐藏消息框,并在状态图标上以提示气泡形式显示。',
|
|
393
|
+
default: "'attached'",
|
|
394
|
+
},
|
|
375
395
|
{
|
|
376
396
|
name: 'labelTooltip',
|
|
377
397
|
type: 'string',
|
|
@@ -545,6 +565,7 @@ export const docsDense = {
|
|
|
545
565
|
placeholder: 'Placeholder when empty. Focused+empty shows format hint.',
|
|
546
566
|
size: 'Input element height.',
|
|
547
567
|
status: 'Colored border+icon. Message rendered below input.',
|
|
568
|
+
statusVariant: 'How status message is placed: attached overlaps below input; detached floats below w/ spacing; tooltip hides the box and shows it on the status icon.',
|
|
548
569
|
labelTooltip: 'Tooltip as info icon at label row end.',
|
|
549
570
|
xstyle:
|
|
550
571
|
'StyleX styles for layout customization. Must be stylex.create() value, not inline style.',
|
|
@@ -571,3 +571,26 @@ describe('TimeInput', () => {
|
|
|
571
571
|
});
|
|
572
572
|
});
|
|
573
573
|
});
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
describe('TimeInput statusVariant forwarding', () => {
|
|
577
|
+
it('defaults to attached (status renders with data-variant="attached")', () => {
|
|
578
|
+
const {container} = render(
|
|
579
|
+
<TimeInput label="Start" value={undefined} onChange={() => {}} status={{type: 'error', message: 'Required'}} />,
|
|
580
|
+
);
|
|
581
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
582
|
+
'data-variant',
|
|
583
|
+
'attached',
|
|
584
|
+
);
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it('forwards statusVariant="detached" to the underlying Field status', () => {
|
|
588
|
+
const {container} = render(
|
|
589
|
+
<TimeInput label="Start" value={undefined} onChange={() => {}} status={{type: 'error', message: 'Required'}} statusVariant="detached" />,
|
|
590
|
+
);
|
|
591
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
592
|
+
'data-variant',
|
|
593
|
+
'detached',
|
|
594
|
+
);
|
|
595
|
+
});
|
|
596
|
+
});
|
|
@@ -29,7 +29,6 @@ import {
|
|
|
29
29
|
type FocusEvent,
|
|
30
30
|
} from 'react';
|
|
31
31
|
import * as stylex from '@stylexjs/stylex';
|
|
32
|
-
import type {IconName} from '../Icon';
|
|
33
32
|
import {
|
|
34
33
|
colorVars,
|
|
35
34
|
sizeVars,
|
|
@@ -41,11 +40,11 @@ import {
|
|
|
41
40
|
import {
|
|
42
41
|
Field,
|
|
43
42
|
type InputStatus,
|
|
44
|
-
type InputStatusType,
|
|
45
43
|
inputWrapperStyles,
|
|
46
44
|
inputStatusBorderStyles,
|
|
47
45
|
inputStatusHoverShadowStyles,
|
|
48
46
|
inputStatusFocusWithinStyles,
|
|
47
|
+
type FieldStatusVariant,
|
|
49
48
|
} from '../Field';
|
|
50
49
|
import {Icon} from '../Icon';
|
|
51
50
|
import {Spinner} from '../Spinner';
|
|
@@ -67,6 +66,7 @@ import type {SizeValue} from '../utils/types';
|
|
|
67
66
|
import {useSize} from '../SizeContext/SizeContext';
|
|
68
67
|
import {useAnnounce} from '../hooks/useAnnounce';
|
|
69
68
|
import {useInputContainer} from '../hooks/useInputContainer';
|
|
69
|
+
import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
|
|
70
70
|
import {useInputGroup} from '../InputGroup/InputGroupContext';
|
|
71
71
|
import {groupStyles} from '../InputGroup/groupStyles';
|
|
72
72
|
import {useTooltip} from '../Tooltip';
|
|
@@ -298,6 +298,14 @@ export interface TimeInputProps extends Omit<
|
|
|
298
298
|
* If message is provided, displays below the input.
|
|
299
299
|
*/
|
|
300
300
|
status?: InputStatus;
|
|
301
|
+
/**
|
|
302
|
+
* How the status message is placed relative to the input.
|
|
303
|
+
* - 'attached': message overlaps directly below the input (bordered treatment)
|
|
304
|
+
* - 'detached': message floats below as a separate element with spacing
|
|
305
|
+
* - 'tooltip': no message box; the status icon becomes a focusable info-tip button that reveals the message on hover, keyboard focus, or tap
|
|
306
|
+
* @default 'attached'
|
|
307
|
+
*/
|
|
308
|
+
statusVariant?: FieldStatusVariant;
|
|
301
309
|
|
|
302
310
|
/**
|
|
303
311
|
* Width of the field. Numbers are treated as pixels, strings are used as-is
|
|
@@ -347,6 +355,7 @@ export function TimeInput({
|
|
|
347
355
|
placeholder: placeholderFromProps,
|
|
348
356
|
size: sizeProp,
|
|
349
357
|
status,
|
|
358
|
+
statusVariant = 'attached',
|
|
350
359
|
labelTooltip,
|
|
351
360
|
width,
|
|
352
361
|
xstyle,
|
|
@@ -400,26 +409,21 @@ export function TimeInput({
|
|
|
400
409
|
});
|
|
401
410
|
|
|
402
411
|
// Status icon mapping
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
const statusIconColorMap: Record<
|
|
410
|
-
InputStatusType,
|
|
411
|
-
'warning' | 'error' | 'success'
|
|
412
|
-
> = {
|
|
413
|
-
warning: 'warning',
|
|
414
|
-
error: 'error',
|
|
415
|
-
success: 'success',
|
|
416
|
-
};
|
|
412
|
+
const {statusIcon, describedBy: statusTooltipDescribedBy} =
|
|
413
|
+
useInputStatusIcon({
|
|
414
|
+
status,
|
|
415
|
+
statusVariant,
|
|
416
|
+
isInGroup: !!inputGroup,
|
|
417
|
+
});
|
|
417
418
|
|
|
418
419
|
const {ariaLabelledBy, ariaDescribedBy} = getInputARIA(
|
|
419
420
|
inputLabelID,
|
|
420
421
|
[
|
|
421
422
|
description ? descriptionID : null,
|
|
422
|
-
status?.message ? statusMessageID : null,
|
|
423
|
+
statusVariant !== 'tooltip' && status?.message ? statusMessageID : null,
|
|
424
|
+
// The tooltip variant renders no message box; describe the input by the
|
|
425
|
+
// tooltip's content instead so the status is still announced.
|
|
426
|
+
statusTooltipDescribedBy,
|
|
423
427
|
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
424
428
|
],
|
|
425
429
|
inputGroup,
|
|
@@ -610,7 +614,7 @@ export function TimeInput({
|
|
|
610
614
|
sizeStyles[size],
|
|
611
615
|
isDisabled && inputWrapperStyles.disabled,
|
|
612
616
|
status && inputStatusBorderStyles[status.type],
|
|
613
|
-
status && inputStatusHoverShadowStyles[status.type],
|
|
617
|
+
status && !isDisabled && inputStatusHoverShadowStyles[status.type],
|
|
614
618
|
status && inputStatusFocusWithinStyles[status.type],
|
|
615
619
|
inputGroup && groupStyles.inGroup,
|
|
616
620
|
xstyle,
|
|
@@ -681,13 +685,7 @@ export function TimeInput({
|
|
|
681
685
|
<Icon icon="close" size="sm" color="secondary" />
|
|
682
686
|
</button>
|
|
683
687
|
)}
|
|
684
|
-
{
|
|
685
|
-
<Icon
|
|
686
|
-
icon={statusIconMap[status.type]}
|
|
687
|
-
size="md"
|
|
688
|
-
color={statusIconColorMap[status.type]}
|
|
689
|
-
/>
|
|
690
|
-
)}
|
|
688
|
+
{statusIcon}
|
|
691
689
|
</div>
|
|
692
690
|
);
|
|
693
691
|
|
|
@@ -720,6 +718,7 @@ export function TimeInput({
|
|
|
720
718
|
}
|
|
721
719
|
: undefined
|
|
722
720
|
}
|
|
721
|
+
statusVariant={statusVariant}
|
|
723
722
|
labelTooltip={labelTooltip}
|
|
724
723
|
width={width}>
|
|
725
724
|
{inputWrapper}
|