@zerodep-dev/vue-tsx-pro-ui 0.1.0 → 0.3.0
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/Badge.js +3 -3
- package/dist/base/Badge.js.map +1 -1
- package/dist/base/Can.d.ts +12 -0
- package/dist/base/Can.js +20 -0
- package/dist/base/Can.js.map +1 -0
- package/dist/base/ClientOnly.d.ts +10 -0
- package/dist/base/ClientOnly.js +18 -0
- package/dist/base/ClientOnly.js.map +1 -0
- package/dist/base/CloseButton.js +3 -3
- package/dist/base/CloseButton.js.map +1 -1
- package/dist/base/CodeBlock.js +5 -5
- package/dist/base/CodeBlock.js.map +1 -1
- package/dist/base/CopyButton.js +3 -3
- package/dist/base/CopyButton.js.map +1 -1
- package/dist/base/Icon.js +3 -3
- package/dist/base/Icon.js.map +1 -1
- package/dist/base/Indicator.js +3 -3
- package/dist/base/Indicator.js.map +1 -1
- package/dist/base/StatusDot.js +3 -3
- package/dist/base/StatusDot.js.map +1 -1
- package/dist/base/Tag.js +5 -5
- package/dist/base/Tag.js.map +1 -1
- package/dist/base/button-core.js +4 -4
- package/dist/base/button-core.js.map +1 -1
- package/dist/charts/AreaChart.js +3 -3
- package/dist/charts/AreaChart.js.map +1 -1
- package/dist/charts/BarChart.js +3 -3
- package/dist/charts/BarChart.js.map +1 -1
- package/dist/charts/ChordChart.js +3 -3
- package/dist/charts/ChordChart.js.map +1 -1
- package/dist/charts/ComboChart.js +3 -3
- package/dist/charts/ComboChart.js.map +1 -1
- package/dist/charts/DonutChart.js +3 -3
- package/dist/charts/DonutChart.js.map +1 -1
- package/dist/charts/FunnelChart.js +5 -5
- package/dist/charts/FunnelChart.js.map +1 -1
- package/dist/charts/GraphChart.js +3 -3
- package/dist/charts/GraphChart.js.map +1 -1
- package/dist/charts/LineChart.js +3 -3
- package/dist/charts/LineChart.js.map +1 -1
- package/dist/charts/MapChart.js +7 -7
- package/dist/charts/MapChart.js.map +1 -1
- package/dist/charts/RadarChart.js +16 -15
- package/dist/charts/RadarChart.js.map +1 -1
- package/dist/charts/SankeyChart.js +3 -3
- package/dist/charts/SankeyChart.js.map +1 -1
- package/dist/charts/ScatterChart.js +3 -3
- package/dist/charts/ScatterChart.js.map +1 -1
- package/dist/charts/TimelineChart.js +6 -5
- package/dist/charts/TimelineChart.js.map +1 -1
- package/dist/charts/TreemapChart.js +3 -3
- package/dist/charts/TreemapChart.js.map +1 -1
- package/dist/charts/WaterfallChart.js +3 -3
- package/dist/charts/WaterfallChart.js.map +1 -1
- package/dist/charts/XYChart.js +9 -7
- package/dist/charts/XYChart.js.map +1 -1
- package/dist/charts/frame.js +10 -8
- package/dist/charts/frame.js.map +1 -1
- package/dist/charts/single.js +4 -3
- package/dist/charts/single.js.map +1 -1
- package/dist/code-editor/CodeEditor.d.ts +18 -0
- package/dist/code-editor/CodeEditor.js +57 -0
- package/dist/code-editor/CodeEditor.js.map +1 -0
- package/dist/code-editor/editor.d.ts +52 -0
- package/dist/code-editor/editor.js +225 -0
- package/dist/code-editor/editor.js.map +1 -0
- package/dist/code-editor/index.d.ts +9 -0
- package/dist/code-editor/index.js +3 -0
- package/dist/config/Provider.d.ts +3 -1
- package/dist/config/Provider.js +9 -4
- package/dist/config/Provider.js.map +1 -1
- package/dist/config/context.d.ts +18 -0
- package/dist/config/context.js +16 -1
- package/dist/config/context.js.map +1 -1
- package/dist/config/createUi.d.ts +20 -3
- package/dist/config/createUi.js +80 -49
- package/dist/config/createUi.js.map +1 -1
- package/dist/config/lang/en-US.js +21 -3
- package/dist/config/lang/en-US.js.map +1 -1
- package/dist/config/lang/format.d.ts +2 -1
- package/dist/config/lang/format.js +9 -2
- package/dist/config/lang/format.js.map +1 -1
- package/dist/config/lang/lang.d.ts +19 -6
- package/dist/config/lang/lang.js +11 -2
- package/dist/config/lang/lang.js.map +1 -1
- package/dist/config/lang/zh-CN.js +21 -3
- package/dist/config/lang/zh-CN.js.map +1 -1
- package/dist/config/layout/preference.d.ts +43 -0
- package/dist/config/layout/preference.js +108 -0
- package/dist/config/layout/preference.js.map +1 -0
- package/dist/date/Calendar.js +3 -3
- package/dist/date/Calendar.js.map +1 -1
- package/dist/date/CalendarBoard.js +9 -9
- package/dist/date/CalendarBoard.js.map +1 -1
- package/dist/date/CalendarView.js +7 -7
- package/dist/date/CalendarView.js.map +1 -1
- package/dist/date/DateField.js +3 -3
- package/dist/date/DateField.js.map +1 -1
- package/dist/date/DatePicker.js +5 -5
- package/dist/date/DatePicker.js.map +1 -1
- package/dist/date/DateRangePicker.js +5 -5
- package/dist/date/DateRangePicker.js.map +1 -1
- package/dist/date/DateSegmentGroup.js +5 -5
- package/dist/date/DateSegmentGroup.js.map +1 -1
- package/dist/date/QuarterCalendar.js +6 -6
- package/dist/date/QuarterCalendar.js.map +1 -1
- package/dist/date/RangeCalendar.js +3 -3
- package/dist/date/RangeCalendar.js.map +1 -1
- package/dist/date/SegmentedField.js +3 -3
- package/dist/date/SegmentedField.js.map +1 -1
- package/dist/date/TimeField.js +3 -3
- package/dist/date/TimeField.js.map +1 -1
- package/dist/date/TimePicker.js +4 -4
- package/dist/date/TimePicker.js.map +1 -1
- package/dist/date/date-segments.js +1 -1
- package/dist/date/date-segments.js.map +1 -1
- package/dist/date/picker-popover.js +3 -2
- package/dist/date/picker-popover.js.map +1 -1
- package/dist/diagram/Diagram.js +12 -12
- package/dist/diagram/Diagram.js.map +1 -1
- package/dist/diagram/DiagramLanes.js +3 -3
- package/dist/diagram/DiagramLanes.js.map +1 -1
- package/dist/diagram/DiagramMinimap.js +4 -4
- package/dist/diagram/DiagramMinimap.js.map +1 -1
- package/dist/diagram/index.d.ts +2 -1
- package/dist/diagram/index.js +2 -1
- package/dist/diagram/layout.d.ts +57 -0
- package/dist/diagram/layout.js +50 -0
- package/dist/diagram/layout.js.map +1 -0
- package/dist/display/Accordion.js +6 -6
- package/dist/display/Accordion.js.map +1 -1
- package/dist/display/AnimatedNumber.js +4 -4
- package/dist/display/AnimatedNumber.js.map +1 -1
- package/dist/display/Avatar.js +4 -4
- package/dist/display/Avatar.js.map +1 -1
- package/dist/display/Checklist.js +7 -7
- package/dist/display/Checklist.js.map +1 -1
- package/dist/display/Collapse.js +8 -5
- package/dist/display/Collapse.js.map +1 -1
- package/dist/display/Collapsible.js +3 -3
- package/dist/display/Collapsible.js.map +1 -1
- package/dist/display/Descriptions.js +5 -5
- package/dist/display/Descriptions.js.map +1 -1
- package/dist/display/Ellipsis.js +3 -3
- package/dist/display/Ellipsis.js.map +1 -1
- package/dist/display/FieldCompare.js +4 -4
- package/dist/display/FieldCompare.js.map +1 -1
- package/dist/display/Gauge.js +11 -11
- package/dist/display/Gauge.js.map +1 -1
- package/dist/display/Image.js +4 -4
- package/dist/display/Image.js.map +1 -1
- package/dist/display/Marquee.js +3 -3
- package/dist/display/Marquee.js.map +1 -1
- package/dist/display/ProportionBar.js +4 -4
- package/dist/display/ProportionBar.js.map +1 -1
- package/dist/display/Sortable.js +4 -4
- package/dist/display/Sortable.js.map +1 -1
- package/dist/display/Sparkline.js +6 -6
- package/dist/display/Sparkline.js.map +1 -1
- package/dist/display/Stat.js +3 -3
- package/dist/display/Stat.js.map +1 -1
- package/dist/display/Timeline.js +7 -7
- package/dist/display/Timeline.js.map +1 -1
- package/dist/display/Tree.js +10 -10
- package/dist/display/Tree.js.map +1 -1
- package/dist/display/VirtualList.js +7 -7
- package/dist/display/VirtualList.js.map +1 -1
- package/dist/display/Watermark.js +3 -3
- package/dist/display/Watermark.js.map +1 -1
- package/dist/docs-kit/CodeGroup.js +5 -5
- package/dist/docs-kit/CodeGroup.js.map +1 -1
- package/dist/docs-kit/CodePreview.js +6 -6
- package/dist/docs-kit/CodePreview.js.map +1 -1
- package/dist/docs-kit/PropsTable.js +4 -4
- package/dist/docs-kit/PropsTable.js.map +1 -1
- package/dist/feedback/Alert.js +5 -5
- package/dist/feedback/Alert.js.map +1 -1
- package/dist/feedback/Banner.js +5 -5
- package/dist/feedback/Banner.js.map +1 -1
- package/dist/feedback/Empty.js +4 -4
- package/dist/feedback/Empty.js.map +1 -1
- package/dist/feedback/LoadingBar.js +20 -13
- package/dist/feedback/LoadingBar.js.map +1 -1
- package/dist/feedback/LoadingOverlay.js +3 -3
- package/dist/feedback/LoadingOverlay.js.map +1 -1
- package/dist/feedback/Progress.js +14 -14
- package/dist/feedback/Progress.js.map +1 -1
- package/dist/feedback/Result.js +4 -4
- package/dist/feedback/Result.js.map +1 -1
- package/dist/feedback/SkeletonText.js +3 -3
- package/dist/feedback/SkeletonText.js.map +1 -1
- package/dist/feedback/Toast.js +6 -6
- package/dist/feedback/Toast.js.map +1 -1
- package/dist/form/Field.d.ts +7 -0
- package/dist/form/Field.js +20 -9
- package/dist/form/Field.js.map +1 -1
- package/dist/form/Form.js +3 -3
- package/dist/form/Form.js.map +1 -1
- package/dist/form/FormErrorSummary.js +3 -3
- package/dist/form/FormErrorSummary.js.map +1 -1
- package/dist/form/FormSection.js +6 -6
- package/dist/form/FormSection.js.map +1 -1
- package/dist/form/useForm.d.ts +4 -1
- package/dist/form/useForm.js +35 -13
- package/dist/form/useForm.js.map +1 -1
- package/dist/index.d.ts +18 -10
- package/dist/index.js +17 -9
- package/dist/input/Autocomplete.js +3 -3
- package/dist/input/Autocomplete.js.map +1 -1
- package/dist/input/Cascader.js +7 -7
- package/dist/input/Cascader.js.map +1 -1
- package/dist/input/CharacterCount.js +3 -3
- package/dist/input/CharacterCount.js.map +1 -1
- package/dist/input/Checkbox.js +5 -5
- package/dist/input/Checkbox.js.map +1 -1
- package/dist/input/ColorField.js +4 -4
- package/dist/input/ColorField.js.map +1 -1
- package/dist/input/Combobox.js +5 -5
- package/dist/input/Combobox.js.map +1 -1
- package/dist/input/ConditionBuilder.js +15 -14
- package/dist/input/ConditionBuilder.js.map +1 -1
- package/dist/input/FileDrop.js +3 -3
- package/dist/input/FileDrop.js.map +1 -1
- package/dist/input/Listbox.js +9 -9
- package/dist/input/Listbox.js.map +1 -1
- package/dist/input/Mentions.js +4 -4
- package/dist/input/Mentions.js.map +1 -1
- package/dist/input/NumberField.js +3 -3
- package/dist/input/NumberField.js.map +1 -1
- package/dist/input/NumberRangeField.js +5 -5
- package/dist/input/NumberRangeField.js.map +1 -1
- package/dist/input/OtpField.js +5 -5
- package/dist/input/OtpField.js.map +1 -1
- package/dist/input/PeoplePicker.js +6 -6
- package/dist/input/PeoplePicker.js.map +1 -1
- package/dist/input/PeoplePickerPanel.js +15 -15
- package/dist/input/PeoplePickerPanel.js.map +1 -1
- package/dist/input/Radio.js +4 -4
- package/dist/input/Radio.js.map +1 -1
- package/dist/input/Rating.js +5 -5
- package/dist/input/Rating.js.map +1 -1
- package/dist/input/Select.js +5 -5
- package/dist/input/Select.js.map +1 -1
- package/dist/input/SelectedTags.js +4 -4
- package/dist/input/SelectedTags.js.map +1 -1
- package/dist/input/Slider.js +6 -6
- package/dist/input/Slider.js.map +1 -1
- package/dist/input/Switch.js +3 -3
- package/dist/input/Switch.js.map +1 -1
- package/dist/input/TagsInput.js +5 -5
- package/dist/input/TagsInput.js.map +1 -1
- package/dist/input/TextField.js +5 -5
- package/dist/input/TextField.js.map +1 -1
- package/dist/input/Textarea.js +4 -4
- package/dist/input/Textarea.js.map +1 -1
- package/dist/input/ToggleGroup.js +4 -4
- package/dist/input/ToggleGroup.js.map +1 -1
- package/dist/input/Transfer.js +8 -8
- package/dist/input/Transfer.js.map +1 -1
- package/dist/input/TreeSelect.js +7 -7
- package/dist/input/TreeSelect.js.map +1 -1
- package/dist/input/Upload.js +10 -9
- package/dist/input/Upload.js.map +1 -1
- package/dist/input/condition.d.ts +1 -1
- package/dist/input/condition.js +32 -14
- package/dist/input/condition.js.map +1 -1
- package/dist/input/people.d.ts +15 -14
- package/dist/input/people.js +5 -5
- package/dist/input/people.js.map +1 -1
- package/dist/input/remote-items.d.ts +4 -2
- package/dist/input/remote-items.js +7 -2
- package/dist/input/remote-items.js.map +1 -1
- package/dist/layout/Affix.js +4 -4
- package/dist/layout/Affix.js.map +1 -1
- package/dist/layout/ResizeHandle.d.ts +6 -2
- package/dist/layout/ResizeHandle.js +32 -9
- package/dist/layout/ResizeHandle.js.map +1 -1
- package/dist/layout/ScrollArea.js +3 -3
- package/dist/layout/ScrollArea.js.map +1 -1
- package/dist/layout/Separator.js +3 -3
- package/dist/layout/Separator.js.map +1 -1
- package/dist/layout/Splitter.js +3 -3
- package/dist/layout/Splitter.js.map +1 -1
- package/dist/layout/ViewportFill.d.ts +2 -2
- package/dist/layout/ViewportFill.js +4 -4
- package/dist/layout/ViewportFill.js.map +1 -1
- package/dist/navigation/Breadcrumbs.js +4 -4
- package/dist/navigation/Breadcrumbs.js.map +1 -1
- package/dist/navigation/NavBar.js +6 -6
- package/dist/navigation/NavBar.js.map +1 -1
- package/dist/navigation/NavList.d.ts +1 -0
- package/dist/navigation/NavList.js +20 -12
- package/dist/navigation/NavList.js.map +1 -1
- package/dist/navigation/NavMenu.d.ts +27 -0
- package/dist/navigation/NavMenu.js +54 -0
- package/dist/navigation/NavMenu.js.map +1 -0
- package/dist/navigation/PageJump.js +3 -3
- package/dist/navigation/PageJump.js.map +1 -1
- package/dist/navigation/PageSizeSelect.js +4 -4
- package/dist/navigation/PageSizeSelect.js.map +1 -1
- package/dist/navigation/Pagination.js +6 -6
- package/dist/navigation/Pagination.js.map +1 -1
- package/dist/navigation/PaginationBar.js +5 -5
- package/dist/navigation/PaginationBar.js.map +1 -1
- package/dist/navigation/Steps.js +4 -4
- package/dist/navigation/Steps.js.map +1 -1
- package/dist/navigation/TableOfContents.js +5 -5
- package/dist/navigation/TableOfContents.js.map +1 -1
- package/dist/navigation/Tabs.js +7 -7
- package/dist/navigation/Tabs.js.map +1 -1
- package/dist/navigation/Toolbar.js +3 -3
- package/dist/navigation/Toolbar.js.map +1 -1
- package/dist/overlay/AlertDialog.js +4 -4
- package/dist/overlay/AlertDialog.js.map +1 -1
- package/dist/overlay/CommandPalette.js +4 -4
- package/dist/overlay/CommandPalette.js.map +1 -1
- package/dist/overlay/ContextMenu.js +3 -3
- package/dist/overlay/ContextMenu.js.map +1 -1
- package/dist/overlay/Dialog.js +4 -4
- package/dist/overlay/Dialog.js.map +1 -1
- package/dist/overlay/Drawer.js +5 -5
- package/dist/overlay/Drawer.js.map +1 -1
- package/dist/overlay/HoverCard.js +5 -3
- package/dist/overlay/HoverCard.js.map +1 -1
- package/dist/overlay/Lightbox.js +5 -5
- package/dist/overlay/Lightbox.js.map +1 -1
- package/dist/overlay/Menu.js +7 -7
- package/dist/overlay/Menu.js.map +1 -1
- package/dist/overlay/ModalCore.js +9 -9
- package/dist/overlay/ModalCore.js.map +1 -1
- package/dist/overlay/Popconfirm.js +6 -6
- package/dist/overlay/Popconfirm.js.map +1 -1
- package/dist/overlay/Popover.js +5 -3
- package/dist/overlay/Popover.js.map +1 -1
- package/dist/overlay/Tooltip.js +5 -3
- package/dist/overlay/Tooltip.js.map +1 -1
- package/dist/overlay/Tour.js +8 -8
- package/dist/overlay/Tour.js.map +1 -1
- package/dist/overlay/detached.d.ts +2 -0
- package/dist/overlay/detached.js +73 -42
- package/dist/overlay/detached.js.map +1 -1
- package/dist/patterns/ActionBar.js +3 -3
- package/dist/patterns/ActionBar.js.map +1 -1
- package/dist/patterns/AppShell.d.ts +28 -1
- package/dist/patterns/AppShell.js +158 -52
- package/dist/patterns/AppShell.js.map +1 -1
- package/dist/patterns/AuthLayout.d.ts +28 -0
- package/dist/patterns/AuthLayout.js +77 -0
- package/dist/patterns/AuthLayout.js.map +1 -0
- package/dist/patterns/CommentThread.js +9 -9
- package/dist/patterns/CommentThread.js.map +1 -1
- package/dist/patterns/DataImport.js +4 -4
- package/dist/patterns/DataImport.js.map +1 -1
- package/dist/patterns/DeadlineBadge.js +3 -3
- package/dist/patterns/DeadlineBadge.js.map +1 -1
- package/dist/patterns/FilterBar.d.ts +11 -1
- package/dist/patterns/FilterBar.js +39 -10
- package/dist/patterns/FilterBar.js.map +1 -1
- package/dist/patterns/FormDialog.d.ts +18 -0
- package/dist/patterns/FormDialog.js +46 -0
- package/dist/patterns/FormDialog.js.map +1 -0
- package/dist/patterns/KanbanBoard.js +8 -8
- package/dist/patterns/KanbanBoard.js.map +1 -1
- package/dist/patterns/LayoutSwitcher.d.ts +12 -0
- package/dist/patterns/LayoutSwitcher.js +79 -0
- package/dist/patterns/LayoutSwitcher.js.map +1 -0
- package/dist/patterns/NotificationCenter.js +8 -8
- package/dist/patterns/NotificationCenter.js.map +1 -1
- package/dist/patterns/PageTabs.d.ts +12 -7
- package/dist/patterns/PageTabs.js +41 -29
- package/dist/patterns/PageTabs.js.map +1 -1
- package/dist/patterns/QueryTable.d.ts +10 -1
- package/dist/patterns/QueryTable.js +128 -68
- package/dist/patterns/QueryTable.js.map +1 -1
- package/dist/patterns/SlideCaptcha.d.ts +80 -0
- package/dist/patterns/SlideCaptcha.js +354 -0
- package/dist/patterns/SlideCaptcha.js.map +1 -0
- package/dist/patterns/StepsForm.js +7 -7
- package/dist/patterns/StepsForm.js.map +1 -1
- package/dist/patterns/ThemeSwitcher.js +3 -3
- package/dist/patterns/ThemeSwitcher.js.map +1 -1
- package/dist/patterns/index.d.ts +7 -3
- package/dist/patterns/index.js +5 -1
- package/dist/patterns/messages.d.ts +39 -1
- package/dist/patterns/messages.js +40 -2
- package/dist/patterns/messages.js.map +1 -1
- package/dist/table/ColumnHeaderActions.js +3 -3
- package/dist/table/ColumnHeaderActions.js.map +1 -1
- package/dist/table/ColumnResizer.js +3 -3
- package/dist/table/ColumnResizer.js.map +1 -1
- package/dist/table/ColumnSettings.js +5 -5
- package/dist/table/ColumnSettings.js.map +1 -1
- package/dist/table/ColumnTable.js +8 -8
- package/dist/table/ColumnTable.js.map +1 -1
- package/dist/table/DataTable.js +8 -8
- package/dist/table/DataTable.js.map +1 -1
- package/dist/table/DataTableView.js +21 -21
- package/dist/table/DataTableView.js.map +1 -1
- package/dist/table/PivotTable.js +3 -3
- package/dist/table/PivotTable.js.map +1 -1
- package/dist/table/SelectionBar.js +4 -4
- package/dist/table/SelectionBar.js.map +1 -1
- package/dist/table/TreeDataTable.js +5 -5
- package/dist/table/TreeDataTable.js.map +1 -1
- package/dist/theme-customize/ThemeCustomizer.js +7 -6
- package/dist/theme-customize/ThemeCustomizer.js.map +1 -1
- package/dist/theme-customize/ThemeThumbnail.js +3 -3
- package/dist/theme-customize/ThemeThumbnail.js.map +1 -1
- package/dist/three/background/AuroraBackground.js +3 -3
- package/dist/three/background/AuroraBackground.js.map +1 -1
- package/dist/three/background/MeshGradient.js +3 -3
- package/dist/three/background/MeshGradient.js.map +1 -1
- package/dist/three/background/ShaderBackground.js +3 -3
- package/dist/three/background/ShaderBackground.js.map +1 -1
- package/dist/three/core/EffectSurface.js +3 -3
- package/dist/three/core/EffectSurface.js.map +1 -1
- package/dist/three/core/ThreeCanvas.js +4 -4
- package/dist/three/core/ThreeCanvas.js.map +1 -1
- package/dist/three/effects/Confetti.js +3 -3
- package/dist/three/effects/Confetti.js.map +1 -1
- package/dist/three/effects/ParticleField.js +3 -3
- package/dist/three/effects/ParticleField.js.map +1 -1
- package/dist/three/effects/WaveGrid.js +3 -3
- package/dist/three/effects/WaveGrid.js.map +1 -1
- package/dist/three/globe/Globe.js +3 -3
- package/dist/three/globe/Globe.js.map +1 -1
- package/dist/three/model/ModelViewer.js +3 -3
- package/dist/three/model/ModelViewer.js.map +1 -1
- package/dist/utils/data/clone.d.ts +8 -0
- package/dist/utils/data/clone.js +21 -0
- package/dist/utils/data/clone.js.map +1 -0
- package/dist/utils/data/date.d.ts +10 -0
- package/dist/utils/data/date.js +13 -1
- package/dist/utils/data/date.js.map +1 -1
- package/dist/utils/data/number.d.ts +5 -0
- package/dist/utils/data/number.js +8 -1
- package/dist/utils/data/number.js.map +1 -1
- package/dist/utils/data/numeric.d.ts +7 -0
- package/dist/utils/data/numeric.js +46 -1
- package/dist/utils/data/numeric.js.map +1 -1
- package/dist/utils/dom/download.d.ts +8 -1
- package/dist/utils/dom/download.js +19 -2
- package/dist/utils/dom/download.js.map +1 -1
- package/dist/utils/dom/element.d.ts +3 -1
- package/dist/utils/dom/element.js +8 -4
- package/dist/utils/dom/element.js.map +1 -1
- package/dist/utils/dom/fullscreen.d.ts +1 -1
- package/dist/utils/dom/fullscreen.js +12 -8
- package/dist/utils/dom/fullscreen.js.map +1 -1
- package/dist/utils/dom/mounted.d.ts +7 -0
- package/dist/utils/dom/mounted.js +16 -0
- package/dist/utils/dom/mounted.js.map +1 -0
- package/dist/utils/dom/overflow.js +2 -1
- package/dist/utils/dom/overflow.js.map +1 -1
- package/dist/utils/dom/pan-zoom.js +2 -1
- package/dist/utils/dom/pan-zoom.js.map +1 -1
- package/dist/utils/props.js +3 -13
- package/dist/utils/props.js.map +1 -1
- package/dist/utils/request/error-message.d.ts +17 -0
- package/dist/utils/request/error-message.js +50 -0
- package/dist/utils/request/error-message.js.map +1 -0
- package/dist/utils/request/http.d.ts +80 -4
- package/dist/utils/request/http.js +121 -24
- package/dist/utils/request/http.js.map +1 -1
- package/dist/utils/request/use-autosave.d.ts +35 -0
- package/dist/utils/request/use-autosave.js +69 -0
- package/dist/utils/request/use-autosave.js.map +1 -0
- package/dist/utils/request/use-request.js +4 -2
- package/dist/utils/request/use-request.js.map +1 -1
- package/package.json +57 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_shallowRef","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/input/Checkbox.tsx"],"sourcesContent":["/**\n * 复选框(原生 input type=\"checkbox\")与复选组。结构与样式见 choice-styles.ts。\n *\n * <Checkbox _checked={agreed}>我已阅读并同意</Checkbox>\n * <Checkbox checked={allChecked} indeterminate={someChecked} onChange={toggleAll}>全选</Checkbox>\n * <Field label=\"通知方式\">\n * <CheckboxGroup _value={channels} name=\"channels\">\n * <Checkbox value=\"email\">邮件</Checkbox>\n * <Checkbox value=\"sms\">短信</Checkbox>\n * </CheckboxGroup>\n * </Field>\n * <CheckboxGroup _value={channels} items={[{ value: 'email', label: '邮件', description: '每天汇总一封' }, …]} />\n *\n * 部分勾选(indeterminate)是原生 input 的属性,读屏念“部分选中”。在 Field 里时关联说明与错误、沿用其状态;\n * 复选组用 role=\"group\",以 Field 的标签为名称(aria-labelledby)。\n *\n * 部件:Root(label)、Control(叠放层)、Indicator(对勾 / 横线图标)、Label(文字);未声明的属性落到 input 上。\n */\nimport { Check, Minus } 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 { useId, type VNodeChild } from 'vue';\nimport { Icon, type IconProps } from '../base/Icon';\nimport { useFieldControl } from '../form/Field';\nimport { toListboxOption, type ListboxOption, type OptionMapping } from './list-state';\nimport {\n hasContent,\n defaultLabelledBy,\n mergeAttrs,\n mergePartProps,\n type PartProps,\n} from '../utils/props';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { toggleSelection } from '../utils/data/selection';\nimport type { StatusTone } from '../utils/style/tone-styles';\nimport type { TextSize } from '../utils/style/typography';\nimport { useRecipe } from '../config/styles';\nimport {\n choiceInputStyles,\n choiceParts,\n choiceRecipe,\n useChoiceAppearance,\n type ChoiceOrientations,\n readonlyChoiceHandlers,\n syncChecked,\n} from './choice-styles';\n\n/** CheckboxGroup 交给组内 Checkbox 的状态 */\nexport interface CheckboxGroupState {\n /** 已勾选的值 */\n readonly value: readonly string[];\n /** 表单提交时的 name,组内每个 Checkbox 共用 */\n readonly name: string | undefined;\n /** 整组不可用 */\n readonly disabled: boolean;\n /** 整组只读 */\n readonly readonly: boolean;\n /** 整组校验未通过 */\n readonly invalid: boolean;\n /** 勾选或取消一个值 */\n toggle(value: string): void;\n}\n\n/** CheckboxGroup 的上下文:自定义的勾选项可以 inject 它接入组 */\nexport const CheckboxGroupContext = createContext<CheckboxGroupState>('CheckboxGroup');\n\n/** 勾选状态与可用性由组件管理;原生的 size 属性让给字号档位 */\nexport type CheckboxManaged =\n 'type' | 'checked' | 'disabled' | 'required' | 'size' | 'aria-invalid' | 'aria-describedby';\n\n/** 未声明的属性落到 input 上;外层 label 用 propsRoot */\nexport interface CheckboxProps extends PartProps<'input', CheckboxManaged> {\n /** 是否勾选:父级写 _checked={x};在复选组里时由组决定 */\n _checked?: boolean;\n /** 部分勾选(“全选”下面只选了一部分):显示横线,读屏念“部分选中” */\n indeterminate?: boolean;\n /** 在复选组里的值;单独使用时是表单提交的值(默认 on) */\n value?: string;\n /** 不可用 */\n disabled?: boolean;\n /** 只读:能聚焦、读屏念“只读”,勾选状态不能改(查看详情、审批时);外观照常 */\n readonly?: boolean;\n /** 必填(如“同意条款”) */\n required?: boolean;\n /** 校验未通过 */\n invalid?: boolean;\n /** 字号档位;不写时继承上下文字号 */\n size?: TextSize;\n /** 选中时的色调(与 Button、Badge 等同一套),默认 accent;可以用 defaults.Choice 统一改 */\n tone?: StatusTone;\n /** 外层 label 的部件属性 */\n propsRoot?: PartProps<'label'>;\n /** 叠放层的部件属性 */\n propsControl?: PartProps<'span'>;\n /** 对勾 / 横线图标的部件属性 */\n propsIndicator?: Partial<IconProps>;\n /** 文字的部件属性 */\n propsLabel?: PartProps<'span'>;\n /** 文字下方的说明(aria-describedby) */\n description?: VNodeChild;\n /** 说明的部件属性 */\n propsDescription?: PartProps<'span'>;\n /** 文字 */\n children?: VNodeChild;\n}\n\n/** Checkbox 的样式:box、indicator、hidden */\nexport const checkboxStyles = css.create({\n box: { width: '1.125em', height: '1.125em', borderRadius: '_sm' },\n indicator: { width: '0.875em', height: '0.875em', color: 'var(--tone-on-fill)' },\n hidden: { visibility: 'hidden' },\n});\n\n/** 复选框:原生 checkbox 加自绘的方框与对勾 */\nexport const Checkbox = _component(\n ({\n _checked: checked = _bindable(false),\n indeterminate = false,\n value,\n disabled,\n readonly,\n required,\n invalid,\n size,\n tone,\n id,\n propsRoot,\n propsControl,\n propsIndicator,\n propsLabel,\n description,\n propsDescription,\n children,\n ...rest\n }: CheckboxProps) => {\n const group = CheckboxGroupContext.inject(null);\n const descriptionId = `${useId()}-description`;\n const appearance = useChoiceAppearance(() => ({ size, tone }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let input = _state.raw<HTMLInputElement | null>(null);\n // 用户点击勾上时对勾描线;初次渲染、外部改值不播\n let drawCheck = _state(false);\n\n // indeterminate 只能经 DOM 属性设置\n _effect(() => {\n if (input) input.indeterminate = indeterminate;\n });\n\n function onChange(event: Event) {\n const target = event.target as HTMLInputElement;\n const next = target.checked;\n drawCheck = next;\n if (group && value != null) group.toggle(value);\n else checked = next;\n syncChecked([target], () => (group && value != null ? group.value.includes(value) : checked));\n }\n\n return () => {\n // 在复选组里时,id 与说明归组所有,不再给每一项\n const field = group ? undefined : control();\n const isChecked = group && value != null ? group.value.includes(value) : checked;\n const off = disabled ?? group?.disabled ?? field?.disabled ?? false;\n const locked = readonly ?? group?.readonly ?? field?.readonly ?? false;\n const bad = invalid ?? group?.invalid ?? field?.invalid ?? false;\n const marked = isChecked || indeterminate;\n const s = choiceParts(appearance(), { disabled: off, readonly: locked });\n return (\n <label\n {...mergeAttrs<'label'>(s.root, propsRoot)}\n data-state={indeterminate ? 'indeterminate' : isChecked ? 'checked' : 'unchecked'}\n data-disabled={off || undefined}\n data-readonly={locked || undefined}\n >\n <span {...mergeAttrs<'span'>(s.control, propsControl)}>\n <input\n {...mergeAttrs<'input'>(\n {\n ...s.input,\n sx: [\n s.input.sx,\n focusRingStyles.tight,\n checkboxStyles.box,\n marked && choiceInputStyles.checked,\n bad && choiceInputStyles.invalid,\n ],\n },\n rest,\n {\n ref: _toRef(input),\n type: 'checkbox',\n id: field?.id ?? id,\n name: rest.name ?? group?.name,\n value,\n checked: isChecked,\n disabled: off,\n required: required ?? field?.required,\n 'aria-invalid': bad || undefined,\n 'aria-readonly': locked || undefined,\n 'aria-describedby':\n [field?.describedBy, hasContent(description) && descriptionId]\n .filter(Boolean)\n .join(' ') || undefined,\n onChange,\n ...(locked && readonlyChoiceHandlers),\n },\n )}\n />\n <Icon\n {...mergePartProps<IconProps>(\n {\n ...s.indicator,\n icon: indeterminate ? Minus : Check,\n draw: drawCheck && isChecked && !indeterminate,\n strokeWidth: 3,\n sx: [s.indicator.sx, checkboxStyles.indicator, !marked && checkboxStyles.hidden],\n },\n propsIndicator,\n )}\n />\n </span>\n {(hasContent(children) || hasContent(description)) && (\n <span {...mergeAttrs<'span'>(s.label, propsLabel)}>\n {children}\n {hasContent(description) && (\n <span\n {...mergeAttrs<'span'>(s.description, propsDescription, {\n id: descriptionId,\n })}\n >\n {description}\n </span>\n )}\n </span>\n )}\n </label>\n );\n };\n },\n);\n\n/** 未声明的属性落到 div(role=\"group\")上 */\nexport interface CheckboxGroupBaseProps<T> extends PartProps<'div', 'role'> {\n /** 勾选的值:父级写 _value={list} */\n _value?: string[];\n /** 表单提交时各项共用的 name */\n name?: string;\n /** 整组不可用 */\n disabled?: boolean;\n /** 整组只读 */\n readonly?: boolean;\n /** 校验未通过(如“至少选一项”) */\n invalid?: boolean;\n /** 排列方向,默认 vertical */\n orientation?: keyof ChoiceOrientations;\n /** 各项:ListboxOption(值、文字、说明、不可用)、字符串,或任意数据加 toOption;写了 children 时不用 */\n items?: readonly T[];\n /** Checkbox;不写时按 items 生成 */\n children?: VNodeChild;\n}\n\n/** CheckboxGroup 的属性:items 是 ListboxOption、字符串时不用 toOption */\nexport type CheckboxGroupProps<T = ListboxOption> = CheckboxGroupBaseProps<T> & OptionMapping<T>;\n\n/** 一组复选框:value 是勾选项的值的数组 */\nexport const CheckboxGroup = _component(\n <T = ListboxOption,>({\n _value: value = _bindable<string[]>([]),\n name,\n disabled,\n readonly,\n invalid,\n orientation = 'vertical',\n id,\n items,\n toOption,\n children,\n ...rest\n }: CheckboxGroupProps<T>) => {\n const control = useFieldControl(() => ({ id, disabled, readonly, invalid }));\n const recipe = useRecipe(choiceRecipe);\n CheckboxGroupContext.provide({\n get value() {\n return value;\n },\n get name() {\n return name;\n },\n get disabled() {\n return control().disabled;\n },\n get readonly() {\n return control().readonly;\n },\n get invalid() {\n return control().invalid;\n },\n toggle(item) {\n value = [...toggleSelection(value, item, { mode: 'multiple' })];\n },\n });\n\n return () => {\n const state = control();\n return (\n <div\n {...mergeAttrs<'div'>(recipe({ orientation }).group, rest, {\n id: state.id,\n role: 'group',\n 'aria-labelledby': defaultLabelledBy(rest, state.labelledBy),\n 'aria-describedby': state.describedBy,\n })}\n data-orientation={orientation}\n data-disabled={state.disabled || undefined}\n data-readonly={state.readonly || undefined}\n >\n {children ??\n items?.map((item) => {\n const option = toListboxOption(item, toOption);\n return (\n <Checkbox\n key={option.value}\n value={option.value}\n disabled={option.disabled || undefined}\n description={option.description}\n >\n {option.label}\n </Checkbox>\n );\n })}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Checkbox.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_shallowRef","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/input/Checkbox.tsx"],"sourcesContent":["/**\n * 复选框(原生 input type=\"checkbox\")与复选组。结构与样式见 choice-styles.ts。\n *\n * <Checkbox _checked={agreed}>我已阅读并同意</Checkbox>\n * <Checkbox _checked={allChecked} indeterminate={someChecked} onChange={toggleAll}>全选</Checkbox>\n * <Field label=\"通知方式\">\n * <CheckboxGroup _value={channels} name=\"channels\">\n * <Checkbox value=\"email\">邮件</Checkbox>\n * <Checkbox value=\"sms\">短信</Checkbox>\n * </CheckboxGroup>\n * </Field>\n * <CheckboxGroup _value={channels} items={[{ value: 'email', label: '邮件', description: '每天汇总一封' }, …]} />\n *\n * 部分勾选(indeterminate)是原生 input 的属性,读屏念“部分选中”。在 Field 里时关联说明与错误、沿用其状态;\n * 复选组用 role=\"group\",以 Field 的标签为名称(aria-labelledby)。\n *\n * 部件:Root(label)、Control(叠放层)、Indicator(对勾 / 横线图标)、Label(文字);未声明的属性落到 input 上。\n */\nimport { Check, Minus } 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 { useId, type VNodeChild } from 'vue';\nimport { Icon, type IconProps } from '../base/Icon';\nimport { useFieldControl } from '../form/Field';\nimport { toListboxOption, type ListboxOption, type OptionMapping } from './list-state';\nimport {\n hasContent,\n defaultLabelledBy,\n mergeAttrs,\n mergePartProps,\n type PartProps,\n} from '../utils/props';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { toggleSelection } from '../utils/data/selection';\nimport type { StatusTone } from '../utils/style/tone-styles';\nimport type { TextSize } from '../utils/style/typography';\nimport { useRecipe } from '../config/styles';\nimport {\n choiceInputStyles,\n choiceParts,\n choiceRecipe,\n useChoiceAppearance,\n type ChoiceOrientations,\n readonlyChoiceHandlers,\n syncChecked,\n} from './choice-styles';\n\n/** CheckboxGroup 交给组内 Checkbox 的状态 */\nexport interface CheckboxGroupState {\n /** 已勾选的值 */\n readonly value: readonly string[];\n /** 表单提交时的 name,组内每个 Checkbox 共用 */\n readonly name: string | undefined;\n /** 整组不可用 */\n readonly disabled: boolean;\n /** 整组只读 */\n readonly readonly: boolean;\n /** 整组校验未通过 */\n readonly invalid: boolean;\n /** 勾选或取消一个值 */\n toggle(value: string): void;\n}\n\n/** CheckboxGroup 的上下文:自定义的勾选项可以 inject 它接入组 */\nexport const CheckboxGroupContext = createContext<CheckboxGroupState>('CheckboxGroup');\n\n/** 勾选状态与可用性由组件管理;原生的 size 属性让给字号档位 */\nexport type CheckboxManaged =\n 'type' | 'checked' | 'disabled' | 'required' | 'size' | 'aria-invalid' | 'aria-describedby';\n\n/** 未声明的属性落到 input 上;外层 label 用 propsRoot */\nexport interface CheckboxProps extends PartProps<'input', CheckboxManaged> {\n /** 是否勾选:父级写 _checked={x};在复选组里时由组决定 */\n _checked?: boolean;\n /** 部分勾选(“全选”下面只选了一部分):显示横线,读屏念“部分选中” */\n indeterminate?: boolean;\n /** 在复选组里的值;单独使用时是表单提交的值(默认 on) */\n value?: string;\n /** 不可用 */\n disabled?: boolean;\n /** 只读:能聚焦、读屏念“只读”,勾选状态不能改(查看详情、审批时);外观照常 */\n readonly?: boolean;\n /** 必填(如“同意条款”) */\n required?: boolean;\n /** 校验未通过 */\n invalid?: boolean;\n /** 字号档位;不写时继承上下文字号 */\n size?: TextSize;\n /** 选中时的色调(与 Button、Badge 等同一套),默认 accent;可以用 defaults.Choice 统一改 */\n tone?: StatusTone;\n /** 外层 label 的部件属性 */\n propsRoot?: PartProps<'label'>;\n /** 叠放层的部件属性 */\n propsControl?: PartProps<'span'>;\n /** 对勾 / 横线图标的部件属性 */\n propsIndicator?: Partial<IconProps>;\n /** 文字的部件属性 */\n propsLabel?: PartProps<'span'>;\n /** 文字下方的说明(aria-describedby) */\n description?: VNodeChild;\n /** 说明的部件属性 */\n propsDescription?: PartProps<'span'>;\n /** 文字 */\n children?: VNodeChild;\n}\n\n/** Checkbox 的样式:box、indicator、hidden */\nexport const checkboxStyles = css.create({\n box: { width: '1.125em', height: '1.125em', borderRadius: '_sm' },\n indicator: { width: '0.875em', height: '0.875em', color: 'var(--tone-on-fill)' },\n hidden: { visibility: 'hidden' },\n});\n\n/** 复选框:原生 checkbox 加自绘的方框与对勾 */\nexport const Checkbox = _component(\n ({\n _checked: checked = _bindable(false),\n indeterminate = false,\n value,\n disabled,\n readonly,\n required,\n invalid,\n size,\n tone,\n id,\n propsRoot,\n propsControl,\n propsIndicator,\n propsLabel,\n description,\n propsDescription,\n children,\n ...rest\n }: CheckboxProps) => {\n const group = CheckboxGroupContext.inject(null);\n const descriptionId = `${useId()}-description`;\n const appearance = useChoiceAppearance(() => ({ size, tone }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let input = _state.raw<HTMLInputElement | null>(null);\n // 用户点击勾上时对勾描线;初次渲染、外部改值不播\n let drawCheck = _state(false);\n\n // indeterminate 只能经 DOM 属性设置\n _effect(() => {\n if (input) input.indeterminate = indeterminate;\n });\n\n function onChange(event: Event) {\n const target = event.target as HTMLInputElement;\n const next = target.checked;\n drawCheck = next;\n if (group && value != null) group.toggle(value);\n else checked = next;\n syncChecked([target], () => (group && value != null ? group.value.includes(value) : checked));\n }\n\n return () => {\n // 在复选组里时,id 与说明归组所有,不再给每一项\n const field = group ? undefined : control();\n const isChecked = group && value != null ? group.value.includes(value) : checked;\n const off = disabled ?? group?.disabled ?? field?.disabled ?? false;\n const locked = readonly ?? group?.readonly ?? field?.readonly ?? false;\n const bad = invalid ?? group?.invalid ?? field?.invalid ?? false;\n const marked = isChecked || indeterminate;\n const s = choiceParts(appearance(), { disabled: off, readonly: locked });\n return (\n <label\n {...mergeAttrs<'label'>(s.root, propsRoot)}\n data-state={indeterminate ? 'indeterminate' : isChecked ? 'checked' : 'unchecked'}\n data-disabled={off || undefined}\n data-readonly={locked || undefined}\n >\n <span {...mergeAttrs<'span'>(s.control, propsControl)}>\n <input\n {...mergeAttrs<'input'>(\n {\n ...s.input,\n sx: [\n s.input.sx,\n focusRingStyles.tight,\n checkboxStyles.box,\n marked && choiceInputStyles.checked,\n bad && choiceInputStyles.invalid,\n ],\n },\n rest,\n {\n ref: _toRef(input),\n type: 'checkbox',\n id: field?.id ?? id,\n name: rest.name ?? group?.name,\n value,\n checked: isChecked,\n disabled: off,\n required: required ?? field?.required,\n 'aria-invalid': bad || undefined,\n 'aria-readonly': locked || undefined,\n 'aria-describedby':\n [field?.describedBy, hasContent(description) && descriptionId]\n .filter(Boolean)\n .join(' ') || undefined,\n onChange,\n ...(locked && readonlyChoiceHandlers),\n },\n )}\n />\n <Icon\n {...mergePartProps<IconProps>(\n {\n ...s.indicator,\n icon: indeterminate ? Minus : Check,\n draw: drawCheck && isChecked && !indeterminate,\n strokeWidth: 3,\n sx: [s.indicator.sx, checkboxStyles.indicator, !marked && checkboxStyles.hidden],\n },\n propsIndicator,\n )}\n />\n </span>\n {(hasContent(children) || hasContent(description)) && (\n <span {...mergeAttrs<'span'>(s.label, propsLabel)}>\n {children}\n {hasContent(description) && (\n <span\n {...mergeAttrs<'span'>(s.description, propsDescription, {\n id: descriptionId,\n })}\n >\n {description}\n </span>\n )}\n </span>\n )}\n </label>\n );\n };\n },\n);\n\n/** 未声明的属性落到 div(role=\"group\")上 */\nexport interface CheckboxGroupBaseProps<T> extends PartProps<'div', 'role'> {\n /** 勾选的值:父级写 _value={list} */\n _value?: string[];\n /** 表单提交时各项共用的 name */\n name?: string;\n /** 整组不可用 */\n disabled?: boolean;\n /** 整组只读 */\n readonly?: boolean;\n /** 校验未通过(如“至少选一项”) */\n invalid?: boolean;\n /** 排列方向,默认 vertical */\n orientation?: keyof ChoiceOrientations;\n /** 各项:ListboxOption(值、文字、说明、不可用)、字符串,或任意数据加 toOption;写了 children 时不用 */\n items?: readonly T[];\n /** Checkbox;不写时按 items 生成 */\n children?: VNodeChild;\n}\n\n/** CheckboxGroup 的属性:items 是 ListboxOption、字符串时不用 toOption */\nexport type CheckboxGroupProps<T = ListboxOption> = CheckboxGroupBaseProps<T> & OptionMapping<T>;\n\n/** 一组复选框:value 是勾选项的值的数组 */\nexport const CheckboxGroup = _component(\n <T = ListboxOption,>({\n _value: value = _bindable<string[]>([]),\n name,\n disabled,\n readonly,\n invalid,\n orientation = 'vertical',\n id,\n items,\n toOption,\n children,\n ...rest\n }: CheckboxGroupProps<T>) => {\n const control = useFieldControl(() => ({ id, disabled, readonly, invalid }));\n const recipe = useRecipe(choiceRecipe);\n CheckboxGroupContext.provide({\n get value() {\n return value;\n },\n get name() {\n return name;\n },\n get disabled() {\n return control().disabled;\n },\n get readonly() {\n return control().readonly;\n },\n get invalid() {\n return control().invalid;\n },\n toggle(item) {\n value = [...toggleSelection(value, item, { mode: 'multiple' })];\n },\n });\n\n return () => {\n const state = control();\n return (\n <div\n {...mergeAttrs<'div'>(recipe({ orientation }).group, rest, {\n id: state.id,\n role: 'group',\n 'aria-labelledby': defaultLabelledBy(rest, state.labelledBy),\n 'aria-describedby': state.describedBy,\n })}\n data-orientation={orientation}\n data-disabled={state.disabled || undefined}\n data-readonly={state.readonly || undefined}\n >\n {children ??\n items?.map((item) => {\n const option = toListboxOption(item, toOption);\n return (\n <Checkbox\n key={option.value}\n value={option.value}\n disabled={option.disabled || undefined}\n description={option.description}\n >\n {option.label}\n </Checkbox>\n );\n })}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
package/dist/input/ColorField.js
CHANGED
|
@@ -5,8 +5,8 @@ import { useFieldControl } from "../form/Field.js";
|
|
|
5
5
|
import { controlParts, focusOnShell, useControlAppearance } from "./control.js";
|
|
6
6
|
import { parseColor, toHex } from "../utils/data/color.js";
|
|
7
7
|
import { swatchStyles } from "../utils/style/swatch-styles.js";
|
|
8
|
-
import { createVNode,
|
|
9
|
-
import { _component, bindable, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
8
|
+
import { createVNode, ref, shallowRef, vModelText, watch, withDirectives } from "vue";
|
|
9
|
+
import { _component, bindable, mergeJsxProps, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
10
10
|
import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
11
11
|
//#region src/input/ColorField.tsx
|
|
12
12
|
/** 值、状态与无障碍关联由组件管理 */
|
|
@@ -90,7 +90,7 @@ var ColorField = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
90
90
|
invalid: showInvalid
|
|
91
91
|
});
|
|
92
92
|
const opaque = toHex(value.value)?.slice(0, 7) ?? "#000000";
|
|
93
|
-
return createVNode("div",
|
|
93
|
+
return createVNode("div", mergeJsxProps(mergeAttrs(s.root, propsRoot.value, { onPointerdown: focusOnShell(() => input.value) }), {
|
|
94
94
|
"data-invalid": showInvalid || void 0,
|
|
95
95
|
"data-disabled": state.disabled || void 0
|
|
96
96
|
}), [createVNode("label", mergeAttrs({ sx: [swatchStyles.checkerboard, colorFieldStyles.swatch] }, propsSwatch.value), [createVNode("span", css.attrs(colorFieldStyles.fill, swatchStyles.ring, css.bind(colorFieldDynamicStyles.fill, () => [value.value], true)), null), createVNode("input", mergeAttrs({ sx: [colorFieldStyles.picker, focusRingStyles.visible] }, propsPicker.value, {
|
|
@@ -99,7 +99,7 @@ var ColorField = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
99
99
|
disabled: !editable,
|
|
100
100
|
"aria-label": lang.colorPick,
|
|
101
101
|
onInput: (event) => value.value = event.target.value
|
|
102
|
-
}), null)]), withDirectives(createVNode("input",
|
|
102
|
+
}), null)]), withDirectives(createVNode("input", mergeJsxProps(mergeAttrs({
|
|
103
103
|
...s.input,
|
|
104
104
|
sx: [s.input.sx, colorFieldStyles.input]
|
|
105
105
|
}, rest, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_vue_ref","_vtp_untrack","_createVNode","_mergeProps","_withDirectives","_vModelText"],"sources":["../../src/input/ColorField.tsx"],"sourcesContent":["/**\n * 颜色输入:前面是色块(点开浏览器原生的取色器),后面可以直接输入颜色值。主题编辑器、品牌色设置这类地方用。\n *\n * <ColorField _value={brand} aria-label=\"品牌色\" />\n *\n * - 值是 #rrggbb(有透明度时 #rrggbbaa):输入 rgb()、颜色名也行,失焦或回车时规范成 #hex 写回;\n * 写不成颜色时外壳标为无效(aria-invalid),值不变,失焦后恢复成原来的值。\n * - 原生取色器不带透明度:用它选色时透明度去掉。\n * - 接入 Field(标签、说明、错误、必填、不可用),外观同 TextField(control.tsx)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { watch } from 'vue';\nimport { useLang } from '../config/context';\nimport { useFieldControl } from '../form/Field';\nimport { parseColor, toHex } from '../utils/data/color';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { swatchStyles } from '../utils/style/swatch-styles';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { controlParts, focusOnShell, useControlAppearance, type ControlOptions } from './control';\n\n/** 值、状态与无障碍关联由组件管理 */\nexport type ColorFieldManaged =\n | 'value'\n | 'type'\n | 'disabled'\n | 'readonly'\n | 'required'\n | 'size'\n | 'aria-invalid'\n | 'aria-describedby';\n\n/** 未声明的属性落到文字输入框(input)上 */\nexport interface ColorFieldProps extends PartProps<'input', ColorFieldManaged>, ControlOptions {\n /** 颜色值(#rrggbb 或 #rrggbbaa):父级写 _value={x} 双向绑定 */\n _value?: string;\n /** 不可用 */\n disabled?: boolean;\n /** 只读:能看到颜色、复制取值,不能修改 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过 */\n invalid?: boolean;\n /** 外壳(边框、焦点环)的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 色块(包着原生取色器的 label)的部件属性 */\n propsSwatch?: PartProps<'label'>;\n /** 原生取色器(透明地盖在色块上)的部件属性;类型、取值、可用性与无障碍名称由组件管理 */\n propsPicker?: PartProps<'input', 'type' | 'value' | 'disabled' | 'aria-label' | 'onInput'>;\n}\n\n/** ColorField 的样式:swatch、fill、picker、input */\nexport const colorFieldStyles = css.create({\n // 色块:棋盘格垫底(swatchStyles),颜色铺在上面一层\n swatch: {\n position: 'relative',\n flexShrink: 0,\n width: '1.25em',\n height: '1.25em',\n borderRadius: '_sm',\n overflow: 'hidden',\n cursor: 'pointer',\n },\n fill: { position: 'absolute', inset: 0 },\n // 原生取色器盖满色块、完全透明:点色块就是点它,键盘也能聚焦它\n picker: {\n position: 'absolute',\n inset: 0,\n width: '_full',\n height: '_full',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n opacity: 0,\n cursor: 'inherit',\n },\n // 等宽字体:#hex 各位对齐,改一位时不跳动\n input: { fontFamily: '_mono', fontVariantLigatures: 'none' },\n});\n\n// 颜色是任意值,用动态样式;单独一个 create,见 COMPONENTS.md §4\n/** ColorField 的动态样式:色块里的颜色 */\nexport const colorFieldDynamicStyles = css.create({\n fill: (color: string) => ({ backgroundColor: color }),\n});\n\n/** 颜色输入(色块 + 文字输入):值是 #hex */\nexport const ColorField = _component(\n ({\n _value: value = _bindable('#000000'),\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n id,\n propsRoot,\n propsSwatch,\n propsPicker,\n ...rest\n }: ColorFieldProps) => {\n const lang = useLang();\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let input = _state.raw<HTMLInputElement | null>(null);\n // 正在输入的文字:写成颜色之前不写回 value\n let draft = _state(_untrack(value));\n watch(\n () => value,\n (next) => (draft = next),\n );\n const parsed = () => parseColor(draft) !== undefined;\n\n function commit() {\n const hex = toHex(draft);\n if (hex) value = hex;\n draft = value;\n }\n\n return () => {\n const state = control();\n const editable = !state.disabled && !state.readonly;\n const showInvalid = state.invalid || !parsed();\n const s = controlParts(appearance(), { ...state, invalid: showInvalid });\n // 原生取色器只认 #rrggbb\n const opaque = toHex(value)?.slice(0, 7) ?? '#000000';\n return (\n <div\n {...mergeAttrs<'div'>(s.root, propsRoot, { onPointerdown: focusOnShell(() => input) })}\n data-invalid={showInvalid || undefined}\n data-disabled={state.disabled || undefined}\n >\n <label\n {...mergeAttrs<'label'>(\n { sx: [swatchStyles.checkerboard, colorFieldStyles.swatch] },\n propsSwatch,\n )}\n >\n <span\n {...css.attrs(\n colorFieldStyles.fill,\n swatchStyles.ring,\n colorFieldDynamicStyles.fill(value),\n )}\n />\n <input\n {...mergeAttrs<'input'>(\n { sx: [colorFieldStyles.picker, focusRingStyles.visible] },\n propsPicker,\n {\n type: 'color',\n value: opaque,\n disabled: !editable,\n 'aria-label': lang.colorPick,\n onInput: (event: Event) => (value = (event.target as HTMLInputElement).value),\n },\n )}\n />\n </label>\n <input\n {...mergeAttrs<'input'>(\n { ...s.input, sx: [s.input.sx, colorFieldStyles.input] },\n rest,\n {\n ref: _toRef(input),\n id: state.id,\n type: 'text',\n spellcheck: false,\n autocomplete: 'off',\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n 'aria-invalid': showInvalid || undefined,\n 'aria-describedby': state.describedBy,\n onBlur: commit,\n onKeydown: (event: KeyboardEvent) => {\n if (event.key === 'Enter') commit();\n },\n },\n )}\n _value={draft}\n />\n </div>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;;;;;;AAqDA,IAAa,mBAAmB,IAAI,OAAO;CAEzC,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,OAAO;EACP,QAAQ;EACR,cAAc;EACd,UAAU;EACV,QAAQ;CACV;CACA,MAAM;EAAE,UAAU;EAAY,OAAO;CAAE;CAEvC,QAAQ;EACN,UAAU;EACV,OAAO;EACP,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,aAAa;EACb,SAAS;EACT,QAAQ;CACV;CAEA,OAAO;EAAE,YAAY;EAAS,sBAAsB;CAAO;AAC7D,CAAC;;AAID,IAAa,0BAA0B,IAAI,OAAO,EAChD,OAAO,WAAmB,EAAE,iBAAiB,MAAM,GACrD,CAAC;;AAGD,IAAa,aAAa,0BACxB,QAAA,SAcuB;CAAA,MAAA,QAAAA,SAAA,QAAA,gBAbK,WAAS,KAAA,IAAA;CAAA,MAAA,UAAAC,aAAA,QAAA,SAAA;CAAA,MAAA,OAAAA,aAAA,QAAA,MAAA;CAAA,MAAA,SAAAA,aAAA,QAAA,QAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,UAAA;CAAA,MAAA,UAAAA,aAAA,QAAA,SAAA;CAAA,MAAA,KAAAA,aAAA,QAAA,IAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAYhC,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,MAAM,OAAO,QAAQ;CACrB,MAAM,aAAa,4BAA4B;EAAE,SAAO,QAAA;EAAE,MAAI,KAAA;EAAE,QAAM,OAAA;CAAC,EAAE;CACzE,MAAM,UAAU,uBAAuB;EAAE,IAAE,GAAA;EAAE,SAAO,QAAA;EAAE,UAAQ,SAAA;EAAE,UAAQ,SAAA;EAAE,UAAQ,SAAA;CAAC,EAAE;CACrF,IAAI,QAAKC,WAAuC,IAAI;CAEpD,IAAI,QAAKC,IAAAC,cAAA,MAAA,KAAA,CAAA;CACT,YACE,MAAA,QACC,SAAU,MAAA,QAAQ,IACrB;CACA,MAAM,eAAe,WAAU,MAAA,KAAM,MAAM,KAAA;CAE3C,SAAS,SAAS;EAChB,MAAM,MAAM,MAAK,MAAA,KAAM;EACvB,IAAI,KAAK,MAAA,QAAQ;EACjB,MAAA,QAAA,MAAA;CACF;CAEA,aAAa;EACX,MAAM,QAAQ,QAAQ;EACtB,MAAM,WAAW,CAAC,MAAM,YAAY,CAAC,MAAM;EAC3C,MAAM,cAAc,MAAM,WAAW,CAAC,OAAO;EAC7C,MAAM,IAAI,aAAa,WAAW,GAAG;GAAE,GAAG;GAAO,SAAS;EAAY,CAAC;EAEvE,MAAM,SAAS,MAAK,MAAA,KAAM,CAAC,EAAE,MAAM,GAAG,CAAC,KAAK;EAC5C,OAAAC,YAAA,OAAAC,
|
|
1
|
+
{"version":3,"file":"ColorField.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_shallowRef","_vue_ref","_vtp_untrack","_createVNode","_mergeProps","_withDirectives","_vModelText"],"sources":["../../src/input/ColorField.tsx"],"sourcesContent":["/**\n * 颜色输入:前面是色块(点开浏览器原生的取色器),后面可以直接输入颜色值。主题编辑器、品牌色设置这类地方用。\n *\n * <ColorField _value={brand} aria-label=\"品牌色\" />\n *\n * - 值是 #rrggbb(有透明度时 #rrggbbaa):输入 rgb()、颜色名也行,失焦或回车时规范成 #hex 写回;\n * 写不成颜色时外壳标为无效(aria-invalid),值不变,失焦后恢复成原来的值。\n * - 原生取色器不带透明度:用它选色时透明度去掉。\n * - 接入 Field(标签、说明、错误、必填、不可用),外观同 TextField(control.tsx)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { watch } from 'vue';\nimport { useLang } from '../config/context';\nimport { useFieldControl } from '../form/Field';\nimport { parseColor, toHex } from '../utils/data/color';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { swatchStyles } from '../utils/style/swatch-styles';\nimport { focusRingStyles } from '../utils/style/styles';\nimport { controlParts, focusOnShell, useControlAppearance, type ControlOptions } from './control';\n\n/** 值、状态与无障碍关联由组件管理 */\nexport type ColorFieldManaged =\n | 'value'\n | 'type'\n | 'disabled'\n | 'readonly'\n | 'required'\n | 'size'\n | 'aria-invalid'\n | 'aria-describedby';\n\n/** 未声明的属性落到文字输入框(input)上 */\nexport interface ColorFieldProps extends PartProps<'input', ColorFieldManaged>, ControlOptions {\n /** 颜色值(#rrggbb 或 #rrggbbaa):父级写 _value={x} 双向绑定 */\n _value?: string;\n /** 不可用 */\n disabled?: boolean;\n /** 只读:能看到颜色、复制取值,不能修改 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过 */\n invalid?: boolean;\n /** 外壳(边框、焦点环)的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 色块(包着原生取色器的 label)的部件属性 */\n propsSwatch?: PartProps<'label'>;\n /** 原生取色器(透明地盖在色块上)的部件属性;类型、取值、可用性与无障碍名称由组件管理 */\n propsPicker?: PartProps<'input', 'type' | 'value' | 'disabled' | 'aria-label' | 'onInput'>;\n}\n\n/** ColorField 的样式:swatch、fill、picker、input */\nexport const colorFieldStyles = css.create({\n // 色块:棋盘格垫底(swatchStyles),颜色铺在上面一层\n swatch: {\n position: 'relative',\n flexShrink: 0,\n width: '1.25em',\n height: '1.25em',\n borderRadius: '_sm',\n overflow: 'hidden',\n cursor: 'pointer',\n },\n fill: { position: 'absolute', inset: 0 },\n // 原生取色器盖满色块、完全透明:点色块就是点它,键盘也能聚焦它\n picker: {\n position: 'absolute',\n inset: 0,\n width: '_full',\n height: '_full',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n opacity: 0,\n cursor: 'inherit',\n },\n // 等宽字体:#hex 各位对齐,改一位时不跳动\n input: { fontFamily: '_mono', fontVariantLigatures: 'none' },\n});\n\n// 颜色是任意值,用动态样式;单独一个 create,见 COMPONENTS.md §4\n/** ColorField 的动态样式:色块里的颜色 */\nexport const colorFieldDynamicStyles = css.create({\n fill: (color: string) => ({ backgroundColor: color }),\n});\n\n/** 颜色输入(色块 + 文字输入):值是 #hex */\nexport const ColorField = _component(\n ({\n _value: value = _bindable('#000000'),\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n id,\n propsRoot,\n propsSwatch,\n propsPicker,\n ...rest\n }: ColorFieldProps) => {\n const lang = useLang();\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n let input = _state.raw<HTMLInputElement | null>(null);\n // 正在输入的文字:写成颜色之前不写回 value\n let draft = _state(_untrack(value));\n watch(\n () => value,\n (next) => (draft = next),\n );\n const parsed = () => parseColor(draft) !== undefined;\n\n function commit() {\n const hex = toHex(draft);\n if (hex) value = hex;\n draft = value;\n }\n\n return () => {\n const state = control();\n const editable = !state.disabled && !state.readonly;\n const showInvalid = state.invalid || !parsed();\n const s = controlParts(appearance(), { ...state, invalid: showInvalid });\n // 原生取色器只认 #rrggbb\n const opaque = toHex(value)?.slice(0, 7) ?? '#000000';\n return (\n <div\n {...mergeAttrs<'div'>(s.root, propsRoot, { onPointerdown: focusOnShell(() => input) })}\n data-invalid={showInvalid || undefined}\n data-disabled={state.disabled || undefined}\n >\n <label\n {...mergeAttrs<'label'>(\n { sx: [swatchStyles.checkerboard, colorFieldStyles.swatch] },\n propsSwatch,\n )}\n >\n <span\n {...css.attrs(\n colorFieldStyles.fill,\n swatchStyles.ring,\n colorFieldDynamicStyles.fill(value),\n )}\n />\n <input\n {...mergeAttrs<'input'>(\n { sx: [colorFieldStyles.picker, focusRingStyles.visible] },\n propsPicker,\n {\n type: 'color',\n value: opaque,\n disabled: !editable,\n 'aria-label': lang.colorPick,\n onInput: (event: Event) => (value = (event.target as HTMLInputElement).value),\n },\n )}\n />\n </label>\n <input\n {...mergeAttrs<'input'>(\n { ...s.input, sx: [s.input.sx, colorFieldStyles.input] },\n rest,\n {\n ref: _toRef(input),\n id: state.id,\n type: 'text',\n spellcheck: false,\n autocomplete: 'off',\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n 'aria-invalid': showInvalid || undefined,\n 'aria-describedby': state.describedBy,\n onBlur: commit,\n onKeydown: (event: KeyboardEvent) => {\n if (event.key === 'Enter') commit();\n },\n },\n )}\n _value={draft}\n />\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
package/dist/input/Combobox.js
CHANGED
|
@@ -12,8 +12,8 @@ import { activeOptionId } from "./Listbox.js";
|
|
|
12
12
|
import { FormValue } from "../form/FormValue.js";
|
|
13
13
|
import { ListPopover } from "./ListPopover.js";
|
|
14
14
|
import { useRemoteItems } from "./remote-items.js";
|
|
15
|
-
import { Fragment, createVNode,
|
|
16
|
-
import { _component, bindable, childrenProp, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
15
|
+
import { Fragment, createVNode, ref, shallowRef, useId, vModelText, watch, withDirectives } from "vue";
|
|
16
|
+
import { _component, bindable, childrenProp, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
17
17
|
import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
18
18
|
import { ChevronDown } from "@lucide/icons";
|
|
19
19
|
//#region src/input/Combobox.tsx
|
|
@@ -200,7 +200,7 @@ var Combobox = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
200
200
|
const state = control();
|
|
201
201
|
const s = controlParts(appearance(), state);
|
|
202
202
|
const editable = !state.disabled && !state.readonly;
|
|
203
|
-
return createVNode(Fragment, null, [createVNode("div",
|
|
203
|
+
return createVNode(Fragment, null, [createVNode("div", mergeJsxProps(mergeAttrs(s.root, propsRoot.value, {
|
|
204
204
|
ref: shell,
|
|
205
205
|
onPointerdown: focusOnShell(() => input.value)
|
|
206
206
|
}), {
|
|
@@ -209,7 +209,7 @@ var Combobox = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
209
209
|
"data-disabled": state.disabled || void 0
|
|
210
210
|
}), [
|
|
211
211
|
controlIcon(s, icon.value, propsIcon.value),
|
|
212
|
-
withDirectives(createVNode("input",
|
|
212
|
+
withDirectives(createVNode("input", mergeJsxProps(mergeAttrs(s.input, rest, {
|
|
213
213
|
ref: input,
|
|
214
214
|
id: state.id,
|
|
215
215
|
role: "combobox",
|
|
@@ -270,7 +270,7 @@ var Combobox = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
270
270
|
list,
|
|
271
271
|
id: listId,
|
|
272
272
|
renderOption: children.value,
|
|
273
|
-
empty: remote.
|
|
273
|
+
empty: remote.failure() ?? empty.value
|
|
274
274
|
},
|
|
275
275
|
"propsListbox": propsListbox.value,
|
|
276
276
|
"propsPopover": propsPopover.value
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_childrenProp","_vtp_restProps","_vue_ref","_vue_shallowRef","_createVNode","_Fragment","_mergeProps","_withDirectives","_vModelText"],"sources":["../../src/input/Combobox.tsx"],"sourcesContent":["/**\n * 组合框(WAI-ARIA Combobox,aria-autocomplete=\"list\"):边输入边从列表里选,或者只当带建议的输入框用。\n *\n * <Field label=\"城市\"><Combobox items={cities} _value={city} /></Field>\n * <Combobox items={results} filter={false} loading={searching} _inputValue={keyword} aria-label=\"搜索用户\" />\n *\n * 组合已有的部件:外壳同 TextField(controlParts),弹出层用 useAnchoredPopover(与外壳同宽),列表是 ListboxView。\n * 焦点一直在输入框里,高亮项经 aria-activedescendant 告诉读屏。\n *\n * - 过滤:默认本地按显示文字包含输入(Intl.Collator,忽略大小写与重音);filter={false} 时不过滤,\n * 由调用方按 inputValue 换 items(异步搜索,配合 loading)。给 load 时组件自己请求:打开时与输入停下 300 ms 后\n * 按输入请求,只采用最后一次(remote-items.ts,同 Select)。\n * - 中文输入法:输入经 v-model 写回,组合输入期间 inputValue 不变,所以不会拿拼音去过滤。\n * - 选中后输入框显示选项文字;失焦时如果文字不是某个选项(且没开 allowCustomValue),恢复成已选项的文字,清空则取消选择。\n * - 键盘:↓ 打开、↑↓ / Page Up / Down 移动,Enter 选中,Esc 关闭(关闭时再按 Esc 清空);Home / End 照常移动光标。\n *\n * 部件:Root(外壳)、Input(主元素)、Clear、Chevron(切换按钮)、Popover、Listbox。\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 { useId, watch, type VNodeChild } from 'vue';\nimport type { PresetIconButtonProps } from '../base/CloseButton';\nimport { IconButton, type IconButtonProps } from '../base/IconButton';\nimport { useLang, useTextMatcher } from '../config/context';\nimport { isComposingKey } from '../utils/dom/hotkeys';\nimport { useAnchoredPopover, type FloatingPlacement } from '../utils/dom/floating';\nimport { openSetter, type OpenChangeProps } from '../utils/dom/open-change';\nimport { ListPopover } from './ListPopover';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport {\n controlClear,\n controlParts,\n focusOnShell,\n controlIcon,\n useControlAppearance,\n type ControlIconOptions,\n type ControlOptions,\n} from './control';\nimport { useFieldControl } from '../form/Field';\nimport { FormValue } from '../form/FormValue';\nimport { disclosureStyles } from '../utils/style/transitions';\nimport { activeOptionId, type ListboxViewProps, type OptionRenderState } from './Listbox';\nimport {\n handleListKeydown,\n useListState,\n useResultAnnouncement,\n useSelectedOptions,\n type ListboxOption,\n type OptionMapping,\n toListboxOption,\n} from './list-state';\nimport { useRemoteItems, type OptionsLoader } from './remote-items';\n\n/** 角色、展开状态、值与可用性由组件管理 */\nexport type ComboboxManaged =\n | 'value'\n | 'role'\n | 'size'\n | 'disabled'\n | 'readonly'\n | 'required'\n | 'autocomplete'\n | 'aria-autocomplete'\n | 'aria-expanded'\n | 'aria-controls'\n | 'aria-activedescendant'\n | 'aria-invalid'\n | 'aria-describedby';\n\n/** Combobox 除 toOption 外的属性;未声明的属性落到 input(主元素)上,外壳用 propsRoot */\nexport interface ComboboxBaseProps<T>\n extends PartProps<'input', ComboboxManaged>, ControlOptions, ControlIconOptions, OpenChangeProps {\n /** 数据:ListboxOption、字符串,或任意数据加 toOption;有 load 时是第一次加载之前的选项(编辑页放上已选的那一项) */\n items?: readonly T[];\n /** 选中项的值:父级写 _value={x};没有选中时是 null */\n _value?: string | null;\n /** 输入框里的文字:父级可以写 _inputValue={x}(异步搜索时据此取数据) */\n _inputValue?: string;\n /** 是否打开:父级可以写 _open={x} */\n _open?: boolean;\n /** 过滤:默认按显示文字包含输入(忽略大小写与重音);函数自定义;false 不过滤(异步搜索) */\n filter?: false | ((item: T, query: string) => boolean);\n /** 远程选项:打开时与输入停下 300 ms 后按输入调用,结果代替 items;只采用最后一次,被顶掉的请求 signal 中止 */\n load?: OptionsLoader<T>;\n /** 允许输入不在选项里的文字:失焦时保留,value 为 null */\n allowCustomValue?: boolean;\n /**\n * 显示右侧的展开按钮;只当带建议的输入框用时(Autocomplete)关掉,列表随输入出现\n * @default true\n */\n showToggle?: boolean;\n /** 没有可选的项时不弹出列表(不显示“没有匹配的选项”):只当带建议的输入框用时(Autocomplete) */\n hideEmpty?: boolean;\n /** 正在取选项(异步搜索):没有选项时列表里是骨架行,已有选项时顶部显示进度条 */\n loading?: boolean;\n /** 弹出位置,默认 bottom-start */\n placement?: FloatingPlacement;\n /** 有内容时显示清空按钮 */\n clearable?: boolean;\n /** 表单提交时的 name(用隐藏的 input 提交 value) */\n name?: string;\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过 */\n invalid?: boolean;\n /** 自定义选项内容:`{(item, { selected, active }) => …}`,拿到 items 里的原始数据 */\n children?: (item: T, state: OptionRenderState) => VNodeChild;\n /** 没有匹配的选项时列表里显示的内容 */\n empty?: VNodeChild;\n /** 外壳的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 清空按钮的部件属性 */\n propsClear?: Partial<PresetIconButtonProps>;\n /** 切换按钮(下拉箭头)的部件属性 */\n propsChevron?: Partial<IconButtonProps>;\n /** 弹出层的部件属性 */\n propsPopover?: PartProps<'div', 'id' | 'popover'>;\n /** 列表的部件属性 */\n propsListbox?: Partial<ListboxViewProps<T>>;\n}\n\n/** 组合框的属性;items 不是 ListboxOption 或字符串时要给 toOption */\nexport type ComboboxProps<T = ListboxOption> = ComboboxBaseProps<T> & OptionMapping<T>;\n\n/** Combobox 的样式:chevronOpen */\nexport const comboboxStyles = css.create({\n chevronOpen: { rotate: '180deg' },\n});\n\n/** 组合框:输入框 + 过滤后的选项列表 */\nexport const Combobox = _component(\n <T,>({\n items = [],\n toOption,\n _value: value = _bindable<string | null>(null),\n _inputValue: inputValue = _bindable(''),\n _open: open = _bindable(false),\n onOpenChange,\n filter,\n load,\n allowCustomValue = false,\n showToggle = true,\n hideEmpty = false,\n loading = false,\n placement = 'bottom-start',\n clearable = false,\n name,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n id,\n children,\n empty,\n propsRoot,\n icon,\n propsIcon,\n propsClear,\n propsChevron,\n propsPopover,\n propsListbox,\n ...rest\n }: ComboboxProps<T>) => {\n const lang = useLang();\n const textMatcher = useTextMatcher();\n const listId = useId();\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n // 用户输入的过滤词:选中、用箭头打开时清空(显示全部选项)\n let query = _state('');\n // 组件自己改 inputValue(选中后写入选项文字)时,不当作用户输入\n let writing = false;\n let shell = _state.raw<HTMLElement | null>(null);\n let input = _state.raw<HTMLInputElement | null>(null);\n let panel = _state.raw<HTMLElement | null>(null);\n const setOpen = openSetter(\n () => open,\n (next) => (open = next),\n () => onOpenChange,\n );\n\n const optionOf = (item: T) => toListboxOption(item, toOption);\n\n function matches(item: T, text: string) {\n if (!text) return true;\n return filter ? filter(item, text) : textMatcher()(optionOf(item).label, text);\n }\n\n const remote = useRemoteItems({\n load: () => load,\n query: () => query,\n open: () => open,\n items: () => items,\n });\n const list = useListState({\n // 有 load 或 filter={false} 时由服务端按输入过滤\n items: () =>\n load || filter === false\n ? remote.items()\n : remote.items().filter((item) => matches(item, query)),\n toOption: optionOf,\n selected: () => (value != null ? [value] : []),\n mode: () => 'single',\n // 再选已选的项不取消\n required: () => true,\n onChange: (next) => (value = next[0] ?? null),\n });\n\n // 已选项的文字:远程搜索换了 items 之后,仍按之前见过的文字显示\n const selectedOf = useSelectedOptions({ items: remote.items, toOption: optionOf });\n const selectedLabel = () => (value == null ? '' : selectedOf([value])[0]!.label);\n\n function setText(text: string) {\n if (inputValue === text) return;\n writing = true;\n inputValue = text;\n }\n\n useResultAnnouncement(() => ({ query, count: list.options.length }));\n\n // 用户输入(含输入法组合结束):打开并按输入过滤,高亮第一项\n watch(\n () => inputValue,\n (text) => {\n if (writing) {\n writing = false;\n return;\n }\n query = text;\n // 只在输入框聚焦时打开:父级把 inputValue 改掉(重置成空)不该弹出列表\n if (!control().readonly && document.activeElement === input) setOpen(true, 'trigger');\n list.move('first');\n },\n );\n\n // 父级改了 value,或选项后到(编辑页先拿到值、再拿到选项):输入框跟着显示它的文字;用户正在输入时不打断\n watch(\n () => [value, selectedLabel()],\n () => {\n if (query) return;\n if (!allowCustomValue || value != null) setText(selectedLabel());\n },\n { immediate: true },\n );\n\n function pick(choice: string, event?: Event) {\n value = choice;\n setText(selectedLabel());\n query = '';\n setOpen(false, 'select', event);\n }\n\n function show(event?: Event) {\n query = '';\n list.activateDefault();\n setOpen(true, 'trigger', event);\n }\n\n // 失焦:文字不是选项时恢复(或清空选择)\n function commit(event: FocusEvent) {\n setOpen(false, 'focus', event);\n if (allowCustomValue) {\n if (inputValue !== selectedLabel()) value = null;\n return;\n }\n if (!inputValue) value = null;\n else setText(selectedLabel());\n query = '';\n }\n\n function onKeydown(event: KeyboardEvent) {\n const state = control();\n if (state.disabled || state.readonly || isComposingKey(event)) return;\n if (event.key === 'Escape') {\n // 打开时交给原生 popover 关闭;关闭时清空\n if (!open && inputValue) {\n event.preventDefault();\n setText('');\n value = null;\n }\n return;\n }\n if (!open) {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n show(event);\n }\n return;\n }\n if (handleListKeydown(list, event, { homeEnd: false }, (choice) => pick(choice, event)))\n event.preventDefault();\n }\n\n // 列表是否真的弹出:hideEmpty 时没有可选的项(也不在加载)就不弹\n const shown = () =>\n open && (!hideEmpty || list.options.length > 0 || loading || remote.loading());\n\n // 弹层贴着外壳、与它同宽;焦点一直在输入框上,关闭时不用归还\n const { onToggle } = useAnchoredPopover(\n () => ({\n open: shown(),\n anchor: shell,\n panel,\n floating: { placement, matchWidth: true, fitHeight: true },\n restoreFocus: false,\n }),\n { close: (reason, event) => setOpen(false, reason, event) },\n );\n\n return () => {\n const state = control();\n const s = controlParts(appearance(), state);\n const editable = !state.disabled && !state.readonly;\n return (\n <>\n <div\n {...mergeAttrs<'div'>(s.root, propsRoot, {\n ref: _toRef(shell),\n onPointerdown: focusOnShell(() => input),\n })}\n data-state={open ? 'open' : 'closed'}\n data-invalid={state.invalid || undefined}\n data-disabled={state.disabled || undefined}\n >\n {controlIcon(s, icon, propsIcon)}\n {/* _bind 编译为 v-model:输入法组合期间不写回 */}\n <input\n {...mergeAttrs<'input'>(s.input, rest, {\n ref: _toRef(input),\n id: state.id,\n role: 'combobox',\n autocomplete: 'off',\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n 'aria-autocomplete': 'list',\n 'aria-expanded': shown(),\n 'aria-controls': listId,\n 'aria-activedescendant': open ? activeOptionId(list, listId) : undefined,\n 'aria-invalid': state.invalid || undefined,\n 'aria-describedby': state.describedBy,\n onKeydown,\n onBlur: commit,\n })}\n _value={inputValue}\n />\n {clearable &&\n inputValue &&\n editable &&\n controlClear(s, propsClear, () => {\n setText('');\n value = null;\n input?.focus();\n })}\n {showToggle && (\n <IconButton\n {...mergePartProps<IconButtonProps>(\n {\n ...s.button,\n sx: [s.button.sx, disclosureStyles.icon, open && comboboxStyles.chevronOpen],\n radius: 'full',\n icon: ChevronDown,\n 'aria-label': lang.comboboxToggle,\n },\n propsChevron,\n {\n tabindex: -1,\n disabled: !editable,\n 'aria-expanded': shown(),\n 'aria-controls': listId,\n // 不让输入框失焦(失焦会提交并关闭)\n onPointerdown: (event: PointerEvent) => event.preventDefault(),\n onClick: (event: MouseEvent) => {\n if (open) setOpen(false, 'trigger', event);\n else show(event);\n input?.focus();\n },\n },\n )}\n />\n )}\n <FormValue name={name} value={value} disabled={state.disabled} />\n </div>\n <ListPopover\n panelRef={_toRef(panel)}\n onToggle={onToggle}\n size={appearance().size}\n labelledBy={state.labelledBy}\n label={rest['aria-label']}\n loading={loading || remote.loading()}\n onPick={(choice) => pick(choice)}\n listbox={{\n list,\n id: listId,\n renderOption: children,\n empty: remote.error() ? lang.listLoadFailed : empty,\n }}\n propsListbox={propsListbox}\n propsPopover={propsPopover}\n />\n </>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Combobox.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_childrenProp","_vtp_restProps","_vue_ref","_vue_shallowRef","_createVNode","_Fragment","_mergeProps","_withDirectives","_vModelText"],"sources":["../../src/input/Combobox.tsx"],"sourcesContent":["/**\n * 组合框(WAI-ARIA Combobox,aria-autocomplete=\"list\"):边输入边从列表里选,或者只当带建议的输入框用。\n *\n * <Field label=\"城市\"><Combobox items={cities} _value={city} /></Field>\n * <Combobox items={results} filter={false} loading={searching} _inputValue={keyword} aria-label=\"搜索用户\" />\n *\n * 组合已有的部件:外壳同 TextField(controlParts),弹出层用 useAnchoredPopover(与外壳同宽),列表是 ListboxView。\n * 焦点一直在输入框里,高亮项经 aria-activedescendant 告诉读屏。\n *\n * - 过滤:默认本地按显示文字包含输入(Intl.Collator,忽略大小写与重音);filter={false} 时不过滤,\n * 由调用方按 inputValue 换 items(异步搜索,配合 loading)。给 load 时组件自己请求:打开时与输入停下 300 ms 后\n * 按输入请求,只采用最后一次(remote-items.ts,同 Select)。\n * - 中文输入法:输入经 v-model 写回,组合输入期间 inputValue 不变,所以不会拿拼音去过滤。\n * - 选中后输入框显示选项文字;失焦时如果文字不是某个选项(且没开 allowCustomValue),恢复成已选项的文字,清空则取消选择。\n * - 键盘:↓ 打开、↑↓ / Page Up / Down 移动,Enter 选中,Esc 关闭(关闭时再按 Esc 清空);Home / End 照常移动光标。\n *\n * 部件:Root(外壳)、Input(主元素)、Clear、Chevron(切换按钮)、Popover、Listbox。\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 { useId, watch, type VNodeChild } from 'vue';\nimport type { PresetIconButtonProps } from '../base/CloseButton';\nimport { IconButton, type IconButtonProps } from '../base/IconButton';\nimport { useLang, useTextMatcher } from '../config/context';\nimport { isComposingKey } from '../utils/dom/hotkeys';\nimport { useAnchoredPopover, type FloatingPlacement } from '../utils/dom/floating';\nimport { openSetter, type OpenChangeProps } from '../utils/dom/open-change';\nimport { ListPopover } from './ListPopover';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport {\n controlClear,\n controlParts,\n focusOnShell,\n controlIcon,\n useControlAppearance,\n type ControlIconOptions,\n type ControlOptions,\n} from './control';\nimport { useFieldControl } from '../form/Field';\nimport { FormValue } from '../form/FormValue';\nimport { disclosureStyles } from '../utils/style/transitions';\nimport { activeOptionId, type ListboxViewProps, type OptionRenderState } from './Listbox';\nimport {\n handleListKeydown,\n useListState,\n useResultAnnouncement,\n useSelectedOptions,\n type ListboxOption,\n type OptionMapping,\n toListboxOption,\n} from './list-state';\nimport { useRemoteItems, type OptionsLoader } from './remote-items';\n\n/** 角色、展开状态、值与可用性由组件管理 */\nexport type ComboboxManaged =\n | 'value'\n | 'role'\n | 'size'\n | 'disabled'\n | 'readonly'\n | 'required'\n | 'autocomplete'\n | 'aria-autocomplete'\n | 'aria-expanded'\n | 'aria-controls'\n | 'aria-activedescendant'\n | 'aria-invalid'\n | 'aria-describedby';\n\n/** Combobox 除 toOption 外的属性;未声明的属性落到 input(主元素)上,外壳用 propsRoot */\nexport interface ComboboxBaseProps<T>\n extends PartProps<'input', ComboboxManaged>, ControlOptions, ControlIconOptions, OpenChangeProps {\n /** 数据:ListboxOption、字符串,或任意数据加 toOption;有 load 时是第一次加载之前的选项(编辑页放上已选的那一项) */\n items?: readonly T[];\n /** 选中项的值:父级写 _value={x};没有选中时是 null */\n _value?: string | null;\n /** 输入框里的文字:父级可以写 _inputValue={x}(异步搜索时据此取数据) */\n _inputValue?: string;\n /** 是否打开:父级可以写 _open={x} */\n _open?: boolean;\n /** 过滤:默认按显示文字包含输入(忽略大小写与重音);函数自定义;false 不过滤(异步搜索) */\n filter?: false | ((item: T, query: string) => boolean);\n /** 远程选项:打开时与输入停下 300 ms 后按输入调用,结果代替 items;只采用最后一次,被顶掉的请求 signal 中止 */\n load?: OptionsLoader<T>;\n /** 允许输入不在选项里的文字:失焦时保留,value 为 null */\n allowCustomValue?: boolean;\n /**\n * 显示右侧的展开按钮;只当带建议的输入框用时(Autocomplete)关掉,列表随输入出现\n * @default true\n */\n showToggle?: boolean;\n /** 没有可选的项时不弹出列表(不显示“没有匹配的选项”):只当带建议的输入框用时(Autocomplete) */\n hideEmpty?: boolean;\n /** 正在取选项(异步搜索):没有选项时列表里是骨架行,已有选项时顶部显示进度条 */\n loading?: boolean;\n /** 弹出位置,默认 bottom-start */\n placement?: FloatingPlacement;\n /** 有内容时显示清空按钮 */\n clearable?: boolean;\n /** 表单提交时的 name(用隐藏的 input 提交 value) */\n name?: string;\n /** 不可用 */\n disabled?: boolean;\n /** 只读 */\n readonly?: boolean;\n /** 必填 */\n required?: boolean;\n /** 校验未通过 */\n invalid?: boolean;\n /** 自定义选项内容:`{(item, { selected, active }) => …}`,拿到 items 里的原始数据 */\n children?: (item: T, state: OptionRenderState) => VNodeChild;\n /** 没有匹配的选项时列表里显示的内容 */\n empty?: VNodeChild;\n /** 外壳的部件属性 */\n propsRoot?: PartProps<'div'>;\n /** 清空按钮的部件属性 */\n propsClear?: Partial<PresetIconButtonProps>;\n /** 切换按钮(下拉箭头)的部件属性 */\n propsChevron?: Partial<IconButtonProps>;\n /** 弹出层的部件属性 */\n propsPopover?: PartProps<'div', 'id' | 'popover'>;\n /** 列表的部件属性 */\n propsListbox?: Partial<ListboxViewProps<T>>;\n}\n\n/** 组合框的属性;items 不是 ListboxOption 或字符串时要给 toOption */\nexport type ComboboxProps<T = ListboxOption> = ComboboxBaseProps<T> & OptionMapping<T>;\n\n/** Combobox 的样式:chevronOpen */\nexport const comboboxStyles = css.create({\n chevronOpen: { rotate: '180deg' },\n});\n\n/** 组合框:输入框 + 过滤后的选项列表 */\nexport const Combobox = _component(\n <T,>({\n items = [],\n toOption,\n _value: value = _bindable<string | null>(null),\n _inputValue: inputValue = _bindable(''),\n _open: open = _bindable(false),\n onOpenChange,\n filter,\n load,\n allowCustomValue = false,\n showToggle = true,\n hideEmpty = false,\n loading = false,\n placement = 'bottom-start',\n clearable = false,\n name,\n variant,\n size,\n radius,\n disabled,\n readonly,\n required,\n invalid,\n id,\n children,\n empty,\n propsRoot,\n icon,\n propsIcon,\n propsClear,\n propsChevron,\n propsPopover,\n propsListbox,\n ...rest\n }: ComboboxProps<T>) => {\n const lang = useLang();\n const textMatcher = useTextMatcher();\n const listId = useId();\n const appearance = useControlAppearance(() => ({ variant, size, radius }));\n const control = useFieldControl(() => ({ id, invalid, required, disabled, readonly }));\n // 用户输入的过滤词:选中、用箭头打开时清空(显示全部选项)\n let query = _state('');\n // 组件自己改 inputValue(选中后写入选项文字)时,不当作用户输入\n let writing = false;\n let shell = _state.raw<HTMLElement | null>(null);\n let input = _state.raw<HTMLInputElement | null>(null);\n let panel = _state.raw<HTMLElement | null>(null);\n const setOpen = openSetter(\n () => open,\n (next) => (open = next),\n () => onOpenChange,\n );\n\n const optionOf = (item: T) => toListboxOption(item, toOption);\n\n function matches(item: T, text: string) {\n if (!text) return true;\n return filter ? filter(item, text) : textMatcher()(optionOf(item).label, text);\n }\n\n const remote = useRemoteItems({\n load: () => load,\n query: () => query,\n open: () => open,\n items: () => items,\n });\n const list = useListState({\n // 有 load 或 filter={false} 时由服务端按输入过滤\n items: () =>\n load || filter === false\n ? remote.items()\n : remote.items().filter((item) => matches(item, query)),\n toOption: optionOf,\n selected: () => (value != null ? [value] : []),\n mode: () => 'single',\n // 再选已选的项不取消\n required: () => true,\n onChange: (next) => (value = next[0] ?? null),\n });\n\n // 已选项的文字:远程搜索换了 items 之后,仍按之前见过的文字显示\n const selectedOf = useSelectedOptions({ items: remote.items, toOption: optionOf });\n const selectedLabel = () => (value == null ? '' : selectedOf([value])[0]!.label);\n\n function setText(text: string) {\n if (inputValue === text) return;\n writing = true;\n inputValue = text;\n }\n\n useResultAnnouncement(() => ({ query, count: list.options.length }));\n\n // 用户输入(含输入法组合结束):打开并按输入过滤,高亮第一项\n watch(\n () => inputValue,\n (text) => {\n if (writing) {\n writing = false;\n return;\n }\n query = text;\n // 只在输入框聚焦时打开:父级把 inputValue 改掉(重置成空)不该弹出列表\n if (!control().readonly && document.activeElement === input) setOpen(true, 'trigger');\n list.move('first');\n },\n );\n\n // 父级改了 value,或选项后到(编辑页先拿到值、再拿到选项):输入框跟着显示它的文字;用户正在输入时不打断\n watch(\n () => [value, selectedLabel()],\n () => {\n if (query) return;\n if (!allowCustomValue || value != null) setText(selectedLabel());\n },\n { immediate: true },\n );\n\n function pick(choice: string, event?: Event) {\n value = choice;\n setText(selectedLabel());\n query = '';\n setOpen(false, 'select', event);\n }\n\n function show(event?: Event) {\n query = '';\n list.activateDefault();\n setOpen(true, 'trigger', event);\n }\n\n // 失焦:文字不是选项时恢复(或清空选择)\n function commit(event: FocusEvent) {\n setOpen(false, 'focus', event);\n if (allowCustomValue) {\n if (inputValue !== selectedLabel()) value = null;\n return;\n }\n if (!inputValue) value = null;\n else setText(selectedLabel());\n query = '';\n }\n\n function onKeydown(event: KeyboardEvent) {\n const state = control();\n if (state.disabled || state.readonly || isComposingKey(event)) return;\n if (event.key === 'Escape') {\n // 打开时交给原生 popover 关闭;关闭时清空\n if (!open && inputValue) {\n event.preventDefault();\n setText('');\n value = null;\n }\n return;\n }\n if (!open) {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n show(event);\n }\n return;\n }\n if (handleListKeydown(list, event, { homeEnd: false }, (choice) => pick(choice, event)))\n event.preventDefault();\n }\n\n // 列表是否真的弹出:hideEmpty 时没有可选的项(也不在加载)就不弹\n const shown = () =>\n open && (!hideEmpty || list.options.length > 0 || loading || remote.loading());\n\n // 弹层贴着外壳、与它同宽;焦点一直在输入框上,关闭时不用归还\n const { onToggle } = useAnchoredPopover(\n () => ({\n open: shown(),\n anchor: shell,\n panel,\n floating: { placement, matchWidth: true, fitHeight: true },\n restoreFocus: false,\n }),\n { close: (reason, event) => setOpen(false, reason, event) },\n );\n\n return () => {\n const state = control();\n const s = controlParts(appearance(), state);\n const editable = !state.disabled && !state.readonly;\n return (\n <>\n <div\n {...mergeAttrs<'div'>(s.root, propsRoot, {\n ref: _toRef(shell),\n onPointerdown: focusOnShell(() => input),\n })}\n data-state={open ? 'open' : 'closed'}\n data-invalid={state.invalid || undefined}\n data-disabled={state.disabled || undefined}\n >\n {controlIcon(s, icon, propsIcon)}\n {/* _bind 编译为 v-model:输入法组合期间不写回 */}\n <input\n {...mergeAttrs<'input'>(s.input, rest, {\n ref: _toRef(input),\n id: state.id,\n role: 'combobox',\n autocomplete: 'off',\n disabled: state.disabled,\n readonly: state.readonly,\n required: state.required,\n 'aria-autocomplete': 'list',\n 'aria-expanded': shown(),\n 'aria-controls': listId,\n 'aria-activedescendant': open ? activeOptionId(list, listId) : undefined,\n 'aria-invalid': state.invalid || undefined,\n 'aria-describedby': state.describedBy,\n onKeydown,\n onBlur: commit,\n })}\n _value={inputValue}\n />\n {clearable &&\n inputValue &&\n editable &&\n controlClear(s, propsClear, () => {\n setText('');\n value = null;\n input?.focus();\n })}\n {showToggle && (\n <IconButton\n {...mergePartProps<IconButtonProps>(\n {\n ...s.button,\n sx: [s.button.sx, disclosureStyles.icon, open && comboboxStyles.chevronOpen],\n radius: 'full',\n icon: ChevronDown,\n 'aria-label': lang.comboboxToggle,\n },\n propsChevron,\n {\n tabindex: -1,\n disabled: !editable,\n 'aria-expanded': shown(),\n 'aria-controls': listId,\n // 不让输入框失焦(失焦会提交并关闭)\n onPointerdown: (event: PointerEvent) => event.preventDefault(),\n onClick: (event: MouseEvent) => {\n if (open) setOpen(false, 'trigger', event);\n else show(event);\n input?.focus();\n },\n },\n )}\n />\n )}\n <FormValue name={name} value={value} disabled={state.disabled} />\n </div>\n <ListPopover\n panelRef={_toRef(panel)}\n onToggle={onToggle}\n size={appearance().size}\n labelledBy={state.labelledBy}\n label={rest['aria-label']}\n loading={loading || remote.loading()}\n onPick={(choice) => pick(choice)}\n listbox={{\n list,\n id: listId,\n renderOption: children,\n empty: remote.failure() ?? empty,\n }}\n propsListbox={propsListbox}\n propsPopover={propsPopover}\n />\n </>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
@@ -12,8 +12,8 @@ import { DateRangePicker } from "../date/DateRangePicker.js";
|
|
|
12
12
|
import { isRuleComplete, operatorLabel, operatorsOf, toText, valueShape } from "./condition.js";
|
|
13
13
|
import { NumberRangeField } from "./NumberRangeField.js";
|
|
14
14
|
import { TagsInput } from "./TagsInput.js";
|
|
15
|
-
import { createVNode,
|
|
16
|
-
import { _component, bindable, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
15
|
+
import { createVNode, nextTick, ref, watch } from "vue";
|
|
16
|
+
import { _component, bindable, mergeJsxProps, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
17
17
|
import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
18
18
|
import { Plus, Trash2, X } from "@lucide/icons";
|
|
19
19
|
//#region src/input/ConditionBuilder.tsx
|
|
@@ -218,8 +218,9 @@ var ConditionBuilder = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
218
218
|
const rest = restProps(_props, _ctx, true);
|
|
219
219
|
const lang = useLang();
|
|
220
220
|
let element = null;
|
|
221
|
-
|
|
222
|
-
let
|
|
221
|
+
const initial = untrack(() => value.value);
|
|
222
|
+
let emitted = JSON.stringify(initial ?? null);
|
|
223
|
+
let tree = ref(initial ? toGroup(initial) : group("all"));
|
|
223
224
|
watch(() => value.value, (next) => {
|
|
224
225
|
const key = JSON.stringify(next ?? null);
|
|
225
226
|
if (key === emitted) return;
|
|
@@ -299,33 +300,33 @@ var ConditionBuilder = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
299
300
|
label: option.label
|
|
300
301
|
}));
|
|
301
302
|
const back = (key) => options.find((option) => String(option.value) === key)?.value;
|
|
302
|
-
return shape === "list" ? createVNode(Select,
|
|
303
|
+
return shape === "list" ? createVNode(Select, mergeJsxProps(common, {
|
|
303
304
|
"items": items,
|
|
304
305
|
"selectionMode": "multiple",
|
|
305
306
|
"maxTagCount": "responsive",
|
|
306
307
|
"_value": (node.value ?? []).map(String),
|
|
307
308
|
"onUpdate:_value": (keys) => onChange(keys.map(back))
|
|
308
|
-
}), null) : createVNode(Select,
|
|
309
|
+
}), null) : createVNode(Select, mergeJsxProps(common, {
|
|
309
310
|
"items": items,
|
|
310
311
|
"_value": optionKey(node.value),
|
|
311
312
|
"onUpdate:_value": (key) => onChange(back(key))
|
|
312
313
|
}), null);
|
|
313
314
|
}
|
|
314
|
-
if (shape === "list") return createVNode(TagsInput,
|
|
315
|
+
if (shape === "list") return createVNode(TagsInput, mergeJsxProps(common, {
|
|
315
316
|
"_value": (node.value ?? []).map(String),
|
|
316
317
|
"onUpdate:_value": (list) => onChange(field.type === "number" ? list.map(Number).filter((n) => !Number.isNaN(n)) : list)
|
|
317
318
|
}), null);
|
|
318
|
-
if (field.type === "number") return shape === "range" ? createVNode(NumberRangeField,
|
|
319
|
+
if (field.type === "number") return shape === "range" ? createVNode(NumberRangeField, mergeJsxProps(common, {
|
|
319
320
|
"_value": node.value ?? [null, null],
|
|
320
321
|
"onUpdate:_value": (range) => onChange([...range])
|
|
321
|
-
}), null) : createVNode(NumberField,
|
|
322
|
+
}), null) : createVNode(NumberField, mergeJsxProps(common, {
|
|
322
323
|
"_value": node.value ?? null,
|
|
323
324
|
"onUpdate:_value": onChange
|
|
324
325
|
}), null);
|
|
325
326
|
if (field.type === "date") {
|
|
326
327
|
if (shape === "range") {
|
|
327
328
|
const [start, end] = node.value ?? [null, null];
|
|
328
|
-
return createVNode(DateRangePicker,
|
|
329
|
+
return createVNode(DateRangePicker, mergeJsxProps(common, {
|
|
329
330
|
"_value": start && end ? {
|
|
330
331
|
start,
|
|
331
332
|
end
|
|
@@ -333,12 +334,12 @@ var ConditionBuilder = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
333
334
|
"onUpdate:_value": (range) => onChange(range ? [range.start, range.end] : [null, null])
|
|
334
335
|
}), null);
|
|
335
336
|
}
|
|
336
|
-
return createVNode(DatePicker,
|
|
337
|
+
return createVNode(DatePicker, mergeJsxProps(common, {
|
|
337
338
|
"_value": node.value ?? null,
|
|
338
339
|
"onUpdate:_value": onChange
|
|
339
340
|
}), null);
|
|
340
341
|
}
|
|
341
|
-
return createVNode(TextField,
|
|
342
|
+
return createVNode(TextField, mergeJsxProps(common, {
|
|
342
343
|
"_value": node.value ?? "",
|
|
343
344
|
"onUpdate:_value": onChange
|
|
344
345
|
}), null);
|
|
@@ -426,8 +427,8 @@ var ConditionBuilder = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
426
427
|
node.children.length === 0 ? !nested && createVNode(Small, { "sx": conditionBuilderStyles.empty }, {
|
|
427
428
|
default: () => [lang.conditionEmpty],
|
|
428
429
|
$stable: true
|
|
429
|
-
}) : createVNode("div", css.attrs(conditionBuilderStyles.rows), [node.children.map((child, index) => createVNode("div",
|
|
430
|
-
createVNode("div",
|
|
430
|
+
}) : createVNode("div", css.attrs(conditionBuilderStyles.rows), [node.children.map((child, index) => createVNode("div", mergeJsxProps({ "key": child.id }, css.attrs(conditionBuilderStyles.row)), [createVNode("span", mergeJsxProps(css.attrs(conditionBuilderStyles.joiner), { "aria-hidden": "true" }), [index > 0 ? joiner : ""]), child.kind === "rule" ? renderRule(node, child, index) : renderGroup(child, depth + 1, node)]))]),
|
|
431
|
+
createVNode("div", mergeJsxProps(css.attrs(conditionBuilderStyles.actions, node.children.length === 0 && conditionBuilderStyles.actionsRoot), { "data-condition-part": "actions" }), [createVNode(Button, {
|
|
431
432
|
"variant": "ghost",
|
|
432
433
|
"size": size.value,
|
|
433
434
|
"icon": Plus,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConditionBuilder.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/input/ConditionBuilder.tsx"],"sourcesContent":["/**\n * 条件构造器:编辑 all / any / not 加比较的条件树(Condition,见 condition.ts)。每条是“字段 · 比较方式 · 值”,\n * 比较方式随字段类型、值的输入随字段类型与比较方式;组的表头选满足方式(全部、任一、都不、不全),组里还能再加组。\n *\n * const fields: ConditionField[] = [\n * { name: 'amount', label: '金额', type: 'number' },\n * { name: 'category', label: '品类', type: 'select', options: [{ value: 'steel', label: '钢材' }, …] },\n * { name: 'owner', label: '经办人', type: 'select', input: ({ value, onChange, label }) => <UserPicker … /> },\n * ];\n * let condition = _state<Condition | null>(null);\n * <ConditionBuilder fields={fields} _value={condition} aria-label=\"审批条件\" />\n *\n * 写回的是只含填完整的比较的条件:没选字段、没填值的那几条留在界面上,不进 _value;一条也没有时是 null。\n * 根总是一个组({ all }、{ any },都不满足是 { not: { any } },不全满足是 { not: { all } });\n * 传进来的单条比较、嵌套的 not 按同样的规则读成组。父级改了 _value(与上次写回的不同)时整棵重读。\n *\n * 读屏:根与每个嵌套的组是 role=\"group\",每条比较也是一组(“条件 2”),三个控件各有名称(“字段”“比较方式”“金额的值”)。\n * 加了一条之后焦点落到它的字段上;删掉之后落到组的“添加条件”上。\n * 部件:Root(div)、Group(每个组)、Rule(每条比较)。\n */\nimport { Plus, Trash2, X } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, watch, type VNodeChild } from 'vue';\nimport { Button } from '../base/Button';\nimport { IconButton } from '../base/IconButton';\nimport { Small } from '../base/Text';\nimport { useLang } from '../config/context';\nimport { t } from '../config/theme/tokens';\nimport { DatePicker } from '../date/DatePicker';\nimport { DateRangePicker } from '../date/DateRangePicker';\nimport { dataAttrs, mergeAttrs, type PartProps } from '../utils/props';\nimport type { TextSize } from '../utils/style/typography';\nimport {\n isRuleComplete,\n operatorLabel,\n toText,\n operatorsOf,\n valueShape,\n type Condition,\n type ConditionField,\n type ConditionOp,\n type ConditionRule,\n} from './condition';\nimport { NumberField } from './NumberField';\nimport { NumberRangeField } from './NumberRangeField';\nimport { Select } from './Select';\nimport { TagsInput } from './TagsInput';\nimport { TextField } from './TextField';\n\n/** 组的满足方式 */\nexport interface ConditionModes {\n /** 全部满足:{ all } */\n all: unknown;\n /** 任一满足:{ any } */\n any: unknown;\n /** 都不满足:{ not: { any } } */\n none: unknown;\n /** 不全满足:{ not: { all } } */\n notAll: unknown;\n}\n\n/** 组的满足方式 */\nexport type ConditionMode = keyof ConditionModes;\n\n/** 未声明的属性落到外层 div(role=\"group\")上:aria-label 写条件管什么 */\nexport interface ConditionBuilderProps extends PartProps<'div', 'role'> {\n /** 能参与比较的字段 */\n fields: readonly ConditionField[];\n /** 条件:父级写 _value={condition} 双向绑定;没有填完整的比较时是 null */\n _value?: Condition | null;\n /** 组最多嵌套几层,默认 2(根组里还能加一层组);1 时不能加组 */\n maxDepth?: number;\n /** 控件与按钮的字号档位,不写时继承 */\n size?: TextSize;\n /** 不可用 */\n disabled?: boolean;\n /** 每个组的部件属性 */\n propsGroup?: PartProps<'div'>;\n /** 每条比较的部件属性 */\n propsRule?: PartProps<'div'>;\n}\n\ninterface RuleNode {\n kind: 'rule';\n id: number;\n field: string | null;\n op: ConditionOp | null;\n value: unknown;\n}\n\ninterface GroupNode {\n kind: 'group';\n id: number;\n mode: ConditionMode;\n children: (RuleNode | GroupNode)[];\n}\n\nconst MODES: readonly ConditionMode[] = ['all', 'any', 'none', 'notAll'];\n\n/** ConditionBuilder 的样式:root、group、nested、header、rows、row、joiner、rule、field、op、value、range、actions、empty */\nexport const conditionBuilderStyles = css.create({\n root: { display: 'flex', flexDirection: 'column', gap: '_sm', minWidth: 0 },\n group: { display: 'flex', flexDirection: 'column', gap: '_sm', minWidth: 0 },\n // 嵌套的组:浅底加描边,和外层的条件分开\n nested: {\n flexGrow: 1,\n padding: '_sm',\n backgroundColor: '_surfaceMuted',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_borderMuted',\n borderRadius: '_md',\n },\n header: { display: 'flex', alignItems: 'center', gap: '_sm' },\n rows: { display: 'flex', flexDirection: 'column', gap: '_sm' },\n row: { display: 'flex', alignItems: 'flex-start', gap: '_sm', minWidth: 0 },\n // 连接词(且、或)一列,宽度固定:各条的字段对齐\n joiner: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-end',\n flexShrink: 0,\n width: '2em',\n // 与控件同高:连接词对着这一条的第一行\n minHeight: `max(${t.sizes.control}, ${t.sizes.minTarget})`,\n color: '_textMuted',\n },\n rule: {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'flex-start',\n gap: '_sm',\n flexGrow: 1,\n minWidth: 0,\n },\n field: { flexGrow: 1, flexShrink: 1, flexBasis: '9rem', minWidth: '7rem', maxWidth: '14rem' },\n op: { flexGrow: 0, flexShrink: 1, flexBasis: '8rem', minWidth: '6rem' },\n // grid:里面的输入框拉满这一格(多选的标签按这个宽度排)\n value: { display: 'grid', flexGrow: 2, flexShrink: 1, flexBasis: '12rem', minWidth: '8rem' },\n range: { display: 'flex', alignItems: 'center', gap: '_xs' },\n actions: {\n display: 'flex',\n flexWrap: 'wrap',\n gap: '_xs',\n paddingInlineStart: 'calc(2em + 0.5rem)',\n },\n actionsRoot: { paddingInlineStart: 0 },\n removeGroup: { marginInlineStart: 'auto' },\n empty: { color: '_textMuted' },\n});\n\nlet nextId = 0;\nconst rule = (\n field: string | null = null,\n op: ConditionOp | null = null,\n value?: unknown,\n): RuleNode => ({\n kind: 'rule',\n id: ++nextId,\n field,\n op,\n value,\n});\nconst group = (mode: ConditionMode, children: (RuleNode | GroupNode)[] = []): GroupNode => ({\n kind: 'group',\n id: ++nextId,\n mode,\n children,\n});\n\n/** 条件读成界面上的组:not 包着 any 是“都不满足”、包着 all 是“不全满足”,包着单条比较是只有它的“都不满足” */\nfunction toGroup(condition: Condition): GroupNode {\n if ('all' in condition) return group('all', condition.all.map(toNode));\n if ('any' in condition) return group('any', condition.any.map(toNode));\n if ('not' in condition) {\n const inner = condition.not;\n if ('not' in inner) return toGroup(inner.not);\n if ('any' in inner) return group('none', inner.any.map(toNode));\n if ('all' in inner) return group('notAll', inner.all.map(toNode));\n return group('none', [toNode(inner)]);\n }\n return group('all', [toNode(condition)]);\n}\n\nfunction toNode(condition: Condition): RuleNode | GroupNode {\n return 'field' in condition\n ? rule(condition.field, condition.op, condition.value)\n : toGroup(condition);\n}\n\n/** 界面上的组写回条件:只留填完整的比较,空的组去掉 */\nfunction toCondition(node: GroupNode): Condition | null {\n const list = node.children.flatMap((child): Condition[] => {\n if (child.kind === 'group') {\n const nested = toCondition(child);\n return nested ? [nested] : [];\n }\n if (!child.field || !child.op) return [];\n const item: ConditionRule =\n valueShape(child.op) === 'none'\n ? { field: child.field, op: child.op }\n : { field: child.field, op: child.op, value: child.value };\n return isRuleComplete(item) ? [item] : [];\n });\n if (list.length === 0) return null;\n switch (node.mode) {\n case 'all':\n return { all: list };\n case 'any':\n return { any: list };\n case 'none':\n return { not: { any: list } };\n case 'notAll':\n return { not: { all: list } };\n }\n}\n\n/** 换比较方式时把值换成新的形状:一个值 ↔ 一组值 ↔ 范围,尽量留住已经填的 */\nfunction reshape(value: unknown, op: ConditionOp): unknown {\n const first = Array.isArray(value) ? value.find((item) => item != null && item !== '') : value;\n switch (valueShape(op)) {\n case 'none':\n return undefined;\n case 'list':\n return Array.isArray(value)\n ? value.filter((item) => item != null)\n : first == null\n ? []\n : [first];\n case 'range':\n return Array.isArray(value) && value.length === 2 ? value : [first ?? null, null];\n case 'single':\n return first;\n }\n}\n\n/** 选项的值写成文字(Select 的值是文字),选中后再换回原来的值 */\nconst optionKey = (value: unknown) => (value == null ? null : toText(value));\n\n/** 条件构造器 */\nexport const ConditionBuilder = _component(\n ({\n fields,\n _value: value = _bindable<Condition | null>(null),\n maxDepth = 2,\n size,\n disabled = false,\n propsGroup,\n propsRule,\n ...rest\n }: ConditionBuilderProps) => {\n const lang = useLang();\n let element: HTMLElement | null = null;\n // 上次写回的值:父级改成别的才整棵重读,自己写回的不重读(没填完的那几条还要留在界面上)\n let emitted = JSON.stringify(value ?? null);\n let tree = _state<GroupNode>(value ? toGroup(value) : group('all'));\n\n watch(\n () => value,\n (next) => {\n const key = JSON.stringify(next ?? null);\n if (key === emitted) return;\n emitted = key;\n tree = next ? toGroup(next) : group('all');\n },\n );\n\n function commit() {\n const next = toCondition(tree);\n emitted = JSON.stringify(next);\n value = next;\n }\n\n const fieldOf = (name: string | null) => fields.find((field) => field.name === name);\n\n /** 渲染之后把焦点移到某个元素上(加了一条之后到它的字段,删掉之后到“添加条件”) */\n function focusLater(selector: string) {\n void nextTick(() => element?.querySelector<HTMLElement>(selector)?.focus());\n }\n\n function addRule(parent: GroupNode) {\n const added = rule();\n parent.children.push(added);\n focusLater(`[data-condition-rule=\"${added.id}\"] [data-condition-part=\"field\"]`);\n }\n\n function addGroup(parent: GroupNode) {\n const added = rule();\n parent.children.push(group('all', [added]));\n focusLater(`[data-condition-rule=\"${added.id}\"] [data-condition-part=\"field\"]`);\n }\n\n function remove(parent: GroupNode, child: RuleNode | GroupNode) {\n parent.children = parent.children.filter((item) => item !== child);\n commit();\n focusLater(`[data-condition-group=\"${parent.id}\"] > [data-condition-part=\"actions\"] button`);\n }\n\n function setField(node: RuleNode, name: string | null) {\n const field = fieldOf(name);\n node.field = name;\n const ops = field ? operatorsOf(field) : [];\n if (!node.op || !ops.includes(node.op)) node.op = ops[0] ?? null;\n // 换了字段,原来的值多半不适用:清空,是否型默认“是”\n node.value = node.op\n ? reshape(field?.type === 'boolean' ? true : undefined, node.op)\n : undefined;\n commit();\n }\n\n function setOp(node: RuleNode, op: ConditionOp) {\n node.op = op;\n node.value = reshape(node.value, op);\n commit();\n }\n\n function setValue(node: RuleNode, next: unknown) {\n node.value = next;\n commit();\n }\n\n /** 值的输入:随字段类型与比较方式 */\n function renderValue(node: RuleNode, field: ConditionField, op: ConditionOp): VNodeChild {\n const label = lang.conditionValue(field.label);\n const shape = valueShape(op);\n const onChange = (next: unknown) => setValue(node, next);\n const common = { size, disabled, 'aria-label': label };\n if (shape === 'none') return null;\n if (field.input) return field.input({ field, op, value: node.value, onChange, label });\n\n if (field.type === 'select' || field.type === 'boolean') {\n const options =\n field.type === 'boolean'\n ? [\n { value: true, label: lang.conditionTrue },\n { value: false, label: lang.conditionFalse },\n ]\n : (field.options ?? []);\n const items = options.map((option) => ({\n value: String(option.value),\n label: option.label,\n }));\n const back = (key: string | null) =>\n options.find((option) => String(option.value) === key)?.value;\n return shape === 'list' ? (\n <Select\n {...common}\n items={items}\n selectionMode=\"multiple\"\n maxTagCount=\"responsive\"\n _value={((node.value as unknown[] | undefined) ?? []).map(String)}\n onUpdate:_value={(keys) => onChange((keys as string[]).map(back))}\n />\n ) : (\n <Select\n {...common}\n items={items}\n _value={optionKey(node.value)}\n onUpdate:_value={(key) => onChange(back(key as string | null))}\n />\n );\n }\n\n if (shape === 'list') {\n return (\n <TagsInput\n {...common}\n _value={((node.value as unknown[] | undefined) ?? []).map(String)}\n onUpdate:_value={(list) =>\n onChange(\n field.type === 'number' ? list.map(Number).filter((n) => !Number.isNaN(n)) : list,\n )\n }\n />\n );\n }\n\n if (field.type === 'number') {\n return shape === 'range' ? (\n <NumberRangeField\n {...common}\n _value={(node.value as [number | null, number | null] | undefined) ?? [null, null]}\n onUpdate:_value={(range) => onChange([...range])}\n />\n ) : (\n <NumberField\n {...common}\n _value={(node.value as number | null | undefined) ?? null}\n onUpdate:_value={onChange}\n />\n );\n }\n\n if (field.type === 'date') {\n if (shape === 'range') {\n const [start, end] = (node.value as [string | null, string | null] | undefined) ?? [\n null,\n null,\n ];\n return (\n <DateRangePicker\n {...common}\n _value={start && end ? { start, end } : null}\n onUpdate:_value={(range) => onChange(range ? [range.start, range.end] : [null, null])}\n />\n );\n }\n return (\n <DatePicker\n {...common}\n _value={(node.value as string | null | undefined) ?? null}\n onUpdate:_value={onChange}\n />\n );\n }\n\n return (\n <TextField\n {...common}\n _value={(node.value as string | undefined) ?? ''}\n onUpdate:_value={onChange}\n />\n );\n }\n\n function renderRule(parent: GroupNode, node: RuleNode, index: number): VNodeChild {\n const field = fieldOf(node.field);\n const ops = field ? operatorsOf(field) : [];\n return (\n <div\n {...mergeAttrs<'div'>({ sx: conditionBuilderStyles.rule }, propsRule, {\n role: 'group',\n 'aria-label': lang.conditionRule(index + 1),\n ...dataAttrs({ 'data-condition-rule': node.id }),\n })}\n >\n <Select\n items={fields.map((item) => ({\n value: item.name,\n label: item.label,\n group: item.group,\n }))}\n _value={node.field}\n onUpdate:_value={(name) => setField(node, name as string | null)}\n searchable={fields.length > 8}\n placeholder={lang.conditionField}\n aria-label={lang.conditionField}\n size={size}\n disabled={disabled}\n propsRoot={{ sx: conditionBuilderStyles.field }}\n data-condition-part=\"field\"\n />\n <Select\n items={ops.map((op) => ({ value: op, label: operatorLabel(lang, field!.type, op) }))}\n _value={node.op}\n onUpdate:_value={(op) => op && setOp(node, op as ConditionOp)}\n aria-label={lang.conditionOperator}\n size={size}\n disabled={disabled || !field}\n propsRoot={{ sx: conditionBuilderStyles.op }}\n />\n {field && node.op && valueShape(node.op) !== 'none' && (\n <div {...css.attrs(conditionBuilderStyles.value)}>\n {renderValue(node, field, node.op)}\n </div>\n )}\n <IconButton\n icon={X}\n variant=\"ghost\"\n size={size}\n disabled={disabled}\n aria-label={lang.conditionRemoveRule}\n onClick={() => remove(parent, node)}\n />\n </div>\n );\n }\n\n function renderGroup(node: GroupNode, depth: number, parent?: GroupNode): VNodeChild {\n const nested = depth > 0;\n const joiner =\n node.mode === 'any' || node.mode === 'none' ? lang.conditionOr : lang.conditionAnd;\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [conditionBuilderStyles.group, nested && conditionBuilderStyles.nested] },\n propsGroup,\n {\n ...(nested ? { role: 'group', 'aria-label': lang.conditionGroup } : {}),\n ...dataAttrs({ 'data-condition-group': node.id }),\n },\n )}\n >\n {(node.children.length > 0 || nested) && (\n <div {...css.attrs(conditionBuilderStyles.header)}>\n <Select\n items={MODES.map((mode) => ({ value: mode, label: lang.conditionModes[mode] }))}\n _value={node.mode}\n onUpdate:_value={(mode) => {\n if (!mode) return;\n node.mode = mode as ConditionMode;\n commit();\n }}\n aria-label={lang.conditionMode}\n size={size}\n disabled={disabled}\n />\n {nested && parent && (\n <IconButton\n icon={Trash2}\n variant=\"ghost\"\n size={size}\n disabled={disabled}\n aria-label={lang.conditionRemoveGroup}\n onClick={() => remove(parent, node)}\n sx={conditionBuilderStyles.removeGroup}\n />\n )}\n </div>\n )}\n {node.children.length === 0 ? (\n !nested && <Small sx={conditionBuilderStyles.empty}>{lang.conditionEmpty}</Small>\n ) : (\n <div {...css.attrs(conditionBuilderStyles.rows)}>\n {node.children.map((child, index) => (\n <div key={child.id} {...css.attrs(conditionBuilderStyles.row)}>\n <span {...css.attrs(conditionBuilderStyles.joiner)} aria-hidden=\"true\">\n {index > 0 ? joiner : ''}\n </span>\n {child.kind === 'rule'\n ? renderRule(node, child, index)\n : renderGroup(child, depth + 1, node)}\n </div>\n ))}\n </div>\n )}\n <div\n {...css.attrs(\n conditionBuilderStyles.actions,\n node.children.length === 0 && conditionBuilderStyles.actionsRoot,\n )}\n data-condition-part=\"actions\"\n >\n <Button\n variant=\"ghost\"\n size={size}\n icon={Plus}\n disabled={disabled}\n onClick={() => addRule(node)}\n >\n {lang.conditionAddRule}\n </Button>\n {depth + 1 < maxDepth && (\n <Button\n variant=\"ghost\"\n size={size}\n icon={Plus}\n disabled={disabled}\n onClick={() => addGroup(node)}\n >\n {lang.conditionAddGroup}\n </Button>\n )}\n </div>\n </div>\n );\n }\n\n return () => (\n <div\n {...mergeAttrs<'div'>({ sx: conditionBuilderStyles.root }, rest, {\n role: 'group',\n ref: (target: unknown) => (element = target as HTMLElement | null),\n })}\n >\n {renderGroup(tree, 0)}\n </div>\n );\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ConditionBuilder.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_vtp_untrack","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/input/ConditionBuilder.tsx"],"sourcesContent":["/**\n * 条件构造器:编辑 all / any / not 加比较的条件树(Condition,见 condition.ts)。每条是“字段 · 比较方式 · 值”,\n * 比较方式随字段类型、值的输入随字段类型与比较方式;组的表头选满足方式(全部、任一、都不、不全),组里还能再加组。\n *\n * const fields: ConditionField[] = [\n * { name: 'amount', label: '金额', type: 'number' },\n * { name: 'category', label: '品类', type: 'select', options: [{ value: 'steel', label: '钢材' }, …] },\n * { name: 'owner', label: '经办人', type: 'select', input: ({ value, onChange, label }) => <UserPicker … /> },\n * ];\n * let condition = _state<Condition | null>(null);\n * <ConditionBuilder fields={fields} _value={condition} aria-label=\"审批条件\" />\n *\n * 写回的是只含填完整的比较的条件:没选字段、没填值的那几条留在界面上,不进 _value;一条也没有时是 null。\n * 根总是一个组({ all }、{ any },都不满足是 { not: { any } },不全满足是 { not: { all } });\n * 传进来的单条比较、嵌套的 not 按同样的规则读成组。父级改了 _value(与上次写回的不同)时整棵重读。\n *\n * 读屏:根与每个嵌套的组是 role=\"group\",每条比较也是一组(“条件 2”),三个控件各有名称(“字段”“比较方式”“金额的值”)。\n * 加了一条之后焦点落到它的字段上;删掉之后落到组的“添加条件”上。\n * 部件:Root(div)、Group(每个组)、Rule(每条比较)。\n */\nimport { Plus, Trash2, X } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, watch, type VNodeChild } from 'vue';\nimport { Button } from '../base/Button';\nimport { IconButton } from '../base/IconButton';\nimport { Small } from '../base/Text';\nimport { useLang } from '../config/context';\nimport { t } from '../config/theme/tokens';\nimport { DatePicker } from '../date/DatePicker';\nimport { DateRangePicker } from '../date/DateRangePicker';\nimport { dataAttrs, mergeAttrs, type PartProps } from '../utils/props';\nimport type { TextSize } from '../utils/style/typography';\nimport {\n isRuleComplete,\n operatorLabel,\n toText,\n operatorsOf,\n valueShape,\n type Condition,\n type ConditionField,\n type ConditionOp,\n type ConditionRule,\n} from './condition';\nimport { NumberField } from './NumberField';\nimport { NumberRangeField } from './NumberRangeField';\nimport { Select } from './Select';\nimport { TagsInput } from './TagsInput';\nimport { TextField } from './TextField';\n\n/** 组的满足方式 */\nexport interface ConditionModes {\n /** 全部满足:{ all } */\n all: unknown;\n /** 任一满足:{ any } */\n any: unknown;\n /** 都不满足:{ not: { any } } */\n none: unknown;\n /** 不全满足:{ not: { all } } */\n notAll: unknown;\n}\n\n/** 组的满足方式 */\nexport type ConditionMode = keyof ConditionModes;\n\n/** 未声明的属性落到外层 div(role=\"group\")上:aria-label 写条件管什么 */\nexport interface ConditionBuilderProps extends PartProps<'div', 'role'> {\n /** 能参与比较的字段 */\n fields: readonly ConditionField[];\n /** 条件:父级写 _value={condition} 双向绑定;没有填完整的比较时是 null */\n _value?: Condition | null;\n /** 组最多嵌套几层,默认 2(根组里还能加一层组);1 时不能加组 */\n maxDepth?: number;\n /** 控件与按钮的字号档位,不写时继承 */\n size?: TextSize;\n /** 不可用 */\n disabled?: boolean;\n /** 每个组的部件属性 */\n propsGroup?: PartProps<'div'>;\n /** 每条比较的部件属性 */\n propsRule?: PartProps<'div'>;\n}\n\ninterface RuleNode {\n kind: 'rule';\n id: number;\n field: string | null;\n op: ConditionOp | null;\n value: unknown;\n}\n\ninterface GroupNode {\n kind: 'group';\n id: number;\n mode: ConditionMode;\n children: (RuleNode | GroupNode)[];\n}\n\nconst MODES: readonly ConditionMode[] = ['all', 'any', 'none', 'notAll'];\n\n/** ConditionBuilder 的样式:root、group、nested、header、rows、row、joiner、rule、field、op、value、range、actions、empty */\nexport const conditionBuilderStyles = css.create({\n root: { display: 'flex', flexDirection: 'column', gap: '_sm', minWidth: 0 },\n group: { display: 'flex', flexDirection: 'column', gap: '_sm', minWidth: 0 },\n // 嵌套的组:浅底加描边,和外层的条件分开\n nested: {\n flexGrow: 1,\n padding: '_sm',\n backgroundColor: '_surfaceMuted',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_borderMuted',\n borderRadius: '_md',\n },\n header: { display: 'flex', alignItems: 'center', gap: '_sm' },\n rows: { display: 'flex', flexDirection: 'column', gap: '_sm' },\n row: { display: 'flex', alignItems: 'flex-start', gap: '_sm', minWidth: 0 },\n // 连接词(且、或)一列,宽度固定:各条的字段对齐\n joiner: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-end',\n flexShrink: 0,\n width: '2em',\n // 与控件同高:连接词对着这一条的第一行\n minHeight: `max(${t.sizes.control}, ${t.sizes.minTarget})`,\n color: '_textMuted',\n },\n rule: {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'flex-start',\n gap: '_sm',\n flexGrow: 1,\n minWidth: 0,\n },\n field: { flexGrow: 1, flexShrink: 1, flexBasis: '9rem', minWidth: '7rem', maxWidth: '14rem' },\n op: { flexGrow: 0, flexShrink: 1, flexBasis: '8rem', minWidth: '6rem' },\n // grid:里面的输入框拉满这一格(多选的标签按这个宽度排)\n value: { display: 'grid', flexGrow: 2, flexShrink: 1, flexBasis: '12rem', minWidth: '8rem' },\n range: { display: 'flex', alignItems: 'center', gap: '_xs' },\n actions: {\n display: 'flex',\n flexWrap: 'wrap',\n gap: '_xs',\n paddingInlineStart: 'calc(2em + 0.5rem)',\n },\n actionsRoot: { paddingInlineStart: 0 },\n removeGroup: { marginInlineStart: 'auto' },\n empty: { color: '_textMuted' },\n});\n\nlet nextId = 0;\nconst rule = (\n field: string | null = null,\n op: ConditionOp | null = null,\n value?: unknown,\n): RuleNode => ({\n kind: 'rule',\n id: ++nextId,\n field,\n op,\n value,\n});\nconst group = (mode: ConditionMode, children: (RuleNode | GroupNode)[] = []): GroupNode => ({\n kind: 'group',\n id: ++nextId,\n mode,\n children,\n});\n\n/** 条件读成界面上的组:not 包着 any 是“都不满足”、包着 all 是“不全满足”,包着单条比较是只有它的“都不满足” */\nfunction toGroup(condition: Condition): GroupNode {\n if ('all' in condition) return group('all', condition.all.map(toNode));\n if ('any' in condition) return group('any', condition.any.map(toNode));\n if ('not' in condition) {\n const inner = condition.not;\n if ('not' in inner) return toGroup(inner.not);\n if ('any' in inner) return group('none', inner.any.map(toNode));\n if ('all' in inner) return group('notAll', inner.all.map(toNode));\n return group('none', [toNode(inner)]);\n }\n return group('all', [toNode(condition)]);\n}\n\nfunction toNode(condition: Condition): RuleNode | GroupNode {\n return 'field' in condition\n ? rule(condition.field, condition.op, condition.value)\n : toGroup(condition);\n}\n\n/** 界面上的组写回条件:只留填完整的比较,空的组去掉 */\nfunction toCondition(node: GroupNode): Condition | null {\n const list = node.children.flatMap((child): Condition[] => {\n if (child.kind === 'group') {\n const nested = toCondition(child);\n return nested ? [nested] : [];\n }\n if (!child.field || !child.op) return [];\n const item: ConditionRule =\n valueShape(child.op) === 'none'\n ? { field: child.field, op: child.op }\n : { field: child.field, op: child.op, value: child.value };\n return isRuleComplete(item) ? [item] : [];\n });\n if (list.length === 0) return null;\n switch (node.mode) {\n case 'all':\n return { all: list };\n case 'any':\n return { any: list };\n case 'none':\n return { not: { any: list } };\n case 'notAll':\n return { not: { all: list } };\n }\n}\n\n/** 换比较方式时把值换成新的形状:一个值 ↔ 一组值 ↔ 范围,尽量留住已经填的 */\nfunction reshape(value: unknown, op: ConditionOp): unknown {\n const first = Array.isArray(value) ? value.find((item) => item != null && item !== '') : value;\n switch (valueShape(op)) {\n case 'none':\n return undefined;\n case 'list':\n return Array.isArray(value)\n ? value.filter((item) => item != null)\n : first == null\n ? []\n : [first];\n case 'range':\n return Array.isArray(value) && value.length === 2 ? value : [first ?? null, null];\n case 'single':\n return first;\n }\n}\n\n/** 选项的值写成文字(Select 的值是文字),选中后再换回原来的值 */\nconst optionKey = (value: unknown) => (value == null ? null : toText(value));\n\n/** 条件构造器 */\nexport const ConditionBuilder = _component(\n ({\n fields,\n _value: value = _bindable<Condition | null>(null),\n maxDepth = 2,\n size,\n disabled = false,\n propsGroup,\n propsRule,\n ...rest\n }: ConditionBuilderProps) => {\n const lang = useLang();\n let element: HTMLElement | null = null;\n // 初始值只取一次,之后由下面的 watch 跟随父级\n const initial = _untrack(value);\n // 上次写回的值:父级改成别的才整棵重读,自己写回的不重读(没填完的那几条还要留在界面上)\n let emitted = JSON.stringify(initial ?? null);\n let tree = _state<GroupNode>(initial ? toGroup(initial) : group('all'));\n\n watch(\n () => value,\n (next) => {\n const key = JSON.stringify(next ?? null);\n if (key === emitted) return;\n emitted = key;\n tree = next ? toGroup(next) : group('all');\n },\n );\n\n function commit() {\n const next = toCondition(tree);\n emitted = JSON.stringify(next);\n value = next;\n }\n\n const fieldOf = (name: string | null) => fields.find((field) => field.name === name);\n\n /** 渲染之后把焦点移到某个元素上(加了一条之后到它的字段,删掉之后到“添加条件”) */\n function focusLater(selector: string) {\n void nextTick(() => element?.querySelector<HTMLElement>(selector)?.focus());\n }\n\n function addRule(parent: GroupNode) {\n const added = rule();\n parent.children.push(added);\n focusLater(`[data-condition-rule=\"${added.id}\"] [data-condition-part=\"field\"]`);\n }\n\n function addGroup(parent: GroupNode) {\n const added = rule();\n parent.children.push(group('all', [added]));\n focusLater(`[data-condition-rule=\"${added.id}\"] [data-condition-part=\"field\"]`);\n }\n\n function remove(parent: GroupNode, child: RuleNode | GroupNode) {\n parent.children = parent.children.filter((item) => item !== child);\n commit();\n focusLater(`[data-condition-group=\"${parent.id}\"] > [data-condition-part=\"actions\"] button`);\n }\n\n function setField(node: RuleNode, name: string | null) {\n const field = fieldOf(name);\n node.field = name;\n const ops = field ? operatorsOf(field) : [];\n if (!node.op || !ops.includes(node.op)) node.op = ops[0] ?? null;\n // 换了字段,原来的值多半不适用:清空,是否型默认“是”\n node.value = node.op\n ? reshape(field?.type === 'boolean' ? true : undefined, node.op)\n : undefined;\n commit();\n }\n\n function setOp(node: RuleNode, op: ConditionOp) {\n node.op = op;\n node.value = reshape(node.value, op);\n commit();\n }\n\n function setValue(node: RuleNode, next: unknown) {\n node.value = next;\n commit();\n }\n\n /** 值的输入:随字段类型与比较方式 */\n function renderValue(node: RuleNode, field: ConditionField, op: ConditionOp): VNodeChild {\n const label = lang.conditionValue(field.label);\n const shape = valueShape(op);\n const onChange = (next: unknown) => setValue(node, next);\n const common = { size, disabled, 'aria-label': label };\n if (shape === 'none') return null;\n if (field.input) return field.input({ field, op, value: node.value, onChange, label });\n\n if (field.type === 'select' || field.type === 'boolean') {\n const options =\n field.type === 'boolean'\n ? [\n { value: true, label: lang.conditionTrue },\n { value: false, label: lang.conditionFalse },\n ]\n : (field.options ?? []);\n const items = options.map((option) => ({\n value: String(option.value),\n label: option.label,\n }));\n const back = (key: string | null) =>\n options.find((option) => String(option.value) === key)?.value;\n return shape === 'list' ? (\n <Select\n {...common}\n items={items}\n selectionMode=\"multiple\"\n maxTagCount=\"responsive\"\n _value={((node.value as unknown[] | undefined) ?? []).map(String)}\n onUpdate:_value={(keys) => onChange((keys as string[]).map(back))}\n />\n ) : (\n <Select\n {...common}\n items={items}\n _value={optionKey(node.value)}\n onUpdate:_value={(key) => onChange(back(key as string | null))}\n />\n );\n }\n\n if (shape === 'list') {\n return (\n <TagsInput\n {...common}\n _value={((node.value as unknown[] | undefined) ?? []).map(String)}\n onUpdate:_value={(list) =>\n onChange(\n field.type === 'number' ? list.map(Number).filter((n) => !Number.isNaN(n)) : list,\n )\n }\n />\n );\n }\n\n if (field.type === 'number') {\n return shape === 'range' ? (\n <NumberRangeField\n {...common}\n _value={(node.value as [number | null, number | null] | undefined) ?? [null, null]}\n onUpdate:_value={(range) => onChange([...range])}\n />\n ) : (\n <NumberField\n {...common}\n _value={(node.value as number | null | undefined) ?? null}\n onUpdate:_value={onChange}\n />\n );\n }\n\n if (field.type === 'date') {\n if (shape === 'range') {\n const [start, end] = (node.value as [string | null, string | null] | undefined) ?? [\n null,\n null,\n ];\n return (\n <DateRangePicker\n {...common}\n _value={start && end ? { start, end } : null}\n onUpdate:_value={(range) => onChange(range ? [range.start, range.end] : [null, null])}\n />\n );\n }\n return (\n <DatePicker\n {...common}\n _value={(node.value as string | null | undefined) ?? null}\n onUpdate:_value={onChange}\n />\n );\n }\n\n return (\n <TextField\n {...common}\n _value={(node.value as string | undefined) ?? ''}\n onUpdate:_value={onChange}\n />\n );\n }\n\n function renderRule(parent: GroupNode, node: RuleNode, index: number): VNodeChild {\n const field = fieldOf(node.field);\n const ops = field ? operatorsOf(field) : [];\n return (\n <div\n {...mergeAttrs<'div'>({ sx: conditionBuilderStyles.rule }, propsRule, {\n role: 'group',\n 'aria-label': lang.conditionRule(index + 1),\n ...dataAttrs({ 'data-condition-rule': node.id }),\n })}\n >\n <Select\n items={fields.map((item) => ({\n value: item.name,\n label: item.label,\n group: item.group,\n }))}\n _value={node.field}\n onUpdate:_value={(name) => setField(node, name as string | null)}\n searchable={fields.length > 8}\n placeholder={lang.conditionField}\n aria-label={lang.conditionField}\n size={size}\n disabled={disabled}\n propsRoot={{ sx: conditionBuilderStyles.field }}\n data-condition-part=\"field\"\n />\n <Select\n items={ops.map((op) => ({ value: op, label: operatorLabel(lang, field!.type, op) }))}\n _value={node.op}\n onUpdate:_value={(op) => op && setOp(node, op as ConditionOp)}\n aria-label={lang.conditionOperator}\n size={size}\n disabled={disabled || !field}\n propsRoot={{ sx: conditionBuilderStyles.op }}\n />\n {field && node.op && valueShape(node.op) !== 'none' && (\n <div {...css.attrs(conditionBuilderStyles.value)}>\n {renderValue(node, field, node.op)}\n </div>\n )}\n <IconButton\n icon={X}\n variant=\"ghost\"\n size={size}\n disabled={disabled}\n aria-label={lang.conditionRemoveRule}\n onClick={() => remove(parent, node)}\n />\n </div>\n );\n }\n\n function renderGroup(node: GroupNode, depth: number, parent?: GroupNode): VNodeChild {\n const nested = depth > 0;\n const joiner =\n node.mode === 'any' || node.mode === 'none' ? lang.conditionOr : lang.conditionAnd;\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [conditionBuilderStyles.group, nested && conditionBuilderStyles.nested] },\n propsGroup,\n {\n ...(nested ? { role: 'group', 'aria-label': lang.conditionGroup } : {}),\n ...dataAttrs({ 'data-condition-group': node.id }),\n },\n )}\n >\n {(node.children.length > 0 || nested) && (\n <div {...css.attrs(conditionBuilderStyles.header)}>\n <Select\n items={MODES.map((mode) => ({ value: mode, label: lang.conditionModes[mode] }))}\n _value={node.mode}\n onUpdate:_value={(mode) => {\n if (!mode) return;\n node.mode = mode as ConditionMode;\n commit();\n }}\n aria-label={lang.conditionMode}\n size={size}\n disabled={disabled}\n />\n {nested && parent && (\n <IconButton\n icon={Trash2}\n variant=\"ghost\"\n size={size}\n disabled={disabled}\n aria-label={lang.conditionRemoveGroup}\n onClick={() => remove(parent, node)}\n sx={conditionBuilderStyles.removeGroup}\n />\n )}\n </div>\n )}\n {node.children.length === 0 ? (\n !nested && <Small sx={conditionBuilderStyles.empty}>{lang.conditionEmpty}</Small>\n ) : (\n <div {...css.attrs(conditionBuilderStyles.rows)}>\n {node.children.map((child, index) => (\n <div key={child.id} {...css.attrs(conditionBuilderStyles.row)}>\n <span {...css.attrs(conditionBuilderStyles.joiner)} aria-hidden=\"true\">\n {index > 0 ? joiner : ''}\n </span>\n {child.kind === 'rule'\n ? renderRule(node, child, index)\n : renderGroup(child, depth + 1, node)}\n </div>\n ))}\n </div>\n )}\n <div\n {...css.attrs(\n conditionBuilderStyles.actions,\n node.children.length === 0 && conditionBuilderStyles.actionsRoot,\n )}\n data-condition-part=\"actions\"\n >\n <Button\n variant=\"ghost\"\n size={size}\n icon={Plus}\n disabled={disabled}\n onClick={() => addRule(node)}\n >\n {lang.conditionAddRule}\n </Button>\n {depth + 1 < maxDepth && (\n <Button\n variant=\"ghost\"\n size={size}\n icon={Plus}\n disabled={disabled}\n onClick={() => addGroup(node)}\n >\n {lang.conditionAddGroup}\n </Button>\n )}\n </div>\n </div>\n );\n }\n\n return () => (\n <div\n {...mergeAttrs<'div'>({ sx: conditionBuilderStyles.root }, rest, {\n role: 'group',\n ref: (target: unknown) => (element = target as HTMLElement | null),\n })}\n >\n {renderGroup(tree, 0)}\n </div>\n );\n },\n);\n"],"mappings":"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"}
|
package/dist/input/FileDrop.js
CHANGED
|
@@ -5,8 +5,8 @@ import { focusRingStyles } from "../utils/style/styles.js";
|
|
|
5
5
|
import { Icon } from "../base/Icon.js";
|
|
6
6
|
import { visuallyHiddenStyles } from "../base/VisuallyHidden.js";
|
|
7
7
|
import { useFieldControl } from "../form/Field.js";
|
|
8
|
-
import { Fragment, createVNode,
|
|
9
|
-
import { _component, childrenProp, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
8
|
+
import { Fragment, createVNode, ref } from "vue";
|
|
9
|
+
import { _component, childrenProp, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
10
10
|
import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
11
11
|
import { Upload } from "@lucide/icons";
|
|
12
12
|
//#region src/input/FileDrop.tsx
|
|
@@ -147,7 +147,7 @@ var FileDrop = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
147
147
|
};
|
|
148
148
|
return () => {
|
|
149
149
|
const field = control();
|
|
150
|
-
return createVNode("label",
|
|
150
|
+
return createVNode("label", mergeJsxProps(mergeAttrs({ sx: [
|
|
151
151
|
fileDropStyles.root,
|
|
152
152
|
focusRingStyles.hasVisible,
|
|
153
153
|
dragging.value && fileDropStyles.dragging,
|