@zerodep-dev/vue-tsx-pro-ui 0.3.1 → 0.3.2
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/dist/base/Blockquote.d.ts +1 -1
- package/dist/base/Blockquote.js +1 -1
- package/dist/base/Blockquote.js.map +1 -1
- package/dist/base/ButtonGroup.d.ts +1 -1
- package/dist/base/ButtonGroup.js +1 -1
- package/dist/base/ButtonGroup.js.map +1 -1
- package/dist/base/Code.d.ts +1 -1
- package/dist/base/Code.js +1 -1
- package/dist/base/Code.js.map +1 -1
- package/dist/base/CodeBlock.d.ts +1 -1
- package/dist/base/CodeBlock.js +1 -1
- package/dist/base/CodeBlock.js.map +1 -1
- package/dist/base/CopyButton.d.ts +1 -1
- package/dist/base/CopyButton.js +1 -1
- package/dist/base/CopyButton.js.map +1 -1
- package/dist/base/Heading.d.ts +1 -1
- package/dist/base/Heading.js +1 -1
- package/dist/base/Heading.js.map +1 -1
- package/dist/base/Icon.d.ts +1 -1
- package/dist/base/Icon.js +1 -1
- package/dist/base/Icon.js.map +1 -1
- package/dist/base/Indicator.d.ts +1 -1
- package/dist/base/Indicator.js +1 -1
- package/dist/base/Indicator.js.map +1 -1
- package/dist/base/Kbd.d.ts +1 -1
- package/dist/base/Kbd.js +1 -1
- package/dist/base/Kbd.js.map +1 -1
- package/dist/base/Link.d.ts +1 -1
- package/dist/base/Link.js +1 -1
- package/dist/base/Link.js.map +1 -1
- package/dist/base/List.d.ts +1 -1
- package/dist/base/List.js +1 -1
- package/dist/base/List.js.map +1 -1
- package/dist/base/Mark.d.ts +1 -1
- package/dist/base/Mark.js +1 -1
- package/dist/base/Mark.js.map +1 -1
- package/dist/base/Spinner.d.ts +1 -1
- package/dist/base/Spinner.js +1 -1
- package/dist/base/Spinner.js.map +1 -1
- package/dist/base/StatusDot.d.ts +1 -1
- package/dist/base/StatusDot.js +1 -1
- package/dist/base/StatusDot.js.map +1 -1
- package/dist/base/Tag.d.ts +1 -1
- package/dist/base/Tag.js +1 -1
- package/dist/base/Tag.js.map +1 -1
- package/dist/base/Text.d.ts +1 -1
- package/dist/base/Text.js +1 -1
- package/dist/base/Text.js.map +1 -1
- package/dist/base/VisuallyHidden.d.ts +1 -1
- package/dist/base/VisuallyHidden.js +1 -1
- package/dist/base/VisuallyHidden.js.map +1 -1
- package/dist/base/badge-styles.d.ts +1 -1
- package/dist/base/badge-styles.js +1 -1
- package/dist/base/badge-styles.js.map +1 -1
- package/dist/base/button-core.d.ts +1 -1
- package/dist/base/button-core.js +1 -1
- package/dist/base/button-core.js.map +1 -1
- package/dist/charts/ChordChart.d.ts +1 -1
- package/dist/charts/ChordChart.js +1 -1
- package/dist/charts/ChordChart.js.map +1 -1
- package/dist/charts/DonutChart.d.ts +1 -1
- package/dist/charts/DonutChart.js +1 -1
- package/dist/charts/DonutChart.js.map +1 -1
- package/dist/charts/FunnelChart.d.ts +1 -1
- package/dist/charts/FunnelChart.js +1 -1
- package/dist/charts/FunnelChart.js.map +1 -1
- package/dist/charts/GraphChart.d.ts +1 -1
- package/dist/charts/GraphChart.js +1 -1
- package/dist/charts/GraphChart.js.map +1 -1
- package/dist/charts/MapChart.d.ts +1 -1
- package/dist/charts/MapChart.js +1 -1
- package/dist/charts/MapChart.js.map +1 -1
- package/dist/charts/RadarChart.d.ts +1 -1
- package/dist/charts/RadarChart.js +1 -1
- package/dist/charts/RadarChart.js.map +1 -1
- package/dist/charts/SankeyChart.d.ts +1 -1
- package/dist/charts/SankeyChart.js +1 -1
- package/dist/charts/SankeyChart.js.map +1 -1
- package/dist/charts/TreemapChart.d.ts +1 -1
- package/dist/charts/TreemapChart.js +1 -1
- package/dist/charts/TreemapChart.js.map +1 -1
- package/dist/charts/XYChart.d.ts +1 -1
- package/dist/charts/XYChart.js +1 -1
- package/dist/charts/XYChart.js.map +1 -1
- package/dist/charts/frame.d.ts +1 -1
- package/dist/charts/frame.js +1 -1
- package/dist/charts/frame.js.map +1 -1
- package/dist/code-editor/CodeEditor.js +1 -1
- package/dist/code-editor/CodeEditor.js.map +1 -1
- package/dist/config/Provider.d.ts +1 -1
- package/dist/config/Provider.js +1 -1
- package/dist/config/Provider.js.map +1 -1
- package/dist/config/createUi.d.ts +1 -1
- package/dist/config/createUi.js +1 -1
- package/dist/config/createUi.js.map +1 -1
- package/dist/config/theme/coffee.d.ts +1 -1
- package/dist/config/theme/coffee.js +1 -1
- package/dist/config/theme/coffee.js.map +1 -1
- package/dist/config/theme/cyberpunk.d.ts +1 -1
- package/dist/config/theme/cyberpunk.js +1 -1
- package/dist/config/theme/cyberpunk.js.map +1 -1
- package/dist/config/theme/dark.d.ts +1 -1
- package/dist/config/theme/dark.js +1 -1
- package/dist/config/theme/dark.js.map +1 -1
- package/dist/config/theme/festive.d.ts +1 -1
- package/dist/config/theme/festive.js +1 -1
- package/dist/config/theme/festive.js.map +1 -1
- package/dist/config/theme/forest.d.ts +1 -1
- package/dist/config/theme/forest.js +1 -1
- package/dist/config/theme/forest.js.map +1 -1
- package/dist/config/theme/high-contrast.d.ts +1 -1
- package/dist/config/theme/high-contrast.js +1 -1
- package/dist/config/theme/high-contrast.js.map +1 -1
- package/dist/config/theme/lemon.d.ts +1 -1
- package/dist/config/theme/lemon.js +1 -1
- package/dist/config/theme/lemon.js.map +1 -1
- package/dist/config/theme/light.d.ts +1 -1
- package/dist/config/theme/light.js +1 -1
- package/dist/config/theme/light.js.map +1 -1
- package/dist/config/theme/midnight.d.ts +1 -1
- package/dist/config/theme/midnight.js +1 -1
- package/dist/config/theme/midnight.js.map +1 -1
- package/dist/config/theme/ocean.d.ts +1 -1
- package/dist/config/theme/ocean.js +1 -1
- package/dist/config/theme/ocean.js.map +1 -1
- package/dist/config/theme/paper.d.ts +1 -1
- package/dist/config/theme/paper.js +1 -1
- package/dist/config/theme/paper.js.map +1 -1
- package/dist/config/theme/sakura.d.ts +1 -1
- package/dist/config/theme/sakura.js +1 -1
- package/dist/config/theme/sakura.js.map +1 -1
- package/dist/config/theme/theme.js +1 -1
- package/dist/config/theme/theme.js.map +1 -1
- package/dist/config/theme/tokens.d.ts +1 -1
- package/dist/config/theme/tokens.js +1 -1
- package/dist/config/theme/tokens.js.map +1 -1
- package/dist/date/CalendarBoard.d.ts +1 -1
- package/dist/date/CalendarBoard.js +1 -1
- package/dist/date/CalendarBoard.js.map +1 -1
- package/dist/date/CalendarView.d.ts +1 -1
- package/dist/date/CalendarView.js +1 -1
- package/dist/date/CalendarView.js.map +1 -1
- package/dist/date/Countdown.d.ts +1 -1
- package/dist/date/Countdown.js +1 -1
- package/dist/date/Countdown.js.map +1 -1
- package/dist/date/DatePicker.d.ts +1 -1
- package/dist/date/DatePicker.js +1 -1
- package/dist/date/DatePicker.js.map +1 -1
- package/dist/date/DateRangePicker.d.ts +1 -1
- package/dist/date/DateRangePicker.js +1 -1
- package/dist/date/DateRangePicker.js.map +1 -1
- package/dist/date/DateSegmentGroup.d.ts +1 -1
- package/dist/date/DateSegmentGroup.js +1 -1
- package/dist/date/DateSegmentGroup.js.map +1 -1
- package/dist/date/QuarterCalendar.js +1 -1
- package/dist/date/QuarterCalendar.js.map +1 -1
- package/dist/date/SegmentedField.d.ts +1 -1
- package/dist/date/SegmentedField.js +1 -1
- package/dist/date/SegmentedField.js.map +1 -1
- package/dist/date/TimePicker.d.ts +1 -1
- package/dist/date/TimePicker.js +1 -1
- package/dist/date/TimePicker.js.map +1 -1
- package/dist/date/picker-popover.d.ts +1 -1
- package/dist/date/picker-popover.js +1 -1
- package/dist/date/picker-popover.js.map +1 -1
- package/dist/diagram/Diagram.d.ts +1 -1
- package/dist/diagram/Diagram.js +1 -1
- package/dist/diagram/Diagram.js.map +1 -1
- package/dist/diagram/DiagramControls.d.ts +1 -1
- package/dist/diagram/DiagramControls.js +1 -1
- package/dist/diagram/DiagramControls.js.map +1 -1
- package/dist/diagram/DiagramLanes.d.ts +1 -1
- package/dist/diagram/DiagramLanes.js +1 -1
- package/dist/diagram/DiagramLanes.js.map +1 -1
- package/dist/diagram/DiagramMinimap.d.ts +1 -1
- package/dist/diagram/DiagramMinimap.js +1 -1
- package/dist/diagram/DiagramMinimap.js.map +1 -1
- package/dist/diagram/DiagramNode.d.ts +1 -1
- package/dist/diagram/DiagramNode.js +1 -1
- package/dist/diagram/DiagramNode.js.map +1 -1
- package/dist/display/Accordion.d.ts +1 -1
- package/dist/display/Accordion.js +1 -1
- package/dist/display/Accordion.js.map +1 -1
- package/dist/display/AnimatedNumber.d.ts +1 -1
- package/dist/display/AnimatedNumber.js +1 -1
- package/dist/display/AnimatedNumber.js.map +1 -1
- package/dist/display/Avatar.d.ts +1 -1
- package/dist/display/Avatar.js +1 -1
- package/dist/display/Avatar.js.map +1 -1
- package/dist/display/AvatarGroup.d.ts +1 -1
- package/dist/display/AvatarGroup.js +1 -1
- package/dist/display/AvatarGroup.js.map +1 -1
- package/dist/display/Card.d.ts +1 -1
- package/dist/display/Card.js +1 -1
- package/dist/display/Card.js.map +1 -1
- package/dist/display/Checklist.d.ts +1 -1
- package/dist/display/Checklist.js +1 -1
- package/dist/display/Checklist.js.map +1 -1
- package/dist/display/Collapse.d.ts +1 -1
- package/dist/display/Collapse.js +1 -1
- package/dist/display/Collapse.js.map +1 -1
- package/dist/display/Descriptions.d.ts +1 -1
- package/dist/display/Descriptions.js +1 -1
- package/dist/display/Descriptions.js.map +1 -1
- package/dist/display/Ellipsis.d.ts +1 -1
- package/dist/display/Ellipsis.js +1 -1
- package/dist/display/Ellipsis.js.map +1 -1
- package/dist/display/FieldCompare.d.ts +1 -1
- package/dist/display/FieldCompare.js +1 -1
- package/dist/display/FieldCompare.js.map +1 -1
- package/dist/display/Gauge.d.ts +1 -1
- package/dist/display/Gauge.js +1 -1
- package/dist/display/Gauge.js.map +1 -1
- package/dist/display/Image.d.ts +1 -1
- package/dist/display/Image.js +1 -1
- package/dist/display/Image.js.map +1 -1
- package/dist/display/ItemList.d.ts +1 -1
- package/dist/display/ItemList.js +1 -1
- package/dist/display/ItemList.js.map +1 -1
- package/dist/display/Marquee.d.ts +1 -1
- package/dist/display/Marquee.js +1 -1
- package/dist/display/Marquee.js.map +1 -1
- package/dist/display/ProportionBar.d.ts +1 -1
- package/dist/display/ProportionBar.js +1 -1
- package/dist/display/ProportionBar.js.map +1 -1
- package/dist/display/Sortable.d.ts +1 -1
- package/dist/display/Sortable.js +1 -1
- package/dist/display/Sortable.js.map +1 -1
- package/dist/display/Sparkline.d.ts +1 -1
- package/dist/display/Sparkline.js +1 -1
- package/dist/display/Sparkline.js.map +1 -1
- package/dist/display/Stat.d.ts +1 -1
- package/dist/display/Stat.js +1 -1
- package/dist/display/Stat.js.map +1 -1
- package/dist/display/Timeline.d.ts +1 -1
- package/dist/display/Timeline.js +1 -1
- package/dist/display/Timeline.js.map +1 -1
- package/dist/display/Tree.d.ts +1 -1
- package/dist/display/Tree.js +1 -1
- package/dist/display/Tree.js.map +1 -1
- package/dist/display/VirtualList.d.ts +1 -1
- package/dist/display/VirtualList.js +1 -1
- package/dist/display/VirtualList.js.map +1 -1
- package/dist/display/Watermark.d.ts +1 -1
- package/dist/display/Watermark.js +1 -1
- package/dist/display/Watermark.js.map +1 -1
- package/dist/docs-kit/CodeGroup.d.ts +1 -1
- package/dist/docs-kit/CodeGroup.js +1 -1
- package/dist/docs-kit/CodeGroup.js.map +1 -1
- package/dist/docs-kit/CodePreview.d.ts +1 -1
- package/dist/docs-kit/CodePreview.js +1 -1
- package/dist/docs-kit/CodePreview.js.map +1 -1
- package/dist/docs-kit/ColorSwatch.d.ts +1 -1
- package/dist/docs-kit/ColorSwatch.js +1 -1
- package/dist/docs-kit/ColorSwatch.js.map +1 -1
- package/dist/docs-kit/PropsTable.d.ts +1 -1
- package/dist/docs-kit/PropsTable.js +1 -1
- package/dist/docs-kit/PropsTable.js.map +1 -1
- package/dist/feedback/Alert.d.ts +1 -1
- package/dist/feedback/Alert.js +1 -1
- package/dist/feedback/Alert.js.map +1 -1
- package/dist/feedback/Banner.d.ts +1 -1
- package/dist/feedback/Banner.js +1 -1
- package/dist/feedback/Banner.js.map +1 -1
- package/dist/feedback/Empty.d.ts +1 -1
- package/dist/feedback/Empty.js +1 -1
- package/dist/feedback/Empty.js.map +1 -1
- package/dist/feedback/LoadingBar.d.ts +1 -1
- package/dist/feedback/LoadingBar.js +1 -1
- package/dist/feedback/LoadingBar.js.map +1 -1
- package/dist/feedback/LoadingOverlay.d.ts +1 -1
- package/dist/feedback/LoadingOverlay.js +1 -1
- package/dist/feedback/LoadingOverlay.js.map +1 -1
- package/dist/feedback/Progress.d.ts +1 -1
- package/dist/feedback/Progress.js +1 -1
- package/dist/feedback/Progress.js.map +1 -1
- package/dist/feedback/Result.d.ts +1 -1
- package/dist/feedback/Result.js +1 -1
- package/dist/feedback/Result.js.map +1 -1
- package/dist/feedback/Skeleton.d.ts +1 -1
- package/dist/feedback/Skeleton.js +1 -1
- package/dist/feedback/Skeleton.js.map +1 -1
- package/dist/feedback/SkeletonText.d.ts +1 -1
- package/dist/feedback/SkeletonText.js +1 -1
- package/dist/feedback/SkeletonText.js.map +1 -1
- package/dist/feedback/Toast.d.ts +1 -1
- package/dist/feedback/Toast.js +1 -1
- package/dist/feedback/Toast.js.map +1 -1
- package/dist/form/Field.d.ts +1 -1
- package/dist/form/Field.js +1 -1
- package/dist/form/Field.js.map +1 -1
- package/dist/form/FormErrorSummary.d.ts +1 -1
- package/dist/form/FormErrorSummary.js +1 -1
- package/dist/form/FormErrorSummary.js.map +1 -1
- package/dist/form/FormSection.d.ts +1 -1
- package/dist/form/FormSection.js +1 -1
- package/dist/form/FormSection.js.map +1 -1
- package/dist/form/schemas.d.ts +1 -1
- package/dist/form/schemas.js +1 -1
- package/dist/form/schemas.js.map +1 -1
- package/dist/input/Cascader.d.ts +1 -1
- package/dist/input/Cascader.js +1 -1
- package/dist/input/Cascader.js.map +1 -1
- package/dist/input/CharacterCount.d.ts +1 -1
- package/dist/input/CharacterCount.js +1 -1
- package/dist/input/CharacterCount.js.map +1 -1
- package/dist/input/Checkbox.d.ts +1 -1
- package/dist/input/Checkbox.js +1 -1
- package/dist/input/Checkbox.js.map +1 -1
- package/dist/input/ColorField.d.ts +1 -1
- package/dist/input/ColorField.js +1 -1
- package/dist/input/ColorField.js.map +1 -1
- package/dist/input/Combobox.d.ts +1 -1
- package/dist/input/Combobox.js +1 -1
- package/dist/input/Combobox.js.map +1 -1
- package/dist/input/ConditionBuilder.d.ts +1 -1
- package/dist/input/ConditionBuilder.js +1 -1
- package/dist/input/ConditionBuilder.js.map +1 -1
- package/dist/input/ControlGroup.d.ts +1 -1
- package/dist/input/ControlGroup.js +1 -1
- package/dist/input/ControlGroup.js.map +1 -1
- package/dist/input/FileDrop.d.ts +1 -1
- package/dist/input/FileDrop.js +1 -1
- package/dist/input/FileDrop.js.map +1 -1
- package/dist/input/ListPopover.d.ts +1 -1
- package/dist/input/ListPopover.js +1 -1
- package/dist/input/ListPopover.js.map +1 -1
- package/dist/input/Listbox.d.ts +1 -1
- package/dist/input/Listbox.js +1 -1
- package/dist/input/Listbox.js.map +1 -1
- package/dist/input/Mentions.d.ts +1 -1
- package/dist/input/Mentions.js +1 -1
- package/dist/input/Mentions.js.map +1 -1
- package/dist/input/NumberRangeField.d.ts +1 -1
- package/dist/input/NumberRangeField.js +1 -1
- package/dist/input/NumberRangeField.js.map +1 -1
- package/dist/input/OtpField.d.ts +1 -1
- package/dist/input/OtpField.js +1 -1
- package/dist/input/OtpField.js.map +1 -1
- package/dist/input/PeoplePicker.js +1 -1
- package/dist/input/PeoplePicker.js.map +1 -1
- package/dist/input/PeoplePickerPanel.d.ts +1 -1
- package/dist/input/PeoplePickerPanel.js +1 -1
- package/dist/input/PeoplePickerPanel.js.map +1 -1
- package/dist/input/Radio.d.ts +1 -1
- package/dist/input/Radio.js +1 -1
- package/dist/input/Radio.js.map +1 -1
- package/dist/input/Rating.d.ts +1 -1
- package/dist/input/Rating.js +1 -1
- package/dist/input/Rating.js.map +1 -1
- package/dist/input/Select.d.ts +1 -1
- package/dist/input/Select.js +1 -1
- package/dist/input/Select.js.map +1 -1
- package/dist/input/SelectedTags.d.ts +1 -1
- package/dist/input/SelectedTags.js +1 -1
- package/dist/input/SelectedTags.js.map +1 -1
- package/dist/input/Slider.d.ts +1 -1
- package/dist/input/Slider.js +1 -1
- package/dist/input/Slider.js.map +1 -1
- package/dist/input/Switch.d.ts +1 -1
- package/dist/input/Switch.js +1 -1
- package/dist/input/Switch.js.map +1 -1
- package/dist/input/TagsInput.d.ts +1 -1
- package/dist/input/TagsInput.js +1 -1
- package/dist/input/TagsInput.js.map +1 -1
- package/dist/input/Textarea.d.ts +1 -1
- package/dist/input/Textarea.js +1 -1
- package/dist/input/Textarea.js.map +1 -1
- package/dist/input/ToggleGroup.d.ts +1 -1
- package/dist/input/ToggleGroup.js +1 -1
- package/dist/input/ToggleGroup.js.map +1 -1
- package/dist/input/Transfer.d.ts +1 -1
- package/dist/input/Transfer.js +1 -1
- package/dist/input/Transfer.js.map +1 -1
- package/dist/input/TreeSelect.d.ts +1 -1
- package/dist/input/TreeSelect.js +1 -1
- package/dist/input/TreeSelect.js.map +1 -1
- package/dist/input/Upload.d.ts +1 -1
- package/dist/input/Upload.js +1 -1
- package/dist/input/Upload.js.map +1 -1
- package/dist/input/choice-styles.d.ts +1 -1
- package/dist/input/choice-styles.js +1 -1
- package/dist/input/choice-styles.js.map +1 -1
- package/dist/input/control.d.ts +1 -1
- package/dist/input/control.js +1 -1
- package/dist/input/control.js.map +1 -1
- package/dist/layout/Affix.d.ts +1 -1
- package/dist/layout/Affix.js +1 -1
- package/dist/layout/Affix.js.map +1 -1
- package/dist/layout/AsideLayout.d.ts +1 -1
- package/dist/layout/AsideLayout.js +1 -1
- package/dist/layout/AsideLayout.js.map +1 -1
- package/dist/layout/BackTop.d.ts +1 -1
- package/dist/layout/BackTop.js +1 -1
- package/dist/layout/BackTop.js.map +1 -1
- package/dist/layout/Container.d.ts +1 -1
- package/dist/layout/Container.js +1 -1
- package/dist/layout/Container.js.map +1 -1
- package/dist/layout/Flex.d.ts +1 -1
- package/dist/layout/Flex.js +1 -1
- package/dist/layout/Flex.js.map +1 -1
- package/dist/layout/Grid.d.ts +1 -1
- package/dist/layout/Grid.js +1 -1
- package/dist/layout/Grid.js.map +1 -1
- package/dist/layout/PageScrollbar.d.ts +1 -1
- package/dist/layout/PageScrollbar.js +1 -1
- package/dist/layout/PageScrollbar.js.map +1 -1
- package/dist/layout/Prose.d.ts +1 -1
- package/dist/layout/Prose.js +1 -1
- package/dist/layout/Prose.js.map +1 -1
- package/dist/layout/ResizeHandle.d.ts +1 -1
- package/dist/layout/ResizeHandle.js +1 -1
- package/dist/layout/ResizeHandle.js.map +1 -1
- package/dist/layout/ScrollArea.d.ts +1 -1
- package/dist/layout/ScrollArea.js +1 -1
- package/dist/layout/ScrollArea.js.map +1 -1
- package/dist/layout/Separator.d.ts +1 -1
- package/dist/layout/Separator.js +1 -1
- package/dist/layout/Separator.js.map +1 -1
- package/dist/layout/Splitter.d.ts +1 -1
- package/dist/layout/Splitter.js +1 -1
- package/dist/layout/Splitter.js.map +1 -1
- package/dist/layout/ViewportFill.d.ts +1 -1
- package/dist/layout/ViewportFill.js +1 -1
- package/dist/layout/ViewportFill.js.map +1 -1
- package/dist/navigation/Breadcrumbs.d.ts +1 -1
- package/dist/navigation/Breadcrumbs.js +1 -1
- package/dist/navigation/Breadcrumbs.js.map +1 -1
- package/dist/navigation/NavBar.d.ts +1 -1
- package/dist/navigation/NavBar.js +1 -1
- package/dist/navigation/NavBar.js.map +1 -1
- package/dist/navigation/NavList.d.ts +1 -1
- package/dist/navigation/NavList.js +1 -1
- package/dist/navigation/NavList.js.map +1 -1
- package/dist/navigation/PageJump.d.ts +1 -1
- package/dist/navigation/PageJump.js +1 -1
- package/dist/navigation/PageJump.js.map +1 -1
- package/dist/navigation/PageSizeSelect.d.ts +1 -1
- package/dist/navigation/PageSizeSelect.js +1 -1
- package/dist/navigation/PageSizeSelect.js.map +1 -1
- package/dist/navigation/Pager.d.ts +1 -1
- package/dist/navigation/Pager.js +1 -1
- package/dist/navigation/Pager.js.map +1 -1
- package/dist/navigation/Pagination.d.ts +1 -1
- package/dist/navigation/Pagination.js +1 -1
- package/dist/navigation/Pagination.js.map +1 -1
- package/dist/navigation/PaginationBar.d.ts +1 -1
- package/dist/navigation/PaginationBar.js +1 -1
- package/dist/navigation/PaginationBar.js.map +1 -1
- package/dist/navigation/SkipLink.d.ts +1 -1
- package/dist/navigation/SkipLink.js +1 -1
- package/dist/navigation/SkipLink.js.map +1 -1
- package/dist/navigation/Steps.d.ts +1 -1
- package/dist/navigation/Steps.js +1 -1
- package/dist/navigation/Steps.js.map +1 -1
- package/dist/navigation/TableOfContents.d.ts +1 -1
- package/dist/navigation/TableOfContents.js +1 -1
- package/dist/navigation/TableOfContents.js.map +1 -1
- package/dist/navigation/Tabs.d.ts +1 -1
- package/dist/navigation/Tabs.js +1 -1
- package/dist/navigation/Tabs.js.map +1 -1
- package/dist/navigation/Toolbar.d.ts +1 -1
- package/dist/navigation/Toolbar.js +1 -1
- package/dist/navigation/Toolbar.js.map +1 -1
- package/dist/overlay/CommandPalette.d.ts +1 -1
- package/dist/overlay/CommandPalette.js +1 -1
- package/dist/overlay/CommandPalette.js.map +1 -1
- package/dist/overlay/Dialog.d.ts +1 -1
- package/dist/overlay/Dialog.js +1 -1
- package/dist/overlay/Dialog.js.map +1 -1
- package/dist/overlay/Drawer.d.ts +1 -1
- package/dist/overlay/Drawer.js +1 -1
- package/dist/overlay/Drawer.js.map +1 -1
- package/dist/overlay/HoverCard.d.ts +1 -1
- package/dist/overlay/HoverCard.js +1 -1
- package/dist/overlay/HoverCard.js.map +1 -1
- package/dist/overlay/Lightbox.d.ts +1 -1
- package/dist/overlay/Lightbox.js +1 -1
- package/dist/overlay/Lightbox.js.map +1 -1
- package/dist/overlay/Menu.d.ts +1 -1
- package/dist/overlay/Menu.js +1 -1
- package/dist/overlay/Menu.js.map +1 -1
- package/dist/overlay/Popconfirm.d.ts +1 -1
- package/dist/overlay/Popconfirm.js +1 -1
- package/dist/overlay/Popconfirm.js.map +1 -1
- package/dist/overlay/Popover.d.ts +1 -1
- package/dist/overlay/Popover.js +1 -1
- package/dist/overlay/Popover.js.map +1 -1
- package/dist/overlay/Tooltip.d.ts +1 -1
- package/dist/overlay/Tooltip.js +1 -1
- package/dist/overlay/Tooltip.js.map +1 -1
- package/dist/overlay/Tour.d.ts +1 -1
- package/dist/overlay/Tour.js +1 -1
- package/dist/overlay/Tour.js.map +1 -1
- package/dist/patterns/ActionBar.d.ts +1 -1
- package/dist/patterns/ActionBar.js +1 -1
- package/dist/patterns/ActionBar.js.map +1 -1
- package/dist/patterns/AppShell.d.ts +1 -1
- package/dist/patterns/AppShell.js +1 -1
- package/dist/patterns/AppShell.js.map +1 -1
- package/dist/patterns/AuthLayout.d.ts +2 -2
- package/dist/patterns/AuthLayout.js +2 -2
- package/dist/patterns/AuthLayout.js.map +1 -1
- package/dist/patterns/CommentThread.d.ts +1 -1
- package/dist/patterns/CommentThread.js +1 -1
- package/dist/patterns/CommentThread.js.map +1 -1
- package/dist/patterns/DataImport.d.ts +1 -1
- package/dist/patterns/DataImport.js +1 -1
- package/dist/patterns/DataImport.js.map +1 -1
- package/dist/patterns/FilterBar.d.ts +1 -1
- package/dist/patterns/FilterBar.js +1 -1
- package/dist/patterns/FilterBar.js.map +1 -1
- package/dist/patterns/KanbanBoard.d.ts +1 -1
- package/dist/patterns/KanbanBoard.js +1 -1
- package/dist/patterns/KanbanBoard.js.map +1 -1
- package/dist/patterns/NotificationCenter.d.ts +1 -1
- package/dist/patterns/NotificationCenter.js +1 -1
- package/dist/patterns/NotificationCenter.js.map +1 -1
- package/dist/patterns/QueryTable.d.ts +1 -1
- package/dist/patterns/QueryTable.js +1 -1
- package/dist/patterns/QueryTable.js.map +1 -1
- package/dist/patterns/SlideCaptcha.d.ts +1 -1
- package/dist/patterns/SlideCaptcha.js +1 -1
- package/dist/patterns/SlideCaptcha.js.map +1 -1
- package/dist/patterns/StepsForm.d.ts +1 -1
- package/dist/patterns/StepsForm.js +1 -1
- package/dist/patterns/StepsForm.js.map +1 -1
- package/dist/table/ColumnHeaderActions.d.ts +1 -1
- package/dist/table/ColumnHeaderActions.js +1 -1
- package/dist/table/ColumnHeaderActions.js.map +1 -1
- package/dist/table/ColumnSettings.d.ts +1 -1
- package/dist/table/ColumnSettings.js +1 -1
- package/dist/table/ColumnSettings.js.map +1 -1
- package/dist/table/ColumnTable.d.ts +1 -1
- package/dist/table/ColumnTable.js +1 -1
- package/dist/table/ColumnTable.js.map +1 -1
- package/dist/table/DataTableView.d.ts +1 -1
- package/dist/table/DataTableView.js +1 -1
- package/dist/table/DataTableView.js.map +1 -1
- package/dist/table/PivotTable.d.ts +1 -1
- package/dist/table/PivotTable.js +1 -1
- package/dist/table/PivotTable.js.map +1 -1
- package/dist/table/SelectionBar.d.ts +1 -1
- package/dist/table/SelectionBar.js +1 -1
- package/dist/table/SelectionBar.js.map +1 -1
- package/dist/table/Table.d.ts +1 -1
- package/dist/table/Table.js +1 -1
- package/dist/table/Table.js.map +1 -1
- package/dist/table/TreeDataTable.d.ts +1 -1
- package/dist/table/TreeDataTable.js +1 -1
- package/dist/table/TreeDataTable.js.map +1 -1
- package/dist/table/table-styles.d.ts +1 -1
- package/dist/table/table-styles.js +1 -1
- package/dist/table/table-styles.js.map +1 -1
- package/dist/theme-customize/ThemeCustomizer.d.ts +1 -1
- package/dist/theme-customize/ThemeCustomizer.js +1 -1
- package/dist/theme-customize/ThemeCustomizer.js.map +1 -1
- package/dist/theme-customize/ThemeThumbnail.d.ts +1 -1
- package/dist/theme-customize/ThemeThumbnail.js +1 -1
- package/dist/theme-customize/ThemeThumbnail.js.map +1 -1
- package/dist/theme-customize/design-tokens.js +1 -1
- package/dist/theme-customize/design-tokens.js.map +1 -1
- package/dist/three/core/EffectSurface.d.ts +1 -1
- package/dist/three/core/EffectSurface.js +1 -1
- package/dist/three/core/EffectSurface.js.map +1 -1
- package/dist/three/core/ThreeCanvas.d.ts +1 -1
- package/dist/three/core/ThreeCanvas.js +1 -1
- package/dist/three/core/ThreeCanvas.js.map +1 -1
- package/dist/three/effects/Confetti.d.ts +1 -1
- package/dist/three/effects/Confetti.js +1 -1
- package/dist/three/effects/Confetti.js.map +1 -1
- package/dist/three/globe/Globe.d.ts +1 -1
- package/dist/three/globe/Globe.js +1 -1
- package/dist/three/globe/Globe.js.map +1 -1
- package/dist/three/model/ModelViewer.d.ts +1 -1
- package/dist/three/model/ModelViewer.js +1 -1
- package/dist/three/model/ModelViewer.js.map +1 -1
- package/dist/utils/dom/floating.d.ts +1 -1
- package/dist/utils/dom/floating.js +1 -1
- package/dist/utils/dom/floating.js.map +1 -1
- package/dist/utils/dom/ripple.d.ts +1 -1
- package/dist/utils/dom/ripple.js +1 -1
- package/dist/utils/dom/ripple.js.map +1 -1
- package/dist/utils/props.js +1 -1
- package/dist/utils/props.js.map +1 -1
- package/dist/utils/style/attached.d.ts +1 -1
- package/dist/utils/style/attached.js +1 -1
- package/dist/utils/style/attached.js.map +1 -1
- package/dist/utils/style/item-styles.d.ts +1 -1
- package/dist/utils/style/item-styles.js +1 -1
- package/dist/utils/style/item-styles.js.map +1 -1
- package/dist/utils/style/markers.d.ts +1 -1
- package/dist/utils/style/markers.js +1 -1
- package/dist/utils/style/markers.js.map +1 -1
- package/dist/utils/style/shimmer.d.ts +1 -1
- package/dist/utils/style/shimmer.js +1 -1
- package/dist/utils/style/shimmer.js.map +1 -1
- package/dist/utils/style/styles.d.ts +1 -1
- package/dist/utils/style/styles.js +1 -1
- package/dist/utils/style/styles.js.map +1 -1
- package/dist/utils/style/swatch-styles.d.ts +1 -1
- package/dist/utils/style/swatch-styles.js +1 -1
- package/dist/utils/style/swatch-styles.js.map +1 -1
- package/dist/utils/style/tone-styles.d.ts +1 -1
- package/dist/utils/style/tone-styles.js +1 -1
- package/dist/utils/style/tone-styles.js.map +1 -1
- package/dist/utils/style/transitions.d.ts +1 -1
- package/dist/utils/style/transitions.js +1 -1
- package/dist/utils/style/transitions.js.map +1 -1
- package/dist/utils/style/typography.d.ts +1 -1
- package/dist/utils/style/typography.js +1 -1
- package/dist/utils/style/typography.js.map +1 -1
- package/dist/utils/style/vars.d.ts +1 -1
- package/dist/utils/style/vars.js +1 -1
- package/dist/utils/style/vars.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Countdown.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_computed","_createVNode"],"sources":["../../src/date/Countdown.tsx"],"sourcesContent":["/**\n * 倒计时(role=\"timer\"):到某个时刻还剩多久,按秒(或分)更新;到点时调用 onEnd,停在 0。\n * 参考 Ant Design Statistic.Countdown、GitHub 的 <relative-time format=\"duration\">。\n *\n * <Countdown to={sale.startsAt} onEnd={refresh} /> // 2天 03:15:42\n * <Countdown to={deadline} precision=\"minute\" /> // 2天 03:15\n * <Countdown to={deadline}>{({ days, hours }) => `还剩 ${days} 天 ${hours} 小时`}</Countdown>\n *\n * 目标时刻同 DateTime 的值(Date、DateValue 或 ISO 字符串)。默认显示 时:分:秒,超过一天时前面加天数(Intl 的单位写法)。\n * role=\"timer\" 默认不播报(aria-live 为 off),读屏用户需要时自己读;到点的提示放在 onEnd 里(Toast 等)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport
|
|
1
|
+
{"version":3,"file":"Countdown.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_computed","_createVNode"],"sources":["../../src/date/Countdown.tsx"],"sourcesContent":["/**\n * 倒计时(role=\"timer\"):到某个时刻还剩多久,按秒(或分)更新;到点时调用 onEnd,停在 0。\n * 参考 Ant Design Statistic.Countdown、GitHub 的 <relative-time format=\"duration\">。\n *\n * <Countdown to={sale.startsAt} onEnd={refresh} /> // 2天 03:15:42\n * <Countdown to={deadline} precision=\"minute\" /> // 2天 03:15\n * <Countdown to={deadline}>{({ days, hours }) => `还剩 ${days} 天 ${hours} 小时`}</Countdown>\n *\n * 目标时刻同 DateTime 的值(Date、DateValue 或 ISO 字符串)。默认显示 时:分:秒,超过一天时前面加天数(Intl 的单位写法)。\n * role=\"timer\" 默认不播报(aria-live 为 off),读屏用户需要时自己读;到点的提示放在 onEnd 里(Toast 等)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { watch, type VNodeChild } from 'vue';\nimport { useLang } from '../config/context';\nimport { useFormat } from '../config/lang/format';\nimport { toInstant } from '../utils/data/date';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { useNow } from './clock';\nimport type { DateTimeInput } from './DateTime';\n\n/** 还剩多久,拆成天、时、分、秒 */\nexport interface CountdownParts {\n /** 剩余的毫秒数,到点后是 0 */\n total: number;\n /** 整天数 */\n days: number;\n /** 不满一天的小时(0–23) */\n hours: number;\n /** 不满一小时的分钟(0–59) */\n minutes: number;\n /** 不满一分钟的秒(0–59);精度为 minute 时总是 0 */\n seconds: number;\n /** 已经到点 */\n ended: boolean;\n}\n\n/** 更新与显示的精度 */\nexport interface CountdownPrecisions {\n /** 到秒(默认):每秒更新 */\n second: unknown;\n /** 到分:每分钟更新,不显示秒 */\n minute: unknown;\n}\n\n/** 未声明的属性落到 span(role=\"timer\")上 */\nexport interface CountdownProps extends PartProps<'span', 'role'> {\n /** 目标时刻 */\n to: DateTimeInput;\n /** 精度,默认 second */\n precision?: keyof CountdownPrecisions;\n /** 到点时调用一次(挂载时已经过了的不调用) */\n onEnd?: () => void;\n /** 自定义显示:拿到拆好的天、时、分、秒 */\n children?: (parts: CountdownParts) => VNodeChild;\n}\n\n/** Countdown 的样式:root */\nexport const countdownStyles = css.create({\n // 等宽数字:每秒跳动时宽度不变\n root: { fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' },\n});\n\nconst SECOND = 1000;\nconst MINUTE = 60 * SECOND;\n\n/** 剩余的毫秒数 → 天、时、分、秒(按精度向上取整:还剩 0.4 秒时显示 1 秒,到点才是 0) */\nexport function countdownParts(\n total: number,\n precision: keyof CountdownPrecisions,\n): CountdownParts {\n const unit = precision === 'minute' ? MINUTE : SECOND;\n const rounded = Math.ceil(Math.max(total, 0) / unit) * unit;\n const seconds = Math.floor(rounded / SECOND);\n return {\n total: Math.max(total, 0),\n days: Math.floor(seconds / 86_400),\n hours: Math.floor(seconds / 3600) % 24,\n minutes: Math.floor(seconds / 60) % 60,\n seconds: seconds % 60,\n ended: total <= 0,\n };\n}\n\nconst pad = (value: number) => String(value).padStart(2, '0');\n\n/** 倒计时 */\nexport const Countdown = _component(\n ({ to, precision = 'second', onEnd, children, ...rest }: CountdownProps) => {\n const lang = useLang();\n const format = useFormat();\n const target = () => toInstant(to, lang.timeZone);\n const now = useNow((current) =>\n current >= target() ? null : precision === 'minute' ? MINUTE : SECOND,\n );\n const parts = _derived(countdownParts(target() - now.value, precision));\n watch(\n () => parts.ended,\n (ended, before) => {\n if (ended && before === false) onEnd?.();\n },\n );\n\n return () => {\n const { days, hours, minutes, seconds } = parts;\n const clock = [hours, minutes, ...(precision === 'second' ? [seconds] : [])]\n .map(pad)\n .join(':');\n const dayText =\n days > 0\n ? `${format.number(days, { style: 'unit', unit: 'day', unitDisplay: 'long' })} `\n : '';\n return (\n <span {...mergeAttrs<'span'>({ sx: countdownStyles.root }, rest, { role: 'timer' })}>\n {children ? children(parts) : `${dayText}${clock}`}\n </span>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;;;;;AA0DA,IAAa,kBAAkB,IAAI,OAAO,EAExC,MAAM;CAAE,oBAAoB;CAAgB,YAAY;AAAS,EACnE,CAAC;AAED,IAAM,SAAS;AACf,IAAM,SAAS,KAAK;;AAGpB,SAAgB,eACd,OACA,WACgB;CAChB,MAAM,OAAO,cAAc,WAAW,SAAS;CAC/C,MAAM,UAAU,KAAK,KAAK,KAAK,IAAI,OAAO,CAAC,IAAI,IAAI,IAAI;CACvD,MAAM,UAAU,KAAK,MAAM,UAAU,MAAM;CAC3C,OAAO;EACL,OAAO,KAAK,IAAI,OAAO,CAAC;EACxB,MAAM,KAAK,MAAM,UAAU,KAAM;EACjC,OAAO,KAAK,MAAM,UAAU,IAAI,IAAI;EACpC,SAAS,KAAK,MAAM,UAAU,EAAE,IAAI;EACpC,SAAS,UAAU;EACnB,OAAO,SAAS;CAClB;AACF;AAEA,IAAM,OAAO,UAAkB,OAAO,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG;;AAG5D,IAAa,YAAY,0BACvB,QAAA,SAA4E;CAAA,MAAA,KAAAA,aAAA,QAAA,IAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,aAAzD,QAAQ;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,WAAAC,aAAA,MAAA;CAAA,MAAsB,OAAIC,UAAA,QAAA,MAAA,KAAA;CACnD,MAAM,OAAO,QAAQ;CACrB,MAAM,SAAS,UAAU;CACzB,MAAM,eAAe,UAAS,GAAA,OAAK,KAAK,QAAQ;CAChD,MAAM,MAAM,QAAQ,YAClB,WAAW,OAAO,IAAI,OAAO,UAAA,UAAc,WAAW,SAAS,MACjE;CACA,MAAM,QAAKC,eAAY,eAAe,OAAO,IAAI,IAAI,OAAK,UAAA,KAAW,CAAC;CACtE,YACQ,MAAA,MAAM,QACX,OAAO,WAAW;EACjB,IAAI,SAAS,WAAW,OAAO,MAAA,QAAQ;CACzC,CACF;CAEA,aAAa;EACX,MAAM,EAAE,MAAM,OAAO,SAAS,YAAS,MAAA;EACvC,MAAM,QAAQ;GAAC;GAAO;GAAS,GAAI,UAAA,UAAc,WAAW,CAAC,OAAO,IAAI,CAAA;EAAG,CAAC,CACzE,IAAI,GAAG,CAAC,CACR,KAAK,GAAG;EACX,MAAM,UACJ,OAAO,IACH,GAAG,OAAO,OAAO,MAAM;GAAE,OAAO;GAAQ,MAAM;GAAO,aAAa;EAAO,CAAC,EAAC,KAC3E;EACN,OAAAC,YAAA,QACY,WAAmB,EAAE,IAAI,gBAAgB,KAAK,GAAG,MAAM,EAAE,MAAM,QAAQ,CAAC,GAAC,CAChF,SAAA,QAAW,SAAA,MAAA,MAAA,KAAc,IAAI,GAAG,UAAU,OAAO,CAAA;CAGxD;AACF,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
|
|
2
2
|
import { type ButtonProps } from '../base/Button';
|
|
3
3
|
import { type OpenChangeProps } from '../utils/dom/open-change';
|
|
4
4
|
import { type PartProps } from '../utils/props';
|
package/dist/date/DatePicker.js
CHANGED
|
@@ -11,7 +11,7 @@ import { QuarterCalendar } from "./QuarterCalendar.js";
|
|
|
11
11
|
import { focusCalendar, renderPickerPresets, usePickerPopover } from "./picker-popover.js";
|
|
12
12
|
import { Fragment, computed, createVNode } from "vue";
|
|
13
13
|
import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
14
|
-
import
|
|
14
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
15
15
|
import { CalendarDays } from "@lucide/icons";
|
|
16
16
|
import { toCalendarDateTime } from "@internationalized/date";
|
|
17
17
|
//#region src/date/DatePicker.tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatePicker.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_computed","_createVNode","_Fragment","_mergeProps"],"sources":["../../src/date/DatePicker.tsx"],"sourcesContent":["/**\n * 日期选择器:DateField 加一个打开日历的按钮,日历弹在输入框下方;可以直接键入,也可以点选。\n * 参考 React Aria DatePicker(输入框可键入,按钮打开对话框里的 Calendar)、Mantine DatePickerInput。\n *\n * <Field label=\"出发日期\"><DatePicker _value={date} min={today} /></Field>\n * <DatePicker granularity=\"month\" _value={month} aria-label=\"账期\" /> // 选月份:'2026-10'\n * <DatePicker granularity=\"minute\" _value={at} aria-label=\"开始时间\" /> // 日期加时间:'2026-10-20T14:30'\n *\n * <DatePicker granularity=\"quarter\" _value={quarter} aria-label=\"考核季度\" /> // 季度:'2026-Q4';week 是 '2026-W43'\n *\n * granularity 决定值的形式(同 DateField)与弹出的选择:year、month 选年份、月份,quarter 弹出季度面板(QuarterCalendar),\n * week 选周(日历按 ISO 周排、行首是周数,点哪天都是选它那一周),其余选日期。\n * 日历下方有“今天”(按粒度是今年、本季度、本月、本周;超出范围时不可用),旁边可以放快捷选项(presets)。\n * 选好后关闭,焦点回到按钮;带时间时焦点落到“时”那一段接着输入(没有时间时先补 00:00)。\n * Esc、点外部关闭;分段里按 Alt + ↓ 打开(同原生 select)。\n *\n * 部件:同 DateField,另有 Button(打开按钮)、Popover(弹层,role=\"dialog\")、Presets、Calendar、Today(“今天”按钮)。\n */\nimport { CalendarDays } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { toCalendarDateTime } from '@internationalized/date';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { Button, type ButtonProps } from '../base/Button';\nimport { useLang } from '../config/context';\nimport { useFieldControl } from '../form/Field';\nimport {\n fullIsoDay,\n parseIsoDate,\n todayIso,\n toIsoDate,\n toIsoQuarter,\n toIsoWeek,\n} from '../utils/data/date';\nimport { openSetter, type OpenChangeProps } from '../utils/dom/open-change';\nimport { mergePartProps, type PartProps } from '../utils/props';\nimport { Calendar, type CalendarBaseProps } from './Calendar';\nimport {\n DateField,\n dateUnitOf,\n isoToValue,\n isPeriodDisabled,\n isTimeGranularity,\n valueToIso,\n type DateFieldProps,\n} from './DateField';\nimport { toDateLimits, useDateLocale, type DateInput } from './date-locale';\nimport { QuarterCalendar } from './QuarterCalendar';\nimport {\n focusCalendar,\n renderPickerPresets,\n usePickerPopover,\n type PickerPopoverParts,\n} from './picker-popover';\n\n/** 自定义的快捷选项(一周前、上个月末) */\nexport interface DatePreset<V extends DateInput = string> {\n /** 按钮上的文字 */\n label: string;\n /** 值(按 granularity 的形式);函数时每次打开按当时算(跟着今天变) */\n value: V | (() => V);\n}\n\n/** 未声明的属性落到这组分段上(主元素);外壳用 propsRoot */\nexport interface DatePickerProps<V extends DateInput = string>\n extends DateFieldProps<V>, PickerPopoverParts, OpenChangeProps {\n /** 弹层是否打开:父级可写 _open={x} */\n _open?: boolean;\n /** 日历并排显示几个月,默认 1 */\n visibleMonths?: number;\n /** 日历旁边的快捷选项:`[{ label: '一周前', value: () => shiftIsoDate(todayIso(), { weeks: -1 }) }]` */\n presets?: readonly DatePreset<V>[];\n /** 日历下方的“今天”(选月份时“本月”、选年份时“今年”),默认 true */\n showToday?: boolean;\n /** 快捷选项那一列的部件属性 */\n propsPresets?: PartProps<'div', 'role'>;\n /** “今天”按钮的部件属性 */\n propsToday?: Partial<ButtonProps>;\n /** 日历的部件属性(值、范围、粒度由选择器给出) */\n propsCalendar?: Omit<\n Partial<CalendarBaseProps<V>>,\n 'granularity' | 'min' | 'max' | 'isDateUnavailable' | 'valueType' | 'onPick'\n >;\n}\n\n/** DatePicker 的样式:popover、main(日历与“今天”)、footer(快捷选项的样式见 pickerPresetStyles) */\nexport const datePickerStyles = css.create({\n popover: { display: 'flex', alignItems: 'flex-start', gap: '_sm', padding: '_sm' },\n main: { display: 'flex', flexDirection: 'column', gap: '_xs' },\n // 选周时已选那一周的另外六天\n inWeek: {\n backgroundColor: { default: '_accentSoft', ':hover': '_accentSoftHover' },\n color: '_accentText',\n },\n footer: {\n display: 'flex',\n justifyContent: 'center',\n paddingBlockStart: '_xs',\n borderBlockStartWidth: '_xs',\n borderBlockStartStyle: 'solid',\n borderBlockStartColor: '_borderMuted',\n },\n});\n\n/** 日期选择器:分段输入 + 弹出的日历 */\nexport const DatePicker = _component(\n <V extends DateInput>({\n _value: value = _bindable<V | null>(null),\n _open: open = _bindable(false),\n onOpenChange,\n granularity = 'day',\n valueType,\n min,\n max,\n isDateUnavailable,\n placement,\n visibleMonths = 1,\n presets = [],\n showToday = true,\n propsPresets,\n propsToday,\n id,\n disabled,\n readonly,\n invalid,\n required,\n propsRoot,\n propsButton,\n propsPopover,\n propsCalendar,\n onKeydown,\n ...rest\n }: DatePickerProps<V>) => {\n const lang = useLang();\n // 输入由里面的 DateField 接 Field;这里只读状态决定能不能打开面板\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }), {\n delegate: true,\n });\n const setOpen = openSetter(\n () => open,\n (next) => (open = next),\n () => onOpenChange,\n );\n const hasTime = () => isTimeGranularity(granularity);\n const picker = usePickerPopover(\n () => ({\n open,\n placement,\n editable: !control().disabled && !control().readonly,\n label: lang.datePickerOpen,\n size: rest.size,\n }),\n { toggle: setOpen, shown: focusCalendar },\n );\n\n // 字符串值按 granularity 的形式('2026'、'2026-10'、'2026-10-20T14:30'):日历只认完整的日期\n const calendarValue = _derived.by((): DateInput | null => {\n return typeof value === 'string' ? fullIsoDay(value) : value;\n });\n\n const locale = useDateLocale();\n /** 能不能选:它那一天(选月份、年份时是那个月、那一年)在范围内、不是不可选的日期 */\n function selectable(input: DateInput): boolean {\n const limits = toDateLimits(locale, { min, max, isDateUnavailable });\n return !isPeriodDisabled(valueToIso(input, granularity), granularity, limits, locale);\n }\n const resolve = (preset: DatePreset<V>): V =>\n typeof preset.value === 'function' ? (preset.value as () => V)() : preset.value;\n // 字符串与 DateValue 都按 ISO 比(DateValue 的 toString 是 ISO)\n const sameValue = (a: DateInput, b: DateInput | null) => b != null && String(a) === String(b);\n\n /** 一天 → 它所在的那一段(按 granularity:年、月、季度、周;日与带时间的就是这一天) */\n function periodOf(day: string): string {\n if (granularity === 'year') return day.slice(0, 4);\n if (granularity === 'month') return day.slice(0, 7);\n if (granularity === 'quarter') return toIsoQuarter(parseIsoDate(day)!);\n if (granularity === 'week') return toIsoWeek(parseIsoDate(day)!);\n return day;\n }\n\n /** 日历选了一天:换回 granularity 的形式;带时间的保留原来的时间,没有时补 00:00 */\n function pickDay(day: DateInput | null) {\n if (day == null) return;\n if (typeof day !== 'string') {\n // 空值按 dateValue 写回时日历给的是 CalendarDate:带时间的粒度要 CalendarDateTime,\n // 选周时换成那一周的周一\n if (granularity === 'week') pickPeriod(periodOf(toIsoDate(day)));\n else value = (hasTime() && !('hour' in day) ? toCalendarDateTime(day) : day) as V;\n return;\n }\n if (!hasTime()) value = periodOf(day) as V;\n else {\n const time = typeof value === 'string' && value.length > 10 ? value.slice(10) : undefined;\n value = `${day}${time ?? (granularity === 'second' ? 'T00:00:00' : 'T00:00')}` as V;\n }\n }\n\n /** 季度面板、选周的日历给的 'YYYY-Qn' / 'YYYY-Www':和当前值同一种类型写回(DateValue 时是这一段的第一天) */\n function pickPeriod(iso: string | null) {\n if (iso != null) value = isoToValue(iso, value ?? undefined, granularity, valueType) as V;\n }\n\n // 选周:已选那一周的另外六天带浅色底(日历只把周一当作已选的那一格)\n const weekCellButton = (date: string) => {\n const week = typeof value === 'string' ? value : value != null ? toIsoWeek(value) : null;\n const day = parseIsoDate(date);\n const inWeek = week != null && day != null && toIsoWeek(day) === week;\n return inWeek && date !== fullIsoDay(week) ? { sx: datePickerStyles.inWeek } : {};\n };\n\n /** “今天”按钮的文字:按粒度是今年、本季度、本月、本周或今天 */\n function todayLabel(): string {\n const labels: Partial<Record<typeof granularity, string>> = {\n year: lang.dateRangePreset.thisYear,\n quarter: lang.datePickerThisQuarter,\n month: lang.dateRangePreset.thisMonth,\n week: lang.dateRangePreset.thisWeek,\n };\n return labels[granularity] ?? lang.dateRangePreset.today;\n }\n\n function picked(event?: Event) {\n setOpen(false, 'select', event);\n // 带时间时接着输入时间:焦点去“时”那一段(关闭后的归还焦点只在焦点丢失时生效,不会抢回去)\n if (hasTime()) picker.anchor?.querySelector<HTMLElement>('[data-type=\"hour\"]')?.focus();\n }\n\n return () => (\n <>\n <DateField\n {...rest}\n _value={value}\n granularity={granularity}\n valueType={valueType}\n min={min}\n max={max}\n isDateUnavailable={isDateUnavailable}\n id={id}\n disabled={disabled}\n readonly={readonly}\n invalid={invalid}\n required={required}\n onKeydown={(event) => {\n onKeydown?.(event);\n picker.onKeydown(event);\n }}\n propsRoot={mergePartProps<PartProps<'div'>>({}, propsRoot, { ref: picker.anchorRef })}\n suffix={picker.button(CalendarDays, propsButton)}\n />\n {picker.panel(\n datePickerStyles.popover,\n propsPopover,\n open && [\n renderPickerPresets(\n presets.map((preset) => {\n const next = resolve(preset);\n return {\n key: preset.label,\n label: preset.label,\n active: sameValue(next, value),\n disabled: !selectable(next),\n onPick: () => {\n value = next;\n picked();\n },\n };\n }),\n lang.datePickerPresets,\n propsPresets,\n ),\n <div {...css.attrs(datePickerStyles.main)}>\n {granularity === 'quarter' ? (\n <QuarterCalendar\n _value={typeof value === 'string' || value == null ? value : toIsoQuarter(value)}\n onUpdate:_value={pickPeriod}\n min={min}\n max={max}\n aria-label={lang.datePickerOpen}\n onPick={() => picked()}\n />\n ) : (\n <Calendar<V>\n {...propsCalendar}\n // 这里的日历是单选:值是一天或空\n onUpdate:_value={(day) => pickDay(day as DateInput | null)}\n _value={calendarValue as V | null}\n granularity={dateUnitOf(granularity)}\n valueType={valueType}\n min={min}\n max={max}\n isDateUnavailable={isDateUnavailable}\n visibleMonths={visibleMonths}\n // 选周:按 ISO 8601 的周(周一开始)排,行首是第几周,与值 'YYYY-Www' 一致\n {...(granularity === 'week' && {\n firstDayOfWeek: 1,\n showWeekNumbers: true,\n propsCellButton: weekCellButton,\n })}\n onPick={() => picked()}\n />\n )}\n {showToday && (\n <div {...css.attrs(datePickerStyles.footer)}>\n <Button\n {...mergePartProps<ButtonProps>({ size: 'sm', variant: 'ghost' }, propsToday, {\n disabled: !selectable(periodOf(todayIso(locale.timeZone))),\n onClick: (event: MouseEvent) => {\n pickDay(todayIso(locale.timeZone));\n picked(event);\n },\n })}\n >\n {todayLabel()}\n </Button>\n </div>\n )}\n </div>,\n ],\n )}\n </>\n );\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqFA,IAAa,mBAAmB,IAAI,OAAO;CACzC,SAAS;EAAE,SAAS;EAAQ,YAAY;EAAc,KAAK;EAAO,SAAS;CAAM;CACjF,MAAM;EAAE,SAAS;EAAQ,eAAe;EAAU,KAAK;CAAM;CAE7D,QAAQ;EACN,iBAAiB;GAAE,SAAS;GAAe,UAAU;EAAmB;EACxE,OAAO;CACT;CACA,QAAQ;EACN,SAAS;EACT,gBAAgB;EAChB,mBAAmB;EACnB,uBAAuB;EACvB,uBAAuB;EACvB,uBAAuB;CACzB;AACF,CAAC;;AAGD,IAAa,aAAa,0BACxB,QAAA,SA0B0B;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,QAAAA,SAAA,QAAA,gBAzBY,MAAI,KAAA,IAAA;CAAA,MAAA,OAAAA,SAAA,QAAA,eAChB,OAAK,KAAA,IAAA;CAAA,MAAA,eAAAC,aAAA,QAAA,cAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,eAEf,KAAK;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,MAAAA,aAAA,QAAA,KAAA;CAAA,MAAA,MAAAA,aAAA,QAAA,KAAA;CAAA,MAAA,oBAAAA,aAAA,QAAA,mBAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,gBAAAA,aAAA,QAAA,iBAMH,CAAC;CAAA,MAAA,UAAAA,aAAA,QAAA,iBACP,CAAA,CAAE;CAAA,MAAA,YAAAA,aAAA,QAAA,aACA,IAAI;CAAA,MAAA,eAAAA,aAAA,QAAA,cAAA;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAAA,KAAAA,aAAA,QAAA,IAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAAA,eAAAA,aAAA,QAAA,cAAA;CAAA,MAAA,gBAAAA,aAAA,QAAA,eAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAab,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,MAAM,OAAO,QAAQ;CAErB,MAAM,UAAU,uBAAuB;EAAE,IAAE,GAAA;EAAE,SAAO,QAAA;EAAE,UAAQ,SAAA;EAAE,UAAQ,SAAA;EAAE,UAAQ,SAAA;CAAC,IAAI,EACrF,UAAU,KACZ,CAAC;CACD,MAAM,UAAU,iBACd,KAAA,QACC,SAAU,KAAA,QAAO,YAClB,aAAA,KACF;CACA,MAAM,gBAAgB,kBAAiB,YAAA,KAAY;CACnD,MAAM,SAAS,wBACN;EACL,MAAI,KAAA;EACJ,WAAS,UAAA;EACT,UAAU,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;EAC5C,OAAO,KAAK;EACZ,MAAM,KAAK;CACb,IACA;EAAE,QAAQ;EAAS,OAAO;CAAc,CAC1C;CAGA,MAAM,gBAAaC,eAAuC;EACxD,OAAO,OAAA,MAAA,UAAiB,WAAW,WAAU,MAAA,KAAM,IAAC,MAAA;CACtD,CAAC;CAED,MAAM,SAAS,cAAc;;CAE7B,SAAS,WAAW,OAA2B;EAC7C,MAAM,SAAS,aAAa,QAAQ;GAAE,KAAG,IAAA;GAAE,KAAG,IAAA;GAAE,mBAAiB,kBAAA;EAAC,CAAC;EACnE,OAAO,CAAC,iBAAiB,WAAW,OAAK,YAAA,KAAa,GAAC,YAAA,OAAe,QAAQ,MAAM;CACtF;CACA,MAAM,WAAW,WACf,OAAO,OAAO,UAAU,aAAc,OAAO,MAAkB,IAAI,OAAO;CAE5E,MAAM,aAAa,GAAc,MAAwB,KAAK,QAAQ,OAAO,CAAC,MAAM,OAAO,CAAC;;CAG5F,SAAS,SAAS,KAAqB;EACrC,IAAI,YAAA,UAAgB,QAAQ,OAAO,IAAI,MAAM,GAAG,CAAC;EACjD,IAAI,YAAA,UAAgB,SAAS,OAAO,IAAI,MAAM,GAAG,CAAC;EAClD,IAAI,YAAA,UAAgB,WAAW,OAAO,aAAa,aAAa,GAAG,CAAE;EACrE,IAAI,YAAA,UAAgB,QAAQ,OAAO,UAAU,aAAa,GAAG,CAAE;EAC/D,OAAO;CACT;;CAGA,SAAS,QAAQ,KAAuB;EACtC,IAAI,OAAO,MAAM;EACjB,IAAI,OAAO,QAAQ,UAAU;GAG3B,IAAI,YAAA,UAAgB,QAAQ,WAAW,SAAS,UAAU,GAAG,CAAC,CAAC;QAC1D,MAAA,QAAS,QAAQ,KAAK,EAAE,UAAU,OAAO,mBAAmB,GAAG,IAAI;GACxE;EACF;EACA,IAAI,CAAC,QAAQ,GAAG,MAAA,QAAQ,SAAS,GAAG;OAC/B;GACH,MAAM,OAAO,OAAA,MAAA,UAAiB,YAAY,MAAA,MAAM,SAAS,KAAK,MAAA,MAAM,MAAM,EAAE,IAAI,KAAA;GAChF,MAAA,QAAQ,GAAG,MAAM,SAAS,YAAA,UAAgB,WAAW,cAAc;EACrE;CACF;;CAGA,SAAS,WAAW,KAAoB;EACtC,IAAI,OAAO,MAAM,MAAA,QAAQ,WAAW,KAAK,MAAA,SAAS,KAAA,GAAS,YAAA,OAAA,UAAA,KAAwB;CACrF;CAGA,MAAM,kBAAkB,SAAiB;EACvC,MAAM,OAAO,OAAA,MAAA,UAAiB,WAAQ,MAAA,QAAW,MAAA,SAAS,OAAO,UAAS,MAAA,KAAM,IAAI;EACpF,MAAM,MAAM,aAAa,IAAI;EAE7B,OADe,QAAQ,QAAQ,OAAO,QAAQ,UAAU,GAAG,MAAM,QAChD,SAAS,WAAW,IAAI,IAAI,EAAE,IAAI,iBAAiB,OAAO,IAAI,CAAC;CAClF;;CAGA,SAAS,aAAqB;EAO5B,OAAO;GALL,MAAM,KAAK,gBAAgB;GAC3B,SAAS,KAAK;GACd,OAAO,KAAK,gBAAgB;GAC5B,MAAM,KAAK,gBAAgB;EAEtB,EAAM,YAAA,UAAiB,KAAK,gBAAgB;CACrD;CAEA,SAAS,OAAO,OAAe;EAC7B,QAAQ,OAAO,UAAU,KAAK;EAE9B,IAAI,QAAQ,GAAG,OAAO,QAAQ,cAA2B,sBAAoB,CAAC,EAAE,MAAM;CACxF;CAEA,aAAOC,YAAAC,UAAA,MAAA,CAAAD,YAAA,WAAAE,cAGG,MAAI;EAAA,UAAA,MAAA;EAAA,mBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,MAAA,QAAA;EAAA,eAAA,YAAA;EAAA,aAAA,UAAA;EAAA,OAAA,IAAA;EAAA,OAAA,IAAA;EAAA,qBAAA,kBAAA;EAAA,MAAA,GAAA;EAAA,YAAA,SAAA;EAAA,YAAA,SAAA;EAAA,WAAA,QAAA;EAAA,YAAA,SAAA;EAAA,aAAA,OAAA,OAAA,OAAA,MAYI,UAAU;GACpB,UAAA,QAAY,KAAK;GACjB,OAAO,UAAU,KAAK;EACxB;EAAC,aACU,eAAiC,CAAC,GAAC,UAAA,OAAa,EAAE,KAAK,OAAO,UAAU,CAAC;EAAC,UAC7E,OAAO,OAAO,cAAY,YAAA,KAAa;CAAC,CAAA,GAAA,IAAA,GAEjD,OAAO,MACN,iBAAiB,SAAO,aAAA,OAExB,KAAA,SAAQ,CACN,oBACE,QAAA,MAAQ,KAAK,WAAW;EACtB,MAAM,OAAO,QAAQ,MAAM;EAC3B,OAAO;GACL,KAAK,OAAO;GACZ,OAAO,OAAO;GACd,QAAQ,UAAU,MAAI,MAAA,KAAO;GAC7B,UAAU,CAAC,WAAW,IAAI;GAC1B,cAAc;IACZ,MAAA,QAAQ;IACR,OAAO;GACT;EACF;CACF,CAAC,GACD,KAAK,mBAAiB,aAAA,KAExB,GAACF,YAAA,OACQ,IAAI,MAAM,iBAAiB,IAAI,GAAC,CACtC,YAAA,UAAgB,YAASA,YAAA,iBAAA;EAAA,UAEd,OAAA,MAAA,UAAiB,YAAY,MAAA,SAAS,OAAI,MAAA,QAAW,aAAY,MAAA,KAAM;EAAC,mBAC/D;EAAU,OAAA,IAAA;EAAA,OAAA,IAAA;EAAA,cAGf,KAAK;EAAc,UAAA,OAAA,OAAA,OAAA,WACjB,OAAO;CAAC,GAAA,IAAA,IAAAA,YAAA,UAAAE,cAAA,cAAA,OAAA;EAAA,mBAAA,OAAA,OAAA,OAAA,MAMJ,QAAQ,QAAQ,GAAuB;EAAC,UAAA,cAAA;EAAA,eAE7C,WAAU,YAAA,KAAY;EAAC,aAAA,UAAA;EAAA,OAAA,IAAA;EAAA,OAAA,IAAA;EAAA,qBAAA,kBAAA;EAAA,iBAAA,cAAA;CAAA,GAO/B,YAAA,UAAgB,UAAU;EAC7B,gBAAgB;EAChB,iBAAiB;EACjB,iBAAiB;CACnB,GAAC,EAAA,UAAA,OAAA,OAAA,OAAA,WACa,OAAO,GAAC,CAAA,GAAA,IAAA,GAGzB,UAAA,SAAAF,YAAA,OACU,IAAI,MAAM,iBAAiB,MAAM,GAAC,CAAAA,YAAA,QAAAE,cAEnC,eAA4B;EAAE,MAAM;EAAM,SAAS;CAAQ,GAAC,WAAA,OAAc;EAC5E,UAAU,CAAC,WAAW,SAAS,SAAS,OAAO,QAAQ,CAAC,CAAC;EACzD,UAAU,UAAsB;GAC9B,QAAQ,SAAS,OAAO,QAAQ,CAAC;GACjC,OAAO,KAAK;EACd;CACF,CAAC,GAAC,EAAA,OAAA,UAAA,CAAA,GAAA;EAAA,eAAA,CAED,WAAW,CAAC;EAAA,SAAA;CAAA,CAAA,CAAA,CAAA,CAGlB,CAAA,CAAA,CAGP,CAAC,CAAA;AAGP,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
|
|
1
|
+
{"version":3,"file":"DatePicker.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_computed","_createVNode","_Fragment","_mergeProps"],"sources":["../../src/date/DatePicker.tsx"],"sourcesContent":["/**\n * 日期选择器:DateField 加一个打开日历的按钮,日历弹在输入框下方;可以直接键入,也可以点选。\n * 参考 React Aria DatePicker(输入框可键入,按钮打开对话框里的 Calendar)、Mantine DatePickerInput。\n *\n * <Field label=\"出发日期\"><DatePicker _value={date} min={today} /></Field>\n * <DatePicker granularity=\"month\" _value={month} aria-label=\"账期\" /> // 选月份:'2026-10'\n * <DatePicker granularity=\"minute\" _value={at} aria-label=\"开始时间\" /> // 日期加时间:'2026-10-20T14:30'\n *\n * <DatePicker granularity=\"quarter\" _value={quarter} aria-label=\"考核季度\" /> // 季度:'2026-Q4';week 是 '2026-W43'\n *\n * granularity 决定值的形式(同 DateField)与弹出的选择:year、month 选年份、月份,quarter 弹出季度面板(QuarterCalendar),\n * week 选周(日历按 ISO 周排、行首是周数,点哪天都是选它那一周),其余选日期。\n * 日历下方有“今天”(按粒度是今年、本季度、本月、本周;超出范围时不可用),旁边可以放快捷选项(presets)。\n * 选好后关闭,焦点回到按钮;带时间时焦点落到“时”那一段接着输入(没有时间时先补 00:00)。\n * Esc、点外部关闭;分段里按 Alt + ↓ 打开(同原生 select)。\n *\n * 部件:同 DateField,另有 Button(打开按钮)、Popover(弹层,role=\"dialog\")、Presets、Calendar、Today(“今天”按钮)。\n */\nimport { CalendarDays } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { toCalendarDateTime } from '@internationalized/date';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { Button, type ButtonProps } from '../base/Button';\nimport { useLang } from '../config/context';\nimport { useFieldControl } from '../form/Field';\nimport {\n fullIsoDay,\n parseIsoDate,\n todayIso,\n toIsoDate,\n toIsoQuarter,\n toIsoWeek,\n} from '../utils/data/date';\nimport { openSetter, type OpenChangeProps } from '../utils/dom/open-change';\nimport { mergePartProps, type PartProps } from '../utils/props';\nimport { Calendar, type CalendarBaseProps } from './Calendar';\nimport {\n DateField,\n dateUnitOf,\n isoToValue,\n isPeriodDisabled,\n isTimeGranularity,\n valueToIso,\n type DateFieldProps,\n} from './DateField';\nimport { toDateLimits, useDateLocale, type DateInput } from './date-locale';\nimport { QuarterCalendar } from './QuarterCalendar';\nimport {\n focusCalendar,\n renderPickerPresets,\n usePickerPopover,\n type PickerPopoverParts,\n} from './picker-popover';\n\n/** 自定义的快捷选项(一周前、上个月末) */\nexport interface DatePreset<V extends DateInput = string> {\n /** 按钮上的文字 */\n label: string;\n /** 值(按 granularity 的形式);函数时每次打开按当时算(跟着今天变) */\n value: V | (() => V);\n}\n\n/** 未声明的属性落到这组分段上(主元素);外壳用 propsRoot */\nexport interface DatePickerProps<V extends DateInput = string>\n extends DateFieldProps<V>, PickerPopoverParts, OpenChangeProps {\n /** 弹层是否打开:父级可写 _open={x} */\n _open?: boolean;\n /** 日历并排显示几个月,默认 1 */\n visibleMonths?: number;\n /** 日历旁边的快捷选项:`[{ label: '一周前', value: () => shiftIsoDate(todayIso(), { weeks: -1 }) }]` */\n presets?: readonly DatePreset<V>[];\n /** 日历下方的“今天”(选月份时“本月”、选年份时“今年”),默认 true */\n showToday?: boolean;\n /** 快捷选项那一列的部件属性 */\n propsPresets?: PartProps<'div', 'role'>;\n /** “今天”按钮的部件属性 */\n propsToday?: Partial<ButtonProps>;\n /** 日历的部件属性(值、范围、粒度由选择器给出) */\n propsCalendar?: Omit<\n Partial<CalendarBaseProps<V>>,\n 'granularity' | 'min' | 'max' | 'isDateUnavailable' | 'valueType' | 'onPick'\n >;\n}\n\n/** DatePicker 的样式:popover、main(日历与“今天”)、footer(快捷选项的样式见 pickerPresetStyles) */\nexport const datePickerStyles = css.create({\n popover: { display: 'flex', alignItems: 'flex-start', gap: '_sm', padding: '_sm' },\n main: { display: 'flex', flexDirection: 'column', gap: '_xs' },\n // 选周时已选那一周的另外六天\n inWeek: {\n backgroundColor: { default: '_accentSoft', ':hover': '_accentSoftHover' },\n color: '_accentText',\n },\n footer: {\n display: 'flex',\n justifyContent: 'center',\n paddingBlockStart: '_xs',\n borderBlockStartWidth: '_xs',\n borderBlockStartStyle: 'solid',\n borderBlockStartColor: '_borderMuted',\n },\n});\n\n/** 日期选择器:分段输入 + 弹出的日历 */\nexport const DatePicker = _component(\n <V extends DateInput>({\n _value: value = _bindable<V | null>(null),\n _open: open = _bindable(false),\n onOpenChange,\n granularity = 'day',\n valueType,\n min,\n max,\n isDateUnavailable,\n placement,\n visibleMonths = 1,\n presets = [],\n showToday = true,\n propsPresets,\n propsToday,\n id,\n disabled,\n readonly,\n invalid,\n required,\n propsRoot,\n propsButton,\n propsPopover,\n propsCalendar,\n onKeydown,\n ...rest\n }: DatePickerProps<V>) => {\n const lang = useLang();\n // 输入由里面的 DateField 接 Field;这里只读状态决定能不能打开面板\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }), {\n delegate: true,\n });\n const setOpen = openSetter(\n () => open,\n (next) => (open = next),\n () => onOpenChange,\n );\n const hasTime = () => isTimeGranularity(granularity);\n const picker = usePickerPopover(\n () => ({\n open,\n placement,\n editable: !control().disabled && !control().readonly,\n label: lang.datePickerOpen,\n size: rest.size,\n }),\n { toggle: setOpen, shown: focusCalendar },\n );\n\n // 字符串值按 granularity 的形式('2026'、'2026-10'、'2026-10-20T14:30'):日历只认完整的日期\n const calendarValue = _derived.by((): DateInput | null => {\n return typeof value === 'string' ? fullIsoDay(value) : value;\n });\n\n const locale = useDateLocale();\n /** 能不能选:它那一天(选月份、年份时是那个月、那一年)在范围内、不是不可选的日期 */\n function selectable(input: DateInput): boolean {\n const limits = toDateLimits(locale, { min, max, isDateUnavailable });\n return !isPeriodDisabled(valueToIso(input, granularity), granularity, limits, locale);\n }\n const resolve = (preset: DatePreset<V>): V =>\n typeof preset.value === 'function' ? (preset.value as () => V)() : preset.value;\n // 字符串与 DateValue 都按 ISO 比(DateValue 的 toString 是 ISO)\n const sameValue = (a: DateInput, b: DateInput | null) => b != null && String(a) === String(b);\n\n /** 一天 → 它所在的那一段(按 granularity:年、月、季度、周;日与带时间的就是这一天) */\n function periodOf(day: string): string {\n if (granularity === 'year') return day.slice(0, 4);\n if (granularity === 'month') return day.slice(0, 7);\n if (granularity === 'quarter') return toIsoQuarter(parseIsoDate(day)!);\n if (granularity === 'week') return toIsoWeek(parseIsoDate(day)!);\n return day;\n }\n\n /** 日历选了一天:换回 granularity 的形式;带时间的保留原来的时间,没有时补 00:00 */\n function pickDay(day: DateInput | null) {\n if (day == null) return;\n if (typeof day !== 'string') {\n // 空值按 dateValue 写回时日历给的是 CalendarDate:带时间的粒度要 CalendarDateTime,\n // 选周时换成那一周的周一\n if (granularity === 'week') pickPeriod(periodOf(toIsoDate(day)));\n else value = (hasTime() && !('hour' in day) ? toCalendarDateTime(day) : day) as V;\n return;\n }\n if (!hasTime()) value = periodOf(day) as V;\n else {\n const time = typeof value === 'string' && value.length > 10 ? value.slice(10) : undefined;\n value = `${day}${time ?? (granularity === 'second' ? 'T00:00:00' : 'T00:00')}` as V;\n }\n }\n\n /** 季度面板、选周的日历给的 'YYYY-Qn' / 'YYYY-Www':和当前值同一种类型写回(DateValue 时是这一段的第一天) */\n function pickPeriod(iso: string | null) {\n if (iso != null) value = isoToValue(iso, value ?? undefined, granularity, valueType) as V;\n }\n\n // 选周:已选那一周的另外六天带浅色底(日历只把周一当作已选的那一格)\n const weekCellButton = (date: string) => {\n const week = typeof value === 'string' ? value : value != null ? toIsoWeek(value) : null;\n const day = parseIsoDate(date);\n const inWeek = week != null && day != null && toIsoWeek(day) === week;\n return inWeek && date !== fullIsoDay(week) ? { sx: datePickerStyles.inWeek } : {};\n };\n\n /** “今天”按钮的文字:按粒度是今年、本季度、本月、本周或今天 */\n function todayLabel(): string {\n const labels: Partial<Record<typeof granularity, string>> = {\n year: lang.dateRangePreset.thisYear,\n quarter: lang.datePickerThisQuarter,\n month: lang.dateRangePreset.thisMonth,\n week: lang.dateRangePreset.thisWeek,\n };\n return labels[granularity] ?? lang.dateRangePreset.today;\n }\n\n function picked(event?: Event) {\n setOpen(false, 'select', event);\n // 带时间时接着输入时间:焦点去“时”那一段(关闭后的归还焦点只在焦点丢失时生效,不会抢回去)\n if (hasTime()) picker.anchor?.querySelector<HTMLElement>('[data-type=\"hour\"]')?.focus();\n }\n\n return () => (\n <>\n <DateField\n {...rest}\n _value={value}\n granularity={granularity}\n valueType={valueType}\n min={min}\n max={max}\n isDateUnavailable={isDateUnavailable}\n id={id}\n disabled={disabled}\n readonly={readonly}\n invalid={invalid}\n required={required}\n onKeydown={(event) => {\n onKeydown?.(event);\n picker.onKeydown(event);\n }}\n propsRoot={mergePartProps<PartProps<'div'>>({}, propsRoot, { ref: picker.anchorRef })}\n suffix={picker.button(CalendarDays, propsButton)}\n />\n {picker.panel(\n datePickerStyles.popover,\n propsPopover,\n open && [\n renderPickerPresets(\n presets.map((preset) => {\n const next = resolve(preset);\n return {\n key: preset.label,\n label: preset.label,\n active: sameValue(next, value),\n disabled: !selectable(next),\n onPick: () => {\n value = next;\n picked();\n },\n };\n }),\n lang.datePickerPresets,\n propsPresets,\n ),\n <div {...css.attrs(datePickerStyles.main)}>\n {granularity === 'quarter' ? (\n <QuarterCalendar\n _value={typeof value === 'string' || value == null ? value : toIsoQuarter(value)}\n onUpdate:_value={pickPeriod}\n min={min}\n max={max}\n aria-label={lang.datePickerOpen}\n onPick={() => picked()}\n />\n ) : (\n <Calendar<V>\n {...propsCalendar}\n // 这里的日历是单选:值是一天或空\n onUpdate:_value={(day) => pickDay(day as DateInput | null)}\n _value={calendarValue as V | null}\n granularity={dateUnitOf(granularity)}\n valueType={valueType}\n min={min}\n max={max}\n isDateUnavailable={isDateUnavailable}\n visibleMonths={visibleMonths}\n // 选周:按 ISO 8601 的周(周一开始)排,行首是第几周,与值 'YYYY-Www' 一致\n {...(granularity === 'week' && {\n firstDayOfWeek: 1,\n showWeekNumbers: true,\n propsCellButton: weekCellButton,\n })}\n onPick={() => picked()}\n />\n )}\n {showToday && (\n <div {...css.attrs(datePickerStyles.footer)}>\n <Button\n {...mergePartProps<ButtonProps>({ size: 'sm', variant: 'ghost' }, propsToday, {\n disabled: !selectable(periodOf(todayIso(locale.timeZone))),\n onClick: (event: MouseEvent) => {\n pickDay(todayIso(locale.timeZone));\n picked(event);\n },\n })}\n >\n {todayLabel()}\n </Button>\n </div>\n )}\n </div>,\n ],\n )}\n </>\n );\n },\n);\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
|
|
2
2
|
import type { PresetIconButtonProps } from '../base/CloseButton';
|
|
3
3
|
import { type ControlIconOptions, type ControlOptions } from '../input/control';
|
|
4
4
|
import { type DateRange, type DateRangePreset } from '../utils/data/date';
|
|
@@ -17,7 +17,7 @@ import { focusCalendar, renderPickerPresets, usePickerPopover } from "./picker-p
|
|
|
17
17
|
import { RangeCalendar } from "./RangeCalendar.js";
|
|
18
18
|
import { Fragment, computed, createTextVNode, createVNode, ref, shallowRef, useId, watch } from "vue";
|
|
19
19
|
import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
20
|
-
import
|
|
20
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
21
21
|
import { CalendarRange } from "@lucide/icons";
|
|
22
22
|
//#region src/date/DateRangePicker.tsx
|
|
23
23
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateRangePicker.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_computed","_vue_shallowRef","_vue_ref","_createVNode","_Fragment","_mergeProps","_createTextVNode"],"sources":["../../src/date/DateRangePicker.tsx"],"sourcesContent":["/**\n * 日期区间选择器:一个输入框里两组分段(开始 – 结束),按钮弹出区间日历,旁边可以放快捷区间(最近 7 天、本月……)。\n * 参考 React Aria DateRangePicker(同一个外壳里两组 DateInput)、Ant Design RangePicker 的 presets。\n *\n * <Field label=\"统计区间\"><DateRangePicker _value={range} max={today} presets={['last7Days', 'thisMonth']} /></Field>\n * <DateRangePicker granularity=\"month\" _value={months} aria-label=\"预算期间\" /> // { start: '2026-01', end: '2026-06' }\n * <DateRangePicker granularity=\"minute\" _value={window} aria-label=\"维护窗口\" /> // '2026-10-24T22:00' – '2026-10-25T06:00'\n *\n * 值是 `{ start, end }`(两端都含;ISO 字符串或 DateValue,写回时保持同一种类型),两端都填好才写回,删掉一段写回 null。\n * granularity 同 DateField:month、year 按月、按年(日历选整月、整年),quarter 弹出季度面板选一段季度,\n * week 按 ISO 周(日历周一开始、行首是周数),hour / minute / second 是日期时间区间\n * (日历里选日期,开始补 00:00、结束补 23:59,已经填了的时间不变)。\n * 结束早于开始、超出范围、是不可选的日期时外壳显示出错,值照样写回,由表单校验决定能不能提交。\n * 开始那组刚填全时焦点自动进结束那组;日历里点开始、再点结束后关闭,焦点回到按钮。Esc、点外部关闭,分段里 Alt + ↓ 打开。\n *\n * 部件:Root(外壳,role=\"group\",主元素)、Start / End(两组分段)、Separator、Clear、Button、Popover、Presets、Calendar。\n */\nimport { CalendarRange } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { useId, watch } from 'vue';\nimport type { PresetIconButtonProps } from '../base/CloseButton';\nimport { VisuallyHidden } from '../base/VisuallyHidden';\nimport { useLang } from '../config/context';\nimport { useFieldControl } from '../form/Field';\nimport { FormValue } from '../form/FormValue';\nimport {\n controlClear,\n controlParts,\n focusOnShell,\n controlIcon,\n useControlAppearance,\n type ControlIconOptions,\n type ControlOptions,\n} from '../input/control';\nimport {\n clampDate,\n fullIsoDay,\n lastIsoDay,\n parseIsoDate,\n presetIsoRange,\n toIsoDate,\n toIsoQuarter,\n toIsoWeek,\n type DateRange,\n type DateRangePreset,\n} from '../utils/data/date';\nimport { toElement } from '../utils/dom/element';\nimport { openSetter, type OpenChangeProps } from '../utils/dom/open-change';\nimport { defaultLabelledBy, mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport {\n toDateLimits,\n useDateLocale,\n type DateInput,\n type DateLimitProps,\n type DateValueTypes,\n} from './date-locale';\nimport { segmentFields, type DateFieldGranularity } from './date-segments';\nimport {\n dateUnitOf,\n isoToValue,\n isPeriodDisabled,\n isTimeGranularity,\n valueToIso,\n} from './DateField';\nimport { DateSegmentGroup, type DateSegmentGroupProps } from './DateSegmentGroup';\nimport {\n focusCalendar,\n renderPickerPresets,\n usePickerPopover,\n type PickerPopoverParts,\n} from './picker-popover';\nimport { QuarterCalendar } from './QuarterCalendar';\nimport { RangeCalendar, type RangeCalendarProps } from './RangeCalendar';\nimport { firstSegmentOf, segmentedFieldStyles, useFieldSegments } from './SegmentedField';\n\n/** 自定义的快捷区间(财年、上个结算周期) */\nexport interface DateRangeCustomPreset<V extends DateInput = string> {\n /** 按钮上的文字 */\n label: string;\n /** 区间;函数时每次打开按当时算(跟着今天变) */\n value: DateRange<V> | (() => DateRange<V>);\n}\n\n/** 未声明的属性落到外壳(role=\"group\")上 */\nexport interface DateRangePickerProps<V extends DateInput = string>\n extends\n PartProps<'div', 'role'>,\n ControlOptions,\n ControlIconOptions,\n DateLimitProps,\n PickerPopoverParts,\n OpenChangeProps {\n /** 区间(两端都含):父级写 _value={x};没填全时 null */\n _value?: DateRange<V> | null;\n /** 弹层是否打开:父级可写 _open={x} */\n _open?: boolean;\n /** 值为空、推不出类型时写回哪一种,默认 iso(字符串) */\n valueType?: keyof DateValueTypes;\n /** 精确到哪一段(同 DateField),默认 day;month、year 按月、按年,hour / minute / second 是日期时间区间 */\n granularity?: DateFieldGranularity;\n /**\n * 快捷区间,显示在日历旁边、夹到 min–max 之内:内置的名字(按今天与语言的一周第一天算),\n * 或自己的 `{ label, value }`(value 可以是函数,每次打开时按当时算)\n */\n presets?: readonly (DateRangePreset | DateRangeCustomPreset<V>)[];\n /** 日历并排显示几个月,默认 2 */\n visibleMonths?: number;\n /** 区间里允许夹着不可选的日期,默认 false */\n allowsUnavailableInRange?: boolean;\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过;不写时结束早于开始、超出范围、是不可选的日期也算 */\n invalid?: boolean;\n /** 有值时显示清空按钮 */\n clearable?: boolean;\n /** 表单提交时开始日期的 name(ISO 字符串) */\n startName?: string;\n /** 表单提交时结束日期的 name */\n endName?: string;\n /** 开始那组分段的部件属性 */\n propsStart?: Partial<DateSegmentGroupProps>;\n /** 结束那组分段的部件属性 */\n propsEnd?: Partial<DateSegmentGroupProps>;\n /** 两组之间的分隔符的部件属性 */\n propsSeparator?: PartProps<'span', 'aria-hidden'>;\n /** 清空按钮的部件属性 */\n propsClear?: Omit<Partial<PresetIconButtonProps>, 'onClick'>;\n /** 快捷区间那一列的部件属性 */\n propsPresets?: PartProps<'div', 'role'>;\n /** 区间日历的部件属性(值、范围由选择器给出) */\n propsCalendar?: Omit<\n Partial<RangeCalendarProps<V>>,\n 'value' | 'min' | 'max' | 'isDateUnavailable' | 'valueType' | 'onPick'\n >;\n}\n\n/** DateRangePicker 的样式:separator、popover(快捷区间的样式见 pickerPresetStyles) */\nexport const dateRangePickerStyles = css.create({\n separator: { flexShrink: 0, paddingInline: '_xs', color: '_textMuted' },\n popover: { display: 'flex', alignItems: 'flex-start', gap: '_sm', padding: '_sm' },\n});\n\n/** 自定义快捷区间的值 → ISO 日期区间(DateValue 取年月日) */\nfunction isoRangeOf<V extends DateInput>(\n value: DateRange<V> | (() => DateRange<V>),\n): DateRange<string> {\n const range = typeof value === 'function' ? value() : value;\n const iso = (input: DateInput) =>\n typeof input === 'string' ? input.slice(0, 10) : toIsoDate(input);\n return { start: iso(range.start), end: iso(range.end) };\n}\n\n/** 日期区间选择器:两组分段 + 弹出的区间日历与快捷区间 */\nexport const DateRangePicker = _component(\n <V extends DateInput>({\n _value: value = _bindable<DateRange<V> | null>(null),\n _open: open = _bindable(false),\n onOpenChange,\n valueType,\n granularity = 'day',\n min,\n max,\n isDateUnavailable,\n presets,\n visibleMonths = 2,\n allowsUnavailableInRange = false,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n clearable = false,\n startName,\n endName,\n placement,\n id,\n propsStart,\n propsEnd,\n propsSeparator,\n propsClear,\n icon,\n propsIcon,\n propsButton,\n propsPopover,\n propsPresets,\n propsCalendar,\n ...rest\n }: DateRangePickerProps<V>) => {\n const lang = useLang();\n const locale = useDateLocale();\n const generatedId = useId();\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n const editable = () => !control().disabled && !control().readonly;\n const limits = _derived(toDateLimits(locale, { min, max, isDateUnavailable }));\n let startGroup = _state.raw<HTMLElement | null>(null);\n let endGroup = _state.raw<HTMLElement | null>(null);\n const setOpen = openSetter(\n () => open,\n (next) => (open = next),\n () => onOpenChange,\n );\n\n const picker = usePickerPopover(\n () => ({\n open,\n placement,\n editable: editable(),\n label: lang.datePickerOpen,\n size: appearance().size,\n }),\n { toggle: setOpen, shown: focusCalendar },\n );\n\n // 两端各自的 ISO 字符串(按 granularity 的形式):只填了一端时值仍是 null,这里记着填了的那一端\n const toIso = (date: DateInput) => valueToIso(date, granularity);\n let start = _state<string | null>(null);\n let end = _state<string | null>(null);\n // 自己写回的值不再同步回两端(否则删掉一端时,写回的 null 会把另一端也清掉)\n let written: DateRange<V> | null | undefined;\n // 值清空后再填:仍按清空前的类型写回\n let lastLike: V | undefined;\n watch(\n () => value,\n (next) => {\n if (next === written) return;\n start = next ? toIso(next.start) : null;\n end = next ? toIso(next.end) : null;\n },\n { immediate: true },\n );\n\n function commit() {\n lastLike = value?.start ?? lastLike;\n const like = (iso: string) => isoToValue(iso, lastLike, granularity, valueType) as V;\n written = start && end ? { start: like(start), end: like(end) } : null;\n if (written !== null || value !== null) value = written;\n }\n\n const startSegments = useFieldSegments(\n () => ({ fields: segmentFields(granularity), value: start, readonly: !editable() }),\n (iso) => {\n start = iso;\n commit();\n },\n // 开始那组最后一段输入满了:焦点进结束那组\n (direction) => direction === 1 && firstSegmentOf(endGroup)?.focus(),\n );\n const endSegments = useFieldSegments(\n () => ({ fields: segmentFields(granularity), value: end, readonly: !editable() }),\n (iso) => {\n end = iso;\n commit();\n },\n // 结束那组第一段删空后再删:回到开始那组的最后一段\n (direction) => {\n if (direction !== -1) return;\n const segments = startGroup?.querySelectorAll<HTMLElement>('[role=\"spinbutton\"]');\n segments?.[segments.length - 1]?.focus();\n },\n );\n\n const outOfRange = (iso: string | null) =>\n iso != null && isPeriodDisabled(iso, granularity, limits, locale);\n\n /** 整天的区间 → 按 granularity 的形式:月、年截短;带时间时开始补 00:00、结束补 23:59(已经填了的时间不变) */\n function fromDays(range: DateRange<string>): DateRange<string> {\n if (granularity === 'year')\n return { start: range.start.slice(0, 4), end: range.end.slice(0, 4) };\n if (granularity === 'month')\n return { start: range.start.slice(0, 7), end: range.end.slice(0, 7) };\n if (granularity === 'quarter' || granularity === 'week') {\n const period = granularity === 'quarter' ? toIsoQuarter : toIsoWeek;\n return {\n start: period(parseIsoDate(range.start)!),\n end: period(parseIsoDate(range.end)!),\n };\n }\n if (!isTimeGranularity(granularity)) return range;\n const timeOf = (iso: string | null, fallback: string) =>\n iso != null && iso.length > 10 ? iso.slice(10) : fallback;\n const endTime = { hour: 'T23:00', minute: 'T23:59', second: 'T23:59:59' }[granularity];\n return {\n start: range.start + timeOf(start, granularity === 'second' ? 'T00:00:00' : 'T00:00'),\n end: range.end + timeOf(end, endTime),\n };\n }\n\n // 区间日历用整天的 ISO 日期:按月、按年、按周时是整段(开始那段的第一天到结束那段的最后一天)\n const calendarRange = (): DateRange<string> | null =>\n start == null || end == null ? null : { start: fullIsoDay(start), end: lastIsoDay(end) };\n\n /** 季度面板选好了区间('YYYY-Qn') */\n function pickQuarters(range: DateRange<string> | null) {\n if (range == null) return;\n start = range.start;\n end = range.end;\n commit();\n }\n\n /** 日历选好了区间:换回 granularity 的形式;带时间时焦点去开始的“时”接着输入 */\n function pickRange(range: DateRange<string> | null) {\n if (range == null) return;\n const next = fromDays(range);\n start = next.start;\n end = next.end;\n commit();\n }\n\n function clear() {\n startSegments.clear();\n endSegments.clear();\n start = null;\n end = null;\n commit();\n firstSegmentOf(startGroup)?.focus();\n }\n\n /** 点外壳空白处:开始没填全时去开始那组,否则去结束那组 */\n const firstEmpty = () =>\n start == null ? firstSegmentOf(startGroup) : firstSegmentOf(endGroup);\n\n /** 快捷区间夹到 min–max 之内:今天之后不能选时,“本月”就是本月 1 日到今天 */\n function presetValue(preset: DateRangePreset | DateRangeCustomPreset<V>): DateRange<string> {\n const range =\n typeof preset === 'string'\n ? presetIsoRange(preset, locale.week, locale.timeZone)\n : isoRangeOf(preset.value);\n const clamp = (iso: string) => toIsoDate(clampDate(parseIsoDate(iso)!, limits));\n return { start: clamp(range.start), end: clamp(range.end) };\n }\n\n function pickPreset(preset: DateRangePreset | DateRangeCustomPreset<V>) {\n const range = fromDays(presetValue(preset));\n start = range.start;\n end = range.end;\n commit();\n setOpen(false, 'select');\n }\n\n return () => {\n const state = control();\n const base = state.id ?? generatedId;\n const ids = { start: `${base}-start-label`, end: `${base}-end-label` };\n const reversed = start != null && end != null && end < start;\n const bad = state.invalid || reversed || outOfRange(start) || outOfRange(end);\n const filled = start != null || end != null || startSegments.partial || endSegments.partial;\n // 两组的名称:字段的标签 + “开始日期” / “结束日期”\n const labelledBy = (own: string) => [state.labelledBy, own].filter(Boolean).join(' ');\n const group = (side: 'start' | 'end') => {\n const isStart = side === 'start';\n return (\n <DateSegmentGroup\n {...mergePartProps<DateSegmentGroupProps>(\n {\n // 开始那组按内容宽,结束那组占满剩下的宽度:读起来是“开始 – 结束”,空白在最后\n sx: isStart ? undefined : segmentedFieldStyles.input,\n segments: isStart ? startSegments : endSegments,\n labelledBy: labelledBy(ids[side]),\n describedBy: state.describedBy,\n },\n isStart ? propsStart : propsEnd,\n {\n ref: (element: unknown) => {\n const found = toElement(element);\n if (isStart) startGroup = found;\n else endGroup = found;\n },\n id: isStart ? base : `${base}-end`,\n segments: isStart ? startSegments : endSegments,\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n invalid: bad,\n onKeydown: picker.onKeydown,\n },\n )}\n />\n );\n };\n const s = controlParts(appearance(), { ...state, invalid: bad });\n return (\n <>\n <div\n {...mergeAttrs<'div'>(\n {\n ...s.root,\n 'aria-labelledby': defaultLabelledBy(rest, state.labelledBy),\n },\n rest,\n {\n ref: picker.anchorRef,\n role: 'group',\n 'aria-disabled': state.disabled || undefined,\n onPointerdown: state.disabled ? undefined : focusOnShell(firstEmpty),\n },\n )}\n data-invalid={bad || undefined}\n data-disabled={state.disabled || undefined}\n >\n {controlIcon(s, icon, propsIcon)}\n <VisuallyHidden id={ids.start}>{lang.dateRangeStart}</VisuallyHidden>\n <VisuallyHidden id={ids.end}>{lang.dateRangeEnd}</VisuallyHidden>\n {group('start')}\n <span\n {...mergeAttrs<'span'>({ sx: dateRangePickerStyles.separator }, propsSeparator)}\n aria-hidden=\"true\"\n >\n –\n </span>\n {group('end')}\n {clearable && filled && editable() && controlClear(s, propsClear, clear)}\n {picker.button(CalendarRange, propsButton)}\n <FormValue name={startName} value={start} disabled={state.disabled} />\n <FormValue name={endName} value={end} disabled={state.disabled} />\n </div>\n {picker.panel(\n dateRangePickerStyles.popover,\n propsPopover,\n open && [\n renderPickerPresets(\n (presets ?? []).map((preset) => {\n const range = presetValue(preset);\n return {\n key: typeof preset === 'string' ? preset : preset.label,\n label: typeof preset === 'string' ? lang.dateRangePreset[preset] : preset.label,\n active: (() => {\n const shown = fromDays(range);\n return shown.start === start && shown.end === end;\n })(),\n onPick: () => pickPreset(preset),\n };\n }),\n lang.dateRangePresets,\n propsPresets,\n ),\n granularity === 'quarter' ? (\n <QuarterCalendar\n mode=\"range\"\n _value={start != null && end != null ? { start, end } : null}\n onUpdate:_value={pickQuarters}\n min={min}\n max={max}\n aria-label={lang.datePickerOpen}\n onPick={() => setOpen(false, 'select')}\n />\n ) : (\n <RangeCalendar\n {...propsCalendar}\n onUpdate:_value={pickRange}\n _value={calendarRange()}\n granularity={dateUnitOf(granularity)}\n min={min}\n max={max}\n isDateUnavailable={isDateUnavailable}\n visibleMonths={visibleMonths}\n allowsUnavailableInRange={allowsUnavailableInRange}\n // 按周:按 ISO 8601 的周排(周一开始),行首是第几周\n {...(granularity === 'week' && { firstDayOfWeek: 1, showWeekNumbers: true })}\n onPick={() => {\n setOpen(false, 'select');\n // 带时间时接着输入时间:焦点去开始那组的“时”\n if (isTimeGranularity(granularity))\n startGroup?.querySelector<HTMLElement>('[data-type=\"hour\"]')?.focus();\n }}\n />\n ),\n ],\n )}\n </>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DateRangePicker.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_computed","_vue_shallowRef","_vue_ref","_createVNode","_Fragment","_mergeProps","_createTextVNode"],"sources":["../../src/date/DateRangePicker.tsx"],"sourcesContent":["/**\n * 日期区间选择器:一个输入框里两组分段(开始 – 结束),按钮弹出区间日历,旁边可以放快捷区间(最近 7 天、本月……)。\n * 参考 React Aria DateRangePicker(同一个外壳里两组 DateInput)、Ant Design RangePicker 的 presets。\n *\n * <Field label=\"统计区间\"><DateRangePicker _value={range} max={today} presets={['last7Days', 'thisMonth']} /></Field>\n * <DateRangePicker granularity=\"month\" _value={months} aria-label=\"预算期间\" /> // { start: '2026-01', end: '2026-06' }\n * <DateRangePicker granularity=\"minute\" _value={window} aria-label=\"维护窗口\" /> // '2026-10-24T22:00' – '2026-10-25T06:00'\n *\n * 值是 `{ start, end }`(两端都含;ISO 字符串或 DateValue,写回时保持同一种类型),两端都填好才写回,删掉一段写回 null。\n * granularity 同 DateField:month、year 按月、按年(日历选整月、整年),quarter 弹出季度面板选一段季度,\n * week 按 ISO 周(日历周一开始、行首是周数),hour / minute / second 是日期时间区间\n * (日历里选日期,开始补 00:00、结束补 23:59,已经填了的时间不变)。\n * 结束早于开始、超出范围、是不可选的日期时外壳显示出错,值照样写回,由表单校验决定能不能提交。\n * 开始那组刚填全时焦点自动进结束那组;日历里点开始、再点结束后关闭,焦点回到按钮。Esc、点外部关闭,分段里 Alt + ↓ 打开。\n *\n * 部件:Root(外壳,role=\"group\",主元素)、Start / End(两组分段)、Separator、Clear、Button、Popover、Presets、Calendar。\n */\nimport { CalendarRange } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { useId, watch } from 'vue';\nimport type { PresetIconButtonProps } from '../base/CloseButton';\nimport { VisuallyHidden } from '../base/VisuallyHidden';\nimport { useLang } from '../config/context';\nimport { useFieldControl } from '../form/Field';\nimport { FormValue } from '../form/FormValue';\nimport {\n controlClear,\n controlParts,\n focusOnShell,\n controlIcon,\n useControlAppearance,\n type ControlIconOptions,\n type ControlOptions,\n} from '../input/control';\nimport {\n clampDate,\n fullIsoDay,\n lastIsoDay,\n parseIsoDate,\n presetIsoRange,\n toIsoDate,\n toIsoQuarter,\n toIsoWeek,\n type DateRange,\n type DateRangePreset,\n} from '../utils/data/date';\nimport { toElement } from '../utils/dom/element';\nimport { openSetter, type OpenChangeProps } from '../utils/dom/open-change';\nimport { defaultLabelledBy, mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport {\n toDateLimits,\n useDateLocale,\n type DateInput,\n type DateLimitProps,\n type DateValueTypes,\n} from './date-locale';\nimport { segmentFields, type DateFieldGranularity } from './date-segments';\nimport {\n dateUnitOf,\n isoToValue,\n isPeriodDisabled,\n isTimeGranularity,\n valueToIso,\n} from './DateField';\nimport { DateSegmentGroup, type DateSegmentGroupProps } from './DateSegmentGroup';\nimport {\n focusCalendar,\n renderPickerPresets,\n usePickerPopover,\n type PickerPopoverParts,\n} from './picker-popover';\nimport { QuarterCalendar } from './QuarterCalendar';\nimport { RangeCalendar, type RangeCalendarProps } from './RangeCalendar';\nimport { firstSegmentOf, segmentedFieldStyles, useFieldSegments } from './SegmentedField';\n\n/** 自定义的快捷区间(财年、上个结算周期) */\nexport interface DateRangeCustomPreset<V extends DateInput = string> {\n /** 按钮上的文字 */\n label: string;\n /** 区间;函数时每次打开按当时算(跟着今天变) */\n value: DateRange<V> | (() => DateRange<V>);\n}\n\n/** 未声明的属性落到外壳(role=\"group\")上 */\nexport interface DateRangePickerProps<V extends DateInput = string>\n extends\n PartProps<'div', 'role'>,\n ControlOptions,\n ControlIconOptions,\n DateLimitProps,\n PickerPopoverParts,\n OpenChangeProps {\n /** 区间(两端都含):父级写 _value={x};没填全时 null */\n _value?: DateRange<V> | null;\n /** 弹层是否打开:父级可写 _open={x} */\n _open?: boolean;\n /** 值为空、推不出类型时写回哪一种,默认 iso(字符串) */\n valueType?: keyof DateValueTypes;\n /** 精确到哪一段(同 DateField),默认 day;month、year 按月、按年,hour / minute / second 是日期时间区间 */\n granularity?: DateFieldGranularity;\n /**\n * 快捷区间,显示在日历旁边、夹到 min–max 之内:内置的名字(按今天与语言的一周第一天算),\n * 或自己的 `{ label, value }`(value 可以是函数,每次打开时按当时算)\n */\n presets?: readonly (DateRangePreset | DateRangeCustomPreset<V>)[];\n /** 日历并排显示几个月,默认 2 */\n visibleMonths?: number;\n /** 区间里允许夹着不可选的日期,默认 false */\n allowsUnavailableInRange?: boolean;\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过;不写时结束早于开始、超出范围、是不可选的日期也算 */\n invalid?: boolean;\n /** 有值时显示清空按钮 */\n clearable?: boolean;\n /** 表单提交时开始日期的 name(ISO 字符串) */\n startName?: string;\n /** 表单提交时结束日期的 name */\n endName?: string;\n /** 开始那组分段的部件属性 */\n propsStart?: Partial<DateSegmentGroupProps>;\n /** 结束那组分段的部件属性 */\n propsEnd?: Partial<DateSegmentGroupProps>;\n /** 两组之间的分隔符的部件属性 */\n propsSeparator?: PartProps<'span', 'aria-hidden'>;\n /** 清空按钮的部件属性 */\n propsClear?: Omit<Partial<PresetIconButtonProps>, 'onClick'>;\n /** 快捷区间那一列的部件属性 */\n propsPresets?: PartProps<'div', 'role'>;\n /** 区间日历的部件属性(值、范围由选择器给出) */\n propsCalendar?: Omit<\n Partial<RangeCalendarProps<V>>,\n 'value' | 'min' | 'max' | 'isDateUnavailable' | 'valueType' | 'onPick'\n >;\n}\n\n/** DateRangePicker 的样式:separator、popover(快捷区间的样式见 pickerPresetStyles) */\nexport const dateRangePickerStyles = css.create({\n separator: { flexShrink: 0, paddingInline: '_xs', color: '_textMuted' },\n popover: { display: 'flex', alignItems: 'flex-start', gap: '_sm', padding: '_sm' },\n});\n\n/** 自定义快捷区间的值 → ISO 日期区间(DateValue 取年月日) */\nfunction isoRangeOf<V extends DateInput>(\n value: DateRange<V> | (() => DateRange<V>),\n): DateRange<string> {\n const range = typeof value === 'function' ? value() : value;\n const iso = (input: DateInput) =>\n typeof input === 'string' ? input.slice(0, 10) : toIsoDate(input);\n return { start: iso(range.start), end: iso(range.end) };\n}\n\n/** 日期区间选择器:两组分段 + 弹出的区间日历与快捷区间 */\nexport const DateRangePicker = _component(\n <V extends DateInput>({\n _value: value = _bindable<DateRange<V> | null>(null),\n _open: open = _bindable(false),\n onOpenChange,\n valueType,\n granularity = 'day',\n min,\n max,\n isDateUnavailable,\n presets,\n visibleMonths = 2,\n allowsUnavailableInRange = false,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n clearable = false,\n startName,\n endName,\n placement,\n id,\n propsStart,\n propsEnd,\n propsSeparator,\n propsClear,\n icon,\n propsIcon,\n propsButton,\n propsPopover,\n propsPresets,\n propsCalendar,\n ...rest\n }: DateRangePickerProps<V>) => {\n const lang = useLang();\n const locale = useDateLocale();\n const generatedId = useId();\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n const editable = () => !control().disabled && !control().readonly;\n const limits = _derived(toDateLimits(locale, { min, max, isDateUnavailable }));\n let startGroup = _state.raw<HTMLElement | null>(null);\n let endGroup = _state.raw<HTMLElement | null>(null);\n const setOpen = openSetter(\n () => open,\n (next) => (open = next),\n () => onOpenChange,\n );\n\n const picker = usePickerPopover(\n () => ({\n open,\n placement,\n editable: editable(),\n label: lang.datePickerOpen,\n size: appearance().size,\n }),\n { toggle: setOpen, shown: focusCalendar },\n );\n\n // 两端各自的 ISO 字符串(按 granularity 的形式):只填了一端时值仍是 null,这里记着填了的那一端\n const toIso = (date: DateInput) => valueToIso(date, granularity);\n let start = _state<string | null>(null);\n let end = _state<string | null>(null);\n // 自己写回的值不再同步回两端(否则删掉一端时,写回的 null 会把另一端也清掉)\n let written: DateRange<V> | null | undefined;\n // 值清空后再填:仍按清空前的类型写回\n let lastLike: V | undefined;\n watch(\n () => value,\n (next) => {\n if (next === written) return;\n start = next ? toIso(next.start) : null;\n end = next ? toIso(next.end) : null;\n },\n { immediate: true },\n );\n\n function commit() {\n lastLike = value?.start ?? lastLike;\n const like = (iso: string) => isoToValue(iso, lastLike, granularity, valueType) as V;\n written = start && end ? { start: like(start), end: like(end) } : null;\n if (written !== null || value !== null) value = written;\n }\n\n const startSegments = useFieldSegments(\n () => ({ fields: segmentFields(granularity), value: start, readonly: !editable() }),\n (iso) => {\n start = iso;\n commit();\n },\n // 开始那组最后一段输入满了:焦点进结束那组\n (direction) => direction === 1 && firstSegmentOf(endGroup)?.focus(),\n );\n const endSegments = useFieldSegments(\n () => ({ fields: segmentFields(granularity), value: end, readonly: !editable() }),\n (iso) => {\n end = iso;\n commit();\n },\n // 结束那组第一段删空后再删:回到开始那组的最后一段\n (direction) => {\n if (direction !== -1) return;\n const segments = startGroup?.querySelectorAll<HTMLElement>('[role=\"spinbutton\"]');\n segments?.[segments.length - 1]?.focus();\n },\n );\n\n const outOfRange = (iso: string | null) =>\n iso != null && isPeriodDisabled(iso, granularity, limits, locale);\n\n /** 整天的区间 → 按 granularity 的形式:月、年截短;带时间时开始补 00:00、结束补 23:59(已经填了的时间不变) */\n function fromDays(range: DateRange<string>): DateRange<string> {\n if (granularity === 'year')\n return { start: range.start.slice(0, 4), end: range.end.slice(0, 4) };\n if (granularity === 'month')\n return { start: range.start.slice(0, 7), end: range.end.slice(0, 7) };\n if (granularity === 'quarter' || granularity === 'week') {\n const period = granularity === 'quarter' ? toIsoQuarter : toIsoWeek;\n return {\n start: period(parseIsoDate(range.start)!),\n end: period(parseIsoDate(range.end)!),\n };\n }\n if (!isTimeGranularity(granularity)) return range;\n const timeOf = (iso: string | null, fallback: string) =>\n iso != null && iso.length > 10 ? iso.slice(10) : fallback;\n const endTime = { hour: 'T23:00', minute: 'T23:59', second: 'T23:59:59' }[granularity];\n return {\n start: range.start + timeOf(start, granularity === 'second' ? 'T00:00:00' : 'T00:00'),\n end: range.end + timeOf(end, endTime),\n };\n }\n\n // 区间日历用整天的 ISO 日期:按月、按年、按周时是整段(开始那段的第一天到结束那段的最后一天)\n const calendarRange = (): DateRange<string> | null =>\n start == null || end == null ? null : { start: fullIsoDay(start), end: lastIsoDay(end) };\n\n /** 季度面板选好了区间('YYYY-Qn') */\n function pickQuarters(range: DateRange<string> | null) {\n if (range == null) return;\n start = range.start;\n end = range.end;\n commit();\n }\n\n /** 日历选好了区间:换回 granularity 的形式;带时间时焦点去开始的“时”接着输入 */\n function pickRange(range: DateRange<string> | null) {\n if (range == null) return;\n const next = fromDays(range);\n start = next.start;\n end = next.end;\n commit();\n }\n\n function clear() {\n startSegments.clear();\n endSegments.clear();\n start = null;\n end = null;\n commit();\n firstSegmentOf(startGroup)?.focus();\n }\n\n /** 点外壳空白处:开始没填全时去开始那组,否则去结束那组 */\n const firstEmpty = () =>\n start == null ? firstSegmentOf(startGroup) : firstSegmentOf(endGroup);\n\n /** 快捷区间夹到 min–max 之内:今天之后不能选时,“本月”就是本月 1 日到今天 */\n function presetValue(preset: DateRangePreset | DateRangeCustomPreset<V>): DateRange<string> {\n const range =\n typeof preset === 'string'\n ? presetIsoRange(preset, locale.week, locale.timeZone)\n : isoRangeOf(preset.value);\n const clamp = (iso: string) => toIsoDate(clampDate(parseIsoDate(iso)!, limits));\n return { start: clamp(range.start), end: clamp(range.end) };\n }\n\n function pickPreset(preset: DateRangePreset | DateRangeCustomPreset<V>) {\n const range = fromDays(presetValue(preset));\n start = range.start;\n end = range.end;\n commit();\n setOpen(false, 'select');\n }\n\n return () => {\n const state = control();\n const base = state.id ?? generatedId;\n const ids = { start: `${base}-start-label`, end: `${base}-end-label` };\n const reversed = start != null && end != null && end < start;\n const bad = state.invalid || reversed || outOfRange(start) || outOfRange(end);\n const filled = start != null || end != null || startSegments.partial || endSegments.partial;\n // 两组的名称:字段的标签 + “开始日期” / “结束日期”\n const labelledBy = (own: string) => [state.labelledBy, own].filter(Boolean).join(' ');\n const group = (side: 'start' | 'end') => {\n const isStart = side === 'start';\n return (\n <DateSegmentGroup\n {...mergePartProps<DateSegmentGroupProps>(\n {\n // 开始那组按内容宽,结束那组占满剩下的宽度:读起来是“开始 – 结束”,空白在最后\n sx: isStart ? undefined : segmentedFieldStyles.input,\n segments: isStart ? startSegments : endSegments,\n labelledBy: labelledBy(ids[side]),\n describedBy: state.describedBy,\n },\n isStart ? propsStart : propsEnd,\n {\n ref: (element: unknown) => {\n const found = toElement(element);\n if (isStart) startGroup = found;\n else endGroup = found;\n },\n id: isStart ? base : `${base}-end`,\n segments: isStart ? startSegments : endSegments,\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n invalid: bad,\n onKeydown: picker.onKeydown,\n },\n )}\n />\n );\n };\n const s = controlParts(appearance(), { ...state, invalid: bad });\n return (\n <>\n <div\n {...mergeAttrs<'div'>(\n {\n ...s.root,\n 'aria-labelledby': defaultLabelledBy(rest, state.labelledBy),\n },\n rest,\n {\n ref: picker.anchorRef,\n role: 'group',\n 'aria-disabled': state.disabled || undefined,\n onPointerdown: state.disabled ? undefined : focusOnShell(firstEmpty),\n },\n )}\n data-invalid={bad || undefined}\n data-disabled={state.disabled || undefined}\n >\n {controlIcon(s, icon, propsIcon)}\n <VisuallyHidden id={ids.start}>{lang.dateRangeStart}</VisuallyHidden>\n <VisuallyHidden id={ids.end}>{lang.dateRangeEnd}</VisuallyHidden>\n {group('start')}\n <span\n {...mergeAttrs<'span'>({ sx: dateRangePickerStyles.separator }, propsSeparator)}\n aria-hidden=\"true\"\n >\n –\n </span>\n {group('end')}\n {clearable && filled && editable() && controlClear(s, propsClear, clear)}\n {picker.button(CalendarRange, propsButton)}\n <FormValue name={startName} value={start} disabled={state.disabled} />\n <FormValue name={endName} value={end} disabled={state.disabled} />\n </div>\n {picker.panel(\n dateRangePickerStyles.popover,\n propsPopover,\n open && [\n renderPickerPresets(\n (presets ?? []).map((preset) => {\n const range = presetValue(preset);\n return {\n key: typeof preset === 'string' ? preset : preset.label,\n label: typeof preset === 'string' ? lang.dateRangePreset[preset] : preset.label,\n active: (() => {\n const shown = fromDays(range);\n return shown.start === start && shown.end === end;\n })(),\n onPick: () => pickPreset(preset),\n };\n }),\n lang.dateRangePresets,\n propsPresets,\n ),\n granularity === 'quarter' ? (\n <QuarterCalendar\n mode=\"range\"\n _value={start != null && end != null ? { start, end } : null}\n onUpdate:_value={pickQuarters}\n min={min}\n max={max}\n aria-label={lang.datePickerOpen}\n onPick={() => setOpen(false, 'select')}\n />\n ) : (\n <RangeCalendar\n {...propsCalendar}\n onUpdate:_value={pickRange}\n _value={calendarRange()}\n granularity={dateUnitOf(granularity)}\n min={min}\n max={max}\n isDateUnavailable={isDateUnavailable}\n visibleMonths={visibleMonths}\n allowsUnavailableInRange={allowsUnavailableInRange}\n // 按周:按 ISO 8601 的周排(周一开始),行首是第几周\n {...(granularity === 'week' && { firstDayOfWeek: 1, showWeekNumbers: true })}\n onPick={() => {\n setOpen(false, 'select');\n // 带时间时接着输入时间:焦点去开始那组的“时”\n if (isTimeGranularity(granularity))\n startGroup?.querySelector<HTMLElement>('[data-type=\"hour\"]')?.focus();\n }}\n />\n ),\n ],\n )}\n </>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8IA,IAAa,wBAAwB,IAAI,OAAO;CAC9C,WAAW;EAAE,YAAY;EAAG,eAAe;EAAO,OAAO;CAAa;CACtE,SAAS;EAAE,SAAS;EAAQ,YAAY;EAAc,KAAK;EAAO,SAAS;CAAM;AACnF,CAAC;;AAGD,SAAS,WACP,OACmB;CACnB,MAAM,QAAQ,OAAO,UAAU,aAAa,MAAM,IAAI;CACtD,MAAM,OAAO,UACX,OAAO,UAAU,WAAW,MAAM,MAAM,GAAG,EAAE,IAAI,UAAU,KAAK;CAClE,OAAO;EAAE,OAAO,IAAI,MAAM,KAAK;EAAG,KAAK,IAAI,MAAM,GAAG;CAAE;AACxD;;AAGA,IAAa,kBAAkB,0BAC7B,QAAA,SAmC+B;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,QAAAA,SAAA,QAAA,gBAlCkB,MAAI,KAAA,IAAA;CAAA,MAAA,OAAAA,SAAA,QAAA,eAC3B,OAAK,KAAA,IAAA;CAAA,MAAA,eAAAC,aAAA,QAAA,cAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,eAGf,KAAK;CAAA,MAAA,MAAAA,aAAA,QAAA,KAAA;CAAA,MAAA,MAAAA,aAAA,QAAA,KAAA;CAAA,MAAA,oBAAAA,aAAA,QAAA,mBAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,gBAAAA,aAAA,QAAA,iBAKH,CAAC;CAAA,MAAA,2BAAAA,aAAA,QAAA,4BACU,KAAK;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,OAAAA,aAAA,QAAA,MAAA;CAAA,MAAA,SAAAA,aAAA,QAAA,QAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,aAQpB,KAAK;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,KAAAA,aAAA,QAAA,IAAA;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,iBAAAA,aAAA,QAAA,gBAAA;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAAA,OAAAA,aAAA,QAAA,MAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAAA,eAAAA,aAAA,QAAA,cAAA;CAAA,MAAA,eAAAA,aAAA,QAAA,cAAA;CAAA,MAAA,gBAAAA,aAAA,QAAA,eAAA;CAAA,MAed,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,MAAM,OAAO,QAAQ;CACrB,MAAM,SAAS,cAAc;CAC7B,MAAM,cAAc,MAAM;CAC1B,MAAM,aAAa,4BAA4B;EAAE,SAAO,QAAA;EAAE,MAAI,KAAA;EAAE,QAAM,OAAA;CAAC,EAAE;CACzE,MAAM,UAAU,uBAAuB;EAAE,IAAE,GAAA;EAAE,SAAO,QAAA;EAAE,UAAQ,SAAA;EAAE,UAAQ,SAAA;EAAE,UAAQ,SAAA;CAAC,EAAE;CACrF,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;CACzD,MAAM,SAAMC,eAAY,aAAa,QAAQ;EAAE,KAAG,IAAA;EAAE,KAAG,IAAA;EAAE,mBAAiB,kBAAA;CAAC,CAAC,CAAC;CAC7E,IAAI,aAAUC,WAAkC,IAAI;CACpD,IAAI,WAAQA,WAAkC,IAAI;CAClD,MAAM,UAAU,iBACd,KAAA,QACC,SAAU,KAAA,QAAO,YAClB,aAAA,KACF;CAEA,MAAM,SAAS,wBACN;EACL,MAAI,KAAA;EACJ,WAAS,UAAA;EACT,UAAU,SAAS;EACnB,OAAO,KAAK;EACZ,MAAM,WAAW,CAAC,CAAC;CACrB,IACA;EAAE,QAAQ;EAAS,OAAO;CAAc,CAC1C;CAGA,MAAM,SAAS,SAAoB,WAAW,MAAI,YAAA,KAAa;CAC/D,IAAI,QAAKC,IAAyB,IAAI;CACtC,IAAI,MAAGA,IAAyB,IAAI;CAEpC,IAAI;CAEJ,IAAI;CACJ,YACE,MAAA,QACC,SAAS;EACR,IAAI,SAAS,SAAS;EACtB,MAAA,QAAQ,OAAO,MAAM,KAAK,KAAK,IAAI;EACnC,IAAA,QAAM,OAAO,MAAM,KAAK,GAAG,IAAI;CACjC,GACA,EAAE,WAAW,KAAK,CACpB;CAEA,SAAS,SAAS;EAChB,WAAW,MAAA,OAAO,SAAS;EAC3B,MAAM,QAAQ,QAAgB,WAAW,KAAK,UAAQ,YAAA,OAAA,UAAA,KAAwB;EAC9E,UAAU,MAAA,SAAA,IAAA,QAAe;GAAE,OAAO,KAAI,MAAA,KAAM;GAAG,KAAK,KAAI,IAAA,KAAI;EAAE,IAAI;EAClE,IAAI,YAAY,QAAQ,MAAA,UAAU,MAAM,MAAA,QAAQ;CAClD;CAEA,MAAM,gBAAgB,wBACb;EAAE,QAAQ,cAAa,YAAA,KAAY;EAAG,OAAK,MAAA;EAAS,UAAU,CAAC,SAAS;CAAE,KAChF,QAAQ;EACP,MAAA,QAAQ;EACR,OAAO;CACT,IAEC,cAAc,cAAc,KAAK,eAAc,SAAA,KAAS,CAAC,EAAE,MAAM,CACpE;CACA,MAAM,cAAc,wBACX;EAAE,QAAQ,cAAa,YAAA,KAAY;EAAG,OAAK,IAAA;EAAO,UAAU,CAAC,SAAS;CAAE,KAC9E,QAAQ;EACP,IAAA,QAAM;EACN,OAAO;CACT,IAEC,cAAc;EACb,IAAI,cAAc,IAAI;EACtB,MAAM,WAAW,WAAA,OAAY,iBAA8B,uBAAqB;EAChF,WAAW,SAAS,SAAS,EAAE,EAAE,MAAM;CACzC,CACF;CAEA,MAAM,cAAc,QAClB,OAAO,QAAQ,iBAAiB,KAAG,YAAA,OAAA,OAAA,OAAuB,MAAM;;CAGlE,SAAS,SAAS,OAA6C;EAC7D,IAAI,YAAA,UAAgB,QAClB,OAAO;GAAE,OAAO,MAAM,MAAM,MAAM,GAAG,CAAC;GAAG,KAAK,MAAM,IAAI,MAAM,GAAG,CAAC;EAAE;EACtE,IAAI,YAAA,UAAgB,SAClB,OAAO;GAAE,OAAO,MAAM,MAAM,MAAM,GAAG,CAAC;GAAG,KAAK,MAAM,IAAI,MAAM,GAAG,CAAC;EAAE;EACtE,IAAI,YAAA,UAAgB,aAAa,YAAA,UAAgB,QAAQ;GACvD,MAAM,SAAS,YAAA,UAAgB,YAAY,eAAe;GAC1D,OAAO;IACL,OAAO,OAAO,aAAa,MAAM,KAAK,CAAE;IACxC,KAAK,OAAO,aAAa,MAAM,GAAG,CAAE;GACtC;EACF;EACA,IAAI,CAAC,kBAAiB,YAAA,KAAY,GAAG,OAAO;EAC5C,MAAM,UAAU,KAAoB,aAClC,OAAO,QAAQ,IAAI,SAAS,KAAK,IAAI,MAAM,EAAE,IAAI;EACnD,MAAM,UAAU;GAAE,MAAM;GAAU,QAAQ;GAAU,QAAQ;EAAY,EAAC,YAAA;EACzE,OAAO;GACL,OAAO,MAAM,QAAQ,OAAM,MAAA,OAAQ,YAAA,UAAgB,WAAW,cAAc,QAAQ;GACpF,KAAK,MAAM,MAAM,OAAM,IAAA,OAAM,OAAO;EACtC;CACF;CAGA,MAAM,sBACJ,MAAA,SAAS,QAAQ,IAAA,SAAO,OAAO,OAAO;EAAE,OAAO,WAAU,MAAA,KAAM;EAAG,KAAK,WAAU,IAAA,KAAI;CAAE;;CAGzF,SAAS,aAAa,OAAiC;EACrD,IAAI,SAAS,MAAM;EACnB,MAAA,QAAQ,MAAM;EACd,IAAA,QAAM,MAAM;EACZ,OAAO;CACT;;CAGA,SAAS,UAAU,OAAiC;EAClD,IAAI,SAAS,MAAM;EACnB,MAAM,OAAO,SAAS,KAAK;EAC3B,MAAA,QAAQ,KAAK;EACb,IAAA,QAAM,KAAK;EACX,OAAO;CACT;CAEA,SAAS,QAAQ;EACf,cAAc,MAAM;EACpB,YAAY,MAAM;EAClB,MAAA,QAAQ;EACR,IAAA,QAAM;EACN,OAAO;EACP,eAAc,WAAA,KAAW,CAAC,EAAE,MAAM;CACpC;;CAGA,MAAM,mBACJ,MAAA,SAAS,OAAO,eAAc,WAAA,KAAW,IAAI,eAAc,SAAA,KAAS;;CAGtE,SAAS,YAAY,QAAuE;EAC1F,MAAM,QACJ,OAAO,WAAW,WACd,eAAe,QAAQ,OAAO,MAAM,OAAO,QAAQ,IACnD,WAAW,OAAO,KAAK;EAC7B,MAAM,SAAS,QAAgB,UAAU,UAAU,aAAa,GAAG,GAAC,OAAA,KAAS,CAAC;EAC9E,OAAO;GAAE,OAAO,MAAM,MAAM,KAAK;GAAG,KAAK,MAAM,MAAM,GAAG;EAAE;CAC5D;CAEA,SAAS,WAAW,QAAoD;EACtE,MAAM,QAAQ,SAAS,YAAY,MAAM,CAAC;EAC1C,MAAA,QAAQ,MAAM;EACd,IAAA,QAAM,MAAM;EACZ,OAAO;EACP,QAAQ,OAAO,QAAQ;CACzB;CAEA,aAAa;EACX,MAAM,QAAQ,QAAQ;EACtB,MAAM,OAAO,MAAM,MAAM;EACzB,MAAM,MAAM;GAAE,OAAO,GAAG,KAAI;GAAgB,KAAK,GAAG,KAAI;EAAa;EACrE,MAAM,WAAW,MAAA,SAAS,QAAQ,IAAA,SAAO,QAAQ,IAAA,QAAA,MAAA;EACjD,MAAM,MAAM,MAAM,WAAW,YAAY,WAAU,MAAA,KAAM,KAAK,WAAU,IAAA,KAAI;EAC5E,MAAM,SAAS,MAAA,SAAS,QAAQ,IAAA,SAAO,QAAQ,cAAc,WAAW,YAAY;EAEpF,MAAM,cAAc,QAAgB,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EACpF,MAAM,SAAS,SAA0B;GACvC,MAAM,UAAU,SAAS;GACzB,OAAAC,YAAA,kBAEQ,eACF;IAEE,IAAI,UAAU,KAAA,IAAY,qBAAqB;IAC/C,UAAU,UAAU,gBAAgB;IACpC,YAAY,WAAW,IAAI,KAAK;IAChC,aAAa,MAAM;GACrB,GACA,UAAO,WAAA,QAAA,SAAA,OACP;IACE,MAAM,YAAqB;KACzB,MAAM,QAAQ,UAAU,OAAO;KAC/B,IAAI,SAAS,WAAA,QAAa;UACrB,SAAA,QAAW;IAClB;IACA,IAAI,UAAU,OAAO,GAAG,KAAI;IAC5B,UAAU,UAAU,gBAAgB;IACpC,UAAU,MAAM;IAChB,UAAU,MAAM;IAChB,UAAU,MAAM;IAChB,SAAS;IACT,WAAW,OAAO;GACpB,CACF,GAAC,IAAA;EAGP;EACA,MAAM,IAAI,aAAa,WAAW,GAAG;GAAE,GAAG;GAAO,SAAS;EAAI,CAAC;EAC/D,OAAAA,YAAAC,UAAA,MAAA,CAAAD,YAAA,OAAAE,cAGU,WACF;GACE,GAAG,EAAE;GACL,mBAAmB,kBAAkB,MAAM,MAAM,UAAU;EAC7D,GACA,MACA;GACE,KAAK,OAAO;GACZ,MAAM;GACN,iBAAiB,MAAM,YAAY,KAAA;GACnC,eAAe,MAAM,WAAW,KAAA,IAAY,aAAa,UAAU;EACrE,CACF,GAAC;GAAA,gBACa,OAAO,KAAA;GAAS,iBACf,MAAM,YAAY,KAAA;EAAS,CAAA,GAAA;GAEzC,YAAY,GAAC,KAAA,OAAA,UAAA,KAAiB;GAACF,YAAA,gBAAA;IAAA,MACZ,IAAI;IAAK,OAAA;GAAA,GAAA;IAAA,eAAA,CAAG,KAAK,cAAc;IAAA,SAAA;GAAA,CAAA;GAAAA,YAAA,gBAAA;IAAA,MAC/B,IAAI;IAAG,OAAA;GAAA,GAAA;IAAA,eAAA,CAAG,KAAK,YAAY;IAAA,SAAA;GAAA,CAAA;GAC9C,MAAM,OAAO;GAACA,YAAA,QAAAE,cAET,WAAmB,EAAE,IAAI,sBAAsB,UAAU,GAAC,eAAA,KAAgB,GAAC,EAAA,eAAA,OAAA,CAAA,GAAA,CAAAC,gBAAA,GAAA,CAAA,CAAA;GAKhF,MAAM,KAAK;GACX,UAAA,SAAa,UAAU,SAAS,KAAK,aAAa,GAAC,WAAA,OAAc,KAAK;GACtE,OAAO,OAAO,eAAa,YAAA,KAAa;GAACH,YAAA,WAAA;IAAA,QAAA,UAAA;IAAA,SAAA,MAAA;IAAA,YACU,MAAM;GAAQ,GAAA,IAAA;GAAAA,YAAA,WAAA;IAAA,QAAA,QAAA;IAAA,SAAA,IAAA;IAAA,YAClB,MAAM;GAAQ,GAAA,IAAA;EAAA,CAAA,GAE/D,OAAO,MACN,sBAAsB,SAAO,aAAA,OAE7B,KAAA,SAAQ,CACN,qBACG,QAAA,SAAW,CAAA,EAAA,CAAI,KAAK,WAAW;GAC9B,MAAM,QAAQ,YAAY,MAAM;GAChC,OAAO;IACL,KAAK,OAAO,WAAW,WAAW,SAAS,OAAO;IAClD,OAAO,OAAO,WAAW,WAAW,KAAK,gBAAgB,UAAU,OAAO;IAC1E,eAAe;KACb,MAAM,QAAQ,SAAS,KAAK;KAC5B,OAAO,MAAM,UAAK,MAAA,SAAc,MAAM,QAAG,IAAA;IAC3C,EAAA,CAAG;IACH,cAAc,WAAW,MAAM;GACjC;EACF,CAAC,GACD,KAAK,kBAAgB,aAAA,KAEvB,GACA,YAAA,UAAgB,YAASA,YAAA,iBAAA;GAAA,QAAA;GAAA,UAGb,MAAA,SAAS,QAAQ,IAAA,SAAO,OAAO;IAAE,OAAK,MAAA;IAAE,KAAG,IAAA;GAAC,IAAI;GAAI,mBAC3C;GAAY,OAAA,IAAA;GAAA,OAAA,IAAA;GAAA,cAGjB,KAAK;GAAc,UAAA,OAAA,OAAA,OAAA,WACjB,QAAQ,OAAO,QAAQ;EAAC,GAAA,IAAA,IAAAA,YAAA,eAAAE,cAAA,cAAA,OAAA;GAAA,mBAKrB;GAAS,UAClB,cAAc;GAAC,eACV,WAAU,YAAA,KAAY;GAAC,OAAA,IAAA;GAAA,OAAA,IAAA;GAAA,qBAAA,kBAAA;GAAA,iBAAA,cAAA;GAAA,4BAAA,yBAAA;EAAA,GAO/B,YAAA,UAAgB,UAAU;GAAE,gBAAgB;GAAG,iBAAiB;EAAK,GAAC,EAAA,UAAA,OAAA,OAAA,OAAA,WAC7D;GACZ,QAAQ,OAAO,QAAQ;GAEvB,IAAI,kBAAiB,YAAA,KAAY,GAC/B,WAAA,OAAY,cAA2B,sBAAoB,CAAC,EAAE,MAAM;EACxE,GAAC,CAAA,GAAA,IAAA,CAEJ,CAEL,CAAC,CAAA;CAGP;AACF,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
|
|
@@ -4,7 +4,7 @@ import { isRtl } from "../utils/dom/direction.js";
|
|
|
4
4
|
import { handleSegmentKeydown } from "./date-segments.js";
|
|
5
5
|
import { createVNode, nextTick, ref, shallowRef, useId } from "vue";
|
|
6
6
|
import { _component, effect, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
7
|
-
import
|
|
7
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
8
8
|
//#region src/date/DateSegmentGroup.tsx
|
|
9
9
|
/** 角色与状态由组件管理 */
|
|
10
10
|
/** 每段由组件管理的属性 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateSegmentGroup.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/date/DateSegmentGroup.tsx"],"sourcesContent":["/**\n * 一组日期分段(年 / 月 / 日、时 : 分):每段是 role=\"spinbutton\" 的可编辑元素,分隔符对读屏隐藏。\n * 状态由调用方的 useDateSegments 给;DateField、TimeField 放在输入框外壳里用,DateRangePicker 在一个外壳里放两组。\n *\n * - 每段 contenteditable 加 inputmode=\"numeric\":手机上弹出数字键盘,输入法打的全角数字也收得到;\n * 文字由组件渲染,beforeinput 一律拦下交给 useDateSegments(输入法组合结束后重新渲染这一段);\n * - 每段在 Tab 顺序里(同 React Aria),←→ 也能换段;输入满了自动跳到下一段,焦点跟过去;\n * - 读屏名称是“字段名 + 段名”(aria-labelledby 指向外部标签与这一段),没填的段取值念“未填写”。\n *\n * 部件:Root(div role=\"group\",主元素)、Segment(每段)、Literal(分隔符)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, useId } from 'vue';\nimport { isRtl } from '../utils/dom/direction';\nimport { defaultLabelledBy, mergeAttrs, type PartProps } from '../utils/props';\nimport {\n handleSegmentKeydown,\n type DateSegment,\n type DateSegmentsState,\n type DateSegmentType,\n} from './date-segments';\nimport { useLang } from '../config/context';\n\n/** 角色与状态由组件管理 */\nexport type DateSegmentGroupManaged = 'role';\n\n/** 每段由组件管理的属性 */\nexport type DateSegmentManaged =\n | 'role'\n | 'id'\n | 'aria-label'\n | 'aria-labelledby'\n | 'tabindex'\n | 'contenteditable'\n | 'inputmode'\n | 'aria-valuenow'\n | 'aria-valuemin'\n | 'aria-valuemax'\n | 'aria-valuetext'\n | 'aria-required'\n | 'aria-invalid'\n | 'aria-readonly'\n | 'aria-disabled';\n\n/** 未声明的属性落到这一组(role=\"group\")上 */\nexport interface DateSegmentGroupProps extends PartProps<'div', DateSegmentGroupManaged> {\n /** 分段状态(useDateSegments) */\n segments: DateSegmentsState;\n /** 不可用:段不能聚焦 */\n disabled?: boolean;\n /** 只读:能聚焦、不能改 */\n readonly?: boolean;\n /** 必填(每段 aria-required) */\n required?: boolean;\n /** 校验未通过 */\n invalid?: boolean;\n /** 外部标签的 id:每段的读屏名称是“标签 + 段名” */\n labelledBy?: string;\n /** 说明与错误的 id(aria-describedby),给每一段 */\n describedBy?: string;\n /** 每段的部件属性:固定的对象,或按这一段返回 */\n propsSegment?:\n | PartProps<'span', DateSegmentManaged>\n | ((segment: DateSegment) => PartProps<'span', DateSegmentManaged>);\n /** 分隔符的部件属性 */\n propsLiteral?: PartProps<'span', 'aria-hidden'>;\n}\n\n/** DateSegmentGroup 的样式:root、segment、placeholder、literal */\nexport const dateSegmentStyles = css.create({\n root: {\n display: 'inline-flex',\n alignItems: 'center',\n minWidth: 0,\n paddingBlock: '_xs',\n whiteSpace: 'nowrap',\n fontVariantNumeric: 'tabular-nums',\n },\n segment: {\n boxSizing: 'content-box',\n paddingInline: '0.1em',\n borderRadius: '_xs',\n // 光标与选区由组件画(整段高亮),不显示浏览器的插入符\n caretColor: 'transparent',\n outlineStyle: 'none',\n textAlign: 'end',\n backgroundColor: { default: 'transparent', ':focus': '_accent' },\n color: { default: 'inherit', ':focus': '_accentContrast' },\n cursor: 'text',\n },\n // 占位文字是真正的文字(不是原生 placeholder),要满足 4.5:1:用 textMuted\n placeholder: { color: { default: '_textMuted', ':focus': '_accentContrast' } },\n literal: { color: '_textMuted', whiteSpace: 'pre' },\n disabled: { cursor: 'not-allowed' },\n});\n\n/** 一组日期分段 */\nexport const DateSegmentGroup = _component(\n ({\n segments,\n disabled = false,\n readonly = false,\n required = false,\n invalid = false,\n labelledBy,\n describedBy,\n propsSegment,\n propsLiteral,\n ...rest\n }: DateSegmentGroupProps) => {\n const lang = useLang();\n const id = useId();\n const elements = new Map<DateSegmentType, HTMLElement>();\n let root = _state.raw<HTMLElement | null>(null);\n // 输入法组合会直接改掉段里的文字(beforeinput 拦不住):结束后换个 key 重新渲染这一段\n let composed = _state(0);\n\n // 输入满了跳段、Backspace 删空退回上一段:焦点跟着 focusedSegment 走(只在焦点本来就在这组里时)\n _effect(() => {\n const type = segments.focusedSegment;\n const target = type && elements.get(type);\n if (!target || !root?.contains(document.activeElement) || document.activeElement === target)\n return;\n target.focus();\n });\n\n const editable = () => !disabled && !readonly;\n\n function onBeforeinput(event: InputEvent) {\n // 输入法组合中的文字取消不了,等 compositionend\n if (event.inputType === 'insertCompositionText') return;\n event.preventDefault();\n if (!editable()) return;\n if (event.inputType.startsWith('delete')) segments.backspace();\n else if (event.data) segments.type(event.data);\n }\n\n function onCompositionend(event: CompositionEvent) {\n const focused = segments.focusedSegment;\n if (editable() && event.data) segments.type(event.data);\n composed += 1;\n // 重新渲染后元素换了:焦点留在原来那段(或已经跳到的下一段)\n void nextTick(() => elements.get(segments.focusedSegment ?? focused!)?.focus());\n }\n\n function onKeydown(event: KeyboardEvent) {\n // Enter 同原生的输入框:写回打了一半的年份,再提交所在的表单(查询栏、对话框里的表单)\n if (event.key === 'Enter') {\n event.preventDefault();\n segments.commit();\n root?.closest('form')?.requestSubmit();\n return;\n }\n if (!root || disabled) return;\n // 只读时只能换段\n if (readonly && !['ArrowLeft', 'ArrowRight'].includes(event.key)) return;\n if (handleSegmentKeydown(segments, event, isRtl(root))) event.preventDefault();\n }\n\n function onFocusout(event: FocusEvent) {\n if (!root?.contains(event.relatedTarget as Node | null)) segments.setFocused(null);\n }\n\n return () => {\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: dateSegmentStyles.root,\n 'aria-labelledby': defaultLabelledBy(rest, labelledBy),\n 'aria-describedby': describedBy,\n },\n rest,\n // 整组标为不可用:标签(for 指向这一组)随之按不可用处理,不只是各段\n {\n ref: _toRef(root),\n role: 'group',\n 'aria-disabled': disabled || undefined,\n onFocusout,\n },\n )}\n data-invalid={invalid || undefined}\n data-disabled={disabled || undefined}\n >\n {segments.segments.map((segment, index) => {\n if (segment.type === 'literal') {\n return (\n <span\n key={`literal-${index}`}\n {...mergeAttrs<'span'>({ sx: dateSegmentStyles.literal }, propsLiteral)}\n aria-hidden=\"true\"\n >\n {segment.text}\n </span>\n );\n }\n const type = segment.type;\n const segmentId = `${id}-${type}`;\n const own = typeof propsSegment === 'function' ? propsSegment(segment) : propsSegment;\n return (\n <span\n key={`${type}-${composed}`}\n {...mergeAttrs<'span'>(\n {\n sx: [\n dateSegmentStyles.segment,\n segment.placeholder && dateSegmentStyles.placeholder,\n disabled && dateSegmentStyles.disabled,\n ],\n 'aria-describedby': describedBy,\n spellcheck: false,\n autocapitalize: 'off',\n autocorrect: 'off',\n enterkeyhint: 'next',\n },\n own,\n {\n // 每段的名称各不相同(年、月、日),由组件管理\n id: segmentId,\n 'aria-label': segment.label,\n 'aria-labelledby': labelledBy ? `${labelledBy} ${segmentId}` : undefined,\n ref: (element: unknown) => {\n if (element instanceof HTMLElement) elements.set(type, element);\n },\n role: 'spinbutton',\n tabindex: disabled ? -1 : 0,\n contenteditable: editable() ? 'true' : undefined,\n inputmode: type === 'dayPeriod' ? 'text' : 'numeric',\n 'aria-valuenow': segment.value ?? undefined,\n 'aria-valuemin': segment.min,\n 'aria-valuemax': segment.max,\n 'aria-valuetext': segment.placeholder ? lang.dateFieldEmpty : segment.text,\n 'aria-required': required || undefined,\n 'aria-invalid': invalid || undefined,\n 'aria-readonly': readonly || undefined,\n 'aria-disabled': disabled || undefined,\n onFocus: () => segments.setFocused(type),\n onBeforeinput,\n onCompositionend,\n onKeydown,\n // 粘贴的文字不进段里(会打乱渲染);需要时用输入\n onPaste: (event: ClipboardEvent) => event.preventDefault(),\n },\n )}\n data-type={type}\n data-placeholder={segment.placeholder || undefined}\n >\n {segment.text}\n </span>\n );\n })}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DateSegmentGroup.js","names":["_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/date/DateSegmentGroup.tsx"],"sourcesContent":["/**\n * 一组日期分段(年 / 月 / 日、时 : 分):每段是 role=\"spinbutton\" 的可编辑元素,分隔符对读屏隐藏。\n * 状态由调用方的 useDateSegments 给;DateField、TimeField 放在输入框外壳里用,DateRangePicker 在一个外壳里放两组。\n *\n * - 每段 contenteditable 加 inputmode=\"numeric\":手机上弹出数字键盘,输入法打的全角数字也收得到;\n * 文字由组件渲染,beforeinput 一律拦下交给 useDateSegments(输入法组合结束后重新渲染这一段);\n * - 每段在 Tab 顺序里(同 React Aria),←→ 也能换段;输入满了自动跳到下一段,焦点跟过去;\n * - 读屏名称是“字段名 + 段名”(aria-labelledby 指向外部标签与这一段),没填的段取值念“未填写”。\n *\n * 部件:Root(div role=\"group\",主元素)、Segment(每段)、Literal(分隔符)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, useId } from 'vue';\nimport { isRtl } from '../utils/dom/direction';\nimport { defaultLabelledBy, mergeAttrs, type PartProps } from '../utils/props';\nimport {\n handleSegmentKeydown,\n type DateSegment,\n type DateSegmentsState,\n type DateSegmentType,\n} from './date-segments';\nimport { useLang } from '../config/context';\n\n/** 角色与状态由组件管理 */\nexport type DateSegmentGroupManaged = 'role';\n\n/** 每段由组件管理的属性 */\nexport type DateSegmentManaged =\n | 'role'\n | 'id'\n | 'aria-label'\n | 'aria-labelledby'\n | 'tabindex'\n | 'contenteditable'\n | 'inputmode'\n | 'aria-valuenow'\n | 'aria-valuemin'\n | 'aria-valuemax'\n | 'aria-valuetext'\n | 'aria-required'\n | 'aria-invalid'\n | 'aria-readonly'\n | 'aria-disabled';\n\n/** 未声明的属性落到这一组(role=\"group\")上 */\nexport interface DateSegmentGroupProps extends PartProps<'div', DateSegmentGroupManaged> {\n /** 分段状态(useDateSegments) */\n segments: DateSegmentsState;\n /** 不可用:段不能聚焦 */\n disabled?: boolean;\n /** 只读:能聚焦、不能改 */\n readonly?: boolean;\n /** 必填(每段 aria-required) */\n required?: boolean;\n /** 校验未通过 */\n invalid?: boolean;\n /** 外部标签的 id:每段的读屏名称是“标签 + 段名” */\n labelledBy?: string;\n /** 说明与错误的 id(aria-describedby),给每一段 */\n describedBy?: string;\n /** 每段的部件属性:固定的对象,或按这一段返回 */\n propsSegment?:\n | PartProps<'span', DateSegmentManaged>\n | ((segment: DateSegment) => PartProps<'span', DateSegmentManaged>);\n /** 分隔符的部件属性 */\n propsLiteral?: PartProps<'span', 'aria-hidden'>;\n}\n\n/** DateSegmentGroup 的样式:root、segment、placeholder、literal */\nexport const dateSegmentStyles = css.create({\n root: {\n display: 'inline-flex',\n alignItems: 'center',\n minWidth: 0,\n paddingBlock: '_xs',\n whiteSpace: 'nowrap',\n fontVariantNumeric: 'tabular-nums',\n },\n segment: {\n boxSizing: 'content-box',\n paddingInline: '0.1em',\n borderRadius: '_xs',\n // 光标与选区由组件画(整段高亮),不显示浏览器的插入符\n caretColor: 'transparent',\n outlineStyle: 'none',\n textAlign: 'end',\n backgroundColor: { default: 'transparent', ':focus': '_accent' },\n color: { default: 'inherit', ':focus': '_accentContrast' },\n cursor: 'text',\n },\n // 占位文字是真正的文字(不是原生 placeholder),要满足 4.5:1:用 textMuted\n placeholder: { color: { default: '_textMuted', ':focus': '_accentContrast' } },\n literal: { color: '_textMuted', whiteSpace: 'pre' },\n disabled: { cursor: 'not-allowed' },\n});\n\n/** 一组日期分段 */\nexport const DateSegmentGroup = _component(\n ({\n segments,\n disabled = false,\n readonly = false,\n required = false,\n invalid = false,\n labelledBy,\n describedBy,\n propsSegment,\n propsLiteral,\n ...rest\n }: DateSegmentGroupProps) => {\n const lang = useLang();\n const id = useId();\n const elements = new Map<DateSegmentType, HTMLElement>();\n let root = _state.raw<HTMLElement | null>(null);\n // 输入法组合会直接改掉段里的文字(beforeinput 拦不住):结束后换个 key 重新渲染这一段\n let composed = _state(0);\n\n // 输入满了跳段、Backspace 删空退回上一段:焦点跟着 focusedSegment 走(只在焦点本来就在这组里时)\n _effect(() => {\n const type = segments.focusedSegment;\n const target = type && elements.get(type);\n if (!target || !root?.contains(document.activeElement) || document.activeElement === target)\n return;\n target.focus();\n });\n\n const editable = () => !disabled && !readonly;\n\n function onBeforeinput(event: InputEvent) {\n // 输入法组合中的文字取消不了,等 compositionend\n if (event.inputType === 'insertCompositionText') return;\n event.preventDefault();\n if (!editable()) return;\n if (event.inputType.startsWith('delete')) segments.backspace();\n else if (event.data) segments.type(event.data);\n }\n\n function onCompositionend(event: CompositionEvent) {\n const focused = segments.focusedSegment;\n if (editable() && event.data) segments.type(event.data);\n composed += 1;\n // 重新渲染后元素换了:焦点留在原来那段(或已经跳到的下一段)\n void nextTick(() => elements.get(segments.focusedSegment ?? focused!)?.focus());\n }\n\n function onKeydown(event: KeyboardEvent) {\n // Enter 同原生的输入框:写回打了一半的年份,再提交所在的表单(查询栏、对话框里的表单)\n if (event.key === 'Enter') {\n event.preventDefault();\n segments.commit();\n root?.closest('form')?.requestSubmit();\n return;\n }\n if (!root || disabled) return;\n // 只读时只能换段\n if (readonly && !['ArrowLeft', 'ArrowRight'].includes(event.key)) return;\n if (handleSegmentKeydown(segments, event, isRtl(root))) event.preventDefault();\n }\n\n function onFocusout(event: FocusEvent) {\n if (!root?.contains(event.relatedTarget as Node | null)) segments.setFocused(null);\n }\n\n return () => {\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: dateSegmentStyles.root,\n 'aria-labelledby': defaultLabelledBy(rest, labelledBy),\n 'aria-describedby': describedBy,\n },\n rest,\n // 整组标为不可用:标签(for 指向这一组)随之按不可用处理,不只是各段\n {\n ref: _toRef(root),\n role: 'group',\n 'aria-disabled': disabled || undefined,\n onFocusout,\n },\n )}\n data-invalid={invalid || undefined}\n data-disabled={disabled || undefined}\n >\n {segments.segments.map((segment, index) => {\n if (segment.type === 'literal') {\n return (\n <span\n key={`literal-${index}`}\n {...mergeAttrs<'span'>({ sx: dateSegmentStyles.literal }, propsLiteral)}\n aria-hidden=\"true\"\n >\n {segment.text}\n </span>\n );\n }\n const type = segment.type;\n const segmentId = `${id}-${type}`;\n const own = typeof propsSegment === 'function' ? propsSegment(segment) : propsSegment;\n return (\n <span\n key={`${type}-${composed}`}\n {...mergeAttrs<'span'>(\n {\n sx: [\n dateSegmentStyles.segment,\n segment.placeholder && dateSegmentStyles.placeholder,\n disabled && dateSegmentStyles.disabled,\n ],\n 'aria-describedby': describedBy,\n spellcheck: false,\n autocapitalize: 'off',\n autocorrect: 'off',\n enterkeyhint: 'next',\n },\n own,\n {\n // 每段的名称各不相同(年、月、日),由组件管理\n id: segmentId,\n 'aria-label': segment.label,\n 'aria-labelledby': labelledBy ? `${labelledBy} ${segmentId}` : undefined,\n ref: (element: unknown) => {\n if (element instanceof HTMLElement) elements.set(type, element);\n },\n role: 'spinbutton',\n tabindex: disabled ? -1 : 0,\n contenteditable: editable() ? 'true' : undefined,\n inputmode: type === 'dayPeriod' ? 'text' : 'numeric',\n 'aria-valuenow': segment.value ?? undefined,\n 'aria-valuemin': segment.min,\n 'aria-valuemax': segment.max,\n 'aria-valuetext': segment.placeholder ? lang.dateFieldEmpty : segment.text,\n 'aria-required': required || undefined,\n 'aria-invalid': invalid || undefined,\n 'aria-readonly': readonly || undefined,\n 'aria-disabled': disabled || undefined,\n onFocus: () => segments.setFocused(type),\n onBeforeinput,\n onCompositionend,\n onKeydown,\n // 粘贴的文字不进段里(会打乱渲染);需要时用输入\n onPaste: (event: ClipboardEvent) => event.preventDefault(),\n },\n )}\n data-type={type}\n data-placeholder={segment.placeholder || undefined}\n >\n {segment.text}\n </span>\n );\n })}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
@@ -12,7 +12,7 @@ import { calendarStyles } from "./CalendarView.js";
|
|
|
12
12
|
import { isPeriodDisabled } from "./DateField.js";
|
|
13
13
|
import { computed, createVNode, isVNode, nextTick, ref, shallowRef, useId } from "vue";
|
|
14
14
|
import { _component, bindable, mergeJsxProps, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
15
|
-
import
|
|
15
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
16
16
|
import { ChevronLeft, ChevronRight } from "@lucide/icons";
|
|
17
17
|
//#region src/date/QuarterCalendar.tsx
|
|
18
18
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QuarterCalendar.js","names":["_isVNode","_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_vue_computed","_vue_ref","_vtp_untrack","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/date/QuarterCalendar.tsx"],"sourcesContent":["/**\n * 季度面板:一年一页的四个季度(季度报表、考核周期),翻页换年;选一个季度,或选一段区间(先开始、再结束)。\n * DatePicker、DateRangePicker 的 granularity=\"quarter\" 弹出的就是它,也可以单独放在页面上。\n *\n * <QuarterCalendar _value={quarter} aria-label=\"考核季度\" /> // '2026-Q4'\n * <QuarterCalendar mode=\"range\" _value={range} aria-label=\"对比区间\" /> // { start: '2026-Q1', end: '2026-Q3' }\n *\n * 外观与 Calendar 的月份视图一致(同一套 calendarStyles):一行四格,区间连成一条,本季度带描边。\n * 焦点在当前季度上(roving tabindex):←→ 移动(到头时换年;从右到左排版时反过来),Home / End 到第一、第四季度,\n * Page Up / Down 换年,Enter / 空格选中;区间选到一半时悬停预览,Esc 取消。整段在 min–max 之外的季度不可用。\n *\n * 部件:Root(div,role=\"group\")、Header、Previous、Next(IconButton)、Heading、Grid(table)、Cell、CellButton。\n */\nimport { ChevronLeft, ChevronRight } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, useId } from 'vue';\nimport { buttonBaseStyles } from '../base/button-core';\nimport { IconButton } from '../base/IconButton';\nimport { VisuallyHidden, visuallyHiddenStyles } from '../base/VisuallyHidden';\nimport { useLang } from '../config/context';\nimport { toIsoQuarter, type DateRange } from '../utils/data/date';\nimport { isRtl } from '../utils/dom/direction';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { interactionTransitions } from '../utils/style/transitions';\nimport { calendarStyles } from './CalendarView';\nimport { isPeriodDisabled } from './DateField';\nimport { toDateLimits, useDateLocale, type DateInput } from './date-locale';\n\n/** 未声明的属性落到根元素上(aria-label 等) */\nexport interface QuarterCalendarProps extends PartProps<'div', 'role'> {\n /** 选一个季度(默认),或选一段区间 */\n mode?: 'single' | 'range';\n /** 单选时是 'YYYY-Qn',区间时是 `{ start, end }`:父级写 _value={x};没有时 null */\n _value?: string | DateRange<string> | null;\n /** 最早可选的日期:整个季度都早于它时不可用 */\n min?: DateInput;\n /** 最晚可选的日期:整个季度都晚于它时不可用 */\n max?: DateInput;\n /** 不可用:不能翻页、不能选 */\n disabled?: boolean;\n /** 只读:能翻页、移动焦点,不能改选择 */\n readonly?: boolean;\n /** 选好了(单选选了一个,区间选了结束):日期选择器据此关闭弹层 */\n onPick?: () => void;\n}\n\nconst quarterKey = (year: number, quarter: number) =>\n `${String(year).padStart(4, '0')}-Q${quarter}`;\nconst yearOf = (key: string) => Number(key.slice(0, 4));\nconst quarterOf = (key: string) => Number(key.slice(6));\n/** 两个季度排好序('YYYY-Qn' 按字符串比较就是先后) */\nconst ordered = (a: string, b: string): DateRange<string> =>\n a <= b ? { start: a, end: b } : { start: b, end: a };\n\n/** 季度面板:四个季度一页,单选或区间 */\nexport const QuarterCalendar = _component(\n ({\n mode = 'single',\n _value: value = _bindable<string | DateRange<string> | null>(null),\n min,\n max,\n disabled = false,\n readonly = false,\n onPick,\n ...rest\n }: QuarterCalendarProps) => {\n const lang = useLang();\n const locale = useDateLocale();\n const hintId = useId();\n const limits = _derived(toDateLimits(locale, { min, max }));\n const current = () => toIsoQuarter(locale.today());\n const chosen = () => (value == null ? null : typeof value === 'string' ? value : value.start);\n // 一开始显示已选(没有时是本季度)那一年,焦点也在它上面\n let focused = _state(chosen() ?? current());\n let year = _state(_untrack(yearOf(focused)));\n // 区间:选了开始、还没选结束时的开始,与悬停的季度(预览)\n let anchor = _state<string | null>(null);\n let hovered = _state<string | null>(null);\n let root = _state.raw<HTMLElement | null>(null);\n\n const off = (key: string) => isPeriodDisabled(key, 'quarter', limits, locale);\n const range = (): DateRange<string> | null => {\n if (mode !== 'range') return null;\n if (anchor) return ordered(anchor, hovered ?? anchor);\n return value != null && typeof value !== 'string' ? value : null;\n };\n\n function pick(key: string) {\n if (disabled || readonly || off(key)) return;\n focused = key;\n if (mode === 'single') {\n value = key;\n onPick?.();\n return;\n }\n if (!anchor) {\n anchor = key;\n hovered = key;\n return;\n }\n value = ordered(anchor, key);\n anchor = null;\n hovered = null;\n onPick?.();\n }\n\n /** 焦点移到 key(换到它那一年),再把 DOM 焦点交过去 */\n function moveTo(key: string) {\n focused = key;\n year = yearOf(key);\n if (anchor) hovered = key;\n void nextTick(() => root?.querySelector<HTMLElement>('[data-focused]')?.focus());\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (disabled || event.altKey || event.ctrlKey || event.metaKey) return;\n const quarter = quarterOf(focused);\n const at = yearOf(focused);\n const forward = root && isRtl(root) ? 'ArrowLeft' : 'ArrowRight';\n const backward = forward === 'ArrowRight' ? 'ArrowLeft' : 'ArrowRight';\n const step = (delta: number) => {\n const index = at * 4 + quarter - 1 + delta;\n moveTo(quarterKey(Math.floor(index / 4), (index % 4) + 1));\n };\n switch (event.key) {\n case forward:\n step(1);\n break;\n case backward:\n step(-1);\n break;\n case 'Home':\n moveTo(quarterKey(at, 1));\n break;\n case 'End':\n moveTo(quarterKey(at, 4));\n break;\n case 'PageUp':\n moveTo(quarterKey(at - 1, quarter));\n break;\n case 'PageDown':\n moveTo(quarterKey(at + 1, quarter));\n break;\n case 'Escape':\n // 取消选到一半的区间;没有时交给弹层关闭\n if (!anchor) return;\n anchor = null;\n hovered = null;\n break;\n default:\n return;\n }\n event.preventDefault();\n }\n\n return () => {\n const preview = range();\n const today = current();\n const heading = String(year);\n return (\n <div\n {...mergeAttrs<'div'>({ sx: calendarStyles.root }, rest, {\n ref: _toRef(root),\n role: 'group',\n })}\n data-view=\"quarter\"\n data-disabled={disabled || undefined}\n >\n <div {...css.attrs(calendarStyles.header)}>\n <IconButton\n icon={ChevronLeft}\n aria-label={lang.calendarPreviousYear}\n propsIcon={{ flipInRtl: true }}\n disabled={disabled}\n onClick={() => (year -= 1)}\n />\n <span {...css.attrs(calendarStyles.heading, calendarStyles.headingStatic)}>\n {lang.calendarYear(year)}\n </span>\n <IconButton\n icon={ChevronRight}\n aria-label={lang.calendarNextYear}\n propsIcon={{ flipInRtl: true }}\n disabled={disabled}\n onClick={() => (year += 1)}\n />\n </div>\n <table\n {...css.attrs(calendarStyles.grid, calendarStyles.periodGrid)}\n role=\"grid\"\n aria-label={lang.calendarYear(year)}\n aria-multiselectable={mode === 'range' || undefined}\n onKeydown={onKeydown}\n >\n <tbody>\n <tr>\n {[1, 2, 3, 4].map((quarter) => {\n const key = quarterKey(year, quarter);\n const disabledHere = disabled || off(key);\n const inRange = preview != null && key >= preview.start && key <= preview.end;\n const ends = preview != null && (key === preview.start || key === preview.end);\n const selected = mode === 'range' ? inRange : value === key;\n const isFocused = key === focused || (yearOf(focused) !== year && quarter === 1);\n return (\n <td\n key={key}\n role=\"gridcell\"\n aria-selected={selected}\n aria-disabled={disabledHere || undefined}\n {...css.attrs(\n calendarStyles.cell,\n inRange && calendarStyles.inRange,\n preview != null && key === preview.start && calendarStyles.rangeStart,\n preview != null && key === preview.end && calendarStyles.rangeEnd,\n )}\n >\n <button\n type=\"button\"\n tabindex={isFocused ? 0 : -1}\n aria-disabled={disabledHere || undefined}\n aria-describedby={anchor ? hintId : undefined}\n {...css.attrs(\n buttonBaseStyles.root,\n interactionTransitions.colors,\n calendarStyles.button,\n calendarStyles.periodButton,\n focusRingStyles.tight,\n key === today && calendarStyles.today,\n inRange && !ends && calendarStyles.middle,\n (mode === 'range' ? ends : selected) && calendarStyles.selected,\n disabledHere && calendarStyles.disabled,\n )}\n data-quarter={key}\n data-focused={isFocused || undefined}\n data-selected={selected || undefined}\n data-disabled={disabledHere || undefined}\n onClick={() => pick(key)}\n onFocus={() => (focused = key)}\n onPointerenter={() => anchor && (hovered = key)}\n >\n <span {...css.attrs(visuallyHiddenStyles.hidden)}>\n {lang.dateFieldPeriodPatterns.quarter\n .replace('{year}', String(year))\n .replace('{quarter}', String(quarter))}\n </span>\n <span aria-hidden=\"true\">{lang.calendarQuarter(quarter)}</span>\n </button>\n </td>\n );\n })}\n </tr>\n </tbody>\n </table>\n <VisuallyHidden aria-live=\"polite\">{heading}</VisuallyHidden>\n {anchor && <VisuallyHidden id={hintId}>{lang.calendarPickEnd}</VisuallyHidden>}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"QuarterCalendar.js","names":["_isVNode","_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_vue_computed","_vue_ref","_vtp_untrack","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/date/QuarterCalendar.tsx"],"sourcesContent":["/**\n * 季度面板:一年一页的四个季度(季度报表、考核周期),翻页换年;选一个季度,或选一段区间(先开始、再结束)。\n * DatePicker、DateRangePicker 的 granularity=\"quarter\" 弹出的就是它,也可以单独放在页面上。\n *\n * <QuarterCalendar _value={quarter} aria-label=\"考核季度\" /> // '2026-Q4'\n * <QuarterCalendar mode=\"range\" _value={range} aria-label=\"对比区间\" /> // { start: '2026-Q1', end: '2026-Q3' }\n *\n * 外观与 Calendar 的月份视图一致(同一套 calendarStyles):一行四格,区间连成一条,本季度带描边。\n * 焦点在当前季度上(roving tabindex):←→ 移动(到头时换年;从右到左排版时反过来),Home / End 到第一、第四季度,\n * Page Up / Down 换年,Enter / 空格选中;区间选到一半时悬停预览,Esc 取消。整段在 min–max 之外的季度不可用。\n *\n * 部件:Root(div,role=\"group\")、Header、Previous、Next(IconButton)、Heading、Grid(table)、Cell、CellButton。\n */\nimport { ChevronLeft, ChevronRight } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, useId } from 'vue';\nimport { buttonBaseStyles } from '../base/button-core';\nimport { IconButton } from '../base/IconButton';\nimport { VisuallyHidden, visuallyHiddenStyles } from '../base/VisuallyHidden';\nimport { useLang } from '../config/context';\nimport { toIsoQuarter, type DateRange } from '../utils/data/date';\nimport { isRtl } from '../utils/dom/direction';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { interactionTransitions } from '../utils/style/transitions';\nimport { calendarStyles } from './CalendarView';\nimport { isPeriodDisabled } from './DateField';\nimport { toDateLimits, useDateLocale, type DateInput } from './date-locale';\n\n/** 未声明的属性落到根元素上(aria-label 等) */\nexport interface QuarterCalendarProps extends PartProps<'div', 'role'> {\n /** 选一个季度(默认),或选一段区间 */\n mode?: 'single' | 'range';\n /** 单选时是 'YYYY-Qn',区间时是 `{ start, end }`:父级写 _value={x};没有时 null */\n _value?: string | DateRange<string> | null;\n /** 最早可选的日期:整个季度都早于它时不可用 */\n min?: DateInput;\n /** 最晚可选的日期:整个季度都晚于它时不可用 */\n max?: DateInput;\n /** 不可用:不能翻页、不能选 */\n disabled?: boolean;\n /** 只读:能翻页、移动焦点,不能改选择 */\n readonly?: boolean;\n /** 选好了(单选选了一个,区间选了结束):日期选择器据此关闭弹层 */\n onPick?: () => void;\n}\n\nconst quarterKey = (year: number, quarter: number) =>\n `${String(year).padStart(4, '0')}-Q${quarter}`;\nconst yearOf = (key: string) => Number(key.slice(0, 4));\nconst quarterOf = (key: string) => Number(key.slice(6));\n/** 两个季度排好序('YYYY-Qn' 按字符串比较就是先后) */\nconst ordered = (a: string, b: string): DateRange<string> =>\n a <= b ? { start: a, end: b } : { start: b, end: a };\n\n/** 季度面板:四个季度一页,单选或区间 */\nexport const QuarterCalendar = _component(\n ({\n mode = 'single',\n _value: value = _bindable<string | DateRange<string> | null>(null),\n min,\n max,\n disabled = false,\n readonly = false,\n onPick,\n ...rest\n }: QuarterCalendarProps) => {\n const lang = useLang();\n const locale = useDateLocale();\n const hintId = useId();\n const limits = _derived(toDateLimits(locale, { min, max }));\n const current = () => toIsoQuarter(locale.today());\n const chosen = () => (value == null ? null : typeof value === 'string' ? value : value.start);\n // 一开始显示已选(没有时是本季度)那一年,焦点也在它上面\n let focused = _state(chosen() ?? current());\n let year = _state(_untrack(yearOf(focused)));\n // 区间:选了开始、还没选结束时的开始,与悬停的季度(预览)\n let anchor = _state<string | null>(null);\n let hovered = _state<string | null>(null);\n let root = _state.raw<HTMLElement | null>(null);\n\n const off = (key: string) => isPeriodDisabled(key, 'quarter', limits, locale);\n const range = (): DateRange<string> | null => {\n if (mode !== 'range') return null;\n if (anchor) return ordered(anchor, hovered ?? anchor);\n return value != null && typeof value !== 'string' ? value : null;\n };\n\n function pick(key: string) {\n if (disabled || readonly || off(key)) return;\n focused = key;\n if (mode === 'single') {\n value = key;\n onPick?.();\n return;\n }\n if (!anchor) {\n anchor = key;\n hovered = key;\n return;\n }\n value = ordered(anchor, key);\n anchor = null;\n hovered = null;\n onPick?.();\n }\n\n /** 焦点移到 key(换到它那一年),再把 DOM 焦点交过去 */\n function moveTo(key: string) {\n focused = key;\n year = yearOf(key);\n if (anchor) hovered = key;\n void nextTick(() => root?.querySelector<HTMLElement>('[data-focused]')?.focus());\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (disabled || event.altKey || event.ctrlKey || event.metaKey) return;\n const quarter = quarterOf(focused);\n const at = yearOf(focused);\n const forward = root && isRtl(root) ? 'ArrowLeft' : 'ArrowRight';\n const backward = forward === 'ArrowRight' ? 'ArrowLeft' : 'ArrowRight';\n const step = (delta: number) => {\n const index = at * 4 + quarter - 1 + delta;\n moveTo(quarterKey(Math.floor(index / 4), (index % 4) + 1));\n };\n switch (event.key) {\n case forward:\n step(1);\n break;\n case backward:\n step(-1);\n break;\n case 'Home':\n moveTo(quarterKey(at, 1));\n break;\n case 'End':\n moveTo(quarterKey(at, 4));\n break;\n case 'PageUp':\n moveTo(quarterKey(at - 1, quarter));\n break;\n case 'PageDown':\n moveTo(quarterKey(at + 1, quarter));\n break;\n case 'Escape':\n // 取消选到一半的区间;没有时交给弹层关闭\n if (!anchor) return;\n anchor = null;\n hovered = null;\n break;\n default:\n return;\n }\n event.preventDefault();\n }\n\n return () => {\n const preview = range();\n const today = current();\n const heading = String(year);\n return (\n <div\n {...mergeAttrs<'div'>({ sx: calendarStyles.root }, rest, {\n ref: _toRef(root),\n role: 'group',\n })}\n data-view=\"quarter\"\n data-disabled={disabled || undefined}\n >\n <div {...css.attrs(calendarStyles.header)}>\n <IconButton\n icon={ChevronLeft}\n aria-label={lang.calendarPreviousYear}\n propsIcon={{ flipInRtl: true }}\n disabled={disabled}\n onClick={() => (year -= 1)}\n />\n <span {...css.attrs(calendarStyles.heading, calendarStyles.headingStatic)}>\n {lang.calendarYear(year)}\n </span>\n <IconButton\n icon={ChevronRight}\n aria-label={lang.calendarNextYear}\n propsIcon={{ flipInRtl: true }}\n disabled={disabled}\n onClick={() => (year += 1)}\n />\n </div>\n <table\n {...css.attrs(calendarStyles.grid, calendarStyles.periodGrid)}\n role=\"grid\"\n aria-label={lang.calendarYear(year)}\n aria-multiselectable={mode === 'range' || undefined}\n onKeydown={onKeydown}\n >\n <tbody>\n <tr>\n {[1, 2, 3, 4].map((quarter) => {\n const key = quarterKey(year, quarter);\n const disabledHere = disabled || off(key);\n const inRange = preview != null && key >= preview.start && key <= preview.end;\n const ends = preview != null && (key === preview.start || key === preview.end);\n const selected = mode === 'range' ? inRange : value === key;\n const isFocused = key === focused || (yearOf(focused) !== year && quarter === 1);\n return (\n <td\n key={key}\n role=\"gridcell\"\n aria-selected={selected}\n aria-disabled={disabledHere || undefined}\n {...css.attrs(\n calendarStyles.cell,\n inRange && calendarStyles.inRange,\n preview != null && key === preview.start && calendarStyles.rangeStart,\n preview != null && key === preview.end && calendarStyles.rangeEnd,\n )}\n >\n <button\n type=\"button\"\n tabindex={isFocused ? 0 : -1}\n aria-disabled={disabledHere || undefined}\n aria-describedby={anchor ? hintId : undefined}\n {...css.attrs(\n buttonBaseStyles.root,\n interactionTransitions.colors,\n calendarStyles.button,\n calendarStyles.periodButton,\n focusRingStyles.tight,\n key === today && calendarStyles.today,\n inRange && !ends && calendarStyles.middle,\n (mode === 'range' ? ends : selected) && calendarStyles.selected,\n disabledHere && calendarStyles.disabled,\n )}\n data-quarter={key}\n data-focused={isFocused || undefined}\n data-selected={selected || undefined}\n data-disabled={disabledHere || undefined}\n onClick={() => pick(key)}\n onFocus={() => (focused = key)}\n onPointerenter={() => anchor && (hovered = key)}\n >\n <span {...css.attrs(visuallyHiddenStyles.hidden)}>\n {lang.dateFieldPeriodPatterns.quarter\n .replace('{year}', String(year))\n .replace('{quarter}', String(quarter))}\n </span>\n <span aria-hidden=\"true\">{lang.calendarQuarter(quarter)}</span>\n </button>\n </td>\n );\n })}\n </tr>\n </tbody>\n </table>\n <VisuallyHidden aria-live=\"polite\">{heading}</VisuallyHidden>\n {anchor && <VisuallyHidden id={hintId}>{lang.calendarPickEnd}</VisuallyHidden>}\n </div>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAA,QAAA,GAAA;CAAA,OAAA,OAAA,MAAA,cAAA,OAAA,UAAA,SAAA,KAAA,CAAA,MAAA,qBAAA,CAAAA,QAAA,CAAA;AAAA;AAkBA,IAAM,cAAc,MAAc,YAChC,GAAG,OAAO,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG,EAAC,IAAK;AACvC,IAAM,UAAU,QAAgB,OAAO,IAAI,MAAM,GAAG,CAAC,CAAC;AACtD,IAAM,aAAa,QAAgB,OAAO,IAAI,MAAM,CAAC,CAAC;;AAEtD,IAAM,WAAW,GAAW,MAC1B,KAAK,IAAI;CAAE,OAAO;CAAG,KAAK;AAAE,IAAI;CAAE,OAAO;CAAG,KAAK;AAAE;;AAGrD,IAAa,kBAAkB,0BAC7B,QAAA,SAS4B;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,OAAAC,aAAA,QAAA,QARnB,QAAQ;CAAA,MAAA,QAAAC,SAAA,QAAA,gBAC8C,MAAI,KAAA,IAAA;CAAA,MAAA,MAAAD,aAAA,QAAA,KAAA;CAAA,MAAA,MAAAA,aAAA,QAAA,KAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,YAGtD,KAAK;CAAA,MAAA,WAAAA,aAAA,QAAA,YACL,KAAK;CAAA,MAAA,SAAAA,aAAA,QAAA,QAAA;CAAA,MAEb,OAAIE,UAAA,QAAA,MAAA,IAAA;CAEP,MAAM,OAAO,QAAQ;CACrB,MAAM,SAAS,cAAc;CAC7B,MAAM,SAAS,MAAM;CACrB,MAAM,SAAMC,eAAY,aAAa,QAAQ;EAAE,KAAG,IAAA;EAAE,KAAG,IAAA;CAAC,CAAC,CAAC;CAC1D,MAAM,gBAAgB,aAAa,OAAO,MAAM,CAAC;CACjD,MAAM,eAAgB,MAAA,SAAS,OAAO,OAAO,OAAA,MAAA,UAAiB,WAAQ,MAAA,QAAW,MAAA,MAAM;CAEvF,IAAI,UAAOC,IAAU,OAAO,KAAK,QAAQ,CAAC;CAC1C,IAAI,OAAIA,IAAAC,cAAmB,OAAM,QAAA,KAAQ,CAAC,CAAA;CAE1C,IAAI,SAAMD,IAAyB,IAAI;CACvC,IAAI,UAAOA,IAAyB,IAAI;CACxC,IAAI,OAAIE,WAAkC,IAAI;CAE9C,MAAM,OAAO,QAAgB,iBAAiB,KAAK,WAAS,OAAA,OAAU,MAAM;CAC5E,MAAM,cAAwC;EAC5C,IAAI,KAAA,UAAS,SAAS,OAAO;EAC7B,IAAA,OAAA,OAAY,OAAO,QAAO,OAAA,OAAS,QAAA,SAAA,OAAA,KAAiB;EACpD,OAAO,MAAA,SAAS,QAAQ,OAAA,MAAA,UAAiB,WAAQ,MAAA,QAAW;CAC9D;CAEA,SAAS,KAAK,KAAa;EACzB,IAAI,SAAA,SAAA,SAAA,SAAwB,IAAI,GAAG,GAAG;EACtC,QAAA,QAAU;EACV,IAAI,KAAA,UAAS,UAAU;GACrB,MAAA,QAAQ;GACR,OAAA,QAAS;GACT;EACF;EACA,IAAI,CAAA,OAAA,OAAS;GACX,OAAA,QAAS;GACT,QAAA,QAAU;GACV;EACF;EACA,MAAA,QAAQ,QAAO,OAAA,OAAS,GAAG;EAC3B,OAAA,QAAS;EACT,QAAA,QAAU;EACV,OAAA,QAAS;CACX;;CAGA,SAAS,OAAO,KAAa;EAC3B,QAAA,QAAU;EACV,KAAA,QAAO,OAAO,GAAG;EACjB,IAAA,OAAA,OAAY,QAAA,QAAU;EACtB,eAAoB,KAAA,OAAM,cAA2B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACjF;CAEA,SAAS,UAAU,OAAsB;EACvC,IAAI,SAAA,SAAY,MAAM,UAAU,MAAM,WAAW,MAAM,SAAS;EAChE,MAAM,UAAU,UAAS,QAAA,KAAQ;EACjC,MAAM,KAAK,OAAM,QAAA,KAAQ;EACzB,MAAM,UAAU,KAAA,SAAQ,MAAK,KAAA,KAAK,IAAI,cAAc;EACpD,MAAM,WAAW,YAAY,eAAe,cAAc;EAC1D,MAAM,QAAQ,UAAkB;GAC9B,MAAM,QAAQ,KAAK,IAAI,UAAU,IAAI;GACrC,OAAO,WAAW,KAAK,MAAM,QAAQ,CAAC,GAAI,QAAQ,IAAK,CAAC,CAAC;EAC3D;EACA,QAAQ,MAAM,KAAd;GACE,KAAK;IACH,KAAK,CAAC;IACN;GACF,KAAK;IACH,KAAK,EAAE;IACP;GACF,KAAK;IACH,OAAO,WAAW,IAAI,CAAC,CAAC;IACxB;GACF,KAAK;IACH,OAAO,WAAW,IAAI,CAAC,CAAC;IACxB;GACF,KAAK;IACH,OAAO,WAAW,KAAK,GAAG,OAAO,CAAC;IAClC;GACF,KAAK;IACH,OAAO,WAAW,KAAK,GAAG,OAAO,CAAC;IAClC;GACF,KAAK;IAEH,IAAI,CAAA,OAAA,OAAS;IACb,OAAA,QAAS;IACT,QAAA,QAAU;IACV;GACF,SACE;EACJ;EACA,MAAM,eAAe;CACvB;CAEA,aAAa;EACX,MAAM,UAAU,MAAM;EACtB,MAAM,QAAQ,QAAQ;EACtB,MAAM,UAAU,OAAM,KAAA,KAAK;EAC3B,OAAAC,YAAA,OAAAC,cAEQ,WAAkB,EAAE,IAAI,eAAe,KAAK,GAAG,MAAM;GACvD,KAAG;GACH,MAAM;EACR,CAAC,GAAC;GAAA,aAAA;GAAA,iBAEa,SAAA,SAAY,KAAA;EAAS,CAAA,GAAA;GAAAD,YAAA,OAE3B,IAAI,MAAM,eAAe,MAAM,GAAC;IAAAA,YAAA,YAAA;KAAA,QAE/B;KAAW,cACL,KAAK;KAAoB,aAAA,OAAA,OAAA,OAAA,KAC1B,EAAE,WAAW,KAAK;KAAC,YAAA,SAAA;KAAA,WAAA,OAAA,OAAA,OAAA,WAEd,KAAA,SAAQ;IAAE,GAAA,IAAA;IAAAA,YAAA,QAElB,IAAI,MAAM,eAAe,SAAS,eAAe,aAAa,GAAC,CACtE,KAAK,aAAY,KAAA,KAAK,CAAC,CAAA;IAAAA,YAAA,YAAA;KAAA,QAGlB;KAAY,cACN,KAAK;KAAgB,aAAA,OAAA,OAAA,OAAA,KACtB,EAAE,WAAW,KAAK;KAAC,YAAA,SAAA;KAAA,WAAA,OAAA,OAAA,OAAA,WAEd,KAAA,SAAQ;IAAE,GAAA,IAAA;GAAA,CAAA;GAAAA,YAAA,SAAAC,cAIxB,IAAI,MAAM,eAAe,MAAM,eAAe,UAAU,GAAC;IAAA,QAAA;IAAA,cAEjD,KAAK,aAAY,KAAA,KAAK;IAAC,wBACb,KAAA,UAAS,WAAW,KAAA;IAAS,aACxC;GAAS,CAAA,GAAA,CAAAD,YAAA,SAAA,MAAA,CAAAA,YAAA,MAAA,MAAA,CAIf;IAAC;IAAG;IAAG;IAAG;GAAC,CAAC,CAAC,KAAK,YAAY;IAC7B,MAAM,MAAM,WAAU,KAAA,OAAO,OAAO;IACpC,MAAM,eAAe,SAAA,SAAY,IAAI,GAAG;IACxC,MAAM,UAAU,WAAW,QAAQ,OAAO,QAAQ,SAAS,OAAO,QAAQ;IAC1E,MAAM,OAAO,WAAW,SAAS,QAAQ,QAAQ,SAAS,QAAQ,QAAQ;IAC1E,MAAM,WAAW,KAAA,UAAS,UAAU,UAAU,MAAA,UAAU;IACxD,MAAM,YAAY,QAAG,QAAA,SAAiB,OAAM,QAAA,KAAQ,MAAC,KAAA,SAAa,YAAY;IAC9E,OAAAA,YAAA,MAAAC,cAAA;KAAA,OAES;KAAG,QAAA;KAAA,iBAEO;KAAQ,iBACR,gBAAgB,KAAA;IAAS,GACpC,IAAI,MACN,eAAe,MACf,WAAW,eAAe,SAC1B,WAAW,QAAQ,QAAQ,QAAQ,SAAS,eAAe,YAC3D,WAAW,QAAQ,QAAQ,QAAQ,OAAO,eAAe,QAC3D,CAAC,GAAA,CAAAD,YAAA,UAAAC,cAAA;KAAA,QAAA;KAAA,YAIW,YAAY,IAAI;KAAE,iBACb,gBAAgB,KAAA;KAAS,oBACtB,OAAA,QAAS,SAAS,KAAA;IAAS,GACzC,IAAI,MACN,iBAAiB,MACjB,uBAAuB,QACvB,eAAe,QACf,eAAe,cACf,gBAAgB,OAChB,QAAQ,SAAS,eAAe,OAChC,WAAW,CAAC,QAAQ,eAAe,SAClC,KAAA,UAAS,UAAU,OAAO,aAAa,eAAe,UACvD,gBAAgB,eAAe,QACjC,GAAC;KAAA,gBACa;KAAG,gBACH,aAAa,KAAA;KAAS,iBACrB,YAAY,KAAA;KAAS,iBACrB,gBAAgB,KAAA;KAAS,iBACzB,KAAK,GAAG;KAAC,iBACR,QAAA,QAAU;KAAI,wBACR,OAAA,UAAW,QAAA,QAAU;IAAI,CAAA,GAAA,CAAAD,YAAA,QAErC,IAAI,MAAM,qBAAqB,MAAM,GAAC,CAC7C,KAAK,wBAAwB,QAC3B,QAAQ,UAAU,OAAM,KAAA,KAAK,CAAC,CAAC,CAC/B,QAAQ,aAAa,OAAO,OAAO,CAAC,CAAC,CAAA,GAAAA,YAAA,QAAA,EAAA,eAAA,OAAA,GAAA,CAEhB,KAAK,gBAAgB,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA;GAI/D,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA;GAAAA,YAAA,gBAAA,EAAA,aAAA,SAAA,GAAA,QAI4B,OAAO,IAAP,UAAO,EAAA,eAAA,CAAP,OAAO,EAAA,CAAA;GAC1C,OAAA,SAAAA,YAAA,gBAAA;IAAA,MAA8B;IAAM,OAAA;GAAA,GAAA;IAAA,eAAA,CAAG,KAAK,eAAe;IAAA,SAAA;GAAA,CAAA;EAAkB,CAAA;CAGpF;AACF,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
|
|
2
2
|
import type { VNodeChild } from 'vue';
|
|
3
3
|
import type { PresetIconButtonProps } from '../base/CloseButton';
|
|
4
4
|
import type { HourCycles } from '../config/lang/lang';
|
|
@@ -10,7 +10,7 @@ import { fieldsToIso, isoToFields, useDateSegments } from "./date-segments.js";
|
|
|
10
10
|
import { DateSegmentGroup } from "./DateSegmentGroup.js";
|
|
11
11
|
import { createVNode, shallowRef } from "vue";
|
|
12
12
|
import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
13
|
-
import
|
|
13
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
14
14
|
import { now } from "@internationalized/date";
|
|
15
15
|
//#region src/date/SegmentedField.tsx
|
|
16
16
|
/** 由组件管理:角色与关联 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentedField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/date/SegmentedField.tsx"],"sourcesContent":["/**\n * 分段输入框:输入框外壳(同 TextField)里放一组日期分段、可选的前置图标、清空按钮与尾部内容。\n * DateField、TimeField 是它的两种用法(只差有哪些段与怎样校验);日期选择器把打开日历的按钮放在 suffix 里。\n *\n * <SegmentedField fields={['hour', 'minute']} _value={time} />\n *\n * 值是 ISO 字符串(fieldsToIso);所有段都填了才写回,删掉一段写回 null。写了 name 时用隐藏的 input 随表单提交。\n * 点外壳的空白处时焦点进第一个没填的段。\n *\n * 部件:Root(外壳)、Input(DateSegmentGroup,主元素)、Segment、Literal、Icon、Clear。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { now } from '@internationalized/date';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport type { PresetIconButtonProps } from '../base/CloseButton';\nimport { useLang } from '../config/context';\nimport type { HourCycles } from '../config/lang/lang';\nimport { useFieldControl, useFormReset } from '../form/Field';\nimport { FormValue } from '../form/FormValue';\nimport {\n controlClear,\n controlParts,\n focusOnShell,\n controlIcon,\n useControlAppearance,\n type ControlIconOptions,\n type ControlOptions,\n} from '../input/control';\nimport { isoWeekOf } from '../utils/data/date';\nimport { toElement } from '../utils/dom/element';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { useDateLocale } from './date-locale';\nimport { fieldsToIso, isoToFields, useDateSegments, type DateSegmentType } from './date-segments';\nimport { DateSegmentGroup, type DateSegmentGroupProps } from './DateSegmentGroup';\n\n/** 由组件管理:角色与关联 */\nexport type SegmentedFieldManaged = 'role' | 'aria-describedby';\n\n/** 分段输入框共有的属性(DateField、TimeField 都有);未声明的属性落到这组分段上(主元素) */\nexport interface SegmentedFieldOptions\n extends\n PartProps<'div', SegmentedFieldManaged>,\n ControlOptions,\n ControlIconOptions,\n Pick<DateSegmentGroupProps, 'propsSegment' | 'propsLiteral'> {\n /** 12 / 24 小时制(有时的段时);不写时按语言 */\n hourCycle?: keyof HourCycles;\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过;不写时值超出范围、是不可选的日期也算 */\n invalid?: boolean;\n /** 表单提交时的 name(用隐藏的 input,值是 ISO 字符串) */\n name?: string;\n /** 有值时显示清空按钮 */\n clearable?: boolean;\n /** 框里最后的内容:日期选择器打开日历的按钮 */\n suffix?: VNodeChild;\n /** 外壳的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 清空按钮的部件属性 */\n propsClear?: Omit<Partial<PresetIconButtonProps>, 'onClick'>;\n}\n\n/** 未声明的属性落到这组分段上 */\nexport interface SegmentedFieldProps extends SegmentedFieldOptions {\n /** 值(ISO 字符串):父级写 _value={x};没填全时 null */\n _value?: string | null;\n /** 有哪些段,按年 → 秒的顺序(显示顺序按语言) */\n fields: readonly Exclude<DateSegmentType, 'dayPeriod'>[];\n /** 值超出范围、不可选(有值时调用):外壳显示出错 */\n outOfRange?: (value: string) => boolean;\n}\n\n/**\n * 一组分段的状态,按当前语言(段的顺序、小时制、占位文字,没填时占位的是此刻);值是 ISO 字符串,填全了才写回。\n * SegmentedField 与 DateRangePicker 的开始、结束两组分段用它。在组件 setup 里调用\n */\nexport function useFieldSegments(\n read: () => {\n fields: readonly Exclude<DateSegmentType, 'dayPeriod'>[];\n value: string | null;\n hourCycle?: keyof HourCycles;\n readonly: boolean;\n },\n onChange: (value: string | null) => void,\n onExit?: (direction: 1 | -1) => void,\n) {\n const lang = useLang();\n const locale = useDateLocale();\n const segments = useDateSegments({\n fields: () => read().fields,\n locale: () => lang.code,\n hourCycle: () => read().hourCycle ?? lang.hourCycle,\n value: () => isoToFields(read().value, read().fields),\n onChange: (next) => onChange(next ? fieldsToIso(next, read().fields) : null),\n placeholderValue: () => {\n const current = now(locale.timeZone);\n // 选周时从这一周所属的年起步(12 月底的那周可能已经算明年的第 1 周)\n const week = isoWeekOf(current);\n return {\n year: read().fields.includes('week') ? week.year : current.year,\n month: current.month,\n day: current.day,\n quarter: Math.ceil(current.month / 3),\n week: week.week,\n hour: current.hour,\n minute: current.minute,\n second: 0,\n };\n },\n placeholders: () => lang.dateFieldPlaceholders,\n periodPatterns: () => lang.dateFieldPeriodPatterns,\n readonly: () => read().readonly,\n onExit,\n });\n useFormReset(() => segments.reset());\n return segments;\n}\n\n/** 一组分段里第一个没填的段(都填了时第一段):点外壳空白处、清空后焦点去这里 */\nexport const firstSegmentOf = (group: Element | null | undefined) =>\n group?.querySelector<HTMLElement>('[role=\"spinbutton\"][data-placeholder]') ??\n group?.querySelector<HTMLElement>('[role=\"spinbutton\"]') ??\n null;\n\n/** SegmentedField 的样式:input */\nexport const segmentedFieldStyles = css.create({\n // 分段占满剩下的宽度:清空按钮、尾部内容贴着外壳的结束边\n input: { flexGrow: 1 },\n});\n\n/** 分段输入框:外壳 + 一组日期分段 */\nexport const SegmentedField = _component(\n ({\n _value: value = _bindable<string | null>(null),\n fields,\n outOfRange,\n hourCycle,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n name,\n clearable = false,\n icon,\n suffix,\n id,\n propsRoot,\n propsIcon,\n propsClear,\n propsSegment,\n propsLiteral,\n ...rest\n }: SegmentedFieldProps) => {\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let group = _state.raw<HTMLElement | null>(null);\n\n const segments = useFieldSegments(\n () => ({\n fields,\n value,\n hourCycle,\n readonly: control().disabled || control().readonly,\n }),\n (next) => (value = next),\n );\n const firstSegment = () => firstSegmentOf(group);\n\n function clear() {\n segments.clear();\n value = null;\n firstSegment()?.focus();\n }\n\n return () => {\n const state = control();\n const bad = state.invalid || (value != null && (outOfRange?.(value) ?? false));\n const filled = value != null || segments.partial;\n const s = controlParts(appearance(), { ...state, invalid: bad });\n return (\n <div\n {...mergeAttrs<'div'>(s.root, propsRoot, {\n onPointerdown: state.disabled ? undefined : focusOnShell(firstSegment),\n })}\n data-invalid={bad || undefined}\n data-disabled={state.disabled || undefined}\n >\n {controlIcon(s, icon, propsIcon)}\n <DateSegmentGroup\n {...mergePartProps<DateSegmentGroupProps>(\n {\n sx: segmentedFieldStyles.input,\n segments,\n labelledBy: state.labelledBy,\n describedBy: state.describedBy,\n },\n rest,\n {\n ref: (instance: unknown) => (group = toElement(instance)),\n id: state.id,\n segments,\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n invalid: bad,\n propsSegment,\n propsLiteral,\n },\n )}\n />\n {clearable &&\n filled &&\n !state.disabled &&\n !state.readonly &&\n controlClear(s, propsClear, clear)}\n {suffix}\n <FormValue name={name} value={value} disabled={state.disabled} />\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SegmentedField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_createVNode","_mergeProps"],"sources":["../../src/date/SegmentedField.tsx"],"sourcesContent":["/**\n * 分段输入框:输入框外壳(同 TextField)里放一组日期分段、可选的前置图标、清空按钮与尾部内容。\n * DateField、TimeField 是它的两种用法(只差有哪些段与怎样校验);日期选择器把打开日历的按钮放在 suffix 里。\n *\n * <SegmentedField fields={['hour', 'minute']} _value={time} />\n *\n * 值是 ISO 字符串(fieldsToIso);所有段都填了才写回,删掉一段写回 null。写了 name 时用隐藏的 input 随表单提交。\n * 点外壳的空白处时焦点进第一个没填的段。\n *\n * 部件:Root(外壳)、Input(DateSegmentGroup,主元素)、Segment、Literal、Icon、Clear。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { now } from '@internationalized/date';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport type { PresetIconButtonProps } from '../base/CloseButton';\nimport { useLang } from '../config/context';\nimport type { HourCycles } from '../config/lang/lang';\nimport { useFieldControl, useFormReset } from '../form/Field';\nimport { FormValue } from '../form/FormValue';\nimport {\n controlClear,\n controlParts,\n focusOnShell,\n controlIcon,\n useControlAppearance,\n type ControlIconOptions,\n type ControlOptions,\n} from '../input/control';\nimport { isoWeekOf } from '../utils/data/date';\nimport { toElement } from '../utils/dom/element';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { useDateLocale } from './date-locale';\nimport { fieldsToIso, isoToFields, useDateSegments, type DateSegmentType } from './date-segments';\nimport { DateSegmentGroup, type DateSegmentGroupProps } from './DateSegmentGroup';\n\n/** 由组件管理:角色与关联 */\nexport type SegmentedFieldManaged = 'role' | 'aria-describedby';\n\n/** 分段输入框共有的属性(DateField、TimeField 都有);未声明的属性落到这组分段上(主元素) */\nexport interface SegmentedFieldOptions\n extends\n PartProps<'div', SegmentedFieldManaged>,\n ControlOptions,\n ControlIconOptions,\n Pick<DateSegmentGroupProps, 'propsSegment' | 'propsLiteral'> {\n /** 12 / 24 小时制(有时的段时);不写时按语言 */\n hourCycle?: keyof HourCycles;\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过;不写时值超出范围、是不可选的日期也算 */\n invalid?: boolean;\n /** 表单提交时的 name(用隐藏的 input,值是 ISO 字符串) */\n name?: string;\n /** 有值时显示清空按钮 */\n clearable?: boolean;\n /** 框里最后的内容:日期选择器打开日历的按钮 */\n suffix?: VNodeChild;\n /** 外壳的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 清空按钮的部件属性 */\n propsClear?: Omit<Partial<PresetIconButtonProps>, 'onClick'>;\n}\n\n/** 未声明的属性落到这组分段上 */\nexport interface SegmentedFieldProps extends SegmentedFieldOptions {\n /** 值(ISO 字符串):父级写 _value={x};没填全时 null */\n _value?: string | null;\n /** 有哪些段,按年 → 秒的顺序(显示顺序按语言) */\n fields: readonly Exclude<DateSegmentType, 'dayPeriod'>[];\n /** 值超出范围、不可选(有值时调用):外壳显示出错 */\n outOfRange?: (value: string) => boolean;\n}\n\n/**\n * 一组分段的状态,按当前语言(段的顺序、小时制、占位文字,没填时占位的是此刻);值是 ISO 字符串,填全了才写回。\n * SegmentedField 与 DateRangePicker 的开始、结束两组分段用它。在组件 setup 里调用\n */\nexport function useFieldSegments(\n read: () => {\n fields: readonly Exclude<DateSegmentType, 'dayPeriod'>[];\n value: string | null;\n hourCycle?: keyof HourCycles;\n readonly: boolean;\n },\n onChange: (value: string | null) => void,\n onExit?: (direction: 1 | -1) => void,\n) {\n const lang = useLang();\n const locale = useDateLocale();\n const segments = useDateSegments({\n fields: () => read().fields,\n locale: () => lang.code,\n hourCycle: () => read().hourCycle ?? lang.hourCycle,\n value: () => isoToFields(read().value, read().fields),\n onChange: (next) => onChange(next ? fieldsToIso(next, read().fields) : null),\n placeholderValue: () => {\n const current = now(locale.timeZone);\n // 选周时从这一周所属的年起步(12 月底的那周可能已经算明年的第 1 周)\n const week = isoWeekOf(current);\n return {\n year: read().fields.includes('week') ? week.year : current.year,\n month: current.month,\n day: current.day,\n quarter: Math.ceil(current.month / 3),\n week: week.week,\n hour: current.hour,\n minute: current.minute,\n second: 0,\n };\n },\n placeholders: () => lang.dateFieldPlaceholders,\n periodPatterns: () => lang.dateFieldPeriodPatterns,\n readonly: () => read().readonly,\n onExit,\n });\n useFormReset(() => segments.reset());\n return segments;\n}\n\n/** 一组分段里第一个没填的段(都填了时第一段):点外壳空白处、清空后焦点去这里 */\nexport const firstSegmentOf = (group: Element | null | undefined) =>\n group?.querySelector<HTMLElement>('[role=\"spinbutton\"][data-placeholder]') ??\n group?.querySelector<HTMLElement>('[role=\"spinbutton\"]') ??\n null;\n\n/** SegmentedField 的样式:input */\nexport const segmentedFieldStyles = css.create({\n // 分段占满剩下的宽度:清空按钮、尾部内容贴着外壳的结束边\n input: { flexGrow: 1 },\n});\n\n/** 分段输入框:外壳 + 一组日期分段 */\nexport const SegmentedField = _component(\n ({\n _value: value = _bindable<string | null>(null),\n fields,\n outOfRange,\n hourCycle,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n name,\n clearable = false,\n icon,\n suffix,\n id,\n propsRoot,\n propsIcon,\n propsClear,\n propsSegment,\n propsLiteral,\n ...rest\n }: SegmentedFieldProps) => {\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let group = _state.raw<HTMLElement | null>(null);\n\n const segments = useFieldSegments(\n () => ({\n fields,\n value,\n hourCycle,\n readonly: control().disabled || control().readonly,\n }),\n (next) => (value = next),\n );\n const firstSegment = () => firstSegmentOf(group);\n\n function clear() {\n segments.clear();\n value = null;\n firstSegment()?.focus();\n }\n\n return () => {\n const state = control();\n const bad = state.invalid || (value != null && (outOfRange?.(value) ?? false));\n const filled = value != null || segments.partial;\n const s = controlParts(appearance(), { ...state, invalid: bad });\n return (\n <div\n {...mergeAttrs<'div'>(s.root, propsRoot, {\n onPointerdown: state.disabled ? undefined : focusOnShell(firstSegment),\n })}\n data-invalid={bad || undefined}\n data-disabled={state.disabled || undefined}\n >\n {controlIcon(s, icon, propsIcon)}\n <DateSegmentGroup\n {...mergePartProps<DateSegmentGroupProps>(\n {\n sx: segmentedFieldStyles.input,\n segments,\n labelledBy: state.labelledBy,\n describedBy: state.describedBy,\n },\n rest,\n {\n ref: (instance: unknown) => (group = toElement(instance)),\n id: state.id,\n segments,\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n invalid: bad,\n propsSegment,\n propsLiteral,\n },\n )}\n />\n {clearable &&\n filled &&\n !state.disabled &&\n !state.readonly &&\n controlClear(s, propsClear, clear)}\n {suffix}\n <FormValue name={name} value={value} disabled={state.disabled} />\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|