@astryxdesign/core 0.3.0 → 0.4.0-canary.3112e99
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 +156 -0
- package/dist/AlertDialog/AlertDialog.d.ts +10 -2
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +22 -3
- package/dist/AppShell/AppShell.d.ts +2 -2
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +40 -9
- package/dist/AspectRatio/AspectRatio.d.ts +13 -0
- package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
- package/dist/AspectRatio/AspectRatio.js +9 -0
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +33 -20
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +2 -3
- package/dist/Banner/Banner.d.ts +3 -0
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +32 -17
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +21 -8
- package/dist/Breadcrumbs/index.d.ts +2 -1
- package/dist/Breadcrumbs/index.d.ts.map +1 -1
- package/dist/Breadcrumbs/index.js +1 -0
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +12 -16
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +2 -1
- package/dist/Calendar/styles.d.ts +0 -2
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +0 -2
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +8 -12
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +2 -1
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +3 -1
- package/dist/Chat/ChatSendButton.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.js +4 -3
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +17 -17
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +2 -6
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +36 -125
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +3 -11
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +84 -67
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +35 -15
- package/dist/CommandPalette/CommandPaletteItem.d.ts +1 -1
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +6 -3
- package/dist/CommandPalette/CommandPaletteList.js +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +32 -31
- package/dist/ContextMenu/ContextMenu.d.ts +2 -2
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +1 -1
- package/dist/ContextMenu/index.d.ts +2 -1
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +1 -0
- package/dist/DateInput/DateInput.d.ts +9 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +47 -33
- package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +55 -32
- package/dist/DateTimeInput/DateTimeInput.d.ts +9 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +54 -30
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +4 -4
- package/dist/DropdownMenu/DropdownMenu.d.ts +33 -8
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +62 -20
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +8 -11
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +32 -31
- package/dist/DropdownMenu/DropdownMenuDivider.d.ts +25 -0
- package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuDivider.js +66 -0
- package/dist/DropdownMenu/DropdownMenuItem.d.ts +15 -2
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +20 -8
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +10 -3
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +5 -5
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +24 -67
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -8
- package/dist/DropdownMenu/index.d.ts +2 -1
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +4 -0
- package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
- package/dist/DropdownMenu/renderDropdownItems.js +35 -27
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +9 -5
- package/dist/Field/InputClearButton.d.ts +16 -3
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +15 -4
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +21 -10
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +3 -19
- package/dist/Indicator/CheckIndicator.d.ts +25 -0
- package/dist/Indicator/CheckIndicator.d.ts.map +1 -0
- package/dist/Indicator/CheckIndicator.js +155 -0
- package/dist/Indicator/CheckboxIndicator.d.ts +22 -0
- package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -0
- package/dist/Indicator/CheckboxIndicator.js +173 -0
- package/dist/Indicator/RadioIndicator.d.ts +23 -0
- package/dist/Indicator/RadioIndicator.d.ts.map +1 -0
- package/dist/Indicator/RadioIndicator.js +137 -0
- package/dist/Indicator/index.d.ts +24 -0
- package/dist/Indicator/index.d.ts.map +1 -0
- package/dist/Indicator/index.js +26 -0
- package/dist/Indicator/indicator.markers.stylex.d.ts +16 -0
- package/dist/Indicator/indicator.markers.stylex.d.ts.map +1 -0
- package/dist/Indicator/indicator.markers.stylex.js +21 -0
- package/dist/Indicator/indicatorRegistry.d.ts +71 -0
- package/dist/Indicator/indicatorRegistry.d.ts.map +1 -0
- package/dist/Indicator/indicatorRegistry.js +93 -0
- package/dist/Indicator/types.d.ts +177 -0
- package/dist/Indicator/types.d.ts.map +1 -0
- package/dist/Indicator/types.js +1 -0
- package/dist/Indicator/useIndicator.d.ts +18 -0
- package/dist/Indicator/useIndicator.d.ts.map +1 -0
- package/dist/Indicator/useIndicator.js +30 -0
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +4 -8
- package/dist/Layer/useLayer.d.ts +14 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +25 -2
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +80 -103
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +4 -5
- package/dist/MobileNav/MobileNav.js +8 -8
- package/dist/MoreMenu/MoreMenu.d.ts +14 -1
- package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
- package/dist/MoreMenu/MoreMenu.js +4 -0
- package/dist/MultiSelector/MultiSelector.d.ts +8 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +119 -95
- package/dist/NumberInput/NumberInput.d.ts +27 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +230 -42
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +2 -3
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +61 -63
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +6 -8
- package/dist/Popover/usePopover.d.ts +15 -0
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +14 -2
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +7 -0
- package/dist/ProgressBar/ProgressBar.d.ts +11 -4
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +95 -6
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +29 -84
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +2 -3
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +2 -3
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +3 -11
- package/dist/Selector/Selector.d.ts +12 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +222 -111
- package/dist/Selector/hooks.d.ts +18 -6
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +57 -40
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +1 -1
- package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavCollapseButton.js +29 -14
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +56 -20
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +28 -22
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +2 -6
- package/dist/Stack/stack.stylex.d.ts +3 -3
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +14 -13
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +2 -3
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +41 -19
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +8 -0
- package/dist/Table/TableRow.d.ts +1 -1
- package/dist/Table/TableRow.d.ts.map +1 -1
- package/dist/Table/TableRow.js +4 -2
- package/dist/Table/index.d.ts +1 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +22 -18
- package/dist/Table/plugins/rowExpansion/index.d.ts +1 -1
- package/dist/Table/plugins/rowExpansion/index.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/index.js +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +41 -76
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +94 -345
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +23 -4
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +29 -33
- package/dist/Table/tableContextMenu.d.ts.map +1 -1
- package/dist/Table/tableContextMenu.js +2 -1
- package/dist/Table/types.d.ts +11 -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 +16 -6
- package/dist/TextInput/TextInput.d.ts +10 -1
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +13 -19
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +32 -26
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +14 -17
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +14 -3
- package/dist/Timestamp/TimestampHoverCard.d.ts.map +1 -1
- package/dist/Timestamp/TimestampHoverCard.js +16 -34
- package/dist/Timestamp/formatInstant.d.ts +11 -1
- package/dist/Timestamp/formatInstant.d.ts.map +1 -1
- package/dist/Timestamp/formatInstant.js +3 -1
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +20 -11
- 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 +3 -19
- package/dist/TopNav/TopNav.d.ts.map +1 -1
- package/dist/TopNav/TopNav.js +6 -5
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +54 -16
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +3 -9
- package/dist/TopNav/TopNavMegaMenu.d.ts +7 -0
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +146 -60
- package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +22 -3
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +83 -38
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +13 -0
- package/dist/TreeList/TreeListBranches.d.ts +1 -1
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +14 -4
- package/dist/TreeList/TreeListItem.d.ts +11 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +57 -30
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +16 -8
- package/dist/astryx.css +84 -96
- package/dist/astryx.umd.js +56 -56
- package/dist/astryx.umd.js.map +4 -4
- package/dist/hooks/containerReveal.stylex.d.ts +61 -0
- package/dist/hooks/containerReveal.stylex.d.ts.map +1 -0
- package/dist/hooks/containerReveal.stylex.js +63 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/useClipboard.d.ts +59 -0
- package/dist/hooks/useClipboard.d.ts.map +1 -0
- package/dist/hooks/useClipboard.js +106 -0
- package/dist/hooks/useContainerReveal.d.ts +14 -8
- package/dist/hooks/useContainerReveal.d.ts.map +1 -1
- package/dist/hooks/useContainerReveal.js +28 -69
- package/dist/hooks/useIndicatorFocusRing.d.ts +28 -0
- package/dist/hooks/useIndicatorFocusRing.d.ts.map +1 -0
- package/dist/hooks/useIndicatorFocusRing.js +96 -0
- package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
- package/dist/hooks/useInputStatusIcon.js +17 -4
- package/dist/hooks/useLongPress.d.ts.map +1 -1
- package/dist/hooks/useLongPress.js +12 -2
- package/dist/hooks/useScrollLock.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.js +33 -18
- package/dist/hooks/useStreamingText.d.ts +18 -3
- package/dist/hooks/useStreamingText.d.ts.map +1 -1
- package/dist/hooks/useStreamingText.js +47 -7
- package/dist/hooks/useTreeFocus.d.ts.map +1 -1
- package/dist/hooks/useTreeFocus.js +9 -3
- package/dist/hooks/useTypeahead.d.ts +3 -2
- package/dist/hooks/useTypeahead.d.ts.map +1 -1
- package/dist/hooks/useTypeahead.js +19 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/defineTheme.d.ts +18 -2
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +10 -1
- package/dist/theme/derivedVarRegistry.d.ts +8 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +14 -13
- package/dist/theme/expandColorScale.d.ts +3 -1
- package/dist/theme/expandColorScale.d.ts.map +1 -1
- package/dist/theme/expandColorScale.js +17 -7
- package/dist/theme/expandTypeScale.d.ts.map +1 -1
- package/dist/theme/expandTypeScale.js +17 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +11 -0
- package/dist/theme/index.d.ts +2 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +1 -1
- package/dist/theme/tokens.stylex.d.ts +12 -0
- package/dist/theme/tokens.stylex.d.ts.map +1 -1
- package/dist/theme/tokens.stylex.js +23 -0
- package/dist/utils/focusOutline.stylex.d.ts +122 -0
- package/dist/utils/focusOutline.stylex.d.ts.map +1 -0
- package/dist/utils/focusOutline.stylex.js +143 -0
- package/dist/utils/focusReturn.d.ts +24 -0
- package/dist/utils/focusReturn.d.ts.map +1 -0
- package/dist/utils/focusReturn.js +29 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +6 -1
- package/dist/utils/mergeRefs.d.ts.map +1 -1
- package/dist/utils/mergeRefs.js +7 -5
- package/dist/utils/rtlStyles.d.ts +2 -2
- package/dist/utils/rtlStyles.js +2 -2
- package/dist/utils/themeProps.d.ts +20 -1
- package/dist/utils/themeProps.d.ts.map +1 -1
- package/dist/utils/themeProps.js +8 -2
- package/locales/en.json +52 -0
- package/locales/pseudo.json +39 -0
- package/package.json +8 -3
- package/src/AlertDialog/AlertDialog.doc.mjs +16 -3
- package/src/AlertDialog/AlertDialog.test.tsx +208 -1
- package/src/AlertDialog/AlertDialog.tsx +21 -3
- package/src/AppShell/AppShell.doc.mjs +11 -0
- package/src/AppShell/AppShell.test.tsx +139 -0
- package/src/AppShell/AppShell.tsx +32 -22
- package/src/AspectRatio/AspectRatio.doc.mjs +27 -3
- package/src/AspectRatio/AspectRatio.test.tsx +30 -0
- package/src/AspectRatio/AspectRatio.tsx +13 -0
- package/src/Avatar/Avatar.doc.mjs +2 -13
- package/src/Avatar/Avatar.test.tsx +33 -8
- package/src/Avatar/Avatar.tsx +52 -50
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -9
- package/src/Banner/Banner.test.tsx +58 -1
- package/src/Banner/Banner.tsx +33 -11
- package/src/Breadcrumbs/BreadcrumbItem.tsx +16 -6
- package/src/Breadcrumbs/index.ts +5 -1
- package/src/Button/Button.doc.mjs +2 -2
- package/src/Button/Button.tsx +22 -41
- package/src/Calendar/Calendar.tsx +2 -1
- package/src/Calendar/styles.ts +0 -8
- package/src/Carousel/Carousel.doc.mjs +3 -0
- package/src/Carousel/Carousel.tsx +10 -6
- package/src/Chat/Chat.doc.mjs +2 -0
- package/src/Chat/ChatDictationButton.tsx +7 -1
- package/src/Chat/ChatLayoutScrollButton.test.tsx +22 -0
- package/src/Chat/ChatLayoutScrollButton.tsx +8 -1
- package/src/Chat/ChatSendButton.tsx +2 -3
- package/src/Chat/ChatToolCalls.test.tsx +35 -0
- package/src/Chat/ChatToolCalls.tsx +36 -16
- package/src/Chat/useTriggerMenu.tsx +2 -5
- package/src/CheckboxInput/CheckboxInput.doc.mjs +4 -2
- package/src/CheckboxInput/CheckboxInput.test.tsx +120 -0
- package/src/CheckboxInput/CheckboxInput.tsx +45 -202
- package/src/ClickableCard/ClickableCard.tsx +6 -11
- package/src/CodeBlock/CodeBlock.doc.mjs +3 -0
- package/src/CodeBlock/CodeBlock.test.tsx +91 -0
- package/src/CodeBlock/CodeBlock.tsx +57 -80
- package/src/Collapsible/Collapsible.tsx +22 -18
- package/src/CommandPalette/CommandPalette.test.tsx +29 -0
- package/src/CommandPalette/CommandPaletteItem.tsx +7 -4
- package/src/CommandPalette/CommandPaletteList.tsx +2 -2
- package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
- package/src/ComplexSelector/ComplexSelector.test.tsx +73 -0
- package/src/ComplexSelector/ComplexSelector.tsx +41 -28
- package/src/ContextMenu/ContextMenu.doc.mjs +1 -1
- package/src/ContextMenu/ContextMenu.test.tsx +41 -0
- package/src/ContextMenu/ContextMenu.tsx +3 -3
- package/src/ContextMenu/index.ts +5 -1
- package/src/DateInput/DateInput.doc.mjs +18 -3
- package/src/DateInput/DateInput.test.tsx +112 -11
- package/src/DateInput/DateInput.tsx +44 -25
- package/src/DateRangeInput/DateRangeInput.doc.mjs +10 -2
- package/src/DateRangeInput/DateRangeInput.test.tsx +110 -14
- package/src/DateRangeInput/DateRangeInput.tsx +27 -21
- package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -2
- package/src/DateTimeInput/DateTimeInput.test.tsx +154 -1
- package/src/DateTimeInput/DateTimeInput.tsx +58 -17
- package/src/Dialog/Dialog.tsx +2 -9
- package/src/DropdownMenu/DropdownMenu.doc.mjs +5 -9
- package/src/DropdownMenu/DropdownMenu.test.tsx +534 -4
- package/src/DropdownMenu/DropdownMenu.tsx +113 -52
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +27 -30
- package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +34 -0
- package/src/DropdownMenu/DropdownMenuDivider.tsx +81 -0
- package/src/DropdownMenu/DropdownMenuItem.doc.mjs +39 -4
- package/src/DropdownMenu/DropdownMenuItem.tsx +48 -10
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +2 -1
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +30 -76
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +25 -19
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +44 -14
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +1 -5
- package/src/DropdownMenu/index.ts +8 -1
- package/src/DropdownMenu/renderDropdownItems.tsx +33 -34
- package/src/EmptyState/EmptyState.doc.mjs +4 -0
- package/src/EmptyState/EmptyState.test.tsx +62 -0
- package/src/EmptyState/EmptyState.tsx +16 -6
- package/src/Field/Field.doc.mjs +1 -0
- package/src/Field/InputClearButton.test.tsx +117 -0
- package/src/Field/InputClearButton.tsx +30 -3
- package/src/FileInput/FileInput.tsx +21 -8
- package/src/HoverCard/useHoverCard.tsx +2 -23
- package/src/Icon/Icon.doc.mjs +2 -1
- package/src/Indicator/CheckIndicator.tsx +174 -0
- package/src/Indicator/CheckboxIndicator.tsx +257 -0
- package/src/Indicator/Indicator.doc.mjs +344 -0
- package/src/Indicator/Indicator.test.tsx +393 -0
- package/src/Indicator/RadioIndicator.tsx +206 -0
- package/src/Indicator/index.ts +46 -0
- package/src/Indicator/indicator.markers.stylex.ts +19 -0
- package/src/Indicator/indicatorRegistry.test.tsx +106 -0
- package/src/Indicator/indicatorRegistry.ts +120 -0
- package/src/Indicator/types.ts +197 -0
- package/src/Indicator/useIndicator.ts +39 -0
- package/src/Item/Item.doc.mjs +1 -1
- package/src/Item/Item.tsx +7 -14
- package/src/Layer/useLayer.doc.mjs +2 -2
- package/src/Layer/useLayer.test.tsx +85 -0
- package/src/Layer/useLayer.tsx +39 -1
- package/src/Lightbox/Lightbox.doc.mjs +1 -1
- package/src/Lightbox/Lightbox.tsx +45 -49
- package/src/Link/Link.tsx +4 -11
- package/src/MobileNav/MobileNav.tsx +3 -3
- package/src/MoreMenu/MoreMenu.doc.mjs +31 -0
- package/src/MoreMenu/MoreMenu.test.tsx +68 -1
- package/src/MoreMenu/MoreMenu.tsx +19 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +16 -1
- package/src/MultiSelector/MultiSelector.test.tsx +259 -16
- package/src/MultiSelector/MultiSelector.tsx +144 -121
- package/src/NumberInput/NumberInput.doc.mjs +265 -50
- package/src/NumberInput/NumberInput.test.tsx +726 -21
- package/src/NumberInput/NumberInput.tsx +353 -59
- package/src/Outline/Outline.tsx +2 -5
- package/src/Pagination/Pagination.doc.mjs +1 -1
- package/src/Pagination/Pagination.test.tsx +22 -7
- package/src/Pagination/Pagination.tsx +38 -35
- package/src/Popover/Popover.doc.mjs +2 -0
- package/src/Popover/Popover.tsx +6 -7
- package/src/Popover/usePopover.tsx +37 -4
- package/src/PowerSearch/PowerSearch.tsx +1 -1
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +42 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +7 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +27 -5
- package/src/ProgressBar/ProgressBar.test.tsx +224 -1
- package/src/ProgressBar/ProgressBar.tsx +126 -30
- package/src/RadioList/RadioList.doc.mjs +4 -2
- package/src/RadioList/RadioListItem.tsx +31 -130
- package/src/Resizable/ResizeHandle.tsx +2 -9
- package/src/SegmentedControl/SegmentedControlItem.tsx +2 -9
- package/src/SelectableCard/SelectableCard.tsx +4 -9
- package/src/Selector/Selector.doc.mjs +15 -4
- package/src/Selector/Selector.test.tsx +1234 -98
- package/src/Selector/Selector.tsx +254 -126
- package/src/Selector/hooks.ts +77 -50
- package/src/SideNav/SideNav.test.tsx +46 -0
- package/src/SideNav/SideNav.tsx +1 -0
- package/src/SideNav/SideNavCollapseButton.tsx +15 -10
- package/src/SideNav/SideNavHeading.tsx +48 -10
- package/src/SideNav/SideNavItem.tsx +20 -12
- package/src/Slider/Slider.tsx +2 -11
- package/src/Stack/Stack.doc.mjs +110 -0
- package/src/StatusDot/StatusDot.doc.mjs +12 -3
- package/src/Switch/Switch.test.tsx +32 -0
- package/src/Switch/Switch.tsx +18 -10
- package/src/TabList/Tab.tsx +2 -9
- package/src/TabList/TabMenu.tsx +14 -21
- package/src/Table/BaseTable.tsx +11 -0
- package/src/Table/Table.test.tsx +31 -0
- package/src/Table/TableRow.tsx +6 -0
- package/src/Table/index.ts +1 -4
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +30 -14
- package/src/Table/plugins/rowExpansion/index.ts +1 -4
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +125 -175
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +115 -458
- package/src/Table/plugins/sortable/useTableSortable.tsx +2 -6
- package/src/Table/plugins/tree/useTableTreeData.tsx +43 -24
- package/src/Table/tableContextMenu.test.tsx +27 -0
- package/src/Table/tableContextMenu.tsx +1 -0
- package/src/Table/types.ts +11 -0
- package/src/Table/useTableGroupedRows.doc.mjs +1 -1
- package/src/Table/useTableRowExpansion.doc.mjs +43 -66
- package/src/TextArea/TextArea.doc.mjs +42 -2
- package/src/TextArea/TextArea.test.tsx +219 -0
- package/src/TextArea/TextArea.tsx +34 -7
- package/src/TextInput/TextInput.doc.mjs +18 -2
- package/src/TextInput/TextInput.test.tsx +189 -0
- package/src/TextInput/TextInput.tsx +25 -31
- package/src/Thumbnail/Thumbnail.tsx +2 -9
- package/src/TimeInput/TimeInput.doc.mjs +2 -2
- package/src/TimeInput/TimeInput.test.tsx +84 -3
- package/src/TimeInput/TimeInput.tsx +26 -28
- package/src/Timestamp/Timestamp.doc.mjs +4 -3
- package/src/Timestamp/Timestamp.test.tsx +91 -14
- package/src/Timestamp/Timestamp.tsx +14 -2
- package/src/Timestamp/TimestampHoverCard.tsx +13 -35
- package/src/Timestamp/formatInstant.ts +16 -1
- package/src/Token/Token.tsx +5 -28
- package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
- package/src/Tokenizer/Tokenizer.test.tsx +45 -3
- package/src/Tokenizer/Tokenizer.tsx +10 -2
- package/src/Tooltip/useTooltip.tsx +2 -23
- package/src/TopNav/TopNav.tsx +1 -3
- package/src/TopNav/TopNavHeading.tsx +42 -13
- package/src/TopNav/TopNavItem.tsx +3 -21
- package/src/TopNav/TopNavMegaMenu.doc.mjs +5 -0
- package/src/TopNav/TopNavMegaMenu.test.tsx +433 -33
- package/src/TopNav/TopNavMegaMenu.tsx +118 -53
- package/src/TopNav/TopNavMegaMenuItem.tsx +2 -9
- package/src/TopNav/TopNavMenu.tsx +34 -37
- package/src/TreeList/TreeList.doc.mjs +5 -0
- package/src/TreeList/TreeList.test.tsx +208 -8
- package/src/TreeList/TreeList.tsx +22 -0
- package/src/TreeList/TreeListBranches.tsx +25 -2
- package/src/TreeList/TreeListItem.tsx +89 -52
- package/src/Typeahead/BaseTypeahead.tsx +19 -6
- package/src/Typeahead/Typeahead.doc.mjs +1 -0
- package/src/Typeahead/Typeahead.test.tsx +76 -3
- package/src/hooks/containerReveal.stylex.ts +102 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useClipboard.doc.mjs +87 -0
- package/src/hooks/useClipboard.test.tsx +151 -0
- package/src/hooks/useClipboard.ts +135 -0
- package/src/hooks/useContainerReveal.doc.mjs +7 -7
- package/src/hooks/useContainerReveal.test.tsx +42 -62
- package/src/hooks/useContainerReveal.ts +36 -91
- package/src/hooks/useImageMode.test.ts +1 -1
- package/src/hooks/useIndicatorFocusRing.tsx +120 -0
- package/src/hooks/useInputStatusIcon.tsx +8 -8
- package/src/hooks/useLongPress.test.tsx +18 -0
- package/src/hooks/useLongPress.ts +12 -2
- package/src/hooks/useScrollLock.test.ts +72 -0
- package/src/hooks/useScrollLock.ts +51 -19
- package/src/hooks/useStreamingText.test.ts +46 -1
- package/src/hooks/useStreamingText.ts +49 -7
- package/src/hooks/useTreeFocus.test.tsx +50 -0
- package/src/hooks/useTreeFocus.ts +14 -3
- package/src/hooks/useTypeahead.test.tsx +150 -0
- package/src/hooks/useTypeahead.ts +24 -9
- package/src/i18n/InternationalizationProvider.doc.mjs +7 -2
- package/src/index.ts +1 -0
- package/src/theme/defineTheme.ts +27 -0
- package/src/theme/derivedVarRegistry.test.ts +21 -1
- package/src/theme/derivedVarRegistry.ts +19 -6
- package/src/theme/expandColorScale.test.ts +14 -0
- package/src/theme/expandColorScale.ts +24 -9
- package/src/theme/expandTypeScale.test.ts +43 -0
- package/src/theme/expandTypeScale.ts +17 -0
- package/src/theme/generateThemeRules.test.ts +78 -20
- package/src/theme/generateThemeRules.ts +11 -0
- package/src/theme/index.ts +15 -0
- package/src/theme/tokens.stylex.ts +18 -0
- package/src/theme/tokens.test.ts +37 -0
- package/src/utils/focusOutline.stylex.ts +177 -0
- package/src/utils/focusReturn.test.ts +42 -0
- package/src/utils/focusReturn.ts +31 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/mergeRefs.test.ts +48 -0
- package/src/utils/mergeRefs.ts +12 -6
- package/src/utils/rtlStyles.ts +2 -2
- package/src/utils/themeProps.ts +26 -4
- package/dist/CheckboxInput/checkbox.markers.stylex.d.ts +0 -9
- package/dist/CheckboxInput/checkbox.markers.stylex.d.ts.map +0 -1
- package/dist/CheckboxInput/checkbox.markers.stylex.js +0 -14
- package/dist/RadioList/radio.markers.stylex.d.ts +0 -7
- package/dist/RadioList/radio.markers.stylex.d.ts.map +0 -1
- package/dist/RadioList/radio.markers.stylex.js +0 -12
- package/dist/hooks/containerReveal.pool.stylex.d.ts +0 -303
- package/dist/hooks/containerReveal.pool.stylex.d.ts.map +0 -1
- package/dist/hooks/containerReveal.pool.stylex.js +0 -292
- package/src/CheckboxInput/checkbox.markers.stylex.ts +0 -12
- package/src/RadioList/radio.markers.stylex.ts +0 -10
- package/src/hooks/containerReveal.pool.stylex.ts +0 -571
|
@@ -30,13 +30,12 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
30
30
|
import {
|
|
31
31
|
colorVars,
|
|
32
32
|
sizeVars,
|
|
33
|
-
radiusVars,
|
|
34
33
|
typographyVars,
|
|
35
34
|
typeScaleVars,
|
|
36
|
-
borderVars,
|
|
37
35
|
} from '../theme/tokens.stylex';
|
|
38
36
|
import {
|
|
39
37
|
Field,
|
|
38
|
+
InputClearButton,
|
|
40
39
|
type InputStatus,
|
|
41
40
|
inputWrapperStyles,
|
|
42
41
|
inputStatusBorderStyles,
|
|
@@ -44,30 +43,13 @@ import {
|
|
|
44
43
|
inputStatusFocusWithinStyles,
|
|
45
44
|
type FieldStatusVariant,
|
|
46
45
|
} from '../Field';
|
|
47
|
-
import {
|
|
46
|
+
import {renderIconSlot, type IconType} from '../Icon';
|
|
48
47
|
import {Spinner} from '../Spinner';
|
|
49
48
|
import {useTooltip} from '../Tooltip';
|
|
50
49
|
import {VisuallyHidden} from '../VisuallyHidden';
|
|
51
50
|
import {getInputARIA} from '../utils';
|
|
52
51
|
|
|
53
52
|
const styles = stylex.create({
|
|
54
|
-
clearButton: {
|
|
55
|
-
display: 'flex',
|
|
56
|
-
alignItems: 'center',
|
|
57
|
-
justifyContent: 'center',
|
|
58
|
-
padding: 0,
|
|
59
|
-
margin: 0,
|
|
60
|
-
borderWidth: 0,
|
|
61
|
-
borderStyle: 'none',
|
|
62
|
-
backgroundColor: 'transparent',
|
|
63
|
-
cursor: 'pointer',
|
|
64
|
-
borderRadius: radiusVars['--radius-element'],
|
|
65
|
-
outline: {
|
|
66
|
-
default: 'none',
|
|
67
|
-
':focus-visible': `${borderVars['--border-width']} solid ${colorVars['--color-accent']}`,
|
|
68
|
-
},
|
|
69
|
-
outlineOffset: 1,
|
|
70
|
-
},
|
|
71
53
|
input: {
|
|
72
54
|
display: 'block',
|
|
73
55
|
flex: 1,
|
|
@@ -166,6 +148,15 @@ export interface TextInputProps extends Omit<
|
|
|
166
148
|
* @default false
|
|
167
149
|
*/
|
|
168
150
|
isDisabled?: boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Whether the input is read-only.
|
|
153
|
+
* The value is shown at full opacity and still submits with the form, but
|
|
154
|
+
* cannot be edited. Unlike `isDisabled`, a read-only input is not dimmed and
|
|
155
|
+
* stays in the tab order — use it for a value the user should see and send
|
|
156
|
+
* but not change. `isDisabled` takes precedence when both are set.
|
|
157
|
+
* @default false
|
|
158
|
+
*/
|
|
159
|
+
isReadOnly?: boolean;
|
|
169
160
|
/**
|
|
170
161
|
* Explains why the input is disabled. When set together with `isDisabled`,
|
|
171
162
|
* the input shows a tooltip with this text on hover and keyboard focus, and
|
|
@@ -285,6 +276,7 @@ export function TextInput({
|
|
|
285
276
|
isOptional = false,
|
|
286
277
|
isRequired = false,
|
|
287
278
|
isDisabled = false,
|
|
279
|
+
isReadOnly = false,
|
|
288
280
|
disabledMessage,
|
|
289
281
|
startIcon,
|
|
290
282
|
status,
|
|
@@ -365,7 +357,7 @@ export function TextInput({
|
|
|
365
357
|
// Value can't change while showing a disabled message (the field is
|
|
366
358
|
// read-only and non-native-disabled), but guard the handler too so the
|
|
367
359
|
// optimistic value and callbacks never fire.
|
|
368
|
-
if (isDisabled) {
|
|
360
|
+
if (isDisabled || isReadOnly) {
|
|
369
361
|
return;
|
|
370
362
|
}
|
|
371
363
|
const newValue = e.target.value;
|
|
@@ -404,7 +396,12 @@ export function TextInput({
|
|
|
404
396
|
onClick={handleWrapperClick}
|
|
405
397
|
onMouseUp={handleWrapperMouseUp}
|
|
406
398
|
{...mergeProps(
|
|
407
|
-
themeProps('text-input', {
|
|
399
|
+
themeProps('text-input', {
|
|
400
|
+
size,
|
|
401
|
+
status: status?.type ?? null,
|
|
402
|
+
disabled: isDisabled ? 'disabled' : null,
|
|
403
|
+
readonly: isReadOnly ? 'readonly' : null,
|
|
404
|
+
}),
|
|
408
405
|
stylex.props(
|
|
409
406
|
inputWrapperStyles.base,
|
|
410
407
|
sizeStyles[size],
|
|
@@ -424,7 +421,7 @@ export function TextInput({
|
|
|
424
421
|
{...rest}
|
|
425
422
|
ref={mergeRefs(ref, inputRef)}
|
|
426
423
|
id={id}
|
|
427
|
-
name={htmlName}
|
|
424
|
+
name={isDisabled ? undefined : htmlName}
|
|
428
425
|
type={type}
|
|
429
426
|
value={optimisticValue}
|
|
430
427
|
onChange={handleChange}
|
|
@@ -444,7 +441,7 @@ export function TextInput({
|
|
|
444
441
|
// keep the value from changing.
|
|
445
442
|
disabled={isDisabled && !showsDisabledMessage}
|
|
446
443
|
aria-disabled={showsDisabledMessage ? 'true' : undefined}
|
|
447
|
-
readOnly={showsDisabledMessage || undefined}
|
|
444
|
+
readOnly={isReadOnly || showsDisabledMessage || undefined}
|
|
448
445
|
autoFocus={hasAutoFocus}
|
|
449
446
|
data-autofocus={hasAutoFocus || undefined}
|
|
450
447
|
aria-describedby={ariaDescribedBy}
|
|
@@ -454,14 +451,11 @@ export function TextInput({
|
|
|
454
451
|
aria-labelledby={ariaLabelledBy}
|
|
455
452
|
{...stylex.props(styles.input, isDisabled && styles.inputDisabled)}
|
|
456
453
|
/>
|
|
457
|
-
{hasClear && value !== '' && !isDisabled && (
|
|
458
|
-
<
|
|
459
|
-
|
|
454
|
+
{hasClear && value !== '' && !isDisabled && !isReadOnly && (
|
|
455
|
+
<InputClearButton
|
|
456
|
+
label={t('@astryx.textInput.clearLabel', {label})}
|
|
460
457
|
onClick={handleClear}
|
|
461
|
-
|
|
462
|
-
{...stylex.props(styles.clearButton)}>
|
|
463
|
-
<Icon icon="close" size="sm" color="secondary" />
|
|
464
|
-
</button>
|
|
458
|
+
/>
|
|
465
459
|
)}
|
|
466
460
|
{isBusy && <Spinner size="sm" />}
|
|
467
461
|
{statusIcon}
|
|
@@ -44,6 +44,7 @@ import {useContainerReveal} from '../hooks/useContainerReveal';
|
|
|
44
44
|
import type {BaseProps} from '../BaseProps';
|
|
45
45
|
import {mergeProps} from '../utils';
|
|
46
46
|
import {themeProps} from '../utils/themeProps';
|
|
47
|
+
import {focusOutlineProps} from '../utils/focusOutline.stylex';
|
|
47
48
|
import {useTranslator} from '../i18n';
|
|
48
49
|
|
|
49
50
|
export interface ThumbnailProps extends BaseProps<HTMLDivElement> {
|
|
@@ -159,14 +160,6 @@ const styles = stylex.create({
|
|
|
159
160
|
},
|
|
160
161
|
interactive: {
|
|
161
162
|
cursor: 'pointer',
|
|
162
|
-
outline: {
|
|
163
|
-
default: null,
|
|
164
|
-
':has(:focus-visible)': `2px solid ${colorVars['--color-accent']}`,
|
|
165
|
-
},
|
|
166
|
-
outlineOffset: {
|
|
167
|
-
default: '0',
|
|
168
|
-
':has(:focus-visible)': '2px',
|
|
169
|
-
},
|
|
170
163
|
},
|
|
171
164
|
// Hover/pressed overlay — the exact same treatment as ClickableCard and
|
|
172
165
|
// SelectableCard. A transparent `::after` tints on hover/press instead of
|
|
@@ -402,7 +395,7 @@ export function Thumbnail({
|
|
|
402
395
|
{...props}>
|
|
403
396
|
<div
|
|
404
397
|
{...mergeProps(
|
|
405
|
-
|
|
398
|
+
focusOutlineProps.focusWithin(
|
|
406
399
|
styles.imageContainer,
|
|
407
400
|
isInteractive && styles.interactive,
|
|
408
401
|
isInteractive && styles.overlay,
|
|
@@ -257,7 +257,7 @@ export const docs = {
|
|
|
257
257
|
],
|
|
258
258
|
theming: {
|
|
259
259
|
targets: [
|
|
260
|
-
{className: 'astryx-time-input', visualProps: ['size', 'status']},
|
|
260
|
+
{className: 'astryx-time-input', visualProps: ['size', 'status'], states: ['disabled']},
|
|
261
261
|
],
|
|
262
262
|
},
|
|
263
263
|
};
|
|
@@ -406,7 +406,7 @@ export const docsZh = {
|
|
|
406
406
|
],
|
|
407
407
|
theming: {
|
|
408
408
|
targets: [
|
|
409
|
-
{className: 'astryx-time-input', visualProps: ['size', 'status']},
|
|
409
|
+
{className: 'astryx-time-input', visualProps: ['size', 'status'], states: ['disabled']},
|
|
410
410
|
],
|
|
411
411
|
},
|
|
412
412
|
usage: {
|
|
@@ -14,6 +14,7 @@ import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import {TimeInput} from './TimeInput';
|
|
16
16
|
import {InputGroup, InputGroupText} from '../InputGroup';
|
|
17
|
+
import {InternationalizationProvider} from '../i18n';
|
|
17
18
|
import type {ISOTimeString} from '../utils';
|
|
18
19
|
import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
|
|
19
20
|
|
|
@@ -209,6 +210,59 @@ describe('TimeInput', () => {
|
|
|
209
210
|
expect(screen.queryByText('Invalid time')).not.toBeInTheDocument();
|
|
210
211
|
});
|
|
211
212
|
|
|
213
|
+
it('resolves the invalid-time announcement from the i18n catalog', () => {
|
|
214
|
+
render(
|
|
215
|
+
<InternationalizationProvider
|
|
216
|
+
locale="en"
|
|
217
|
+
overrides={{en: {'@astryx.timeInput.invalidTime': 'Ungültige Zeit'}}}>
|
|
218
|
+
<TimeInput label="Time" onChange={() => {}} />
|
|
219
|
+
</InternationalizationProvider>,
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
fireEvent.change(screen.getByRole('textbox'), {target: {value: '25:99'}});
|
|
223
|
+
|
|
224
|
+
expect(screen.getByRole('alert')).toHaveTextContent('Ungültige Zeit');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Arrow-key stepping mutates a plain textbox programmatically, and screen
|
|
228
|
+
// readers do not announce programmatic textbox changes — the new value must
|
|
229
|
+
// be announced through the polite live region (WCAG 4.1.2).
|
|
230
|
+
it('politely announces the new time after ArrowUp stepping', async () => {
|
|
231
|
+
const onChange = vi.fn();
|
|
232
|
+
render(
|
|
233
|
+
<TimeInput
|
|
234
|
+
label="Time"
|
|
235
|
+
value={'14:30' as ISOTimeString}
|
|
236
|
+
onChange={onChange}
|
|
237
|
+
/>,
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
fireEvent.keyDown(screen.getByRole('textbox'), {key: 'ArrowUp'});
|
|
241
|
+
|
|
242
|
+
expect(onChange).toHaveBeenCalledWith('14:31');
|
|
243
|
+
await waitFor(() => {
|
|
244
|
+
expect(politeRegion()).toHaveTextContent('2:31 PM');
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('politely announces the new time after ArrowDown stepping', async () => {
|
|
249
|
+
const onChange = vi.fn();
|
|
250
|
+
render(
|
|
251
|
+
<TimeInput
|
|
252
|
+
label="Time"
|
|
253
|
+
value={'14:30' as ISOTimeString}
|
|
254
|
+
onChange={onChange}
|
|
255
|
+
/>,
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
fireEvent.keyDown(screen.getByRole('textbox'), {key: 'ArrowDown'});
|
|
259
|
+
|
|
260
|
+
expect(onChange).toHaveBeenCalledWith('14:29');
|
|
261
|
+
await waitFor(() => {
|
|
262
|
+
expect(politeRegion()).toHaveTextContent('2:29 PM');
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
212
266
|
it('calls onChange on blur when input is valid', async () => {
|
|
213
267
|
const user = userEvent.setup();
|
|
214
268
|
const onChange = vi.fn();
|
|
@@ -572,11 +626,15 @@ describe('TimeInput', () => {
|
|
|
572
626
|
});
|
|
573
627
|
});
|
|
574
628
|
|
|
575
|
-
|
|
576
629
|
describe('TimeInput statusVariant forwarding', () => {
|
|
577
630
|
it('defaults to attached (status renders with data-variant="attached")', () => {
|
|
578
631
|
const {container} = render(
|
|
579
|
-
<TimeInput
|
|
632
|
+
<TimeInput
|
|
633
|
+
label="Start"
|
|
634
|
+
value={undefined}
|
|
635
|
+
onChange={() => {}}
|
|
636
|
+
status={{type: 'error', message: 'Required'}}
|
|
637
|
+
/>,
|
|
580
638
|
);
|
|
581
639
|
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
582
640
|
'data-variant',
|
|
@@ -586,7 +644,13 @@ describe('TimeInput statusVariant forwarding', () => {
|
|
|
586
644
|
|
|
587
645
|
it('forwards statusVariant="detached" to the underlying Field status', () => {
|
|
588
646
|
const {container} = render(
|
|
589
|
-
<TimeInput
|
|
647
|
+
<TimeInput
|
|
648
|
+
label="Start"
|
|
649
|
+
value={undefined}
|
|
650
|
+
onChange={() => {}}
|
|
651
|
+
status={{type: 'error', message: 'Required'}}
|
|
652
|
+
statusVariant="detached"
|
|
653
|
+
/>,
|
|
590
654
|
);
|
|
591
655
|
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
592
656
|
'data-variant',
|
|
@@ -594,3 +658,20 @@ describe('TimeInput statusVariant forwarding', () => {
|
|
|
594
658
|
);
|
|
595
659
|
});
|
|
596
660
|
});
|
|
661
|
+
|
|
662
|
+
describe('TimeInput disabled theme state', () => {
|
|
663
|
+
it('reflects disabled on the root target so themes can gate paint on it', () => {
|
|
664
|
+
const {container} = render(
|
|
665
|
+
<TimeInput label="Time" onChange={() => {}} isDisabled />,
|
|
666
|
+
);
|
|
667
|
+
const root = container.querySelector('.astryx-time-input');
|
|
668
|
+
expect(root).toHaveAttribute('data-disabled', 'disabled');
|
|
669
|
+
expect(root).toHaveClass('disabled');
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
it('omits data-disabled when enabled, like status does', () => {
|
|
673
|
+
const {container} = render(<TimeInput label="Time" onChange={() => {}} />);
|
|
674
|
+
const root = container.querySelector('.astryx-time-input');
|
|
675
|
+
expect(root).not.toHaveAttribute('data-disabled');
|
|
676
|
+
});
|
|
677
|
+
});
|
|
@@ -32,13 +32,12 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
32
32
|
import {
|
|
33
33
|
colorVars,
|
|
34
34
|
sizeVars,
|
|
35
|
-
radiusVars,
|
|
36
35
|
typographyVars,
|
|
37
36
|
typeScaleVars,
|
|
38
|
-
borderVars,
|
|
39
37
|
} from '../theme/tokens.stylex';
|
|
40
38
|
import {
|
|
41
39
|
Field,
|
|
40
|
+
InputClearButton,
|
|
42
41
|
type InputStatus,
|
|
43
42
|
inputWrapperStyles,
|
|
44
43
|
inputStatusBorderStyles,
|
|
@@ -106,23 +105,6 @@ const styles = stylex.create({
|
|
|
106
105
|
inputInvalid: {
|
|
107
106
|
color: colorVars['--color-text-secondary'],
|
|
108
107
|
},
|
|
109
|
-
clearButton: {
|
|
110
|
-
display: 'flex',
|
|
111
|
-
alignItems: 'center',
|
|
112
|
-
justifyContent: 'center',
|
|
113
|
-
padding: 0,
|
|
114
|
-
margin: 0,
|
|
115
|
-
borderWidth: 0,
|
|
116
|
-
borderStyle: 'none',
|
|
117
|
-
backgroundColor: 'transparent',
|
|
118
|
-
cursor: 'pointer',
|
|
119
|
-
borderRadius: radiusVars['--radius-element'],
|
|
120
|
-
outline: {
|
|
121
|
-
default: 'none',
|
|
122
|
-
':focus-visible': `${borderVars['--border-width']} solid ${colorVars['--color-accent']}`,
|
|
123
|
-
},
|
|
124
|
-
outlineOffset: 1,
|
|
125
|
-
},
|
|
126
108
|
});
|
|
127
109
|
|
|
128
110
|
const sizeStyles = stylex.create({
|
|
@@ -576,10 +558,25 @@ export function TimeInput({
|
|
|
576
558
|
// Check if within range
|
|
577
559
|
if (isTimeInRange(newTime, min, max)) {
|
|
578
560
|
fireChange(newTime);
|
|
561
|
+
// Stepping programmatically rewrites a plain textbox's value, and
|
|
562
|
+
// screen readers do not announce programmatic textbox changes — the
|
|
563
|
+
// new value must be spoken explicitly or stepping is silent
|
|
564
|
+
// (WCAG 4.1.2).
|
|
565
|
+
announce(formatDisplayTime(newTime, hasSeconds));
|
|
579
566
|
}
|
|
580
567
|
}
|
|
581
568
|
},
|
|
582
|
-
[
|
|
569
|
+
[
|
|
570
|
+
value,
|
|
571
|
+
hasSeconds,
|
|
572
|
+
increment,
|
|
573
|
+
min,
|
|
574
|
+
max,
|
|
575
|
+
fireChange,
|
|
576
|
+
isDisabled,
|
|
577
|
+
announce,
|
|
578
|
+
formatDisplayTime,
|
|
579
|
+
],
|
|
583
580
|
);
|
|
584
581
|
|
|
585
582
|
// Handle clear button click
|
|
@@ -608,7 +605,11 @@ export function TimeInput({
|
|
|
608
605
|
onClick={handleWrapperClick}
|
|
609
606
|
onMouseUp={handleWrapperMouseUp}
|
|
610
607
|
{...mergeProps(
|
|
611
|
-
themeProps('time-input', {
|
|
608
|
+
themeProps('time-input', {
|
|
609
|
+
size,
|
|
610
|
+
status: status?.type ?? null,
|
|
611
|
+
disabled: isDisabled ? 'disabled' : null,
|
|
612
|
+
}),
|
|
612
613
|
stylex.props(
|
|
613
614
|
inputWrapperStyles.base,
|
|
614
615
|
sizeStyles[size],
|
|
@@ -673,17 +674,14 @@ export function TimeInput({
|
|
|
673
674
|
user would get no feedback that their entry was rejected (WCAG 3.3.1).
|
|
674
675
|
*/}
|
|
675
676
|
<VisuallyHidden as="div" role="alert" aria-live="assertive">
|
|
676
|
-
{!isInputValid ? '
|
|
677
|
+
{!isInputValid ? t('@astryx.timeInput.invalidTime') : ''}
|
|
677
678
|
</VisuallyHidden>
|
|
678
679
|
{isBusy && <Spinner size="sm" />}
|
|
679
680
|
{hasClear && value && !isDisabled && (
|
|
680
|
-
<
|
|
681
|
-
|
|
681
|
+
<InputClearButton
|
|
682
|
+
label={t('@astryx.timeInput.clearLabel', {label})}
|
|
682
683
|
onClick={handleClear}
|
|
683
|
-
|
|
684
|
-
{...stylex.props(styles.clearButton)}>
|
|
685
|
-
<Icon icon="close" size="sm" color="secondary" />
|
|
686
|
-
</button>
|
|
684
|
+
/>
|
|
687
685
|
)}
|
|
688
686
|
{statusIcon}
|
|
689
687
|
</div>
|
|
@@ -49,7 +49,7 @@ export const docs = {
|
|
|
49
49
|
name: 'tooltipEntries',
|
|
50
50
|
type: 'ReadonlyArray<{timezoneID?: string; format?: TimestampTooltipFormat; label?: string; isCopyable?: boolean}>',
|
|
51
51
|
description:
|
|
52
|
-
"Lines to show on hover, so one instant can be read
|
|
52
|
+
"Lines to show on hover, so one instant can be read (and optionally copied) in several time zones and/or formats at once. Each entry is one line, in the order given. Omit timezoneID (or pass 'local') for the viewer's own zone; format defaults to the full absolute style and also accepts 'full' alongside every non-relative TimestampFormat. Rows are read-only unless they set isCopyable (default false); copyable rows show a copy button in a dedicated trailing action column so buttons align, and the column is only present when some row is copyable. With no entries the card shows a single default row with the full absolute time, which is copyable. Configuring entries also attaches the surface to absolute formats, which otherwise have none.",
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
name: 'isTimezoneShown',
|
|
@@ -104,7 +104,7 @@ export const docs = {
|
|
|
104
104
|
{guidance: true, description: 'Use tooltipEntries when readers must compare zones, such as an incident log where the reader\'s time and the event\'s origin zone both matter.'},
|
|
105
105
|
{guidance: true, description: 'Label every entry once a tooltip shows more than one zone; a bare abbreviation is not always recognizable (Tokyo renders as "GMT+9", not "JST").'},
|
|
106
106
|
{guidance: true, description: 'Use isLive for active dashboards or real-time feeds so the relative time stays accurate without a page refresh.'},
|
|
107
|
-
{guidance: true, description: 'Reach for tooltipEntries when readers need to grab an exact value
|
|
107
|
+
{guidance: true, description: 'Reach for tooltipEntries when readers need to grab an exact value: an incident log or deploy record where someone pastes the UTC time or Unix seconds elsewhere; configuring entries turns the hover into copy-to-clipboard rows.'},
|
|
108
108
|
{guidance: false, description: 'Don\'t display raw Unix timestamps or ISO strings to users; always pass them through Timestamp to get a human-readable format.'},
|
|
109
109
|
{guidance: false, description: 'Avoid system_date or system_time formats in user-facing UI; they are meant for developer tools, logs, and machine-readable contexts.'},
|
|
110
110
|
{guidance: false, description: 'Don\'t disable the hover card on relative timestamps; users expect to hover for the full date when they see "3 hours ago".'},
|
|
@@ -147,7 +147,7 @@ export const docsZh = {
|
|
|
147
147
|
{guidance: true, description: 'Use tooltipEntries when readers must compare zones, such as an incident log where the reader\'s time and the event\'s origin zone both matter.'},
|
|
148
148
|
{guidance: true, description: 'Label every entry once a tooltip shows more than one zone; a bare abbreviation is not always recognizable (Tokyo renders as "GMT+9", not "JST").'},
|
|
149
149
|
{guidance: true, description: 'Use isLive for active dashboards or real-time feeds so the relative time stays accurate without a page refresh.'},
|
|
150
|
-
{guidance: true, description: 'Reach for tooltipEntries when readers need to grab an exact value
|
|
150
|
+
{guidance: true, description: 'Reach for tooltipEntries when readers need to grab an exact value: an incident log or deploy record where someone pastes the UTC time or Unix seconds elsewhere; configuring entries turns the hover into copy-to-clipboard rows.'},
|
|
151
151
|
{guidance: false, description: 'Don\'t display raw Unix timestamps or ISO strings to users; always pass them through Timestamp to get a human-readable format.'},
|
|
152
152
|
{guidance: false, description: 'Avoid system_date or system_time formats in user-facing UI; they are meant for developer tools, logs, and machine-readable contexts.'},
|
|
153
153
|
{guidance: false, description: 'Don\'t disable the hover card on relative timestamps; users expect to hover for the full date when they see "3 hours ago".'},
|
|
@@ -176,6 +176,7 @@ export const docsDense = {
|
|
|
176
176
|
{guidance: true, description: 'tooltipEntries to compare zones when the reader time and event zone both matter.'},
|
|
177
177
|
{guidance: true, description: 'Label each entry once a tooltip shows more than one zone; a bare abbreviation is not always recognizable (Tokyo renders "GMT+9", not "JST").'},
|
|
178
178
|
{guidance: true, description: 'isLive for dashboards so relative time stays current.'},
|
|
179
|
+
{guidance: true, description: 'tooltipEntries when readers must grab an exact value: an incident log or deploy record where someone pastes the UTC time or Unix seconds; entries turn the hover into copy-to-clipboard rows.'},
|
|
179
180
|
{guidance: false, description: 'Don\'t show raw Unix timestamps or ISO strings; always use Timestamp.'},
|
|
180
181
|
{guidance: false, description: 'Avoid system_* formats in user-facing UI; those are for dev tools and logs.'},
|
|
181
182
|
{guidance: false, description: 'Don\'t disable the hover card on relative timestamps; users expect the full date on hover.'},
|
|
@@ -408,6 +408,50 @@ describe('Timestamp', () => {
|
|
|
408
408
|
expect(el.getAttribute('aria-label')).toBeNull();
|
|
409
409
|
});
|
|
410
410
|
|
|
411
|
+
// Timezone abbreviations like "PST" or "GMT+2" are unexpanded abbreviations
|
|
412
|
+
// to a screen-reader user (WCAG 3.1.4) — the AT-facing aria-label must spell
|
|
413
|
+
// the timezone out in full, while visible text keeps the compact short form.
|
|
414
|
+
it('uses the long timezone name in the aria-label (WCAG 3.1.4)', () => {
|
|
415
|
+
const oneHourAgo = new Date(Date.now() - 3600 * 1000);
|
|
416
|
+
render(
|
|
417
|
+
<Timestamp
|
|
418
|
+
value={oneHourAgo.getTime() / 1000}
|
|
419
|
+
format="relative"
|
|
420
|
+
hasTooltip={false}
|
|
421
|
+
data-testid="ts"
|
|
422
|
+
/>,
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
const longTz =
|
|
426
|
+
new Intl.DateTimeFormat(undefined, {timeZoneName: 'long'})
|
|
427
|
+
.formatToParts(oneHourAgo)
|
|
428
|
+
.find(p => p.type === 'timeZoneName')?.value ?? '';
|
|
429
|
+
expect(longTz).not.toBe('');
|
|
430
|
+
expect(screen.getByTestId('ts').getAttribute('aria-label')).toContain(
|
|
431
|
+
longTz,
|
|
432
|
+
);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('keeps the short timezone form in visible text when isTimezoneShown', () => {
|
|
436
|
+
const date = new Date('2026-03-25T10:00:00Z');
|
|
437
|
+
render(
|
|
438
|
+
<Timestamp
|
|
439
|
+
value="2026-03-25T10:00:00Z"
|
|
440
|
+
format="time"
|
|
441
|
+
isTimezoneShown
|
|
442
|
+
data-testid="ts"
|
|
443
|
+
/>,
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
const tzPart = (form: 'short' | 'long') =>
|
|
447
|
+
new Intl.DateTimeFormat(undefined, {timeZoneName: form})
|
|
448
|
+
.formatToParts(date)
|
|
449
|
+
.find(p => p.type === 'timeZoneName')?.value ?? '';
|
|
450
|
+
const text = screen.getByTestId('ts').textContent ?? '';
|
|
451
|
+
expect(text).toContain(tzPart('short'));
|
|
452
|
+
expect(text).not.toContain(tzPart('long'));
|
|
453
|
+
});
|
|
454
|
+
|
|
411
455
|
// --- Input handling ---
|
|
412
456
|
|
|
413
457
|
it('accepts Unix timestamp in seconds', () => {
|
|
@@ -602,15 +646,26 @@ describe('Timestamp', () => {
|
|
|
602
646
|
);
|
|
603
647
|
const el = screen.getByTestId('ts');
|
|
604
648
|
|
|
605
|
-
// The card layer mounts inline and carries the full absolute time
|
|
606
|
-
//
|
|
649
|
+
// The card layer mounts inline and carries the full absolute time in
|
|
650
|
+
// its visible form (short timezone abbreviation) as its single default
|
|
651
|
+
// copyable row. The aria-label spells the timezone out in full
|
|
652
|
+
// (WCAG 3.1.4), so the two strings intentionally differ — compare the
|
|
653
|
+
// card against an independently formatted short-form string.
|
|
607
654
|
// Compare with normalized whitespace: Intl output can contain narrow
|
|
608
655
|
// no-break spaces that jest-dom's matcher normalization would break on.
|
|
609
656
|
const card = await screen.findByRole('dialog', {hidden: true});
|
|
610
657
|
const normalize = (s: string) => s.replace(/\s+/g, ' ');
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
658
|
+
const datetime = new Date(el.getAttribute('datetime') ?? '');
|
|
659
|
+
const expected = new Intl.DateTimeFormat(undefined, {
|
|
660
|
+
year: 'numeric',
|
|
661
|
+
month: 'long',
|
|
662
|
+
day: 'numeric',
|
|
663
|
+
hour: 'numeric',
|
|
664
|
+
minute: '2-digit',
|
|
665
|
+
second: '2-digit',
|
|
666
|
+
timeZoneName: 'short',
|
|
667
|
+
}).format(datetime);
|
|
668
|
+
expect(normalize(card.textContent ?? '')).toContain(normalize(expected));
|
|
614
669
|
|
|
615
670
|
// Tab onto the timestamp — the only tab stop in the document.
|
|
616
671
|
await user.tab();
|
|
@@ -705,15 +760,28 @@ describe('Timestamp', () => {
|
|
|
705
760
|
// The default card is the named details card, exactly as the configured
|
|
706
761
|
// one is.
|
|
707
762
|
expect(card).toHaveAttribute('aria-label', 'Timestamp details');
|
|
708
|
-
// Exactly one row, carrying the full absolute time
|
|
709
|
-
//
|
|
763
|
+
// Exactly one row, carrying the full absolute time in its visible form
|
|
764
|
+
// (short timezone abbreviation) with its own copy button. The
|
|
765
|
+
// aria-label spells the timezone out in full (WCAG 3.1.4), so the two
|
|
766
|
+
// strings intentionally differ — compare the row against an
|
|
767
|
+
// independently formatted short-form string.
|
|
710
768
|
expect(card.querySelectorAll('dd')).toHaveLength(1);
|
|
711
769
|
expect(card.querySelectorAll('button')).toHaveLength(1);
|
|
712
770
|
|
|
713
771
|
const normalize = (s: string) => s.replace(/\s+/g, ' ');
|
|
714
|
-
|
|
715
|
-
|
|
772
|
+
const datetime = new Date(
|
|
773
|
+
screen.getByTestId('ts').getAttribute('datetime') ?? '',
|
|
716
774
|
);
|
|
775
|
+
const expected = new Intl.DateTimeFormat(undefined, {
|
|
776
|
+
year: 'numeric',
|
|
777
|
+
month: 'long',
|
|
778
|
+
day: 'numeric',
|
|
779
|
+
hour: 'numeric',
|
|
780
|
+
minute: '2-digit',
|
|
781
|
+
second: '2-digit',
|
|
782
|
+
timeZoneName: 'short',
|
|
783
|
+
}).format(datetime);
|
|
784
|
+
expect(normalize(card.textContent ?? '')).toContain(normalize(expected));
|
|
717
785
|
});
|
|
718
786
|
|
|
719
787
|
it("copies the default absolute row's value", async () => {
|
|
@@ -1171,10 +1239,14 @@ describe('Timestamp', () => {
|
|
|
1171
1239
|
},
|
|
1172
1240
|
);
|
|
1173
1241
|
|
|
1174
|
-
it('renders the full style
|
|
1242
|
+
it('renders the full style as the aria-label and as a line, differing only in zone-name spelling', () => {
|
|
1175
1243
|
// 'full' is the one member with no visible-text counterpart — it backs
|
|
1176
1244
|
// the accessible name of a relative timestamp and the tooltip's default
|
|
1177
|
-
// line.
|
|
1245
|
+
// line. The two must not drift apart on anything but the zone name: the
|
|
1246
|
+
// aria-label spells the zone out in full for assistive tech (WCAG 3.1.4),
|
|
1247
|
+
// the visible line keeps the abbreviation. Comparing them after swapping
|
|
1248
|
+
// the abbreviation for the spelled-out form keeps this a direct
|
|
1249
|
+
// surface-to-surface check, so re-forking either path still fails here.
|
|
1178
1250
|
render(
|
|
1179
1251
|
<Timestamp
|
|
1180
1252
|
value={VALUE}
|
|
@@ -1183,9 +1255,14 @@ describe('Timestamp', () => {
|
|
|
1183
1255
|
data-testid="ts"
|
|
1184
1256
|
/>,
|
|
1185
1257
|
);
|
|
1186
|
-
const
|
|
1187
|
-
|
|
1188
|
-
|
|
1258
|
+
const date = new Date(VALUE);
|
|
1259
|
+
const tzPart = (form: 'short' | 'long') =>
|
|
1260
|
+
new Intl.DateTimeFormat(undefined, {timeZoneName: form})
|
|
1261
|
+
.formatToParts(date)
|
|
1262
|
+
.find(p => p.type === 'timeZoneName')?.value ?? '';
|
|
1263
|
+
const [line] = formatTooltipLines(date, [{format: 'full'}]);
|
|
1264
|
+
expect(screen.getByTestId('ts').getAttribute('aria-label')).toBe(
|
|
1265
|
+
line.value.replace(tzPart('short'), tzPart('long')),
|
|
1189
1266
|
);
|
|
1190
1267
|
});
|
|
1191
1268
|
});
|
|
@@ -451,8 +451,14 @@ export function Timestamp({
|
|
|
451
451
|
? formatInstant(date, effectiveFormat, {isTimezoneShown})
|
|
452
452
|
: '';
|
|
453
453
|
|
|
454
|
-
// Full absolute text for tooltip
|
|
454
|
+
// Full absolute text for the tooltip (visible — keeps the compact timezone
|
|
455
|
+
// abbreviation) and for the AT-facing aria-label, which spells the timezone
|
|
456
|
+
// out in full: abbreviations like "PST" or "GMT+2" are unexpanded
|
|
457
|
+
// abbreviations to a screen-reader user (WCAG 3.1.4).
|
|
455
458
|
const fullAbsoluteText = isValidDate ? formatInstant(date, 'full') : '';
|
|
459
|
+
const ariaLabelText = isValidDate
|
|
460
|
+
? formatInstant(date, 'full', {timeZoneNameStyle: 'long'})
|
|
461
|
+
: '';
|
|
456
462
|
|
|
457
463
|
// Live updates
|
|
458
464
|
useEffect(() => {
|
|
@@ -518,8 +524,14 @@ export function Timestamp({
|
|
|
518
524
|
<time
|
|
519
525
|
ref={mergeRefs(ref, timeRef)}
|
|
520
526
|
dateTime={isoString}
|
|
527
|
+
// `ariaLabelText` is '' only for an invalid date, which bails out
|
|
528
|
+
// before rendering — but keep the guard local: an empty aria-label
|
|
529
|
+
// must be omitted entirely (not rendered as aria-label="") so AT
|
|
530
|
+
// falls back to reading the visible <time> content.
|
|
521
531
|
aria-label={
|
|
522
|
-
isRelativeFormat(effectiveFormat)
|
|
532
|
+
isRelativeFormat(effectiveFormat) && ariaLabelText !== ''
|
|
533
|
+
? ariaLabelText
|
|
534
|
+
: undefined
|
|
523
535
|
}
|
|
524
536
|
// The hover card is anchored here with focusTrigger="always", which
|
|
525
537
|
// attaches focus listeners but does not itself make the anchor
|