@astryxdesign/core 0.4.5 → 0.4.6-canary.cea9ecd
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 +134 -0
- package/dist/Avatar/Avatar.d.ts +10 -5
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +139 -30
- package/dist/Avatar/AvatarStatusDot.d.ts +2 -1
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- package/dist/Avatar/AvatarStatusDot.js +30 -4
- package/dist/Avatar/AvatarStatusLabelContext.d.ts +39 -0
- package/dist/Avatar/AvatarStatusLabelContext.d.ts.map +1 -0
- package/dist/Avatar/AvatarStatusLabelContext.js +41 -0
- package/dist/AvatarGroup/AvatarGroup.d.ts +3 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +15 -9
- package/dist/Blockquote/Blockquote.d.ts +4 -3
- package/dist/Blockquote/Blockquote.d.ts.map +1 -1
- package/dist/Blockquote/Blockquote.js +9 -10
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +21 -5
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +47 -34
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +7 -7
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +21 -12
- package/dist/Calendar/hooks/useCalendarNavigation.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarNavigation.js +8 -4
- package/dist/Calendar/styles.d.ts +2 -2
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +5 -5
- 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 +3 -3
- package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
- package/dist/Chat/ChatComposerDrawer.js +2 -2
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +2 -2
- 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/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +2 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +2 -2
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +5 -5
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +4 -4
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +1 -1
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +2 -2
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +3 -3
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +6 -6
- package/dist/DateInput/DateInput.d.ts +31 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +90 -22
- package/dist/DateInput/MonthScroller.d.ts +35 -0
- package/dist/DateInput/MonthScroller.d.ts.map +1 -0
- package/dist/DateInput/MonthScroller.js +658 -0
- package/dist/DateInput/MonthYearWheels.d.ts +24 -0
- package/dist/DateInput/MonthYearWheels.d.ts.map +1 -0
- package/dist/DateInput/MonthYearWheels.js +114 -0
- package/dist/DateInput/TouchDateField.d.ts +10 -0
- package/dist/DateInput/TouchDateField.d.ts.map +1 -0
- package/dist/DateInput/TouchDateField.js +810 -0
- package/dist/DateInput/Wheel.d.ts +41 -0
- package/dist/DateInput/Wheel.d.ts.map +1 -0
- package/dist/DateInput/Wheel.js +315 -0
- package/dist/DateInput/monthGeometry.d.ts +65 -0
- package/dist/DateInput/monthGeometry.d.ts.map +1 -0
- package/dist/DateInput/monthGeometry.js +98 -0
- package/dist/DateInput/tokens.stylex.d.ts +63 -0
- package/dist/DateInput/tokens.stylex.d.ts.map +1 -0
- package/dist/DateInput/tokens.stylex.js +74 -0
- package/dist/DateInput/useOwnScrollGesture.d.ts +41 -0
- package/dist/DateInput/useOwnScrollGesture.d.ts.map +1 -0
- package/dist/DateInput/useOwnScrollGesture.js +202 -0
- package/dist/DateInput/usePointerDragScroll.d.ts +15 -0
- package/dist/DateInput/usePointerDragScroll.d.ts.map +1 -0
- package/dist/DateInput/usePointerDragScroll.js +216 -0
- package/dist/DateInput/useScrollSettle.d.ts +26 -0
- package/dist/DateInput/useScrollSettle.d.ts.map +1 -0
- package/dist/DateInput/useScrollSettle.js +149 -0
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +17 -14
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +17 -14
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +3 -3
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +2 -2
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +2 -2
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +2 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -2
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +4 -4
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +6 -0
- package/dist/Field/inputStyles.stylex.d.ts +1 -1
- package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
- package/dist/Field/inputStyles.stylex.js +5 -5
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +6 -6
- 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/InputGroup/InputGroup.js +1 -1
- package/dist/Item/Item.d.ts +9 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +52 -14
- 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 +5 -4
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +6 -6
- package/dist/MetadataList/MetadataList.d.ts.map +1 -1
- package/dist/MetadataList/MetadataList.js +1 -1
- 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 -8
- package/dist/NavItem/navItemStyles.stylex.d.ts +4 -4
- package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
- package/dist/NavItem/navItemStyles.stylex.js +4 -4
- package/dist/NavMenu/NavHeadingMenuItem.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenuItem.js +3 -3
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +36 -8
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +3 -3
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +2 -2
- 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/RadioListItem.d.ts +2 -2
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +70 -40
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +7 -7
- 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 +7 -2
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +3 -3
- package/dist/Selector/Selector.d.ts +26 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +93 -20
- 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.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +4 -4
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +3 -3
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +7 -7
- 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/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +2 -2
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +1 -1
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +3 -3
- 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/filtering/useTableFiltering.d.ts.map +1 -1
- package/dist/Table/plugins/filtering/useTableFiltering.js +2 -2
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +2 -2
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +2 -2
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +1 -1
- 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.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +3 -3
- package/dist/TextArea/TextArea.js +1 -1
- package/dist/TextInput/TextInput.js +1 -1
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +3 -3
- package/dist/TimeInput/TimeInput.js +2 -2
- 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/Toast/Toast.d.ts +4 -3
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +10 -7
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +6 -6
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.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.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +4 -4
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +3 -3
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +2 -2
- package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +2 -2
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +4 -4
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +7 -7
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +2 -2
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +1 -1
- package/dist/astryx.css +124 -62
- 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/useAutoMediaMode.d.ts +31 -0
- package/dist/hooks/useAutoMediaMode.d.ts.map +1 -0
- package/dist/hooks/useAutoMediaMode.js +201 -0
- package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
- package/dist/hooks/useInputStatusIcon.js +1 -1
- package/dist/hooks/useListFocus.d.ts +5 -2
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +12 -6
- 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/MediaTheme.d.ts +25 -5
- package/dist/theme/MediaTheme.d.ts.map +1 -1
- package/dist/theme/MediaTheme.js +31 -6
- 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/theme/index.d.ts +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/syntax/index.d.ts +6 -0
- package/dist/theme/syntax/index.d.ts.map +1 -1
- package/dist/theme/syntax/index.js +7 -2
- 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/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/plainDate.d.ts +5 -2
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +20 -4
- package/locales/en.json +28 -0
- package/locales/pseudo.json +21 -0
- package/package.json +3 -3
- package/src/Avatar/Avatar.doc.mjs +10 -6
- package/src/Avatar/Avatar.test.tsx +219 -1
- package/src/Avatar/Avatar.tsx +179 -37
- package/src/Avatar/AvatarStatusDot.tsx +30 -4
- package/src/Avatar/AvatarStatusLabelContext.ts +47 -0
- package/src/AvatarGroup/AvatarGroup.doc.mjs +10 -6
- package/src/AvatarGroup/AvatarGroup.test.tsx +62 -0
- package/src/AvatarGroup/AvatarGroup.tsx +3 -1
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +31 -8
- package/src/Banner/Banner.doc.mjs +2 -0
- package/src/Blockquote/Blockquote.doc.mjs +30 -7
- package/src/Blockquote/Blockquote.test.tsx +34 -3
- package/src/Blockquote/Blockquote.tsx +11 -9
- package/src/BottomSheet/BottomSheet.doc.mjs +3 -3
- package/src/BottomSheet/BottomSheet.test.tsx +24 -0
- package/src/BottomSheet/BottomSheetPanel.test.tsx +91 -0
- package/src/BottomSheet/BottomSheetPanel.tsx +58 -3
- package/src/Breadcrumbs/BreadcrumbItem.tsx +36 -23
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +26 -2
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -0
- package/src/Button/Button.tsx +12 -9
- package/src/Calendar/Calendar.tsx +15 -9
- package/src/Calendar/hooks/useCalendarNavigation.ts +6 -4
- package/src/Calendar/styles.ts +8 -5
- 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 +11 -5
- package/src/Chat/ChatComposerDrawer.tsx +4 -1
- package/src/Chat/ChatToolCalls.tsx +13 -4
- 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/Chat/useTriggerMenu.tsx +4 -1
- package/src/CheckboxInput/CheckboxInput.tsx +5 -2
- package/src/Citation/Citation.test.tsx +6 -1
- package/src/Citation/Citation.tsx +11 -5
- package/src/ClickableCard/ClickableCard.tsx +7 -4
- package/src/CodeBlock/CodeBlock.tsx +4 -1
- package/src/Collapsible/Collapsible.tsx +5 -2
- package/src/CommandPalette/CommandPaletteItem.tsx +6 -3
- package/src/ComplexSelector/ComplexSelector.doc.mjs +10 -0
- package/src/ComplexSelector/ComplexSelector.tsx +14 -7
- package/src/DateInput/DateInput.test.tsx +17 -1
- package/src/DateInput/DateInput.tsx +93 -21
- package/src/DateInput/DateInputTouch.test.tsx +2582 -0
- package/src/DateInput/MonthScroller.tsx +878 -0
- package/src/DateInput/MonthYearWheels.tsx +147 -0
- package/src/DateInput/TouchDateField.tsx +1223 -0
- package/src/DateInput/Wheel.tsx +473 -0
- package/src/DateInput/monthGeometry.ts +118 -0
- package/src/DateInput/tokens.stylex.ts +99 -0
- package/src/DateInput/useOwnScrollGesture.ts +227 -0
- package/src/DateInput/usePointerDragScroll.ts +220 -0
- package/src/DateInput/useScrollSettle.ts +164 -0
- package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
- package/src/DateRangeInput/DateRangeInput.tsx +31 -13
- package/src/DateTimeInput/DateTimeInput.tsx +25 -9
- package/src/Dialog/Dialog.test.tsx +24 -0
- package/src/Dialog/Dialog.tsx +3 -0
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +5 -2
- package/src/DropdownMenu/DropdownMenuItem.tsx +5 -2
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +5 -2
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +5 -2
- package/src/Field/Field.doc.mjs +2 -0
- package/src/Field/FieldLabel.tsx +9 -3
- package/src/Field/InputClearButton.test.tsx +110 -3
- package/src/Field/InputClearButton.tsx +38 -0
- package/src/Field/inputStyles.stylex.ts +17 -13
- package/src/FileInput/FileInput.tsx +15 -8
- package/src/FormLayout/FormLayout.doc.mjs +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/InputGroup/InputGroup.tsx +1 -1
- package/src/Item/Item.doc.mjs +1 -0
- package/src/Item/Item.test.tsx +50 -0
- package/src/Item/Item.tsx +54 -6
- 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 +11 -3
- package/src/Link/Link.tsx +9 -6
- package/src/MetadataList/MetadataList.tsx +4 -1
- 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 +26 -10
- package/src/NavItem/navItemStyles.stylex.ts +7 -4
- package/src/NavMenu/NavHeadingMenuItem.tsx +6 -3
- package/src/NumberInput/NumberInput.doc.mjs +24 -0
- package/src/NumberInput/NumberInput.test.tsx +138 -0
- package/src/NumberInput/NumberInput.tsx +47 -8
- package/src/Outline/Outline.tsx +5 -2
- package/src/Pagination/Pagination.tsx +5 -2
- package/src/Popover/Popover.test.tsx +27 -1
- 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/RadioListItem.tsx +88 -53
- package/src/Resizable/ResizeHandle.test.tsx +22 -0
- package/src/Resizable/ResizeHandle.tsx +25 -7
- 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 +15 -3
- package/src/SelectableCard/SelectableCard.tsx +6 -3
- package/src/Selector/Selector.doc.mjs +16 -2
- package/src/Selector/Selector.test.tsx +525 -1
- package/src/Selector/Selector.tsx +180 -25
- 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 +14 -5
- package/src/SideNav/SideNavItem.tsx +9 -3
- package/src/Slider/Slider.tsx +25 -6
- 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/Switch/Switch.tsx +5 -2
- package/src/TabList/Tab.tsx +4 -1
- package/src/TabList/TabMenu.tsx +9 -3
- package/src/Table/TableRow.tsx +4 -4
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +6 -2
- package/src/Table/plugins/filtering/useTableFiltering.tsx +4 -1
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +10 -3
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +6 -3
- package/src/Table/plugins/sortable/useTableSortable.tsx +4 -1
- 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 +10 -4
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextArea/TextArea.tsx +1 -1
- package/src/TextInput/TextInput.tsx +1 -1
- package/src/Thumbnail/Thumbnail.tsx +9 -3
- package/src/TimeInput/TimeInput.tsx +1 -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/Toast/Toast.tsx +9 -7
- package/src/Token/Token.tsx +14 -5
- package/src/Tokenizer/Tokenizer.tsx +4 -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 +13 -4
- package/src/TopNav/TopNavItem.tsx +6 -3
- package/src/TopNav/TopNavMegaMenu.tsx +5 -2
- package/src/TopNav/TopNavMegaMenuItem.tsx +5 -2
- package/src/TopNav/TopNavMenu.tsx +10 -4
- package/src/TreeList/TreeListItem.tsx +22 -7
- package/src/Typeahead/BaseTypeahead.tsx +5 -2
- package/src/Typeahead/Typeahead.tsx +4 -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/useAutoMediaMode.test.ts +109 -0
- package/src/hooks/useAutoMediaMode.ts +233 -0
- package/src/hooks/useInputStatusIcon.tsx +4 -1
- package/src/hooks/useListFocus.doc.mjs +2 -2
- package/src/hooks/useListFocus.test.tsx +65 -3
- package/src/hooks/useListFocus.ts +15 -7
- 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/reset.css +9 -2
- package/src/reset.test.ts +22 -0
- package/src/theme/MediaTheme.doc.mjs +23 -4
- package/src/theme/MediaTheme.dom.test.tsx +97 -0
- package/src/theme/MediaTheme.tsx +42 -7
- 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/theme/index.ts +1 -1
- package/src/theme/syntax/index.ts +6 -2
- package/src/theme/syntax/serverSafeSyntax.test.ts +68 -0
- package/src/utils/dateParser.test.ts +20 -0
- package/src/utils/dateParser.ts +14 -7
- package/src/utils/index.ts +2 -0
- package/src/utils/plainDate.test.ts +6 -0
- package/src/utils/plainDate.ts +21 -4
|
@@ -16,7 +16,14 @@
|
|
|
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,
|
|
@@ -65,7 +72,8 @@ import {useResolvedRequired} from '../hooks/useResolvedRequired';
|
|
|
65
72
|
import {themeProps} from '../utils/themeProps';
|
|
66
73
|
import {focusOutlineStyles} from '../utils/focusOutline.stylex';
|
|
67
74
|
import {stableClassName} from '../naming';
|
|
68
|
-
import {useTranslator} from '../i18n';
|
|
75
|
+
import {useTranslator, InternationalizationContext} from '../i18n';
|
|
76
|
+
import type {Locale} from '../i18n/types';
|
|
69
77
|
|
|
70
78
|
export type {DateRange} from '../Calendar';
|
|
71
79
|
|
|
@@ -98,7 +106,10 @@ const styles = stylex.create({
|
|
|
98
106
|
color: colorVars['--color-text-primary'],
|
|
99
107
|
backgroundColor: 'transparent',
|
|
100
108
|
outline: 'none',
|
|
101
|
-
cursor:
|
|
109
|
+
cursor: {
|
|
110
|
+
default: 'pointer',
|
|
111
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
112
|
+
},
|
|
102
113
|
textAlign: 'start',
|
|
103
114
|
whiteSpace: 'nowrap',
|
|
104
115
|
overflow: 'hidden',
|
|
@@ -108,7 +119,7 @@ const styles = stylex.create({
|
|
|
108
119
|
color: colorVars['--color-text-secondary'],
|
|
109
120
|
},
|
|
110
121
|
triggerDisabled: {
|
|
111
|
-
cursor: '
|
|
122
|
+
cursor: 'default',
|
|
112
123
|
},
|
|
113
124
|
iconButton: {
|
|
114
125
|
display: 'flex',
|
|
@@ -119,11 +130,14 @@ const styles = stylex.create({
|
|
|
119
130
|
borderWidth: 0,
|
|
120
131
|
borderStyle: 'none',
|
|
121
132
|
backgroundColor: 'transparent',
|
|
122
|
-
cursor:
|
|
133
|
+
cursor: {
|
|
134
|
+
default: 'pointer',
|
|
135
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
136
|
+
},
|
|
123
137
|
borderRadius: radiusVars['--radius-element'],
|
|
124
138
|
},
|
|
125
139
|
iconButtonDisabled: {
|
|
126
|
-
cursor: '
|
|
140
|
+
cursor: 'default',
|
|
127
141
|
},
|
|
128
142
|
popoverLayout: {
|
|
129
143
|
display: 'flex',
|
|
@@ -148,7 +162,7 @@ const styles = stylex.create({
|
|
|
148
162
|
borderRadius: radiusVars['--radius-element'],
|
|
149
163
|
backgroundColor: {
|
|
150
164
|
default: 'transparent',
|
|
151
|
-
':hover': {
|
|
165
|
+
':hover:where(:not(:disabled,[aria-disabled="true"]))': {
|
|
152
166
|
'@media (hover: hover)': colorVars['--color-overlay-hover'],
|
|
153
167
|
},
|
|
154
168
|
},
|
|
@@ -156,7 +170,10 @@ const styles = stylex.create({
|
|
|
156
170
|
fontSize: typeScaleVars['--text-label-size'],
|
|
157
171
|
lineHeight: typeScaleVars['--text-label-leading'],
|
|
158
172
|
color: colorVars['--color-text-primary'],
|
|
159
|
-
cursor:
|
|
173
|
+
cursor: {
|
|
174
|
+
default: 'pointer',
|
|
175
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
176
|
+
},
|
|
160
177
|
textAlign: 'start',
|
|
161
178
|
},
|
|
162
179
|
presetButtonActive: {
|
|
@@ -165,7 +182,7 @@ const styles = stylex.create({
|
|
|
165
182
|
},
|
|
166
183
|
presetButtonDisabled: {
|
|
167
184
|
color: colorVars['--color-text-disabled'],
|
|
168
|
-
cursor: '
|
|
185
|
+
cursor: 'default',
|
|
169
186
|
backgroundColor: 'transparent',
|
|
170
187
|
},
|
|
171
188
|
});
|
|
@@ -185,7 +202,7 @@ const sizeStyles = stylex.create({
|
|
|
185
202
|
},
|
|
186
203
|
});
|
|
187
204
|
|
|
188
|
-
function formatRangeDisplay(range: DateRange | null): string {
|
|
205
|
+
function formatRangeDisplay(range: DateRange | null, locale?: Locale): string {
|
|
189
206
|
if (!range) {
|
|
190
207
|
return '';
|
|
191
208
|
}
|
|
@@ -195,7 +212,7 @@ function formatRangeDisplay(range: DateRange | null): string {
|
|
|
195
212
|
const sameYear = start.year === end.year && start.year === currentYear;
|
|
196
213
|
|
|
197
214
|
const fmt = sameYear ? DATE_FORMAT_SHORT : DATE_FORMAT_SHORT_WITH_YEAR;
|
|
198
|
-
return `${plainDateFormat(start, fmt)} – ${plainDateFormat(end, fmt)}`;
|
|
215
|
+
return `${plainDateFormat(start, fmt, locale)} – ${plainDateFormat(end, fmt, locale)}`;
|
|
199
216
|
}
|
|
200
217
|
|
|
201
218
|
function isRangeEqual(a: DateRange | null, b: DateRange | null): boolean {
|
|
@@ -475,6 +492,7 @@ export function DateRangeInput({
|
|
|
475
492
|
}: DateRangeInputProps) {
|
|
476
493
|
const t = useTranslator();
|
|
477
494
|
const isEffectivelyRequired = useResolvedRequired({isRequired, isOptional});
|
|
495
|
+
const {locale} = use(InternationalizationContext);
|
|
478
496
|
const placeholder =
|
|
479
497
|
placeholderFromProps ?? t('@astryx.dateRangeInput.placeholder');
|
|
480
498
|
const size = useSize(sizeProp, 'md');
|
|
@@ -521,8 +539,8 @@ export function DateRangeInput({
|
|
|
521
539
|
.join(' ') || undefined;
|
|
522
540
|
|
|
523
541
|
const displayValue = useMemo(
|
|
524
|
-
() => formatRangeDisplay(optimisticValue),
|
|
525
|
-
[optimisticValue],
|
|
542
|
+
() => formatRangeDisplay(optimisticValue, locale),
|
|
543
|
+
[optimisticValue, locale],
|
|
526
544
|
);
|
|
527
545
|
|
|
528
546
|
const popover = usePopover({
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import {
|
|
20
|
+
use,
|
|
20
21
|
useId,
|
|
21
22
|
useState,
|
|
22
23
|
useCallback,
|
|
@@ -88,7 +89,7 @@ import {useResolvedRequired} from '../hooks/useResolvedRequired';
|
|
|
88
89
|
import {useSize} from '../SizeContext/SizeContext';
|
|
89
90
|
import {themeProps} from '../utils/themeProps';
|
|
90
91
|
import {focusOutlineStyles} from '../utils/focusOutline.stylex';
|
|
91
|
-
import {useTranslator} from '../i18n';
|
|
92
|
+
import {useTranslator, InternationalizationContext} from '../i18n';
|
|
92
93
|
|
|
93
94
|
export type ISODateTimeString = string & {
|
|
94
95
|
readonly __brand: 'ISODateTimeString';
|
|
@@ -120,11 +121,14 @@ const styles = stylex.create({
|
|
|
120
121
|
borderWidth: 0,
|
|
121
122
|
borderStyle: 'none',
|
|
122
123
|
backgroundColor: 'transparent',
|
|
123
|
-
cursor:
|
|
124
|
+
cursor: {
|
|
125
|
+
default: 'pointer',
|
|
126
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
127
|
+
},
|
|
124
128
|
borderRadius: radiusVars['--radius-element'],
|
|
125
129
|
},
|
|
126
130
|
iconButtonDisabled: {
|
|
127
|
-
cursor: '
|
|
131
|
+
cursor: 'default',
|
|
128
132
|
},
|
|
129
133
|
icon: {
|
|
130
134
|
display: 'flex',
|
|
@@ -153,7 +157,7 @@ const styles = stylex.create({
|
|
|
153
157
|
},
|
|
154
158
|
},
|
|
155
159
|
inputDisabled: {
|
|
156
|
-
cursor: '
|
|
160
|
+
cursor: 'default',
|
|
157
161
|
},
|
|
158
162
|
inputInvalid: {
|
|
159
163
|
color: colorVars['--color-text-secondary'],
|
|
@@ -450,6 +454,7 @@ export function DateTimeInput({
|
|
|
450
454
|
}: DateTimeInputProps) {
|
|
451
455
|
const t = useTranslator();
|
|
452
456
|
const isEffectivelyRequired = useResolvedRequired({isRequired, isOptional});
|
|
457
|
+
const {locale} = use(InternationalizationContext);
|
|
453
458
|
// Speaks arrow-key stepping results through the persistent live regions:
|
|
454
459
|
// stepping programmatically rewrites a plain textbox's value, which screen
|
|
455
460
|
// readers do not announce on their own (WCAG 4.1.2).
|
|
@@ -560,13 +565,17 @@ export function DateTimeInput({
|
|
|
560
565
|
datePendingInput !== null
|
|
561
566
|
? datePendingInput
|
|
562
567
|
: valueParts.date && /^\d{4}-\d{2}-\d{2}$/.test(valueParts.date)
|
|
563
|
-
? plainDateFormat(
|
|
568
|
+
? plainDateFormat(
|
|
569
|
+
plainDateFromISO(valueParts.date),
|
|
570
|
+
DATE_FORMAT_LONG,
|
|
571
|
+
locale,
|
|
572
|
+
)
|
|
564
573
|
: '';
|
|
565
574
|
|
|
566
575
|
const isDateInputValid =
|
|
567
576
|
datePendingInput === null || !datePendingInput.trim()
|
|
568
577
|
? true
|
|
569
|
-
: parseDateInput(datePendingInput) !== null;
|
|
578
|
+
: parseDateInput(datePendingInput, locale) !== null;
|
|
570
579
|
|
|
571
580
|
// --- Time input state ---
|
|
572
581
|
const [timePendingInput, setTimePendingInput] = useState<string | null>(null);
|
|
@@ -694,7 +703,7 @@ export function DateTimeInput({
|
|
|
694
703
|
const text = e.target.value;
|
|
695
704
|
setDatePendingInput(text);
|
|
696
705
|
|
|
697
|
-
const parsed = parseDateInput(text);
|
|
706
|
+
const parsed = parseDateInput(text, locale);
|
|
698
707
|
if (
|
|
699
708
|
parsed &&
|
|
700
709
|
plainDateToISO(parsed) !== valueParts.date &&
|
|
@@ -706,7 +715,13 @@ export function DateTimeInput({
|
|
|
706
715
|
calendarRef.current?.navigateTo(parsedISO);
|
|
707
716
|
}
|
|
708
717
|
},
|
|
709
|
-
[
|
|
718
|
+
[
|
|
719
|
+
valueParts.date,
|
|
720
|
+
isDateDisabled,
|
|
721
|
+
handleDateChange,
|
|
722
|
+
isEffectivelyDisabled,
|
|
723
|
+
locale,
|
|
724
|
+
],
|
|
710
725
|
);
|
|
711
726
|
|
|
712
727
|
const commitDatePendingInput = useCallback(() => {
|
|
@@ -722,7 +737,7 @@ export function DateTimeInput({
|
|
|
722
737
|
return;
|
|
723
738
|
}
|
|
724
739
|
|
|
725
|
-
const parsed = parseDateInput(datePendingInput);
|
|
740
|
+
const parsed = parseDateInput(datePendingInput, locale);
|
|
726
741
|
if (parsed && !isDateDisabled(parsed)) {
|
|
727
742
|
const parsedISO = plainDateToISO(parsed);
|
|
728
743
|
if (parsedISO !== valueParts.date) {
|
|
@@ -737,6 +752,7 @@ export function DateTimeInput({
|
|
|
737
752
|
fireChange,
|
|
738
753
|
isDateDisabled,
|
|
739
754
|
handleDateChange,
|
|
755
|
+
locale,
|
|
740
756
|
]);
|
|
741
757
|
|
|
742
758
|
const handleDateBlur = useCallback(() => {
|
|
@@ -461,4 +461,28 @@ describe('Dialog', () => {
|
|
|
461
461
|
before.remove();
|
|
462
462
|
});
|
|
463
463
|
});
|
|
464
|
+
|
|
465
|
+
describe('container padding isolation', () => {
|
|
466
|
+
it('resets container padding custom properties on the root dialog element', () => {
|
|
467
|
+
render(
|
|
468
|
+
<Dialog isOpen={true} onOpenChange={() => {}}>
|
|
469
|
+
Content
|
|
470
|
+
</Dialog>,
|
|
471
|
+
);
|
|
472
|
+
const dialog = screen.getByRole('dialog');
|
|
473
|
+
const computed = window.getComputedStyle(dialog);
|
|
474
|
+
expect(
|
|
475
|
+
computed.getPropertyValue('--container-padding-inline-start'),
|
|
476
|
+
).toBe('0px');
|
|
477
|
+
expect(computed.getPropertyValue('--container-padding-inline-end')).toBe(
|
|
478
|
+
'0px',
|
|
479
|
+
);
|
|
480
|
+
expect(computed.getPropertyValue('--container-padding-block-start')).toBe(
|
|
481
|
+
'0px',
|
|
482
|
+
);
|
|
483
|
+
expect(computed.getPropertyValue('--container-padding-block-end')).toBe(
|
|
484
|
+
'0px',
|
|
485
|
+
);
|
|
486
|
+
});
|
|
487
|
+
});
|
|
464
488
|
});
|
package/src/Dialog/Dialog.tsx
CHANGED
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
containerPaddingBlockStartVarStyles,
|
|
45
45
|
containerPaddingBlockEndVarStyles,
|
|
46
46
|
spacingStepToToken,
|
|
47
|
+
overlayPaddingReset,
|
|
47
48
|
} from '../Layout/padding.stylex';
|
|
48
49
|
import type {SpacingStep} from '../utils/types';
|
|
49
50
|
import {mergeProps, mergeRefs} from '../utils';
|
|
@@ -610,6 +611,7 @@ export function Dialog({
|
|
|
610
611
|
themeProps('dialog', {variant}),
|
|
611
612
|
stylex.props(
|
|
612
613
|
styles.inlineWrapper,
|
|
614
|
+
overlayPaddingReset.reset,
|
|
613
615
|
!isFullscreen && dynamicStyles.sizing(width, maxHeight),
|
|
614
616
|
isFullscreen && styles.fullscreen,
|
|
615
617
|
xstyle,
|
|
@@ -636,6 +638,7 @@ export function Dialog({
|
|
|
636
638
|
themeProps('dialog', {variant}),
|
|
637
639
|
focusOutlineProps.focusVisible(
|
|
638
640
|
styles.dialog,
|
|
641
|
+
overlayPaddingReset.reset,
|
|
639
642
|
isOpen && styles.open,
|
|
640
643
|
styles.backdrop,
|
|
641
644
|
!isFullscreen && dynamicStyles.sizing(width, maxHeight),
|
|
@@ -46,12 +46,15 @@ const styles = stylex.create({
|
|
|
46
46
|
default: 'transparent',
|
|
47
47
|
':focus': colorVars['--color-overlay-hover'],
|
|
48
48
|
},
|
|
49
|
-
cursor:
|
|
49
|
+
cursor: {
|
|
50
|
+
default: 'pointer',
|
|
51
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
52
|
+
},
|
|
50
53
|
outline: 'none',
|
|
51
54
|
},
|
|
52
55
|
disabled: {
|
|
53
56
|
opacity: 0.5,
|
|
54
|
-
cursor: '
|
|
57
|
+
cursor: 'default',
|
|
55
58
|
},
|
|
56
59
|
// Rendered in Item's `marker` slot as a raw flex child, so `order` moves it
|
|
57
60
|
// relative to the label within the row. On touch it moves to the inline-end.
|
|
@@ -54,13 +54,16 @@ const menuItemStyles = stylex.create({
|
|
|
54
54
|
':focus': colorVars['--color-overlay-hover'],
|
|
55
55
|
},
|
|
56
56
|
border: 'none',
|
|
57
|
-
cursor:
|
|
57
|
+
cursor: {
|
|
58
|
+
default: 'pointer',
|
|
59
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
60
|
+
},
|
|
58
61
|
textAlign: 'start',
|
|
59
62
|
outline: 'none',
|
|
60
63
|
},
|
|
61
64
|
disabled: {
|
|
62
65
|
opacity: 0.5,
|
|
63
|
-
cursor: '
|
|
66
|
+
cursor: 'default',
|
|
64
67
|
},
|
|
65
68
|
destructive: {
|
|
66
69
|
// Only recolor the text/icon; the hover / focus background stays the shared
|
|
@@ -42,12 +42,15 @@ const styles = stylex.create({
|
|
|
42
42
|
default: 'transparent',
|
|
43
43
|
':focus': colorVars['--color-overlay-hover'],
|
|
44
44
|
},
|
|
45
|
-
cursor:
|
|
45
|
+
cursor: {
|
|
46
|
+
default: 'pointer',
|
|
47
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
48
|
+
},
|
|
46
49
|
outline: 'none',
|
|
47
50
|
},
|
|
48
51
|
disabled: {
|
|
49
52
|
opacity: 0.5,
|
|
50
|
-
cursor: '
|
|
53
|
+
cursor: 'default',
|
|
51
54
|
},
|
|
52
55
|
// Rendered in Item's `marker` slot as a raw flex child. On touch it moves to
|
|
53
56
|
// the inline-end of the row via `order`.
|
|
@@ -96,7 +96,10 @@ const triggerStyles = stylex.create({
|
|
|
96
96
|
':focus': colorVars['--color-overlay-hover'],
|
|
97
97
|
},
|
|
98
98
|
border: 'none',
|
|
99
|
-
cursor:
|
|
99
|
+
cursor: {
|
|
100
|
+
default: 'pointer',
|
|
101
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
102
|
+
},
|
|
100
103
|
textAlign: 'start',
|
|
101
104
|
outline: 'none',
|
|
102
105
|
},
|
|
@@ -107,7 +110,7 @@ const triggerStyles = stylex.create({
|
|
|
107
110
|
},
|
|
108
111
|
disabled: {
|
|
109
112
|
opacity: 0.5,
|
|
110
|
-
cursor: '
|
|
113
|
+
cursor: 'default',
|
|
111
114
|
},
|
|
112
115
|
caret: {
|
|
113
116
|
display: 'flex',
|
package/src/Field/Field.doc.mjs
CHANGED
|
@@ -39,6 +39,8 @@ export const docs = {
|
|
|
39
39
|
],
|
|
40
40
|
vars: [
|
|
41
41
|
{name: '--_field-radius', description: 'Border radius of input fields', default: 'var(--radius-element)', private: true},
|
|
42
|
+
{name: '--_input-clear-hit-inset', description: 'Outset of the clear (\u2715) button\u2019s invisible hit area, applied to a ::after overlay. 0 on a fine pointer; negative on a coarse one, which grows the 20px button to the 24px touch target without changing what is drawn.', default: '0px', private: true},
|
|
43
|
+
{name: '--_input-clear-hit-content', description: 'Whether the clear (\u2715) button\u2019s invisible hit overlay exists. `none` on a fine pointer, so no ::after is generated and hover still reaches the glyph; `""` on a coarse one, where the overlay provides the 24px touch target.', default: 'none', private: true},
|
|
42
44
|
],
|
|
43
45
|
derived: [
|
|
44
46
|
{property: 'borderRadius', vars: ['--_field-radius']},
|
package/src/Field/FieldLabel.tsx
CHANGED
|
@@ -45,11 +45,14 @@ const styles = stylex.create({
|
|
|
45
45
|
lineHeight: typeScaleVars['--text-label-leading'],
|
|
46
46
|
fontWeight: fontWeightVars['--font-weight-medium'],
|
|
47
47
|
color: colorVars['--color-text-secondary'],
|
|
48
|
-
cursor:
|
|
48
|
+
cursor: {
|
|
49
|
+
default: 'pointer',
|
|
50
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
51
|
+
},
|
|
49
52
|
},
|
|
50
53
|
labelDisabled: {
|
|
51
54
|
color: colorVars['--color-text-disabled'],
|
|
52
|
-
cursor: '
|
|
55
|
+
cursor: 'default',
|
|
53
56
|
},
|
|
54
57
|
srOnly: {
|
|
55
58
|
borderStyle: 'none',
|
|
@@ -82,7 +85,10 @@ const styles = stylex.create({
|
|
|
82
85
|
// When the description forwards clicks to a click-activatable control
|
|
83
86
|
// (checkbox/switch), it reads as part of the same hit target as the label.
|
|
84
87
|
descriptionClickable: {
|
|
85
|
-
cursor:
|
|
88
|
+
cursor: {
|
|
89
|
+
default: 'pointer',
|
|
90
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
91
|
+
},
|
|
86
92
|
},
|
|
87
93
|
});
|
|
88
94
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @file InputClearButton.test.tsx
|
|
5
|
-
* @input Uses vitest, @testing-library/react, InputClearButton, Icon,
|
|
5
|
+
* @input Uses node:fs, node:path, vitest, @testing-library/react, InputClearButton, Icon,
|
|
6
|
+
* theme
|
|
6
7
|
* @output Unit tests for the shared clear-button primitive
|
|
7
8
|
* @position Testing; validates InputClearButton.tsx — the single home for the
|
|
8
9
|
* clearable input family's clear (✕) affordance and its theme target.
|
|
@@ -10,6 +11,8 @@
|
|
|
10
11
|
* SYNC: When InputClearButton.tsx changes, update tests to match new behavior.
|
|
11
12
|
*/
|
|
12
13
|
|
|
14
|
+
import {readFileSync} from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
13
16
|
import {describe, it, expect, vi} from 'vitest';
|
|
14
17
|
import {render, screen, fireEvent} from '@testing-library/react';
|
|
15
18
|
import {InputClearButton} from './InputClearButton';
|
|
@@ -22,6 +25,39 @@ function generateThemeTestCSS(theme: Parameters<typeof generateThemeCSS>[0]) {
|
|
|
22
25
|
return [prose, component].filter(Boolean).join('\n\n');
|
|
23
26
|
}
|
|
24
27
|
|
|
28
|
+
interface InjectedRule {
|
|
29
|
+
selector: string;
|
|
30
|
+
text: string;
|
|
31
|
+
media: string | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Every style rule StyleX has injected at runtime (`runtimeInjection` in the
|
|
36
|
+
* root vitest config), flattened out of any at-rule wrapper and tagged with
|
|
37
|
+
* that wrapper's condition — so a `@media (pointer: coarse)` rule stays
|
|
38
|
+
* distinguishable from the unconditional one.
|
|
39
|
+
*/
|
|
40
|
+
function injectedRules(): InjectedRule[] {
|
|
41
|
+
const walk = (rules: CSSRuleList, condition: string | null) =>
|
|
42
|
+
[...rules].flatMap((rule): InjectedRule[] => {
|
|
43
|
+
const {selectorText} = rule as CSSStyleRule;
|
|
44
|
+
if (typeof selectorText === 'string') {
|
|
45
|
+
return [{selector: selectorText, text: rule.cssText, media: condition}];
|
|
46
|
+
}
|
|
47
|
+
// A grouping rule (@media, @keyframes, ...): descend, carrying the
|
|
48
|
+
// innermost condition down. jsdom hangs an empty `cssRules` off plain
|
|
49
|
+
// style rules too, which is why the leaf check comes first.
|
|
50
|
+
const nested = (rule as CSSGroupingRule).cssRules;
|
|
51
|
+
if (nested == null) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
const own = (rule as CSSMediaRule).media?.mediaText;
|
|
55
|
+
return walk(nested, own != null && own !== '' ? own : condition);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return [...document.styleSheets].flatMap(sheet => walk(sheet.cssRules, null));
|
|
59
|
+
}
|
|
60
|
+
|
|
25
61
|
const getGlyph = (): HTMLElement => {
|
|
26
62
|
const button = screen.getByRole('button', {name: 'Clear'});
|
|
27
63
|
const icon = button.querySelector('.astryx-icon');
|
|
@@ -111,7 +147,7 @@ describe('InputClearButton', () => {
|
|
|
111
147
|
const css = generateThemeTestCSS(theme);
|
|
112
148
|
expect(css).toContain('.astryx-input-clear-icon {');
|
|
113
149
|
expect(css).toContain('width: 12px');
|
|
114
|
-
expect(css).toContain('.astryx-input-clear-icon:hover
|
|
150
|
+
expect(css).toContain('.astryx-input-clear-icon:hover');
|
|
115
151
|
expect(css).toContain('color: var(--color-icon-primary)');
|
|
116
152
|
});
|
|
117
153
|
|
|
@@ -121,6 +157,77 @@ describe('InputClearButton', () => {
|
|
|
121
157
|
expect(button).toHaveClass('astryx-input-clear-button');
|
|
122
158
|
});
|
|
123
159
|
|
|
160
|
+
it('grows the hit area to 24px on a coarse pointer only (WCAG 2.5.8 AA)', () => {
|
|
161
|
+
// The visual glyph stays 20px; an ::after overlay expands only the
|
|
162
|
+
// tappable region, and only under a coarse pointer. Asserted against the
|
|
163
|
+
// CSS StyleX injects at runtime, because jsdom resolves neither media
|
|
164
|
+
// queries nor pseudo-element boxes.
|
|
165
|
+
render(<InputClearButton label="Clear" onClick={() => {}} />);
|
|
166
|
+
const button = screen.getByRole('button', {name: 'Clear'});
|
|
167
|
+
const classes = new Set(button.className.split(' ').filter(Boolean));
|
|
168
|
+
|
|
169
|
+
const css = injectedRules();
|
|
170
|
+
const rulesForButton = css.filter(({selector}) =>
|
|
171
|
+
[...classes].some(c => selector.includes(`.${c}`)),
|
|
172
|
+
);
|
|
173
|
+
// Guards every assertion below against silently passing if StyleX's
|
|
174
|
+
// runtime injection or the class plumbing ever changes shape.
|
|
175
|
+
expect(rulesForButton.length).toBeGreaterThan(0);
|
|
176
|
+
|
|
177
|
+
const decl = (pattern: RegExp, inMedia?: string) =>
|
|
178
|
+
rulesForButton.some(
|
|
179
|
+
({text, media}) =>
|
|
180
|
+
pattern.test(text) &&
|
|
181
|
+
(inMedia == null ? media == null : (media ?? '').includes(inMedia)),
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
// Fine pointer: hit area == the 20px visual glyph, no expansion.
|
|
185
|
+
expect(decl(/--_input-clear-hit-inset\s*:\s*0px/)).toBe(true);
|
|
186
|
+
// Coarse pointer: 20px + 2px on each side = 24x24, the AA floor.
|
|
187
|
+
expect(decl(/--_input-clear-hit-inset\s*:\s*-2px/, 'pointer: coarse')).toBe(
|
|
188
|
+
true,
|
|
189
|
+
);
|
|
190
|
+
// ...and nothing wider than that, which would reach into the adornment
|
|
191
|
+
// gap and the input's caret area. Scoped to the coarse block, because
|
|
192
|
+
// that is the only place a wider value can appear.
|
|
193
|
+
expect(
|
|
194
|
+
decl(
|
|
195
|
+
/--_input-clear-hit-inset\s*:\s*-(?:[3-9]|\d{2,})px/,
|
|
196
|
+
'pointer: coarse',
|
|
197
|
+
),
|
|
198
|
+
).toBe(false);
|
|
199
|
+
// The overlay exists only on touch. On a fine pointer a generated
|
|
200
|
+
// ::after would cover the button and take hover away from the glyph
|
|
201
|
+
// target, so `content` is gated the same way the inset is.
|
|
202
|
+
expect(decl(/--_input-clear-hit-content\s*:\s*none/)).toBe(true);
|
|
203
|
+
expect(decl(/--_input-clear-hit-content\s*:\s*""/, 'pointer: coarse')).toBe(
|
|
204
|
+
true,
|
|
205
|
+
);
|
|
206
|
+
// The overlay itself is what carries the expansion, and what is gated.
|
|
207
|
+
expect(
|
|
208
|
+
decl(/::after\s*\{[^}]*inset\s*:\s*var\(--_input-clear-hit-inset\)/),
|
|
209
|
+
).toBe(true);
|
|
210
|
+
expect(
|
|
211
|
+
decl(/::after\s*\{[^}]*content\s*:\s*var\(--_input-clear-hit-content\)/),
|
|
212
|
+
).toBe(true);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('declares its own containing block for the hit overlay', () => {
|
|
216
|
+
// The ::after overlay must resolve against this button. Button happens to
|
|
217
|
+
// set `position: relative` on itself, so at runtime the overlay is
|
|
218
|
+
// correctly placed either way — and StyleX compiles both declarations to
|
|
219
|
+
// the same atomic class, so the rendered CSS cannot tell the two apart.
|
|
220
|
+
// Assert on the source instead, so a future edit can't quietly leave the
|
|
221
|
+
// overlay depending on another component's internal.
|
|
222
|
+
const source = readFileSync(
|
|
223
|
+
path.resolve(__dirname, './InputClearButton.tsx'),
|
|
224
|
+
'utf-8',
|
|
225
|
+
);
|
|
226
|
+
const buttonStyle = source.match(/button:\s*\{[\s\S]*?\n {2}\},/)?.[0];
|
|
227
|
+
expect(buttonStyle).toBeDefined();
|
|
228
|
+
expect(buttonStyle).toMatch(/position:\s*'relative'/);
|
|
229
|
+
});
|
|
230
|
+
|
|
124
231
|
it('exposes input-clear-button so a theme controls the button size and hover', () => {
|
|
125
232
|
const theme = defineTheme({
|
|
126
233
|
name: 'input-clear-button-test',
|
|
@@ -136,7 +243,7 @@ describe('InputClearButton', () => {
|
|
|
136
243
|
const css = generateThemeTestCSS(theme);
|
|
137
244
|
expect(css).toContain('.astryx-input-clear-button {');
|
|
138
245
|
expect(css).toContain('height: 28px');
|
|
139
|
-
expect(css).toContain('.astryx-input-clear-button:hover
|
|
246
|
+
expect(css).toContain('.astryx-input-clear-button:hover');
|
|
140
247
|
expect(css).toContain('background-image: none');
|
|
141
248
|
});
|
|
142
249
|
});
|
|
@@ -25,6 +25,44 @@ const styles = stylex.create({
|
|
|
25
25
|
button: {
|
|
26
26
|
height: '20px',
|
|
27
27
|
flexShrink: 0,
|
|
28
|
+
// Containing block for the ::after hit overlay below. Button sets its own
|
|
29
|
+
// `position: relative`, so the overlay would resolve correctly without
|
|
30
|
+
// this — but that is another component's internal, and if it ever changes
|
|
31
|
+
// the overlay silently reattaches to some ancestor and the hit area lands
|
|
32
|
+
// in the wrong place. Declaring it here keeps the containing block
|
|
33
|
+
// colocated with the thing that depends on it. No-op at runtime.
|
|
34
|
+
position: 'relative',
|
|
35
|
+
// Expand the tap target to 24px ONLY on touch (WCAG 2.5.8 AA is a touch
|
|
36
|
+
// requirement, and its floor is 24x24). On a fine pointer the 20px glyph
|
|
37
|
+
// is precise enough, and an unconditional overlay could overlap
|
|
38
|
+
// neighboring controls in dense layouts. The inset is 0 by default (hit
|
|
39
|
+
// area == visual glyph) and grows to -2px (=> 24x24) under a coarse
|
|
40
|
+
// pointer — no further, because at -4px the overlay reaches into the 8px
|
|
41
|
+
// adornment gap and, on the inline-start side, over the input's own caret
|
|
42
|
+
// area. Driven through a custom property because StyleX only allows plain
|
|
43
|
+
// values inside a pseudo-element; the conditional lives on this top-level
|
|
44
|
+
// property instead. Private (--_) because it is an internal implementation
|
|
45
|
+
// detail, not a themeable target.
|
|
46
|
+
'--_input-clear-hit-inset': {
|
|
47
|
+
default: '0px',
|
|
48
|
+
'@media (pointer: coarse)': '-2px',
|
|
49
|
+
},
|
|
50
|
+
// The overlay itself is gated too, not just its size. An ::after that is
|
|
51
|
+
// generated on a fine pointer sits exactly over the button at inset 0,
|
|
52
|
+
// where it adds no hit area but is the topmost hit-test box — so hover
|
|
53
|
+
// stops reaching the descendants and `.astryx-input-clear-icon:hover`, a
|
|
54
|
+
// public theme target, no longer matches. `content: none` means the
|
|
55
|
+
// pseudo-element is not generated at all, so on a fine pointer the
|
|
56
|
+
// overlay does not exist.
|
|
57
|
+
'--_input-clear-hit-content': {
|
|
58
|
+
default: 'none',
|
|
59
|
+
'@media (pointer: coarse)': '""',
|
|
60
|
+
},
|
|
61
|
+
'::after': {
|
|
62
|
+
content: 'var(--_input-clear-hit-content)',
|
|
63
|
+
position: 'absolute',
|
|
64
|
+
inset: 'var(--_input-clear-hit-inset)',
|
|
65
|
+
},
|
|
28
66
|
},
|
|
29
67
|
});
|
|
30
68
|
|
|
@@ -56,15 +56,16 @@ export const inputWrapperStyles = stylex.create({
|
|
|
56
56
|
transitionTimingFunction: easeVars['--ease-standard'],
|
|
57
57
|
boxShadow: {
|
|
58
58
|
default: 'none',
|
|
59
|
-
':hover:not(:focus-within)':
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
':hover:not(:focus-within):where(:not(:disabled,[aria-disabled="true"]))':
|
|
60
|
+
{
|
|
61
|
+
'@media (hover: hover)': `inset 0px 0px 0px 2px color-mix(in srgb, ${colorVars['--color-border-emphasized']} 30%, transparent)`,
|
|
62
|
+
},
|
|
62
63
|
':focus-within': `inset 0px 0px 0px 2px ${colorVars['--color-accent-muted']}`,
|
|
63
64
|
},
|
|
64
65
|
outline: 'none',
|
|
65
66
|
},
|
|
66
67
|
disabled: {
|
|
67
|
-
cursor: '
|
|
68
|
+
cursor: 'default',
|
|
68
69
|
opacity: 0.5,
|
|
69
70
|
borderColor: colorVars['--color-border-emphasized'],
|
|
70
71
|
// Suppress the base hover ring — a disabled control must not react to hover.
|
|
@@ -96,25 +97,28 @@ export const inputStatusHoverShadowStyles = stylex.create({
|
|
|
96
97
|
warning: {
|
|
97
98
|
boxShadow: {
|
|
98
99
|
default: 'none',
|
|
99
|
-
':hover:not(:focus-within)':
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
':hover:not(:focus-within):where(:not(:disabled,[aria-disabled="true"]))':
|
|
101
|
+
{
|
|
102
|
+
'@media (hover: hover)': shadowVars['--shadow-inset-warning'],
|
|
103
|
+
},
|
|
102
104
|
},
|
|
103
105
|
},
|
|
104
106
|
error: {
|
|
105
107
|
boxShadow: {
|
|
106
108
|
default: 'none',
|
|
107
|
-
':hover:not(:focus-within)':
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
':hover:not(:focus-within):where(:not(:disabled,[aria-disabled="true"]))':
|
|
110
|
+
{
|
|
111
|
+
'@media (hover: hover)': shadowVars['--shadow-inset-error'],
|
|
112
|
+
},
|
|
110
113
|
},
|
|
111
114
|
},
|
|
112
115
|
success: {
|
|
113
116
|
boxShadow: {
|
|
114
117
|
default: 'none',
|
|
115
|
-
':hover:not(:focus-within)':
|
|
116
|
-
|
|
117
|
-
|
|
118
|
+
':hover:not(:focus-within):where(:not(:disabled,[aria-disabled="true"]))':
|
|
119
|
+
{
|
|
120
|
+
'@media (hover: hover)': shadowVars['--shadow-inset-success'],
|
|
121
|
+
},
|
|
118
122
|
},
|
|
119
123
|
},
|
|
120
124
|
});
|