@astryxdesign/core 0.4.4 → 0.4.5-canary.013e728
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 +40 -0
- package/dist/AvatarGroup/AvatarGroupOverflow.js +1 -1
- package/dist/BottomSheet/BottomSheet.d.ts +11 -2
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +4 -0
- package/dist/BottomSheet/BottomSheetPanel.d.ts +5 -2
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +65 -15
- package/dist/BottomSheet/index.d.ts +1 -1
- package/dist/BottomSheet/index.d.ts.map +1 -1
- package/dist/BottomSheet/snapOffsets.d.ts +57 -20
- package/dist/BottomSheet/snapOffsets.d.ts.map +1 -1
- package/dist/BottomSheet/snapOffsets.js +106 -30
- package/dist/BottomSheet/useSheetGestures.d.ts +13 -8
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +160 -64
- package/dist/Breadcrumbs/BreadcrumbItem.js +6 -6
- package/dist/Button/Button.js +5 -5
- package/dist/Calendar/Calendar.d.ts +17 -0
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +55 -15
- package/dist/Calendar/getStandaloneShortWeekdayNames.d.ts +14 -0
- package/dist/Calendar/getStandaloneShortWeekdayNames.d.ts.map +1 -0
- package/dist/Calendar/getStandaloneShortWeekdayNames.js +26 -0
- package/dist/Calendar/hooks/useCalendarConstraints.d.ts +22 -1
- package/dist/Calendar/hooks/useCalendarConstraints.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarConstraints.js +26 -4
- package/dist/Calendar/hooks/useCalendarDays.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarDays.js +14 -10
- package/dist/Calendar/hooks/useCalendarNavigation.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarNavigation.js +8 -4
- package/dist/Calendar/standaloneShortWeekdayNames.generated.d.ts +47 -0
- package/dist/Calendar/standaloneShortWeekdayNames.generated.d.ts.map +1 -0
- package/dist/Calendar/standaloneShortWeekdayNames.generated.js +40 -0
- package/dist/Calendar/styles.js +3 -3
- package/dist/Center/Center.d.ts +23 -1
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +12 -6
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +2 -2
- package/dist/Chat/ChatToolCalls.js +1 -1
- package/dist/Chat/useChatDictation.d.ts +1 -1
- package/dist/Chat/useChatDictation.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.d.ts +1 -1
- package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.js +4 -3
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +9 -0
- package/dist/Citation/Citation.js +3 -3
- package/dist/ClickableCard/ClickableCard.js +2 -2
- package/dist/CommandPalette/CommandPaletteItem.js +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +8 -3
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +17 -9
- package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +47 -9
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +18 -10
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +3 -3
- package/dist/Field/FieldLabel.d.ts +2 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +21 -3
- package/dist/Field/InputClearButton.d.ts +2 -1
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +12 -1
- package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
- package/dist/Field/inputStyles.stylex.js +4 -4
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +2 -2
- package/dist/FormLayout/FormLayout.d.ts +24 -2
- package/dist/FormLayout/FormLayout.d.ts.map +1 -1
- package/dist/FormLayout/FormLayout.js +7 -2
- package/dist/FormLayout/FormLayoutContext.d.ts +15 -2
- package/dist/FormLayout/FormLayoutContext.d.ts.map +1 -1
- package/dist/FormLayout/FormLayoutContext.js +19 -4
- package/dist/FormLayout/index.d.ts +1 -1
- package/dist/FormLayout/index.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.d.ts +13 -3
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +2 -0
- package/dist/HoverCard/index.d.ts +1 -1
- package/dist/HoverCard/index.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.d.ts +17 -2
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +78 -9
- package/dist/Item/Item.d.ts +9 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +46 -8
- package/dist/Layer/index.d.ts +4 -2
- package/dist/Layer/index.d.ts.map +1 -1
- package/dist/Layer/index.js +2 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +3 -2
- package/dist/Layer/useTouchTrigger.d.ts +113 -0
- package/dist/Layer/useTouchTrigger.d.ts.map +1 -0
- package/dist/Layer/useTouchTrigger.js +241 -0
- package/dist/Layout/container.stylex.d.ts +4 -2
- package/dist/Layout/container.stylex.d.ts.map +1 -1
- package/dist/Layout/container.stylex.js +19 -11
- package/dist/Layout/index.d.ts +1 -0
- package/dist/Layout/index.d.ts.map +1 -1
- package/dist/Layout/index.js +4 -0
- package/dist/Layout/padding.stylex.d.ts +315 -12
- package/dist/Layout/padding.stylex.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.js +389 -12
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +2 -1
- package/dist/Link/Link.js +4 -4
- package/dist/Markdown/Markdown.d.ts +8 -0
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +31 -3
- package/dist/Markdown/parser.d.ts +14 -2
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +50 -2
- package/dist/MobileNav/MobileNav.d.ts +1 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +24 -6
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +8 -3
- package/dist/NavItem/navItemStyles.stylex.d.ts +2 -2
- package/dist/NavItem/navItemStyles.stylex.js +2 -2
- package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +38 -5
- package/dist/Outline/Outline.js +2 -2
- package/dist/Outline/parseOutlineFromMarkdown.d.ts +2 -0
- package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
- package/dist/Outline/parseOutlineFromMarkdown.js +5 -31
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +11 -12
- package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchToken.js +3 -1
- package/dist/PowerSearch/formatFilterValue.d.ts +11 -2
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +23 -8
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +12 -1
- package/dist/RadioList/RadioListItem.d.ts +2 -2
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +68 -38
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +3 -3
- package/dist/Section/Section.d.ts +36 -1
- package/dist/Section/Section.d.ts.map +1 -1
- package/dist/Section/Section.js +12 -2
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +6 -1
- package/dist/SelectableCard/SelectableCard.js +1 -1
- package/dist/Selector/Selector.d.ts +26 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +95 -17
- package/dist/Selector/SelectorOption.d.ts +14 -1
- package/dist/Selector/SelectorOption.d.ts.map +1 -1
- package/dist/Selector/SelectorOption.js +6 -0
- package/dist/Selector/SelectorRowLayoutContext.d.ts +8 -0
- package/dist/Selector/SelectorRowLayoutContext.d.ts.map +1 -0
- package/dist/Selector/SelectorRowLayoutContext.js +27 -0
- package/dist/Selector/types.d.ts +1 -0
- package/dist/Selector/types.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +1 -1
- package/dist/SideNav/SideNavItem.js +1 -1
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +3 -3
- package/dist/Stack/Stack.d.ts +23 -1
- package/dist/Stack/Stack.d.ts.map +1 -1
- package/dist/Stack/Stack.js +12 -6
- package/dist/StatusDot/StatusDot.d.ts +43 -3
- package/dist/StatusDot/StatusDot.d.ts.map +1 -1
- package/dist/StatusDot/StatusDot.js +42 -5
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +9 -0
- package/dist/TabList/TabMenu.js +1 -1
- package/dist/Table/TableRow.js +4 -4
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +7 -2
- package/dist/Table/plugins/sortable/useTableSortableState.d.ts +5 -3
- package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortableState.js +12 -9
- package/dist/Table/plugins/tree/useTableTreeData.js +2 -2
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +6 -1
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +6 -1
- package/dist/Thumbnail/Thumbnail.js +1 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +6 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +6 -4
- package/dist/Timestamp/formatInstant.d.ts +3 -2
- package/dist/Timestamp/formatInstant.d.ts.map +1 -1
- package/dist/Timestamp/formatInstant.js +8 -8
- package/dist/Timestamp/tooltipEntries.d.ts +2 -1
- package/dist/Timestamp/tooltipEntries.d.ts.map +1 -1
- package/dist/Timestamp/tooltipEntries.js +5 -3
- package/dist/Token/Token.js +1 -1
- package/dist/Tooltip/Tooltip.d.ts +16 -3
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip/Tooltip.js +2 -0
- package/dist/Tooltip/index.d.ts +1 -1
- package/dist/Tooltip/index.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.d.ts +21 -2
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +71 -13
- package/dist/TopNav/TopNavHeading.js +2 -2
- package/dist/TopNav/TopNavItem.js +2 -2
- package/dist/TopNav/TopNavMegaMenu.js +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +1 -1
- package/dist/TopNav/TopNavMenu.js +2 -2
- package/dist/TreeList/TreeListItem.js +1 -1
- package/dist/astryx.css +85 -60
- package/dist/hooks/containerReveal.stylex.d.ts.map +1 -1
- package/dist/hooks/containerReveal.stylex.js +18 -18
- package/dist/hooks/scrollbarGutter.d.ts +28 -0
- package/dist/hooks/scrollbarGutter.d.ts.map +1 -0
- package/dist/hooks/scrollbarGutter.js +103 -0
- package/dist/hooks/useResolvedRequired.d.ts +19 -0
- package/dist/hooks/useResolvedRequired.d.ts.map +1 -0
- package/dist/hooks/useResolvedRequired.js +40 -0
- package/dist/hooks/useScrollLock.d.ts +4 -0
- package/dist/hooks/useScrollLock.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.js +13 -1
- package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
- package/dist/i18n/InternationalizationContext.js +2 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +6 -0
- package/dist/i18n/useCollator.d.ts +12 -0
- package/dist/i18n/useCollator.d.ts.map +1 -0
- package/dist/i18n/useCollator.js +40 -0
- package/dist/i18n/useLocale.d.ts +3 -0
- package/dist/i18n/useLocale.d.ts.map +1 -0
- package/dist/i18n/useLocale.js +31 -0
- package/dist/theme/defineTheme.d.ts +5 -0
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +5 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +7 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +66 -5
- package/dist/utils/dateParser.d.ts +4 -3
- package/dist/utils/dateParser.d.ts.map +1 -1
- package/dist/utils/dateParser.js +8 -8
- package/dist/utils/plainDate.d.ts +9 -2
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +16 -4
- package/locales/af-ZA.json +958 -0
- package/locales/ar-SA.json +998 -0
- package/locales/ca-ES.json +974 -0
- package/locales/cs-CZ.json +990 -0
- package/locales/da-DK.json +966 -0
- package/locales/de-DE.json +966 -0
- package/locales/el-GR.json +990 -0
- package/locales/en.json +8 -0
- package/locales/es-ES.json +978 -0
- package/locales/fi-FI.json +990 -0
- package/locales/fr-FR.json +928 -0
- package/locales/he-IL.json +990 -0
- package/locales/hu-HU.json +990 -0
- package/locales/it-IT.json +978 -0
- package/locales/ja-JP.json +998 -0
- package/locales/ko-KR.json +990 -0
- package/locales/nl-NL.json +954 -0
- package/locales/no-NO.json +978 -0
- package/locales/pl-PL.json +982 -0
- package/locales/pseudo.json +6 -0
- package/locales/pt-BR.json +982 -0
- package/locales/pt-PT.json +982 -0
- package/locales/ro-RO.json +982 -0
- package/locales/ru-RU.json +990 -0
- package/locales/sr-SP.json +990 -0
- package/locales/sv-SE.json +986 -0
- package/locales/tr-TR.json +990 -0
- package/locales/uk-UA.json +990 -0
- package/locales/vi-VN.json +986 -0
- package/locales/zh-CN.json +998 -0
- package/locales/zh-TW.json +998 -0
- package/package.json +3 -3
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +1 -1
- package/src/Banner/Banner.doc.mjs +2 -0
- package/src/BottomSheet/BottomSheet.doc.mjs +36 -3
- package/src/BottomSheet/BottomSheet.test.tsx +177 -2
- package/src/BottomSheet/BottomSheet.tsx +16 -2
- package/src/BottomSheet/BottomSheetPanel.test.tsx +41 -0
- package/src/BottomSheet/BottomSheetPanel.tsx +95 -15
- package/src/BottomSheet/index.ts +5 -1
- package/src/BottomSheet/snapOffsets.test.ts +114 -47
- package/src/BottomSheet/snapOffsets.ts +119 -33
- package/src/BottomSheet/useSheetGestures.test.ts +113 -15
- package/src/BottomSheet/useSheetGestures.ts +196 -100
- package/src/Breadcrumbs/BreadcrumbItem.tsx +1 -1
- package/src/Button/Button.tsx +7 -7
- package/src/Calendar/Calendar.doc.mjs +16 -0
- package/src/Calendar/Calendar.test.tsx +137 -0
- package/src/Calendar/Calendar.tsx +80 -11
- package/src/Calendar/getStandaloneShortWeekdayNames.test.ts +54 -0
- package/src/Calendar/getStandaloneShortWeekdayNames.ts +38 -0
- package/src/Calendar/hooks/useCalendarConstraints.ts +54 -3
- package/src/Calendar/hooks/useCalendarDays.ts +13 -10
- package/src/Calendar/hooks/useCalendarNavigation.ts +6 -4
- package/src/Calendar/standaloneShortWeekdayNames.generated.ts +50 -0
- package/src/Calendar/styles.ts +3 -3
- package/src/Center/Center.doc.mjs +48 -0
- package/src/Center/Center.test.tsx +158 -0
- package/src/Center/Center.tsx +50 -9
- package/src/Chat/ChatComposer.tsx +7 -4
- package/src/Chat/ChatToolCalls.tsx +1 -1
- package/src/Chat/{useChatDictation.test.ts → useChatDictation.test.tsx} +29 -14
- package/src/Chat/useChatDictation.ts +1 -1
- package/src/Chat/useSpeechRecognition.ts +5 -3
- package/src/CheckboxInput/CheckboxInput.tsx +6 -0
- package/src/Citation/Citation.tsx +3 -3
- package/src/ClickableCard/ClickableCard.tsx +2 -2
- package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
- package/src/ComplexSelector/ComplexSelector.doc.mjs +10 -0
- package/src/ComplexSelector/ComplexSelector.tsx +8 -5
- package/src/DateInput/DateInput.test.tsx +17 -1
- package/src/DateInput/DateInput.tsx +13 -9
- package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
- package/src/DateRangeInput/DateRangeInput.test.tsx +81 -1
- package/src/DateRangeInput/DateRangeInput.tsx +88 -8
- package/src/DateTimeInput/DateTimeInput.tsx +23 -8
- package/src/Dialog/Dialog.test.tsx +24 -0
- package/src/Dialog/Dialog.tsx +3 -0
- package/src/Field/Field.doc.mjs +3 -0
- package/src/Field/FieldLabel.tsx +20 -4
- package/src/Field/InputClearButton.test.tsx +134 -2
- package/src/Field/InputClearButton.tsx +42 -1
- package/src/Field/inputStyles.stylex.ts +16 -12
- package/src/FileInput/FileInput.tsx +5 -4
- package/src/FormLayout/FormLayout.doc.mjs +13 -0
- package/src/FormLayout/FormLayout.test.tsx +181 -4
- package/src/FormLayout/FormLayout.tsx +33 -2
- package/src/FormLayout/FormLayoutContext.ts +22 -7
- package/src/FormLayout/index.ts +1 -1
- package/src/HoverCard/HoverCard.doc.mjs +18 -0
- package/src/HoverCard/HoverCard.test.tsx +189 -0
- package/src/HoverCard/HoverCard.tsx +22 -2
- package/src/HoverCard/index.ts +1 -0
- package/src/HoverCard/useHoverCard.doc.mjs +2 -0
- package/src/HoverCard/useHoverCard.tsx +103 -7
- package/src/Item/Item.doc.mjs +1 -0
- package/src/Item/Item.test.tsx +50 -0
- package/src/Item/Item.tsx +41 -2
- package/src/Layer/index.ts +10 -0
- package/src/Layer/useLayer.tsx +13 -2
- package/src/Layer/useTouchTrigger.test.ts +70 -0
- package/src/Layer/useTouchTrigger.ts +366 -0
- package/src/Layout/Layout.doc.mjs +18 -0
- package/src/Layout/container.stylex.ts +11 -3
- package/src/Layout/index.ts +4 -0
- package/src/Layout/overlayPaddingReset.test.tsx +222 -0
- package/src/Layout/padding.stylex.ts +192 -12
- package/src/Lightbox/Lightbox.tsx +2 -1
- package/src/Link/Link.tsx +4 -4
- package/src/Markdown/Markdown.doc.mjs +3 -0
- package/src/Markdown/Markdown.test.tsx +78 -0
- package/src/Markdown/Markdown.tsx +41 -1
- package/src/Markdown/parser.ts +60 -2
- package/src/MobileNav/MobileNav.tsx +61 -5
- package/src/MobileNav/MobileNavEntryAnimation.test.tsx +212 -0
- package/src/MobileNav/MobileNavScrollbarGutter.test.tsx +109 -0
- package/src/MultiSelector/MultiSelector.test.tsx +1 -1
- package/src/MultiSelector/MultiSelector.tsx +8 -5
- package/src/NavItem/navItemStyles.stylex.ts +2 -2
- package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
- package/src/NumberInput/NumberInput.doc.mjs +24 -0
- package/src/NumberInput/NumberInput.test.tsx +138 -0
- package/src/NumberInput/NumberInput.tsx +44 -6
- package/src/Outline/Outline.doc.mjs +2 -0
- package/src/Outline/Outline.tsx +1 -1
- package/src/Outline/parseOutlineFromMarkdown.ts +10 -40
- package/src/PowerSearch/PowerSearch.tsx +17 -8
- package/src/PowerSearch/PowerSearchToken.tsx +3 -0
- package/src/PowerSearch/formatFilterValue.test.ts +22 -2
- package/src/PowerSearch/formatFilterValue.ts +31 -6
- package/src/RadioList/RadioList.doc.mjs +1 -1
- package/src/RadioList/RadioList.test.tsx +170 -2
- package/src/RadioList/RadioList.tsx +9 -1
- package/src/RadioList/RadioListItem.tsx +83 -51
- package/src/Resizable/ResizeHandle.test.tsx +22 -0
- package/src/Resizable/ResizeHandle.tsx +9 -3
- package/src/Section/Section.doc.mjs +55 -0
- package/src/Section/Section.test.tsx +201 -4
- package/src/Section/Section.tsx +69 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +11 -2
- package/src/SelectableCard/SelectableCard.tsx +1 -1
- package/src/Selector/Selector.doc.mjs +16 -2
- package/src/Selector/Selector.test.tsx +525 -1
- package/src/Selector/Selector.tsx +166 -21
- package/src/Selector/SelectorOption.doc.mjs +7 -0
- package/src/Selector/SelectorOption.tsx +21 -0
- package/src/Selector/SelectorRowLayoutContext.ts +32 -0
- package/src/Selector/types.ts +4 -4
- package/src/SideNav/SideNavHeading.tsx +2 -2
- package/src/SideNav/SideNavItem.tsx +1 -1
- package/src/Slider/Slider.tsx +11 -1
- package/src/Stack/Stack.doc.mjs +72 -0
- package/src/Stack/Stack.test.tsx +156 -0
- package/src/Stack/Stack.tsx +50 -8
- package/src/StatusDot/StatusDot.doc.mjs +13 -0
- package/src/StatusDot/StatusDot.test.tsx +115 -8
- package/src/StatusDot/StatusDot.tsx +74 -9
- package/src/Switch/Switch.tsx +6 -0
- package/src/TabList/TabMenu.tsx +1 -1
- package/src/Table/TableRow.tsx +4 -4
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +2 -1
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +2 -1
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +22 -4
- package/src/Table/plugins/sortable/useTableSortableState.test.tsx +34 -0
- package/src/Table/plugins/sortable/useTableSortableState.tsx +26 -23
- package/src/Table/plugins/tree/useTableTreeData.tsx +2 -2
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextArea/TextArea.tsx +3 -1
- package/src/TextInput/TextInput.tsx +3 -1
- package/src/Thumbnail/Thumbnail.tsx +1 -1
- package/src/TimeInput/TimeInput.tsx +3 -1
- package/src/Timestamp/Timestamp.test.tsx +27 -7
- package/src/Timestamp/Timestamp.tsx +8 -4
- package/src/Timestamp/formatInstant.ts +9 -7
- package/src/Timestamp/tooltipEntries.test.ts +11 -6
- package/src/Timestamp/tooltipEntries.ts +6 -2
- package/src/Token/Token.tsx +1 -1
- package/src/Tooltip/Tooltip.doc.mjs +18 -0
- package/src/Tooltip/Tooltip.test.tsx +254 -1
- package/src/Tooltip/Tooltip.tsx +22 -2
- package/src/Tooltip/index.ts +1 -0
- package/src/Tooltip/useTooltip.doc.mjs +2 -0
- package/src/Tooltip/useTooltip.tsx +99 -21
- package/src/TopNav/TopNavHeading.tsx +1 -1
- package/src/TopNav/TopNavItem.tsx +2 -2
- package/src/TopNav/TopNavMegaMenu.tsx +1 -1
- package/src/TopNav/TopNavMegaMenuItem.tsx +1 -1
- package/src/TopNav/TopNavMenu.tsx +2 -2
- package/src/TreeList/TreeListItem.tsx +1 -1
- package/src/hooks/containerReveal.stylex.ts +54 -18
- package/src/hooks/scrollbarGutter.test.ts +167 -0
- package/src/hooks/scrollbarGutter.ts +121 -0
- package/src/hooks/useResolvedRequired.ts +42 -0
- package/src/hooks/useScrollLock.doc.mjs +4 -4
- package/src/hooks/useScrollLock.test.ts +73 -0
- package/src/hooks/useScrollLock.ts +14 -0
- package/src/i18n/InternationalizationContext.ts +2 -0
- package/src/i18n/__tests__/e2e-powersearch.test.tsx +37 -1
- package/src/i18n/__tests__/useCollator.test.tsx +115 -0
- package/src/i18n/__tests__/useLocale.test.tsx +52 -0
- package/src/i18n/index.ts +6 -0
- package/src/i18n/useCollator.doc.mjs +84 -0
- package/src/i18n/useCollator.ts +44 -0
- package/src/i18n/useLocale.doc.mjs +70 -0
- package/src/i18n/useLocale.ts +34 -0
- package/src/i18n/useTranslator.doc.mjs +1 -1
- package/src/theme/defineTheme.test.ts +9 -3
- package/src/theme/defineTheme.ts +5 -0
- package/src/theme/derivedVarRegistry.test.ts +19 -5
- package/src/theme/derivedVarRegistry.ts +4 -0
- package/src/theme/generateThemeRules.test.ts +118 -0
- package/src/theme/generateThemeRules.ts +83 -5
- package/src/utils/dateParser.test.ts +20 -0
- package/src/utils/dateParser.ts +14 -7
- package/src/utils/plainDate.test.ts +56 -0
- package/src/utils/plainDate.ts +17 -4
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import {useState, useCallback, useEffect, useMemo, useRef} from 'react';
|
|
17
|
-
import {useTranslator} from '../i18n';
|
|
17
|
+
import {useLocale, useTranslator} from '../i18n';
|
|
18
18
|
|
|
19
19
|
// =============================================================================
|
|
20
20
|
// Types
|
|
21
21
|
// =============================================================================
|
|
22
22
|
|
|
23
23
|
export interface UseSpeechRecognitionOptions {
|
|
24
|
-
/** BCP-47 language tag. @default
|
|
24
|
+
/** BCP-47 language tag. @default InternationalizationProvider locale */
|
|
25
25
|
lang?: string;
|
|
26
26
|
/** Whether recognition continues until explicitly stopped. @default true */
|
|
27
27
|
continuous?: boolean;
|
|
@@ -260,6 +260,7 @@ export function useSpeechRecognition(
|
|
|
260
260
|
options: UseSpeechRecognitionOptions = {},
|
|
261
261
|
): UseSpeechRecognitionReturn {
|
|
262
262
|
const t = useTranslator();
|
|
263
|
+
const providerLocale = useLocale();
|
|
263
264
|
const {
|
|
264
265
|
lang,
|
|
265
266
|
continuous = true,
|
|
@@ -348,7 +349,7 @@ export function useSpeechRecognition(
|
|
|
348
349
|
}
|
|
349
350
|
recognitionRef.current?.abort();
|
|
350
351
|
const recognition = new SR();
|
|
351
|
-
recognition.lang = lang ??
|
|
352
|
+
recognition.lang = lang ?? providerLocale;
|
|
352
353
|
recognition.continuous = continuous;
|
|
353
354
|
recognition.interimResults = interimResults;
|
|
354
355
|
|
|
@@ -418,6 +419,7 @@ export function useSpeechRecognition(
|
|
|
418
419
|
recognition.start();
|
|
419
420
|
}, [
|
|
420
421
|
lang,
|
|
422
|
+
providerLocale,
|
|
421
423
|
continuous,
|
|
422
424
|
interimResults,
|
|
423
425
|
startVolumePolling,
|
|
@@ -47,6 +47,7 @@ import {useTooltip} from '../Tooltip';
|
|
|
47
47
|
import {mergeProps, mergeRefs} from '../utils';
|
|
48
48
|
import {indicatorScope} from '../Indicator/indicator.markers.stylex';
|
|
49
49
|
import {useIndicatorFocusRing} from '../hooks/useIndicatorFocusRing';
|
|
50
|
+
import {useResolvedRequired} from '../hooks/useResolvedRequired';
|
|
50
51
|
import {useIndicator} from '../Indicator';
|
|
51
52
|
import {themeProps} from '../utils/themeProps';
|
|
52
53
|
import {CheckboxListContext} from '../CheckboxList/CheckboxListContext';
|
|
@@ -301,6 +302,10 @@ export function CheckboxInput({
|
|
|
301
302
|
const id = useId();
|
|
302
303
|
const descriptionID = useId();
|
|
303
304
|
const statusMessageID = useId();
|
|
305
|
+
// Announce the effective required state (form default included) while the
|
|
306
|
+
// native `required` stays bound to the explicit `isRequired` so a layout
|
|
307
|
+
// default never switches on browser validation.
|
|
308
|
+
const isEffectivelyRequired = useResolvedRequired({isRequired, isOptional});
|
|
304
309
|
|
|
305
310
|
const [, startTransition] = useTransition();
|
|
306
311
|
const [optimisticValue, setOptimisticValue] = useOptimistic(value);
|
|
@@ -421,6 +426,7 @@ export function CheckboxInput({
|
|
|
421
426
|
form={isFocusableDisabled ? '' : undefined}
|
|
422
427
|
readOnly={isReadOnly}
|
|
423
428
|
required={isRequired}
|
|
429
|
+
aria-required={isEffectivelyRequired ? 'true' : undefined}
|
|
424
430
|
onChange={e => {
|
|
425
431
|
if (isDisabled || isBusy || isReadOnly) {
|
|
426
432
|
return;
|
|
@@ -103,7 +103,7 @@ const styles = stylex.create({
|
|
|
103
103
|
},
|
|
104
104
|
labelHover: {
|
|
105
105
|
backgroundColor: {
|
|
106
|
-
':hover': {
|
|
106
|
+
':hover:where(:not(:disabled,[aria-disabled="true"]))': {
|
|
107
107
|
'@media (hover: hover)': colorVars['--color-overlay-hover'],
|
|
108
108
|
},
|
|
109
109
|
},
|
|
@@ -112,7 +112,7 @@ const styles = stylex.create({
|
|
|
112
112
|
// the base secondary color from `label` (last-wins property merge),
|
|
113
113
|
// leaving linked citations to inherit the surrounding text color.
|
|
114
114
|
default: colorVars['--color-text-secondary'],
|
|
115
|
-
':hover': {
|
|
115
|
+
':hover:where(:not(:disabled,[aria-disabled="true"]))': {
|
|
116
116
|
'@media (hover: hover)': colorVars['--color-text-primary'],
|
|
117
117
|
},
|
|
118
118
|
},
|
|
@@ -145,7 +145,7 @@ const styles = stylex.create({
|
|
|
145
145
|
// hover-only conditional replaces the base accent-muted pill from
|
|
146
146
|
// `number` on merge, leaving linked badges transparent.
|
|
147
147
|
default: colorVars['--color-accent-muted'],
|
|
148
|
-
':hover': {
|
|
148
|
+
':hover:where(:not(:disabled,[aria-disabled="true"]))': {
|
|
149
149
|
'@media (hover: hover)': colorVars['--color-overlay-hover'],
|
|
150
150
|
},
|
|
151
151
|
},
|
|
@@ -78,7 +78,7 @@ const styles = stylex.create({
|
|
|
78
78
|
},
|
|
79
79
|
hoverOnPointer: {
|
|
80
80
|
'@media (hover: hover)': {
|
|
81
|
-
':hover::after': {
|
|
81
|
+
':hover:where(:not(:disabled,[aria-disabled="true"]))::after': {
|
|
82
82
|
backgroundColor: colorVars['--color-overlay-hover'],
|
|
83
83
|
},
|
|
84
84
|
},
|
|
@@ -110,7 +110,7 @@ const styles = stylex.create({
|
|
|
110
110
|
// @media (hover: hover) so touch devices don't get a stuck hover state.
|
|
111
111
|
borderedHoverOnPointer: {
|
|
112
112
|
'@media (hover: hover)': {
|
|
113
|
-
':hover': {
|
|
113
|
+
':hover:where(:not(:disabled,[aria-disabled="true"]))': {
|
|
114
114
|
borderColor: colorVars['--color-border-emphasized'],
|
|
115
115
|
},
|
|
116
116
|
},
|
|
@@ -215,6 +215,16 @@ export const docsDense = {
|
|
|
215
215
|
description:
|
|
216
216
|
'Use when a selection needs richer custom content than a Selector row. One component: it owns field, trigger, popover, focus restore, and changeAction; the render prop owns the selector-specific accessible structure.',
|
|
217
217
|
bestPractices: [
|
|
218
|
+
{
|
|
219
|
+
guidance: true,
|
|
220
|
+
description:
|
|
221
|
+
'Use variant="ghost" with a startIcon for a toolbar trigger. Use alignment="end" when a wide surface should align its end edge to the trigger.',
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
guidance: true,
|
|
225
|
+
description:
|
|
226
|
+
'For staged editors, keep draft state in the composed content and call the provided onChange helper only from Apply. Cancel or dismiss without committing.',
|
|
227
|
+
},
|
|
218
228
|
{
|
|
219
229
|
guidance: true,
|
|
220
230
|
description:
|
|
@@ -35,6 +35,7 @@ import {useTranslator} from '../i18n';
|
|
|
35
35
|
import {layerAnimations} from '../Layer/layerAnimations.stylex';
|
|
36
36
|
import type {LayerAlignment, LayerPlacement} from '../Layer/useLayer';
|
|
37
37
|
import {usePopover} from '../Popover/usePopover';
|
|
38
|
+
import {useResolvedRequired} from '../hooks/useResolvedRequired';
|
|
38
39
|
import {
|
|
39
40
|
colorVars,
|
|
40
41
|
durationVars,
|
|
@@ -110,16 +111,17 @@ const styles = stylex.create({
|
|
|
110
111
|
backgroundColor: 'transparent',
|
|
111
112
|
backgroundImage: {
|
|
112
113
|
default: null,
|
|
113
|
-
':hover': {
|
|
114
|
+
':hover:where(:not(:disabled,[aria-disabled="true"]))': {
|
|
114
115
|
'@media (hover: hover)': `linear-gradient(${colorVars['--color-overlay-hover']}, ${colorVars['--color-overlay-hover']})`,
|
|
115
116
|
},
|
|
116
117
|
':active': `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`,
|
|
117
118
|
},
|
|
118
119
|
boxShadow: {
|
|
119
120
|
default: 'none',
|
|
120
|
-
':hover:not(:focus-within)':
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
':hover:not(:focus-within):where(:not(:disabled,[aria-disabled="true"]))':
|
|
122
|
+
{
|
|
123
|
+
'@media (hover: hover)': 'none',
|
|
124
|
+
},
|
|
123
125
|
':focus-within': 'none',
|
|
124
126
|
},
|
|
125
127
|
fontWeight: fontWeightVars['--font-weight-medium'],
|
|
@@ -344,6 +346,7 @@ export function ComplexSelector<Value>({
|
|
|
344
346
|
...props
|
|
345
347
|
}: ComplexSelectorProps<Value>) {
|
|
346
348
|
const t = useTranslator();
|
|
349
|
+
const isEffectivelyRequired = useResolvedRequired({isRequired, isOptional});
|
|
347
350
|
const placeholder = placeholderFromProps ?? t('@astryx.selector.placeholder');
|
|
348
351
|
const effectiveStatusVariant =
|
|
349
352
|
variant === 'ghost' && statusVariant === 'attached'
|
|
@@ -497,7 +500,7 @@ export function ComplexSelector<Value>({
|
|
|
497
500
|
aria-controls={contentId}
|
|
498
501
|
aria-describedby={ariaDescribedBy}
|
|
499
502
|
aria-labelledby={labelId}
|
|
500
|
-
aria-required={
|
|
503
|
+
aria-required={isEffectivelyRequired ? 'true' : undefined}
|
|
501
504
|
aria-invalid={status?.type === 'error' ? 'true' : undefined}
|
|
502
505
|
aria-busy={isBusy || undefined}
|
|
503
506
|
disabled={isDisabled}
|
|
@@ -917,6 +917,22 @@ describe('DateInput', () => {
|
|
|
917
917
|
expect(screen.getByDisplayValue('Jan 25, 2026')).toBeInTheDocument();
|
|
918
918
|
});
|
|
919
919
|
|
|
920
|
+
it('follows the InternationalizationProvider locale (#5074)', () => {
|
|
921
|
+
render(
|
|
922
|
+
<InternationalizationProvider locale="es-ES">
|
|
923
|
+
<DateInput
|
|
924
|
+
label="Date"
|
|
925
|
+
value="2026-01-25"
|
|
926
|
+
onChange={() => {}}
|
|
927
|
+
format="date_long"
|
|
928
|
+
/>
|
|
929
|
+
</InternationalizationProvider>,
|
|
930
|
+
);
|
|
931
|
+
expect(
|
|
932
|
+
screen.getByDisplayValue('25 de enero de 2026'),
|
|
933
|
+
).toBeInTheDocument();
|
|
934
|
+
});
|
|
935
|
+
|
|
920
936
|
it('renders the ISO shape for format="system_date"', () => {
|
|
921
937
|
render(
|
|
922
938
|
<DateInput
|
|
@@ -1186,7 +1202,7 @@ describe('DateInput clear icon theme target', () => {
|
|
|
1186
1202
|
expect(css).toContain('.astryx-date-input-clear-icon {');
|
|
1187
1203
|
expect(css).toContain('width: 12px');
|
|
1188
1204
|
expect(css).toContain('height: 12px');
|
|
1189
|
-
expect(css).toContain('.astryx-date-input-clear-icon:hover
|
|
1205
|
+
expect(css).toContain('.astryx-date-input-clear-icon:hover');
|
|
1190
1206
|
expect(css).toContain('color: var(--color-icon-primary)');
|
|
1191
1207
|
});
|
|
1192
1208
|
});
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import {
|
|
20
|
+
use,
|
|
20
21
|
useId,
|
|
21
22
|
useState,
|
|
22
23
|
useCallback,
|
|
@@ -58,6 +59,7 @@ import {
|
|
|
58
59
|
} from '../Calendar';
|
|
59
60
|
import {useCalendarConstraints} from '../Calendar/hooks';
|
|
60
61
|
import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
|
|
62
|
+
import {useResolvedRequired} from '../hooks/useResolvedRequired';
|
|
61
63
|
import {usePopover} from '../Popover';
|
|
62
64
|
import {useTooltip} from '../Tooltip';
|
|
63
65
|
import {getInputARIA, isImeKeyEvent, parseDateInput} from '../utils';
|
|
@@ -160,7 +162,7 @@ import type {SizeValue} from '../utils/types';
|
|
|
160
162
|
import {themeProps} from '../utils/themeProps';
|
|
161
163
|
import {focusOutlineStyles} from '../utils/focusOutline.stylex';
|
|
162
164
|
import {stableClassName} from '../naming';
|
|
163
|
-
import {useTranslator} from '../i18n';
|
|
165
|
+
import {useTranslator, InternationalizationContext} from '../i18n';
|
|
164
166
|
|
|
165
167
|
export interface DateInputProps extends Omit<
|
|
166
168
|
BaseProps,
|
|
@@ -399,6 +401,8 @@ export function DateInput({
|
|
|
399
401
|
...rest
|
|
400
402
|
}: DateInputProps) {
|
|
401
403
|
const t = useTranslator();
|
|
404
|
+
const isEffectivelyRequired = useResolvedRequired({isRequired, isOptional});
|
|
405
|
+
const {locale} = use(InternationalizationContext);
|
|
402
406
|
const placeholder =
|
|
403
407
|
placeholderFromProps ?? t('@astryx.dateInput.placeholder');
|
|
404
408
|
const size = useSize(sizeProp, 'md');
|
|
@@ -481,8 +485,8 @@ export function DateInput({
|
|
|
481
485
|
(iso: ISODateString): string =>
|
|
482
486
|
typeof format === 'function'
|
|
483
487
|
? format(iso)
|
|
484
|
-
: formatSharedDate(plainDateFromISO(iso), format),
|
|
485
|
-
[format],
|
|
488
|
+
: formatSharedDate(plainDateFromISO(iso), format, locale),
|
|
489
|
+
[format, locale],
|
|
486
490
|
);
|
|
487
491
|
|
|
488
492
|
// Display value: pending input if typing, otherwise formatted value
|
|
@@ -497,7 +501,7 @@ export function DateInput({
|
|
|
497
501
|
const isInputValid =
|
|
498
502
|
pendingInput === null || !pendingInput.trim()
|
|
499
503
|
? true
|
|
500
|
-
: parseDateInput(pendingInput) !== null;
|
|
504
|
+
: parseDateInput(pendingInput, locale) !== null;
|
|
501
505
|
|
|
502
506
|
const popover = usePopover({
|
|
503
507
|
dialogLabel: t('@astryx.dateInput.dialogLabel'),
|
|
@@ -579,7 +583,7 @@ export function DateInput({
|
|
|
579
583
|
setPendingInput(newValue);
|
|
580
584
|
|
|
581
585
|
// If the input is valid and passes constraints, update immediately
|
|
582
|
-
const parsed = parseDateInput(newValue);
|
|
586
|
+
const parsed = parseDateInput(newValue, locale);
|
|
583
587
|
if (
|
|
584
588
|
parsed &&
|
|
585
589
|
plainDateToISO(parsed) !== value &&
|
|
@@ -592,7 +596,7 @@ export function DateInput({
|
|
|
592
596
|
calendarRef.current?.navigateTo(parsedISO);
|
|
593
597
|
}
|
|
594
598
|
},
|
|
595
|
-
[value, fireChange, isDateDisabled, isEffectivelyDisabled],
|
|
599
|
+
[value, fireChange, isDateDisabled, isEffectivelyDisabled, locale],
|
|
596
600
|
);
|
|
597
601
|
|
|
598
602
|
// Commit pending input (shared by blur and Enter key)
|
|
@@ -609,7 +613,7 @@ export function DateInput({
|
|
|
609
613
|
return;
|
|
610
614
|
}
|
|
611
615
|
|
|
612
|
-
const parsed = parseDateInput(pendingInput);
|
|
616
|
+
const parsed = parseDateInput(pendingInput, locale);
|
|
613
617
|
if (parsed && !isDateDisabled(parsed)) {
|
|
614
618
|
const parsedISO = plainDateToISO(parsed);
|
|
615
619
|
if (parsedISO !== value) {
|
|
@@ -617,7 +621,7 @@ export function DateInput({
|
|
|
617
621
|
}
|
|
618
622
|
}
|
|
619
623
|
setPendingInput(null);
|
|
620
|
-
}, [pendingInput, value, fireChange, isDateDisabled]);
|
|
624
|
+
}, [pendingInput, value, fireChange, isDateDisabled, locale]);
|
|
621
625
|
|
|
622
626
|
// Handle blur - validate, check constraints, and clear pending input
|
|
623
627
|
const handleBlur = useCallback(() => {
|
|
@@ -737,7 +741,7 @@ export function DateInput({
|
|
|
737
741
|
readOnly={showsDisabledMessage || undefined}
|
|
738
742
|
aria-labelledby={ariaLabelledBy}
|
|
739
743
|
aria-describedby={ariaDescribedBy}
|
|
740
|
-
aria-required={
|
|
744
|
+
aria-required={isEffectivelyRequired ? 'true' : undefined}
|
|
741
745
|
aria-invalid={
|
|
742
746
|
status?.type === 'error' || !isInputValid ? 'true' : undefined
|
|
743
747
|
}
|
|
@@ -98,6 +98,18 @@ export const docs = {
|
|
|
98
98
|
type: 'Array<(date: Date) => boolean>',
|
|
99
99
|
description: 'Custom constraint functions to disable specific dates.',
|
|
100
100
|
},
|
|
101
|
+
{
|
|
102
|
+
name: 'maxRangeSpan',
|
|
103
|
+
type: 'number',
|
|
104
|
+
description:
|
|
105
|
+
'Maximum days a selected range may span, counting both endpoints (`7` = a 7-day window, start + 6). Once a start is picked, days beyond this distance are disabled so the range cannot stretch past the cap. Rolling window relative to the start; for fixed calendar bounds use `min`/`max`. Constrains selection only; it never rewrites a `value` already wider than the cap (flag that with `status`).',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'minRangeSpan',
|
|
109
|
+
type: 'number',
|
|
110
|
+
description:
|
|
111
|
+
'Minimum days a selected range must span, counting both endpoints (`2` forbids a single-day range). Once a start is picked, days closer than this are disabled. Defaults to 1 (same-day start and end allowed).',
|
|
112
|
+
},
|
|
101
113
|
{
|
|
102
114
|
name: 'presets',
|
|
103
115
|
type: 'Array<DateRangePreset>',
|
|
@@ -313,6 +325,10 @@ export const docsDense = {
|
|
|
313
325
|
min: 'min selectable date: ISODateString template literal type (YYYY-MM-DD); use string literal or cast `as ISODateString`',
|
|
314
326
|
max: 'max selectable date: ISODateString template literal type (YYYY-MM-DD); use string literal or cast `as ISODateString`',
|
|
315
327
|
dateConstraints: 'custom constraint fns to disable dates',
|
|
328
|
+
maxRangeSpan:
|
|
329
|
+
'max days a range may span, both endpoints counted (7 = a 7-day window); caps the window from the picked start. Selection-only; does not rewrite an over-wide value',
|
|
330
|
+
minRangeSpan:
|
|
331
|
+
'min days a range must span, both endpoints counted (2 forbids a single-day range); default 1',
|
|
316
332
|
presets: 'preset ranges as quick-select options',
|
|
317
333
|
hasClear: 'clear button when range is set (default true)',
|
|
318
334
|
placeholder: 'placeholder when empty',
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* SYNC: When DateRangeInput.tsx changes, update tests to match new behavior
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
12
|
+
import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
|
|
13
13
|
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
|
|
@@ -712,3 +712,83 @@ describe('DateRangeInput disabled theme state', () => {
|
|
|
712
712
|
expect(root).not.toHaveAttribute('data-disabled');
|
|
713
713
|
});
|
|
714
714
|
});
|
|
715
|
+
|
|
716
|
+
describe('DateRangeInput range-span forwarding', () => {
|
|
717
|
+
// Pin "today" so the popover opens on a known month and the day buttons we
|
|
718
|
+
// query are guaranteed to render.
|
|
719
|
+
beforeEach(() => {
|
|
720
|
+
vi.useFakeTimers();
|
|
721
|
+
vi.setSystemTime(new Date('2026-01-05T12:00:00Z'));
|
|
722
|
+
});
|
|
723
|
+
afterEach(() => {
|
|
724
|
+
vi.useRealTimers();
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
// The calendar renders in the top layer; jsdom keeps day buttons in the DOM
|
|
728
|
+
// but role queries skip them, so reach them by their machine-readable
|
|
729
|
+
// data-date (ISO) attribute — the same approach Calendar's own tests use.
|
|
730
|
+
const dayButton = (iso: string): HTMLButtonElement | null =>
|
|
731
|
+
document.querySelector<HTMLButtonElement>(`button[data-date="${iso}"]`);
|
|
732
|
+
|
|
733
|
+
it('forwards maxRangeSpan so the window caps after a start is picked', () => {
|
|
734
|
+
render(
|
|
735
|
+
<DateRangeInput
|
|
736
|
+
label="Reporting period"
|
|
737
|
+
value={null}
|
|
738
|
+
onChange={() => {}}
|
|
739
|
+
maxRangeSpan={7}
|
|
740
|
+
/>,
|
|
741
|
+
);
|
|
742
|
+
|
|
743
|
+
fireEvent.click(getButton('Open calendar'));
|
|
744
|
+
|
|
745
|
+
// Before a start is picked, a far-off day is selectable.
|
|
746
|
+
expect(dayButton('2026-01-20')).not.toBeDisabled();
|
|
747
|
+
|
|
748
|
+
fireEvent.click(dayButton('2026-01-10') as HTMLButtonElement);
|
|
749
|
+
|
|
750
|
+
// A 7-day window spans start ± 6 days: Jan 16 is the edge, Jan 17 is out.
|
|
751
|
+
expect(dayButton('2026-01-16')).not.toBeDisabled();
|
|
752
|
+
expect(dayButton('2026-01-17')).toBeDisabled();
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
it('disables a preset whose range violates the span cap', () => {
|
|
756
|
+
const presets = [
|
|
757
|
+
{
|
|
758
|
+
label: 'Last 3 days',
|
|
759
|
+
getRange: (): DateRange => ({
|
|
760
|
+
start: '2026-01-08',
|
|
761
|
+
end: '2026-01-10',
|
|
762
|
+
}),
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
label: 'Last 30 days',
|
|
766
|
+
getRange: (): DateRange => ({
|
|
767
|
+
start: '2025-12-12',
|
|
768
|
+
end: '2026-01-10',
|
|
769
|
+
}),
|
|
770
|
+
},
|
|
771
|
+
];
|
|
772
|
+
const handleChange = vi.fn();
|
|
773
|
+
render(
|
|
774
|
+
<DateRangeInput
|
|
775
|
+
label="Reporting period"
|
|
776
|
+
value={null}
|
|
777
|
+
onChange={handleChange}
|
|
778
|
+
maxRangeSpan={7}
|
|
779
|
+
presets={presets}
|
|
780
|
+
/>,
|
|
781
|
+
);
|
|
782
|
+
|
|
783
|
+
fireEvent.click(getButton('Open calendar'));
|
|
784
|
+
|
|
785
|
+
// The 3-day preset fits the 7-day cap; the 30-day preset can't be committed.
|
|
786
|
+
const withinCap = getButton('Last 3 days');
|
|
787
|
+
const overCap = getButton('Last 30 days');
|
|
788
|
+
expect(withinCap).not.toBeDisabled();
|
|
789
|
+
expect(overCap).toBeDisabled();
|
|
790
|
+
|
|
791
|
+
fireEvent.click(overCap);
|
|
792
|
+
expect(handleChange).not.toHaveBeenCalled();
|
|
793
|
+
});
|
|
794
|
+
});
|
|
@@ -16,12 +16,20 @@
|
|
|
16
16
|
* - /packages/cli/assets/templates/blocks/components/DateRangeInput/ (showcase blocks)
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
use,
|
|
21
|
+
useId,
|
|
22
|
+
useCallback,
|
|
23
|
+
useMemo,
|
|
24
|
+
useOptimistic,
|
|
25
|
+
useTransition,
|
|
26
|
+
} from 'react';
|
|
20
27
|
import * as stylex from '@stylexjs/stylex';
|
|
21
28
|
import {
|
|
22
29
|
plainDateFromISO,
|
|
23
30
|
plainDateToday,
|
|
24
31
|
plainDateFormat,
|
|
32
|
+
plainDateDiffDays,
|
|
25
33
|
DATE_FORMAT_SHORT,
|
|
26
34
|
DATE_FORMAT_SHORT_WITH_YEAR,
|
|
27
35
|
} from '../utils/plainDate';
|
|
@@ -60,10 +68,12 @@ import type {BaseProps} from '../BaseProps';
|
|
|
60
68
|
import type {SizeValue} from '../utils/types';
|
|
61
69
|
import {useSize} from '../SizeContext/SizeContext';
|
|
62
70
|
import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
|
|
71
|
+
import {useResolvedRequired} from '../hooks/useResolvedRequired';
|
|
63
72
|
import {themeProps} from '../utils/themeProps';
|
|
64
73
|
import {focusOutlineStyles} from '../utils/focusOutline.stylex';
|
|
65
74
|
import {stableClassName} from '../naming';
|
|
66
|
-
import {useTranslator} from '../i18n';
|
|
75
|
+
import {useTranslator, InternationalizationContext} from '../i18n';
|
|
76
|
+
import type {Locale} from '../i18n/types';
|
|
67
77
|
|
|
68
78
|
export type {DateRange} from '../Calendar';
|
|
69
79
|
|
|
@@ -146,7 +156,7 @@ const styles = stylex.create({
|
|
|
146
156
|
borderRadius: radiusVars['--radius-element'],
|
|
147
157
|
backgroundColor: {
|
|
148
158
|
default: 'transparent',
|
|
149
|
-
':hover': {
|
|
159
|
+
':hover:where(:not(:disabled,[aria-disabled="true"]))': {
|
|
150
160
|
'@media (hover: hover)': colorVars['--color-overlay-hover'],
|
|
151
161
|
},
|
|
152
162
|
},
|
|
@@ -161,6 +171,11 @@ const styles = stylex.create({
|
|
|
161
171
|
backgroundColor: colorVars['--color-accent-muted'],
|
|
162
172
|
color: colorVars['--color-accent'],
|
|
163
173
|
},
|
|
174
|
+
presetButtonDisabled: {
|
|
175
|
+
color: colorVars['--color-text-disabled'],
|
|
176
|
+
cursor: 'not-allowed',
|
|
177
|
+
backgroundColor: 'transparent',
|
|
178
|
+
},
|
|
164
179
|
});
|
|
165
180
|
|
|
166
181
|
const sizeStyles = stylex.create({
|
|
@@ -178,7 +193,7 @@ const sizeStyles = stylex.create({
|
|
|
178
193
|
},
|
|
179
194
|
});
|
|
180
195
|
|
|
181
|
-
function formatRangeDisplay(range: DateRange | null): string {
|
|
196
|
+
function formatRangeDisplay(range: DateRange | null, locale?: Locale): string {
|
|
182
197
|
if (!range) {
|
|
183
198
|
return '';
|
|
184
199
|
}
|
|
@@ -188,7 +203,7 @@ function formatRangeDisplay(range: DateRange | null): string {
|
|
|
188
203
|
const sameYear = start.year === end.year && start.year === currentYear;
|
|
189
204
|
|
|
190
205
|
const fmt = sameYear ? DATE_FORMAT_SHORT : DATE_FORMAT_SHORT_WITH_YEAR;
|
|
191
|
-
return `${plainDateFormat(start, fmt)} – ${plainDateFormat(end, fmt)}`;
|
|
206
|
+
return `${plainDateFormat(start, fmt, locale)} – ${plainDateFormat(end, fmt, locale)}`;
|
|
192
207
|
}
|
|
193
208
|
|
|
194
209
|
function isRangeEqual(a: DateRange | null, b: DateRange | null): boolean {
|
|
@@ -201,6 +216,34 @@ function isRangeEqual(a: DateRange | null, b: DateRange | null): boolean {
|
|
|
201
216
|
return a.start === b.start && a.end === b.end;
|
|
202
217
|
}
|
|
203
218
|
|
|
219
|
+
// A preset that would land outside the span bounds is disabled rather than
|
|
220
|
+
// allowed to override them: the cap is authoritative, so an out-of-window
|
|
221
|
+
// preset stays visible (discoverable) but non-committable, mirroring how the
|
|
222
|
+
// calendar disables out-of-window days. Spans count both endpoints.
|
|
223
|
+
function isRangeWithinSpan(
|
|
224
|
+
range: DateRange,
|
|
225
|
+
maxRangeSpan: number | undefined,
|
|
226
|
+
minRangeSpan: number | undefined,
|
|
227
|
+
): boolean {
|
|
228
|
+
if (maxRangeSpan == null && minRangeSpan == null) {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
const span =
|
|
232
|
+
Math.abs(
|
|
233
|
+
plainDateDiffDays(
|
|
234
|
+
plainDateFromISO(range.start),
|
|
235
|
+
plainDateFromISO(range.end),
|
|
236
|
+
),
|
|
237
|
+
) + 1;
|
|
238
|
+
if (maxRangeSpan != null && span > maxRangeSpan) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
if (minRangeSpan != null && span < minRangeSpan) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
|
|
204
247
|
export interface DateRangeInputProps extends Omit<
|
|
205
248
|
BaseProps,
|
|
206
249
|
'onChange' | 'defaultValue'
|
|
@@ -303,6 +346,30 @@ export interface DateRangeInputProps extends Omit<
|
|
|
303
346
|
*/
|
|
304
347
|
dateConstraints?: ReadonlyArray<(date: Date) => boolean>;
|
|
305
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Maximum number of days the selected range may span, counting both
|
|
351
|
+
* endpoints — `maxRangeSpan={7}` allows a 7-day window (start + 6 days).
|
|
352
|
+
* Once a start date is picked, days beyond this distance from it are
|
|
353
|
+
* disabled, so the user can't stretch the range past the cap. Use for
|
|
354
|
+
* rolling windows like "at most a week from the chosen day"; for fixed
|
|
355
|
+
* calendar bounds use `min`/`max`.
|
|
356
|
+
*
|
|
357
|
+
* This constrains selection only — it never rewrites a `value` that is
|
|
358
|
+
* already wider than the cap. Surface such a value with `status` if you
|
|
359
|
+
* need to flag it. A `preset` whose range violates the cap is disabled
|
|
360
|
+
* (shown but not committable) rather than allowed to override it.
|
|
361
|
+
*/
|
|
362
|
+
maxRangeSpan?: number;
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Minimum number of days the selected range must span, counting both
|
|
366
|
+
* endpoints — `minRangeSpan={2}` forbids a single-day range. Once a start
|
|
367
|
+
* date is picked, days closer than this to it are disabled — except the
|
|
368
|
+
* start itself, which stays selectable as the active anchor. Defaults to 1
|
|
369
|
+
* (a same-day start and end is allowed).
|
|
370
|
+
*/
|
|
371
|
+
minRangeSpan?: number;
|
|
372
|
+
|
|
306
373
|
/**
|
|
307
374
|
* Preset date ranges shown as quick-select options beside the calendar.
|
|
308
375
|
*/
|
|
@@ -396,6 +463,8 @@ export function DateRangeInput({
|
|
|
396
463
|
min,
|
|
397
464
|
max,
|
|
398
465
|
dateConstraints,
|
|
466
|
+
maxRangeSpan,
|
|
467
|
+
minRangeSpan,
|
|
399
468
|
presets,
|
|
400
469
|
hasClear = true,
|
|
401
470
|
placeholder: placeholderFromProps,
|
|
@@ -413,6 +482,8 @@ export function DateRangeInput({
|
|
|
413
482
|
...rest
|
|
414
483
|
}: DateRangeInputProps) {
|
|
415
484
|
const t = useTranslator();
|
|
485
|
+
const isEffectivelyRequired = useResolvedRequired({isRequired, isOptional});
|
|
486
|
+
const {locale} = use(InternationalizationContext);
|
|
416
487
|
const placeholder =
|
|
417
488
|
placeholderFromProps ?? t('@astryx.dateRangeInput.placeholder');
|
|
418
489
|
const size = useSize(sizeProp, 'md');
|
|
@@ -459,8 +530,8 @@ export function DateRangeInput({
|
|
|
459
530
|
.join(' ') || undefined;
|
|
460
531
|
|
|
461
532
|
const displayValue = useMemo(
|
|
462
|
-
() => formatRangeDisplay(optimisticValue),
|
|
463
|
-
[optimisticValue],
|
|
533
|
+
() => formatRangeDisplay(optimisticValue, locale),
|
|
534
|
+
[optimisticValue, locale],
|
|
464
535
|
);
|
|
465
536
|
|
|
466
537
|
const popover = usePopover({
|
|
@@ -609,7 +680,7 @@ export function DateRangeInput({
|
|
|
609
680
|
aria-disabled={showsDisabledMessage ? 'true' : undefined}
|
|
610
681
|
aria-label={triggerAriaLabel}
|
|
611
682
|
aria-describedby={ariaDescribedBy}
|
|
612
|
-
aria-required={
|
|
683
|
+
aria-required={isEffectivelyRequired ? 'true' : undefined}
|
|
613
684
|
aria-invalid={status?.type === 'error' ? 'true' : undefined}
|
|
614
685
|
aria-busy={isBusy || undefined}
|
|
615
686
|
aria-expanded={popover.isOpen}
|
|
@@ -642,6 +713,11 @@ export function DateRangeInput({
|
|
|
642
713
|
{presets.map(preset => {
|
|
643
714
|
const presetRange = preset.getRange();
|
|
644
715
|
const isActive = isRangeEqual(value, presetRange);
|
|
716
|
+
const isPresetDisabled = !isRangeWithinSpan(
|
|
717
|
+
presetRange,
|
|
718
|
+
maxRangeSpan,
|
|
719
|
+
minRangeSpan,
|
|
720
|
+
);
|
|
645
721
|
return (
|
|
646
722
|
<button
|
|
647
723
|
key={preset.label}
|
|
@@ -652,11 +728,13 @@ export function DateRangeInput({
|
|
|
652
728
|
// marked with aria-current (not aria-selected, a listbox
|
|
653
729
|
// concept that contradicted the Tab interaction) (forms-5).
|
|
654
730
|
aria-current={isActive ? 'true' : undefined}
|
|
731
|
+
disabled={isPresetDisabled}
|
|
655
732
|
onClick={() => handlePresetClick(preset)}
|
|
656
733
|
{...stylex.props(
|
|
657
734
|
focusOutlineStyles.focusVisible,
|
|
658
735
|
styles.presetButton,
|
|
659
736
|
isActive && styles.presetButtonActive,
|
|
737
|
+
isPresetDisabled && styles.presetButtonDisabled,
|
|
660
738
|
)}>
|
|
661
739
|
{preset.label}
|
|
662
740
|
</button>
|
|
@@ -671,6 +749,8 @@ export function DateRangeInput({
|
|
|
671
749
|
min={min}
|
|
672
750
|
max={max}
|
|
673
751
|
dateConstraints={dateConstraints}
|
|
752
|
+
maxRangeSpan={maxRangeSpan}
|
|
753
|
+
minRangeSpan={minRangeSpan}
|
|
674
754
|
numberOfMonths={numberOfMonths}
|
|
675
755
|
weekStartsOn={weekStartsOn}
|
|
676
756
|
/>
|