@astryxdesign/core 0.1.8 → 0.1.9
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 +100 -0
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +6 -2
- package/dist/AppShell/AppShellMobileContext.d.ts +8 -0
- package/dist/AppShell/AppShellMobileContext.d.ts.map +1 -1
- package/dist/Avatar/Avatar.d.ts +18 -2
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +63 -7
- package/dist/Avatar/AvatarStatusDot.d.ts +33 -5
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- package/dist/Avatar/AvatarStatusDot.js +144 -19
- package/dist/Banner/Banner.d.ts +9 -1
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +31 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +31 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +208 -6
- package/dist/Breadcrumbs/index.d.ts +5 -0
- package/dist/Breadcrumbs/index.d.ts.map +1 -1
- package/dist/Breadcrumbs/index.js +9 -1
- package/dist/Button/Button.d.ts +8 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +31 -2
- package/dist/ButtonGroup/ButtonGroup.d.ts +9 -1
- package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
- package/dist/ButtonGroup/ButtonGroup.js +30 -1
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +30 -2
- package/dist/Calendar/dayCellUtils.js +1 -1
- package/dist/Card/Card.d.ts +8 -2
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +28 -2
- package/dist/Carousel/Carousel.d.ts +4 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +24 -4
- package/dist/Chat/ChatComposer.d.ts +8 -0
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +46 -7
- package/dist/Chat/ChatComposerDrawer.d.ts +2 -0
- package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
- package/dist/Chat/ChatComposerDrawer.js +11 -1
- package/dist/Chat/ChatComposerInput.d.ts +20 -3
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +35 -3
- package/dist/Chat/ChatContext.d.ts +33 -0
- package/dist/Chat/ChatContext.d.ts.map +1 -1
- package/dist/Chat/ChatContext.js +16 -2
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +1 -1
- package/dist/Chat/ChatLayout.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +4 -4
- package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.js +7 -1
- package/dist/Chat/ChatToolCalls.d.ts +5 -1
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +18 -9
- package/dist/Chat/index.d.ts +2 -1
- package/dist/Chat/index.d.ts.map +1 -1
- package/dist/Chat/index.js +1 -1
- package/dist/Chat/useChatStreamScroll.d.ts +2 -1
- package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
- package/dist/Chat/useChatStreamScroll.js +22 -8
- package/dist/Chat/useSpeechRecognition.d.ts +0 -1
- package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.js +1 -1
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +1 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts +20 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +11 -1
- package/dist/ClickableCard/ClickableCard.d.ts +9 -2
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +5 -2
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +8 -1
- package/dist/CommandPalette/CommandPalette.d.ts +1 -1
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +3 -1
- package/dist/CommandPalette/CommandPaletteGroup.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteGroup.js +9 -2
- package/dist/CommandPalette/CommandPaletteInput.d.ts +7 -1
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +6 -1
- package/dist/DateInput/DateInput.d.ts +47 -1
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +26 -2
- package/dist/DateInput/index.d.ts +1 -1
- package/dist/DateInput/index.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +10 -1
- package/dist/Dialog/Dialog.d.ts +3 -0
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +57 -6
- package/dist/Dialog/DialogContext.d.ts +7 -0
- package/dist/Dialog/DialogContext.d.ts.map +1 -1
- package/dist/Dialog/DialogContext.js +2 -2
- package/dist/Dialog/DialogHeader.d.ts +5 -2
- package/dist/Dialog/DialogHeader.d.ts.map +1 -1
- package/dist/Dialog/DialogHeader.js +6 -1
- package/dist/Divider/Divider.js +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -2
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +1 -2
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +1 -2
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +1 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +2 -3
- package/dist/Field/FieldLabel.d.ts +1 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +42 -15
- package/dist/FieldStatus/FieldStatus.d.ts +8 -0
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +22 -4
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +10 -2
- package/dist/HoverCard/HoverCard.d.ts +9 -1
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +2 -0
- package/dist/HoverCard/useHoverCard.d.ts +8 -0
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +7 -2
- package/dist/Icon/Icon.d.ts +7 -2
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Item/Item.d.ts +6 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +22 -1
- package/dist/Layer/useLayer.d.ts +6 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +2 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +6 -1
- package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
- package/dist/MobileNav/MobileNavToggle.js +4 -0
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +39 -12
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +16 -0
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/Outline/Outline.d.ts +0 -1
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +0 -1
- package/dist/OverflowList/OverflowList.d.ts +20 -3
- package/dist/OverflowList/OverflowList.d.ts.map +1 -1
- package/dist/OverflowList/OverflowList.js +29 -4
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +3 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +3 -9
- package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
- package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.d.ts +9 -2
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +16 -13
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +4 -2
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +16 -0
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +21 -8
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +19 -2
- package/dist/Stack/stack.stylex.d.ts +9 -9
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +3 -2
- package/dist/Table/index.d.ts +2 -0
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +1 -0
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/rowStatus/index.d.ts +3 -0
- package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -0
- package/dist/Table/plugins/rowStatus/index.js +3 -0
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +60 -0
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -0
- package/dist/Table/plugins/rowStatus/useTableRowStatus.js +145 -0
- package/dist/Table/plugins/selection/useTableSelection.d.ts +13 -0
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +4 -1
- package/dist/Table/plugins/tree/useTableTreeData.d.ts +16 -0
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +87 -0
- package/dist/Table/plugins/tree/useTableTreeState.d.ts +6 -0
- package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeState.js +22 -1
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +5 -3
- package/dist/Thumbnail/Thumbnail.d.ts +26 -5
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +97 -54
- package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +9 -0
- package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +1 -0
- package/dist/Thumbnail/thumbnail.markers.stylex.js +14 -0
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +15 -4
- package/dist/Timestamp/Timestamp.d.ts +3 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +8 -6
- package/dist/Toast/useToast.d.ts.map +1 -1
- package/dist/Toast/useToast.js +2 -5
- package/dist/ToggleButton/ToggleButtonGroup.d.ts +0 -1
- package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButtonGroup.js +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +16 -4
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +18 -8
- package/dist/TopNav/TopNavMegaMenu.js +10 -4
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +9 -1
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +8 -1
- package/dist/TopNav/TopNavMenu.d.ts +2 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +68 -6
- package/dist/TreeList/TreeList.d.ts +12 -3
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +2 -0
- package/dist/TreeList/TreeListBranches.d.ts +5 -0
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +10 -4
- package/dist/TreeList/TreeListItem.d.ts +8 -2
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +27 -7
- package/dist/TreeList/TreeListTypes.d.ts +25 -1
- package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
- package/dist/TreeList/index.d.ts +2 -2
- package/dist/TreeList/index.d.ts.map +1 -1
- package/dist/astryx.css +28 -18
- package/dist/astryx.umd.js +51 -51
- package/dist/astryx.umd.js.map +4 -4
- package/dist/authoring/doc.d.ts.map +1 -1
- package/dist/docs-types.d.ts +8 -0
- package/dist/docs-types.d.ts.map +1 -1
- package/dist/hooks/computeOverflow.d.ts +47 -0
- package/dist/hooks/computeOverflow.d.ts.map +1 -0
- package/dist/hooks/computeOverflow.js +213 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -1
- package/dist/hooks/useDevWarning.d.ts +18 -0
- package/dist/hooks/useDevWarning.d.ts.map +1 -0
- package/dist/hooks/useDevWarning.js +49 -0
- package/dist/hooks/useOverflow.d.ts +19 -0
- package/dist/hooks/useOverflow.d.ts.map +1 -1
- package/dist/hooks/useOverflow.js +36 -25
- package/dist/i18n/resolve.d.ts.map +1 -1
- package/dist/i18n/resolve.js +7 -18
- package/dist/theme/Theme.d.ts.map +1 -1
- package/dist/theme/Theme.js +2 -7
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +51 -0
- package/dist/theme/hct.d.ts +0 -1
- package/dist/theme/hct.d.ts.map +1 -1
- package/dist/theme/hct.js +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.js +2 -1
- package/dist/utils/devWarning.d.ts +42 -0
- package/dist/utils/devWarning.d.ts.map +1 -0
- package/dist/utils/devWarning.js +88 -0
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -2
- package/dist/utils/plainDate.d.ts +30 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +53 -0
- package/dist/utils/types.d.ts +13 -0
- package/dist/utils/types.d.ts.map +1 -1
- package/locales/en.json +24 -0
- package/locales/fr-FR.json +14 -0
- package/locales/pseudo.json +18 -0
- package/package.json +1 -1
- package/src/AppShell/AppShell.tsx +6 -0
- package/src/AppShell/AppShellMobileContext.tsx +8 -0
- package/src/AppShell/useAppShellMobile.doc.mjs +8 -0
- package/src/Avatar/Avatar.doc.mjs +15 -3
- package/src/Avatar/Avatar.test.tsx +156 -1
- package/src/Avatar/Avatar.tsx +96 -4
- package/src/Avatar/AvatarStatusDot.doc.mjs +23 -12
- package/src/Avatar/AvatarStatusDot.test.tsx +284 -0
- package/src/Avatar/AvatarStatusDot.tsx +178 -21
- package/src/Banner/Banner.doc.mjs +9 -0
- package/src/Banner/Banner.test.tsx +30 -0
- package/src/Banner/Banner.tsx +47 -3
- package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +26 -0
- package/src/Breadcrumbs/BreadcrumbItem.tsx +333 -14
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -0
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +284 -2
- package/src/Breadcrumbs/index.ts +27 -0
- package/src/Button/Button.doc.mjs +9 -0
- package/src/Button/Button.test.tsx +49 -0
- package/src/Button/Button.tsx +25 -1
- package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -0
- package/src/ButtonGroup/ButtonGroup.test.tsx +37 -0
- package/src/ButtonGroup/ButtonGroup.tsx +32 -0
- package/src/Calendar/Calendar.doc.mjs +12 -1
- package/src/Calendar/Calendar.test.tsx +193 -0
- package/src/Calendar/Calendar.tsx +38 -16
- package/src/Calendar/dayCellUtils.test.ts +5 -0
- package/src/Calendar/dayCellUtils.ts +1 -1
- package/src/Card/Card.doc.mjs +9 -0
- package/src/Card/Card.test.tsx +21 -3
- package/src/Card/Card.tsx +35 -2
- package/src/Carousel/Carousel.doc.mjs +1 -0
- package/src/Carousel/Carousel.test.tsx +53 -0
- package/src/Carousel/Carousel.tsx +34 -4
- package/src/Chat/ChatComposer.doc.mjs +12 -3
- package/src/Chat/ChatComposer.test.tsx +115 -0
- package/src/Chat/ChatComposer.tsx +73 -9
- package/src/Chat/ChatComposerDrawer.test.tsx +61 -0
- package/src/Chat/ChatComposerDrawer.tsx +11 -1
- package/src/Chat/ChatComposerInput.doc.mjs +7 -0
- package/src/Chat/ChatComposerInput.test.tsx +103 -0
- package/src/Chat/ChatComposerInput.tsx +49 -3
- package/src/Chat/ChatContext.tsx +37 -10
- package/src/Chat/ChatDictationButton.tsx +4 -1
- package/src/Chat/ChatLayout.tsx +3 -1
- package/src/Chat/ChatLayoutScrollButton.tsx +7 -2
- package/src/Chat/ChatMessageMetadata.tsx +1 -2
- package/src/Chat/ChatSendButton.tsx +11 -1
- package/src/Chat/ChatToolCalls.test.tsx +64 -0
- package/src/Chat/ChatToolCalls.tsx +25 -4
- package/src/Chat/index.ts +5 -1
- package/src/Chat/useChatStreamScroll.test.tsx +49 -0
- package/src/Chat/useChatStreamScroll.ts +27 -10
- package/src/Chat/useSpeechRecognition.ts +1 -1
- package/src/Chat/useTriggerMenu.tsx +3 -1
- package/src/CheckboxInput/CheckboxInput.test.tsx +32 -1
- package/src/CheckboxInput/CheckboxInput.tsx +1 -1
- package/src/CheckboxList/CheckboxList.test.tsx +81 -3
- package/src/CheckboxList/CheckboxListItem.doc.mjs +33 -5
- package/src/CheckboxList/CheckboxListItem.tsx +41 -5
- package/src/ClickableCard/ClickableCard.doc.mjs +2 -0
- package/src/ClickableCard/ClickableCard.test.tsx +34 -0
- package/src/ClickableCard/ClickableCard.tsx +13 -3
- package/src/CodeBlock/CodeBlock.test.tsx +56 -0
- package/src/CodeBlock/CodeBlock.tsx +9 -1
- package/src/CommandPalette/CommandPalette.doc.mjs +1 -0
- package/src/CommandPalette/CommandPalette.tsx +3 -1
- package/src/CommandPalette/CommandPaletteGroup.test.tsx +71 -0
- package/src/CommandPalette/CommandPaletteGroup.tsx +12 -1
- package/src/CommandPalette/CommandPaletteInput.doc.mjs +26 -9
- package/src/CommandPalette/CommandPaletteInput.test.tsx +34 -0
- package/src/CommandPalette/CommandPaletteInput.tsx +11 -0
- package/src/ContextMenu/ContextMenu.test.tsx +193 -0
- package/src/DateInput/DateInput.doc.mjs +16 -0
- package/src/DateInput/DateInput.test.tsx +108 -0
- package/src/DateInput/DateInput.tsx +68 -3
- package/src/DateInput/index.ts +1 -0
- package/src/DateTimeInput/DateTimeInput.test.tsx +35 -0
- package/src/DateTimeInput/DateTimeInput.tsx +14 -2
- package/src/Dialog/Dialog.doc.mjs +2 -2
- package/src/Dialog/Dialog.test.tsx +77 -4
- package/src/Dialog/Dialog.tsx +89 -5
- package/src/Dialog/DialogContext.ts +9 -2
- package/src/Dialog/DialogHeader.doc.mjs +2 -2
- package/src/Dialog/DialogHeader.tsx +9 -2
- package/src/Divider/Divider.tsx +2 -2
- package/src/DropdownMenu/DropdownMenu.test.tsx +169 -0
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -2
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +1 -2
- package/src/Field/Field.test.tsx +57 -12
- package/src/Field/Field.tsx +6 -5
- package/src/Field/FieldLabel.tsx +8 -0
- package/src/FieldStatus/FieldStatus.doc.mjs +17 -5
- package/src/FieldStatus/FieldStatus.test.tsx +78 -40
- package/src/FieldStatus/FieldStatus.tsx +22 -4
- package/src/FileInput/FileInput.test.tsx +52 -3
- package/src/FileInput/FileInput.tsx +13 -2
- package/src/HoverCard/HoverCard.doc.mjs +13 -0
- package/src/HoverCard/HoverCard.test.tsx +21 -2
- package/src/HoverCard/HoverCard.tsx +11 -0
- package/src/HoverCard/useHoverCard.doc.mjs +2 -0
- package/src/HoverCard/useHoverCard.tsx +24 -2
- package/src/Icon/Icon.doc.mjs +3 -2
- package/src/Icon/Icon.tsx +7 -2
- package/src/IconButton/IconButton.doc.mjs +8 -0
- package/src/IconButton/IconButton.test.tsx +15 -18
- package/src/Item/Item.test.tsx +40 -18
- package/src/Item/Item.tsx +38 -2
- package/src/Layer/useLayer.tsx +8 -0
- package/src/List/List.test.tsx +9 -8
- package/src/MobileNav/MobileNav.tsx +12 -1
- package/src/MobileNav/MobileNavToggle.test.tsx +116 -0
- package/src/MobileNav/MobileNavToggle.tsx +9 -1
- package/src/MultiSelector/MultiSelector.doc.mjs +4 -2
- package/src/MultiSelector/MultiSelector.test.tsx +172 -3
- package/src/MultiSelector/MultiSelector.tsx +55 -12
- package/src/MultiSelector/hooks.ts +17 -0
- package/src/NumberInput/NumberInput.test.tsx +11 -7
- package/src/NumberInput/NumberInput.tsx +1 -2
- package/src/Outline/Outline.tsx +0 -1
- package/src/OverflowList/OverflowList.doc.mjs +39 -6
- package/src/OverflowList/OverflowList.test.tsx +111 -0
- package/src/OverflowList/OverflowList.tsx +48 -8
- package/src/Popover/Popover.tsx +7 -4
- package/src/Popover/usePopover.tsx +9 -13
- package/src/PowerSearch/PowerSearch.doc.mjs +14 -0
- package/src/PowerSearch/PowerSearch.test.tsx +20 -0
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +67 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
- package/src/PowerSearch/usePowerSearchSource.ts +1 -2
- package/src/SelectableCard/SelectableCard.doc.mjs +2 -0
- package/src/SelectableCard/SelectableCard.test.tsx +46 -4
- package/src/SelectableCard/SelectableCard.tsx +29 -16
- package/src/Selector/Selector.test.tsx +69 -0
- package/src/Selector/Selector.tsx +5 -1
- package/src/Selector/hooks.ts +17 -0
- package/src/SideNav/SideNav.test.tsx +119 -3
- package/src/SideNav/SideNavCollapseButton.tsx +6 -1
- package/src/SideNav/SideNavHeading.tsx +24 -8
- package/src/SideNav/SideNavItem.tsx +5 -1
- package/src/Slider/Slider.test.tsx +75 -2
- package/src/Slider/Slider.tsx +21 -5
- package/src/Switch/Switch.test.tsx +32 -1
- package/src/Table/BaseTable.tsx +3 -5
- package/src/Table/index.ts +5 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +6 -2
- package/src/Table/plugins/rowStatus/index.ts +7 -0
- package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +138 -0
- package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +189 -0
- package/src/Table/plugins/selection/useTableSelection.test.tsx +16 -0
- package/src/Table/plugins/selection/useTableSelection.tsx +19 -1
- package/src/Table/plugins/tree/useTableTreeData.test.tsx +135 -3
- package/src/Table/plugins/tree/useTableTreeData.tsx +128 -1
- package/src/Table/plugins/tree/useTableTreeState.test.tsx +104 -0
- package/src/Table/plugins/tree/useTableTreeState.tsx +46 -2
- package/src/Table/useBaseTablePlugins.ts +10 -6
- package/src/Table/useTableRowStatus.doc.mjs +30 -0
- package/src/Table/useTableSelection.doc.mjs +65 -14
- package/src/Table/useTableTreeData.doc.mjs +29 -0
- package/src/Table/useTableTreeState.doc.mjs +2 -2
- package/src/TextArea/TextArea.test.tsx +9 -1
- package/src/Thumbnail/Thumbnail.doc.mjs +19 -10
- package/src/Thumbnail/Thumbnail.test.tsx +98 -7
- package/src/Thumbnail/Thumbnail.tsx +141 -41
- package/src/Thumbnail/thumbnail.markers.stylex.ts +12 -0
- package/src/TimeInput/TimeInput.test.tsx +76 -1
- package/src/TimeInput/TimeInput.tsx +19 -6
- package/src/Timestamp/Timestamp.doc.mjs +4 -4
- package/src/Timestamp/Timestamp.test.tsx +32 -0
- package/src/Timestamp/Timestamp.tsx +28 -8
- package/src/Toast/useToast.tsx +7 -8
- package/src/ToggleButton/ToggleButtonGroup.tsx +1 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +15 -1
- package/src/Tokenizer/Tokenizer.test.tsx +183 -2
- package/src/Tokenizer/Tokenizer.tsx +16 -4
- package/src/TopNav/TopNav.test.tsx +125 -1
- package/src/TopNav/TopNavHeading.tsx +24 -8
- package/src/TopNav/TopNavMegaMenu.test.tsx +149 -1
- package/src/TopNav/TopNavMegaMenu.tsx +10 -4
- package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +3 -3
- package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +19 -2
- package/src/TopNav/TopNavMenu.test.tsx +118 -4
- package/src/TopNav/TopNavMenu.tsx +83 -5
- package/src/TreeList/TreeList.doc.mjs +22 -0
- package/src/TreeList/TreeList.test.tsx +232 -0
- package/src/TreeList/TreeList.tsx +18 -2
- package/src/TreeList/TreeListBranches.tsx +16 -2
- package/src/TreeList/TreeListItem.tsx +51 -11
- package/src/TreeList/TreeListTypes.ts +27 -1
- package/src/TreeList/index.ts +2 -2
- package/src/authoring/doc.ts +1 -3
- package/src/docs-types.ts +5 -0
- package/src/hooks/computeOverflow.test.ts +422 -0
- package/src/hooks/computeOverflow.ts +290 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useDevWarning.test.tsx +45 -0
- package/src/hooks/useDevWarning.ts +54 -0
- package/src/hooks/useOverflow.test.ts +96 -4
- package/src/hooks/useOverflow.ts +74 -33
- package/src/i18n/InternationalizationProvider.doc.mjs +99 -2
- package/src/i18n/resolve.ts +9 -21
- package/src/theme/Theme.tsx +11 -14
- package/src/theme/generateThemeRules.test.ts +65 -0
- package/src/theme/generateThemeRules.ts +56 -0
- package/src/theme/hct.ts +1 -1
- package/src/theme/syntax/defineSyntaxTheme.ts +5 -6
- package/src/utils/devWarning.test.ts +56 -0
- package/src/utils/devWarning.ts +102 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/plainDate.test.ts +22 -0
- package/src/utils/plainDate.ts +61 -0
- package/src/utils/types.ts +14 -0
|
@@ -611,3 +611,196 @@ describe('ContextMenu selectable items', () => {
|
|
|
611
611
|
expect(onToggle).toHaveBeenCalledWith(true);
|
|
612
612
|
});
|
|
613
613
|
});
|
|
614
|
+
|
|
615
|
+
describe('ContextMenu keyboard access for menuitemradio/menuitemcheckbox (#3829)', () => {
|
|
616
|
+
it('arrow navigation reaches consumer-rendered menuitemradio and menuitemcheckbox items', () => {
|
|
617
|
+
render(
|
|
618
|
+
<ContextMenu
|
|
619
|
+
menuContent={
|
|
620
|
+
<>
|
|
621
|
+
<DropdownMenuItem label="Cut" onClick={() => {}} />
|
|
622
|
+
<div role="menuitemradio" tabIndex={-1} aria-checked="false">
|
|
623
|
+
Newest
|
|
624
|
+
</div>
|
|
625
|
+
<div role="menuitemcheckbox" tabIndex={-1} aria-checked="false">
|
|
626
|
+
Archived
|
|
627
|
+
</div>
|
|
628
|
+
</>
|
|
629
|
+
}>
|
|
630
|
+
<div>Right-click me</div>
|
|
631
|
+
</ContextMenu>,
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
fireEvent.contextMenu(screen.getByText('Right-click me'));
|
|
635
|
+
const menu = screen.getByRole('menu', {hidden: true});
|
|
636
|
+
screen.getByRole('menuitem', {name: 'Cut', hidden: true}).focus();
|
|
637
|
+
|
|
638
|
+
fireEvent.keyDown(menu, {key: 'ArrowDown'});
|
|
639
|
+
expect(
|
|
640
|
+
screen.getByRole('menuitemradio', {name: 'Newest', hidden: true}),
|
|
641
|
+
).toHaveFocus();
|
|
642
|
+
|
|
643
|
+
fireEvent.keyDown(menu, {key: 'ArrowDown'});
|
|
644
|
+
expect(
|
|
645
|
+
screen.getByRole('menuitemcheckbox', {name: 'Archived', hidden: true}),
|
|
646
|
+
).toHaveFocus();
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
it('activates a focused menuitemradio with Enter and a menuitemcheckbox with Space', () => {
|
|
650
|
+
const onSelect = vi.fn();
|
|
651
|
+
const onToggle = vi.fn();
|
|
652
|
+
render(
|
|
653
|
+
<ContextMenu
|
|
654
|
+
menuContent={
|
|
655
|
+
<>
|
|
656
|
+
<DropdownMenuItem label="Cut" onClick={() => {}} />
|
|
657
|
+
<div
|
|
658
|
+
role="menuitemradio"
|
|
659
|
+
tabIndex={-1}
|
|
660
|
+
aria-checked="false"
|
|
661
|
+
onClick={onSelect}>
|
|
662
|
+
Newest
|
|
663
|
+
</div>
|
|
664
|
+
<div
|
|
665
|
+
role="menuitemcheckbox"
|
|
666
|
+
tabIndex={-1}
|
|
667
|
+
aria-checked="false"
|
|
668
|
+
onClick={onToggle}>
|
|
669
|
+
Archived
|
|
670
|
+
</div>
|
|
671
|
+
</>
|
|
672
|
+
}>
|
|
673
|
+
<div>Right-click me</div>
|
|
674
|
+
</ContextMenu>,
|
|
675
|
+
);
|
|
676
|
+
|
|
677
|
+
fireEvent.contextMenu(screen.getByText('Right-click me'));
|
|
678
|
+
const menu = screen.getByRole('menu', {hidden: true});
|
|
679
|
+
|
|
680
|
+
screen.getByRole('menuitemradio', {name: 'Newest', hidden: true}).focus();
|
|
681
|
+
fireEvent.keyDown(menu, {key: 'Enter'});
|
|
682
|
+
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
683
|
+
|
|
684
|
+
screen
|
|
685
|
+
.getByRole('menuitemcheckbox', {name: 'Archived', hidden: true})
|
|
686
|
+
.focus();
|
|
687
|
+
fireEvent.keyDown(menu, {key: ' '});
|
|
688
|
+
expect(onToggle).toHaveBeenCalledTimes(1);
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
it('typeahead matches a menuitemradio label', () => {
|
|
692
|
+
render(
|
|
693
|
+
<ContextMenu
|
|
694
|
+
menuContent={
|
|
695
|
+
<>
|
|
696
|
+
<DropdownMenuItem label="Cut" onClick={() => {}} />
|
|
697
|
+
<div role="menuitemradio" tabIndex={-1} aria-checked="false">
|
|
698
|
+
Newest
|
|
699
|
+
</div>
|
|
700
|
+
<div role="menuitemcheckbox" tabIndex={-1} aria-checked="false">
|
|
701
|
+
Archived
|
|
702
|
+
</div>
|
|
703
|
+
</>
|
|
704
|
+
}>
|
|
705
|
+
<div>Right-click me</div>
|
|
706
|
+
</ContextMenu>,
|
|
707
|
+
);
|
|
708
|
+
|
|
709
|
+
fireEvent.contextMenu(screen.getByText('Right-click me'));
|
|
710
|
+
fireEvent.keyDown(screen.getByRole('menu', {hidden: true}), {key: 'n'});
|
|
711
|
+
expect(
|
|
712
|
+
screen.getByRole('menuitemradio', {name: 'Newest', hidden: true}),
|
|
713
|
+
).toHaveFocus();
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
it('typeahead matches a menuitemcheckbox label', () => {
|
|
717
|
+
render(
|
|
718
|
+
<ContextMenu
|
|
719
|
+
menuContent={
|
|
720
|
+
<>
|
|
721
|
+
<DropdownMenuItem label="Cut" onClick={() => {}} />
|
|
722
|
+
<div role="menuitemradio" tabIndex={-1} aria-checked="false">
|
|
723
|
+
Newest
|
|
724
|
+
</div>
|
|
725
|
+
<div role="menuitemcheckbox" tabIndex={-1} aria-checked="false">
|
|
726
|
+
Archived
|
|
727
|
+
</div>
|
|
728
|
+
</>
|
|
729
|
+
}>
|
|
730
|
+
<div>Right-click me</div>
|
|
731
|
+
</ContextMenu>,
|
|
732
|
+
);
|
|
733
|
+
|
|
734
|
+
fireEvent.contextMenu(screen.getByText('Right-click me'));
|
|
735
|
+
fireEvent.keyDown(screen.getByRole('menu', {hidden: true}), {key: 'a'});
|
|
736
|
+
expect(
|
|
737
|
+
screen.getByRole('menuitemcheckbox', {name: 'Archived', hidden: true}),
|
|
738
|
+
).toHaveFocus();
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
it('typeahead skips an aria-disabled item and matches the next enabled label', () => {
|
|
742
|
+
render(
|
|
743
|
+
<ContextMenu
|
|
744
|
+
menuContent={
|
|
745
|
+
<>
|
|
746
|
+
<DropdownMenuItem label="Cut" onClick={() => {}} />
|
|
747
|
+
<div role="menuitemradio" tabIndex={-1} aria-disabled="true">
|
|
748
|
+
Newest
|
|
749
|
+
</div>
|
|
750
|
+
<div role="menuitemcheckbox" tabIndex={-1} aria-checked="false">
|
|
751
|
+
Nightly
|
|
752
|
+
</div>
|
|
753
|
+
</>
|
|
754
|
+
}>
|
|
755
|
+
<div>Right-click me</div>
|
|
756
|
+
</ContextMenu>,
|
|
757
|
+
);
|
|
758
|
+
|
|
759
|
+
fireEvent.contextMenu(screen.getByText('Right-click me'));
|
|
760
|
+
// Anchor the search on 'Cut' so typeahead scans forward and meets the
|
|
761
|
+
// disabled 'Newest' (also an 'n' match) before the enabled 'Nightly'.
|
|
762
|
+
// This pins the `:not([aria-disabled="true"])` in MENU_ITEM_SELECTOR: the
|
|
763
|
+
// menus never pass useTypeahead's `isDisabled` option, so that clause is
|
|
764
|
+
// the only thing keeping disabled rows out of the typeahead list. An
|
|
765
|
+
// arrow-key test cannot cover it — useListFocus re-filters disabled items
|
|
766
|
+
// independently, so arrow navigation is guarded twice over.
|
|
767
|
+
// The disabled row keeps tabIndex={-1} on purpose: it stays focusable, so
|
|
768
|
+
// the selector clause is the sole reason focus skips it.
|
|
769
|
+
screen.getByRole('menuitem', {name: 'Cut', hidden: true}).focus();
|
|
770
|
+
fireEvent.keyDown(screen.getByRole('menu', {hidden: true}), {key: 'n'});
|
|
771
|
+
expect(
|
|
772
|
+
screen.getByRole('menuitemcheckbox', {name: 'Nightly', hidden: true}),
|
|
773
|
+
).toHaveFocus();
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
it('skips aria-disabled menuitemradio and menuitemcheckbox items during arrow navigation', () => {
|
|
777
|
+
render(
|
|
778
|
+
<ContextMenu
|
|
779
|
+
menuContent={
|
|
780
|
+
<>
|
|
781
|
+
<DropdownMenuItem label="Cut" onClick={() => {}} />
|
|
782
|
+
<div role="menuitemradio" tabIndex={-1} aria-disabled="true">
|
|
783
|
+
Newest
|
|
784
|
+
</div>
|
|
785
|
+
<div role="menuitemcheckbox" tabIndex={-1} aria-disabled="true">
|
|
786
|
+
Archived
|
|
787
|
+
</div>
|
|
788
|
+
<div role="menuitemradio" tabIndex={-1} aria-checked="false">
|
|
789
|
+
Oldest
|
|
790
|
+
</div>
|
|
791
|
+
</>
|
|
792
|
+
}>
|
|
793
|
+
<div>Right-click me</div>
|
|
794
|
+
</ContextMenu>,
|
|
795
|
+
);
|
|
796
|
+
|
|
797
|
+
fireEvent.contextMenu(screen.getByText('Right-click me'));
|
|
798
|
+
const menu = screen.getByRole('menu', {hidden: true});
|
|
799
|
+
screen.getByRole('menuitem', {name: 'Cut', hidden: true}).focus();
|
|
800
|
+
|
|
801
|
+
fireEvent.keyDown(menu, {key: 'ArrowDown'});
|
|
802
|
+
expect(
|
|
803
|
+
screen.getByRole('menuitemradio', {name: 'Oldest', hidden: true}),
|
|
804
|
+
).toHaveFocus();
|
|
805
|
+
});
|
|
806
|
+
});
|
|
@@ -135,6 +135,13 @@ export const docs = {
|
|
|
135
135
|
'Number of months displayed simultaneously in the calendar popover.',
|
|
136
136
|
default: '1',
|
|
137
137
|
},
|
|
138
|
+
{
|
|
139
|
+
name: 'format',
|
|
140
|
+
type: "'date' | 'date_long' | 'date_weekday' | 'system_date' | ((value: ISODateString) => string)",
|
|
141
|
+
description:
|
|
142
|
+
"How the committed date value is displayed. Named values are reused from Timestamp's format vocabulary: 'date' shows 'Mar 21, 2026', 'date_long' shows 'March 21, 2026', 'date_weekday' shows 'Wed, Mar 21, 2026', 'system_date' shows '2026-03-21'. A function receives the ISO value and returns a custom string. Applies only to the committed value, never to text being typed.",
|
|
143
|
+
default: "'date_long'",
|
|
144
|
+
},
|
|
138
145
|
{
|
|
139
146
|
name: 'xstyle',
|
|
140
147
|
type: 'StyleXStyles',
|
|
@@ -388,6 +395,13 @@ export const docsZh = {
|
|
|
388
395
|
description: '日历弹出层中同时显示的月份数量。',
|
|
389
396
|
default: '1',
|
|
390
397
|
},
|
|
398
|
+
{
|
|
399
|
+
name: 'format',
|
|
400
|
+
type: "'date' | 'date_long' | 'date_weekday' | 'system_date' | ((value: ISODateString) => string)",
|
|
401
|
+
description:
|
|
402
|
+
"已选日期的显示格式。命名值复用 Timestamp 的格式词汇:'date' 显示 'Mar 21, 2026','date_long' 显示 'March 21, 2026','date_weekday' 显示 'Wed, Mar 21, 2026','system_date' 显示 '2026-03-21'。函数接收 ISO 值并返回自定义字符串。仅作用于已提交的值,不影响正在输入的文本。",
|
|
403
|
+
default: "'date_long'",
|
|
404
|
+
},
|
|
391
405
|
{
|
|
392
406
|
name: 'xstyle',
|
|
393
407
|
type: 'StyleXStyles',
|
|
@@ -481,6 +495,8 @@ export const docsDense = {
|
|
|
481
495
|
labelTooltip: 'tooltip text via info icon at label end',
|
|
482
496
|
hasClear: 'Shows clear button when date is set. Clears value on click.',
|
|
483
497
|
numberOfMonths: 'months shown simultaneously in calendar popover',
|
|
498
|
+
format:
|
|
499
|
+
"committed-value display: 'date_long' (default, March 21, 2026), 'date' (Mar 21, 2026), 'date_weekday' (Wed, Mar 21, 2026), 'system_date' (2026-03-21), or (iso)=>string; reuses Timestamp vocabulary. Committed value only, not while typing.",
|
|
484
500
|
xstyle: 'StyleX styles for layout; must be stylex.create() value',
|
|
485
501
|
},
|
|
486
502
|
};
|
|
@@ -834,4 +834,112 @@ describe('DateInput', () => {
|
|
|
834
834
|
expect(input).not.toHaveAttribute('aria-disabled');
|
|
835
835
|
});
|
|
836
836
|
});
|
|
837
|
+
|
|
838
|
+
describe('format', () => {
|
|
839
|
+
it('defaults to the long-month date_long shape', () => {
|
|
840
|
+
// Non-breaking default: byte-identical to the historical hardcoded
|
|
841
|
+
// DATE_FORMAT_LONG rendering. `format` now defaults to 'date_long'.
|
|
842
|
+
render(<DateInput label="Date" value="2026-01-25" onChange={() => {}} />);
|
|
843
|
+
expect(screen.getByDisplayValue('January 25, 2026')).toBeInTheDocument();
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
it('renders the long-month shape for explicit format="date_long"', () => {
|
|
847
|
+
// Explicit date_long is identical to the unset default above and to the
|
|
848
|
+
// old hardcoded long-month output — real named parity with Timestamp.
|
|
849
|
+
render(
|
|
850
|
+
<DateInput
|
|
851
|
+
label="Date"
|
|
852
|
+
value="2026-01-25"
|
|
853
|
+
onChange={() => {}}
|
|
854
|
+
format="date_long"
|
|
855
|
+
/>,
|
|
856
|
+
);
|
|
857
|
+
expect(screen.getByDisplayValue('January 25, 2026')).toBeInTheDocument();
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
it('renders the short-month shape for format="date"', () => {
|
|
861
|
+
// Same literal + same shape as <Timestamp format="date" />.
|
|
862
|
+
render(
|
|
863
|
+
<DateInput
|
|
864
|
+
label="Date"
|
|
865
|
+
value="2026-01-25"
|
|
866
|
+
onChange={() => {}}
|
|
867
|
+
format="date"
|
|
868
|
+
/>,
|
|
869
|
+
);
|
|
870
|
+
expect(screen.getByDisplayValue('Jan 25, 2026')).toBeInTheDocument();
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
it('renders the ISO shape for format="system_date"', () => {
|
|
874
|
+
render(
|
|
875
|
+
<DateInput
|
|
876
|
+
label="Date"
|
|
877
|
+
value="2026-01-25"
|
|
878
|
+
onChange={() => {}}
|
|
879
|
+
format="system_date"
|
|
880
|
+
/>,
|
|
881
|
+
);
|
|
882
|
+
expect(screen.getByDisplayValue('2026-01-25')).toBeInTheDocument();
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
it('renders a weekday prefix for format="date_weekday"', () => {
|
|
886
|
+
render(
|
|
887
|
+
<DateInput
|
|
888
|
+
label="Date"
|
|
889
|
+
value="2026-01-25"
|
|
890
|
+
onChange={() => {}}
|
|
891
|
+
format="date_weekday"
|
|
892
|
+
/>,
|
|
893
|
+
);
|
|
894
|
+
// 2026-01-25 is a Sunday; assert the weekday-prefixed shape without
|
|
895
|
+
// over-fitting locale punctuation.
|
|
896
|
+
const input = screen.getByRole('combobox');
|
|
897
|
+
expect(input).toHaveValue('Sun, Jan 25, 2026');
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
it('supports a custom function format', () => {
|
|
901
|
+
render(
|
|
902
|
+
<DateInput
|
|
903
|
+
label="Date"
|
|
904
|
+
value="2026-01-25"
|
|
905
|
+
onChange={() => {}}
|
|
906
|
+
format={iso => `custom:${iso}`}
|
|
907
|
+
/>,
|
|
908
|
+
);
|
|
909
|
+
expect(screen.getByDisplayValue('custom:2026-01-25')).toBeInTheDocument();
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
it('does not apply format to in-progress typed input', async () => {
|
|
913
|
+
const user = userEvent.setup();
|
|
914
|
+
render(
|
|
915
|
+
<DateInput label="Date" onChange={() => {}} format="system_date" />,
|
|
916
|
+
);
|
|
917
|
+
const input = screen.getByRole('combobox');
|
|
918
|
+
await user.click(input);
|
|
919
|
+
await user.type(input, 'January 25');
|
|
920
|
+
// While typing, the raw text is shown verbatim — not reformatted.
|
|
921
|
+
expect(input).toHaveValue('January 25');
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
it('recomputes the display in format on external value change', () => {
|
|
925
|
+
const {rerender} = render(
|
|
926
|
+
<DateInput
|
|
927
|
+
label="Date"
|
|
928
|
+
value="2026-01-25"
|
|
929
|
+
onChange={() => {}}
|
|
930
|
+
format="date"
|
|
931
|
+
/>,
|
|
932
|
+
);
|
|
933
|
+
expect(screen.getByDisplayValue('Jan 25, 2026')).toBeInTheDocument();
|
|
934
|
+
rerender(
|
|
935
|
+
<DateInput
|
|
936
|
+
label="Date"
|
|
937
|
+
value="2026-03-10"
|
|
938
|
+
onChange={() => {}}
|
|
939
|
+
format="date"
|
|
940
|
+
/>,
|
|
941
|
+
);
|
|
942
|
+
expect(screen.getByDisplayValue('Mar 10, 2026')).toBeInTheDocument();
|
|
943
|
+
});
|
|
944
|
+
});
|
|
837
945
|
});
|
|
@@ -57,9 +57,9 @@ import {getInputARIA, parseDateInput} from '../utils';
|
|
|
57
57
|
import {
|
|
58
58
|
plainDateFromISO,
|
|
59
59
|
plainDateToISO,
|
|
60
|
-
|
|
61
|
-
DATE_FORMAT_LONG,
|
|
60
|
+
formatSharedDate,
|
|
62
61
|
} from '../utils/plainDate';
|
|
62
|
+
import type {TimestampFormat} from '../Timestamp';
|
|
63
63
|
|
|
64
64
|
const styles = stylex.create({
|
|
65
65
|
iconButton: {
|
|
@@ -127,6 +127,25 @@ const sizeStyles = stylex.create({
|
|
|
127
127
|
|
|
128
128
|
export type DateInputSize = keyof typeof sizeStyles;
|
|
129
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Named display formats for a committed date value. These are the date-only
|
|
132
|
+
* members of Timestamp's `format` vocabulary — reused verbatim (via
|
|
133
|
+
* `Extract`) so the same literal renders the same date shape in both
|
|
134
|
+
* `Timestamp` and `DateInput`:
|
|
135
|
+
* - `'date'`: locale short-month date, e.g. "Mar 21, 2026"
|
|
136
|
+
* - `'date_long'`: locale long-month date, e.g. "March 21, 2026" (the default)
|
|
137
|
+
* - `'date_weekday'`: short weekday + date, e.g. "Wed, Mar 21, 2026"
|
|
138
|
+
* - `'system_date'`: ISO 8601 calendar date, e.g. "2026-03-21"
|
|
139
|
+
*
|
|
140
|
+
* Because `DateInputFormat` is `Extract`ed from `TimestampFormat`, the two
|
|
141
|
+
* types stay in compile-time lockstep: renaming or removing one of these
|
|
142
|
+
* members from `TimestampFormat` breaks this type at build time.
|
|
143
|
+
*/
|
|
144
|
+
export type DateInputFormat = Extract<
|
|
145
|
+
TimestampFormat,
|
|
146
|
+
'date' | 'date_long' | 'date_weekday' | 'system_date'
|
|
147
|
+
>;
|
|
148
|
+
|
|
130
149
|
// Re-export shared types for convenience
|
|
131
150
|
|
|
132
151
|
export type {
|
|
@@ -283,6 +302,37 @@ export interface DateInputProps extends Omit<
|
|
|
283
302
|
* @default 1
|
|
284
303
|
*/
|
|
285
304
|
numberOfMonths?: 1 | 2;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* How the committed date value is displayed in the text field. Accepts a
|
|
308
|
+
* named format reused from `Timestamp`'s `format` vocabulary (so the same
|
|
309
|
+
* literal renders the same date shape in both components) or a function that
|
|
310
|
+
* maps the ISO value to a custom display string.
|
|
311
|
+
*
|
|
312
|
+
* - `'date_long'` (default): long-month date, e.g. "March 21, 2026"
|
|
313
|
+
* - `'date'`: short-month date, e.g. "Mar 21, 2026"
|
|
314
|
+
* - `'date_weekday'`: short weekday + date, e.g. "Wed, Mar 21, 2026"
|
|
315
|
+
* - `'system_date'`: ISO 8601 calendar date, e.g. "2026-03-21"
|
|
316
|
+
* - `(value: ISODateString) => string`: fully custom display string
|
|
317
|
+
*
|
|
318
|
+
* Formatting applies only to the committed value — never to text the user is
|
|
319
|
+
* actively typing. A custom function's output that `parseDateInput` cannot
|
|
320
|
+
* read back can't be re-committed after an edit; external `value` changes
|
|
321
|
+
* always recompute the display from the ISO value.
|
|
322
|
+
*
|
|
323
|
+
* @default 'date_long'
|
|
324
|
+
* @example
|
|
325
|
+
* ```
|
|
326
|
+
* <DateInput label="Ship date" value={date} onChange={setDate} format="date" />
|
|
327
|
+
* <DateInput
|
|
328
|
+
* label="Ship date"
|
|
329
|
+
* value={date}
|
|
330
|
+
* onChange={setDate}
|
|
331
|
+
* format={iso => new Date(iso + 'T00:00').toDateString()}
|
|
332
|
+
* />
|
|
333
|
+
* ```
|
|
334
|
+
*/
|
|
335
|
+
format?: DateInputFormat | ((value: ISODateString) => string);
|
|
286
336
|
}
|
|
287
337
|
|
|
288
338
|
/**
|
|
@@ -318,6 +368,7 @@ export function DateInput({
|
|
|
318
368
|
labelTooltip,
|
|
319
369
|
hasClear = false,
|
|
320
370
|
numberOfMonths = 1,
|
|
371
|
+
format = 'date_long',
|
|
321
372
|
width,
|
|
322
373
|
xstyle,
|
|
323
374
|
className,
|
|
@@ -404,12 +455,26 @@ export function DateInput({
|
|
|
404
455
|
}
|
|
405
456
|
}
|
|
406
457
|
|
|
458
|
+
// Format a committed ISO value for display. The default `date_long` renders
|
|
459
|
+
// the long-month shape (byte-identical to the historical hardcoded
|
|
460
|
+
// DATE_FORMAT_LONG rendering, so still non-breaking); a function is called
|
|
461
|
+
// with the ISO value; every other named member reuses Timestamp's shared
|
|
462
|
+
// date mapping. Applies ONLY to the committed value, never to in-progress
|
|
463
|
+
// typed input.
|
|
464
|
+
const formatCommittedValue = useCallback(
|
|
465
|
+
(iso: ISODateString): string =>
|
|
466
|
+
typeof format === 'function'
|
|
467
|
+
? format(iso)
|
|
468
|
+
: formatSharedDate(plainDateFromISO(iso), format),
|
|
469
|
+
[format],
|
|
470
|
+
);
|
|
471
|
+
|
|
407
472
|
// Display value: pending input if typing, otherwise formatted value
|
|
408
473
|
const displayValue =
|
|
409
474
|
pendingInput !== null
|
|
410
475
|
? pendingInput
|
|
411
476
|
: optimisticValue && /^\d{4}-\d{2}-\d{2}$/.test(optimisticValue)
|
|
412
|
-
?
|
|
477
|
+
? formatCommittedValue(optimisticValue)
|
|
413
478
|
: '';
|
|
414
479
|
|
|
415
480
|
// Check if current input is valid (for styling purposes)
|
package/src/DateInput/index.ts
CHANGED
|
@@ -185,6 +185,41 @@ describe('DateTimeInput', () => {
|
|
|
185
185
|
);
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
+
it('opens the calendar popover on ArrowDown (keyboard, forms-13)', () => {
|
|
189
|
+
render(<DateTimeInput label="Meeting" onChange={() => {}} />);
|
|
190
|
+
const input = screen.getByRole('combobox');
|
|
191
|
+
input.focus();
|
|
192
|
+
expect(input).toHaveAttribute('aria-expanded', 'false');
|
|
193
|
+
fireEvent.keyDown(input, {key: 'ArrowDown'});
|
|
194
|
+
expect(input).toHaveAttribute('aria-expanded', 'true');
|
|
195
|
+
// skipAutoFocus keeps focus in the input, per the APG date-picker pattern
|
|
196
|
+
expect(input).toHaveFocus();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('opens the calendar popover on Alt+ArrowDown (keyboard, forms-13)', () => {
|
|
200
|
+
render(<DateTimeInput label="Meeting" onChange={() => {}} />);
|
|
201
|
+
const input = screen.getByRole('combobox');
|
|
202
|
+
fireEvent.keyDown(input, {key: 'ArrowDown', altKey: true});
|
|
203
|
+
expect(input).toHaveAttribute('aria-expanded', 'true');
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('does not open on ArrowDown when disabled', () => {
|
|
207
|
+
render(<DateTimeInput label="Meeting" isDisabled onChange={() => {}} />);
|
|
208
|
+
const input = screen.getByRole('combobox');
|
|
209
|
+
fireEvent.keyDown(input, {key: 'ArrowDown'});
|
|
210
|
+
expect(input).toHaveAttribute('aria-expanded', 'false');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('does not re-trigger on ArrowDown when the calendar is already open', () => {
|
|
214
|
+
render(<DateTimeInput label="Meeting" onChange={() => {}} />);
|
|
215
|
+
const input = screen.getByRole('combobox');
|
|
216
|
+
fireEvent.keyDown(input, {key: 'ArrowDown'});
|
|
217
|
+
expect(input).toHaveAttribute('aria-expanded', 'true');
|
|
218
|
+
// A second ArrowDown is a no-op: the calendar stays open
|
|
219
|
+
fireEvent.keyDown(input, {key: 'ArrowDown'});
|
|
220
|
+
expect(input).toHaveAttribute('aria-expanded', 'true');
|
|
221
|
+
});
|
|
222
|
+
|
|
188
223
|
it('calendar button is focusable and clickable', () => {
|
|
189
224
|
render(<DateTimeInput label="Meeting" onChange={() => {}} />);
|
|
190
225
|
const button = getButton('Open calendar');
|
|
@@ -719,12 +719,22 @@ export function DateTimeInput({
|
|
|
719
719
|
if (e.key === 'Escape' && popover.isOpen) {
|
|
720
720
|
e.preventDefault();
|
|
721
721
|
popover.hide();
|
|
722
|
+
} else if (
|
|
723
|
+
(e.key === 'ArrowDown' || (e.altKey && e.key === 'ArrowDown')) &&
|
|
724
|
+
!popover.isOpen
|
|
725
|
+
) {
|
|
726
|
+
// APG combobox: ArrowDown (and Alt+ArrowDown) opens the calendar
|
|
727
|
+
// popover from the keyboard, keeping focus in the input (forms-13).
|
|
728
|
+
e.preventDefault();
|
|
729
|
+
if (!isEffectivelyDisabled) {
|
|
730
|
+
popover.show({skipAutoFocus: true});
|
|
731
|
+
}
|
|
722
732
|
} else if (e.key === 'Enter') {
|
|
723
733
|
e.preventDefault();
|
|
724
734
|
commitDatePendingInput();
|
|
725
735
|
}
|
|
726
736
|
},
|
|
727
|
-
[popover, commitDatePendingInput],
|
|
737
|
+
[popover, commitDatePendingInput, isEffectivelyDisabled],
|
|
728
738
|
);
|
|
729
739
|
|
|
730
740
|
// --- Time handlers ---
|
|
@@ -1000,7 +1010,9 @@ export function DateTimeInput({
|
|
|
1000
1010
|
disabled={isEffectivelyDisabled && !showsDisabledMessage}
|
|
1001
1011
|
aria-disabled={showsDisabledMessage ? 'true' : undefined}
|
|
1002
1012
|
readOnly={showsDisabledMessage || undefined}
|
|
1003
|
-
aria-label={
|
|
1013
|
+
aria-label={
|
|
1014
|
+
timeLabel ?? t('@astryx.dateTimeInput.timeSuffix', {label})
|
|
1015
|
+
}
|
|
1004
1016
|
aria-describedby={ariaDescribedBy}
|
|
1005
1017
|
aria-required={isRequired === true ? 'true' : undefined}
|
|
1006
1018
|
aria-invalid={
|
|
@@ -111,7 +111,7 @@ export const docs = {
|
|
|
111
111
|
{ guidance: false, description: 'Use the fullscreen variant for simple confirmations; it is meant for complex content like editors or long forms.' },
|
|
112
112
|
],
|
|
113
113
|
anatomy: [
|
|
114
|
-
{name: 'Header', required: true, description: 'Title, optional subtitle, and close button. The title receives focus on open
|
|
114
|
+
{name: 'Header', required: true, description: 'Title, optional subtitle, and close button. The title receives focus on open and labels the dialog via aria-labelledby.'},
|
|
115
115
|
{name: 'Body', required: true, description: 'The main content area: text, forms, lists, or any layout.'},
|
|
116
116
|
{name: 'Footer', required: false, description: 'Action buttons like Save/Cancel or Accept/Decline, aligned to the end.'},
|
|
117
117
|
{name: 'Backdrop', required: true, description: 'Semi-transparent overlay behind the dialog that blocks page interaction.'},
|
|
@@ -133,7 +133,7 @@ export const docsZh = {
|
|
|
133
133
|
{ guidance: false, description: 'Use the fullscreen variant for simple confirmations; it is meant for complex content like editors or long forms.' },
|
|
134
134
|
],
|
|
135
135
|
anatomy: [
|
|
136
|
-
{name: 'Header', required: true, description: 'Title, optional subtitle, and close button. The title receives focus on open
|
|
136
|
+
{name: 'Header', required: true, description: 'Title, optional subtitle, and close button. The title receives focus on open and labels the dialog via aria-labelledby.'},
|
|
137
137
|
{name: 'Body', required: true, description: 'The main content area: text, forms, lists, or any layout.'},
|
|
138
138
|
{name: 'Footer', required: false, description: 'Action buttons like Save/Cancel or Accept/Decline, aligned to the end.'},
|
|
139
139
|
{name: 'Backdrop', required: true, description: 'Semi-transparent overlay behind the dialog that blocks page interaction.'},
|
|
@@ -212,10 +212,7 @@ describe('Dialog', () => {
|
|
|
212
212
|
|
|
213
213
|
it('forwards additional props to dialog element', () => {
|
|
214
214
|
render(
|
|
215
|
-
<Dialog
|
|
216
|
-
isOpen={true}
|
|
217
|
-
onOpenChange={() => {}}
|
|
218
|
-
data-testid="custom-dialog">
|
|
215
|
+
<Dialog isOpen={true} onOpenChange={() => {}} data-testid="custom-dialog">
|
|
219
216
|
Content
|
|
220
217
|
</Dialog>,
|
|
221
218
|
);
|
|
@@ -267,6 +264,82 @@ describe('Dialog', () => {
|
|
|
267
264
|
});
|
|
268
265
|
});
|
|
269
266
|
|
|
267
|
+
describe('accessible name', () => {
|
|
268
|
+
it('is labelled by the DialogHeader title by default', () => {
|
|
269
|
+
render(
|
|
270
|
+
<Dialog isOpen={true} onOpenChange={() => {}}>
|
|
271
|
+
<DialogHeader title="Dialog title" />
|
|
272
|
+
</Dialog>,
|
|
273
|
+
);
|
|
274
|
+
const dialog = screen.getByRole('dialog');
|
|
275
|
+
const heading = screen.getByRole('heading', {name: 'Dialog title'});
|
|
276
|
+
expect(heading.id).not.toBe('');
|
|
277
|
+
expect(dialog).toHaveAttribute('aria-labelledby', heading.id);
|
|
278
|
+
expect(dialog).toHaveAccessibleName('Dialog title');
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('prefers a consumer-provided aria-label over the header title', () => {
|
|
282
|
+
render(
|
|
283
|
+
<Dialog isOpen={true} onOpenChange={() => {}} aria-label="Custom name">
|
|
284
|
+
<DialogHeader title="Dialog title" />
|
|
285
|
+
</Dialog>,
|
|
286
|
+
);
|
|
287
|
+
const dialog = screen.getByRole('dialog');
|
|
288
|
+
expect(dialog).not.toHaveAttribute('aria-labelledby');
|
|
289
|
+
expect(dialog).toHaveAccessibleName('Custom name');
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('prefers a consumer-provided aria-labelledby over the header title', () => {
|
|
293
|
+
render(
|
|
294
|
+
<>
|
|
295
|
+
<span id="external-label">External name</span>
|
|
296
|
+
<Dialog
|
|
297
|
+
isOpen={true}
|
|
298
|
+
onOpenChange={() => {}}
|
|
299
|
+
aria-labelledby="external-label">
|
|
300
|
+
<DialogHeader title="Dialog title" />
|
|
301
|
+
</Dialog>
|
|
302
|
+
</>,
|
|
303
|
+
);
|
|
304
|
+
const dialog = screen.getByRole('dialog');
|
|
305
|
+
expect(dialog).toHaveAttribute('aria-labelledby', 'external-label');
|
|
306
|
+
expect(dialog).toHaveAccessibleName('External name');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('omits aria-labelledby and warns when open with no name source', () => {
|
|
310
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
311
|
+
try {
|
|
312
|
+
render(
|
|
313
|
+
<Dialog isOpen={true} onOpenChange={() => {}}>
|
|
314
|
+
Content
|
|
315
|
+
</Dialog>,
|
|
316
|
+
);
|
|
317
|
+
const dialog = screen.getByRole('dialog');
|
|
318
|
+
expect(dialog).not.toHaveAttribute('aria-labelledby');
|
|
319
|
+
expect(warnSpy).toHaveBeenCalledTimes(1);
|
|
320
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
321
|
+
expect.stringContaining('accessible name'),
|
|
322
|
+
);
|
|
323
|
+
} finally {
|
|
324
|
+
warnSpy.mockRestore();
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('does not warn when the header provides a title', () => {
|
|
329
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
330
|
+
try {
|
|
331
|
+
render(
|
|
332
|
+
<Dialog isOpen={true} onOpenChange={() => {}}>
|
|
333
|
+
<DialogHeader title="Dialog title" />
|
|
334
|
+
</Dialog>,
|
|
335
|
+
);
|
|
336
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
337
|
+
} finally {
|
|
338
|
+
warnSpy.mockRestore();
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
|
|
270
343
|
describe('inner flex wrapper', () => {
|
|
271
344
|
it('wraps children in a flex container for scroll support', () => {
|
|
272
345
|
render(
|