@astryxdesign/core 0.1.9-canary.d2d84f8 → 0.1.9-canary.e00a241
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/dist/Avatar/Avatar.d.ts +6 -1
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +46 -12
- package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- 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/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/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +3 -1
- 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/CheckboxInput/CheckboxInput.js +4 -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 +13 -7
- 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/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +14 -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 +1 -0
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +31 -19
- package/dist/DateRangeInput/DateRangeInput.d.ts +1 -0
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +20 -19
- 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 +4 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +4 -1
- 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/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 +4 -1
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +4 -2
- package/dist/FileInput/FileInput.d.ts +1 -0
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +91 -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/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +15 -9
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +6 -3
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +7 -0
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +65 -40
- package/dist/NumberInput/NumberInput.d.ts +1 -0
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +20 -17
- package/dist/Outline/Outline.js +2 -2
- package/dist/RadioList/RadioList.d.ts +2 -2
- package/dist/RadioList/RadioListItem.js +4 -4
- 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 +2 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +58 -16
- 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/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 +160 -91
- 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/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +30 -4
- 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 +36 -26
- 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 +14 -6
- 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 +1 -0
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +16 -19
- package/dist/TextInput/TextInput.d.ts +1 -0
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +18 -17
- package/dist/TimeInput/TimeInput.d.ts +1 -0
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +15 -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/Token/Token.d.ts +30 -3
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +17 -2
- package/dist/Token/index.d.ts +1 -1
- package/dist/Token/index.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +2 -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.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +19 -10
- package/dist/Typeahead/Typeahead.js +1 -1
- 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 +38 -14
- package/dist/astryx.umd.js +52 -52
- 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/useListFocus.d.ts +39 -1
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +54 -9
- 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 +76 -0
- package/locales/pseudo.json +57 -0
- package/package.json +6 -1
- package/src/Avatar/Avatar.doc.mjs +18 -4
- package/src/Avatar/Avatar.test.tsx +106 -0
- package/src/Avatar/Avatar.tsx +62 -10
- package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
- package/src/Avatar/AvatarStatusDot.tsx +6 -4
- package/src/AvatarGroup/AvatarGroup.test.tsx +16 -1
- package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +51 -0
- package/src/Breadcrumbs/index.ts +4 -0
- package/src/Button/Button.doc.mjs +0 -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/ChatDictationButton.tsx +7 -1
- package/src/Chat/ChatMessageBubble.tsx +15 -10
- package/src/Chat/ChatSystemMessage.test.tsx +5 -0
- package/src/Chat/ChatToolCalls.tsx +9 -2
- package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
- package/src/CheckboxInput/CheckboxInput.tsx +4 -4
- package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
- 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.tsx +35 -8
- 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/ContextMenu/ContextMenu.test.tsx +42 -0
- package/src/ContextMenu/ContextMenu.tsx +13 -11
- package/src/ContextMenu/index.ts +5 -0
- package/src/DateInput/DateInput.doc.mjs +15 -5
- package/src/DateInput/DateInput.test.tsx +210 -3
- package/src/DateInput/DateInput.tsx +41 -29
- package/src/DateRangeInput/DateRangeInput.doc.mjs +11 -3
- package/src/DateRangeInput/DateRangeInput.test.tsx +120 -3
- package/src/DateRangeInput/DateRangeInput.tsx +29 -27
- 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 +8 -2
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +8 -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/inputStyles.stylex.ts +2 -0
- package/src/FieldStatus/FieldStatus.tsx +10 -4
- package/src/FileInput/FileInput.doc.mjs +13 -7
- package/src/FileInput/FileInput.test.tsx +84 -16
- package/src/FileInput/FileInput.tsx +96 -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/Lightbox/Lightbox.tsx +11 -3
- package/src/List/List.test.tsx +17 -29
- package/src/List/List.tsx +6 -1
- package/src/Markdown/Markdown.test.tsx +21 -0
- package/src/Markdown/Markdown.tsx +4 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +11 -0
- package/src/MultiSelector/MultiSelector.test.tsx +306 -3
- package/src/MultiSelector/MultiSelector.tsx +88 -57
- package/src/NumberInput/NumberInput.doc.mjs +11 -5
- package/src/NumberInput/NumberInput.test.tsx +48 -0
- package/src/NumberInput/NumberInput.tsx +25 -26
- package/src/Outline/Outline.test.tsx +12 -12
- package/src/Outline/Outline.tsx +2 -2
- package/src/RadioList/RadioList.doc.mjs +6 -0
- package/src/RadioList/RadioList.tsx +2 -2
- package/src/RadioList/RadioListItem.tsx +4 -4
- package/src/Resizable/ResizeHandle.test.tsx +94 -0
- package/src/Resizable/ResizeHandle.tsx +70 -20
- package/src/SegmentedControl/SegmentedControlItem.tsx +2 -0
- package/src/Selector/Selector.doc.mjs +8 -0
- package/src/Selector/Selector.test.tsx +328 -3
- package/src/Selector/Selector.tsx +70 -19
- package/src/SideNav/SideNav.tsx +1 -8
- package/src/SideNav/SideNavCollapseButton.tsx +9 -7
- package/src/SideNav/SideNavItem.tsx +5 -3
- 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 +22 -0
- package/src/Switch/Switch.tsx +90 -33
- 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/Table/BaseTable.tsx +34 -2
- package/src/Table/Table.doc.mjs +11 -0
- package/src/Table/Table.test.tsx +85 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +24 -17
- 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 +37 -8
- 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 +11 -5
- package/src/TextArea/TextArea.tsx +17 -26
- package/src/TextInput/TextInput.doc.mjs +11 -5
- package/src/TextInput/TextInput.test.tsx +130 -3
- package/src/TextInput/TextInput.tsx +18 -25
- package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
- package/src/TimeInput/TimeInput.doc.mjs +11 -5
- package/src/TimeInput/TimeInput.tsx +14 -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/Token/Token.test.tsx +21 -15
- package/src/Token/Token.tsx +31 -14
- package/src/Token/index.ts +1 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +8 -1
- package/src/Tokenizer/Tokenizer.tsx +4 -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 +29 -14
- package/src/Typeahead/Typeahead.doc.mjs +6 -0
- package/src/Typeahead/Typeahead.test.tsx +27 -0
- package/src/Typeahead/Typeahead.tsx +1 -1
- package/src/Typeahead/TypeaheadItem.tsx +2 -1
- 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/useListFocus.doc.mjs +25 -3
- package/src/hooks/useListFocus.test.tsx +153 -1
- package/src/hooks/useListFocus.ts +102 -9
- 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
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
useTransition,
|
|
26
26
|
} from 'react';
|
|
27
27
|
import * as stylex from '@stylexjs/stylex';
|
|
28
|
-
import type {IconName} from '../Icon';
|
|
29
28
|
import {
|
|
30
29
|
colorVars,
|
|
31
30
|
sizeVars,
|
|
@@ -37,7 +36,6 @@ import {
|
|
|
37
36
|
import {
|
|
38
37
|
Field,
|
|
39
38
|
type InputStatus,
|
|
40
|
-
type InputStatusType,
|
|
41
39
|
inputWrapperStyles,
|
|
42
40
|
inputStatusBorderStyles,
|
|
43
41
|
inputStatusHoverShadowStyles,
|
|
@@ -52,6 +50,7 @@ import {useSize} from '../SizeContext/SizeContext';
|
|
|
52
50
|
import {Spinner} from '../Spinner';
|
|
53
51
|
import {Calendar, type ISODateString, type CalendarHandle} from '../Calendar';
|
|
54
52
|
import {useCalendarConstraints} from '../Calendar/hooks';
|
|
53
|
+
import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
|
|
55
54
|
import {usePopover} from '../Popover';
|
|
56
55
|
import {useTooltip} from '../Tooltip';
|
|
57
56
|
import {getInputARIA, parseDateInput} from '../utils';
|
|
@@ -283,6 +282,7 @@ export interface DateInputProps extends Omit<
|
|
|
283
282
|
* How the status message is placed relative to the input.
|
|
284
283
|
* - 'attached': message overlaps directly below the input (bordered treatment)
|
|
285
284
|
* - 'detached': message floats below as a separate element with spacing
|
|
285
|
+
* - 'tooltip': no message box; the status icon becomes a focusable info-tip button that reveals the message on hover, keyboard focus, or tap
|
|
286
286
|
* @default 'attached'
|
|
287
287
|
*/
|
|
288
288
|
statusVariant?: FieldStatusVariant;
|
|
@@ -419,30 +419,24 @@ export function DateInput({
|
|
|
419
419
|
isEnabled: showsDisabledMessage,
|
|
420
420
|
});
|
|
421
421
|
|
|
422
|
-
// Status icon mapping
|
|
423
|
-
const statusIconMap: Record<InputStatusType, IconName> = {
|
|
424
|
-
warning: 'warning',
|
|
425
|
-
error: 'error',
|
|
426
|
-
success: 'success',
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
const statusIconColorMap: Record<
|
|
430
|
-
InputStatusType,
|
|
431
|
-
'warning' | 'error' | 'success'
|
|
432
|
-
> = {
|
|
433
|
-
warning: 'warning',
|
|
434
|
-
error: 'error',
|
|
435
|
-
success: 'success',
|
|
436
|
-
};
|
|
437
|
-
|
|
438
422
|
// Constraint checking for text input validation (reuses calendar logic)
|
|
439
423
|
const {isDateDisabled} = useCalendarConstraints({min, max, dateConstraints});
|
|
440
424
|
|
|
425
|
+
const {statusIcon, describedBy: statusTooltipDescribedBy} =
|
|
426
|
+
useInputStatusIcon({
|
|
427
|
+
status,
|
|
428
|
+
statusVariant,
|
|
429
|
+
isInGroup: !!inputGroup,
|
|
430
|
+
});
|
|
431
|
+
|
|
441
432
|
const {ariaLabelledBy, ariaDescribedBy} = getInputARIA(
|
|
442
433
|
inputLabelID,
|
|
443
434
|
[
|
|
444
435
|
description ? descriptionID : null,
|
|
445
|
-
status?.message ? statusMessageID : null,
|
|
436
|
+
statusVariant !== 'tooltip' && status?.message ? statusMessageID : null,
|
|
437
|
+
// The tooltip variant renders no message box; describe the input by the
|
|
438
|
+
// tooltip's content instead so the status is still announced.
|
|
439
|
+
statusTooltipDescribedBy,
|
|
446
440
|
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
447
441
|
],
|
|
448
442
|
inputGroup,
|
|
@@ -647,7 +641,9 @@ export function DateInput({
|
|
|
647
641
|
sizeStyles[size],
|
|
648
642
|
isEffectivelyDisabled && inputWrapperStyles.disabled,
|
|
649
643
|
status && inputStatusBorderStyles[status.type],
|
|
650
|
-
status &&
|
|
644
|
+
status &&
|
|
645
|
+
!isEffectivelyDisabled &&
|
|
646
|
+
inputStatusHoverShadowStyles[status.type],
|
|
651
647
|
status && inputStatusFocusWithinStyles[status.type],
|
|
652
648
|
inputGroup && groupStyles.inGroup,
|
|
653
649
|
xstyle,
|
|
@@ -669,7 +665,20 @@ export function DateInput({
|
|
|
669
665
|
styles.iconButton,
|
|
670
666
|
isEffectivelyDisabled && styles.iconButtonDisabled,
|
|
671
667
|
)}>
|
|
672
|
-
<Icon
|
|
668
|
+
<Icon
|
|
669
|
+
icon="calendar"
|
|
670
|
+
size="sm"
|
|
671
|
+
color="secondary"
|
|
672
|
+
// Stable theme target on the toggle glyph itself, so a theme can
|
|
673
|
+
// restyle just this icon (color, size, hover) — and each open/closed
|
|
674
|
+
// state — via `defineTheme`. Same-element rules in @layer astryx-theme
|
|
675
|
+
// win over the icon's own base color/size, which a button-level target
|
|
676
|
+
// could not reach. Reflects the popover's open/closed state as a
|
|
677
|
+
// `data-state` attribute.
|
|
678
|
+
{...themeProps('date-input-toggle-icon', {
|
|
679
|
+
state: popover.isOpen ? 'expanded' : 'collapsed',
|
|
680
|
+
})}
|
|
681
|
+
/>
|
|
673
682
|
</button>
|
|
674
683
|
<input
|
|
675
684
|
ref={mergeRefs(ref, inputRef)}
|
|
@@ -721,17 +730,20 @@ export function DateInput({
|
|
|
721
730
|
onClick={handleClear}
|
|
722
731
|
aria-label={t('@astryx.dateInput.clear', {label})}
|
|
723
732
|
{...stylex.props(styles.iconButton)}>
|
|
724
|
-
<Icon
|
|
733
|
+
<Icon
|
|
734
|
+
icon="close"
|
|
735
|
+
size="sm"
|
|
736
|
+
color="secondary"
|
|
737
|
+
// Stable theme target on the clear glyph itself, so a theme can
|
|
738
|
+
// restyle just this icon (color, size, hover) via `defineTheme`.
|
|
739
|
+
// Same-element rules in @layer astryx-theme win over the icon's own
|
|
740
|
+
// base color/size, which a button-level target could not reach.
|
|
741
|
+
{...themeProps('date-input-clear-icon')}
|
|
742
|
+
/>
|
|
725
743
|
</button>
|
|
726
744
|
)}
|
|
727
745
|
{isBusy && <Spinner size="sm" />}
|
|
728
|
-
{
|
|
729
|
-
<Icon
|
|
730
|
-
icon={statusIconMap[status.type]}
|
|
731
|
-
size="md"
|
|
732
|
-
color={statusIconColorMap[status.type]}
|
|
733
|
-
/>
|
|
734
|
-
)}
|
|
746
|
+
{statusIcon}
|
|
735
747
|
{popover.render(
|
|
736
748
|
<Calendar
|
|
737
749
|
handleRef={calendarRef}
|
|
@@ -129,9 +129,9 @@ export const docs = {
|
|
|
129
129
|
},
|
|
130
130
|
{
|
|
131
131
|
name: 'statusVariant',
|
|
132
|
-
type: "'attached' | 'detached'",
|
|
132
|
+
type: "'attached' | 'detached' | 'tooltip'",
|
|
133
133
|
description:
|
|
134
|
-
'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.',
|
|
134
|
+
'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.',
|
|
135
135
|
default: "'attached'",
|
|
136
136
|
},
|
|
137
137
|
{
|
|
@@ -145,6 +145,12 @@ export const docs = {
|
|
|
145
145
|
description: 'Number of months in the calendar.',
|
|
146
146
|
default: '2',
|
|
147
147
|
},
|
|
148
|
+
{
|
|
149
|
+
name: 'width',
|
|
150
|
+
type: 'SizeValue',
|
|
151
|
+
description:
|
|
152
|
+
'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.',
|
|
153
|
+
},
|
|
148
154
|
{
|
|
149
155
|
name: 'xstyle',
|
|
150
156
|
type: 'StyleXStyles',
|
|
@@ -154,6 +160,8 @@ export const docs = {
|
|
|
154
160
|
theming: {
|
|
155
161
|
targets: [
|
|
156
162
|
{className: 'astryx-date-range-input', visualProps: ['size', 'status']},
|
|
163
|
+
{className: 'astryx-date-range-input-toggle-icon', states: ['state']},
|
|
164
|
+
{className: 'astryx-date-range-input-clear-icon'},
|
|
157
165
|
],
|
|
158
166
|
},
|
|
159
167
|
usage: {
|
|
@@ -303,7 +311,7 @@ export const docsDense = {
|
|
|
303
311
|
placeholder: 'placeholder when empty',
|
|
304
312
|
size: 'trigger size',
|
|
305
313
|
status: 'error/warning/success status',
|
|
306
|
-
statusVariant: 'How status message is placed: attached overlaps below input; detached floats below w/ spacing.',
|
|
314
|
+
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.',
|
|
307
315
|
labelTooltip: 'tooltip via info icon at label end',
|
|
308
316
|
numberOfMonths: 'months in calendar (default 2)',
|
|
309
317
|
changeAction:
|
|
@@ -19,6 +19,9 @@ import userEvent from '@testing-library/user-event';
|
|
|
19
19
|
import {getButton, queryButton} from '../__tests__/fastRoleQueries';
|
|
20
20
|
import {DateRangeInput} from './DateRangeInput';
|
|
21
21
|
import type {DateRange} from './DateRangeInput';
|
|
22
|
+
import {Icon} from '../Icon';
|
|
23
|
+
import {defineTheme} from '../theme/defineTheme';
|
|
24
|
+
import {generateThemeCSSFlat} from '../theme/generateThemeRules';
|
|
22
25
|
|
|
23
26
|
describe('DateRangeInput', () => {
|
|
24
27
|
it('renders with label', () => {
|
|
@@ -472,11 +475,15 @@ describe('DateRangeInput', () => {
|
|
|
472
475
|
});
|
|
473
476
|
});
|
|
474
477
|
|
|
475
|
-
|
|
476
478
|
describe('DateRangeInput statusVariant forwarding', () => {
|
|
477
479
|
it('defaults to attached (status renders with data-variant="attached")', () => {
|
|
478
480
|
const {container} = render(
|
|
479
|
-
<DateRangeInput
|
|
481
|
+
<DateRangeInput
|
|
482
|
+
label="Range"
|
|
483
|
+
value={null}
|
|
484
|
+
onChange={() => {}}
|
|
485
|
+
status={{type: 'error', message: 'Required'}}
|
|
486
|
+
/>,
|
|
480
487
|
);
|
|
481
488
|
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
482
489
|
'data-variant',
|
|
@@ -486,7 +493,13 @@ describe('DateRangeInput statusVariant forwarding', () => {
|
|
|
486
493
|
|
|
487
494
|
it('forwards statusVariant="detached" to the underlying Field status', () => {
|
|
488
495
|
const {container} = render(
|
|
489
|
-
<DateRangeInput
|
|
496
|
+
<DateRangeInput
|
|
497
|
+
label="Range"
|
|
498
|
+
value={null}
|
|
499
|
+
onChange={() => {}}
|
|
500
|
+
status={{type: 'error', message: 'Required'}}
|
|
501
|
+
statusVariant="detached"
|
|
502
|
+
/>,
|
|
490
503
|
);
|
|
491
504
|
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
492
505
|
'data-variant',
|
|
@@ -494,3 +507,107 @@ describe('DateRangeInput statusVariant forwarding', () => {
|
|
|
494
507
|
);
|
|
495
508
|
});
|
|
496
509
|
});
|
|
510
|
+
|
|
511
|
+
describe('DateRangeInput icon theme targets', () => {
|
|
512
|
+
const RANGE: DateRange = {start: '2026-03-15', end: '2026-03-22'};
|
|
513
|
+
|
|
514
|
+
// Resolve a glyph span (the astryx-icon element) inside a given button,
|
|
515
|
+
// independent of the theme target class.
|
|
516
|
+
const iconIn = (button: HTMLElement): HTMLElement => {
|
|
517
|
+
const icon = button.querySelector('.astryx-icon');
|
|
518
|
+
if (icon == null) {
|
|
519
|
+
throw new Error('icon not found');
|
|
520
|
+
}
|
|
521
|
+
return icon as HTMLElement;
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
it('renders astryx-date-range-input-clear-icon on the clear glyph', () => {
|
|
525
|
+
render(
|
|
526
|
+
<DateRangeInput
|
|
527
|
+
label="Range"
|
|
528
|
+
value={RANGE}
|
|
529
|
+
onChange={() => {}}
|
|
530
|
+
hasClear
|
|
531
|
+
/>,
|
|
532
|
+
);
|
|
533
|
+
// The stable target lands on the icon element itself (not the button), so a
|
|
534
|
+
// theme can restyle just this glyph (color, size, hover) via defineTheme —
|
|
535
|
+
// a button-level target could not reach the icon's own color/size.
|
|
536
|
+
const icon = iconIn(getButton('Clear Range'));
|
|
537
|
+
expect(icon).toHaveClass('astryx-date-range-input-clear-icon');
|
|
538
|
+
expect(icon).toHaveClass('astryx-icon');
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
it('renders astryx-date-range-input-toggle-icon on the calendar-toggle glyph, reflecting state', () => {
|
|
542
|
+
render(<DateRangeInput label="Range" value={null} onChange={() => {}} />);
|
|
543
|
+
const icon = iconIn(getButton('Open calendar'));
|
|
544
|
+
expect(icon).toHaveClass('astryx-date-range-input-toggle-icon');
|
|
545
|
+
expect(icon).toHaveClass('astryx-icon');
|
|
546
|
+
// Closed by default → data-state="collapsed".
|
|
547
|
+
expect(icon).toHaveAttribute('data-state', 'collapsed');
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
it('renders the default icons (secondary color, sm size) byte-identically', () => {
|
|
551
|
+
// Pixel-identical default guard: the glyphs must carry the exact same
|
|
552
|
+
// StyleX color/size classes as a standalone secondary/sm icon. The added
|
|
553
|
+
// target class is purely additive — it changes nothing until a theme
|
|
554
|
+
// targets it.
|
|
555
|
+
render(
|
|
556
|
+
<DateRangeInput
|
|
557
|
+
label="Range"
|
|
558
|
+
value={RANGE}
|
|
559
|
+
onChange={() => {}}
|
|
560
|
+
hasClear
|
|
561
|
+
/>,
|
|
562
|
+
);
|
|
563
|
+
const clearIcon = iconIn(getButton('Clear Range'));
|
|
564
|
+
|
|
565
|
+
const {container: refContainer} = render(
|
|
566
|
+
<Icon icon="close" size="sm" color="secondary" />,
|
|
567
|
+
);
|
|
568
|
+
const refIcon = refContainer.querySelector('.astryx-icon') as HTMLElement;
|
|
569
|
+
|
|
570
|
+
const styleClasses = (el: HTMLElement) =>
|
|
571
|
+
el.className
|
|
572
|
+
.split(' ')
|
|
573
|
+
.filter(
|
|
574
|
+
c =>
|
|
575
|
+
c !== 'astryx-date-range-input-clear-icon' &&
|
|
576
|
+
c !== 'astryx-date-range-input-toggle-icon',
|
|
577
|
+
)
|
|
578
|
+
.sort();
|
|
579
|
+
|
|
580
|
+
expect(styleClasses(clearIcon)).toEqual(styleClasses(refIcon));
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
it('exposes the icon targets so a theme reaches icon color, size, and hover', () => {
|
|
584
|
+
// jsdom cannot resolve the @layer cascade, so the DOM-class assertions
|
|
585
|
+
// above (targets land on the icon elements) plus this generation assertion
|
|
586
|
+
// (the theme emits same-element icon rules in @layer astryx-theme) together
|
|
587
|
+
// prove the seam: a same-element theme rule wins over the icon's own
|
|
588
|
+
// base-layer color/size.
|
|
589
|
+
const theme = defineTheme({
|
|
590
|
+
name: 'date-range-input-icon-test',
|
|
591
|
+
components: {
|
|
592
|
+
'date-range-input-clear-icon': {
|
|
593
|
+
base: {
|
|
594
|
+
width: '12px',
|
|
595
|
+
height: '12px',
|
|
596
|
+
fontSize: '12px',
|
|
597
|
+
color: 'var(--color-icon-secondary)',
|
|
598
|
+
':hover': {color: 'var(--color-icon-primary)'},
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
'date-range-input-toggle-icon': {
|
|
602
|
+
base: {width: '14px', height: '14px', fontSize: '14px'},
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
});
|
|
606
|
+
const css = generateThemeCSSFlat(theme);
|
|
607
|
+
expect(css).toContain('.astryx-date-range-input-clear-icon');
|
|
608
|
+
expect(css).toContain('.astryx-date-range-input-toggle-icon');
|
|
609
|
+
expect(css).toContain(':hover');
|
|
610
|
+
expect(css).toContain('12px');
|
|
611
|
+
expect(css).toContain('14px');
|
|
612
|
+
});
|
|
613
|
+
});
|
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
DATE_FORMAT_SHORT,
|
|
26
26
|
DATE_FORMAT_SHORT_WITH_YEAR,
|
|
27
27
|
} from '../utils/plainDate';
|
|
28
|
-
import type {IconName} from '../Icon';
|
|
29
28
|
import {
|
|
30
29
|
colorVars,
|
|
31
30
|
sizeVars,
|
|
@@ -38,7 +37,6 @@ import {
|
|
|
38
37
|
import {
|
|
39
38
|
Field,
|
|
40
39
|
type InputStatus,
|
|
41
|
-
type InputStatusType,
|
|
42
40
|
inputWrapperStyles,
|
|
43
41
|
inputStatusBorderStyles,
|
|
44
42
|
inputStatusHoverShadowStyles,
|
|
@@ -54,6 +52,7 @@ import {mergeProps} from '../utils';
|
|
|
54
52
|
import type {BaseProps} from '../BaseProps';
|
|
55
53
|
import type {SizeValue} from '../utils/types';
|
|
56
54
|
import {useSize} from '../SizeContext/SizeContext';
|
|
55
|
+
import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
|
|
57
56
|
import {themeProps} from '../utils/themeProps';
|
|
58
57
|
import {useTranslator} from '../i18n';
|
|
59
58
|
|
|
@@ -335,6 +334,7 @@ export interface DateRangeInputProps extends Omit<
|
|
|
335
334
|
* How the status message is placed relative to the input.
|
|
336
335
|
* - 'attached': message overlaps directly below the input (bordered treatment)
|
|
337
336
|
* - 'detached': message floats below as a separate element with spacing
|
|
337
|
+
* - 'tooltip': no message box; the status icon becomes a focusable info-tip button that reveals the message on hover, keyboard focus, or tap
|
|
338
338
|
* @default 'attached'
|
|
339
339
|
*/
|
|
340
340
|
statusVariant?: FieldStatusVariant;
|
|
@@ -431,25 +431,19 @@ export function DateRangeInput({
|
|
|
431
431
|
isEnabled: showsDisabledMessage,
|
|
432
432
|
});
|
|
433
433
|
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
const statusIconColorMap: Record<
|
|
441
|
-
InputStatusType,
|
|
442
|
-
'warning' | 'error' | 'success'
|
|
443
|
-
> = {
|
|
444
|
-
warning: 'warning',
|
|
445
|
-
error: 'error',
|
|
446
|
-
success: 'success',
|
|
447
|
-
};
|
|
434
|
+
const {statusIcon, describedBy: statusTooltipDescribedBy} =
|
|
435
|
+
useInputStatusIcon({
|
|
436
|
+
status,
|
|
437
|
+
statusVariant,
|
|
438
|
+
});
|
|
448
439
|
|
|
449
440
|
const ariaDescribedBy =
|
|
450
441
|
[
|
|
451
442
|
description ? descriptionID : null,
|
|
452
|
-
status?.message ? statusMessageID : null,
|
|
443
|
+
statusVariant !== 'tooltip' && status?.message ? statusMessageID : null,
|
|
444
|
+
// The tooltip variant renders no message box; describe the input by the
|
|
445
|
+
// tooltip's content instead so the status is still announced.
|
|
446
|
+
statusTooltipDescribedBy,
|
|
453
447
|
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
454
448
|
]
|
|
455
449
|
.filter(Boolean)
|
|
@@ -560,7 +554,9 @@ export function DateRangeInput({
|
|
|
560
554
|
sizeStyles[size],
|
|
561
555
|
isEffectivelyDisabled && inputWrapperStyles.disabled,
|
|
562
556
|
status && inputStatusBorderStyles[status.type],
|
|
563
|
-
status &&
|
|
557
|
+
status &&
|
|
558
|
+
!isEffectivelyDisabled &&
|
|
559
|
+
inputStatusHoverShadowStyles[status.type],
|
|
564
560
|
status && inputStatusFocusWithinStyles[status.type],
|
|
565
561
|
xstyle,
|
|
566
562
|
),
|
|
@@ -581,7 +577,14 @@ export function DateRangeInput({
|
|
|
581
577
|
styles.iconButton,
|
|
582
578
|
isEffectivelyDisabled && styles.iconButtonDisabled,
|
|
583
579
|
)}>
|
|
584
|
-
<Icon
|
|
580
|
+
<Icon
|
|
581
|
+
icon="calendar"
|
|
582
|
+
size="sm"
|
|
583
|
+
color="secondary"
|
|
584
|
+
{...themeProps('date-range-input-toggle-icon', {
|
|
585
|
+
state: popover.isOpen ? 'expanded' : 'collapsed',
|
|
586
|
+
})}
|
|
587
|
+
/>
|
|
585
588
|
</button>
|
|
586
589
|
<button
|
|
587
590
|
ref={ref}
|
|
@@ -614,17 +617,16 @@ export function DateRangeInput({
|
|
|
614
617
|
onClick={handleClear}
|
|
615
618
|
aria-label={t('@astryx.dateInput.clear', {label})}
|
|
616
619
|
{...stylex.props(styles.iconButton)}>
|
|
617
|
-
<Icon
|
|
620
|
+
<Icon
|
|
621
|
+
icon="close"
|
|
622
|
+
size="sm"
|
|
623
|
+
color="secondary"
|
|
624
|
+
{...themeProps('date-range-input-clear-icon')}
|
|
625
|
+
/>
|
|
618
626
|
</button>
|
|
619
627
|
)}
|
|
620
628
|
{isBusy && <Spinner size="sm" />}
|
|
621
|
-
{
|
|
622
|
-
<Icon
|
|
623
|
-
icon={statusIconMap[status.type]}
|
|
624
|
-
size="md"
|
|
625
|
-
color={statusIconColorMap[status.type]}
|
|
626
|
-
/>
|
|
627
|
-
)}
|
|
629
|
+
{statusIcon}
|
|
628
630
|
</div>
|
|
629
631
|
{popover.render(
|
|
630
632
|
<div {...stylex.props(styles.popoverLayout)}>
|
|
@@ -173,6 +173,12 @@ export const docs = {
|
|
|
173
173
|
description: 'Number of months displayed simultaneously in the calendar.',
|
|
174
174
|
default: '1',
|
|
175
175
|
},
|
|
176
|
+
{
|
|
177
|
+
name: 'width',
|
|
178
|
+
type: 'SizeValue',
|
|
179
|
+
description:
|
|
180
|
+
'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.',
|
|
181
|
+
},
|
|
176
182
|
{
|
|
177
183
|
name: 'xstyle',
|
|
178
184
|
type: 'StyleXStyles',
|
|
@@ -183,6 +189,14 @@ export const docs = {
|
|
|
183
189
|
theming: {
|
|
184
190
|
targets: [
|
|
185
191
|
{className: 'astryx-date-time-input', visualProps: ['size', 'status']},
|
|
192
|
+
{
|
|
193
|
+
className: 'astryx-date-time-input-date-segment',
|
|
194
|
+
visualProps: ['size', 'status'],
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
className: 'astryx-date-time-input-time-segment',
|
|
198
|
+
visualProps: ['size', 'status'],
|
|
199
|
+
},
|
|
186
200
|
],
|
|
187
201
|
},
|
|
188
202
|
usage: {
|
|
@@ -469,11 +483,18 @@ export const docsZh = {
|
|
|
469
483
|
description:
|
|
470
484
|
'用于布局自定义的 StyleX 样式。必须是 stylex.create() 的值。',
|
|
471
485
|
},
|
|
472
|
-
|
|
473
486
|
],
|
|
474
487
|
theming: {
|
|
475
488
|
targets: [
|
|
476
489
|
{className: 'astryx-date-time-input', visualProps: ['size', 'status']},
|
|
490
|
+
{
|
|
491
|
+
className: 'astryx-date-time-input-date-segment',
|
|
492
|
+
visualProps: ['size', 'status'],
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
className: 'astryx-date-time-input-time-segment',
|
|
496
|
+
visualProps: ['size', 'status'],
|
|
497
|
+
},
|
|
477
498
|
],
|
|
478
499
|
},
|
|
479
500
|
};
|
|
@@ -15,6 +15,8 @@ import userEvent from '@testing-library/user-event';
|
|
|
15
15
|
import {getButton, queryButton} from '../__tests__/fastRoleQueries';
|
|
16
16
|
import {DateTimeInput} from './DateTimeInput';
|
|
17
17
|
import type {ISODateTimeString} from './DateTimeInput';
|
|
18
|
+
import {defineTheme} from '../theme/defineTheme';
|
|
19
|
+
import {generateThemeCSSFlat} from '../theme/generateThemeRules';
|
|
18
20
|
|
|
19
21
|
describe('DateTimeInput', () => {
|
|
20
22
|
it('renders with label', () => {
|
|
@@ -814,4 +816,114 @@ describe('DateTimeInput', () => {
|
|
|
814
816
|
expect(onChange.mock.calls[0][0]).toContain('14:31');
|
|
815
817
|
});
|
|
816
818
|
});
|
|
819
|
+
// ===========================================================================
|
|
820
|
+
// Segment theme targets (#4075)
|
|
821
|
+
// ===========================================================================
|
|
822
|
+
|
|
823
|
+
describe('segment theme targets', () => {
|
|
824
|
+
// The root only publishes `astryx-date-time-input`; the date and time
|
|
825
|
+
// wrappers were anonymous nodes carrying hashed atomic classes only, so a
|
|
826
|
+
// theme that restyles input geometry through the text-input/date-input/
|
|
827
|
+
// time-input targets could not reach them and DateTimeInput rendered
|
|
828
|
+
// shorter than every other input under that theme.
|
|
829
|
+
|
|
830
|
+
it('renders the date segment target on the date wrapper', () => {
|
|
831
|
+
render(<DateTimeInput label="Meeting" onChange={() => {}} />);
|
|
832
|
+
const wrapper = screen
|
|
833
|
+
.getByLabelText('Meeting')
|
|
834
|
+
.closest('.astryx-date-time-input-date-segment');
|
|
835
|
+
|
|
836
|
+
expect(wrapper).not.toBeNull();
|
|
837
|
+
// The wrapper is the input's own container, not an ancestor further up.
|
|
838
|
+
expect(wrapper).toBe(screen.getByLabelText('Meeting').parentElement);
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
it('renders the time segment target on the time wrapper', () => {
|
|
842
|
+
render(<DateTimeInput label="Meeting" onChange={() => {}} />);
|
|
843
|
+
const wrapper = screen
|
|
844
|
+
.getByLabelText('Meeting time')
|
|
845
|
+
.closest('.astryx-date-time-input-time-segment');
|
|
846
|
+
|
|
847
|
+
expect(wrapper).not.toBeNull();
|
|
848
|
+
expect(wrapper).toBe(screen.getByLabelText('Meeting time').parentElement);
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
it('reflects size on both segments so themes can restyle geometry', () => {
|
|
852
|
+
render(<DateTimeInput label="Meeting" size="lg" onChange={() => {}} />);
|
|
853
|
+
|
|
854
|
+
const date = screen
|
|
855
|
+
.getByLabelText('Meeting')
|
|
856
|
+
.closest('.astryx-date-time-input-date-segment');
|
|
857
|
+
const time = screen
|
|
858
|
+
.getByLabelText('Meeting time')
|
|
859
|
+
.closest('.astryx-date-time-input-time-segment');
|
|
860
|
+
|
|
861
|
+
expect(date).toHaveAttribute('data-size', 'lg');
|
|
862
|
+
expect(date).toHaveClass('lg');
|
|
863
|
+
expect(time).toHaveAttribute('data-size', 'lg');
|
|
864
|
+
expect(time).toHaveClass('lg');
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
it('reflects status on both segments, mirroring the root', () => {
|
|
868
|
+
render(
|
|
869
|
+
<DateTimeInput
|
|
870
|
+
label="Meeting"
|
|
871
|
+
status={{type: 'error', message: 'Required'}}
|
|
872
|
+
onChange={() => {}}
|
|
873
|
+
/>,
|
|
874
|
+
);
|
|
875
|
+
|
|
876
|
+
const date = screen
|
|
877
|
+
.getByLabelText('Meeting')
|
|
878
|
+
.closest('.astryx-date-time-input-date-segment');
|
|
879
|
+
const time = screen
|
|
880
|
+
.getByLabelText('Meeting time')
|
|
881
|
+
.closest('.astryx-date-time-input-time-segment');
|
|
882
|
+
|
|
883
|
+
expect(date).toHaveAttribute('data-status', 'error');
|
|
884
|
+
expect(time).toHaveAttribute('data-status', 'error');
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
it('omits data-status when there is no status, like the root does', () => {
|
|
888
|
+
render(<DateTimeInput label="Meeting" onChange={() => {}} />);
|
|
889
|
+
|
|
890
|
+
const date = screen
|
|
891
|
+
.getByLabelText('Meeting')
|
|
892
|
+
.closest('.astryx-date-time-input-date-segment');
|
|
893
|
+
|
|
894
|
+
expect(date).not.toHaveAttribute('data-status');
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
it('keeps the root target intact', () => {
|
|
898
|
+
const {container} = render(
|
|
899
|
+
<DateTimeInput label="Meeting" onChange={() => {}} />,
|
|
900
|
+
);
|
|
901
|
+
// Additive change — the existing root target still renders.
|
|
902
|
+
expect(container.querySelector('.astryx-date-time-input')).not.toBeNull();
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
it('exposes both segments as themeable defineTheme targets', () => {
|
|
906
|
+
// jsdom cannot resolve the @layer cascade, so the generated CSS is what
|
|
907
|
+
// proves a theme can actually reach these nodes.
|
|
908
|
+
const theme = defineTheme({
|
|
909
|
+
name: 'date-time-input-segments-test',
|
|
910
|
+
components: {
|
|
911
|
+
'date-time-input-date-segment': {
|
|
912
|
+
base: {blockSize: 'var(--size-element-lg)'},
|
|
913
|
+
lg: {paddingInline: 'var(--spacing-4)'},
|
|
914
|
+
},
|
|
915
|
+
'date-time-input-time-segment': {
|
|
916
|
+
base: {blockSize: 'var(--size-element-lg)'},
|
|
917
|
+
},
|
|
918
|
+
},
|
|
919
|
+
});
|
|
920
|
+
const css = generateThemeCSSFlat(theme);
|
|
921
|
+
|
|
922
|
+
expect(css).toContain('.astryx-date-time-input-date-segment {');
|
|
923
|
+
expect(css).toContain('.astryx-date-time-input-date-segment.lg');
|
|
924
|
+
expect(css).toContain('.astryx-date-time-input-time-segment {');
|
|
925
|
+
expect(css).toContain('block-size: var(--size-element-lg)');
|
|
926
|
+
expect(css).toContain('padding-inline: var(--spacing-4)');
|
|
927
|
+
});
|
|
928
|
+
});
|
|
817
929
|
});
|