@astryxdesign/core 0.1.9 → 0.2.0-canary.0f56f82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +107 -0
- package/dist/Avatar/Avatar.d.ts +42 -3
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +190 -59
- package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts +7 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.js +58 -6
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -2
- package/dist/Banner/Banner.js +2 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +11 -4
- package/dist/Breadcrumbs/index.d.ts +1 -0
- package/dist/Breadcrumbs/index.d.ts.map +1 -1
- package/dist/Breadcrumbs/index.js +2 -1
- package/dist/Button/Button.d.ts +1 -1
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +6 -4
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +50 -9
- package/dist/Calendar/dayCellUtils.d.ts +4 -4
- package/dist/Calendar/dayCellUtils.js +2 -2
- package/dist/Calendar/styles.d.ts +30 -31
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +30 -31
- package/dist/Card/Card.js +1 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +22 -12
- package/dist/Chat/ChatComposerInput.js +1 -1
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +3 -1
- package/dist/Chat/ChatLayout.js +4 -4
- package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
- package/dist/Chat/ChatMessageBubble.js +8 -8
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +10 -3
- package/dist/Chat/useTriggerMenu.js +2 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +6 -6
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +19 -4
- package/dist/Citation/Citation.d.ts +22 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +20 -6
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +16 -10
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +3 -1
- package/dist/CommandPalette/CommandPalette.d.ts +1 -1
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +42 -3
- package/dist/CommandPalette/CommandPaletteItem.js +1 -1
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +23 -5
- package/dist/ContextMenu/index.d.ts +1 -0
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +3 -1
- package/dist/DateInput/DateInput.d.ts +10 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +33 -19
- package/dist/DateRangeInput/DateRangeInput.d.ts +10 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +23 -20
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +23 -18
- package/dist/Divider/Divider.d.ts +2 -2
- package/dist/Divider/Divider.d.ts.map +1 -1
- package/dist/Divider/Divider.js +13 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +22 -5
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +4 -1
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +5 -2
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +8 -11
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +3 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +5 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +427 -0
- package/dist/DropdownMenu/index.d.ts +10 -0
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +13 -0
- package/dist/DropdownMenu/menuItemHover.d.ts +23 -0
- package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
- package/dist/DropdownMenu/menuItemHover.js +33 -0
- package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
- package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
- package/dist/DropdownMenu/menuItemRoles.js +10 -1
- package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
- package/dist/DropdownMenu/renderDropdownItems.js +21 -6
- package/dist/Field/Field.d.ts +3 -1
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +4 -1
- package/dist/Field/FieldLabel.d.ts +2 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +9 -5
- package/dist/Field/inputStyles.stylex.d.ts +1 -0
- package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
- package/dist/Field/inputStyles.stylex.js +1 -0
- package/dist/FieldStatus/FieldStatus.d.ts +10 -0
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +51 -5
- package/dist/FileInput/FileInput.d.ts +10 -2
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +93 -65
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +10 -4
- package/dist/Icon/Icon.d.ts +15 -1
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +19 -3
- package/dist/Item/Item.d.ts +16 -3
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +31 -6
- package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
- package/dist/Layer/layerAnimations.stylex.js +10 -2
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +19 -13
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +6 -3
- package/dist/List/ListItem.d.ts +11 -1
- package/dist/List/ListItem.d.ts.map +1 -1
- package/dist/List/ListItem.js +2 -0
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +7 -0
- package/dist/MetadataList/MetadataList.d.ts +1 -1
- package/dist/MetadataList/MetadataList.d.ts.map +1 -1
- package/dist/MetadataList/MetadataList.js +4 -2
- package/dist/MultiSelector/MultiSelector.d.ts +9 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +80 -42
- package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
- package/dist/NumberInput/NumberInput.d.ts +10 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +22 -17
- package/dist/Outline/Outline.js +2 -2
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +11 -3
- package/dist/PowerSearch/PowerSearch.d.ts +9 -2
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +2 -0
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +6 -1
- package/dist/RadioList/RadioList.d.ts +2 -2
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +5 -5
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +49 -19
- package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +5 -3
- package/dist/Selector/Selector.d.ts +8 -0
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +66 -17
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +5 -5
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavCollapseButton.js +13 -10
- package/dist/SideNav/SideNavItem.d.ts +1 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +12 -10
- package/dist/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton/Skeleton.js +2 -2
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +87 -34
- package/dist/Spinner/Spinner.d.ts +3 -2
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +11 -2
- package/dist/Switch/Switch.d.ts +8 -1
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +171 -91
- package/dist/TabList/Tab.js +2 -2
- package/dist/TabList/TabList.d.ts +2 -11
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +5 -9
- package/dist/TabList/TabListContext.d.ts +0 -5
- package/dist/TabList/TabListContext.d.ts.map +1 -1
- package/dist/TabList/TabListContext.js +0 -5
- package/dist/TabList/TabMenu.js +1 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +30 -4
- package/dist/Table/TableCell.js +3 -3
- package/dist/Table/TableHeaderCell.js +3 -3
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +37 -27
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +3 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +15 -7
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +29 -23
- package/dist/Table/types.d.ts +32 -0
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/TextArea/TextArea.d.ts +10 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +18 -19
- package/dist/TextInput/TextInput.d.ts +10 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +20 -17
- package/dist/Thumbnail/Thumbnail.js +2 -2
- package/dist/TimeInput/TimeInput.d.ts +10 -2
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +17 -17
- package/dist/Timestamp/Timestamp.d.ts +31 -3
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +47 -76
- package/dist/Timestamp/formatInstant.d.ts +41 -0
- package/dist/Timestamp/formatInstant.d.ts.map +1 -0
- package/dist/Timestamp/formatInstant.js +177 -0
- package/dist/Timestamp/index.d.ts +1 -0
- package/dist/Timestamp/index.d.ts.map +1 -1
- package/dist/Timestamp/tooltipEntries.d.ts +56 -0
- package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
- package/dist/Timestamp/tooltipEntries.js +163 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +61 -9
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +3 -1
- package/dist/Token/Token.d.ts +34 -4
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +85 -45
- package/dist/Token/TokenLink.d.ts +62 -0
- package/dist/Token/TokenLink.d.ts.map +1 -0
- package/dist/Token/TokenLink.js +76 -0
- package/dist/Token/index.d.ts +1 -1
- package/dist/Token/index.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts +9 -2
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +4 -2
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +17 -1
- package/dist/TopNav/TopNavItem.d.ts +3 -1
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +30 -3
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +9 -3
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +1 -0
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +8 -6
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +32 -14
- package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +22 -11
- package/dist/Typeahead/Typeahead.d.ts +9 -2
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +11 -2
- package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
- package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
- package/dist/Typeahead/TypeaheadItem.js +20 -10
- package/dist/astryx.css +74 -33
- package/dist/astryx.umd.js +51 -51
- package/dist/astryx.umd.js.map +4 -4
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/isRtlElement.d.ts +18 -0
- package/dist/hooks/isRtlElement.d.ts.map +1 -0
- package/dist/hooks/isRtlElement.js +27 -0
- package/dist/hooks/useAnnounce.d.ts +3 -0
- package/dist/hooks/useAnnounce.d.ts.map +1 -1
- package/dist/hooks/useAnnounce.js +39 -1
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +52 -11
- package/dist/hooks/useGridFocus.d.ts +6 -1
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +12 -9
- package/dist/hooks/useHotkeys.d.ts +9 -0
- package/dist/hooks/useHotkeys.d.ts.map +1 -1
- package/dist/hooks/useHotkeys.js +9 -0
- package/dist/hooks/useInputStatusIcon.d.ts +38 -0
- package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
- package/dist/hooks/useInputStatusIcon.js +169 -0
- package/dist/hooks/useKeyboardHint.d.ts +1 -1
- package/dist/hooks/useKeyboardHint.d.ts.map +1 -1
- package/dist/hooks/useKeyboardHint.js +4 -2
- package/dist/hooks/useListFocus.d.ts +39 -1
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +54 -9
- package/dist/i18n/InternationalizationContext.d.ts +1 -0
- package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
- package/dist/i18n/InternationalizationContext.js +3 -0
- package/dist/i18n/InternationalizationProvider.d.ts +8 -1
- package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
- package/dist/i18n/InternationalizationProvider.js +5 -1
- package/dist/i18n/getLocaleDirection.d.ts +18 -0
- package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
- package/dist/i18n/getLocaleDirection.js +29 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +7 -1
- package/dist/i18n/useDirection.d.ts +2 -0
- package/dist/i18n/useDirection.d.ts.map +1 -0
- package/dist/i18n/useDirection.js +27 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +13 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/plainDate.d.ts +17 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +23 -4
- package/dist/utils/rtlStyles.d.ts +24 -0
- package/dist/utils/rtlStyles.d.ts.map +1 -0
- package/dist/utils/rtlStyles.js +27 -0
- package/locales/en.json +112 -0
- package/locales/pseudo.json +84 -0
- package/package.json +6 -1
- package/src/Avatar/Avatar.doc.mjs +50 -3
- package/src/Avatar/Avatar.test.tsx +218 -0
- package/src/Avatar/Avatar.tsx +285 -79
- package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
- package/src/Avatar/AvatarStatusDot.tsx +6 -4
- package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
- package/src/AvatarGroup/AvatarGroup.test.tsx +162 -2
- package/src/AvatarGroup/AvatarGroup.tsx +58 -3
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +5 -2
- package/src/Banner/Banner.tsx +6 -6
- package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +52 -1
- package/src/Breadcrumbs/index.ts +4 -0
- package/src/Button/Button.doc.mjs +0 -4
- package/src/Button/Button.test.tsx +16 -0
- package/src/Button/Button.tsx +6 -4
- package/src/Calendar/Calendar.test.tsx +170 -20
- package/src/Calendar/Calendar.tsx +73 -16
- package/src/Calendar/dayCellUtils.test.ts +18 -18
- package/src/Calendar/dayCellUtils.ts +2 -2
- package/src/Calendar/styles.ts +33 -39
- package/src/Card/Card.tsx +1 -1
- package/src/Carousel/Carousel.tsx +25 -6
- package/src/Chat/ChatComposer.doc.mjs +2 -2
- package/src/Chat/ChatComposerInput.doc.mjs +1 -1
- package/src/Chat/ChatComposerInput.tsx +2 -2
- package/src/Chat/ChatDictationButton.tsx +7 -1
- package/src/Chat/ChatLayout.tsx +4 -4
- package/src/Chat/ChatMessageBubble.tsx +15 -10
- package/src/Chat/ChatSystemMessage.test.tsx +5 -0
- package/src/Chat/ChatToolCalls.tsx +9 -2
- package/src/Chat/useTriggerMenu.tsx +1 -1
- package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +23 -0
- package/src/CheckboxInput/CheckboxInput.tsx +21 -6
- package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
- package/src/CheckboxList/CheckboxList.test.tsx +94 -3
- package/src/CheckboxList/CheckboxListItem.tsx +17 -10
- package/src/Citation/Citation.doc.mjs +4 -3
- package/src/Citation/Citation.test.tsx +97 -0
- package/src/Citation/Citation.tsx +43 -11
- package/src/CodeBlock/CodeBlock.test.tsx +17 -0
- package/src/CodeBlock/CodeBlock.tsx +38 -11
- package/src/Collapsible/Collapsible.doc.mjs +1 -0
- package/src/Collapsible/Collapsible.test.tsx +7 -0
- package/src/Collapsible/Collapsible.tsx +16 -6
- package/src/CommandPalette/CommandPalette.test.tsx +95 -1
- package/src/CommandPalette/CommandPalette.tsx +41 -2
- package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
- package/src/ContextMenu/ContextMenu.test.tsx +59 -2
- package/src/ContextMenu/ContextMenu.tsx +22 -11
- package/src/ContextMenu/index.ts +5 -0
- package/src/DateInput/DateInput.doc.mjs +25 -0
- package/src/DateInput/DateInput.test.tsx +230 -0
- package/src/DateInput/DateInput.tsx +51 -29
- package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
- package/src/DateRangeInput/DateRangeInput.test.tsx +140 -0
- package/src/DateRangeInput/DateRangeInput.tsx +42 -30
- package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
- package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
- package/src/DateTimeInput/DateTimeInput.tsx +44 -39
- package/src/Divider/Divider.test.tsx +32 -8
- package/src/Divider/Divider.tsx +14 -1
- package/src/DropdownMenu/DropdownMenu.test.tsx +60 -0
- package/src/DropdownMenu/DropdownMenu.tsx +31 -12
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +8 -2
- package/src/DropdownMenu/DropdownMenuItem.tsx +9 -3
- package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +4 -12
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +9 -10
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +9 -3
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +20 -2
- package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +635 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +553 -0
- package/src/DropdownMenu/index.ts +16 -0
- package/src/DropdownMenu/menuItemHover.ts +39 -0
- package/src/DropdownMenu/menuItemRoles.ts +9 -0
- package/src/DropdownMenu/renderDropdownItems.tsx +29 -15
- package/src/Field/Field.doc.mjs +4 -0
- package/src/Field/Field.tsx +14 -9
- package/src/Field/FieldLabel.test.tsx +25 -0
- package/src/Field/FieldLabel.tsx +12 -3
- package/src/Field/inputStyles.stylex.ts +2 -0
- package/src/FieldStatus/FieldStatus.doc.mjs +1 -0
- package/src/FieldStatus/FieldStatus.test.tsx +133 -0
- package/src/FieldStatus/FieldStatus.tsx +61 -4
- package/src/FileInput/FileInput.doc.mjs +23 -2
- package/src/FileInput/FileInput.test.tsx +104 -13
- package/src/FileInput/FileInput.tsx +106 -79
- package/src/HoverCard/useHoverCard.tsx +15 -3
- package/src/Icon/Icon.doc.mjs +13 -0
- package/src/Icon/Icon.test.tsx +89 -0
- package/src/Icon/Icon.tsx +51 -3
- package/src/Item/Item.doc.mjs +5 -0
- package/src/Item/Item.test.tsx +88 -0
- package/src/Item/Item.tsx +57 -11
- package/src/Layer/layerAnimations.stylex.ts +23 -0
- package/src/Lightbox/Lightbox.tsx +15 -7
- package/src/List/List.test.tsx +17 -29
- package/src/List/List.tsx +6 -1
- package/src/List/ListItem.doc.mjs +12 -0
- package/src/List/ListItem.tsx +13 -0
- package/src/Markdown/Markdown.test.tsx +21 -0
- package/src/Markdown/Markdown.tsx +4 -0
- package/src/MetadataList/MetadataList.test.tsx +24 -0
- package/src/MetadataList/MetadataList.tsx +6 -2
- package/src/MultiSelector/MultiSelector.doc.mjs +20 -0
- package/src/MultiSelector/MultiSelector.test.tsx +402 -0
- package/src/MultiSelector/MultiSelector.tsx +120 -59
- package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
- package/src/NumberInput/NumberInput.doc.mjs +21 -0
- package/src/NumberInput/NumberInput.test.tsx +71 -0
- package/src/NumberInput/NumberInput.tsx +35 -26
- package/src/Outline/Outline.test.tsx +12 -12
- package/src/Outline/Outline.tsx +2 -2
- package/src/Pagination/Pagination.tsx +11 -3
- package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
- package/src/PowerSearch/PowerSearch.test.tsx +23 -0
- package/src/PowerSearch/PowerSearch.tsx +10 -1
- package/src/ProgressBar/ProgressBar.test.tsx +34 -0
- package/src/ProgressBar/ProgressBar.tsx +16 -1
- package/src/RadioList/RadioList.doc.mjs +6 -0
- package/src/RadioList/RadioList.test.tsx +26 -4
- package/src/RadioList/RadioList.tsx +2 -2
- package/src/RadioList/RadioListItem.tsx +12 -5
- package/src/Resizable/ResizeHandle.test.tsx +94 -0
- package/src/Resizable/ResizeHandle.tsx +70 -20
- package/src/SegmentedControl/SegmentedControl.test.tsx +28 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +22 -2
- package/src/Selector/Selector.doc.mjs +15 -0
- package/src/Selector/Selector.test.tsx +370 -0
- package/src/Selector/Selector.tsx +88 -20
- package/src/SideNav/SideNav.tsx +1 -8
- package/src/SideNav/SideNavCollapseButton.tsx +9 -7
- package/src/SideNav/SideNavItem.tsx +5 -3
- package/src/Skeleton/Skeleton.test.tsx +16 -0
- package/src/Skeleton/Skeleton.tsx +13 -1
- package/src/Slider/Slider.doc.mjs +6 -0
- package/src/Slider/Slider.test.tsx +240 -12
- package/src/Slider/Slider.tsx +96 -23
- package/src/Spinner/Spinner.test.tsx +10 -8
- package/src/Spinner/Spinner.tsx +15 -5
- package/src/Switch/Switch.doc.mjs +142 -42
- package/src/Switch/Switch.test.tsx +111 -0
- package/src/Switch/Switch.tsx +149 -32
- package/src/TabList/Tab.tsx +2 -2
- package/src/TabList/TabList.doc.mjs +0 -6
- package/src/TabList/TabList.test.tsx +3 -15
- package/src/TabList/TabList.tsx +6 -17
- package/src/TabList/TabListContext.ts +0 -6
- package/src/TabList/TabMenu.tsx +2 -2
- package/src/Table/BaseTable.tsx +34 -2
- package/src/Table/Table.doc.mjs +11 -0
- package/src/Table/Table.test.tsx +85 -0
- package/src/Table/TableCell.tsx +3 -3
- package/src/Table/TableHeaderCell.tsx +3 -3
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +19 -0
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +27 -18
- package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
- package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +38 -9
- package/src/Table/plugins/tree/useTableTreeData.tsx +17 -13
- package/src/Table/types.ts +33 -0
- package/src/Table/useTableRowStatus.doc.mjs +1 -1
- package/src/TextArea/TextArea.doc.mjs +21 -0
- package/src/TextArea/TextArea.test.tsx +23 -0
- package/src/TextArea/TextArea.tsx +27 -26
- package/src/TextInput/TextInput.doc.mjs +21 -0
- package/src/TextInput/TextInput.test.tsx +150 -0
- package/src/TextInput/TextInput.tsx +28 -25
- package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
- package/src/Thumbnail/Thumbnail.tsx +1 -1
- package/src/TimeInput/TimeInput.doc.mjs +21 -0
- package/src/TimeInput/TimeInput.test.tsx +23 -0
- package/src/TimeInput/TimeInput.tsx +24 -25
- package/src/Timestamp/Timestamp.doc.mjs +32 -6
- package/src/Timestamp/Timestamp.test.tsx +371 -0
- package/src/Timestamp/Timestamp.tsx +96 -93
- package/src/Timestamp/formatInstant.ts +218 -0
- package/src/Timestamp/index.ts +4 -0
- package/src/Timestamp/tooltipEntries.test.ts +552 -0
- package/src/Timestamp/tooltipEntries.ts +210 -0
- package/src/Toast/ToastViewport.test.tsx +218 -8
- package/src/Toast/ToastViewport.tsx +71 -12
- package/src/ToggleButton/ToggleButton.test.tsx +24 -0
- package/src/ToggleButton/ToggleButton.tsx +19 -1
- package/src/Token/Token.test.tsx +166 -15
- package/src/Token/Token.tsx +104 -47
- package/src/Token/TokenLink.tsx +107 -0
- package/src/Token/index.ts +1 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +23 -1
- package/src/Tokenizer/Tokenizer.test.tsx +23 -0
- package/src/Tokenizer/Tokenizer.tsx +14 -2
- package/src/Tooltip/Tooltip.test.tsx +46 -0
- package/src/Tooltip/useTooltip.tsx +20 -0
- package/src/TopNav/TopNav.test.tsx +93 -2
- package/src/TopNav/TopNavItem.doc.mjs +3 -3
- package/src/TopNav/TopNavItem.tsx +35 -6
- package/src/TopNav/TopNavMegaMenu.tsx +26 -2
- package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
- package/src/TreeList/TreeList.doc.mjs +6 -0
- package/src/TreeList/TreeList.test.tsx +50 -10
- package/src/TreeList/TreeList.tsx +5 -0
- package/src/TreeList/TreeListBranches.tsx +8 -6
- package/src/TreeList/TreeListItem.tsx +33 -11
- package/src/Typeahead/BaseTypeahead.tsx +42 -15
- package/src/Typeahead/Typeahead.doc.mjs +13 -0
- package/src/Typeahead/Typeahead.test.tsx +112 -0
- package/src/Typeahead/Typeahead.tsx +17 -1
- package/src/Typeahead/TypeaheadItem.tsx +2 -1
- package/src/__tests__/forcedColors.ts +60 -0
- package/src/__tests__/inputWidthContract.test.tsx +62 -0
- package/src/doc-mjs.d.ts +19 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/isRtlElement.ts +27 -0
- package/src/hooks/useAnnounce.test.tsx +75 -2
- package/src/hooks/useAnnounce.ts +47 -1
- package/src/hooks/useFocusTrap.test.tsx +104 -0
- package/src/hooks/useFocusTrap.ts +61 -12
- package/src/hooks/useGridFocus.doc.mjs +3 -3
- package/src/hooks/useGridFocus.test.tsx +41 -0
- package/src/hooks/useGridFocus.ts +21 -10
- package/src/hooks/useHotkeys.ts +9 -0
- package/src/hooks/useInputStatusIcon.test.tsx +221 -0
- package/src/hooks/useInputStatusIcon.tsx +235 -0
- package/src/hooks/useKeyboardHint.test.tsx +22 -0
- package/src/hooks/useKeyboardHint.tsx +6 -2
- package/src/hooks/useListFocus.doc.mjs +25 -3
- package/src/hooks/useListFocus.test.tsx +153 -1
- package/src/hooks/useListFocus.ts +102 -9
- package/src/i18n/InternationalizationContext.ts +4 -0
- package/src/i18n/InternationalizationProvider.tsx +12 -2
- package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
- package/src/i18n/__tests__/useDirection.test.tsx +66 -0
- package/src/i18n/getLocaleDirection.ts +29 -0
- package/src/i18n/index.ts +6 -0
- package/src/i18n/useDirection.ts +29 -0
- package/src/reset.css +0 -26
- package/src/reset.test.ts +60 -0
- package/src/theme/derivedVarRegistry.test.ts +1 -0
- package/src/theme/derivedVarRegistry.ts +6 -0
- package/src/theme/generateThemeRules.test.ts +42 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/plainDate.test.ts +24 -6
- package/src/utils/plainDate.ts +18 -4
- package/src/utils/rtlStyles.ts +27 -0
|
@@ -10,6 +10,7 @@ import type {ReactNode} from 'react';
|
|
|
10
10
|
import * as stylex from '@stylexjs/stylex';
|
|
11
11
|
import {Divider} from '../Divider';
|
|
12
12
|
import {DropdownMenuItem} from './DropdownMenuItem';
|
|
13
|
+
import {DropdownMenuSubMenu} from './DropdownMenuSubMenu';
|
|
13
14
|
import {
|
|
14
15
|
spacingVars,
|
|
15
16
|
typographyVars,
|
|
@@ -49,18 +50,14 @@ function getSectionKey(section: DropdownMenuSection, index: number): string {
|
|
|
49
50
|
* Converts data-driven items into DropdownMenuItem components,
|
|
50
51
|
* so both modes share the same rendering and keyboard navigation path.
|
|
51
52
|
*/
|
|
52
|
-
export function renderDropdownItems(
|
|
53
|
-
items: DropdownMenuOption[],
|
|
54
|
-
): ReactNode {
|
|
53
|
+
export function renderDropdownItems(items: DropdownMenuOption[]): ReactNode {
|
|
55
54
|
const elements: ReactNode[] = [];
|
|
56
55
|
|
|
57
56
|
for (let i = 0; i < items.length; i++) {
|
|
58
57
|
const option = items[i];
|
|
59
58
|
|
|
60
59
|
if ('type' in option && option.type === 'divider') {
|
|
61
|
-
elements.push(
|
|
62
|
-
<Divider key={`divider-${i}`} xstyle={styles.divider} />,
|
|
63
|
-
);
|
|
60
|
+
elements.push(<Divider key={`divider-${i}`} xstyle={styles.divider} />);
|
|
64
61
|
} else if ('type' in option && option.type === 'section') {
|
|
65
62
|
elements.push(
|
|
66
63
|
<div
|
|
@@ -84,15 +81,32 @@ export function renderDropdownItems(
|
|
|
84
81
|
</div>,
|
|
85
82
|
);
|
|
86
83
|
} else if (!('type' in option)) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
84
|
+
// A plain item that declares nested `items` becomes a submenu (data-mode
|
|
85
|
+
// parity with the compound DropdownMenuSubMenu API); otherwise it's a
|
|
86
|
+
// leaf. renderDropdownItems owns the recursion and hands the rendered
|
|
87
|
+
// children to DropdownMenuSubMenu — so DropdownMenuSubMenu never imports
|
|
88
|
+
// this module back (no import cycle).
|
|
89
|
+
if (option.items && option.items.length > 0) {
|
|
90
|
+
elements.push(
|
|
91
|
+
<DropdownMenuSubMenu
|
|
92
|
+
key={getItemKey(option)}
|
|
93
|
+
icon={option.icon}
|
|
94
|
+
label={option.label}
|
|
95
|
+
isDisabled={option.isDisabled}>
|
|
96
|
+
{renderDropdownItems(option.items)}
|
|
97
|
+
</DropdownMenuSubMenu>,
|
|
98
|
+
);
|
|
99
|
+
} else {
|
|
100
|
+
elements.push(
|
|
101
|
+
<DropdownMenuItem
|
|
102
|
+
key={getItemKey(option)}
|
|
103
|
+
icon={option.icon}
|
|
104
|
+
label={option.label}
|
|
105
|
+
onClick={option.onClick}
|
|
106
|
+
isDisabled={option.isDisabled}
|
|
107
|
+
/>,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
96
110
|
}
|
|
97
111
|
}
|
|
98
112
|
|
package/src/Field/Field.doc.mjs
CHANGED
|
@@ -30,6 +30,10 @@ export const docs = {
|
|
|
30
30
|
{className: 'astryx-field', visualProps: ['layout']},
|
|
31
31
|
{className: 'astryx-field-label'},
|
|
32
32
|
{className: 'astryx-field-status', visualProps: ['type', 'variant']},
|
|
33
|
+
{
|
|
34
|
+
className: 'astryx-input-status-icon',
|
|
35
|
+
visualProps: ['size', 'status'],
|
|
36
|
+
},
|
|
33
37
|
],
|
|
34
38
|
vars: [
|
|
35
39
|
{name: '--_field-radius', description: 'Border radius of input fields', default: 'var(--radius-element)', private: true},
|
package/src/Field/Field.tsx
CHANGED
|
@@ -22,6 +22,7 @@ import type {BaseProps} from '../BaseProps';
|
|
|
22
22
|
import type {SizeValue} from '../utils/types';
|
|
23
23
|
import {FieldLabel} from './FieldLabel';
|
|
24
24
|
import {FieldStatus} from '../FieldStatus/FieldStatus';
|
|
25
|
+
import type {FieldStatusVariant} from '../FieldStatus/FieldStatus';
|
|
25
26
|
import {spacingVars, borderVars} from '../theme/tokens.stylex';
|
|
26
27
|
import type {IconType} from '../Icon';
|
|
27
28
|
import {mergeProps} from '../utils';
|
|
@@ -156,9 +157,10 @@ export interface FieldProps extends Omit<
|
|
|
156
157
|
* How the status message is rendered relative to the input.
|
|
157
158
|
* - 'attached': Status sits directly below the input (default, for bordered inputs)
|
|
158
159
|
* - 'detached': Status is a separate element below the field (for checkboxes, switches, sliders)
|
|
160
|
+
* - 'tooltip': No message box; the input surfaces status through a tooltip on its on-field icon
|
|
159
161
|
* @default 'attached'
|
|
160
162
|
*/
|
|
161
|
-
statusVariant?:
|
|
163
|
+
statusVariant?: FieldStatusVariant;
|
|
162
164
|
/**
|
|
163
165
|
* Width of the field. Numbers are treated as pixels, strings are used as-is
|
|
164
166
|
* (e.g. `'100%'`). Sizes the whole field — label, control, and status — so
|
|
@@ -239,14 +241,17 @@ export function Field({
|
|
|
239
241
|
/>
|
|
240
242
|
);
|
|
241
243
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
244
|
+
// The 'tooltip' variant surfaces status through the input's on-field icon
|
|
245
|
+
// tooltip, so Field renders no message box for it.
|
|
246
|
+
const statusNode =
|
|
247
|
+
status?.message && statusVariant !== 'tooltip' ? (
|
|
248
|
+
<FieldStatus
|
|
249
|
+
type={status.type}
|
|
250
|
+
message={status.message}
|
|
251
|
+
id={resolvedMessageID}
|
|
252
|
+
variant={statusVariant}
|
|
253
|
+
/>
|
|
254
|
+
) : null;
|
|
250
255
|
|
|
251
256
|
// ─── Horizontal-labels mode ───────────────────────────────────────────
|
|
252
257
|
// Use display:contents so the parent grid's `auto 1fr` columns place
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import {describe, it, expect, vi} from 'vitest';
|
|
13
13
|
import {render, screen} from '@testing-library/react';
|
|
14
14
|
import {TestIcon} from '../__tests__/TestIcon';
|
|
15
|
+
import {InternationalizationProvider} from '../i18n';
|
|
15
16
|
import {FieldLabel} from './FieldLabel';
|
|
16
17
|
|
|
17
18
|
describe('FieldLabel', () => {
|
|
@@ -36,6 +37,30 @@ describe('FieldLabel', () => {
|
|
|
36
37
|
expect(screen.getByText(/Required/)).toBeInTheDocument();
|
|
37
38
|
});
|
|
38
39
|
|
|
40
|
+
it('localizes the required indicator via the i18n provider', () => {
|
|
41
|
+
render(
|
|
42
|
+
<InternationalizationProvider
|
|
43
|
+
locale="fr"
|
|
44
|
+
overrides={{fr: {'@astryx.field.required': 'Obligatoire'}}}>
|
|
45
|
+
<FieldLabel label="Nom" inputID="name-input" isRequired />
|
|
46
|
+
</InternationalizationProvider>,
|
|
47
|
+
);
|
|
48
|
+
expect(screen.getByText(/Obligatoire/)).toBeInTheDocument();
|
|
49
|
+
expect(screen.queryByText(/Required/)).not.toBeInTheDocument();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('localizes the optional indicator via the i18n provider', () => {
|
|
53
|
+
render(
|
|
54
|
+
<InternationalizationProvider
|
|
55
|
+
locale="fr"
|
|
56
|
+
overrides={{fr: {'@astryx.field.optional': 'Facultatif'}}}>
|
|
57
|
+
<FieldLabel label="Nom" inputID="name-input" isOptional />
|
|
58
|
+
</InternationalizationProvider>,
|
|
59
|
+
);
|
|
60
|
+
expect(screen.getByText(/Facultatif/)).toBeInTheDocument();
|
|
61
|
+
expect(screen.queryByText(/Optional/)).not.toBeInTheDocument();
|
|
62
|
+
});
|
|
63
|
+
|
|
39
64
|
it('shows Optional when both isOptional and isRequired are true', () => {
|
|
40
65
|
render(
|
|
41
66
|
<FieldLabel label="Name" inputID="name-input" isOptional isRequired />,
|
package/src/Field/FieldLabel.tsx
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* @file FieldLabel.tsx
|
|
5
|
-
* @input Uses React, Icon, IconType
|
|
7
|
+
* @input Uses React, Icon, IconType, useTranslator
|
|
6
8
|
* @output Exports FieldLabel component, FieldLabelProps
|
|
7
9
|
* @position Core label implementation; used by Field, CheckboxInput, Switch
|
|
8
10
|
*
|
|
@@ -10,6 +12,7 @@
|
|
|
10
12
|
* - /packages/core/src/Field/Field.doc.mjs (props table, features, implementation notes)
|
|
11
13
|
* - /packages/core/src/Field/index.ts (exports if types change)
|
|
12
14
|
* - /packages/cli/templates/blocks/components/Field/ (showcase blocks)
|
|
15
|
+
* - /packages/core/locales/en.json (@astryx.field.required / @astryx.field.optional)
|
|
13
16
|
*/
|
|
14
17
|
|
|
15
18
|
import type {ReactNode} from 'react';
|
|
@@ -26,6 +29,7 @@ import {
|
|
|
26
29
|
} from '../theme/tokens.stylex';
|
|
27
30
|
import {Icon, renderIconSlot, type IconType} from '../Icon';
|
|
28
31
|
import {Tooltip} from '../Tooltip';
|
|
32
|
+
import {useTranslator} from '../i18n';
|
|
29
33
|
import {themeProps} from '../utils/themeProps';
|
|
30
34
|
|
|
31
35
|
const styles = stylex.create({
|
|
@@ -48,7 +52,7 @@ const styles = stylex.create({
|
|
|
48
52
|
borderStyle: 'none',
|
|
49
53
|
clip: 'rect(0, 0, 0, 0)',
|
|
50
54
|
height: 1,
|
|
51
|
-
|
|
55
|
+
insetInlineStart: 0,
|
|
52
56
|
margin: -1,
|
|
53
57
|
overflow: 'hidden',
|
|
54
58
|
padding: 0,
|
|
@@ -177,7 +181,12 @@ export function FieldLabel({
|
|
|
177
181
|
ref,
|
|
178
182
|
...rest
|
|
179
183
|
}: FieldLabelProps) {
|
|
180
|
-
const
|
|
184
|
+
const t = useTranslator();
|
|
185
|
+
const statusText = isOptional
|
|
186
|
+
? t('@astryx.field.optional')
|
|
187
|
+
: isRequired
|
|
188
|
+
? t('@astryx.field.required')
|
|
189
|
+
: null;
|
|
181
190
|
|
|
182
191
|
// A group label (e.g. for a radiogroup) must not be a literal `<label>`
|
|
183
192
|
// element: a `<label>` semantically names a single form control and can't be
|
|
@@ -67,6 +67,8 @@ export const inputWrapperStyles = stylex.create({
|
|
|
67
67
|
cursor: 'not-allowed',
|
|
68
68
|
opacity: 0.5,
|
|
69
69
|
borderColor: colorVars['--color-border-emphasized'],
|
|
70
|
+
// Suppress the base hover ring — a disabled control must not react to hover.
|
|
71
|
+
boxShadow: 'none',
|
|
70
72
|
},
|
|
71
73
|
});
|
|
72
74
|
|
|
@@ -300,6 +300,139 @@ describe('FieldStatus', () => {
|
|
|
300
300
|
});
|
|
301
301
|
});
|
|
302
302
|
|
|
303
|
+
// The detached message must convey status by more than color/position:
|
|
304
|
+
// a leading status glyph precedes the message text (WCAG 1.4.1). The glyph
|
|
305
|
+
// is decorative for AT (aria-hidden) because the message text already names
|
|
306
|
+
// the status in words and it is announced via the live region.
|
|
307
|
+
describe('detached leading status icon (use-of-color a11y)', () => {
|
|
308
|
+
it('renders a leading status icon before the message for the detached variant', () => {
|
|
309
|
+
render(
|
|
310
|
+
<FieldStatus
|
|
311
|
+
type="error"
|
|
312
|
+
message="Something went wrong"
|
|
313
|
+
variant="detached"
|
|
314
|
+
data-testid="fs"
|
|
315
|
+
/>,
|
|
316
|
+
);
|
|
317
|
+
const el = screen.getByTestId('fs');
|
|
318
|
+
const icon = el.querySelector('[aria-hidden="true"]');
|
|
319
|
+
const text = screen.getByText('Something went wrong');
|
|
320
|
+
expect(icon).toBeInTheDocument();
|
|
321
|
+
// Icon comes before the message text in document order.
|
|
322
|
+
expect(
|
|
323
|
+
icon!.compareDocumentPosition(text) & Node.DOCUMENT_POSITION_FOLLOWING,
|
|
324
|
+
).toBeTruthy();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('marks the status icon aria-hidden (visual redundancy, not a second announcement)', () => {
|
|
328
|
+
render(
|
|
329
|
+
<FieldStatus
|
|
330
|
+
type="warning"
|
|
331
|
+
message="Heads up"
|
|
332
|
+
variant="detached"
|
|
333
|
+
data-testid="fs"
|
|
334
|
+
/>,
|
|
335
|
+
);
|
|
336
|
+
const icon = screen
|
|
337
|
+
.getByTestId('fs')
|
|
338
|
+
.querySelector('[aria-hidden="true"]');
|
|
339
|
+
expect(icon).toBeInTheDocument();
|
|
340
|
+
expect(icon).toHaveAttribute('aria-hidden', 'true');
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('renders a status icon for each status type in the detached variant', () => {
|
|
344
|
+
for (const type of ['error', 'warning', 'success'] as const) {
|
|
345
|
+
const {unmount} = render(
|
|
346
|
+
<FieldStatus
|
|
347
|
+
type={type}
|
|
348
|
+
message="msg"
|
|
349
|
+
variant="detached"
|
|
350
|
+
data-testid="fs"
|
|
351
|
+
/>,
|
|
352
|
+
);
|
|
353
|
+
expect(
|
|
354
|
+
screen.getByTestId('fs').querySelector('[aria-hidden="true"]'),
|
|
355
|
+
).toBeInTheDocument();
|
|
356
|
+
unmount();
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('does not render a leading status icon for the attached variant', () => {
|
|
361
|
+
render(
|
|
362
|
+
<FieldStatus
|
|
363
|
+
type="error"
|
|
364
|
+
message="msg"
|
|
365
|
+
variant="attached"
|
|
366
|
+
data-testid="fs"
|
|
367
|
+
/>,
|
|
368
|
+
);
|
|
369
|
+
expect(
|
|
370
|
+
screen.getByTestId('fs').querySelector('[aria-hidden="true"]'),
|
|
371
|
+
).toBeNull();
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
describe('field-status-icon theme target', () => {
|
|
376
|
+
// The stable theme target lands on the detached message box's leading glyph
|
|
377
|
+
// itself, so a theme can restyle (e.g. resize) just this icon via
|
|
378
|
+
// `defineTheme`. It reflects the status type as a data attribute so themes
|
|
379
|
+
// can target per status, mirroring the parent astryx-field-status.
|
|
380
|
+
const getStatusIcon = (root: HTMLElement): HTMLElement => {
|
|
381
|
+
const icon = root.querySelector('.astryx-field-status-icon');
|
|
382
|
+
if (icon == null) {
|
|
383
|
+
throw new Error('status icon not found');
|
|
384
|
+
}
|
|
385
|
+
return icon as HTMLElement;
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
it('renders the target on the detached leading icon', () => {
|
|
389
|
+
render(
|
|
390
|
+
<FieldStatus
|
|
391
|
+
type="error"
|
|
392
|
+
message="msg"
|
|
393
|
+
variant="detached"
|
|
394
|
+
data-testid="fs"
|
|
395
|
+
/>,
|
|
396
|
+
);
|
|
397
|
+
const icon = getStatusIcon(screen.getByTestId('fs'));
|
|
398
|
+
expect(icon).toHaveClass('astryx-field-status-icon');
|
|
399
|
+
expect(icon).toHaveClass('astryx-icon');
|
|
400
|
+
expect(icon).toHaveAttribute('data-type', 'error');
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it('reflects the status type per status', () => {
|
|
404
|
+
for (const type of ['error', 'warning', 'success'] as const) {
|
|
405
|
+
const {unmount} = render(
|
|
406
|
+
<FieldStatus
|
|
407
|
+
type={type}
|
|
408
|
+
message="msg"
|
|
409
|
+
variant="detached"
|
|
410
|
+
data-testid="fs"
|
|
411
|
+
/>,
|
|
412
|
+
);
|
|
413
|
+
expect(getStatusIcon(screen.getByTestId('fs'))).toHaveAttribute(
|
|
414
|
+
'data-type',
|
|
415
|
+
type,
|
|
416
|
+
);
|
|
417
|
+
unmount();
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('does not render the target for the attached variant', () => {
|
|
422
|
+
render(
|
|
423
|
+
<FieldStatus
|
|
424
|
+
type="error"
|
|
425
|
+
message="msg"
|
|
426
|
+
variant="attached"
|
|
427
|
+
data-testid="fs"
|
|
428
|
+
/>,
|
|
429
|
+
);
|
|
430
|
+
expect(
|
|
431
|
+
screen.getByTestId('fs').querySelector('.astryx-field-status-icon'),
|
|
432
|
+
).toBeNull();
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
|
|
303
436
|
describe('edge cases', () => {
|
|
304
437
|
it('renders an empty message without crashing', () => {
|
|
305
438
|
render(<FieldStatus type="error" message="" data-testid="fs" />);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @file FieldStatus.tsx
|
|
5
|
-
* @input Uses React, stylex, theme tokens, useAnnounce
|
|
5
|
+
* @input Uses React, stylex, theme tokens, useAnnounce, Icon
|
|
6
6
|
* @output Exports FieldStatus component, FieldStatusProps
|
|
7
7
|
* @position Core implementation; consumed by Field, Switch, CheckboxInput, and the FieldStatus entrypoint
|
|
8
8
|
*
|
|
@@ -31,6 +31,19 @@ import {
|
|
|
31
31
|
import type {InputStatusType} from '../Field/types';
|
|
32
32
|
import {useEntryAnimation} from '../hooks/useEntryAnimation';
|
|
33
33
|
import {themeProps} from '../utils/themeProps';
|
|
34
|
+
import {Icon} from '../Icon';
|
|
35
|
+
import type {IconName} from '../Icon';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Maps each status type to its status glyph. Mirrors the mapping the input
|
|
39
|
+
* controls already use for the on-field status affordance, so the detached
|
|
40
|
+
* message shows the same icon a consumer sees elsewhere for that status.
|
|
41
|
+
*/
|
|
42
|
+
const statusIconMap: Record<InputStatusType, IconName> = {
|
|
43
|
+
warning: 'warning',
|
|
44
|
+
error: 'error',
|
|
45
|
+
success: 'success',
|
|
46
|
+
};
|
|
34
47
|
|
|
35
48
|
const styles = stylex.create({
|
|
36
49
|
base: {
|
|
@@ -43,8 +56,8 @@ const styles = stylex.create({
|
|
|
43
56
|
paddingBlockStart: `calc(${spacingVars['--spacing-1-5']} + ${spacingVars['--spacing-2']})`,
|
|
44
57
|
paddingBlockEnd: spacingVars['--spacing-2'],
|
|
45
58
|
paddingInline: spacingVars['--spacing-2'],
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
borderEndStartRadius: radiusVars['--radius-element'],
|
|
60
|
+
borderEndEndRadius: radiusVars['--radius-element'],
|
|
48
61
|
},
|
|
49
62
|
detached: {
|
|
50
63
|
marginTop: spacingVars['--spacing-1'],
|
|
@@ -52,6 +65,20 @@ const styles = stylex.create({
|
|
|
52
65
|
paddingInline: spacingVars['--spacing-2'],
|
|
53
66
|
borderRadius: radiusVars['--radius-element'],
|
|
54
67
|
},
|
|
68
|
+
detachedContent: {
|
|
69
|
+
display: 'flex',
|
|
70
|
+
alignItems: 'flex-start',
|
|
71
|
+
gap: spacingVars['--spacing-1'],
|
|
72
|
+
},
|
|
73
|
+
detachedIcon: {
|
|
74
|
+
// Center the glyph within the first text-line box so it aligns to the
|
|
75
|
+
// first line of the message (rather than the top of the flex row) when the
|
|
76
|
+
// message wraps to multiple lines.
|
|
77
|
+
display: 'inline-flex',
|
|
78
|
+
alignItems: 'center',
|
|
79
|
+
height: `calc(${typeScaleVars['--text-supporting-size']} * ${typeScaleVars['--text-supporting-leading']})`,
|
|
80
|
+
flexShrink: 0,
|
|
81
|
+
},
|
|
55
82
|
});
|
|
56
83
|
|
|
57
84
|
const colorStyles = stylex.create({
|
|
@@ -85,6 +112,7 @@ const colorStyles = stylex.create({
|
|
|
85
112
|
export interface FieldStatusVariantMap {
|
|
86
113
|
attached: true;
|
|
87
114
|
detached: true;
|
|
115
|
+
tooltip: true;
|
|
88
116
|
}
|
|
89
117
|
|
|
90
118
|
/**
|
|
@@ -114,6 +142,15 @@ export interface FieldStatusProps extends BaseProps<HTMLDivElement> {
|
|
|
114
142
|
/**
|
|
115
143
|
* A status message component for form fields.
|
|
116
144
|
*
|
|
145
|
+
* The `detached` variant renders a leading status icon before the message so
|
|
146
|
+
* status is not conveyed by color or position alone (WCAG 1.4.1). The icon is
|
|
147
|
+
* decorative for assistive tech (`aria-hidden`): the message text already names
|
|
148
|
+
* the status in words and is announced through the live region. The `attached`
|
|
149
|
+
* variant keeps its status affordance on the bordered input, so it renders no
|
|
150
|
+
* icon here to avoid a duplicate. The `tooltip` variant renders no message box
|
|
151
|
+
* at all — the input surfaces the status through a tooltip on its on-field
|
|
152
|
+
* icon — so callers skip rendering FieldStatus for it.
|
|
153
|
+
*
|
|
117
154
|
* Screen-reader announcements go through the persistent `useAnnounce` live
|
|
118
155
|
* regions (assertive for errors, polite otherwise) rather than `role`/
|
|
119
156
|
* `aria-live` on the rendered element. Live regions that mount together with
|
|
@@ -176,7 +213,27 @@ export function FieldStatus({
|
|
|
176
213
|
className,
|
|
177
214
|
style,
|
|
178
215
|
)}>
|
|
179
|
-
{
|
|
216
|
+
{variant === 'detached' ? (
|
|
217
|
+
<span {...stylex.props(styles.detachedContent)}>
|
|
218
|
+
<span {...stylex.props(styles.detachedIcon)}>
|
|
219
|
+
<Icon
|
|
220
|
+
icon={statusIconMap[type]}
|
|
221
|
+
size="sm"
|
|
222
|
+
color="inherit"
|
|
223
|
+
// Stable theme target on the detached message box's leading glyph
|
|
224
|
+
// itself, so a theme can restyle just this icon (color, size) —
|
|
225
|
+
// and each status — via `defineTheme`. Same-element rules in
|
|
226
|
+
// @layer astryx-theme win over the icon's own base
|
|
227
|
+
// width/height/fontSize, which a field-level target could not
|
|
228
|
+
// reach.
|
|
229
|
+
{...themeProps('field-status-icon', {type})}
|
|
230
|
+
/>
|
|
231
|
+
</span>
|
|
232
|
+
<span>{message}</span>
|
|
233
|
+
</span>
|
|
234
|
+
) : (
|
|
235
|
+
message
|
|
236
|
+
)}
|
|
180
237
|
</div>
|
|
181
238
|
);
|
|
182
239
|
}
|
|
@@ -78,7 +78,7 @@ export const docs = {
|
|
|
78
78
|
name: 'isRequired',
|
|
79
79
|
type: 'boolean',
|
|
80
80
|
description:
|
|
81
|
-
'Displays a "Required" indicator next to the label and
|
|
81
|
+
'Displays a "Required" indicator next to the label and adds a screen-reader-only "Required" description to the trigger (assistive tech does not reliably announce aria-required on the trigger). Mutually exclusive with isOptional.',
|
|
82
82
|
default: 'false',
|
|
83
83
|
},
|
|
84
84
|
{
|
|
@@ -119,12 +119,25 @@ export const docs = {
|
|
|
119
119
|
description:
|
|
120
120
|
'Validation status: applies a colored border. If message is provided, displays a floating message below the input. Error type also sets aria-invalid.',
|
|
121
121
|
},
|
|
122
|
+
{
|
|
123
|
+
name: 'statusVariant',
|
|
124
|
+
type: "'attached' | 'detached' | 'tooltip'",
|
|
125
|
+
description:
|
|
126
|
+
'How the status message is placed relative to the input. attached overlaps directly below the input (bordered treatment); detached floats below as a separate element with spacing; tooltip hides the message box and surfaces it in a tooltip on the status icon.',
|
|
127
|
+
default: "'attached'",
|
|
128
|
+
},
|
|
122
129
|
{
|
|
123
130
|
name: 'labelTooltip',
|
|
124
131
|
type: 'string',
|
|
125
132
|
description:
|
|
126
133
|
'Tooltip text displayed in an info icon at the end of the label.',
|
|
127
134
|
},
|
|
135
|
+
{
|
|
136
|
+
name: 'width',
|
|
137
|
+
type: 'SizeValue',
|
|
138
|
+
description:
|
|
139
|
+
'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.',
|
|
140
|
+
},
|
|
128
141
|
],
|
|
129
142
|
theming: {
|
|
130
143
|
targets: [
|
|
@@ -246,6 +259,13 @@ export const docsZh = {
|
|
|
246
259
|
type: "{type: 'error' | 'warning' | 'success', message?: string}",
|
|
247
260
|
description: '验证状态。',
|
|
248
261
|
},
|
|
262
|
+
{
|
|
263
|
+
name: 'statusVariant',
|
|
264
|
+
type: "'attached' | 'detached' | 'tooltip'",
|
|
265
|
+
description:
|
|
266
|
+
'状态消息相对于输入框的放置方式。attached 直接叠加在输入框下方(带边框处理);detached 作为独立元素浮于下方并留有间距;tooltip 隐藏消息框,并在状态图标上以提示气泡形式显示。',
|
|
267
|
+
default: "'attached'",
|
|
268
|
+
},
|
|
249
269
|
],
|
|
250
270
|
theming: {
|
|
251
271
|
targets: [
|
|
@@ -308,7 +328,7 @@ export const docsDense = {
|
|
|
308
328
|
isLabelHidden: 'Visually hides label; keeps screen reader access.',
|
|
309
329
|
description: 'Description text between label+input.',
|
|
310
330
|
isOptional: 'Shows "Optional" indicator.',
|
|
311
|
-
isRequired: 'Shows "Required" indicator+
|
|
331
|
+
isRequired: 'Shows "Required" indicator+SR-only trigger description.',
|
|
312
332
|
isDisabled: 'Disables input, prevents interaction.',
|
|
313
333
|
disabledMessage:
|
|
314
334
|
'Explains why input is disabled. With isDisabled, shows tooltip on hover/focus + keeps trigger focusable via aria-disabled (opening picker stays blocked). Use instead of wrapping a disabled FileInput in Tooltip.',
|
|
@@ -316,6 +336,7 @@ export const docsDense = {
|
|
|
316
336
|
placeholder: 'Placeholder when no files selected.',
|
|
317
337
|
mode: "Visual mode: 'input' (compact) or 'dropzone' (drag-and-drop).",
|
|
318
338
|
status: 'Validation status; colored border. Message floats below.',
|
|
339
|
+
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.',
|
|
319
340
|
labelTooltip: 'Tooltip in info icon at label end.',
|
|
320
341
|
},
|
|
321
342
|
};
|