@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
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file Wheel.tsx
|
|
7
|
+
* @input Option list, selected value, change callback
|
|
8
|
+
* @output Exports Wheel — a snap-scrolling picker column
|
|
9
|
+
* @position Internal component; consumed by MonthYearWheels.tsx
|
|
10
|
+
*
|
|
11
|
+
* A wheel is a scroll container, not a custom gesture surface. Momentum,
|
|
12
|
+
* rubber-banding, and the settle animation are the platform's; all this adds
|
|
13
|
+
* is `scroll-snap-align: center` on each option, half a viewport of padding at
|
|
14
|
+
* each end so the first and last option can reach the middle, and a commit
|
|
15
|
+
* when the scrolling stops.
|
|
16
|
+
*
|
|
17
|
+
* The falloff (rows fading and tipping away from the centre) is a CSS
|
|
18
|
+
* scroll-driven animation on a `view()` timeline — the browser interpolates it
|
|
19
|
+
* against each row's own position in the scrollport, so it stays glued to the
|
|
20
|
+
* finger with no JS in the frame loop. It is guarded by `@supports`, because a
|
|
21
|
+
* browser that does not understand `animation-timeline` would otherwise run
|
|
22
|
+
* the same keyframes on the document timeline and simply play them once.
|
|
23
|
+
*
|
|
24
|
+
* Accessibility: this is a listbox, not a novel widget. It is one tab stop
|
|
25
|
+
* with arrow/Home/End/PageUp/PageDown keys, `aria-activedescendant` tracking
|
|
26
|
+
* the active row, and every row reachable by tap — none of which depends on
|
|
27
|
+
* the scroll-driven decoration.
|
|
28
|
+
*
|
|
29
|
+
* SYNC: When modified, update:
|
|
30
|
+
* - /packages/core/src/DateInput/TouchDateField.tsx
|
|
31
|
+
* - /packages/core/src/DateInput/DateInput.doc.mjs
|
|
32
|
+
* - /packages/core/src/DateInput/DateInputTouch.test.tsx
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import {useCallback, useEffect, useId, useRef, useState} from 'react';
|
|
36
|
+
import * as stylex from '@stylexjs/stylex';
|
|
37
|
+
import {
|
|
38
|
+
colorVars,
|
|
39
|
+
radiusVars,
|
|
40
|
+
fontWeightVars,
|
|
41
|
+
typeScaleVars,
|
|
42
|
+
spacingVars,
|
|
43
|
+
durationVars,
|
|
44
|
+
} from '../theme/tokens.stylex';
|
|
45
|
+
import {focusOutlineStyles} from '../utils';
|
|
46
|
+
import {dateInputTouchSizes, dateInputTouchGeometry} from './tokens.stylex';
|
|
47
|
+
import {useOwnScrollGesture} from './useOwnScrollGesture';
|
|
48
|
+
import {usePointerDragScroll} from './usePointerDragScroll';
|
|
49
|
+
import {useScrollSettle} from './useScrollSettle';
|
|
50
|
+
|
|
51
|
+
const ITEM_BLOCK_SIZE = dateInputTouchSizes.wheelItemSize;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Rows tip away from the centre of the wheel. 0% is a row just entering at the
|
|
55
|
+
* bottom of the scrollport, 50% is a row centred in it, 100% is a row leaving
|
|
56
|
+
* at the top — which is what a `view()` timeline over the `cover` range means,
|
|
57
|
+
* and why this reads as a cylinder rotating under the finger.
|
|
58
|
+
*/
|
|
59
|
+
const falloff = stylex.keyframes({
|
|
60
|
+
'0%': {
|
|
61
|
+
opacity: 0.3,
|
|
62
|
+
transform: 'rotateX(52deg) scale(0.86)',
|
|
63
|
+
},
|
|
64
|
+
'50%': {
|
|
65
|
+
opacity: 1,
|
|
66
|
+
transform: 'rotateX(0deg) scale(1)',
|
|
67
|
+
},
|
|
68
|
+
'100%': {
|
|
69
|
+
opacity: 0.3,
|
|
70
|
+
transform: 'rotateX(-52deg) scale(0.86)',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/** Motion-free equivalent: the depth cue survives as opacity alone. */
|
|
75
|
+
const fadeOnly = stylex.keyframes({
|
|
76
|
+
'0%': {opacity: 0.3},
|
|
77
|
+
'50%': {opacity: 1},
|
|
78
|
+
'100%': {opacity: 0.3},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const styles = stylex.create({
|
|
82
|
+
column: {
|
|
83
|
+
position: 'relative',
|
|
84
|
+
flex: '1 1 0',
|
|
85
|
+
minWidth: 0,
|
|
86
|
+
},
|
|
87
|
+
scroller: {
|
|
88
|
+
blockSize: dateInputTouchGeometry.paneBlockSize,
|
|
89
|
+
// Load-bearing, and stated rather than inherited from the reset (whose
|
|
90
|
+
// rule is zero-specificity `:where`): with content-box the end padding
|
|
91
|
+
// below would be added to the scrollport instead of sitting inside it,
|
|
92
|
+
// and every snap position would be wrong.
|
|
93
|
+
boxSizing: 'border-box',
|
|
94
|
+
overflowY: 'auto',
|
|
95
|
+
overflowX: 'hidden',
|
|
96
|
+
// Snap every row to the middle of the scrollport, where the selection band
|
|
97
|
+
// sits. `mandatory` (not `proximity`) because a wheel has no valid resting
|
|
98
|
+
// position between two options.
|
|
99
|
+
scrollSnapType: 'y mandatory',
|
|
100
|
+
overscrollBehavior: 'contain',
|
|
101
|
+
// Room for row 0 and row n-1 to reach the centre.
|
|
102
|
+
paddingBlock: dateInputTouchGeometry.wheelEdgePadding,
|
|
103
|
+
// Gives the rotateX falloff somewhere to recede to.
|
|
104
|
+
perspective: '520px',
|
|
105
|
+
transformStyle: 'preserve-3d',
|
|
106
|
+
scrollbarWidth: 'none',
|
|
107
|
+
outline: 'none',
|
|
108
|
+
touchAction: 'pan-y',
|
|
109
|
+
},
|
|
110
|
+
item: {
|
|
111
|
+
display: 'flex',
|
|
112
|
+
alignItems: 'center',
|
|
113
|
+
justifyContent: 'center',
|
|
114
|
+
blockSize: ITEM_BLOCK_SIZE,
|
|
115
|
+
paddingInline: spacingVars['--spacing-2'],
|
|
116
|
+
scrollSnapAlign: 'center',
|
|
117
|
+
borderWidth: 0,
|
|
118
|
+
borderStyle: 'none',
|
|
119
|
+
backgroundColor: 'transparent',
|
|
120
|
+
// Larger than body text, and larger than the calendar's day numbers: on
|
|
121
|
+
// a wheel the value under the band is the whole interface, and the rows
|
|
122
|
+
// above and below are read at a glance while moving.
|
|
123
|
+
fontSize: typeScaleVars['--text-large-size'],
|
|
124
|
+
fontWeight: fontWeightVars['--font-weight-normal'],
|
|
125
|
+
color: colorVars['--color-text-primary'],
|
|
126
|
+
whiteSpace: 'nowrap',
|
|
127
|
+
// NO `overflow: hidden` here. It would make the row itself a scroll
|
|
128
|
+
// container, and `view()` binds to the subject's nearest ancestor scroll
|
|
129
|
+
// container — the falloff would measure the row against itself and sit
|
|
130
|
+
// frozen at 50% forever. Clipping belongs on the inner element.
|
|
131
|
+
cursor: {
|
|
132
|
+
default: 'pointer',
|
|
133
|
+
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
134
|
+
},
|
|
135
|
+
userSelect: 'none',
|
|
136
|
+
transitionProperty: 'color, font-weight',
|
|
137
|
+
transitionDuration: durationVars['--duration-fast'],
|
|
138
|
+
},
|
|
139
|
+
/**
|
|
140
|
+
* The falloff rides an inner element, never the row itself.
|
|
141
|
+
*
|
|
142
|
+
* A snap area is the element's TRANSFORMED border box, so animating the row
|
|
143
|
+
* would move the very positions the scroller is snapping to — the wheel
|
|
144
|
+
* settles a few pixels off, and the offset feeds back into the animation.
|
|
145
|
+
* Transforming a child leaves the row's box, and every snap offset, exact.
|
|
146
|
+
*/
|
|
147
|
+
itemInner: {
|
|
148
|
+
display: 'flex',
|
|
149
|
+
alignItems: 'center',
|
|
150
|
+
justifyContent: 'center',
|
|
151
|
+
inlineSize: '100%',
|
|
152
|
+
blockSize: '100%',
|
|
153
|
+
overflow: 'hidden',
|
|
154
|
+
textOverflow: 'ellipsis',
|
|
155
|
+
// The wheel look. Held behind @supports so browsers without scroll-driven
|
|
156
|
+
// animations get a plain, fully legible list instead of these keyframes
|
|
157
|
+
// playing themselves out once on the document timeline. Under reduced
|
|
158
|
+
// motion the same timeline drives opacity only — the depth cue survives,
|
|
159
|
+
// the tipping does not.
|
|
160
|
+
animationName: {
|
|
161
|
+
default: null,
|
|
162
|
+
'@supports (animation-timeline: view())': {
|
|
163
|
+
default: falloff,
|
|
164
|
+
'@media (prefers-reduced-motion: reduce)': fadeOnly,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
animationTimeline: 'view(y)',
|
|
168
|
+
animationRange: 'cover 0% cover 100%',
|
|
169
|
+
animationFillMode: 'both',
|
|
170
|
+
animationDuration: 'auto',
|
|
171
|
+
animationTimingFunction: 'linear',
|
|
172
|
+
backfaceVisibility: 'hidden',
|
|
173
|
+
},
|
|
174
|
+
itemActive: {
|
|
175
|
+
color: colorVars['--color-text-accent'],
|
|
176
|
+
fontWeight: fontWeightVars['--font-weight-semibold'],
|
|
177
|
+
},
|
|
178
|
+
itemDisabled: {
|
|
179
|
+
color: colorVars['--color-text-disabled'],
|
|
180
|
+
cursor: 'default',
|
|
181
|
+
},
|
|
182
|
+
/**
|
|
183
|
+
* The selection band: a single centred row-height plate behind the options.
|
|
184
|
+
* Purely decorative — the committed value is announced by `aria-selected`.
|
|
185
|
+
*/
|
|
186
|
+
band: {
|
|
187
|
+
position: 'absolute',
|
|
188
|
+
insetInline: 0,
|
|
189
|
+
insetBlockStart: `calc(50% - (${ITEM_BLOCK_SIZE} / 2))`,
|
|
190
|
+
blockSize: ITEM_BLOCK_SIZE,
|
|
191
|
+
borderRadius: radiusVars['--radius-element'],
|
|
192
|
+
// `--color-neutral`, not `--color-background-muted`. Muted is 4.7% alpha,
|
|
193
|
+
// which puts the whole plate 17 units of colour away from the sheet
|
|
194
|
+
// behind it — so when the wheels fade in, the band's animation has 17
|
|
195
|
+
// units to happen in while the text beside it travels 412. It did not
|
|
196
|
+
// read as fading, it read as appearing. Neutral is 10%, which doubles the
|
|
197
|
+
// range to 36 and is still quiet enough to sit under text.
|
|
198
|
+
backgroundColor: colorVars['--color-neutral'],
|
|
199
|
+
pointerEvents: 'none',
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
export interface WheelOption {
|
|
204
|
+
/** Stable numeric identity of the row (a month 1-12, or a year). */
|
|
205
|
+
value: number;
|
|
206
|
+
/** Row text. */
|
|
207
|
+
label: string;
|
|
208
|
+
/** Rows outside min/max stay visible but cannot be committed. */
|
|
209
|
+
isDisabled?: boolean;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export interface WheelProps {
|
|
213
|
+
/** Accessible name for the column, e.g. "Month". */
|
|
214
|
+
label: string;
|
|
215
|
+
/** Rows, top to bottom. */
|
|
216
|
+
options: ReadonlyArray<WheelOption>;
|
|
217
|
+
/** Committed value; must match one option's `value`. */
|
|
218
|
+
value: number;
|
|
219
|
+
/** Fired when the wheel comes to rest on a different, enabled row. */
|
|
220
|
+
onChange: (value: number) => void;
|
|
221
|
+
/**
|
|
222
|
+
* False while the wheel is hidden — scroll offsets of a display:none
|
|
223
|
+
* scroller are meaningless, so listeners and the initial scroll wait.
|
|
224
|
+
*/
|
|
225
|
+
isActive?: boolean;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* One snap-scrolling picker column.
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```
|
|
233
|
+
* <Wheel
|
|
234
|
+
* label="Month"
|
|
235
|
+
* options={monthOptions}
|
|
236
|
+
* value={month}
|
|
237
|
+
* onChange={setMonth}
|
|
238
|
+
* />
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
export function Wheel({
|
|
242
|
+
label,
|
|
243
|
+
options,
|
|
244
|
+
value,
|
|
245
|
+
onChange,
|
|
246
|
+
isActive = true,
|
|
247
|
+
}: WheelProps) {
|
|
248
|
+
const id = useId();
|
|
249
|
+
const scrollerRef = useRef<HTMLDivElement | null>(null);
|
|
250
|
+
const selectedIndex = Math.max(
|
|
251
|
+
0,
|
|
252
|
+
options.findIndex(option => option.value === value),
|
|
253
|
+
);
|
|
254
|
+
// Which row is under the band right now. Tracks the finger during a scroll;
|
|
255
|
+
// `selectedIndex` only catches up when the wheel settles.
|
|
256
|
+
const [activeIndex, setActiveIndex] = useState(selectedIndex);
|
|
257
|
+
|
|
258
|
+
// Row height in px, read from layout rather than assumed, so a theme that
|
|
259
|
+
// retunes --date-input-touch-wheel-item-size still lands on the right row.
|
|
260
|
+
const itemBlockSize = useCallback((): number => {
|
|
261
|
+
const first = scrollerRef.current?.firstElementChild;
|
|
262
|
+
return first instanceof HTMLElement && first.offsetHeight > 0
|
|
263
|
+
? first.offsetHeight
|
|
264
|
+
: 0;
|
|
265
|
+
}, []);
|
|
266
|
+
|
|
267
|
+
const scrollToIndex = useCallback(
|
|
268
|
+
(index: number, behavior: ScrollBehavior) => {
|
|
269
|
+
const scroller = scrollerRef.current;
|
|
270
|
+
const size = itemBlockSize();
|
|
271
|
+
if (scroller == null || size === 0) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
scroller.scrollTo({top: index * size, behavior});
|
|
275
|
+
},
|
|
276
|
+
[itemBlockSize],
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
// Commit on rest. A disabled row is bounced back to the committed one
|
|
280
|
+
// rather than silently keeping a value the wheel is not showing.
|
|
281
|
+
//
|
|
282
|
+
// Declared here, above the park effect, because that effect consults the
|
|
283
|
+
// `isAtRestRef` this returns before it repositions anything.
|
|
284
|
+
const {isAtRestRef} = useScrollSettle(
|
|
285
|
+
scrollerRef,
|
|
286
|
+
scroller => {
|
|
287
|
+
const size = itemBlockSize();
|
|
288
|
+
if (size === 0) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const index = Math.min(
|
|
292
|
+
options.length - 1,
|
|
293
|
+
Math.max(0, Math.round(scroller.scrollTop / size)),
|
|
294
|
+
);
|
|
295
|
+
const option = options[index];
|
|
296
|
+
if (option == null || option.isDisabled) {
|
|
297
|
+
scrollToIndex(selectedIndex, 'smooth');
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (option.value !== value) {
|
|
301
|
+
onChange(option.value);
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
isActive,
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
// Park the committed row under the band whenever the wheel is shown, or the
|
|
308
|
+
// value is changed from outside (the calendar scrolled to another month).
|
|
309
|
+
//
|
|
310
|
+
// NEVER while the wheel is still moving. A scroller that is mid-gesture or
|
|
311
|
+
// still carrying momentum is the user's, and repositioning it does not stop
|
|
312
|
+
// the momentum — on iOS it feeds a cycle where the scroll this causes reads
|
|
313
|
+
// as a new settle, commits the next row along, and parks again. See
|
|
314
|
+
// useScrollSettle. The settle handler re-checks the position afterwards, so
|
|
315
|
+
// a correction that is genuinely needed still happens, just at rest.
|
|
316
|
+
useEffect(() => {
|
|
317
|
+
if (!isActive || !isAtRestRef.current) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const size = itemBlockSize();
|
|
321
|
+
const scroller = scrollerRef.current;
|
|
322
|
+
if (scroller == null || size === 0) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
if (Math.round(scroller.scrollTop / size) !== selectedIndex) {
|
|
326
|
+
scroller.scrollTo({top: selectedIndex * size, behavior: 'auto'});
|
|
327
|
+
}
|
|
328
|
+
// eslint-disable-next-line @eslint-react/set-state-in-effect -- the highlight follows a scroll position, which only exists after layout
|
|
329
|
+
setActiveIndex(selectedIndex);
|
|
330
|
+
}, [isActive, selectedIndex, itemBlockSize, isAtRestRef]);
|
|
331
|
+
|
|
332
|
+
// Highlight follows the finger. rAF-throttled: a scroll can fire far more
|
|
333
|
+
// often than the display refreshes, and this only feeds a repaint.
|
|
334
|
+
const frameRef = useRef<number | undefined>(undefined);
|
|
335
|
+
useEffect(() => {
|
|
336
|
+
const scroller = scrollerRef.current;
|
|
337
|
+
if (scroller == null || !isActive) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const onScroll = () => {
|
|
341
|
+
if (frameRef.current != null) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
frameRef.current = requestAnimationFrame(() => {
|
|
345
|
+
frameRef.current = undefined;
|
|
346
|
+
const size = itemBlockSize();
|
|
347
|
+
if (size === 0) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const index = Math.min(
|
|
351
|
+
options.length - 1,
|
|
352
|
+
Math.max(0, Math.round(scroller.scrollTop / size)),
|
|
353
|
+
);
|
|
354
|
+
setActiveIndex(index);
|
|
355
|
+
});
|
|
356
|
+
};
|
|
357
|
+
scroller.addEventListener('scroll', onScroll, {passive: true});
|
|
358
|
+
return () => {
|
|
359
|
+
scroller.removeEventListener('scroll', onScroll);
|
|
360
|
+
if (frameRef.current != null) {
|
|
361
|
+
cancelAnimationFrame(frameRef.current);
|
|
362
|
+
frameRef.current = undefined;
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
}, [isActive, options.length, itemBlockSize]);
|
|
366
|
+
|
|
367
|
+
// Keep the finger. Inside a BottomSheet the sheet would otherwise read a
|
|
368
|
+
// downward drag here as swipe-to-dismiss; see useOwnScrollGesture. Gated on
|
|
369
|
+
// isActive because the hidden panel keeps its layout box.
|
|
370
|
+
// 'all': a wheel scrolls vertically, the same axis the sheet wants, so
|
|
371
|
+
// there is no way to share — it takes every touch that lands on it.
|
|
372
|
+
useOwnScrollGesture(scrollerRef, 'all', {isEnabled: isActive});
|
|
373
|
+
|
|
374
|
+
// A mouse cannot drag a scroll container, so without this the wheel ignores
|
|
375
|
+
// the one gesture its shape invites. Touch is untouched — it pans natively,
|
|
376
|
+
// with momentum this could not match. See usePointerDragScroll.
|
|
377
|
+
usePointerDragScroll(scrollerRef, isActive);
|
|
378
|
+
|
|
379
|
+
const moveBy = useCallback(
|
|
380
|
+
(delta: number) => {
|
|
381
|
+
const next = Math.min(
|
|
382
|
+
options.length - 1,
|
|
383
|
+
Math.max(0, activeIndex + delta),
|
|
384
|
+
);
|
|
385
|
+
const option = options[next];
|
|
386
|
+
if (option == null || option.isDisabled) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
setActiveIndex(next);
|
|
390
|
+
scrollToIndex(next, 'smooth');
|
|
391
|
+
if (option.value !== value) {
|
|
392
|
+
onChange(option.value);
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
[activeIndex, options, scrollToIndex, value, onChange],
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
const handleKeyDown = useCallback(
|
|
399
|
+
(event: React.KeyboardEvent) => {
|
|
400
|
+
switch (event.key) {
|
|
401
|
+
case 'ArrowDown':
|
|
402
|
+
event.preventDefault();
|
|
403
|
+
moveBy(1);
|
|
404
|
+
break;
|
|
405
|
+
case 'ArrowUp':
|
|
406
|
+
event.preventDefault();
|
|
407
|
+
moveBy(-1);
|
|
408
|
+
break;
|
|
409
|
+
case 'PageDown':
|
|
410
|
+
event.preventDefault();
|
|
411
|
+
moveBy(10);
|
|
412
|
+
break;
|
|
413
|
+
case 'PageUp':
|
|
414
|
+
event.preventDefault();
|
|
415
|
+
moveBy(-10);
|
|
416
|
+
break;
|
|
417
|
+
case 'Home':
|
|
418
|
+
event.preventDefault();
|
|
419
|
+
moveBy(-activeIndex);
|
|
420
|
+
break;
|
|
421
|
+
case 'End':
|
|
422
|
+
event.preventDefault();
|
|
423
|
+
moveBy(options.length - 1 - activeIndex);
|
|
424
|
+
break;
|
|
425
|
+
default:
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
[moveBy, activeIndex, options.length],
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
return (
|
|
433
|
+
<div {...stylex.props(styles.column)}>
|
|
434
|
+
<div aria-hidden="true" {...stylex.props(styles.band)} />
|
|
435
|
+
<div
|
|
436
|
+
ref={scrollerRef}
|
|
437
|
+
role="listbox"
|
|
438
|
+
aria-label={label}
|
|
439
|
+
aria-activedescendant={`${id}-${options[activeIndex]?.value}`}
|
|
440
|
+
tabIndex={0}
|
|
441
|
+
onKeyDown={handleKeyDown}
|
|
442
|
+
{...stylex.props(styles.scroller, focusOutlineStyles.focusVisible)}>
|
|
443
|
+
{options.map((option, index) => (
|
|
444
|
+
<div
|
|
445
|
+
key={option.value}
|
|
446
|
+
id={`${id}-${option.value}`}
|
|
447
|
+
role="option"
|
|
448
|
+
aria-selected={option.value === value}
|
|
449
|
+
aria-disabled={option.isDisabled || undefined}
|
|
450
|
+
onClick={() => {
|
|
451
|
+
if (option.isDisabled) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
setActiveIndex(index);
|
|
455
|
+
scrollToIndex(index, 'smooth');
|
|
456
|
+
if (option.value !== value) {
|
|
457
|
+
onChange(option.value);
|
|
458
|
+
}
|
|
459
|
+
}}
|
|
460
|
+
{...stylex.props(
|
|
461
|
+
styles.item,
|
|
462
|
+
index === activeIndex && styles.itemActive,
|
|
463
|
+
option.isDisabled && styles.itemDisabled,
|
|
464
|
+
)}>
|
|
465
|
+
<span {...stylex.props(styles.itemInner)}>{option.label}</span>
|
|
466
|
+
</div>
|
|
467
|
+
))}
|
|
468
|
+
</div>
|
|
469
|
+
</div>
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
Wheel.displayName = 'Wheel';
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file monthGeometry.ts
|
|
5
|
+
* @input PlainDate values, scroll offsets, pane heights
|
|
6
|
+
* @output Pure month-index arithmetic and the virtualized pane window
|
|
7
|
+
* @position Internal helper; consumed by MonthScroller.tsx and DateInput.tsx
|
|
8
|
+
*
|
|
9
|
+
* A "month index" is a single integer that totally orders calendar months:
|
|
10
|
+
* `year * 12 + (month - 1)`. The scroller is a list of equal-width panes, so
|
|
11
|
+
* one integer converts freely between a month, a row in that list, and a
|
|
12
|
+
* scroll offset — which is the whole trick behind continuous scrolling.
|
|
13
|
+
*
|
|
14
|
+
* These are pure functions on purpose: the scroll math is the part most likely
|
|
15
|
+
* to be wrong, and it is testable without a layout engine.
|
|
16
|
+
*
|
|
17
|
+
* SYNC: When modified, update DateInputTouch.test.tsx.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type {PlainDate} from '../utils';
|
|
21
|
+
|
|
22
|
+
/** How many months are reachable in either direction when unbounded. */
|
|
23
|
+
export const DEFAULT_MONTH_REACH = 600;
|
|
24
|
+
|
|
25
|
+
/** `year * 12 + (month - 1)`, for a 1-based month. */
|
|
26
|
+
export function toMonthIndex(year: number, month: number): number {
|
|
27
|
+
return year * 12 + (month - 1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** The month index of a PlainDate. */
|
|
31
|
+
export function monthIndexOf(date: PlainDate): number {
|
|
32
|
+
return toMonthIndex(date.year, date.month);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Inverse of {@link toMonthIndex}; month comes back 1-based. */
|
|
36
|
+
export function fromMonthIndex(index: number): {year: number; month: number} {
|
|
37
|
+
return {
|
|
38
|
+
year: Math.floor(index / 12),
|
|
39
|
+
month: (((index % 12) + 12) % 12) + 1,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** `value` limited to `[min, max]`. */
|
|
44
|
+
export function clampIndex(value: number, min: number, max: number): number {
|
|
45
|
+
return Math.min(Math.max(value, min), max);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The month a scrollport is resting on (or nearest to, mid-scroll).
|
|
50
|
+
*
|
|
51
|
+
* Returns a row offset from the start of the list, not a month index — add
|
|
52
|
+
* `minMonthIndex` for that.
|
|
53
|
+
*
|
|
54
|
+
* `scrollOffset` is `scrollLeft` for the horizontal scroller. Under RTL that
|
|
55
|
+
* is NEGATIVE — the spec has the inline start at 0 and scrolling run down
|
|
56
|
+
* from there — so the sign is normalized away here rather than at each call
|
|
57
|
+
* site, where forgetting it would silently pin the calendar to month zero.
|
|
58
|
+
*/
|
|
59
|
+
export function rowAtScrollOffset(
|
|
60
|
+
scrollOffset: number,
|
|
61
|
+
paneSize: number,
|
|
62
|
+
rowCount: number,
|
|
63
|
+
isRTL: boolean = false,
|
|
64
|
+
): number {
|
|
65
|
+
if (paneSize <= 0) {
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
const distance = isRTL ? -scrollOffset : scrollOffset;
|
|
69
|
+
return clampIndex(Math.round(distance / paneSize), 0, rowCount - 1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The scroll offset that brings `row` to rest, ready for `scrollTo`. The
|
|
74
|
+
* inverse of {@link rowAtScrollOffset}, including its RTL sign.
|
|
75
|
+
*/
|
|
76
|
+
export function scrollOffsetForRow(
|
|
77
|
+
row: number,
|
|
78
|
+
paneSize: number,
|
|
79
|
+
isRTL: boolean = false,
|
|
80
|
+
): number {
|
|
81
|
+
const distance = row * paneSize;
|
|
82
|
+
return isRTL ? -distance : distance;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface PaneWindow {
|
|
86
|
+
/** First rendered row, inclusive. */
|
|
87
|
+
start: number;
|
|
88
|
+
/** Last rendered row, inclusive. */
|
|
89
|
+
end: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The slice of rows to actually mount around `centerRow`.
|
|
94
|
+
*
|
|
95
|
+
* Only a handful of panes exist in the DOM at a time; the rest of the list is
|
|
96
|
+
* a spacer. `overscan` is how many extra panes ride along on each side so a
|
|
97
|
+
* fast fling never lands on an unmounted one — which under `scroll-snap-type:
|
|
98
|
+
* mandatory` would be visible as a jump.
|
|
99
|
+
*/
|
|
100
|
+
export function paneWindow(
|
|
101
|
+
centerRow: number,
|
|
102
|
+
rowCount: number,
|
|
103
|
+
overscan: number,
|
|
104
|
+
): PaneWindow {
|
|
105
|
+
return {
|
|
106
|
+
start: Math.max(0, centerRow - overscan),
|
|
107
|
+
end: Math.min(rowCount - 1, centerRow + overscan),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** `[start, end]` inclusive, as an array of rows. */
|
|
112
|
+
export function rowsIn({start, end}: PaneWindow): number[] {
|
|
113
|
+
const rows: number[] = [];
|
|
114
|
+
for (let row = start; row <= end; row++) {
|
|
115
|
+
rows.push(row);
|
|
116
|
+
}
|
|
117
|
+
return rows;
|
|
118
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file tokens.stylex.ts
|
|
5
|
+
* @input StyleX variable and constant definitions
|
|
6
|
+
* @output Exports DateInput layout constants and derived geometry
|
|
7
|
+
* @position Lab component tokens consumed by DateInput.tsx, MonthScroller.tsx, Wheel.tsx, MonthYearWheels.tsx
|
|
8
|
+
*
|
|
9
|
+
* The picker's whole geometry derives from two numbers, which is what makes
|
|
10
|
+
* the fixed height and the scroll snapping exact:
|
|
11
|
+
*
|
|
12
|
+
* pane height = weeks x day size (one month, always 6 rows)
|
|
13
|
+
* body height = pane height (calendar body AND wheel body)
|
|
14
|
+
* wheel pad = (body height - item) / 2 (so row 0 can rest centered)
|
|
15
|
+
*
|
|
16
|
+
* Every month pane is the same height as the scrollport, so `scroll-snap-align:
|
|
17
|
+
* start` produces a paged scroller with no partial rest positions, and the
|
|
18
|
+
* wheel overlay swaps in without the component changing size.
|
|
19
|
+
*
|
|
20
|
+
* The derived values are `defineConsts`, not plain exported strings: StyleX
|
|
21
|
+
* inlines a constant at build time only through `defineVars`/`defineConsts`
|
|
22
|
+
* from a `.stylex.ts` file. A plain `export const` fails the build with
|
|
23
|
+
* "a style value can only contain an array, string or number".
|
|
24
|
+
*
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import * as stylex from '@stylexjs/stylex';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Week rows per month pane. Fixed at 6 — the most any month needs — so every
|
|
31
|
+
* pane is identical in height and no snap offset ever shifts. Not a themeable
|
|
32
|
+
* variable: it is a fact about the Gregorian calendar, and `repeat()` cannot
|
|
33
|
+
* take a custom property as its count.
|
|
34
|
+
*/
|
|
35
|
+
export const WEEKS_PER_PANE = 6;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The picker's two size inputs.
|
|
39
|
+
*
|
|
40
|
+
* `defineConsts`, not `defineVars`: these are inlined at build time and emit
|
|
41
|
+
* no CSS custom property, so they are internal geometry rather than public
|
|
42
|
+
* theming API. That is deliberate for both of them.
|
|
43
|
+
*
|
|
44
|
+
* The day size is an accessibility floor — 44px is the comfortable minimum
|
|
45
|
+
* tap target on iOS and Android, and every other target in the sheet is held
|
|
46
|
+
* to it. Exposing it as a variable would let a theme quietly lower the floor,
|
|
47
|
+
* which is not a knob a design system should hand out.
|
|
48
|
+
*
|
|
49
|
+
* The wheel row height is only meaningful against the day size (see below),
|
|
50
|
+
* so tuning one without the other produces a picker whose panes no longer
|
|
51
|
+
* agree — a variable that is only safe to change in lockstep with another is
|
|
52
|
+
* not really a variable.
|
|
53
|
+
*
|
|
54
|
+
* If a real need to theme either appears, promoting a const to a var is an
|
|
55
|
+
* additive change; removing a var that consumers have started setting is not.
|
|
56
|
+
*/
|
|
57
|
+
export const dateInputTouchSizes = stylex.defineConsts({
|
|
58
|
+
/**
|
|
59
|
+
* Height of one day row, and the minimum touch target of a day. 44px is the
|
|
60
|
+
* comfortable minimum tap target on both iOS and Android.
|
|
61
|
+
*/
|
|
62
|
+
daySize: '44px',
|
|
63
|
+
/**
|
|
64
|
+
* Height of one wheel option row, and so the spacing between options and
|
|
65
|
+
* the height of the selection band.
|
|
66
|
+
*
|
|
67
|
+
* 28px against a day's 44px: a wheel row is scroll-first — a value is
|
|
68
|
+
* chosen by bringing it under the band, and tapping one is a shortcut
|
|
69
|
+
* rather than the mechanism — so it does not carry a day cell's tap-target
|
|
70
|
+
* duty, and a mis-tap costs nothing, because the neighbouring rows are the
|
|
71
|
+
* same control and the result is visible immediately.
|
|
72
|
+
*
|
|
73
|
+
* The row is deliberately close to the text it holds (17px), the way a
|
|
74
|
+
* platform picker packs them: the list should read as one continuous
|
|
75
|
+
* column of values, not as a stack of buttons with air between them. At
|
|
76
|
+
* this height ~9 options are on screen.
|
|
77
|
+
*/
|
|
78
|
+
wheelItemSize: '28px',
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Local aliases for the derived values below. StyleX resolves a `defineConsts`
|
|
82
|
+
// member through an import, so consumers read `dateInputTouchSizes.*` directly
|
|
83
|
+
// rather than a re-exported plain const, which its static analysis cannot
|
|
84
|
+
// follow across files.
|
|
85
|
+
const DAY_SIZE = dateInputTouchSizes.daySize;
|
|
86
|
+
const WHEEL_ITEM_SIZE = dateInputTouchSizes.wheelItemSize;
|
|
87
|
+
|
|
88
|
+
/** Geometry derived from the sizes above, shared across the component. */
|
|
89
|
+
export const dateInputTouchGeometry = stylex.defineConsts({
|
|
90
|
+
/** One month pane — and therefore the scrollport, and the wheel body. */
|
|
91
|
+
paneBlockSize: `calc(${WEEKS_PER_PANE} * ${DAY_SIZE})`,
|
|
92
|
+
/** The six equal week rows inside a pane. */
|
|
93
|
+
paneRows: `repeat(${WEEKS_PER_PANE}, 1fr)`,
|
|
94
|
+
/**
|
|
95
|
+
* Padding above the first and below the last wheel option, so either end
|
|
96
|
+
* can come to rest under the centered selection band.
|
|
97
|
+
*/
|
|
98
|
+
wheelEdgePadding: `calc((${WEEKS_PER_PANE} * ${DAY_SIZE} - ${WHEEL_ITEM_SIZE}) / 2)`,
|
|
99
|
+
});
|