@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":"Toast.js","names":["_isVNode","_vtp_readonlyProp","_createVNode","_mergeProps","_vtp_restProps","_vue_shallowRef","_vue_ref"],"sources":["../../src/feedback/Toast.tsx"],"sourcesContent":["/**\n * 通知(toast):操作结果的短暂提示,几秒后自动消失。控制器 + 显示区域(参考 Sonner、Radix Toast、React Aria Toast):\n *\n * // toaster.ts:应用里创建一次,组件内外(请求拦截器、store)都能导入使用\n * export const toaster = createToaster();\n * // App:放一个显示区域\n * <Toaster controller={toaster} placement=\"bottom-end\" />\n * // 任意位置\n * toaster.show({ tone: 'success', title: '已保存' }); // 或 toaster.success('已保存')\n * const id = toaster.show({ title: '已删除', action: <Button onClick={() => undo(id)}>撤销</Button> });\n * toaster.loading('正在导出', { id: 'export' }); …; toaster.success('导出完成', { id: 'export' }); // 同一个 id 换掉原来那条\n * await toaster.promise(upload(file), { loading: { title: '正在上传' }, success: { title: '上传完成' }, error: (e) => ({ title: String(e) }) });\n *\n * 控制器是普通对象,不经 Provider 注入(COMPONENTS.md §1 的“命令式能力”),所以组件外也能用。\n * 写了 id 的通知不重复:同一个 id 再 show 时换掉那一条(重新计时),不再加一条(接口重试、连点保存时只留一条)。\n *\n * - 每条通知就是 Alert(surface 外观加阴影),图标、标题、正文、操作、关闭按钮都复用它;加载中用 Alert 的 loading。\n * - 计时:默认 5 秒;指针在区域上、焦点在区域里、页面切到后台时暂停;加载中的、duration 为 Infinity 的不自动消失。\n * - 无障碍:区域是带名称的 landmark(section),F8 跳到通知区域,焦点在一条通知里时 Esc 关闭它;\n * 列表 aria-live=\"polite\",新通知被读屏念出。\n * 关闭一条后焦点交给相邻的通知,没有时回到进入通知区域之前的位置。\n * - 区域传送到 body(或最上层的模态里),用 ConfigScope 带上当前的主题与语言。\n * - 顶层:区域是 popover=\"manual\",显示在页面之上;模态打开时外面的元素都是 inert 的(顶层也不例外),\n * 所以这时区域移进最上层的模态 dialog 里(topModal),通知里的按钮仍可点击、可 Tab 到。\n * - 动画:进场淡入并从边缘移入(@starting-style),离场时高度收起(复用 Collapse)后从列表移除。\n * - 横向滑动(触摸、鼠标拖动)超过宽度的 35% 就关闭,否则弹回(startMove;同 Sonner、Radix Toast 的滑动关闭)。\n */\nimport { utils } from 'animejs';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n nextTick,\n onBeforeUnmount,\n onMounted,\n shallowReactive,\n Teleport,\n watch,\n type VNodeChild,\n} from 'vue';\nimport type { IconData } from '../base/Icon';\nimport { useLang } from '../config/context';\nimport { ConfigScope } from '../config/Provider';\nimport { Collapse, type CollapseProps } from '../display/Collapse';\nimport { useAnimate } from '../utils/motion/animation';\nimport { useLayoutAnimation } from '../utils/motion/layout';\nimport { usePresence } from '../utils/motion/presence';\nimport { startMove } from '../utils/dom/move';\nimport { topModal } from '../utils/dom/overlay';\nimport { toElement } from '../utils/dom/element';\nimport { useHotkeys, type HotkeyMap } from '../utils/dom/hotkeys';\nimport { focusAfterRemoval } from '../utils/dom/focus';\nimport { usePageVisible } from '../utils/dom/page-visibility';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport type { StatusTone } from '../utils/style/tone-styles';\nimport { Alert, type AlertProps } from './Alert';\nimport { FlexOrderedList, type FlexProps } from '../layout/Flex';\nimport { t } from '../config/theme/tokens';\n\n/** 一条通知的内容与行为 */\nexport interface ToastOptions {\n /** 标题(加粗的第一行) */\n title?: VNodeChild;\n /** 正文 */\n description?: VNodeChild;\n /** 色调,默认 neutral */\n tone?: StatusTone;\n /** 图标;不写时按色调选,false 不显示 */\n icon?: IconData | false;\n /** 进行中:图标换成加载指示,不自动消失 */\n loading?: boolean;\n /** 右侧的操作(如“撤销”按钮) */\n action?: VNodeChild;\n /** 显示关闭按钮,默认 true */\n closable?: boolean;\n /** 显示多久(毫秒)后自动消失;Infinity 不自动消失;不写时用 createToaster 的默认值 */\n duration?: number;\n /** 重要:读屏立即打断播报(aria-live=\"assertive\"),用于出错、需要马上处理的通知;默认按礼貌的顺序念 */\n important?: boolean;\n /** 编号:同一个编号的通知只有一条,再 show 时换掉它;不写时自动生成 */\n id?: string;\n /** 开始关闭时调用(自动消失或被关闭);同一条通知只调用一次 */\n onClose?: (reason: keyof ToastCloseReasons) => void;\n}\n\n/** 快捷方法的选项:标题由第一个参数给出 */\nexport type ToastShortcutOptions = Omit<ToastOptions, 'title' | 'tone'>;\n\n/** 通知为什么关闭 */\nexport interface ToastCloseReasons {\n /** 到时间自动消失 */\n timeout: unknown;\n /** 用户点了关闭、滑走、按了 Esc,或代码调用了 dismiss */\n dismissed: unknown;\n}\n\n/** 列表里的一条通知 */\nexport interface ToastRecord extends ToastOptions {\n /** show 返回的编号 */\n readonly id: string;\n /** 正在离场(已关闭,等离场过渡结束后移除) */\n readonly closing: boolean;\n /** 本轮自动关闭的计时:总时长(毫秒)与编号(重新计时时换一个);不自动关闭(加载中、Infinity)时为 null */\n readonly countdown: { readonly duration: number; readonly id: number } | null;\n}\n\n/** promise 各阶段的通知:固定内容,或由结果算出 */\nexport type ToastMessage<T> = ToastOptions | ((value: T) => ToastOptions);\n\n/** toaster.promise 的三个阶段 */\nexport interface ToastPromiseMessages<T> {\n /** 进行中(自动带上 loading) */\n loading: ToastOptions;\n /** 成功,默认色调 success */\n success: ToastMessage<T>;\n /** 失败,默认色调 danger */\n error: ToastMessage<unknown>;\n}\n\n/** createToaster 的选项 */\nexport interface ToasterOptions {\n /** 默认显示时长(毫秒),默认 5000 */\n duration?: number;\n}\n\n/** 通知控制器:createToaster() 创建,交给 <Toaster controller>,在任何地方调用 */\nexport interface ToasterController {\n /** 当前的通知,旧的在前 */\n readonly toasts: readonly ToastRecord[];\n /** 计时是否暂停(悬停、聚焦、页面隐藏时) */\n readonly paused: boolean;\n /** 显示一条通知,返回它的编号;options.id 已有时换掉那一条(不与它合并) */\n show(options: ToastOptions): string;\n /** 成功的通知:`toaster.success('已保存')` */\n success(title: VNodeChild, options?: ToastShortcutOptions): string;\n /** 出错的通知(读屏立即播报) */\n error(title: VNodeChild, options?: ToastShortcutOptions): string;\n /** 警告的通知 */\n warning(title: VNodeChild, options?: ToastShortcutOptions): string;\n /** 提示的通知 */\n info(title: VNodeChild, options?: ToastShortcutOptions): string;\n /** 进行中的通知(不自动消失):完成后用同一个 id 调 success / error 换掉它,或 dismiss */\n loading(title: VNodeChild, options?: ToastShortcutOptions): string;\n /** 改一条通知的内容(如加载完成);计时按新的 duration 重新开始 */\n update(id: string, options: ToastOptions): void;\n /** 关闭一条通知;不给编号时关闭全部 */\n dismiss(id?: string): void;\n /** 进行中 → 成功 / 失败:同一条通知依次更新;返回原 Promise 的结果(失败时照样抛出) */\n promise<T>(promise: Promise<T>, messages: ToastPromiseMessages<T>): Promise<T>;\n /** 暂停 / 继续所有通知的计时:Toaster 在悬停、聚焦、页面隐藏时调用 */\n pause(): void;\n /** 继续计时,见 pause */\n resume(): void;\n /** 从列表里移除(Toaster 在离场过渡结束后调用;直接调用则没有离场动画) */\n remove(id: string): void;\n /** 最多显示几条(Toaster 的 max):只给显示出来的通知计时,没轮到的等它出现再开始 */\n setLimit(limit: number): void;\n}\n\n/** 控制器内部可写的通知记录 */\ntype MutableToast = { -readonly [K in keyof ToastRecord]: ToastRecord[K] };\n\ninterface Timer {\n remaining: number;\n startedAt: number;\n handle?: ReturnType<typeof setTimeout>;\n}\n\nlet nextId = 0;\n\n/** 创建通知控制器 */\nexport function createToaster({\n duration: defaultDuration = 5000,\n}: ToasterOptions = {}): ToasterController {\n // 浅层响应:列表增删与每条通知的字段变化会触发渲染;内容是 VNode,不需要(也不该)深层代理\n const toasts = shallowReactive<MutableToast[]>([]);\n const timers = new Map<string, Timer>();\n const state = shallowReactive({ paused: false });\n let countdowns = 0;\n let limit = Infinity;\n\n const find = (id: string) => toasts.find((toast) => toast.id === id);\n\n function start(id: string, timer: Timer) {\n timer.startedAt = Date.now();\n timer.handle = setTimeout(() => close(id, 'timeout'), timer.remaining);\n }\n\n function close(id: string, reason: keyof ToastCloseReasons) {\n const toast = find(id);\n if (!toast || toast.closing) return;\n toast.closing = true;\n toast.countdown = null;\n clearTimeout(timers.get(toast.id)?.handle);\n timers.delete(toast.id);\n toast.onClose?.(reason);\n }\n\n function stop(timer: Timer) {\n if (timer.handle === undefined) return;\n clearTimeout(timer.handle);\n timer.handle = undefined;\n timer.remaining -= Date.now() - timer.startedAt;\n }\n\n /** 计时与显示对齐:显示出来的(最新的 limit 条)在走,其余停着;暂停时都停 */\n function sync() {\n const shown = new Set(toasts.slice(-limit).map((toast) => toast.id));\n for (const [id, timer] of timers) {\n const running = timer.handle !== undefined;\n if (!state.paused && shown.has(id)) {\n if (!running) start(id, timer);\n } else if (running) stop(timer);\n }\n }\n\n function schedule(toast: MutableToast) {\n clearTimeout(timers.get(toast.id)?.handle);\n timers.delete(toast.id);\n const duration = toast.loading ? Infinity : (toast.duration ?? defaultDuration);\n toast.countdown = Number.isFinite(duration) ? { duration, id: ++countdowns } : null;\n if (!toast.countdown) return;\n const timer: Timer = { remaining: duration, startedAt: 0 };\n timers.set(toast.id, timer);\n sync();\n }\n\n const resolve = <T,>(message: ToastMessage<T>, value: T) =>\n typeof message === 'function' ? message(value) : message;\n\n const controller: ToasterController = {\n toasts,\n get paused() {\n return state.paused;\n },\n show(options) {\n const existing = options.id === undefined ? undefined : find(options.id);\n if (existing && !existing.closing) {\n // 换掉整条(不与上一条合并):上一条的“进行中”、不可关闭都不留着\n for (const key of Object.keys(existing) as (keyof MutableToast)[]) {\n if (key !== 'id' && key !== 'closing' && key !== 'countdown') delete existing[key];\n }\n controller.update(existing.id, options);\n return existing.id;\n }\n // 同一个编号的那条正在离场:先移走,新的接着出现\n if (existing) controller.remove(existing.id);\n const id = options.id ?? `toast-${++nextId}`;\n toasts.push(shallowReactive({ ...options, id, closing: false, countdown: null }));\n schedule(find(id)!);\n return id;\n },\n success: (title, options) => controller.show({ ...options, title, tone: 'success' }),\n error: (title, options) =>\n controller.show({ important: true, ...options, title, tone: 'danger' }),\n warning: (title, options) => controller.show({ ...options, title, tone: 'warning' }),\n info: (title, options) => controller.show({ ...options, title, tone: 'info' }),\n loading: (title, options) =>\n controller.show({ closable: false, ...options, title, tone: 'neutral', loading: true }),\n update(id, options) {\n const toast = find(id);\n if (!toast || toast.closing) return;\n Object.assign(toast, options);\n schedule(toast);\n },\n dismiss(id) {\n for (const toast of id == null ? [...toasts] : [find(id)]) {\n if (toast) close(toast.id, 'dismissed');\n }\n },\n async promise(promise, { loading, success, error }) {\n const id = controller.show({ closable: false, ...loading, loading: true });\n try {\n const value = await promise;\n controller.update(id, {\n tone: 'success',\n closable: true,\n ...resolve(success, value),\n loading: false,\n });\n return value;\n } catch (reason) {\n controller.update(id, {\n tone: 'danger',\n closable: true,\n ...resolve(error, reason),\n loading: false,\n });\n throw reason;\n }\n },\n pause() {\n if (state.paused) return;\n state.paused = true;\n sync();\n },\n resume() {\n if (!state.paused) return;\n state.paused = false;\n sync();\n },\n remove(id) {\n const index = toasts.findIndex((toast) => toast.id === id);\n if (index >= 0) toasts.splice(index, 1);\n clearTimeout(timers.get(id)?.handle);\n timers.delete(id);\n // 腾出一个位置:下一条没轮到的通知出现,开始计时\n sync();\n },\n setLimit(next) {\n limit = next;\n sync();\n },\n };\n return controller;\n}\n\n/** 通知显示在视口的哪个位置 */\nexport interface ToastPlacements {\n /** 左上(从右到左排版时右上) */\n 'top-start': unknown;\n /** 顶部居中 */\n top: unknown;\n /** 右上(从右到左排版时左上) */\n 'top-end': unknown;\n /** 左下(从右到左排版时右下) */\n 'bottom-start': unknown;\n /** 底部居中 */\n bottom: unknown;\n /** 右下(默认;从右到左排版时左下) */\n 'bottom-end': unknown;\n}\n\n/** 未声明的属性落到区域(section)上;aria-label 默认取语言包(通知) */\nexport interface ToasterProps extends PartProps<'section', 'popover' | 'tabindex'> {\n /** createToaster() 创建的控制器 */\n controller: ToasterController;\n /** 显示位置,默认 bottom-end */\n placement?: keyof ToastPlacements;\n /** 最多同时显示几条,默认 3;更早的先不显示,前面的关闭后补上 */\n max?: number;\n /** 叠成一摞(同 Sonner):只露出最新的一条,更早的缩小叠在后面;悬停或聚焦时展开,展开收起有布局动画。默认 false(平铺) */\n stack?: boolean;\n /** 在自动关闭的通知底部显示剩余时间条(暂停计时时一起停),默认 false */\n progress?: boolean;\n /** 列表(ol)的部件属性 */\n propsList?: Omit<Partial<FlexProps<'ol'>>, 'aria-live'>;\n /** 每一项(li)的部件属性 */\n propsItem?: PartProps<'li'> | ((toast: ToastRecord) => PartProps<'li'>);\n /** 每条通知(Alert)的部件属性 */\n propsToast?: Partial<AlertProps> | ((toast: ToastRecord) => Partial<AlertProps>);\n /** 剩余时间条的部件属性 */\n propsProgress?: PartProps<'span'>;\n /** 每一项里收起高度的 Collapse 的部件属性(离场时它收起,下面的通知补上来) */\n propsCollapse?: Partial<CollapseProps>;\n}\n\nconst countdown = css.keyframes({\n from: { transform: 'scaleX(1)' },\n to: { transform: 'scaleX(0)' },\n});\n\n/** Toaster 的样式:region、list、listFromTop、item、itemFromBottom、itemFromTop 等 */\nexport const toastStyles = css.create({\n region: {\n // 原生 popover 默认居中、带边框与底色,改为贴着视口的一角\n position: 'fixed',\n inset: 'auto',\n margin: 0,\n padding: '_lg',\n borderWidth: 0,\n backgroundColor: 'transparent',\n overflow: 'visible',\n boxSizing: 'border-box',\n width: 'min(26em, 100vw)',\n maxHeight: '100dvh',\n // 区域本身不挡住下面页面的点击,只有通知能点\n pointerEvents: 'none',\n outlineStyle: 'none',\n },\n item: {\n pointerEvents: 'auto',\n // 纵向仍可滚动页面,横向交给滑动关闭\n touchAction: 'pan-y',\n opacity: { default: 1, '@starting-style': 0 },\n transition: `opacity ${t.durations.md} ${t.easings.enter}, translate ${t.durations.md} ${t.easings.enter}`,\n },\n itemFromBottom: { translate: { default: 'none', '@starting-style': '0 0.75em' } },\n itemFromTop: { translate: { default: 'none', '@starting-style': '0 -0.75em' } },\n itemClosing: {\n opacity: 0,\n transition: `opacity ${t.durations.sm} ${t.easings.exit}`,\n },\n // 间距放在每一项里:离场收起高度时间距一起收掉;剩余时间条按它定位\n gap: { position: 'relative', paddingBlock: '_xs' },\n toast: { boxShadow: '_lg' },\n // 贴着通知底边的细条,从满到空;时长是这条通知的计时(不是主题时长),由动态样式给出\n countdown: {\n position: 'absolute',\n insetInline: '_md',\n bottom: `calc(${t.space.xs} + ${t.borderWidths.xs})`,\n height: '_borderWidths.sm',\n borderRadius: '_full',\n backgroundColor: `color-mix(in srgb, ${t.colors.textMuted} 50%, transparent)`,\n transformOrigin: { default: 'left', ':dir(rtl)': 'right' },\n animationName: countdown,\n animationTimingFunction: 'linear',\n animationFillMode: 'forwards',\n pointerEvents: 'none',\n },\n countdownPaused: { animationPlayState: 'paused' },\n // 叠放:每一项都定位、按深度排层叠顺序;最新的一条留在文档流里撑起高度,更早的绝对定位叠在它后面\n stacked: {\n position: 'relative',\n transition: `opacity ${t.durations.md} ${t.easings.standard}, translate ${t.durations.md} ${t.easings.standard}, scale ${t.durations.md} ${t.easings.standard}`,\n },\n stackedBehind: { position: 'absolute', insetInline: 0 },\n stackedHidden: { opacity: 0 },\n stackedFromTop: { top: 0 },\n stackedFromBottom: { bottom: 0 },\n});\n\n// 深度是运行时的数,用动态样式;单独一个 create,见 COMPONENTS.md §4\n/** Toaster 的样式:叠放时第 depth 层(0 是最新的)的位移、缩放与层叠顺序 */\nexport const toastStackStyles = css.create({\n depth: (offset: string, scale: number, zIndex: number) => ({ translate: offset, scale, zIndex }),\n});\n\n// 时长来自每条通知,用动态样式;单独一个 create,见 COMPONENTS.md §4\n/** Toaster 的样式:剩余时间条的时长 */\nexport const toastCountdownStyles = css.create({\n duration: (ms: string) => ({ animationDuration: ms }),\n});\n\n/** Toaster 的样式:top-start、top、top-end、bottom-start、bottom、bottom-end */\nexport const toastPlacementStyles = css.create({\n 'top-start': { top: 0, insetInlineStart: 0 },\n top: { top: 0, insetInline: 0, marginInline: 'auto' },\n 'top-end': { top: 0, insetInlineEnd: 0 },\n 'bottom-start': { bottom: 0, insetInlineStart: 0 },\n bottom: { bottom: 0, insetInline: 0, marginInline: 'auto' },\n 'bottom-end': { bottom: 0, insetInlineEnd: 0 },\n});\n\n/** Toaster 里每条通知的 props */\nexport interface ToastItemProps {\n /** 这条通知 */\n toast: ToastRecord;\n /** 所属的通知器:关闭、暂停计时 */\n controller: ToasterController;\n /** Toaster 在顶部:进场从上方滑入 */\n fromTop: boolean;\n /** 最后一条被关闭时焦点回到这里 */\n fallbackFocus: () => HTMLElement | null;\n /** 每条通知外层(li)的部件属性 */\n propsItem: ToasterProps['propsItem'];\n /** 通知本身(Alert)的部件属性 */\n propsToast: ToasterProps['propsToast'];\n /** 叠放时的深度(0 是最新的一条);平铺或展开时为 null */\n depth: number | null;\n /** 显示剩余时间条 */\n progress: boolean;\n /** 剩余时间条的部件属性 */\n propsProgress: ToasterProps['propsProgress'];\n /** 收起高度的 Collapse 的部件属性 */\n propsCollapse: ToasterProps['propsCollapse'];\n}\n\n/** 滑动超过宽度的这个比例就关闭 */\nconst SWIPE_RATIO = 0.35;\n\n/** 叠放的一层:每深一层错开 0.75em、缩小 5%,第三层之后隐藏 */\nfunction stackSx(depth: number, fromTop: boolean) {\n const offset = `0 ${(fromTop ? 0.75 : -0.75) * depth}em`;\n return [\n toastStyles.stacked,\n depth > 0 && [\n toastStyles.stackedBehind,\n fromTop ? toastStyles.stackedFromTop : toastStyles.stackedFromBottom,\n ],\n toastStackStyles.depth(offset, 1 - depth * 0.05, 100 - depth),\n depth > 2 && toastStyles.stackedHidden,\n ];\n}\n\n/** 列表里的一项:Collapse 负责离场时收起高度,收起后从控制器里移除 */\nexport const ToastItem = _component(\n ({\n toast,\n controller,\n fromTop,\n fallbackFocus,\n depth,\n progress,\n propsItem,\n propsToast,\n propsProgress,\n propsCollapse,\n }: ToastItemProps) => {\n let item: HTMLElement | null = null;\n const animate = useAnimate();\n\n const presence = usePresence(() => !toast.closing, {\n onExited: () => controller.remove(toast.id),\n });\n\n function close() {\n if (item) focusAfterRemoval(item, fallbackFocus());\n controller.dismiss(toast.id);\n }\n\n // 焦点在通知里(操作、关闭按钮)时 Esc 关闭它(同 Radix Toast);不能关闭的通知不处理\n function onKeydown(event: KeyboardEvent) {\n if (event.key !== 'Escape' || toast.closable === false || toast.closing) return;\n event.preventDefault();\n event.stopPropagation();\n close();\n }\n\n // 横向滑动关闭:拖动中直接写元素的样式(不触发渲染)。松开时过了阈值就沿滑动方向滑出再关闭,\n // 不够就用弹簧弹回(Anime.js,时长取主题;减少动态效果时立即到位)。不能关闭的通知(promise 的加载中)不跟手\n function onPointerdown(event: PointerEvent) {\n const element = item;\n if (!element || toast.closing || toast.closable === false) return;\n if ((event.target as Element).closest('button, a, input, textarea, select')) return;\n const width = element.getBoundingClientRect().width;\n startMove(event, {\n threshold: 4,\n onMove: ({ deltaX }) => {\n // 拖动中跟手:去掉进出场的 CSS 过渡,不然每一帧都在追赶\n element.style.transition = 'none';\n void utils.set(element, {\n x: deltaX,\n opacity: Math.max(0, 1 - Math.abs(deltaX) / width),\n });\n },\n onEnd: ({ deltaX, moved, cancelled }) => {\n // 弹回后去掉内联样式:之后的离场淡出要靠 CSS 的 opacity\n const settled = () => {\n element.style.transition = '';\n element.style.removeProperty('transform');\n element.style.removeProperty('opacity');\n };\n if (moved && !cancelled && Math.abs(deltaX) > width * SWIPE_RATIO) {\n const out = { x: Math.sign(deltaX) * width, opacity: 0 };\n void animate(element, out, { duration: 'sm', ease: 'exit' }).then(() => {\n close();\n element.style.transition = '';\n });\n return;\n }\n void animate(element, { x: 0, opacity: 1 }, { bounce: 0.35 }).then(settled);\n },\n });\n }\n\n return () => {\n const itemProps = typeof propsItem === 'function' ? propsItem(toast) : propsItem;\n const toastProps = typeof propsToast === 'function' ? propsToast(toast) : propsToast;\n return (\n <li\n {...mergeAttrs<'li'>(\n {\n sx: [\n toastStyles.item,\n fromTop ? toastStyles.itemFromTop : toastStyles.itemFromBottom,\n depth != null && stackSx(depth, fromTop),\n toast.closing && toastStyles.itemClosing,\n ],\n },\n itemProps,\n {\n // 重要的通知打断播报(同 Sonner);其余随列表的 aria-live=\"polite\"\n 'aria-live': toast.important ? 'assertive' : undefined,\n 'aria-atomic': toast.important || undefined,\n ref: (element: unknown) => {\n item = toElement(element);\n presence.ref(element);\n },\n onPointerdown,\n onKeydown,\n },\n )}\n data-state={presence.state}\n >\n <Collapse\n {...mergePartProps<CollapseProps>(\n { propsContent: { sx: toastStyles.gap } },\n propsCollapse,\n )}\n _open={!toast.closing}\n >\n <Alert\n {...mergePartProps<AlertProps>(\n {\n variant: 'surface',\n tone: toast.tone ?? 'neutral',\n icon: toast.icon,\n loading: toast.loading,\n title: toast.title,\n description: toast.description,\n action: toast.action,\n sx: toastStyles.toast,\n },\n toastProps,\n { onClose: toast.closable === false ? undefined : close },\n )}\n />\n {progress && toast.countdown && (\n <span\n key={toast.countdown.id}\n {...mergeAttrs<'span'>({ sx: toastStyles.countdown }, propsProgress, {\n sx: [\n toastCountdownStyles.duration(`${toast.countdown.duration}ms`),\n controller.paused && toastStyles.countdownPaused,\n ],\n 'aria-hidden': true,\n })}\n />\n )}\n </Collapse>\n </li>\n );\n };\n },\n { name: 'ToastItem' },\n);\n\n/** 通知的显示区域:放一个即可;模态打开时自动移进最上层的模态 */\nexport const Toaster = _component(\n ({\n controller,\n placement = 'bottom-end',\n max = 3,\n stack = false,\n progress = false,\n propsList,\n propsItem,\n propsToast,\n propsProgress,\n propsCollapse,\n ...rest\n }: ToasterProps) => {\n const lang = useLang();\n let region = _state.raw<HTMLElement | null>(null);\n let hovering = _state(false);\n let focused = _state(false);\n const pageVisible = usePageVisible();\n // 叠放时悬停或聚焦就展开;展开、收起时各项从旧位置平移过去\n let list = _state.raw<HTMLElement | null>(null);\n let expanded = _state(false);\n const layout = useLayoutAnimation(() => list, { children: ':scope > li' });\n watch(\n () => hovering || focused,\n (next) => {\n if (stack) void layout.change(() => (expanded = next));\n else expanded = next;\n },\n );\n // 进入通知区域之前焦点所在的元素:最后一条通知被关闭后焦点回到这里\n let outsideFocus: HTMLElement | null = null;\n\n _effect(() => {\n if (hovering || focused || !pageVisible.value) controller.pause();\n else controller.resume();\n });\n\n // 移动到别的父元素(Teleport 换目标)时浏览器会关掉 popover,移完重新打开\n const reopen = () => {\n if (region?.isConnected && !region.matches(':popover-open')) region.showPopover();\n };\n watch(topModal, () => void nextTick(reopen));\n\n // F8 跳到通知区域(同 Radix Toast);输入框里也能用\n const noHotkeys: HotkeyMap = {};\n useHotkeys(\n () => (region && controller.toasts.length ? { F8: () => region?.focus() } : noHotkeys),\n { inInputs: true },\n );\n onMounted(reopen);\n // 只给显示出来的通知计时:告诉控制器最多显示几条\n watch(\n () => max,\n (limit) => controller.setLimit(limit),\n { immediate: true },\n );\n onBeforeUnmount(() => {\n controller.setLimit(Infinity);\n controller.resume();\n });\n\n function onFocusin(event: FocusEvent) {\n focused = true;\n const from = event.relatedTarget;\n if (from instanceof HTMLElement && !region?.contains(from)) outsideFocus = from;\n }\n function onFocusout(event: FocusEvent) {\n const to = event.relatedTarget;\n if (!(to instanceof Node && region?.contains(to))) focused = false;\n }\n\n return () => {\n const fromTop = placement.startsWith('top');\n const visible = controller.toasts.slice(-max);\n // 深度只数还在显示的:正在离场的不占一层\n let depth = visible.filter((toast) => !toast.closing).length;\n const depths = visible.map((toast) => (toast.closing ? depth : --depth));\n const stacked = stack && !expanded;\n return (\n <Teleport to={topModal() ?? 'body'}>\n <ConfigScope>\n <section\n {...mergeAttrs<'section'>(\n {\n sx: [toastStyles.region, toastPlacementStyles[placement]],\n 'aria-label': lang.toasterLabel,\n },\n rest,\n {\n ref: _toRef(region),\n popover: 'manual',\n tabindex: -1,\n onPointerenter: () => (hovering = true),\n onPointerleave: () => (hovering = false),\n onFocusin,\n onFocusout,\n },\n )}\n data-placement={placement}\n data-expanded={stack ? String(!stacked) : undefined}\n >\n <FlexOrderedList\n {...mergePartProps<FlexProps<'ol'>>(\n // 新通知靠近所在的边缘:在顶部时最新的在最上面\n { direction: fromTop ? 'column-reverse' : 'column' },\n propsList,\n {\n ref: (value: unknown) => (list = toElement(value)),\n 'aria-live': 'polite',\n },\n )}\n >\n {visible.map((toast, index) => (\n <ToastItem\n key={toast.id}\n depth={stacked ? depths[index]! : null}\n toast={toast}\n controller={controller}\n fromTop={fromTop}\n fallbackFocus={() => outsideFocus}\n propsItem={propsItem}\n propsToast={propsToast}\n progress={progress}\n propsProgress={propsProgress}\n propsCollapse={propsCollapse}\n />\n ))}\n </FlexOrderedList>\n </section>\n </ConfigScope>\n </Teleport>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Toast.js","names":["_isVNode","_vtp_readonlyProp","_createVNode","_mergeProps","_vtp_restProps","_vue_shallowRef","_vue_ref"],"sources":["../../src/feedback/Toast.tsx"],"sourcesContent":["/**\n * 通知(toast):操作结果的短暂提示,几秒后自动消失。控制器 + 显示区域(参考 Sonner、Radix Toast、React Aria Toast):\n *\n * // toaster.ts:应用里创建一次,组件内外(请求拦截器、store)都能导入使用\n * export const toaster = createToaster();\n * // App:放一个显示区域\n * <Toaster controller={toaster} placement=\"bottom-end\" />\n * // 任意位置\n * toaster.show({ tone: 'success', title: '已保存' }); // 或 toaster.success('已保存')\n * const id = toaster.show({ title: '已删除', action: <Button onClick={() => undo(id)}>撤销</Button> });\n * toaster.loading('正在导出', { id: 'export' }); …; toaster.success('导出完成', { id: 'export' }); // 同一个 id 换掉原来那条\n * await toaster.promise(upload(file), { loading: { title: '正在上传' }, success: { title: '上传完成' }, error: (e) => ({ title: String(e) }) });\n *\n * 控制器是普通对象,不经 Provider 注入(COMPONENTS.md §1 的“命令式能力”),所以组件外也能用。\n * 写了 id 的通知不重复:同一个 id 再 show 时换掉那一条(重新计时),不再加一条(接口重试、连点保存时只留一条)。\n *\n * - 每条通知就是 Alert(surface 外观加阴影),图标、标题、正文、操作、关闭按钮都复用它;加载中用 Alert 的 loading。\n * - 计时:默认 5 秒;指针在区域上、焦点在区域里、页面切到后台时暂停;加载中的、duration 为 Infinity 的不自动消失。\n * - 无障碍:区域是带名称的 landmark(section),F8 跳到通知区域,焦点在一条通知里时 Esc 关闭它;\n * 列表 aria-live=\"polite\",新通知被读屏念出。\n * 关闭一条后焦点交给相邻的通知,没有时回到进入通知区域之前的位置。\n * - 区域传送到 body(或最上层的模态里),用 ConfigScope 带上当前的主题与语言。\n * - 顶层:区域是 popover=\"manual\",显示在页面之上;模态打开时外面的元素都是 inert 的(顶层也不例外),\n * 所以这时区域移进最上层的模态 dialog 里(topModal),通知里的按钮仍可点击、可 Tab 到。\n * - 动画:进场淡入并从边缘移入(@starting-style),离场时高度收起(复用 Collapse)后从列表移除。\n * - 横向滑动(触摸、鼠标拖动)超过宽度的 35% 就关闭,否则弹回(startMove;同 Sonner、Radix Toast 的滑动关闭)。\n */\nimport { utils } from 'animejs';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n nextTick,\n onBeforeUnmount,\n onMounted,\n shallowReactive,\n Teleport,\n watch,\n type VNodeChild,\n} from 'vue';\nimport type { IconData } from '../base/Icon';\nimport { useLang } from '../config/context';\nimport { ConfigScope } from '../config/Provider';\nimport { Collapse, type CollapseProps } from '../display/Collapse';\nimport { useAnimate } from '../utils/motion/animation';\nimport { useLayoutAnimation } from '../utils/motion/layout';\nimport { usePresence } from '../utils/motion/presence';\nimport { startMove } from '../utils/dom/move';\nimport { topModal } from '../utils/dom/overlay';\nimport { toElement } from '../utils/dom/element';\nimport { useHotkeys, type HotkeyMap } from '../utils/dom/hotkeys';\nimport { focusAfterRemoval } from '../utils/dom/focus';\nimport { usePageVisible } from '../utils/dom/page-visibility';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport type { StatusTone } from '../utils/style/tone-styles';\nimport { Alert, type AlertProps } from './Alert';\nimport { FlexOrderedList, type FlexProps } from '../layout/Flex';\nimport { t } from '../config/theme/tokens';\n\n/** 一条通知的内容与行为 */\nexport interface ToastOptions {\n /** 标题(加粗的第一行) */\n title?: VNodeChild;\n /** 正文 */\n description?: VNodeChild;\n /** 色调,默认 neutral */\n tone?: StatusTone;\n /** 图标;不写时按色调选,false 不显示 */\n icon?: IconData | false;\n /** 进行中:图标换成加载指示,不自动消失 */\n loading?: boolean;\n /** 右侧的操作(如“撤销”按钮) */\n action?: VNodeChild;\n /** 显示关闭按钮,默认 true */\n closable?: boolean;\n /** 显示多久(毫秒)后自动消失;Infinity 不自动消失;不写时用 createToaster 的默认值 */\n duration?: number;\n /** 重要:读屏立即打断播报(aria-live=\"assertive\"),用于出错、需要马上处理的通知;默认按礼貌的顺序念 */\n important?: boolean;\n /** 编号:同一个编号的通知只有一条,再 show 时换掉它;不写时自动生成 */\n id?: string;\n /** 开始关闭时调用(自动消失或被关闭);同一条通知只调用一次 */\n onClose?: (reason: keyof ToastCloseReasons) => void;\n}\n\n/** 快捷方法的选项:标题由第一个参数给出 */\nexport type ToastShortcutOptions = Omit<ToastOptions, 'title' | 'tone'>;\n\n/** 通知为什么关闭 */\nexport interface ToastCloseReasons {\n /** 到时间自动消失 */\n timeout: unknown;\n /** 用户点了关闭、滑走、按了 Esc,或代码调用了 dismiss */\n dismissed: unknown;\n}\n\n/** 列表里的一条通知 */\nexport interface ToastRecord extends ToastOptions {\n /** show 返回的编号 */\n readonly id: string;\n /** 正在离场(已关闭,等离场过渡结束后移除) */\n readonly closing: boolean;\n /** 本轮自动关闭的计时:总时长(毫秒)与编号(重新计时时换一个);不自动关闭(加载中、Infinity)时为 null */\n readonly countdown: { readonly duration: number; readonly id: number } | null;\n}\n\n/** promise 各阶段的通知:固定内容,或由结果算出 */\nexport type ToastMessage<T> = ToastOptions | ((value: T) => ToastOptions);\n\n/** toaster.promise 的三个阶段 */\nexport interface ToastPromiseMessages<T> {\n /** 进行中(自动带上 loading) */\n loading: ToastOptions;\n /** 成功,默认色调 success */\n success: ToastMessage<T>;\n /** 失败,默认色调 danger */\n error: ToastMessage<unknown>;\n}\n\n/** createToaster 的选项 */\nexport interface ToasterOptions {\n /** 默认显示时长(毫秒),默认 5000 */\n duration?: number;\n}\n\n/** 通知控制器:createToaster() 创建,交给 <Toaster controller>,在任何地方调用 */\nexport interface ToasterController {\n /** 当前的通知,旧的在前 */\n readonly toasts: readonly ToastRecord[];\n /** 计时是否暂停(悬停、聚焦、页面隐藏时) */\n readonly paused: boolean;\n /** 显示一条通知,返回它的编号;options.id 已有时换掉那一条(不与它合并) */\n show(options: ToastOptions): string;\n /** 成功的通知:`toaster.success('已保存')` */\n success(title: VNodeChild, options?: ToastShortcutOptions): string;\n /** 出错的通知(读屏立即播报) */\n error(title: VNodeChild, options?: ToastShortcutOptions): string;\n /** 警告的通知 */\n warning(title: VNodeChild, options?: ToastShortcutOptions): string;\n /** 提示的通知 */\n info(title: VNodeChild, options?: ToastShortcutOptions): string;\n /** 进行中的通知(不自动消失):完成后用同一个 id 调 success / error 换掉它,或 dismiss */\n loading(title: VNodeChild, options?: ToastShortcutOptions): string;\n /** 改一条通知的内容(如加载完成);计时按新的 duration 重新开始 */\n update(id: string, options: ToastOptions): void;\n /** 关闭一条通知;不给编号时关闭全部 */\n dismiss(id?: string): void;\n /** 进行中 → 成功 / 失败:同一条通知依次更新;返回原 Promise 的结果(失败时照样抛出) */\n promise<T>(promise: Promise<T>, messages: ToastPromiseMessages<T>): Promise<T>;\n /** 暂停 / 继续所有通知的计时:Toaster 在悬停、聚焦、页面隐藏时调用 */\n pause(): void;\n /** 继续计时,见 pause */\n resume(): void;\n /** 从列表里移除(Toaster 在离场过渡结束后调用;直接调用则没有离场动画) */\n remove(id: string): void;\n /** 最多显示几条(Toaster 的 max):只给显示出来的通知计时,没轮到的等它出现再开始 */\n setLimit(limit: number): void;\n}\n\n/** 控制器内部可写的通知记录 */\ntype MutableToast = { -readonly [K in keyof ToastRecord]: ToastRecord[K] };\n\ninterface Timer {\n remaining: number;\n startedAt: number;\n handle?: ReturnType<typeof setTimeout>;\n}\n\nlet nextId = 0;\n\n/** 创建通知控制器 */\nexport function createToaster({\n duration: defaultDuration = 5000,\n}: ToasterOptions = {}): ToasterController {\n // 浅层响应:列表增删与每条通知的字段变化会触发渲染;内容是 VNode,不需要(也不该)深层代理\n const toasts = shallowReactive<MutableToast[]>([]);\n const timers = new Map<string, Timer>();\n const state = shallowReactive({ paused: false });\n let countdowns = 0;\n let limit = Infinity;\n\n const find = (id: string) => toasts.find((toast) => toast.id === id);\n\n function start(id: string, timer: Timer) {\n timer.startedAt = Date.now();\n timer.handle = setTimeout(() => close(id, 'timeout'), timer.remaining);\n }\n\n function close(id: string, reason: keyof ToastCloseReasons) {\n const toast = find(id);\n if (!toast || toast.closing) return;\n toast.closing = true;\n toast.countdown = null;\n clearTimeout(timers.get(toast.id)?.handle);\n timers.delete(toast.id);\n toast.onClose?.(reason);\n }\n\n function stop(timer: Timer) {\n if (timer.handle === undefined) return;\n clearTimeout(timer.handle);\n timer.handle = undefined;\n timer.remaining -= Date.now() - timer.startedAt;\n }\n\n /** 计时与显示对齐:显示出来的(最新的 limit 条)在走,其余停着;暂停时都停 */\n function sync() {\n const shown = new Set(toasts.slice(-limit).map((toast) => toast.id));\n for (const [id, timer] of timers) {\n const running = timer.handle !== undefined;\n if (!state.paused && shown.has(id)) {\n if (!running) start(id, timer);\n } else if (running) stop(timer);\n }\n }\n\n function schedule(toast: MutableToast) {\n clearTimeout(timers.get(toast.id)?.handle);\n timers.delete(toast.id);\n const duration = toast.loading ? Infinity : (toast.duration ?? defaultDuration);\n toast.countdown = Number.isFinite(duration) ? { duration, id: ++countdowns } : null;\n if (!toast.countdown) return;\n const timer: Timer = { remaining: duration, startedAt: 0 };\n timers.set(toast.id, timer);\n sync();\n }\n\n const resolve = <T,>(message: ToastMessage<T>, value: T) =>\n typeof message === 'function' ? message(value) : message;\n\n const controller: ToasterController = {\n toasts,\n get paused() {\n return state.paused;\n },\n show(options) {\n const existing = options.id === undefined ? undefined : find(options.id);\n if (existing && !existing.closing) {\n // 换掉整条(不与上一条合并):上一条的“进行中”、不可关闭都不留着\n for (const key of Object.keys(existing) as (keyof MutableToast)[]) {\n if (key !== 'id' && key !== 'closing' && key !== 'countdown') delete existing[key];\n }\n controller.update(existing.id, options);\n return existing.id;\n }\n // 同一个编号的那条正在离场:先移走,新的接着出现\n if (existing) controller.remove(existing.id);\n const id = options.id ?? `toast-${++nextId}`;\n toasts.push(shallowReactive({ ...options, id, closing: false, countdown: null }));\n schedule(find(id)!);\n return id;\n },\n success: (title, options) => controller.show({ ...options, title, tone: 'success' }),\n error: (title, options) =>\n controller.show({ important: true, ...options, title, tone: 'danger' }),\n warning: (title, options) => controller.show({ ...options, title, tone: 'warning' }),\n info: (title, options) => controller.show({ ...options, title, tone: 'info' }),\n loading: (title, options) =>\n controller.show({ closable: false, ...options, title, tone: 'neutral', loading: true }),\n update(id, options) {\n const toast = find(id);\n if (!toast || toast.closing) return;\n Object.assign(toast, options);\n schedule(toast);\n },\n dismiss(id) {\n for (const toast of id == null ? [...toasts] : [find(id)]) {\n if (toast) close(toast.id, 'dismissed');\n }\n },\n async promise(promise, { loading, success, error }) {\n const id = controller.show({ closable: false, ...loading, loading: true });\n try {\n const value = await promise;\n controller.update(id, {\n tone: 'success',\n closable: true,\n ...resolve(success, value),\n loading: false,\n });\n return value;\n } catch (reason) {\n controller.update(id, {\n tone: 'danger',\n closable: true,\n ...resolve(error, reason),\n loading: false,\n });\n throw reason;\n }\n },\n pause() {\n if (state.paused) return;\n state.paused = true;\n sync();\n },\n resume() {\n if (!state.paused) return;\n state.paused = false;\n sync();\n },\n remove(id) {\n const index = toasts.findIndex((toast) => toast.id === id);\n if (index >= 0) toasts.splice(index, 1);\n clearTimeout(timers.get(id)?.handle);\n timers.delete(id);\n // 腾出一个位置:下一条没轮到的通知出现,开始计时\n sync();\n },\n setLimit(next) {\n limit = next;\n sync();\n },\n };\n return controller;\n}\n\n/** 通知显示在视口的哪个位置 */\nexport interface ToastPlacements {\n /** 左上(从右到左排版时右上) */\n 'top-start': unknown;\n /** 顶部居中 */\n top: unknown;\n /** 右上(从右到左排版时左上) */\n 'top-end': unknown;\n /** 左下(从右到左排版时右下) */\n 'bottom-start': unknown;\n /** 底部居中 */\n bottom: unknown;\n /** 右下(默认;从右到左排版时左下) */\n 'bottom-end': unknown;\n}\n\n/** 未声明的属性落到区域(section)上;aria-label 默认取语言包(通知) */\nexport interface ToasterProps extends PartProps<'section', 'popover' | 'tabindex'> {\n /** createToaster() 创建的控制器 */\n controller: ToasterController;\n /** 显示位置,默认 bottom-end */\n placement?: keyof ToastPlacements;\n /** 最多同时显示几条,默认 3;更早的先不显示,前面的关闭后补上 */\n max?: number;\n /** 叠成一摞(同 Sonner):只露出最新的一条,更早的缩小叠在后面;悬停或聚焦时展开,展开收起有布局动画。默认 false(平铺) */\n stack?: boolean;\n /** 在自动关闭的通知底部显示剩余时间条(暂停计时时一起停),默认 false */\n progress?: boolean;\n /** 列表(ol)的部件属性 */\n propsList?: Omit<Partial<FlexProps<'ol'>>, 'aria-live'>;\n /** 每一项(li)的部件属性 */\n propsItem?: PartProps<'li'> | ((toast: ToastRecord) => PartProps<'li'>);\n /** 每条通知(Alert)的部件属性 */\n propsToast?: Partial<AlertProps> | ((toast: ToastRecord) => Partial<AlertProps>);\n /** 剩余时间条的部件属性 */\n propsProgress?: PartProps<'span'>;\n /** 每一项里收起高度的 Collapse 的部件属性(离场时它收起,下面的通知补上来) */\n propsCollapse?: Partial<CollapseProps>;\n}\n\nconst countdown = css.keyframes({\n from: { transform: 'scaleX(1)' },\n to: { transform: 'scaleX(0)' },\n});\n\n/** Toaster 的样式:region、list、listFromTop、item、itemFromBottom、itemFromTop 等 */\nexport const toastStyles = css.create({\n region: {\n // 原生 popover 默认居中、带边框与底色,改为贴着视口的一角\n position: 'fixed',\n inset: 'auto',\n margin: 0,\n padding: '_lg',\n borderWidth: 0,\n backgroundColor: 'transparent',\n overflow: 'visible',\n boxSizing: 'border-box',\n width: 'min(26em, 100vw)',\n maxHeight: '100dvh',\n // 区域本身不挡住下面页面的点击,只有通知能点\n pointerEvents: 'none',\n outlineStyle: 'none',\n },\n item: {\n pointerEvents: 'auto',\n // 纵向仍可滚动页面,横向交给滑动关闭\n touchAction: 'pan-y',\n opacity: { default: 1, '@starting-style': 0 },\n transition: `opacity ${t.durations.md} ${t.easings.enter}, translate ${t.durations.md} ${t.easings.enter}`,\n },\n itemFromBottom: { translate: { default: 'none', '@starting-style': '0 0.75em' } },\n itemFromTop: { translate: { default: 'none', '@starting-style': '0 -0.75em' } },\n itemClosing: {\n opacity: 0,\n transition: `opacity ${t.durations.sm} ${t.easings.exit}`,\n },\n // 间距放在每一项里:离场收起高度时间距一起收掉;剩余时间条按它定位\n gap: { position: 'relative', paddingBlock: '_xs' },\n toast: { boxShadow: '_lg' },\n // 贴着通知底边的细条,从满到空;时长是这条通知的计时(不是主题时长),由动态样式给出\n countdown: {\n position: 'absolute',\n insetInline: '_md',\n bottom: `calc(${t.space.xs} + ${t.borderWidths.xs})`,\n height: '_borderWidths.sm',\n borderRadius: '_full',\n backgroundColor: `color-mix(in srgb, ${t.colors.textMuted} 50%, transparent)`,\n transformOrigin: { default: 'left', ':dir(rtl)': 'right' },\n animationName: countdown,\n animationTimingFunction: 'linear',\n animationFillMode: 'forwards',\n pointerEvents: 'none',\n },\n countdownPaused: { animationPlayState: 'paused' },\n // 叠放:每一项都定位、按深度排层叠顺序;最新的一条留在文档流里撑起高度,更早的绝对定位叠在它后面\n stacked: {\n position: 'relative',\n transition: `opacity ${t.durations.md} ${t.easings.standard}, translate ${t.durations.md} ${t.easings.standard}, scale ${t.durations.md} ${t.easings.standard}`,\n },\n stackedBehind: { position: 'absolute', insetInline: 0 },\n stackedHidden: { opacity: 0 },\n stackedFromTop: { top: 0 },\n stackedFromBottom: { bottom: 0 },\n});\n\n// 深度是运行时的数,用动态样式;单独一个 create,见 COMPONENTS.md §4\n/** Toaster 的样式:叠放时第 depth 层(0 是最新的)的位移、缩放与层叠顺序 */\nexport const toastStackStyles = css.create({\n depth: (offset: string, scale: number, zIndex: number) => ({ translate: offset, scale, zIndex }),\n});\n\n// 时长来自每条通知,用动态样式;单独一个 create,见 COMPONENTS.md §4\n/** Toaster 的样式:剩余时间条的时长 */\nexport const toastCountdownStyles = css.create({\n duration: (ms: string) => ({ animationDuration: ms }),\n});\n\n/** Toaster 的样式:top-start、top、top-end、bottom-start、bottom、bottom-end */\nexport const toastPlacementStyles = css.create({\n 'top-start': { top: 0, insetInlineStart: 0 },\n top: { top: 0, insetInline: 0, marginInline: 'auto' },\n 'top-end': { top: 0, insetInlineEnd: 0 },\n 'bottom-start': { bottom: 0, insetInlineStart: 0 },\n bottom: { bottom: 0, insetInline: 0, marginInline: 'auto' },\n 'bottom-end': { bottom: 0, insetInlineEnd: 0 },\n});\n\n/** Toaster 里每条通知的 props */\nexport interface ToastItemProps {\n /** 这条通知 */\n toast: ToastRecord;\n /** 所属的通知器:关闭、暂停计时 */\n controller: ToasterController;\n /** Toaster 在顶部:进场从上方滑入 */\n fromTop: boolean;\n /** 最后一条被关闭时焦点回到这里 */\n fallbackFocus: () => HTMLElement | null;\n /** 每条通知外层(li)的部件属性 */\n propsItem: ToasterProps['propsItem'];\n /** 通知本身(Alert)的部件属性 */\n propsToast: ToasterProps['propsToast'];\n /** 叠放时的深度(0 是最新的一条);平铺或展开时为 null */\n depth: number | null;\n /** 显示剩余时间条 */\n progress: boolean;\n /** 剩余时间条的部件属性 */\n propsProgress: ToasterProps['propsProgress'];\n /** 收起高度的 Collapse 的部件属性 */\n propsCollapse: ToasterProps['propsCollapse'];\n}\n\n/** 滑动超过宽度的这个比例就关闭 */\nconst SWIPE_RATIO = 0.35;\n\n/** 叠放的一层:每深一层错开 0.75em、缩小 5%,第三层之后隐藏 */\nfunction stackSx(depth: number, fromTop: boolean) {\n const offset = `0 ${(fromTop ? 0.75 : -0.75) * depth}em`;\n return [\n toastStyles.stacked,\n depth > 0 && [\n toastStyles.stackedBehind,\n fromTop ? toastStyles.stackedFromTop : toastStyles.stackedFromBottom,\n ],\n toastStackStyles.depth(offset, 1 - depth * 0.05, 100 - depth),\n depth > 2 && toastStyles.stackedHidden,\n ];\n}\n\n/** 列表里的一项:Collapse 负责离场时收起高度,收起后从控制器里移除 */\nexport const ToastItem = _component(\n ({\n toast,\n controller,\n fromTop,\n fallbackFocus,\n depth,\n progress,\n propsItem,\n propsToast,\n propsProgress,\n propsCollapse,\n }: ToastItemProps) => {\n let item: HTMLElement | null = null;\n const animate = useAnimate();\n\n const presence = usePresence(() => !toast.closing, {\n onExited: () => controller.remove(toast.id),\n });\n\n function close() {\n if (item) focusAfterRemoval(item, fallbackFocus());\n controller.dismiss(toast.id);\n }\n\n // 焦点在通知里(操作、关闭按钮)时 Esc 关闭它(同 Radix Toast);不能关闭的通知不处理\n function onKeydown(event: KeyboardEvent) {\n if (event.key !== 'Escape' || toast.closable === false || toast.closing) return;\n event.preventDefault();\n event.stopPropagation();\n close();\n }\n\n // 横向滑动关闭:拖动中直接写元素的样式(不触发渲染)。松开时过了阈值就沿滑动方向滑出再关闭,\n // 不够就用弹簧弹回(Anime.js,时长取主题;减少动态效果时立即到位)。不能关闭的通知(promise 的加载中)不跟手\n function onPointerdown(event: PointerEvent) {\n const element = item;\n if (!element || toast.closing || toast.closable === false) return;\n if ((event.target as Element).closest('button, a, input, textarea, select')) return;\n const width = element.getBoundingClientRect().width;\n startMove(event, {\n threshold: 4,\n onMove: ({ deltaX }) => {\n // 拖动中跟手:去掉进出场的 CSS 过渡,不然每一帧都在追赶\n element.style.transition = 'none';\n void utils.set(element, {\n x: deltaX,\n opacity: Math.max(0, 1 - Math.abs(deltaX) / width),\n });\n },\n onEnd: ({ deltaX, moved, cancelled }) => {\n // 弹回后去掉内联样式:之后的离场淡出要靠 CSS 的 opacity\n const settled = () => {\n element.style.transition = '';\n element.style.removeProperty('transform');\n element.style.removeProperty('opacity');\n };\n if (moved && !cancelled && Math.abs(deltaX) > width * SWIPE_RATIO) {\n const out = { x: Math.sign(deltaX) * width, opacity: 0 };\n void animate(element, out, { duration: 'sm', ease: 'exit' }).then(() => {\n close();\n element.style.transition = '';\n });\n return;\n }\n void animate(element, { x: 0, opacity: 1 }, { bounce: 0.35 }).then(settled);\n },\n });\n }\n\n return () => {\n const itemProps = typeof propsItem === 'function' ? propsItem(toast) : propsItem;\n const toastProps = typeof propsToast === 'function' ? propsToast(toast) : propsToast;\n return (\n <li\n {...mergeAttrs<'li'>(\n {\n sx: [\n toastStyles.item,\n fromTop ? toastStyles.itemFromTop : toastStyles.itemFromBottom,\n depth != null && stackSx(depth, fromTop),\n toast.closing && toastStyles.itemClosing,\n ],\n },\n itemProps,\n {\n // 重要的通知打断播报(同 Sonner);其余随列表的 aria-live=\"polite\"\n 'aria-live': toast.important ? 'assertive' : undefined,\n 'aria-atomic': toast.important || undefined,\n ref: (element: unknown) => {\n item = toElement(element);\n presence.ref(element);\n },\n onPointerdown,\n onKeydown,\n },\n )}\n data-state={presence.state}\n >\n <Collapse\n {...mergePartProps<CollapseProps>(\n { propsContent: { sx: toastStyles.gap } },\n propsCollapse,\n )}\n _open={!toast.closing}\n >\n <Alert\n {...mergePartProps<AlertProps>(\n {\n variant: 'surface',\n tone: toast.tone ?? 'neutral',\n icon: toast.icon,\n loading: toast.loading,\n title: toast.title,\n description: toast.description,\n action: toast.action,\n sx: toastStyles.toast,\n },\n toastProps,\n { onClose: toast.closable === false ? undefined : close },\n )}\n />\n {progress && toast.countdown && (\n <span\n key={toast.countdown.id}\n {...mergeAttrs<'span'>({ sx: toastStyles.countdown }, propsProgress, {\n sx: [\n toastCountdownStyles.duration(`${toast.countdown.duration}ms`),\n controller.paused && toastStyles.countdownPaused,\n ],\n 'aria-hidden': true,\n })}\n />\n )}\n </Collapse>\n </li>\n );\n };\n },\n { name: 'ToastItem' },\n);\n\n/** 通知的显示区域:放一个即可;模态打开时自动移进最上层的模态 */\nexport const Toaster = _component(\n ({\n controller,\n placement = 'bottom-end',\n max = 3,\n stack = false,\n progress = false,\n propsList,\n propsItem,\n propsToast,\n propsProgress,\n propsCollapse,\n ...rest\n }: ToasterProps) => {\n const lang = useLang();\n let region = _state.raw<HTMLElement | null>(null);\n let hovering = _state(false);\n let focused = _state(false);\n const pageVisible = usePageVisible();\n // 叠放时悬停或聚焦就展开;展开、收起时各项从旧位置平移过去\n let list = _state.raw<HTMLElement | null>(null);\n let expanded = _state(false);\n const layout = useLayoutAnimation(() => list, { children: ':scope > li' });\n watch(\n () => hovering || focused,\n (next) => {\n if (stack) void layout.change(() => (expanded = next));\n else expanded = next;\n },\n );\n // 进入通知区域之前焦点所在的元素:最后一条通知被关闭后焦点回到这里\n let outsideFocus: HTMLElement | null = null;\n\n _effect(() => {\n if (hovering || focused || !pageVisible.value) controller.pause();\n else controller.resume();\n });\n\n // 移动到别的父元素(Teleport 换目标)时浏览器会关掉 popover,移完重新打开\n const reopen = () => {\n if (region?.isConnected && !region.matches(':popover-open')) region.showPopover();\n };\n watch(topModal, () => void nextTick(reopen));\n\n // F8 跳到通知区域(同 Radix Toast);输入框里也能用\n const noHotkeys: HotkeyMap = {};\n useHotkeys(\n () => (region && controller.toasts.length ? { F8: () => region?.focus() } : noHotkeys),\n { inInputs: true },\n );\n onMounted(reopen);\n // 只给显示出来的通知计时:告诉控制器最多显示几条\n watch(\n () => max,\n (limit) => controller.setLimit(limit),\n { immediate: true },\n );\n onBeforeUnmount(() => {\n controller.setLimit(Infinity);\n controller.resume();\n });\n\n function onFocusin(event: FocusEvent) {\n focused = true;\n const from = event.relatedTarget;\n if (from instanceof HTMLElement && !region?.contains(from)) outsideFocus = from;\n }\n function onFocusout(event: FocusEvent) {\n const to = event.relatedTarget;\n if (!(to instanceof Node && region?.contains(to))) focused = false;\n }\n\n return () => {\n const fromTop = placement.startsWith('top');\n const visible = controller.toasts.slice(-max);\n // 深度只数还在显示的:正在离场的不占一层\n let depth = visible.filter((toast) => !toast.closing).length;\n const depths = visible.map((toast) => (toast.closing ? depth : --depth));\n const stacked = stack && !expanded;\n return (\n <Teleport to={topModal() ?? 'body'}>\n <ConfigScope>\n <section\n {...mergeAttrs<'section'>(\n {\n sx: [toastStyles.region, toastPlacementStyles[placement]],\n 'aria-label': lang.toasterLabel,\n },\n rest,\n {\n ref: _toRef(region),\n popover: 'manual',\n tabindex: -1,\n onPointerenter: () => (hovering = true),\n onPointerleave: () => (hovering = false),\n onFocusin,\n onFocusout,\n },\n )}\n data-placement={placement}\n data-expanded={stack ? String(!stacked) : undefined}\n >\n <FlexOrderedList\n {...mergePartProps<FlexProps<'ol'>>(\n // 新通知靠近所在的边缘:在顶部时最新的在最上面\n { direction: fromTop ? 'column-reverse' : 'column' },\n propsList,\n {\n ref: (value: unknown) => (list = toElement(value)),\n 'aria-live': 'polite',\n },\n )}\n >\n {visible.map((toast, index) => (\n <ToastItem\n key={toast.id}\n depth={stacked ? depths[index]! : null}\n toast={toast}\n controller={controller}\n fromTop={fromTop}\n fallbackFocus={() => outsideFocus}\n propsItem={propsItem}\n propsToast={propsToast}\n progress={progress}\n propsProgress={propsProgress}\n propsCollapse={propsCollapse}\n />\n ))}\n </FlexOrderedList>\n </section>\n </ConfigScope>\n </Teleport>\n );\n };\n },\n);\n"],"mappings":"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"}
|
package/dist/form/Field.d.ts
CHANGED
package/dist/form/Field.js
CHANGED
|
@@ -9,7 +9,7 @@ import { FieldLayoutContext } from "./field-layout.js";
|
|
|
9
9
|
import { FormContext } from "./Form.js";
|
|
10
10
|
import { Fragment, cloneVNode, createVNode, isVNode, onBeforeUnmount, unref, useId, watch } from "vue";
|
|
11
11
|
import { _component, childrenProp, createContext, effect, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
12
|
-
import
|
|
12
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
13
13
|
import { Asterisk } from "@lucide/icons";
|
|
14
14
|
//#region src/form/Field.tsx
|
|
15
15
|
/**
|
package/dist/form/Field.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Field.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_createVNode","_mergeProps","Text","_vue_unref"],"sources":["../../src/form/Field.tsx"],"sourcesContent":["/**\n * 表单字段:标签 + 控件 + 说明 + 错误信息,并把它们关联起来(参考 Ark UI Field、React Aria 的 Label / Description / FieldError)。\n *\n * <Field label=\"邮箱\" description=\"用于找回密码\" error={errors.email} required>\n * <TextField _value={form.email} type=\"email\" />\n * </Field>\n *\n * Field 经上下文告诉里面的控件:控件的 id(标签的 for 指向它)、标签的 id(不是原生输入的控件用 aria-labelledby)、\n * 说明与错误的 id(aria-describedby),以及 invalid / required / disabled / readonly。\n * 控件上显式写的状态优先于 Field 的。控件用 useFieldControl 读取这些信息,单独使用(不在 Field 里)时照常工作。\n * 在 Form 里写了 name 时,错误信息取自表单控制器(useForm),焦点离开字段时报告失焦(何时显示错误见 useForm);\n * 里面只有一个控件、控件上没写值时自动绑定表单的这个字段(valueProp 决定写 _value 还是 _checked),\n * 标签与控件登记给表单,错误汇总(FormErrorSummary)据此列出字段名、跳到控件。\n *\n * 标签可以放在起始边(`labelPlacement=\"start\"`):标签一列、控件一列,标签与控件的第一行文字按基线对齐,\n * 多行文本框、勾选组也对得齐。通常在 Form、FormSection 上统一设置(见 field-layout),整组的只读、不可用同样从那里来。\n *\n * 部件:Root(div)、Label(Label)、Control(div,标签在起始边时包住控件、说明与错误)、\n * Description(Text)、Error(Text,带警示图标)。\n */\nimport { Asterisk } from '@lucide/icons';\nimport { createContext, _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n cloneVNode,\n Fragment,\n isVNode,\n onBeforeUnmount,\n useId,\n watch,\n type VNode,\n type VNodeChild,\n} from 'vue';\nimport { Icon, type IconProps } from '../base/Icon';\nimport { Text, type TextProps } from '../base/Text';\nimport { visuallyHiddenStyles } from '../base/VisuallyHidden';\nimport { plainText } from '../utils/data/text';\nimport { focusControl } from '../utils/dom/focus';\nimport { hasContent, mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { statusIcons } from '../utils/style/tone-styles';\nimport {\n FieldLayoutContext,\n type FieldLabelAligns,\n type FieldLabelPlacements,\n} from './field-layout';\nimport { FormContext } from './Form';\nimport type { FieldConstraints } from './form-constraints';\n\nconst NO_CONSTRAINTS: FieldConstraints = Object.freeze({});\n\n/** Field 交给控件的信息 */\nexport interface FieldState {\n /** 控件(主元素)的 id,标签的 for 指向它 */\n readonly controlId: string;\n /** 标签的 id:控件不是原生输入元素(滑块、单选组)时用 aria-labelledby 指向它 */\n readonly labelId: string | undefined;\n /** 说明与错误信息的 id,空格分隔,给 aria-describedby */\n readonly describedBy: string | undefined;\n /** 校验未通过 */\n readonly invalid: boolean;\n /** 必填 */\n readonly required: boolean;\n /** 不可用 */\n readonly disabled: boolean;\n /** 只读 */\n readonly readonly: boolean;\n /** 从表单 schema 推出的约束(在 Form 里写了 name 时);控件据此加 maxlength、min / max 等 */\n readonly constraints: FieldConstraints;\n /**\n * 认领 Field 的 id 与标签:Field 里有几个控件时(一组勾选框),只有第一个控件拿 Field 的 id、用它的标签当名字,\n * 其余控件留着自己的名字(勾选框自己的文字),id 也不重复。认领到了返回 true\n */\n claim?(token: symbol): boolean;\n /** 认领的控件卸载了:下一个控件可以认领 */\n release?(token: symbol): void;\n}\n\n/** Field 的上下文:自定义控件用 useFieldControl 接入,一般不直接读它;null 表示子树不属于任何 Field */\nexport const FieldContext = createContext<FieldState | null>('Field');\n\n/** 控件自己的状态(不写时取 Field 的) */\nexport interface FieldControlOptions {\n /** 控件上显式写的 id */\n id?: string;\n /** 校验未通过 */\n invalid?: boolean;\n /** 必填;在 Form 里写了 name 时默认按表单的 schema(如 z.string().min(1)) */\n required?: boolean;\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n}\n\n/** useFieldControl 的选项 */\nexport interface FieldControlUse {\n /** 输入交给里面的另一个控件(DatePicker 里的 DateField):子树仍属于 Field,由那个控件接 */\n delegate?: boolean;\n}\n\n/** 控件合并 Field 之后的状态与关联属性 */\nexport interface FieldControl {\n /** 控件的 id:显式写的优先,其次是 Field 给的 */\n id: string | undefined;\n /** 不是原生输入元素的控件用它作 aria-labelledby */\n labelledBy: string | undefined;\n /** aria-describedby */\n describedBy: string | undefined;\n /** 校验未通过 */\n invalid: boolean;\n /** 必填 */\n required: boolean;\n /** 不可用 */\n disabled: boolean;\n /** 只读 */\n readonly: boolean;\n /** 从表单 schema 推出的约束;不在 Field 里、或推不出时为空对象。控件上显式写的属性优先 */\n constraints: FieldConstraints;\n}\n\n/**\n * 所在的表单重置时(form.reset()、type=\"reset\" 的按钮)调用:控件丢掉自己还没写回的输入(日期分段打了一半)。\n * 值本身由表单改回去;只是半截输入时值一直是 null,重置前后没有变化,控件不知道要清。在 setup 里调用\n */\nexport function useFormReset(onReset: () => void): void {\n const form = FormContext.inject(null);\n if (form) watch(() => form.resetCount, onReset);\n}\n\n/**\n * 控件读取所在 Field 的信息(在 setup 里调用,返回的函数在渲染时调用):\n * 控件上显式写的状态优先;不在 Field 里时用控件自己的,不可用与只读再看所在的 Form、FormSection。\n * 控件里再嵌的控件(Select 的搜索框、区间的两个框、时间面板的列表)不是 Field 的控件,\n * 拿到 Field 的 id、说明与必填会重复 id、让表单提交被空的搜索框拦住:调用后子树与 Field 隔开,\n * 除非写了 delegate\n */\nexport function useFieldControl(\n read: () => FieldControlOptions,\n { delegate = false }: FieldControlUse = {},\n): () => FieldControl {\n const field = FieldContext.inject(null);\n if (!delegate) FieldContext.provide(null);\n const layout = field ? null : FieldLayoutContext.inject(null);\n // 把输入交给里面控件的(delegate)不认领:由里面那个控件认领;它自己仍用 Field 的标签\n const token = Symbol('field-control');\n const owns = field == null ? false : delegate || (field.claim?.(token) ?? true);\n if (field && !delegate) onBeforeUnmount(() => field.release?.(token));\n return () => {\n const own = read();\n return {\n id: own.id ?? (owns ? field?.controlId : undefined),\n labelledBy: owns ? field?.labelId : undefined,\n describedBy: field?.describedBy,\n invalid: own.invalid ?? field?.invalid ?? false,\n required: own.required ?? field?.required ?? false,\n disabled: own.disabled ?? field?.disabled ?? layout?.disabled ?? false,\n readonly: own.readonly ?? field?.readonly ?? layout?.readonly ?? false,\n constraints: field?.constraints ?? NO_CONSTRAINTS,\n };\n };\n}\n\n/** 未声明的属性落到 label 上 */\nexport interface LabelProps extends PartProps<'label'> {\n /** 必填:文字后加一个星号图标(对读屏隐藏,必填由控件的 required 告诉读屏) */\n required?: boolean;\n /** 不可用:变淡 */\n disabled?: boolean;\n /** 必填标记的部件属性 */\n propsRequired?: Partial<IconProps>;\n children?: VNodeChild;\n}\n\n/** Field 的样式:root、disabled、required */\nexport const labelStyles = css.create({\n root: {\n display: 'inline-flex',\n alignItems: 'baseline',\n gap: '_xs',\n fontSize: '_sm',\n fontWeight: '_medium',\n lineHeight: '_tight',\n color: '_text',\n },\n disabled: { opacity: '_disabled' },\n required: { alignSelf: 'flex-start', width: '0.7em', height: '0.7em', color: '_dangerText' },\n});\n\n/**\n * for 指向的不是原生能被标签关联的元素(单选组、滑块组、日期分段这类 role=\"group\")时,点标签浏览器什么也不做:\n * 改为聚焦它里面第一个能聚焦的控件(同点原生输入框的标签)\n */\nfunction focusGroupControl(event: MouseEvent) {\n const label = event.currentTarget as HTMLLabelElement;\n if (event.defaultPrevented || label.control || !label.htmlFor) return;\n const target = label.ownerDocument.getElementById(label.htmlFor);\n if (target) focusControl(target);\n}\n\n/** 表单标签(label):for 指向控件;Field 里自动关联,单独使用时自己写 for */\nexport const Label = _component(\n ({ required = false, disabled = false, propsRequired, children, ...rest }: LabelProps) =>\n () => (\n <label\n {...mergeAttrs<'label'>(\n { sx: [labelStyles.root, disabled && labelStyles.disabled] },\n rest,\n { onClick: focusGroupControl },\n )}\n data-disabled={disabled || undefined}\n >\n {children}\n {required && (\n <Icon\n {...mergePartProps<IconProps>(\n { icon: Asterisk, sx: labelStyles.required },\n propsRequired,\n )}\n />\n )}\n </label>\n ),\n);\n\n/** 未声明的属性落到外层 div 上 */\nexport interface FieldProps extends PartProps<'div'> {\n /** 在 Form 里对应的字段路径(如 `email`、`address.city`):错误取自表单控制器,只有一个控件时自动绑定它的值 */\n name?: string;\n /**\n * 自动绑定值时写到控件的哪个属性:默认 _value;控件声明了 _checked 而没有 _value(Switch、单个 Checkbox)时是 _checked\n */\n valueProp?: '_value' | '_checked';\n /** 标签 */\n label?: VNodeChild;\n /** 控件下方的说明 */\n description?: VNodeChild;\n /** 错误信息:给了(且 invalid 不是 false)就显示,并把控件标为出错;在 Form 里写了 name 时默认取表单的错误 */\n error?: VNodeChild;\n /** 校验未通过;不写时有 error 就算出错 */\n invalid?: boolean;\n /** 必填 */\n required?: boolean;\n /** 不可用;不写时取所在 Form、FormSection 的 */\n disabled?: boolean;\n /** 只读;不写时取所在 Form、FormSection 的 */\n readonly?: boolean;\n /** 标签放在哪;不写时取所在 Form、FormSection 的,都没写时在上方 */\n labelPlacement?: keyof FieldLabelPlacements;\n /** 标签在起始边时标签列的宽度:数字是 px,也可以写 CSS 长度;默认 `'8em'` */\n labelWidth?: number | string;\n /** 标签在起始边时文字的对齐,默认 end(贴着控件) */\n labelAlign?: keyof FieldLabelAligns;\n /**\n * 标签只给读屏:视觉上隐藏,仍是控件的名称(表格式的重复行只在第一行显示列名、紧凑的筛选条);\n * 这时不占标签列,控件单独一列\n */\n labelHidden?: boolean;\n /** 标签的部件属性 */\n propsLabel?: Partial<LabelProps>;\n /** 控件列(标签在起始边时包住控件、说明与错误的 div)的部件属性 */\n propsControl?: PartProps<'div'>;\n /** 说明的部件属性 */\n propsDescription?: Partial<TextProps>;\n /** 错误信息的部件属性 */\n propsError?: Partial<TextProps>;\n /** 控件 */\n children?: VNodeChild;\n}\n\n/** 控件的组件声明了这个属性(运行时的 props 定义) */\nfunction declares(node: VNode, key: string): boolean {\n const declared = (node.type as { props?: unknown }).props;\n if (Array.isArray(declared)) return declared.includes(key);\n return typeof declared === 'object' && declared !== null && key in declared;\n}\n\n/** Field 里唯一的控件:一个组件的 VNode(数组里只有一项也算);不是时 undefined */\nfunction soleControl(children: VNodeChild): VNode | undefined {\n const node = Array.isArray(children) && children.length === 1 ? children[0] : children;\n if (!isVNode(node) || typeof node.type === 'string' || node.type === Fragment) return undefined;\n return node;\n}\n\n/** 标签在起始边时默认的标签列宽度:放得下七八个汉字 */\nconst DEFAULT_LABEL_WIDTH = '8em';\n\n/** Field 的样式:root、start、label…、control、hint、error、errorIcon */\nexport const fieldStyles = css.create({\n root: { display: 'flex', flexDirection: 'column', gap: '_xs', minWidth: 0 },\n // 标签一列、控件一列;第一行按基线对齐:标签与输入框里的文字、勾选项的文字在同一条线上\n start: {\n display: 'grid',\n columnGap: '_md',\n rowGap: '_xs',\n alignItems: 'baseline',\n },\n labelStart: { justifySelf: 'start', textAlign: 'start' },\n labelEnd: { justifySelf: 'end', textAlign: 'end' },\n // 没有标签时控件仍放在第二列,与上下的字段对齐\n controlWithoutLabel: { gridColumnStart: '2' },\n control: { display: 'flex', flexDirection: 'column', gap: '_xs', minWidth: 0 },\n hint: { fontSize: '_sm', lineHeight: '_normal' },\n error: { display: 'inline-flex', alignItems: 'flex-start', gap: '_xs' },\n errorIcon: { flexShrink: 0, marginBlock: '0.25em' },\n});\n\n/** Field 的动态样式:标签列的宽度 */\nexport const fieldColumnStyles = css.create({\n columns: (labelWidth: string) => ({ gridTemplateColumns: `${labelWidth} minmax(0, 1fr)` }),\n});\n\n/** 表单字段:标签、控件、说明、错误信息,自动关联 id 与状态 */\nexport const Field = _component(\n ({\n name,\n valueProp,\n label,\n description,\n error,\n invalid,\n required,\n disabled,\n readonly,\n labelPlacement,\n labelWidth,\n labelAlign,\n labelHidden = false,\n propsLabel,\n propsControl,\n propsDescription,\n propsError,\n children,\n ...rest\n }: FieldProps) => {\n const id = useId();\n const ids = {\n control: `${id}-control`,\n label: `${id}-label`,\n description: `${id}-description`,\n error: `${id}-error`,\n };\n const form = FormContext.inject(null);\n const layout = FieldLayoutContext.inject(null);\n // error={cond && '…'} 条件不成立时是 false:当作没写,用表单的错误\n const message = () =>\n hasContent(error) ? error : name != null ? form?.visibleError(name) : undefined;\n const showError = () => hasContent(message()) && invalid !== false;\n const constraints = () => (name != null && form ? form.constraints(name) : NO_CONSTRAINTS);\n const isRequired = () => required ?? constraints().required ?? false;\n const isDisabled = () => disabled ?? layout?.disabled ?? false;\n const isReadonly = () => readonly ?? layout?.readonly ?? false;\n\n // 第一个接入的控件认领 id 与标签(见 FieldState.claim)\n let owner: symbol | null = null;\n FieldContext.provide({\n claim: (token) => {\n owner ??= token;\n return owner === token;\n },\n release: (token) => {\n if (owner === token) owner = null;\n },\n controlId: ids.control,\n get labelId() {\n return hasContent(label) ? ids.label : undefined;\n },\n get describedBy() {\n const parts = [hasContent(description) && ids.description, showError() && ids.error];\n return parts.filter(Boolean).join(' ') || undefined;\n },\n get invalid() {\n return invalid ?? hasContent(message());\n },\n get required() {\n return isRequired();\n },\n get constraints() {\n return constraints();\n },\n get disabled() {\n return isDisabled();\n },\n get readonly() {\n return isReadonly();\n },\n });\n\n // 登记给表单:错误汇总据此显示字段名、跳到控件\n _effect(() =>\n name != null && form\n ? form.register(name, { label: plainText(label) ?? name, controlId: ids.control })\n : undefined,\n );\n\n /** 只有一个控件、控件上没写值时,自动绑定表单的这个字段(同 Ant Design Form.Item 的 name) */\n function bindValue(content: VNodeChild): VNodeChild {\n const control = name != null && form ? soleControl(content) : undefined;\n if (!control || !form) return content;\n const key =\n valueProp ??\n (declares(control, '_checked') && !declares(control, '_value') ? '_checked' : '_value');\n if (control.props && key in control.props) return content;\n const path = name!;\n return cloneVNode(control, {\n [key]: form.getValue(path),\n [`onUpdate:${key}`]: (value: unknown) => form.setValue(path, value),\n });\n }\n\n // 焦点离开整个字段(不是在字段内部移动)时报告失焦\n function onFocusout(event: FocusEvent) {\n const next = event.relatedTarget;\n const field = event.currentTarget as HTMLElement;\n if (name != null && !(next instanceof Node && field.contains(next))) form?.blur(name);\n }\n\n return () => {\n const placement = labelPlacement ?? layout?.labelPlacement ?? 'top';\n const start = placement === 'start' && !labelHidden;\n const width = labelWidth ?? layout?.labelWidth ?? DEFAULT_LABEL_WIDTH;\n const align = labelAlign ?? layout?.labelAlign ?? 'end';\n const hints = [\n hasContent(description) && (\n <Text\n {...mergePartProps<TextProps>(\n { tone: 'muted', sx: fieldStyles.hint },\n propsDescription,\n {\n id: ids.description,\n },\n )}\n >\n {description}\n </Text>\n ),\n showError() && (\n <Text\n {...mergePartProps<TextProps>(\n { tone: 'danger', sx: [fieldStyles.hint, fieldStyles.error] },\n propsError,\n { id: ids.error },\n )}\n >\n <Icon icon={statusIcons.danger} sx={fieldStyles.errorIcon} />\n {message()}\n </Text>\n ),\n ];\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: start\n ? [\n fieldStyles.start,\n fieldColumnStyles.columns(typeof width === 'number' ? `${width}px` : width),\n ]\n : fieldStyles.root,\n },\n rest,\n { onFocusout },\n )}\n data-invalid={(invalid ?? message() != null) || undefined}\n data-disabled={isDisabled() || undefined}\n data-label-placement={placement}\n >\n {hasContent(label) && (\n <Label\n {...mergePartProps<LabelProps>(\n {\n required: isRequired(),\n disabled: isDisabled(),\n sx: labelHidden\n ? visuallyHiddenStyles.hidden\n : start && (align === 'end' ? fieldStyles.labelEnd : fieldStyles.labelStart),\n },\n propsLabel,\n { id: ids.label, for: ids.control },\n )}\n >\n {label}\n </Label>\n )}\n {start ? (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [fieldStyles.control, !hasContent(label) && fieldStyles.controlWithoutLabel],\n },\n propsControl,\n )}\n >\n {bindValue(children)}\n {hints}\n </div>\n ) : (\n [bindValue(children), hints]\n )}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Field.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_createVNode","_mergeProps","Text","_vue_unref"],"sources":["../../src/form/Field.tsx"],"sourcesContent":["/**\n * 表单字段:标签 + 控件 + 说明 + 错误信息,并把它们关联起来(参考 Ark UI Field、React Aria 的 Label / Description / FieldError)。\n *\n * <Field label=\"邮箱\" description=\"用于找回密码\" error={errors.email} required>\n * <TextField _value={form.email} type=\"email\" />\n * </Field>\n *\n * Field 经上下文告诉里面的控件:控件的 id(标签的 for 指向它)、标签的 id(不是原生输入的控件用 aria-labelledby)、\n * 说明与错误的 id(aria-describedby),以及 invalid / required / disabled / readonly。\n * 控件上显式写的状态优先于 Field 的。控件用 useFieldControl 读取这些信息,单独使用(不在 Field 里)时照常工作。\n * 在 Form 里写了 name 时,错误信息取自表单控制器(useForm),焦点离开字段时报告失焦(何时显示错误见 useForm);\n * 里面只有一个控件、控件上没写值时自动绑定表单的这个字段(valueProp 决定写 _value 还是 _checked),\n * 标签与控件登记给表单,错误汇总(FormErrorSummary)据此列出字段名、跳到控件。\n *\n * 标签可以放在起始边(`labelPlacement=\"start\"`):标签一列、控件一列,标签与控件的第一行文字按基线对齐,\n * 多行文本框、勾选组也对得齐。通常在 Form、FormSection 上统一设置(见 field-layout),整组的只读、不可用同样从那里来。\n *\n * 部件:Root(div)、Label(Label)、Control(div,标签在起始边时包住控件、说明与错误)、\n * Description(Text)、Error(Text,带警示图标)。\n */\nimport { Asterisk } from '@lucide/icons';\nimport { createContext, _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport {\n cloneVNode,\n Fragment,\n isVNode,\n onBeforeUnmount,\n useId,\n watch,\n type VNode,\n type VNodeChild,\n} from 'vue';\nimport { Icon, type IconProps } from '../base/Icon';\nimport { Text, type TextProps } from '../base/Text';\nimport { visuallyHiddenStyles } from '../base/VisuallyHidden';\nimport { plainText } from '../utils/data/text';\nimport { focusControl } from '../utils/dom/focus';\nimport { hasContent, mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { statusIcons } from '../utils/style/tone-styles';\nimport {\n FieldLayoutContext,\n type FieldLabelAligns,\n type FieldLabelPlacements,\n} from './field-layout';\nimport { FormContext } from './Form';\nimport type { FieldConstraints } from './form-constraints';\n\nconst NO_CONSTRAINTS: FieldConstraints = Object.freeze({});\n\n/** Field 交给控件的信息 */\nexport interface FieldState {\n /** 控件(主元素)的 id,标签的 for 指向它 */\n readonly controlId: string;\n /** 标签的 id:控件不是原生输入元素(滑块、单选组)时用 aria-labelledby 指向它 */\n readonly labelId: string | undefined;\n /** 说明与错误信息的 id,空格分隔,给 aria-describedby */\n readonly describedBy: string | undefined;\n /** 校验未通过 */\n readonly invalid: boolean;\n /** 必填 */\n readonly required: boolean;\n /** 不可用 */\n readonly disabled: boolean;\n /** 只读 */\n readonly readonly: boolean;\n /** 从表单 schema 推出的约束(在 Form 里写了 name 时);控件据此加 maxlength、min / max 等 */\n readonly constraints: FieldConstraints;\n /**\n * 认领 Field 的 id 与标签:Field 里有几个控件时(一组勾选框),只有第一个控件拿 Field 的 id、用它的标签当名字,\n * 其余控件留着自己的名字(勾选框自己的文字),id 也不重复。认领到了返回 true\n */\n claim?(token: symbol): boolean;\n /** 认领的控件卸载了:下一个控件可以认领 */\n release?(token: symbol): void;\n}\n\n/** Field 的上下文:自定义控件用 useFieldControl 接入,一般不直接读它;null 表示子树不属于任何 Field */\nexport const FieldContext = createContext<FieldState | null>('Field');\n\n/** 控件自己的状态(不写时取 Field 的) */\nexport interface FieldControlOptions {\n /** 控件上显式写的 id */\n id?: string;\n /** 校验未通过 */\n invalid?: boolean;\n /** 必填;在 Form 里写了 name 时默认按表单的 schema(如 z.string().min(1)) */\n required?: boolean;\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n}\n\n/** useFieldControl 的选项 */\nexport interface FieldControlUse {\n /** 输入交给里面的另一个控件(DatePicker 里的 DateField):子树仍属于 Field,由那个控件接 */\n delegate?: boolean;\n}\n\n/** 控件合并 Field 之后的状态与关联属性 */\nexport interface FieldControl {\n /** 控件的 id:显式写的优先,其次是 Field 给的 */\n id: string | undefined;\n /** 不是原生输入元素的控件用它作 aria-labelledby */\n labelledBy: string | undefined;\n /** aria-describedby */\n describedBy: string | undefined;\n /** 校验未通过 */\n invalid: boolean;\n /** 必填 */\n required: boolean;\n /** 不可用 */\n disabled: boolean;\n /** 只读 */\n readonly: boolean;\n /** 从表单 schema 推出的约束;不在 Field 里、或推不出时为空对象。控件上显式写的属性优先 */\n constraints: FieldConstraints;\n}\n\n/**\n * 所在的表单重置时(form.reset()、type=\"reset\" 的按钮)调用:控件丢掉自己还没写回的输入(日期分段打了一半)。\n * 值本身由表单改回去;只是半截输入时值一直是 null,重置前后没有变化,控件不知道要清。在 setup 里调用\n */\nexport function useFormReset(onReset: () => void): void {\n const form = FormContext.inject(null);\n if (form) watch(() => form.resetCount, onReset);\n}\n\n/**\n * 控件读取所在 Field 的信息(在 setup 里调用,返回的函数在渲染时调用):\n * 控件上显式写的状态优先;不在 Field 里时用控件自己的,不可用与只读再看所在的 Form、FormSection。\n * 控件里再嵌的控件(Select 的搜索框、区间的两个框、时间面板的列表)不是 Field 的控件,\n * 拿到 Field 的 id、说明与必填会重复 id、让表单提交被空的搜索框拦住:调用后子树与 Field 隔开,\n * 除非写了 delegate\n */\nexport function useFieldControl(\n read: () => FieldControlOptions,\n { delegate = false }: FieldControlUse = {},\n): () => FieldControl {\n const field = FieldContext.inject(null);\n if (!delegate) FieldContext.provide(null);\n const layout = field ? null : FieldLayoutContext.inject(null);\n // 把输入交给里面控件的(delegate)不认领:由里面那个控件认领;它自己仍用 Field 的标签\n const token = Symbol('field-control');\n const owns = field == null ? false : delegate || (field.claim?.(token) ?? true);\n if (field && !delegate) onBeforeUnmount(() => field.release?.(token));\n return () => {\n const own = read();\n return {\n id: own.id ?? (owns ? field?.controlId : undefined),\n labelledBy: owns ? field?.labelId : undefined,\n describedBy: field?.describedBy,\n invalid: own.invalid ?? field?.invalid ?? false,\n required: own.required ?? field?.required ?? false,\n disabled: own.disabled ?? field?.disabled ?? layout?.disabled ?? false,\n readonly: own.readonly ?? field?.readonly ?? layout?.readonly ?? false,\n constraints: field?.constraints ?? NO_CONSTRAINTS,\n };\n };\n}\n\n/** 未声明的属性落到 label 上 */\nexport interface LabelProps extends PartProps<'label'> {\n /** 必填:文字后加一个星号图标(对读屏隐藏,必填由控件的 required 告诉读屏) */\n required?: boolean;\n /** 不可用:变淡 */\n disabled?: boolean;\n /** 必填标记的部件属性 */\n propsRequired?: Partial<IconProps>;\n children?: VNodeChild;\n}\n\n/** Field 的样式:root、disabled、required */\nexport const labelStyles = css.create({\n root: {\n display: 'inline-flex',\n alignItems: 'baseline',\n gap: '_xs',\n fontSize: '_sm',\n fontWeight: '_medium',\n lineHeight: '_tight',\n color: '_text',\n },\n disabled: { opacity: '_disabled' },\n required: { alignSelf: 'flex-start', width: '0.7em', height: '0.7em', color: '_dangerText' },\n});\n\n/**\n * for 指向的不是原生能被标签关联的元素(单选组、滑块组、日期分段这类 role=\"group\")时,点标签浏览器什么也不做:\n * 改为聚焦它里面第一个能聚焦的控件(同点原生输入框的标签)\n */\nfunction focusGroupControl(event: MouseEvent) {\n const label = event.currentTarget as HTMLLabelElement;\n if (event.defaultPrevented || label.control || !label.htmlFor) return;\n const target = label.ownerDocument.getElementById(label.htmlFor);\n if (target) focusControl(target);\n}\n\n/** 表单标签(label):for 指向控件;Field 里自动关联,单独使用时自己写 for */\nexport const Label = _component(\n ({ required = false, disabled = false, propsRequired, children, ...rest }: LabelProps) =>\n () => (\n <label\n {...mergeAttrs<'label'>(\n { sx: [labelStyles.root, disabled && labelStyles.disabled] },\n rest,\n { onClick: focusGroupControl },\n )}\n data-disabled={disabled || undefined}\n >\n {children}\n {required && (\n <Icon\n {...mergePartProps<IconProps>(\n { icon: Asterisk, sx: labelStyles.required },\n propsRequired,\n )}\n />\n )}\n </label>\n ),\n);\n\n/** 未声明的属性落到外层 div 上 */\nexport interface FieldProps extends PartProps<'div'> {\n /** 在 Form 里对应的字段路径(如 `email`、`address.city`):错误取自表单控制器,只有一个控件时自动绑定它的值 */\n name?: string;\n /**\n * 自动绑定值时写到控件的哪个属性:默认 _value;控件声明了 _checked 而没有 _value(Switch、单个 Checkbox)时是 _checked\n */\n valueProp?: '_value' | '_checked';\n /** 标签 */\n label?: VNodeChild;\n /** 控件下方的说明 */\n description?: VNodeChild;\n /** 错误信息:给了(且 invalid 不是 false)就显示,并把控件标为出错;在 Form 里写了 name 时默认取表单的错误 */\n error?: VNodeChild;\n /** 校验未通过;不写时有 error 就算出错 */\n invalid?: boolean;\n /** 必填 */\n required?: boolean;\n /** 不可用;不写时取所在 Form、FormSection 的 */\n disabled?: boolean;\n /** 只读;不写时取所在 Form、FormSection 的 */\n readonly?: boolean;\n /** 标签放在哪;不写时取所在 Form、FormSection 的,都没写时在上方 */\n labelPlacement?: keyof FieldLabelPlacements;\n /** 标签在起始边时标签列的宽度:数字是 px,也可以写 CSS 长度;默认 `'8em'` */\n labelWidth?: number | string;\n /** 标签在起始边时文字的对齐,默认 end(贴着控件) */\n labelAlign?: keyof FieldLabelAligns;\n /**\n * 标签只给读屏:视觉上隐藏,仍是控件的名称(表格式的重复行只在第一行显示列名、紧凑的筛选条);\n * 这时不占标签列,控件单独一列\n */\n labelHidden?: boolean;\n /** 标签的部件属性 */\n propsLabel?: Partial<LabelProps>;\n /** 控件列(标签在起始边时包住控件、说明与错误的 div)的部件属性 */\n propsControl?: PartProps<'div'>;\n /** 说明的部件属性 */\n propsDescription?: Partial<TextProps>;\n /** 错误信息的部件属性 */\n propsError?: Partial<TextProps>;\n /** 控件 */\n children?: VNodeChild;\n}\n\n/** 控件的组件声明了这个属性(运行时的 props 定义) */\nfunction declares(node: VNode, key: string): boolean {\n const declared = (node.type as { props?: unknown }).props;\n if (Array.isArray(declared)) return declared.includes(key);\n return typeof declared === 'object' && declared !== null && key in declared;\n}\n\n/** Field 里唯一的控件:一个组件的 VNode(数组里只有一项也算);不是时 undefined */\nfunction soleControl(children: VNodeChild): VNode | undefined {\n const node = Array.isArray(children) && children.length === 1 ? children[0] : children;\n if (!isVNode(node) || typeof node.type === 'string' || node.type === Fragment) return undefined;\n return node;\n}\n\n/** 标签在起始边时默认的标签列宽度:放得下七八个汉字 */\nconst DEFAULT_LABEL_WIDTH = '8em';\n\n/** Field 的样式:root、start、label…、control、hint、error、errorIcon */\nexport const fieldStyles = css.create({\n root: { display: 'flex', flexDirection: 'column', gap: '_xs', minWidth: 0 },\n // 标签一列、控件一列;第一行按基线对齐:标签与输入框里的文字、勾选项的文字在同一条线上\n start: {\n display: 'grid',\n columnGap: '_md',\n rowGap: '_xs',\n alignItems: 'baseline',\n },\n labelStart: { justifySelf: 'start', textAlign: 'start' },\n labelEnd: { justifySelf: 'end', textAlign: 'end' },\n // 没有标签时控件仍放在第二列,与上下的字段对齐\n controlWithoutLabel: { gridColumnStart: '2' },\n control: { display: 'flex', flexDirection: 'column', gap: '_xs', minWidth: 0 },\n hint: { fontSize: '_sm', lineHeight: '_normal' },\n error: { display: 'inline-flex', alignItems: 'flex-start', gap: '_xs' },\n errorIcon: { flexShrink: 0, marginBlock: '0.25em' },\n});\n\n/** Field 的动态样式:标签列的宽度 */\nexport const fieldColumnStyles = css.create({\n columns: (labelWidth: string) => ({ gridTemplateColumns: `${labelWidth} minmax(0, 1fr)` }),\n});\n\n/** 表单字段:标签、控件、说明、错误信息,自动关联 id 与状态 */\nexport const Field = _component(\n ({\n name,\n valueProp,\n label,\n description,\n error,\n invalid,\n required,\n disabled,\n readonly,\n labelPlacement,\n labelWidth,\n labelAlign,\n labelHidden = false,\n propsLabel,\n propsControl,\n propsDescription,\n propsError,\n children,\n ...rest\n }: FieldProps) => {\n const id = useId();\n const ids = {\n control: `${id}-control`,\n label: `${id}-label`,\n description: `${id}-description`,\n error: `${id}-error`,\n };\n const form = FormContext.inject(null);\n const layout = FieldLayoutContext.inject(null);\n // error={cond && '…'} 条件不成立时是 false:当作没写,用表单的错误\n const message = () =>\n hasContent(error) ? error : name != null ? form?.visibleError(name) : undefined;\n const showError = () => hasContent(message()) && invalid !== false;\n const constraints = () => (name != null && form ? form.constraints(name) : NO_CONSTRAINTS);\n const isRequired = () => required ?? constraints().required ?? false;\n const isDisabled = () => disabled ?? layout?.disabled ?? false;\n const isReadonly = () => readonly ?? layout?.readonly ?? false;\n\n // 第一个接入的控件认领 id 与标签(见 FieldState.claim)\n let owner: symbol | null = null;\n FieldContext.provide({\n claim: (token) => {\n owner ??= token;\n return owner === token;\n },\n release: (token) => {\n if (owner === token) owner = null;\n },\n controlId: ids.control,\n get labelId() {\n return hasContent(label) ? ids.label : undefined;\n },\n get describedBy() {\n const parts = [hasContent(description) && ids.description, showError() && ids.error];\n return parts.filter(Boolean).join(' ') || undefined;\n },\n get invalid() {\n return invalid ?? hasContent(message());\n },\n get required() {\n return isRequired();\n },\n get constraints() {\n return constraints();\n },\n get disabled() {\n return isDisabled();\n },\n get readonly() {\n return isReadonly();\n },\n });\n\n // 登记给表单:错误汇总据此显示字段名、跳到控件\n _effect(() =>\n name != null && form\n ? form.register(name, { label: plainText(label) ?? name, controlId: ids.control })\n : undefined,\n );\n\n /** 只有一个控件、控件上没写值时,自动绑定表单的这个字段(同 Ant Design Form.Item 的 name) */\n function bindValue(content: VNodeChild): VNodeChild {\n const control = name != null && form ? soleControl(content) : undefined;\n if (!control || !form) return content;\n const key =\n valueProp ??\n (declares(control, '_checked') && !declares(control, '_value') ? '_checked' : '_value');\n if (control.props && key in control.props) return content;\n const path = name!;\n return cloneVNode(control, {\n [key]: form.getValue(path),\n [`onUpdate:${key}`]: (value: unknown) => form.setValue(path, value),\n });\n }\n\n // 焦点离开整个字段(不是在字段内部移动)时报告失焦\n function onFocusout(event: FocusEvent) {\n const next = event.relatedTarget;\n const field = event.currentTarget as HTMLElement;\n if (name != null && !(next instanceof Node && field.contains(next))) form?.blur(name);\n }\n\n return () => {\n const placement = labelPlacement ?? layout?.labelPlacement ?? 'top';\n const start = placement === 'start' && !labelHidden;\n const width = labelWidth ?? layout?.labelWidth ?? DEFAULT_LABEL_WIDTH;\n const align = labelAlign ?? layout?.labelAlign ?? 'end';\n const hints = [\n hasContent(description) && (\n <Text\n {...mergePartProps<TextProps>(\n { tone: 'muted', sx: fieldStyles.hint },\n propsDescription,\n {\n id: ids.description,\n },\n )}\n >\n {description}\n </Text>\n ),\n showError() && (\n <Text\n {...mergePartProps<TextProps>(\n { tone: 'danger', sx: [fieldStyles.hint, fieldStyles.error] },\n propsError,\n { id: ids.error },\n )}\n >\n <Icon icon={statusIcons.danger} sx={fieldStyles.errorIcon} />\n {message()}\n </Text>\n ),\n ];\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: start\n ? [\n fieldStyles.start,\n fieldColumnStyles.columns(typeof width === 'number' ? `${width}px` : width),\n ]\n : fieldStyles.root,\n },\n rest,\n { onFocusout },\n )}\n data-invalid={(invalid ?? message() != null) || undefined}\n data-disabled={isDisabled() || undefined}\n data-label-placement={placement}\n >\n {hasContent(label) && (\n <Label\n {...mergePartProps<LabelProps>(\n {\n required: isRequired(),\n disabled: isDisabled(),\n sx: labelHidden\n ? visuallyHiddenStyles.hidden\n : start && (align === 'end' ? fieldStyles.labelEnd : fieldStyles.labelStart),\n },\n propsLabel,\n { id: ids.label, for: ids.control },\n )}\n >\n {label}\n </Label>\n )}\n {start ? (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [fieldStyles.control, !hasContent(label) && fieldStyles.controlWithoutLabel],\n },\n propsControl,\n )}\n >\n {bindValue(children)}\n {hints}\n </div>\n ) : (\n [bindValue(children), hints]\n )}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import { statusIcons } from "../utils/style/tone-styles.js";
|
|
|
7
7
|
import { FormContext } from "./Form.js";
|
|
8
8
|
import { createVNode } from "vue";
|
|
9
9
|
import { _component, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
10
|
-
import
|
|
10
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
11
11
|
//#region src/form/FormErrorSummary.tsx
|
|
12
12
|
/** 未声明的属性落到外层 div 上 */
|
|
13
13
|
/** FormErrorSummary 的样式:root、title、list、link */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormErrorSummary.js","names":["_vtp_readonlyProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/form/FormErrorSummary.tsx"],"sourcesContent":["/**\n * 错误汇总:提交没通过时在表单顶上列出各项错误(“有 3 项需要修改”),每项是链接,点了跳到那个字段的控件。\n * 放在 Form 里(通常是第一个);提交失败时 Form 把焦点移到它上面,读屏念出有几项、各是什么(GOV.UK 的 Error summary)。\n *\n * <Form controller={form}>\n * <FormErrorSummary />\n * <form.Field name=\"email\" label=\"邮箱\"><TextField /></form.Field>\n * </Form>\n *\n * 只列显示着的错误(失焦过、提交过的字段),按字段在表单里出现的顺序;改对一项它就从列表里消失,全改对了汇总收起。\n * 整份表单的错误(不属于哪个字段)排在最前,不带链接。字段名取自 Field 的标签。\n * 部件:Root(div,role=\"alert\" 之外可以聚焦)、Title(div)、List(ul)、Link(a)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport
|
|
1
|
+
{"version":3,"file":"FormErrorSummary.js","names":["_vtp_readonlyProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/form/FormErrorSummary.tsx"],"sourcesContent":["/**\n * 错误汇总:提交没通过时在表单顶上列出各项错误(“有 3 项需要修改”),每项是链接,点了跳到那个字段的控件。\n * 放在 Form 里(通常是第一个);提交失败时 Form 把焦点移到它上面,读屏念出有几项、各是什么(GOV.UK 的 Error summary)。\n *\n * <Form controller={form}>\n * <FormErrorSummary />\n * <form.Field name=\"email\" label=\"邮箱\"><TextField /></form.Field>\n * </Form>\n *\n * 只列显示着的错误(失焦过、提交过的字段),按字段在表单里出现的顺序;改对一项它就从列表里消失,全改对了汇总收起。\n * 整份表单的错误(不属于哪个字段)排在最前,不带链接。字段名取自 Field 的标签。\n * 部件:Root(div,role=\"alert\" 之外可以聚焦)、Title(div)、List(ul)、Link(a)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { Icon } from '../base/Icon';\nimport { useLang } from '../config/context';\nimport { focusControl } from '../utils/dom/focus';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { statusIcons } from '../utils/style/tone-styles';\nimport { FormContext } from './Form';\n\n/** 未声明的属性落到外层 div 上 */\nexport interface FormErrorSummaryProps extends PartProps<'div', 'title'> {\n /** 标题;不写时取语言包(有 N 项需要修改) */\n title?: (count: number) => VNodeChild;\n /** 标题的部件属性 */\n propsTitle?: PartProps<'div'>;\n /** 列表的部件属性 */\n propsList?: PartProps<'ul'>;\n /** 每一项链接的部件属性 */\n propsLink?: PartProps<'a'>;\n}\n\n/** FormErrorSummary 的样式:root、title、list、link */\nexport const formErrorSummaryStyles = css.create({\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: '_sm',\n padding: '_md',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_dangerBorder',\n borderRadius: '_md',\n backgroundColor: '_dangerSoft',\n color: '_text',\n },\n title: {\n display: 'flex',\n alignItems: 'center',\n gap: '_xs',\n fontWeight: '_semibold',\n color: '_dangerText',\n },\n list: { margin: 0, paddingInlineStart: '1.5em', display: 'grid', gap: '_xs' },\n link: {\n color: '_dangerText',\n textDecoration: { default: 'underline', ':hover': 'none' },\n textUnderlineOffset: '0.2em',\n },\n});\n\n/** 错误汇总:提交没通过时列出各项错误,点了跳到字段 */\nexport const FormErrorSummary = _component(\n ({ title, propsTitle, propsList, propsLink, ...rest }: FormErrorSummaryProps) => {\n const lang = useLang();\n const form = FormContext.inject(null);\n\n /** 显示着的错误:整份表单的在前,其余按字段在表单里出现的顺序 */\n const items = () => {\n if (!form || form.submitCount === 0) return [];\n const fields = [...form.fields].flatMap(([path, field]) => {\n const message = form.visibleError(path);\n return message ? [{ path, label: field.label, controlId: field.controlId, message }] : [];\n });\n return form.formError\n ? [{ path: '', label: '', controlId: '', message: form.formError }, ...fields]\n : fields;\n };\n\n function jump(event: MouseEvent, controlId: string) {\n event.preventDefault();\n const control = document.getElementById(controlId);\n if (control) focusControl(control);\n }\n\n return () => {\n const list = items();\n if (list.length === 0) return null;\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [formErrorSummaryStyles.root, focusRingStyles.visible] },\n rest,\n {\n // 提交失败时 Form 把焦点移到这里\n tabindex: -1,\n },\n )}\n data-form-error-summary=\"\"\n >\n <div {...mergeAttrs<'div'>({ sx: formErrorSummaryStyles.title }, propsTitle)}>\n <Icon icon={statusIcons.danger} />\n {title ? title(list.length) : lang.formErrorSummary(list.length)}\n </div>\n <ul {...mergeAttrs<'ul'>({ sx: formErrorSummaryStyles.list }, propsList)}>\n {list.map((item) => (\n <li key={item.path}>\n {item.controlId ? (\n <a\n {...mergeAttrs<'a'>({ sx: formErrorSummaryStyles.link }, propsLink, {\n href: `#${item.controlId}`,\n onClick: (event: MouseEvent) => jump(event, item.controlId),\n })}\n >\n {item.label ? lang.formErrorItem(item.label, item.message) : item.message}\n </a>\n ) : (\n item.message\n )}\n </li>\n ))}\n </ul>\n </div>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;;;;;AAqCA,IAAa,yBAAyB,IAAI,OAAO;CAC/C,MAAM;EACJ,SAAS;EACT,eAAe;EACf,KAAK;EACL,SAAS;EACT,aAAa;EACb,aAAa;EACb,aAAa;EACb,cAAc;EACd,iBAAiB;EACjB,OAAO;CACT;CACA,OAAO;EACL,SAAS;EACT,YAAY;EACZ,KAAK;EACL,YAAY;EACZ,OAAO;CACT;CACA,MAAM;EAAE,QAAQ;EAAG,oBAAoB;EAAS,SAAS;EAAQ,KAAK;CAAM;CAC5E,MAAM;EACJ,OAAO;EACP,gBAAgB;GAAE,SAAS;GAAa,UAAU;EAAO;EACzD,qBAAqB;CACvB;AACF,CAAC;;AAGD,IAAa,mBAAmB,0BAC9B,QAAA,SAAiF;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,aAAAA,aAAA,QAAA,YAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAlC,OAAIC,UAAA,QAAA,MAAA,IAAA;CACjD,MAAM,OAAO,QAAQ;CACrB,MAAM,OAAO,YAAY,OAAO,IAAI;;CAGpC,MAAM,cAAc;EAClB,IAAI,CAAC,QAAQ,KAAK,gBAAgB,GAAG,OAAO,CAAA;EAC5C,MAAM,SAAS,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,WAAW;GACzD,MAAM,UAAU,KAAK,aAAa,IAAI;GACtC,OAAO,UAAU,CAAC;IAAE;IAAM,OAAO,MAAM;IAAO,WAAW,MAAM;IAAW;GAAQ,CAAC,IAAI,CAAA;EACzF,CAAC;EACD,OAAO,KAAK,YACR,CAAC;GAAE,MAAM;GAAI,OAAO;GAAI,WAAW;GAAI,SAAS,KAAK;EAAU,GAAG,GAAG,MAAM,IAC3E;CACN;CAEA,SAAS,KAAK,OAAmB,WAAmB;EAClD,MAAM,eAAe;EACrB,MAAM,UAAU,SAAS,eAAe,SAAS;EACjD,IAAI,SAAS,aAAa,OAAO;CACnC;CAEA,aAAa;EACX,MAAM,OAAO,MAAM;EACnB,IAAI,KAAK,WAAW,GAAG,OAAO;EAC9B,OAAAC,YAAA,OAAAC,cAEQ,WACF,EAAE,IAAI,CAAC,uBAAuB,MAAM,gBAAgB,OAAO,EAAE,GAC7D,MACA,EAEE,UAAU,GACZ,CACF,GAAC,EAAA,2BAAA,GAAA,CAAA,GAAA,CAAAD,YAAA,OAGQ,WAAkB,EAAE,IAAI,uBAAuB,MAAM,GAAC,WAAA,KAAY,GAAC,CAAAA,YAAA,MAAA,EAAA,QAC9D,YAAY,OAAM,GAAA,IAAA,GAC7B,MAAA,QAAQ,MAAA,MAAM,KAAK,MAAM,IAAI,KAAK,iBAAiB,KAAK,MAAM,CAAC,CAAA,GAAAA,YAAA,MAE1D,WAAiB,EAAE,IAAI,uBAAuB,KAAK,GAAC,UAAA,KAAW,GAAC,CACrE,KAAK,KAAK,SAAIA,YAAA,MAAA,EAAA,OACJ,KAAK,KAAI,GAAA,CACf,KAAK,YAASA,YAAA,KAEP,WAAgB,EAAE,IAAI,uBAAuB,KAAK,GAAC,UAAA,OAAa;GAClE,MAAM,IAAI,KAAK;GACf,UAAU,UAAsB,KAAK,OAAO,KAAK,SAAS;EAC5D,CAAC,GAAC,CAED,KAAK,QAAQ,KAAK,cAAc,KAAK,OAAO,KAAK,OAAO,IAAI,KAAK,OAAO,CAAA,IAG3E,KAAK,OACN,CAAA,CAEJ,CAAC,CAAA,CAAA,CAAA;CAIV;AACF,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
|
package/dist/form/FormSection.js
CHANGED
|
@@ -10,7 +10,7 @@ import { Collapse } from "../display/Collapse.js";
|
|
|
10
10
|
import { provideFieldLayout } from "./field-layout.js";
|
|
11
11
|
import { createVNode, h, isVNode, unref, useId } from "vue";
|
|
12
12
|
import { _component, bindable, childrenProp, 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 { ChevronDown } from "@lucide/icons";
|
|
15
15
|
//#region src/form/FormSection.tsx
|
|
16
16
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormSection.js","names":["_isVNode","_vtp_readonlyProp","_vtp_bindable","_vtp_childrenProp","_vtp_restProps","_createVNode","_mergeProps","Text","_vue_unref"],"sources":["../../src/form/FormSection.tsx"],"sourcesContent":["/**\n * 表单里的一组字段:标题、说明、右侧的操作,下面一条细线,再下面是字段的栅格。长表单按主题分组(基本信息、计划与实施……)。\n *\n * <FormSection title=\"项目基本信息\" columns={2}>\n * <Field label=\"项目名称\">…</Field>\n * <Field label=\"任务类别\">…</Field>\n * <GridItem span=\"full\"><Field label=\"简要描述\">…</Field></GridItem>\n * </FormSection>\n *\n * columns 是最多几列:每列不窄于 minColumnWidth,容器窄时自动减少列数,不需要断点;跨列用 GridItem(多列时用 span=\"full\")。\n * 也是一层字段布局(field-layout):标签位置、宽度、对齐、只读、不可用写在这里只作用于这一组,没写的沿用 Form 的。\n * collapsible 时标题是展开收起的按钮(aria-expanded),收起的字段不能被 Tab 到。\n * 给了 id 就能当锚点:长表单旁边放一个 TableOfContents(items 用各组的 id 与标题)做分节导航,跳过来时让开粘性顶栏。\n * 语义:role=\"group\" 以标题为名称、说明为描述,标题是 h2–h6(headingLevel),读屏能按标题跳转。\n *\n * 部件:Root(div)、Header(div)、Heading(h2–h6)、Trigger(ButtonBase,collapsible 时)、Chevron(Icon)、\n * Description(Text)、Extra(div)、Body(div,字段的栅格)、Collapse(collapsible 时包住 Body)。\n */\nimport { ChevronDown } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { h, useId, type VNodeChild } from 'vue';\nimport { ButtonBase, type ButtonBaseProps } from '../base/ButtonBase';\nimport { Icon, type IconProps } from '../base/Icon';\nimport { Text, type TextProps } from '../base/Text';\nimport { space, t } from '../config/theme/tokens';\nimport { Collapse, type CollapseProps } from '../display/Collapse';\nimport { provideGridColumns } from '../layout/Grid';\nimport { hasContent, mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { disclosureStyles } from '../utils/style/transitions';\nimport { layoutVars } from '../utils/style/vars';\nimport { provideFieldLayout, type FieldLayout } from './field-layout';\n\n/** 角色与关联由组件管理;原生的 title 属性让给标题内容 */\nexport type FormSectionManaged = 'role' | 'title' | 'aria-labelledby' | 'aria-describedby';\n\n/** 未声明的属性落到外层 div 上 */\nexport interface FormSectionProps extends PartProps<'div', FormSectionManaged>, FieldLayout {\n /** 标题;不写时没有标题栏,只是一层栅格与字段布局 */\n title?: VNodeChild;\n /** 标题下面的说明 */\n description?: VNodeChild;\n /** 标题栏结束边的内容:链接、按钮(“查看关联明细”“添加”) */\n extra?: VNodeChild;\n /** 标题的级别(h2–h6),默认 3 */\n headingLevel?: 2 | 3 | 4 | 5 | 6;\n /** 最多几列,默认 1;容器窄时按 minColumnWidth 自动减少 */\n columns?: number;\n /** 每列的最小宽度(CSS 长度),默认 `'26em'`:标签在起始边时放得下标签、控件与横排的三四个选项 */\n minColumnWidth?: string;\n /** 可以展开收起:标题变成按钮 */\n collapsible?: boolean;\n /** 是否展开(collapsible 时):父级写 _open={x},默认展开 */\n _open?: boolean;\n /** 标题栏的部件属性 */\n propsHeader?: PartProps<'div'>;\n /** 标题(h2–h6)的部件属性 */\n propsHeading?: PartProps<'h3'>;\n /** 展开收起按钮的部件属性 */\n propsTrigger?: Omit<Partial<ButtonBaseProps>, 'aria-expanded' | 'aria-controls'>;\n /** 展开箭头的部件属性 */\n propsChevron?: Partial<IconProps>;\n /** 说明的部件属性 */\n propsDescription?: Partial<TextProps>;\n /** 标题栏结束边内容的部件属性 */\n propsExtra?: PartProps<'div'>;\n /** 字段栅格的部件属性 */\n propsBody?: PartProps<'div'>;\n /** 展开收起层的部件属性(collapsible 时) */\n propsCollapse?: Partial<CollapseProps>;\n /** 字段 */\n children?: VNodeChild;\n}\n\n/** FormSection 的样式:root、header、headerText、heading、trigger、chevron、description、extra、body、singleColumn */\nexport const formSectionStyles = css.create({\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: '_lg',\n minWidth: 0,\n // 分节导航(TableOfContents、锚点)跳过来时让开粘性顶栏,再留一点空\n scrollMarginBlockStart: `calc(${layoutVars.stickyOffset} + ${space.lg})`,\n },\n header: {\n display: 'flex',\n alignItems: 'flex-end',\n justifyContent: 'space-between',\n flexWrap: 'wrap',\n columnGap: '_lg',\n rowGap: '_xs',\n paddingBlockEnd: '_sm',\n borderBlockEndWidth: '_xs',\n borderBlockEndStyle: 'solid',\n borderBlockEndColor: '_borderMuted',\n },\n headerText: { display: 'flex', flexDirection: 'column', gap: '_xs', minWidth: 0 },\n heading: {\n margin: 0,\n fontSize: '_md',\n fontWeight: '_semibold',\n lineHeight: '_tight',\n color: '_text',\n },\n trigger: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '_xs',\n marginInline: `calc(-1 * ${t.space.xs})`,\n paddingInline: '_xs',\n borderRadius: '_sm',\n fontWeight: 'inherit',\n color: 'inherit',\n textAlign: 'start',\n backgroundColor: { default: 'transparent', ':hover': '_fill' },\n },\n chevron: { flexShrink: 0, color: '_textMuted' },\n chevronClosed: { rotate: '-90deg' },\n description: { fontSize: '_sm', lineHeight: '_normal' },\n extra: { display: 'flex', alignItems: 'center', gap: '_sm', flexShrink: 0 },\n // 多列时列间距比行间距大:一眼看出哪几项是同一列\n body: {\n '--form-section-column-gap': '_space.xl',\n display: 'grid',\n columnGap: 'var(--form-section-column-gap)',\n rowGap: '_md',\n gridTemplateColumns: 'minmax(0, 1fr)',\n alignItems: 'start',\n },\n});\n\n/** FormSection 的样式:columns(最多几列、每列不窄于多少) */\nexport const formSectionColumnStyles = css.create({\n columns: (count: number, minWidth: string) => ({\n gridTemplateColumns: `repeat(auto-fill, minmax(max(min(${minWidth}, 100%), calc((100% - ${count - 1} * var(--form-section-column-gap)) / ${count})), 1fr))`,\n }),\n});\n\n/** 表单里的一组字段:标题栏、字段栅格,可折叠;这一组的标签布局、只读、不可用 */\nexport const FormSection = _component(\n ({\n title,\n description,\n extra,\n headingLevel = 3,\n columns = 1,\n minColumnWidth = '26em',\n collapsible = false,\n _open: open = _bindable(true),\n labelPlacement,\n labelWidth,\n labelAlign,\n disabled,\n readonly,\n propsHeader,\n propsHeading,\n propsTrigger,\n propsChevron,\n propsDescription,\n propsExtra,\n propsBody,\n propsCollapse,\n children,\n ...rest\n }: FormSectionProps) => {\n const id = useId();\n const ids = { title: `${id}-title`, description: `${id}-description`, body: `${id}-body` };\n provideFieldLayout(() => ({ labelPlacement, labelWidth, labelAlign, disabled, readonly }));\n const bodyRef = provideGridColumns(() =>\n columns > 1 ? { columns, minItemWidth: minColumnWidth } : { columns: 1 },\n );\n\n return () => {\n const expanded = !collapsible || open;\n const state = expanded ? 'open' : 'closed';\n const titleContent = collapsible ? (\n <ButtonBase\n {...mergePartProps<ButtonBaseProps>({ sx: formSectionStyles.trigger }, propsTrigger, {\n id: ids.title,\n 'aria-expanded': open,\n 'aria-controls': ids.body,\n onClick: () => (open = !open),\n })}\n data-state={state}\n >\n <span>{title}</span>\n <Icon\n {...mergePartProps<IconProps>(\n {\n icon: ChevronDown,\n sx: [\n formSectionStyles.chevron,\n disclosureStyles.icon,\n !open && formSectionStyles.chevronClosed,\n ],\n },\n propsChevron,\n )}\n />\n </ButtonBase>\n ) : (\n <span id={ids.title}>{title}</span>\n );\n const body = (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n formSectionStyles.body,\n columns > 1 && formSectionColumnStyles.columns(columns, minColumnWidth),\n ],\n },\n propsBody,\n { ref: bodyRef, ...(collapsible ? {} : { id: ids.body }) },\n )}\n >\n {children}\n </div>\n );\n return (\n <div\n {...mergeAttrs<'div'>({ sx: formSectionStyles.root }, rest, {\n role: hasContent(title) ? 'group' : undefined,\n 'aria-labelledby': hasContent(title) ? ids.title : undefined,\n 'aria-describedby': hasContent(description) ? ids.description : undefined,\n })}\n data-state={collapsible ? state : undefined}\n >\n {(title != null || extra != null) && (\n <div {...mergeAttrs<'div'>({ sx: formSectionStyles.header }, propsHeader)}>\n <div {...css.attrs(formSectionStyles.headerText)}>\n {hasContent(title) &&\n h(\n `h${headingLevel}`,\n mergeAttrs<'h3'>({ sx: formSectionStyles.heading }, propsHeading),\n [titleContent],\n )}\n {hasContent(description) && (\n <Text\n {...mergePartProps<TextProps>(\n { tone: 'muted', sx: formSectionStyles.description },\n propsDescription,\n { id: ids.description },\n )}\n >\n {description}\n </Text>\n )}\n </div>\n {hasContent(extra) && (\n <div {...mergeAttrs<'div'>({ sx: formSectionStyles.extra }, propsExtra)}>\n {extra}\n </div>\n )}\n </div>\n )}\n {collapsible ? (\n <Collapse\n {...mergePartProps<CollapseProps>({}, propsCollapse, { id: ids.body })}\n _open={open}\n >\n {body}\n </Collapse>\n ) : (\n body\n )}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FormSection.js","names":["_isVNode","_vtp_readonlyProp","_vtp_bindable","_vtp_childrenProp","_vtp_restProps","_createVNode","_mergeProps","Text","_vue_unref"],"sources":["../../src/form/FormSection.tsx"],"sourcesContent":["/**\n * 表单里的一组字段:标题、说明、右侧的操作,下面一条细线,再下面是字段的栅格。长表单按主题分组(基本信息、计划与实施……)。\n *\n * <FormSection title=\"项目基本信息\" columns={2}>\n * <Field label=\"项目名称\">…</Field>\n * <Field label=\"任务类别\">…</Field>\n * <GridItem span=\"full\"><Field label=\"简要描述\">…</Field></GridItem>\n * </FormSection>\n *\n * columns 是最多几列:每列不窄于 minColumnWidth,容器窄时自动减少列数,不需要断点;跨列用 GridItem(多列时用 span=\"full\")。\n * 也是一层字段布局(field-layout):标签位置、宽度、对齐、只读、不可用写在这里只作用于这一组,没写的沿用 Form 的。\n * collapsible 时标题是展开收起的按钮(aria-expanded),收起的字段不能被 Tab 到。\n * 给了 id 就能当锚点:长表单旁边放一个 TableOfContents(items 用各组的 id 与标题)做分节导航,跳过来时让开粘性顶栏。\n * 语义:role=\"group\" 以标题为名称、说明为描述,标题是 h2–h6(headingLevel),读屏能按标题跳转。\n *\n * 部件:Root(div)、Header(div)、Heading(h2–h6)、Trigger(ButtonBase,collapsible 时)、Chevron(Icon)、\n * Description(Text)、Extra(div)、Body(div,字段的栅格)、Collapse(collapsible 时包住 Body)。\n */\nimport { ChevronDown } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { h, useId, type VNodeChild } from 'vue';\nimport { ButtonBase, type ButtonBaseProps } from '../base/ButtonBase';\nimport { Icon, type IconProps } from '../base/Icon';\nimport { Text, type TextProps } from '../base/Text';\nimport { space, t } from '../config/theme/tokens';\nimport { Collapse, type CollapseProps } from '../display/Collapse';\nimport { provideGridColumns } from '../layout/Grid';\nimport { hasContent, mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { disclosureStyles } from '../utils/style/transitions';\nimport { layoutVars } from '../utils/style/vars';\nimport { provideFieldLayout, type FieldLayout } from './field-layout';\n\n/** 角色与关联由组件管理;原生的 title 属性让给标题内容 */\nexport type FormSectionManaged = 'role' | 'title' | 'aria-labelledby' | 'aria-describedby';\n\n/** 未声明的属性落到外层 div 上 */\nexport interface FormSectionProps extends PartProps<'div', FormSectionManaged>, FieldLayout {\n /** 标题;不写时没有标题栏,只是一层栅格与字段布局 */\n title?: VNodeChild;\n /** 标题下面的说明 */\n description?: VNodeChild;\n /** 标题栏结束边的内容:链接、按钮(“查看关联明细”“添加”) */\n extra?: VNodeChild;\n /** 标题的级别(h2–h6),默认 3 */\n headingLevel?: 2 | 3 | 4 | 5 | 6;\n /** 最多几列,默认 1;容器窄时按 minColumnWidth 自动减少 */\n columns?: number;\n /** 每列的最小宽度(CSS 长度),默认 `'26em'`:标签在起始边时放得下标签、控件与横排的三四个选项 */\n minColumnWidth?: string;\n /** 可以展开收起:标题变成按钮 */\n collapsible?: boolean;\n /** 是否展开(collapsible 时):父级写 _open={x},默认展开 */\n _open?: boolean;\n /** 标题栏的部件属性 */\n propsHeader?: PartProps<'div'>;\n /** 标题(h2–h6)的部件属性 */\n propsHeading?: PartProps<'h3'>;\n /** 展开收起按钮的部件属性 */\n propsTrigger?: Omit<Partial<ButtonBaseProps>, 'aria-expanded' | 'aria-controls'>;\n /** 展开箭头的部件属性 */\n propsChevron?: Partial<IconProps>;\n /** 说明的部件属性 */\n propsDescription?: Partial<TextProps>;\n /** 标题栏结束边内容的部件属性 */\n propsExtra?: PartProps<'div'>;\n /** 字段栅格的部件属性 */\n propsBody?: PartProps<'div'>;\n /** 展开收起层的部件属性(collapsible 时) */\n propsCollapse?: Partial<CollapseProps>;\n /** 字段 */\n children?: VNodeChild;\n}\n\n/** FormSection 的样式:root、header、headerText、heading、trigger、chevron、description、extra、body、singleColumn */\nexport const formSectionStyles = css.create({\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: '_lg',\n minWidth: 0,\n // 分节导航(TableOfContents、锚点)跳过来时让开粘性顶栏,再留一点空\n scrollMarginBlockStart: `calc(${layoutVars.stickyOffset} + ${space.lg})`,\n },\n header: {\n display: 'flex',\n alignItems: 'flex-end',\n justifyContent: 'space-between',\n flexWrap: 'wrap',\n columnGap: '_lg',\n rowGap: '_xs',\n paddingBlockEnd: '_sm',\n borderBlockEndWidth: '_xs',\n borderBlockEndStyle: 'solid',\n borderBlockEndColor: '_borderMuted',\n },\n headerText: { display: 'flex', flexDirection: 'column', gap: '_xs', minWidth: 0 },\n heading: {\n margin: 0,\n fontSize: '_md',\n fontWeight: '_semibold',\n lineHeight: '_tight',\n color: '_text',\n },\n trigger: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '_xs',\n marginInline: `calc(-1 * ${t.space.xs})`,\n paddingInline: '_xs',\n borderRadius: '_sm',\n fontWeight: 'inherit',\n color: 'inherit',\n textAlign: 'start',\n backgroundColor: { default: 'transparent', ':hover': '_fill' },\n },\n chevron: { flexShrink: 0, color: '_textMuted' },\n chevronClosed: { rotate: '-90deg' },\n description: { fontSize: '_sm', lineHeight: '_normal' },\n extra: { display: 'flex', alignItems: 'center', gap: '_sm', flexShrink: 0 },\n // 多列时列间距比行间距大:一眼看出哪几项是同一列\n body: {\n '--form-section-column-gap': '_space.xl',\n display: 'grid',\n columnGap: 'var(--form-section-column-gap)',\n rowGap: '_md',\n gridTemplateColumns: 'minmax(0, 1fr)',\n alignItems: 'start',\n },\n});\n\n/** FormSection 的样式:columns(最多几列、每列不窄于多少) */\nexport const formSectionColumnStyles = css.create({\n columns: (count: number, minWidth: string) => ({\n gridTemplateColumns: `repeat(auto-fill, minmax(max(min(${minWidth}, 100%), calc((100% - ${count - 1} * var(--form-section-column-gap)) / ${count})), 1fr))`,\n }),\n});\n\n/** 表单里的一组字段:标题栏、字段栅格,可折叠;这一组的标签布局、只读、不可用 */\nexport const FormSection = _component(\n ({\n title,\n description,\n extra,\n headingLevel = 3,\n columns = 1,\n minColumnWidth = '26em',\n collapsible = false,\n _open: open = _bindable(true),\n labelPlacement,\n labelWidth,\n labelAlign,\n disabled,\n readonly,\n propsHeader,\n propsHeading,\n propsTrigger,\n propsChevron,\n propsDescription,\n propsExtra,\n propsBody,\n propsCollapse,\n children,\n ...rest\n }: FormSectionProps) => {\n const id = useId();\n const ids = { title: `${id}-title`, description: `${id}-description`, body: `${id}-body` };\n provideFieldLayout(() => ({ labelPlacement, labelWidth, labelAlign, disabled, readonly }));\n const bodyRef = provideGridColumns(() =>\n columns > 1 ? { columns, minItemWidth: minColumnWidth } : { columns: 1 },\n );\n\n return () => {\n const expanded = !collapsible || open;\n const state = expanded ? 'open' : 'closed';\n const titleContent = collapsible ? (\n <ButtonBase\n {...mergePartProps<ButtonBaseProps>({ sx: formSectionStyles.trigger }, propsTrigger, {\n id: ids.title,\n 'aria-expanded': open,\n 'aria-controls': ids.body,\n onClick: () => (open = !open),\n })}\n data-state={state}\n >\n <span>{title}</span>\n <Icon\n {...mergePartProps<IconProps>(\n {\n icon: ChevronDown,\n sx: [\n formSectionStyles.chevron,\n disclosureStyles.icon,\n !open && formSectionStyles.chevronClosed,\n ],\n },\n propsChevron,\n )}\n />\n </ButtonBase>\n ) : (\n <span id={ids.title}>{title}</span>\n );\n const body = (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n formSectionStyles.body,\n columns > 1 && formSectionColumnStyles.columns(columns, minColumnWidth),\n ],\n },\n propsBody,\n { ref: bodyRef, ...(collapsible ? {} : { id: ids.body }) },\n )}\n >\n {children}\n </div>\n );\n return (\n <div\n {...mergeAttrs<'div'>({ sx: formSectionStyles.root }, rest, {\n role: hasContent(title) ? 'group' : undefined,\n 'aria-labelledby': hasContent(title) ? ids.title : undefined,\n 'aria-describedby': hasContent(description) ? ids.description : undefined,\n })}\n data-state={collapsible ? state : undefined}\n >\n {(title != null || extra != null) && (\n <div {...mergeAttrs<'div'>({ sx: formSectionStyles.header }, propsHeader)}>\n <div {...css.attrs(formSectionStyles.headerText)}>\n {hasContent(title) &&\n h(\n `h${headingLevel}`,\n mergeAttrs<'h3'>({ sx: formSectionStyles.heading }, propsHeading),\n [titleContent],\n )}\n {hasContent(description) && (\n <Text\n {...mergePartProps<TextProps>(\n { tone: 'muted', sx: formSectionStyles.description },\n propsDescription,\n { id: ids.description },\n )}\n >\n {description}\n </Text>\n )}\n </div>\n {hasContent(extra) && (\n <div {...mergeAttrs<'div'>({ sx: formSectionStyles.extra }, propsExtra)}>\n {extra}\n </div>\n )}\n </div>\n )}\n {collapsible ? (\n <Collapse\n {...mergePartProps<CollapseProps>({}, propsCollapse, { id: ids.body })}\n _open={open}\n >\n {body}\n </Collapse>\n ) : (\n body\n )}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
package/dist/form/schemas.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* 校验用 zod 的标准错误码(too_small、too_big、not_multiple_of),提示跟着使用方配置的 zod 语言走。
|
|
14
14
|
*/
|
|
15
15
|
import type Decimal from 'decimal.js';
|
|
16
|
-
import
|
|
16
|
+
import { z } from 'zod';
|
|
17
17
|
import { type NumericValue } from '../utils/data/numeric';
|
|
18
18
|
/** decimalSchema 的选项;边界与步长可以是数字、bigint、Decimal 或十进制文本('0.01') */
|
|
19
19
|
export interface DecimalSchemaOptions {
|
package/dist/form/schemas.js
CHANGED
package/dist/form/schemas.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.js","names":[],"sources":["../../src/form/schemas.ts"],"sourcesContent":["/**\n * 内置值类型的 zod schema:Decimal(金额、精确小数)与 bigint(超过 2^53 的整数、ID);\n * 常见的格式:手机号(phoneSchema)、居民身份证号(idCardSchema,校验出生日期与校验码)。\n *\n * const schema = z.object({\n * price: decimalSchema({ min: 0, scale: 2 }), // Decimal,最小 0,最多两位小数\n * stock: bigintSchema({ min: 0n }),\n * });\n * // useForm 从 schema 推出约束:NumberField 拿到 min 0、step 0.01,不用再写一遍\n *\n * zod 自带的 z.bigint()、自定义类型转 JSON Schema 时表达不了,表单推不出字段约束;\n * 这里用 .meta() 把 minimum、maximum、multipleOf 写进去(form-constraints 读 JSON Schema)。\n * 校验用 zod 的标准错误码(too_small、too_big、not_multiple_of),提示跟着使用方配置的 zod 语言走。\n */\nimport type Decimal from 'decimal.js';\nimport
|
|
1
|
+
{"version":3,"file":"schemas.js","names":[],"sources":["../../src/form/schemas.ts"],"sourcesContent":["/**\n * 内置值类型的 zod schema:Decimal(金额、精确小数)与 bigint(超过 2^53 的整数、ID);\n * 常见的格式:手机号(phoneSchema)、居民身份证号(idCardSchema,校验出生日期与校验码)。\n *\n * const schema = z.object({\n * price: decimalSchema({ min: 0, scale: 2 }), // Decimal,最小 0,最多两位小数\n * stock: bigintSchema({ min: 0n }),\n * });\n * // useForm 从 schema 推出约束:NumberField 拿到 min 0、step 0.01,不用再写一遍\n *\n * zod 自带的 z.bigint()、自定义类型转 JSON Schema 时表达不了,表单推不出字段约束;\n * 这里用 .meta() 把 minimum、maximum、multipleOf 写进去(form-constraints 读 JSON Schema)。\n * 校验用 zod 的标准错误码(too_small、too_big、not_multiple_of),提示跟着使用方配置的 zod 语言走。\n */\nimport type Decimal from 'decimal.js';\nimport { z } from 'zod';\nimport { isDecimal, toNumber, type NumericValue } from '../utils/data/numeric';\n\n/** decimalSchema 的选项;边界与步长可以是数字、bigint、Decimal 或十进制文本('0.01') */\nexport interface DecimalSchemaOptions {\n /** 最小值(含) */\n min?: NumericValue | string;\n /** 最大值(含) */\n max?: NumericValue | string;\n /** 步长:值要是 step 的整数倍(从 0 算起) */\n step?: NumericValue | string;\n /** 最多几位小数(金额通常是 2) */\n scale?: number;\n}\n\n/** Decimal 的 schema:类型、范围、步长与小数位数 */\nexport function decimalSchema({ min, max, step, scale }: DecimalSchemaOptions = {}) {\n // 小数位数等价于步长 10^-scale;两个都给时都要满足\n const steps = [step, scale == null ? undefined : `1e-${scale}`].filter((item) => item != null);\n return z\n .custom<Decimal>(isDecimal)\n .check((ctx) => {\n const value = ctx.value;\n // 边界按值自己的构造函数转成 Decimal:使用方可能用 Decimal.clone 配了精度\n const Ctor = value.constructor as typeof Decimal;\n const of = (bound: NumericValue | string) =>\n isDecimal(bound) ? bound : new Ctor(String(bound));\n if (min != null && value.lt(of(min))) {\n ctx.issues.push({\n code: 'too_small',\n origin: 'number',\n minimum: toNumber(of(min)),\n inclusive: true,\n input: value,\n });\n }\n if (max != null && value.gt(of(max))) {\n ctx.issues.push({\n code: 'too_big',\n origin: 'number',\n maximum: toNumber(of(max)),\n inclusive: true,\n input: value,\n });\n }\n for (const item of steps) {\n const divisor = of(item);\n if (!value.mod(divisor).isZero()) {\n ctx.issues.push({\n code: 'not_multiple_of',\n origin: 'number',\n divisor: toNumber(divisor),\n // zod 的类型要求这里是 number(只用来拼提示文字);判断本身已经按十进制精确做过了\n input: toNumber(value),\n });\n }\n }\n })\n .meta({\n type: 'number',\n ...(min != null && { minimum: Number(String(min)) }),\n ...(max != null && { maximum: Number(String(max)) }),\n ...(steps.length > 0 && {\n multipleOf: Math.min(...steps.map((item) => Number(String(item)))),\n }),\n });\n}\n\n/** bigintSchema 的选项 */\nexport interface BigIntSchemaOptions {\n /** 最小值(含) */\n min?: bigint;\n /** 最大值(含) */\n max?: bigint;\n}\n\n/** bigint 的 schema:范围由 zod 精确校验,约束(转成 number,只给控件用)写进 JSON Schema */\nexport function bigintSchema({ min, max }: BigIntSchemaOptions = {}) {\n let schema = z.bigint();\n if (min != null) schema = schema.min(min);\n if (max != null) schema = schema.max(max);\n return schema.meta({\n type: 'integer',\n ...(min != null && { minimum: Number(min) }),\n ...(max != null && { maximum: Number(max) }),\n });\n}\n\n/** phoneSchema、idCardSchema 的选项 */\nexport interface PatternSchemaOptions {\n /** 不符合时的提示;不写时用 zod 的“格式不对”(跟着语言包) */\n message?: string;\n}\n\n/** 中国大陆手机号:1 开头、第二位 3–9、共 11 位数字(配 TextField 的 phoneFormat,值里没有空格) */\nexport function phoneSchema({ message }: PatternSchemaOptions = {}) {\n return z.string().regex(/^1[3-9]\\d{9}$/, message === undefined ? undefined : { message });\n}\n\nconst ID_WEIGHTS = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];\nconst ID_CHECK_CODES = '10X98765432';\n\n/**\n * 居民身份证号(GB 11643)是否有效:18 位,出生日期是真实的日期,最后一位校验码对得上(配 idCardFormat)\n */\nexport function isValidIdCard(value: string): boolean {\n if (!/^\\d{17}[\\dX]$/.test(value)) return false;\n const [year, month, day] = [value.slice(6, 10), value.slice(10, 12), value.slice(12, 14)].map(\n Number,\n ) as [number, number, number];\n const birth = new Date(Date.UTC(year, month - 1, day));\n if (\n birth.getUTCFullYear() !== year ||\n birth.getUTCMonth() !== month - 1 ||\n birth.getUTCDate() !== day ||\n year < 1900\n ) {\n return false;\n }\n const sum = ID_WEIGHTS.reduce((total, weight, index) => total + weight * Number(value[index]), 0);\n return ID_CHECK_CODES[sum % 11] === value[17];\n}\n\n/** 居民身份证号的 schema:长度、出生日期与校验码(isValidIdCard) */\nexport function idCardSchema({ message }: PatternSchemaOptions = {}) {\n return z.string().refine(isValidIdCard, message === undefined ? undefined : { message });\n}\n"],"mappings":"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"}
|