@zerodep-dev/vue-tsx-pro-ui 0.2.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/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/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/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.js +7 -7
- 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/index.d.ts +11 -6
- package/dist/index.js +10 -5
- 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 +4 -4
- 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 +3 -3
- 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 +4 -4
- 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 +4 -4
- 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 +6 -6
- package/dist/input/TreeSelect.js.map +1 -1
- package/dist/input/Upload.js +8 -8
- package/dist/input/Upload.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 +7 -1
- package/dist/patterns/QueryTable.js +116 -81
- 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 +37 -1
- package/dist/patterns/messages.js +38 -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/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/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/http.d.ts +12 -0
- package/dist/utils/request/http.js +6 -2
- package/dist/utils/request/http.js.map +1 -1
- package/dist/utils/request/use-request.js +4 -2
- package/dist/utils/request/use-request.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Diagram.js","names":["_vtp_readonlyProp","_createVNode","_mergeProps","_vtp_childrenProp","_vtp_bindable","_vtp_restProps","_vtp_untrack","_vue_shallowRef","_vue_computed"],"sources":["../../src/diagram/Diagram.tsx"],"sourcesContent":["/**\n * 画布:在一块能平移、缩放的视口里摆放节点(HTML)与连线(SVG)。流程图、组织架构图、关系图都建在它上面:\n * 画布负责定位、视口、选择、拖动、连线与焦点;节点默认画成 DiagramNode(标题是 getNodeLabel),\n * 要别的样子时 children 给渲染函数,常见的是换 DiagramNode 的属性(说明、图标、色调、形状)。\n *\n * let selection = _state<DiagramSelection>({ nodes: [], edges: [] });\n * <Diagram nodes={nodes} edges={edges} getNodeLabel={(node) => node.name} selectable _selected={selection} fitView aria-label=\"组织架构\">\n * {(node) => <DiagramNode title={node.name} description={node.title} />}\n * </Diagram>\n *\n * - 视口(见 useDiagram):滚轮平移,按住 Ctrl / ⌘ 或触控板捏合缩放;拖动空白处平移,dragMode=\"select\" 时改为框选、\n * 按住空格再拖动才平移;视口有焦点时方向键平移、+ / − 缩放、0 回到适应内容。fitView 在第一次有尺寸时把内容放进视口。\n * - 选择(selectable):点节点或连线选中它,按住 Shift / Ctrl / ⌘ 再点加选或取消;按住 Shift 拖动空白处框选\n * (selectionMode:整个框住才算,或碰到就算),按住 Ctrl / ⌘ 时框到的加进原来的选择;点空白处、Esc 清空,\n * Ctrl / ⌘ + A 全选。_selected 双向绑定。\n * - 拖动(draggable):拖节点(选中的一起拖),snapToGrid 吸附网格,guides 与别的节点对齐时吸过去并画对齐线,\n * 拖到视口边上自动平移,Esc 取消;聚焦的节点按方向键挪一步(Shift 五步)。位置由使用方保存:松开后 onNodesMove 给出新位置。\n * - 连线(connectable):悬停或选中的节点四条边上出现端口,从端口拖到另一个节点上松开调用 onConnect;\n * 选中的连线两端出现把手,拖到别的节点上调用 onReconnect。canConnect 决定能不能连,不能连的节点不高亮。\n * - 连线的画法:points 是折线(排布、路由的结果),没给时按 routing 画:straight 是两个节点之间的直线,\n * orthogonal 是绕开节点的正交折线(routeEdges);拖动时相连的线按 routing 实时重画。终点画箭头,拐角是圆角;\n * 连线的 tone 改线与文字的颜色(退回、驳回用 danger),dashed 画虚线。backdrop 里放泳道 DiagramLanes。\n * - 键盘:节点(可选择时连线也是)按数组顺序用 Tab 聚焦,Enter / 空格选中;键盘聚焦到视口外的节点时自动平移过去。\n * 拖动、连线都有不用指针的做法:方向键挪节点,连线交给设计器的属性面板(WCAG 2.5.7)。\n * - overlay 里的内容(DiagramControls、DiagramMinimap、图例)浮在最上面、不随视口动,经 DiagramContext 拿到控制器。\n * 部件:Root(视口)、World(随视口平移缩放的一层)、Node(节点框)、Port(端口)、Edge(每条连线的 g)、EdgeText(连线上的文字)、\n * Marquee(框选框)、Guide(对齐线)。\n */\nimport { _component, createContext } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { useMessages } from '../config/lang/messages';\nimport { t } from '../config/theme/tokens';\nimport { startMove } from '../utils/dom/move';\nimport { useResizeObserver } from '../utils/dom/resize';\nimport { dataAttrs, mergeAttrs, type PartProps } from '../utils/props';\nimport { interactionTransitions } from '../utils/style/transitions';\nimport type { StatusTone } from '../utils/style/tone-styles';\nimport { diagramInternals, useDiagram, type DiagramController } from './controller';\nimport { DiagramNode } from './DiagramNode';\nimport {\n alignToGuides,\n arrowHead,\n boundsOf,\n polylineMidpoint,\n polylinePath,\n rectAt,\n rectContains,\n rectFromCorners,\n rectsIntersect,\n trimEnd,\n type DiagramGuide,\n type DiagramPoint,\n type DiagramRect,\n} from './geometry';\nimport { diagramMessages } from './messages';\nimport { nearestSide, routeEdges, sidePoint, straightRoute, type DiagramSide } from './route';\n\n/** 画布上的一个节点:位置与大小(画布坐标),其余字段使用方自己用 */\nexport interface DiagramNodeItem extends DiagramRect {\n /** 节点的标识:连线的 from、to 与选择里用它 */\n id: string;\n}\n\n/** 画布上的一条连线 */\nexport interface DiagramEdgeItem {\n /** 连线的标识 */\n id: string;\n /** 起点节点 */\n from: string;\n /** 终点节点 */\n to: string;\n /** 折线经过的点(画布坐标,含两端);不给时按 routing 画 */\n points?: readonly DiagramPoint[];\n /** 从起点的哪条边出去(routing=\"orthogonal\" 时用);不写时自动选 */\n fromSide?: DiagramSide;\n /** 从终点的哪条边进来;不写时自动选 */\n toSide?: DiagramSide;\n /** 连线文字的位置;不给时放在折线走到一半的地方 */\n labelAt?: DiagramPoint;\n /** 色调:线、箭头与连线文字的颜色(退回、驳回用 danger,走过的路径用 success),默认中性的灰 */\n tone?: StatusTone;\n /** 画成虚线:可选的、还没生效的连线 */\n dashed?: boolean;\n}\n\n/** 选中的节点与连线(标识) */\nexport interface DiagramSelection {\n /** 选中的节点 */\n readonly nodes: readonly string[];\n /** 选中的连线 */\n readonly edges: readonly string[];\n}\n\n/** 节点、连线渲染时的状态 */\nexport interface DiagramItemState {\n /** 已选中 */\n readonly selected: boolean;\n}\n\n/** 拖动结束后一个节点的新位置 */\nexport interface DiagramNodeMove {\n /** 节点的标识 */\n readonly id: string;\n /** 新的横坐标 */\n readonly x: number;\n /** 新的纵坐标 */\n readonly y: number;\n}\n\n/** 从端口拖出的一条新连线 */\nexport interface DiagramConnection {\n /** 起点节点 */\n readonly from: string;\n /** 终点节点 */\n readonly to: string;\n /** 从起点的哪条边出去 */\n readonly fromSide: DiagramSide;\n /** 从终点的哪条边进来(松开时离指针最近的边) */\n readonly toSide: DiagramSide;\n}\n\n/** 拖动连线的一端改接到别的节点 */\nexport interface DiagramReconnection {\n /** 连线的标识 */\n readonly edge: string;\n /** 改的是哪一端 */\n readonly end: 'from' | 'to';\n /** 改接到的节点 */\n readonly node: string;\n /** 从这个节点的哪条边进出 */\n readonly side: DiagramSide;\n}\n\n/** 拖动空白处做什么 */\nexport interface DiagramDragModes {\n /** 平移视口;按住 Shift 拖动是框选(看图为主:流程图、组织架构图) */\n pan: unknown;\n /** 框选;按住空格拖动、滚轮平移(编辑为主:设计器) */\n select: unknown;\n}\n\n/** 框选时怎样算选中 */\nexport interface DiagramSelectionModes {\n /** 整个在框里才选中 */\n full: unknown;\n /** 碰到框就选中 */\n partial: unknown;\n}\n\n/** 背景的网格 */\nexport interface DiagramGrids {\n /** 不画 */\n none: unknown;\n /** 点阵(设计器) */\n dots: unknown;\n /** 线格 */\n lines: unknown;\n}\n\n/** 没给折线的连线怎样画 */\nexport interface DiagramRoutings {\n /** 两个节点之间的直线,两端落在边框上 */\n straight: unknown;\n /** 绕开节点的正交折线(横竖两个方向,拐弯少,同一条边上的几条线排开) */\n orthogonal: unknown;\n}\n\n/** 未声明的属性落到视口(Root)上:aria-label 写画布画的是什么 */\nexport interface DiagramProps<\n N extends DiagramNodeItem,\n E extends DiagramEdgeItem,\n> extends PartProps<'div', 'role' | 'tabindex' | 'draggable'> {\n /** 节点:位置与大小由使用方给(排布的结果或用户摆的位置) */\n nodes: readonly N[];\n /** 连线 */\n edges?: readonly E[];\n /** 节点的内容:节点框(定位、选中、焦点)由画布画,里面画什么由这里给,内容拉伸到节点的大小。默认是标题为 getNodeLabel 的 DiagramNode */\n children?: (node: N, state: DiagramItemState) => VNodeChild;\n /** 节点的无障碍名称(读屏念的;连线的默认名称“从 A 到 B”也用它)。节点里画了文字时按同样的先后写进来(如“姓名,岗位”),语音控制才能按看得见的字找到它 */\n getNodeLabel: (node: N) => string;\n /** 连线的无障碍名称,默认“从 A 到 B” */\n getEdgeLabel?: (edge: E) => string;\n /** 连线上的文字(处理结果、条件);返回空时不画 */\n edgeText?: (edge: E, state: DiagramItemState) => VNodeChild;\n /**\n * 视口的高(数字是 px)\n * @default 360\n */\n height?: number | string;\n /** 控制器(useDiagram):画布外的按钮要缩放、适应内容时传进来;不传时画布自己建一个 */\n controller?: DiagramController;\n /** 节点与连线可以点选、框选 */\n selectable?: boolean;\n /** 选中的节点与连线:父级写 _selected={selection} 双向绑定 */\n _selected?: DiagramSelection;\n /** 拖动空白处做什么,默认 pan */\n dragMode?: keyof DiagramDragModes;\n /** 框选时怎样算选中,默认 full */\n selectionMode?: keyof DiagramSelectionModes;\n /** 背景的网格,默认 none */\n grid?: keyof DiagramGrids;\n /** 网格的间距(画布坐标),默认 20;snapToGrid 也按它吸附 */\n gridSize?: number;\n /** 第一次有尺寸时把全部内容放进视口(不超过原大);用户动过视口之前,尺寸变了也重新适应。默认 false:从原点、原大开始 */\n fitView?: boolean;\n /** 内容的范围(画布坐标):适应画布按它算。默认包住全部节点与连线;backdrop 比节点占得大时(泳道)写上它 */\n extent?: DiagramRect;\n /** 没给折线的连线怎样画,默认 straight;拖动时相连的线也按它重画 */\n routing?: keyof DiagramRoutings;\n /** 折线拐角的圆角半径,默认 6;0 为直角 */\n edgeRadius?: number;\n /** 节点可以拖动(可以按节点判断);松开后 onNodesMove 给出新位置 */\n draggable?: boolean | ((node: N) => boolean);\n /** 拖动、方向键挪动时吸附到网格(gridSize) */\n snapToGrid?: boolean;\n /** 拖动时与别的节点的边、中线对齐就吸过去并画对齐线,默认 true */\n guides?: boolean;\n /** 拖动或方向键挪动后节点的新位置:使用方写回自己的数据(顺带记一步撤销) */\n onNodesMove?: (moves: DiagramNodeMove[]) => void;\n /** 能从节点的端口拖出连线;选中的连线两端可以拖去改接 */\n connectable?: boolean;\n /** 能不能从 from 连到 to(拖动时只高亮能连的节点);默认除了自己都能连 */\n canConnect?: (from: N, to: N) => boolean;\n /** 从端口拖出连线、在另一个节点上松开 */\n onConnect?: (connection: DiagramConnection) => void;\n /** 拖动选中连线的一端、在别的节点上松开 */\n onReconnect?: (change: DiagramReconnection) => void;\n /** 画在连线下面、随视口平移缩放的内容(画布坐标的 HTML):泳道、分区、背景标注 */\n backdrop?: VNodeChild;\n /** 浮在最上面、不随视口动的内容(视口坐标):缩放按钮 DiagramControls、小地图 DiagramMinimap、图例 */\n overlay?: VNodeChild;\n /** 随视口平移缩放的那一层的部件属性 */\n propsWorld?: PartProps<'div'>;\n /** 节点框的部件属性,可以按节点计算 */\n propsNode?: PartProps<'div'> | ((node: N, state: DiagramItemState) => PartProps<'div'>);\n /** 端口的部件属性 */\n propsPort?: PartProps<'span'>;\n /** 连线(g)的部件属性,可以按连线计算(颜色、虚线用连线的 tone、dashed) */\n propsEdge?: PartProps<'g'> | ((edge: E, state: DiagramItemState) => PartProps<'g'>);\n /** 连线文字的部件属性,可以按连线计算 */\n propsEdgeText?: PartProps<'div'> | ((edge: E, state: DiagramItemState) => PartProps<'div'>);\n /** 框选框的部件属性 */\n propsMarquee?: PartProps<'div'>;\n /** 对齐线的部件属性 */\n propsGuide?: PartProps<'line'>;\n}\n\n/** 画布里的部件(DiagramControls、DiagramMinimap)取控制器 */\nexport const DiagramContext = createContext<DiagramController>('Diagram');\n\n/** 箭头的长度(画布坐标) */\nconst ARROW = 9;\n/** 网格的间距在屏幕上小于这么多 px 时放大四倍,缩得很小时不糊成一片 */\nconst MIN_GRID = 8;\n/** 对齐线吸附的距离(屏幕 px) */\nconst GUIDE_TOLERANCE = 6;\n/** 拖到离视口边多近开始自动平移(px) */\nconst EDGE_PAN = 32;\n/** 没吸附网格时方向键一次挪多少(画布坐标) */\nconst NUDGE = 8;\nconst NO_SELECTION: DiagramSelection = { nodes: [], edges: [] };\nconst SIDES: readonly DiagramSide[] = ['top', 'right', 'bottom', 'left'];\n\n/** Diagram 的样式 */\nexport const diagramStyles = css.create({\n root: {\n position: 'relative',\n overflow: 'hidden',\n backgroundColor: '_surface',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_border',\n borderRadius: '_md',\n fontSize: '_sm',\n color: '_text',\n // 画布上点选、框选、按着 Shift 加选时不选中文字(节点里要能选中复制的内容自己写 userSelect: 'text')\n userSelect: 'none',\n cursor: { default: 'grab', ':active': 'grabbing' },\n outlineStyle: { default: 'none', ':focus-visible': 'solid' },\n outlineWidth: '_sm',\n outlineColor: '_focusRing',\n outlineOffset: '_borderWidths.sm',\n },\n rootSelect: { cursor: 'default' },\n world: {\n position: 'absolute',\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n transformOrigin: '0 0',\n // 画布坐标与方向无关:从右到左的页面里节点的位置不镜像,节点里的文字照常跟随页面\n direction: 'ltr',\n },\n edges: {\n position: 'absolute',\n left: 0,\n top: 0,\n zIndex: 1,\n overflow: 'visible',\n pointerEvents: 'none',\n },\n // 对齐线、拖出来的连线、改接把手:画在节点上面,除了把手都不挡指针\n above: { zIndex: 3 },\n edge: {\n color: { default: '_borderStrong', _pressed: '_accent', ':focus-visible': '_accent' },\n strokeWidth: { default: 1.5, _pressed: 2.5, ':focus-visible': 2.5 },\n outlineStyle: 'none',\n },\n edgeSelectable: {\n cursor: 'pointer',\n // :hover 的优先级高过 aria-pressed:悬停在选中的线上时还要是强调色\n color: {\n default: '_borderStrong',\n ':hover': { default: '_textMuted', _pressed: '_accent' },\n _pressed: '_accent',\n ':focus-visible': '_accent',\n },\n },\n edgeDashed: { strokeDasharray: '6 4' },\n edgeLine: {\n fill: 'none',\n stroke: 'currentColor',\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n },\n edgeArrow: { fill: 'currentColor', stroke: 'none' },\n // 加粗的透明命中区域:细线也好点中\n edgeHit: { fill: 'none', stroke: 'transparent', strokeWidth: 14, pointerEvents: 'stroke' },\n edgeEnd: {\n fill: '_surface',\n stroke: '_accent',\n strokeWidth: 2,\n cursor: 'crosshair',\n pointerEvents: 'all',\n },\n preview: {\n color: '_accent',\n strokeWidth: 2,\n strokeDasharray: '6 4',\n },\n guide: { stroke: '_accent', strokeWidth: 1, strokeDasharray: '4 3' },\n edgeText: {\n position: 'absolute',\n left: 0,\n top: 0,\n zIndex: 1,\n paddingInline: '4px',\n borderRadius: '_sm',\n fontSize: '0.85em',\n lineHeight: '_tight',\n whiteSpace: 'nowrap',\n color: '_textMuted',\n backgroundColor: '_surface',\n pointerEvents: 'none',\n },\n node: {\n position: 'absolute',\n left: 0,\n top: 0,\n zIndex: 2,\n display: 'grid',\n boxSizing: 'border-box',\n // 选中、焦点的描边跟着节点的形状走(DiagramNode 的 shape)\n borderRadius: { default: '_md', ':has(> [data-diagram-shape=\"pill\"])': '_full' },\n outlineStyle: {\n default: 'none',\n _pressed: 'solid',\n ':focus-visible': 'solid',\n '[data-link-target]': 'dashed',\n },\n outlineWidth: '2px',\n outlineColor: { default: '_accent', ':focus-visible': '_focusRing' },\n outlineOffset: '3px',\n },\n nodeSelectable: { cursor: 'pointer' },\n nodeDraggable: { cursor: { default: 'grab', ':active': 'grabbing' } },\n nodeDragging: { cursor: 'grabbing', opacity: 0.9 },\n port: {\n position: 'absolute',\n width: '10px',\n height: '10px',\n boxSizing: 'border-box',\n borderRadius: '_full',\n borderWidth: '2px',\n borderStyle: 'solid',\n borderColor: '_accent',\n backgroundColor: '_surface',\n cursor: 'crosshair',\n transform: { default: 'translate(-50%, -50%)', ':hover': 'translate(-50%, -50%) scale(1.3)' },\n transition: `transform ${t.durations.sm} ${t.easings.standard}`,\n },\n portTop: { left: '50%', top: 0 },\n portRight: { left: '100%', top: '50%' },\n portBottom: { left: '50%', top: '100%' },\n portLeft: { left: 0, top: '50%' },\n marquee: {\n position: 'absolute',\n left: 0,\n top: 0,\n zIndex: 3,\n pointerEvents: 'none',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_accent',\n borderRadius: '_xs',\n backgroundColor: `color-mix(in srgb, ${t.colors.accent} 10%, transparent)`,\n },\n overlay: { position: 'absolute', inset: 0, zIndex: 4, pointerEvents: 'none' },\n});\n\n/** 有色调的连线:选中、焦点时照样是强调色 */\nconst toned = (color: string) => ({\n color: { default: color, _pressed: '_accent', ':focus-visible': '_accent' },\n});\n\n/** 连线的色调(neutral 用默认的灰) */\nconst edgeToneStyles = css.create({\n neutral: {},\n accent: toned('_accent'),\n info: toned('_infoText'),\n success: toned('_successText'),\n warning: toned('_warningText'),\n danger: toned('_dangerText'),\n});\n\n/** 连线文字的色调 */\nconst edgeTextToneStyles = css.create({\n neutral: {},\n accent: { color: '_accentText' },\n info: { color: '_infoText' },\n success: { color: '_successText' },\n warning: { color: '_warningText' },\n danger: { color: '_dangerText' },\n});\n\nconst portStyles: Record<DiagramSide, typeof diagramStyles.portTop> = {\n top: diagramStyles.portTop,\n right: diagramStyles.portRight,\n bottom: diagramStyles.portBottom,\n left: diagramStyles.portLeft,\n};\n\n/** 网格的图案:点阵、线格 */\nconst gridImages: Record<keyof DiagramGrids, string> = {\n none: 'none',\n dots: `radial-gradient(circle, ${t.colors.borderStrong} 1px, transparent 1.5px)`,\n lines: `linear-gradient(${t.colors.borderMuted} 1px, transparent 1px), linear-gradient(90deg, ${t.colors.borderMuted} 1px, transparent 1px)`,\n};\n\n/** 随视口变的样式:平移缩放、网格、节点与文字的位置(值变化只改元素上的变量,画布不重新渲染) */\nexport const diagramDynamicStyles = css.create({\n world: (x: number, y: number, scale: number) => ({\n transform: `translate(${x}px, ${y}px) scale(${scale})`,\n }),\n grid: (kind: keyof DiagramGrids, x: number, y: number, scale: number, gridSize: number) => {\n const step = gridSize * scale < MIN_GRID ? gridSize * scale * 4 : gridSize * scale;\n return {\n backgroundImage: gridImages[kind],\n backgroundSize: `${step}px ${step}px`,\n backgroundPosition: `${x}px ${y}px`,\n };\n },\n box: (x: number, y: number, width: number, height: number) => ({\n transform: `translate(${x}px, ${y}px)`,\n width,\n height,\n }),\n at: (x: number, y: number) => ({ transform: `translate(${x}px, ${y}px) translate(-50%, -50%)` }),\n height: (height: number | string) => ({ height }),\n});\n\n/** 部件属性可以是对象,也可以按节点、连线计算 */\nfunction partOf<T, A extends unknown[]>(part: T | ((...args: A) => T) | undefined, ...args: A) {\n return typeof part === 'function' ? (part as (...args: A) => T)(...args) : part;\n}\n\n/** 按着加选键:Shift、Ctrl、⌘ */\nconst toggles = (event: MouseEvent | KeyboardEvent) =>\n event.shiftKey || event.ctrlKey || event.metaKey;\n\n/** 方向键 → 挪动的方向 */\nconst ARROWS: Record<string, readonly [number, number]> = {\n ArrowLeft: [-1, 0],\n ArrowRight: [1, 0],\n ArrowUp: [0, -1],\n ArrowDown: [0, 1],\n};\n\n/** 一条连线画出来的折线 */\ninterface Route<E> {\n edge: E;\n points: readonly DiagramPoint[];\n}\n\n/** 拖动中的节点:哪些在动、挪了多少、要画的对齐线 */\ninterface DragState {\n ids: ReadonlySet<string>;\n dx: number;\n dy: number;\n guides: DiagramGuide[];\n}\n\n/** 正在拖的连线:从哪一点到哪一点,指针下能连的节点 */\ninterface LinkState {\n from: DiagramPoint;\n to: DiagramPoint;\n target: string | null;\n}\n\n/**\n * 节点、连线视图收到的事件处理:画布在 setup 里建一次,传给每个视图的都是同一个对象,\n * 视图的 props 不因事件处理重新生成而变化(拖动、悬停时只有变了的节点与连线重新渲染)\n */\ninterface ItemActions {\n nodeDown(id: string, event: PointerEvent): void;\n nodeClick(id: string, event: MouseEvent): void;\n nodeKey(id: string, event: KeyboardEvent): void;\n nodeEnter(id: string): void;\n nodeLeave(id: string): void;\n portDown(id: string, side: DiagramSide, event: PointerEvent): void;\n edgeClick(id: string, event: MouseEvent): void;\n edgeKey(id: string, event: KeyboardEvent): void;\n endDown(id: string, end: 'from' | 'to', event: PointerEvent): void;\n focus(rect: DiagramRect, event: FocusEvent): void;\n}\n\n/** 节点视图的属性:位置单独给(拖动中只有动着的节点位置变),状态都是原始值,比较时不会每次都“变了” */\ninterface NodeViewProps {\n item: DiagramNodeItem;\n x: number;\n y: number;\n label: string;\n roleDescription: string;\n selected: boolean;\n selectable: boolean;\n focusable: boolean;\n movable: boolean;\n dragging: boolean;\n ports: boolean;\n linkTarget: boolean;\n render: (node: never, state: DiagramItemState) => VNodeChild;\n part?: PartProps<'div'> | ((node: never, state: DiagramItemState) => PartProps<'div'>);\n portPart?: PartProps<'span'>;\n actions: ItemActions;\n}\n\n/** 一个节点:节点框(定位、选中、焦点、拖动)、使用方画的内容、端口 */\nconst NodeView = _component(\n ({\n item,\n x,\n y,\n label,\n roleDescription,\n selected,\n selectable,\n focusable,\n movable,\n dragging,\n ports,\n linkTarget,\n render,\n part,\n portPart,\n actions,\n }: NodeViewProps) =>\n () => {\n const state: DiagramItemState = { selected };\n const id = item.id;\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramStyles.node,\n selectable && diagramStyles.nodeSelectable,\n selectable && interactionTransitions.colors,\n movable && diagramStyles.nodeDraggable,\n dragging && diagramStyles.nodeDragging,\n diagramDynamicStyles.box(x, y, item.width, item.height),\n ],\n },\n partOf(part, item as never, state),\n {\n ...dataAttrs({\n 'data-diagram-item': 'node',\n 'data-node': id,\n 'data-link-target': linkTarget || undefined,\n }),\n 'aria-roledescription': roleDescription,\n 'aria-label': label,\n onPointerdown: (event: PointerEvent) => actions.nodeDown(id, event),\n onPointerenter: () => actions.nodeEnter(id),\n onPointerleave: () => actions.nodeLeave(id),\n ...(focusable\n ? {\n role: 'button',\n tabindex: 0,\n 'aria-pressed': selectable ? selected : undefined,\n onClick: (event: MouseEvent) => actions.nodeClick(id, event),\n onKeydown: (event: KeyboardEvent) => actions.nodeKey(id, event),\n onFocus: (event: FocusEvent) =>\n actions.focus({ x, y, width: item.width, height: item.height }, event),\n }\n : { role: 'img' }),\n },\n )}\n >\n {render(item as never, state)}\n {ports &&\n SIDES.map((side) => (\n <span\n key={side}\n {...mergeAttrs<'span'>({ sx: [diagramStyles.port, portStyles[side]] }, portPart, {\n ...dataAttrs({ 'data-diagram-port': side }),\n 'aria-hidden': 'true',\n onPointerdown: (event: PointerEvent) => actions.portDown(id, side, event),\n })}\n />\n ))}\n </div>\n );\n },\n);\n\n/** 连线视图的属性:折线的数组只在这条线真的变了时才换(不动的线一直是同一个数组) */\ninterface EdgeViewProps {\n item: DiagramEdgeItem;\n points: readonly DiagramPoint[];\n label: string;\n roleDescription: string;\n radius: number;\n selected: boolean;\n selectable: boolean;\n part?: PartProps<'g'> | ((edge: never, state: DiagramItemState) => PartProps<'g'>);\n actions: ItemActions;\n}\n\n/** 一条连线:加粗的透明命中区域、线、箭头(改接的把手画在节点上面那层,见 Diagram) */\nconst EdgeView = _component(\n ({\n item,\n points,\n label,\n roleDescription,\n radius,\n selected,\n selectable,\n part,\n actions,\n }: EdgeViewProps) =>\n () => {\n const state: DiagramItemState = { selected };\n const path = polylinePath(trimEnd(points, ARROW * 0.7), radius);\n return (\n <g\n {...mergeAttrs<'g'>(\n {\n sx: [\n diagramStyles.edge,\n selectable && diagramStyles.edgeSelectable,\n item.tone && edgeToneStyles[item.tone],\n item.dashed && diagramStyles.edgeDashed,\n ],\n },\n partOf(part, item as never, state),\n {\n ...dataAttrs({ 'data-diagram-item': 'edge', 'data-edge': item.id }),\n ...(selectable\n ? {\n role: 'button',\n tabindex: 0,\n 'aria-roledescription': roleDescription,\n 'aria-label': label,\n 'aria-pressed': selected,\n onClick: (event: MouseEvent) => actions.edgeClick(item.id, event),\n onKeydown: (event: KeyboardEvent) => actions.edgeKey(item.id, event),\n onFocus: (event: FocusEvent) => actions.focus(boundsOf([], points)!, event),\n }\n : {}),\n },\n )}\n >\n {selectable && <path d={path} {...css.attrs(diagramStyles.edgeHit)} />}\n <path d={path} {...css.attrs(diagramStyles.edgeLine)} />\n <polygon points={arrowHead(points, ARROW)} {...css.attrs(diagramStyles.edgeArrow)} />\n </g>\n );\n },\n);\n\n/** 连线文字视图的属性 */\ninterface EdgeTextViewProps {\n item: DiagramEdgeItem;\n x: number;\n y: number;\n selected: boolean;\n render: (edge: never, state: DiagramItemState) => VNodeChild;\n part?: PartProps<'div'> | ((edge: never, state: DiagramItemState) => PartProps<'div'>);\n}\n\n/** 连线上的文字(HTML,画在连线上面);渲染函数返回空时不画 */\nconst EdgeTextView = _component(\n ({ item, x, y, selected, render, part }: EdgeTextViewProps) =>\n () => {\n const state: DiagramItemState = { selected };\n const text = render(item as never, state);\n if (text == null || text === false || text === '') return null;\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramStyles.edgeText,\n item.tone && edgeTextToneStyles[item.tone],\n diagramDynamicStyles.at(x, y),\n ],\n },\n partOf(part, item as never, state),\n { 'aria-hidden': 'true' },\n )}\n >\n {text}\n </div>\n );\n },\n);\n\n/** 画布 */\nexport const Diagram = _component(\n <N extends DiagramNodeItem, E extends DiagramEdgeItem>({\n nodes,\n edges = [],\n children,\n getNodeLabel,\n getEdgeLabel,\n edgeText,\n height = 360,\n controller,\n selectable = false,\n _selected: selected = _bindable<DiagramSelection>(NO_SELECTION),\n dragMode = 'pan',\n selectionMode = 'full',\n grid = 'none',\n gridSize = 20,\n fitView = false,\n extent,\n routing = 'straight',\n edgeRadius = 6,\n draggable = false,\n snapToGrid = false,\n guides = true,\n onNodesMove,\n connectable = false,\n canConnect,\n onConnect,\n onReconnect,\n backdrop,\n overlay,\n propsWorld,\n propsNode,\n propsPort,\n propsEdge,\n propsEdgeText,\n propsMarquee,\n propsGuide,\n ...rest\n }: DiagramProps<N, E>) => {\n const messages = useMessages('diagram', diagramMessages);\n // 控制器只在创建时取:换控制器要换一个画布\n const diagram = _untrack(controller) ?? useDiagram();\n const internal = diagramInternals(diagram);\n DiagramContext.provide(diagram);\n\n // 框选框(视口坐标)、拖动中的节点、拖出来的连线、指针下的节点\n let marquee = _state.raw<DiagramRect | null>(null);\n let drag = _state.raw<DragState | null>(null);\n let link = _state.raw<LinkState | null>(null);\n let hovered = _state.raw<string | null>(null);\n // 按着空格:拖动一律平移(框选模式里平移的办法)\n let space = false;\n // 用户自己动过视口之后,尺寸变化不再自动适应\n let moved = false;\n\n /** 没给 children 时的节点:标题是无障碍名称的 DiagramNode */\n const defaultNode = (node: N) => <DiagramNode title={getNodeLabel(node)} />;\n const nodeById = _derived(new Map(nodes.map((node) => [node.id, node])));\n const draggableOf = (node: N) =>\n typeof draggable === 'function' ? draggable(node) : draggable;\n /** 节点现在的位置:拖动中的按拖到的位置 */\n const placed = (node: N): N =>\n drag?.ids.has(node.id) ? { ...node, x: node.x + drag.dx, y: node.y + drag.dy } : node;\n\n /** 不拖动时每条连线的折线:给了 points 用它,没给时按 routing 画;两端的节点缺了不画 */\n const restingRoutes = _derived.by(() => {\n const automatic = edges.filter((edge) => !hasPoints(edge));\n const routed = routing === 'orthogonal' ? routeEdges(nodes, automatic) : undefined;\n return edges.flatMap((edge): Route<E>[] => {\n if (hasPoints(edge)) return [{ edge, points: edge.points }];\n const from = nodeById.get(edge.from);\n const to = nodeById.get(edge.to);\n if (!from || !to) return [];\n return [{ edge, points: routed?.get(edge.id) ?? straightRoute(from, to) }];\n });\n });\n /** 拖动中:与动着的节点相连的线按 routing 实时重画,别的线不动 */\n const routes = _derived.by(() => {\n if (!drag) return restingRoutes;\n const moving = drag.ids;\n const touches = (edge: E) => moving.has(edge.from) || moving.has(edge.to);\n const list = nodes.map(placed);\n const byId = new Map(list.map((node) => [node.id, node]));\n const touched = edges.filter(touches);\n const routed = routing === 'orthogonal' ? routeEdges(list, touched) : undefined;\n return restingRoutes.map((route): Route<E> => {\n if (!touches(route.edge)) return route;\n const from = byId.get(route.edge.from);\n const to = byId.get(route.edge.to);\n if (!from || !to) return route;\n return { edge: route.edge, points: routed?.get(route.edge.id) ?? straightRoute(from, to) };\n });\n });\n const bounds = _derived(\n boundsOf(\n nodes,\n restingRoutes.flatMap((route) => route.points),\n ),\n );\n const selectedNodes = _derived(new Set(selected.nodes));\n const selectedEdges = _derived(new Set(selected.edges));\n\n internal.content = () => extent ?? bounds;\n internal.nodes = () => nodes.map(placed);\n const root = () => internal.element.value;\n const inOverlay = (target: EventTarget | null) =>\n target instanceof Element && target.closest('[data-diagram-overlay]') !== null;\n /** 事件发生在空白处:不在节点、连线、浮层里 */\n const onBackground = (target: EventTarget | null) =>\n target instanceof Element && !target.closest('[data-diagram-item],[data-diagram-overlay]');\n /** 这次按下要框选:可选择、在空白处、按的是主键,拖动方式是框选或按着 Shift */\n const startsMarquee = (event: PointerEvent) =>\n selectable &&\n !space &&\n event.button === 0 &&\n onBackground(event.target) &&\n (dragMode === 'select' || event.shiftKey);\n\n /** 视口(平移缩放)要不要处理这个事件;处理了就算用户动过视口 */\n function handlesViewport(event: PointerEvent | WheelEvent | MouseEvent | KeyboardEvent) {\n if (inOverlay(event.target)) return false;\n // 视口自己的按键(方向键平移、+ − 缩放)只在焦点就在视口上时生效,节点上的按键留给节点\n const handles =\n event.type === 'wheel'\n ? true\n : event.type === 'keydown'\n ? event.target === root()\n : space ||\n (onBackground(event.target) &&\n !(\n event.type === 'pointerdown' &&\n (dragMode === 'select' || (event as PointerEvent).shiftKey)\n ));\n if (handles) moved = true;\n return handles;\n }\n internal.filter = handlesViewport;\n\n // 量视口的大小(小地图用);fitView 时第一次有尺寸就适应内容,用户没动过视口时尺寸变化也重新适应\n useResizeObserver(root, () => {\n const element = root();\n if (!element) return;\n internal.size.value = { width: element.clientWidth, height: element.clientHeight };\n if (fitView && !moved && element.clientWidth > 0) diagram.fit();\n });\n\n /** 点了一项:加选键按着时切换它,否则只选它 */\n function choose(kind: 'nodes' | 'edges', id: string, toggle: boolean) {\n if (!selectable) return;\n if (!toggle) {\n selected = { nodes: kind === 'nodes' ? [id] : [], edges: kind === 'edges' ? [id] : [] };\n return;\n }\n const list = selected[kind];\n selected = {\n ...selected,\n [kind]: list.includes(id) ? list.filter((item) => item !== id) : [...list, id],\n };\n }\n\n const clear = () => {\n if (selected.nodes.length || selected.edges.length) selected = NO_SELECTION;\n };\n const selectAll = () => {\n selected = {\n nodes: nodes.map((node) => node.id),\n edges: routes.map((route) => route.edge.id),\n };\n };\n\n /**\n * 拖到视口边上时自动平移:指针停着不动也继续移,每移一帧调 onPan 让拖着的东西跟上指针\n * (拖动按指针的画布坐标算,视口挪了画布坐标就变了)\n */\n function edgePan(onPan: () => void) {\n let frame = 0;\n let speed = { x: 0, y: 0 };\n const tick = () => {\n frame = 0;\n if (!speed.x && !speed.y) return;\n internal.view.panTo(diagram.x + speed.x, diagram.y + speed.y);\n onPan();\n frame = requestAnimationFrame(tick);\n };\n return {\n follow(point: { clientX: number; clientY: number }) {\n const box = root()?.getBoundingClientRect();\n if (!box) return;\n const near = (distance: number) =>\n distance < EDGE_PAN ? Math.ceil((EDGE_PAN - distance) / 3) : 0;\n speed = {\n x: near(point.clientX - box.left) - near(box.right - point.clientX),\n y: near(point.clientY - box.top) - near(box.bottom - point.clientY),\n };\n if ((speed.x || speed.y) && !frame) frame = requestAnimationFrame(tick);\n },\n stop() {\n speed = { x: 0, y: 0 };\n if (frame) cancelAnimationFrame(frame);\n frame = 0;\n },\n };\n }\n\n /** 拖动期间按 Esc 取消:在捕获阶段拦下,不让它再去清空选择 */\n function cancelOnEscape(cancel: () => void) {\n const onKey = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopPropagation();\n cancel();\n };\n window.addEventListener('keydown', onKey, true);\n return () => window.removeEventListener('keydown', onKey, true);\n }\n\n function startMarquee(event: PointerEvent) {\n const element = root();\n if (!element || !startsMarquee(event)) return;\n const box = element.getBoundingClientRect();\n const origin = { x: event.clientX - box.left, y: event.clientY - box.top };\n const additive = event.ctrlKey || event.metaKey || (dragMode === 'select' && event.shiftKey);\n const base = additive ? selected : NO_SELECTION;\n const covers = (area: DiagramRect, rect: DiagramRect) =>\n selectionMode === 'partial' ? rectsIntersect(area, rect) : rectContains(area, rect);\n startMove(event, {\n threshold: 3,\n onMove: (point) => {\n const screen = rectFromCorners(origin, {\n x: point.clientX - box.left,\n y: point.clientY - box.top,\n });\n marquee = screen;\n const { x, y, scale } = diagram;\n const area = {\n x: (screen.x - x) / scale,\n y: (screen.y - y) / scale,\n width: screen.width / scale,\n height: screen.height / scale,\n };\n const next = {\n nodes: union(\n base.nodes,\n nodes.filter((node) => covers(area, node)).map((node) => node.id),\n ),\n edges: union(\n base.edges,\n routes\n .filter((route) => covers(area, boundsOf([], route.points)!))\n .map((route) => route.edge.id),\n ),\n };\n // 框到的没变时不写:画布只在选择真的变了才重新渲染\n if (!sameIds(next.nodes, selected.nodes) || !sameIds(next.edges, selected.edges)) {\n selected = next;\n }\n },\n onEnd: () => (marquee = null),\n });\n }\n\n /** 按在节点上:拖动它(选中的一起拖);按在节点里的输入框、按钮、端口上时不拖 */\n function startDrag(node: N, event: PointerEvent) {\n if (event.button !== 0 || space || !draggableOf(node)) return;\n const target = event.target as Element;\n if (\n target.closest(\n '[data-diagram-port],input,textarea,select,button,a,[contenteditable=\"true\"]',\n )\n ) {\n return;\n }\n const additive = toggles(event);\n const ids = selectedNodes.has(node.id)\n ? selected.nodes\n : additive\n ? [...selected.nodes, node.id]\n : [node.id];\n const moving = ids.flatMap((id) => {\n const item = nodeById.get(id);\n return item && draggableOf(item) ? [item] : [];\n });\n const others = nodes.filter((item) => !ids.includes(item.id));\n const start = diagram.toDiagram(event.clientX, event.clientY);\n let pointer = { clientX: event.clientX, clientY: event.clientY };\n let begun = false;\n let release = () => {};\n\n // 以按住的节点为准吸附网格与对齐线,算出整组挪多少\n const update = () => {\n const now = diagram.toDiagram(pointer.clientX, pointer.clientY);\n let x = node.x + now.x - start.x;\n let y = node.y + now.y - start.y;\n if (snapToGrid) {\n x = Math.round(x / gridSize) * gridSize;\n y = Math.round(y / gridSize) * gridSize;\n }\n let lines: DiagramGuide[] = [];\n if (guides) {\n const aligned = alignToGuides({ ...node, x, y }, others, GUIDE_TOLERANCE / diagram.scale);\n ({ x, y } = aligned);\n lines = aligned.guides;\n }\n drag = {\n ids: new Set(moving.map((item) => item.id)),\n dx: x - node.x,\n dy: y - node.y,\n guides: lines,\n };\n };\n const pan = edgePan(update);\n const cancel = startMove(event, {\n threshold: 3,\n onMove: (point) => {\n pointer = point;\n if (!begun) {\n begun = true;\n // 拖一个没选中的节点:选中它(按着加选键时加进原来的选择)\n if (selectable && !selectedNodes.has(node.id)) {\n selected = { nodes: ids, edges: additive ? selected.edges : [] };\n }\n release = cancelOnEscape(() => cancel());\n }\n update();\n pan.follow(point);\n },\n onEnd: ({ moved: dragged, cancelled }) => {\n pan.stop();\n release();\n const result = drag;\n drag = null;\n if (!dragged || cancelled || !result || (result.dx === 0 && result.dy === 0)) return;\n onNodesMove?.(\n moving.map((item) => ({ id: item.id, x: item.x + result.dx, y: item.y + result.dy })),\n );\n },\n });\n }\n\n /**\n * 拖一条连线:从 anchor 拉出来,松开在能连的节点上时 done(节点, 离指针最近的边)。\n * fixed 是不动的那一端的节点(连到它自己不算);fixedIsSource 时它是起点、箭头在指针一端\n */\n function startLink(\n event: PointerEvent,\n anchor: DiagramPoint,\n fixed: N,\n fixedIsSource: boolean,\n done: (target: N, side: DiagramSide) => void,\n ) {\n if (event.button !== 0) return;\n event.stopPropagation();\n event.preventDefault();\n let pointer = { clientX: event.clientX, clientY: event.clientY };\n let release = () => {};\n let landing: { node: N; side: DiagramSide } | null = null;\n const allowed = (candidate: N) =>\n candidate.id !== fixed.id &&\n (canConnect?.(fixedIsSource ? fixed : candidate, fixedIsSource ? candidate : fixed) ??\n true);\n const update = () => {\n const point = diagram.toDiagram(pointer.clientX, pointer.clientY);\n const hit = rectAt(nodes, point);\n landing = hit && allowed(hit) ? { node: hit, side: nearestSide(hit, point) } : null;\n const end = landing ? sidePoint(landing.node, landing.side) : point;\n link = {\n from: fixedIsSource ? anchor : end,\n to: fixedIsSource ? end : anchor,\n target: landing?.node.id ?? null,\n };\n };\n const pan = edgePan(update);\n update();\n const cancel = startMove(event, {\n // 端口、改接把手拖动中会消失:捕获放在画布上;松开时的 click 也落在画布上,不能当成点空白处\n captureTarget: root() ?? undefined,\n swallowClick: true,\n onMove: (point) => {\n pointer = point;\n update();\n pan.follow(point);\n },\n onEnd: ({ cancelled }) => {\n pan.stop();\n release();\n link = null;\n if (!cancelled && landing) done(landing.node, landing.side);\n },\n });\n release = cancelOnEscape(() => cancel());\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (event.key === ' ' && event.target === root()) space = true;\n if (!selectable) return;\n if (event.key === 'Escape') clear();\n if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') {\n event.preventDefault();\n selectAll();\n }\n }\n\n /** 节点上的方向键:挪动(选中的一起挪,Shift 五步) */\n function nudge(node: N, event: KeyboardEvent) {\n const arrow = ARROWS[event.key];\n if (!arrow || !onNodesMove || !draggableOf(node)) return;\n event.preventDefault();\n const step = (snapToGrid ? gridSize : NUDGE) * (event.shiftKey ? 5 : 1);\n const ids = selectedNodes.has(node.id) ? selected.nodes : [node.id];\n onNodesMove(\n ids.flatMap((id) => {\n const item = nodeById.get(id);\n return item && draggableOf(item)\n ? [{ id, x: item.x + arrow[0] * step, y: item.y + arrow[1] * step }]\n : [];\n }),\n );\n }\n\n /** Enter / 空格:选中(同点击) */\n function activates(event: KeyboardEvent) {\n if (event.key !== 'Enter' && event.key !== ' ') return false;\n event.preventDefault();\n return true;\n }\n\n const actions: ItemActions = {\n nodeDown(id, event) {\n const node = nodeById.get(id);\n if (node) startDrag(node, event);\n },\n nodeClick: (id, event) => choose('nodes', id, toggles(event)),\n nodeKey(id, event) {\n const node = nodeById.get(id);\n if (!node) return;\n if (activates(event)) choose('nodes', id, toggles(event));\n else nudge(node, event);\n },\n nodeEnter: (id) => (hovered = id),\n nodeLeave(id) {\n if (hovered === id) hovered = null;\n },\n portDown(id, side, event) {\n const node = nodeById.get(id);\n if (!node) return;\n startLink(event, sidePoint(node, side), node, true, (target, toSide) =>\n onConnect?.({ from: id, to: target.id, fromSide: side, toSide }),\n );\n },\n edgeClick: (id, event) => choose('edges', id, toggles(event)),\n edgeKey(id, event) {\n if (activates(event)) choose('edges', id, toggles(event));\n },\n endDown(id, end, event) {\n const route = routes.find((item) => item.edge.id === id);\n const from = route && nodeById.get(route.edge.from);\n const to = route && nodeById.get(route.edge.to);\n if (!route || !from || !to || !onReconnect) return;\n const { points } = route;\n // 拖的是终点:不动的是起点,箭头在指针一端;拖的是起点:反过来\n const anchor = end === 'to' ? points[0]! : points[points.length - 1]!;\n startLink(event, anchor, end === 'to' ? from : to, end === 'to', (target, side) =>\n onReconnect({ edge: id, end, node: target.id, side }),\n );\n },\n // 键盘把焦点移到视口外的节点、连线时平移过去(鼠标点到的本来就看得见)\n focus(rect, event) {\n if (event.target instanceof Element && event.target.matches(':focus-visible')) {\n diagram.reveal(rect);\n }\n },\n };\n\n return () => {\n const { view } = internal;\n const focusable = selectable || !!onNodesMove;\n // 选中的连线两端的改接把手:两端的节点都在时才能改接\n const ends =\n connectable && onReconnect && !drag && !link\n ? routes.filter(\n ({ edge }) =>\n selectedEdges.has(edge.id) && nodeById.has(edge.from) && nodeById.has(edge.to),\n )\n : [];\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramStyles.root,\n diagramDynamicStyles.height(height),\n dragMode === 'select' && diagramStyles.rootSelect,\n diagramDynamicStyles.grid(grid, diagram.x, diagram.y, diagram.scale, gridSize),\n ],\n },\n rest,\n {\n ...view.viewportProps,\n ref: (element: unknown) => (internal.element.value = element as HTMLElement | null),\n role: 'group',\n tabindex: 0,\n 'aria-roledescription': messages.canvas,\n onPointerdown: (event: PointerEvent) => {\n startMarquee(event);\n (view.viewportProps.onPointerdown as (event: PointerEvent) => void)(event);\n },\n onClick: (event: MouseEvent) => {\n if (selectable && onBackground(event.target)) clear();\n },\n onKeydown: (event: KeyboardEvent) => {\n onKeydown(event);\n (view.viewportProps.onKeydown as (event: KeyboardEvent) => void)(event);\n },\n onKeyup: (event: KeyboardEvent) => {\n if (event.key === ' ') space = false;\n },\n onBlur: () => (space = false),\n // 焦点移到视口外的节点时浏览器会滚动视口(overflow: hidden 也能被滚动),视口的位置只由平移决定\n onScroll: (event: Event) => {\n const element = event.currentTarget as HTMLElement;\n element.scrollTop = 0;\n element.scrollLeft = 0;\n },\n },\n )}\n >\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramStyles.world,\n diagramDynamicStyles.world(diagram.x, diagram.y, diagram.scale),\n ],\n },\n propsWorld,\n dataAttrs({ 'data-diagram-world': true }),\n )}\n >\n {backdrop}\n {nodes.map((node) => {\n const at = placed(node);\n const isSelected = selectedNodes.has(node.id);\n return (\n <NodeView\n key={node.id}\n item={node}\n x={at.x}\n y={at.y}\n label={getNodeLabel(node)}\n roleDescription={messages.node}\n selected={isSelected}\n selectable={selectable}\n focusable={focusable}\n movable={draggableOf(node)}\n dragging={drag?.ids.has(node.id) ?? false}\n ports={\n connectable &&\n !drag &&\n (hovered === node.id || isSelected || link?.target === node.id)\n }\n linkTarget={link?.target === node.id}\n render={(children ?? defaultNode) as NodeViewProps['render']}\n part={propsNode as NodeViewProps['part']}\n portPart={propsPort}\n actions={actions}\n />\n );\n })}\n <svg\n {...css.attrs(diagramStyles.edges)}\n width=\"1\"\n height=\"1\"\n aria-hidden={selectable ? undefined : 'true'}\n >\n {routes.map(({ edge, points }) => {\n const from = nodeById.get(edge.from);\n const to = nodeById.get(edge.to);\n const isSelected = selectedEdges.has(edge.id);\n return (\n <EdgeView\n key={edge.id}\n item={edge}\n points={points}\n label={\n getEdgeLabel?.(edge) ??\n messages.edgeBetween(\n from ? getNodeLabel(from) : edge.from,\n to ? getNodeLabel(to) : edge.to,\n )\n }\n roleDescription={messages.edge}\n radius={edgeRadius}\n selected={isSelected}\n selectable={selectable}\n part={propsEdge as EdgeViewProps['part']}\n actions={actions}\n />\n );\n })}\n </svg>\n {edgeText &&\n routes.map(({ edge, points }) => {\n const at = drag || !edge.labelAt ? polylineMidpoint(points) : edge.labelAt;\n return (\n <EdgeTextView\n key={edge.id}\n item={edge}\n x={at.x}\n y={at.y}\n selected={selectedEdges.has(edge.id)}\n render={edgeText as EdgeTextViewProps['render']}\n part={propsEdgeText as EdgeTextViewProps['part']}\n />\n );\n })}\n {(!!drag?.guides.length || !!link || ends.length > 0) && (\n <svg\n {...css.attrs(diagramStyles.edges, diagramStyles.above)}\n width=\"1\"\n height=\"1\"\n aria-hidden=\"true\"\n data-diagram-transient=\"\"\n >\n {drag?.guides.map((guide, index) => (\n <line\n key={index}\n {...mergeAttrs<'line'>({ sx: diagramStyles.guide }, propsGuide, {\n x1: guide.from.x,\n y1: guide.from.y,\n x2: guide.to.x,\n y2: guide.to.y,\n })}\n />\n ))}\n {ends.flatMap(({ edge, points }) =>\n (['from', 'to'] as const).map((end) => {\n const at = end === 'from' ? points[0]! : points[points.length - 1]!;\n return (\n <circle\n key={`${edge.id}:${end}`}\n cx={at.x}\n cy={at.y}\n r={5}\n {...css.attrs(diagramStyles.edgeEnd)}\n data-diagram-end={end}\n onPointerdown={(event: PointerEvent) =>\n actions.endDown(edge.id, end, event)\n }\n />\n );\n }),\n )}\n {link && (\n <g {...css.attrs(diagramStyles.preview)}>\n <path\n d={polylinePath(trimEnd([link.from, link.to], ARROW * 0.7))}\n {...css.attrs(diagramStyles.edgeLine)}\n />\n <polygon\n points={arrowHead([link.from, link.to], ARROW)}\n {...css.attrs(diagramStyles.edgeArrow)}\n />\n </g>\n )}\n </svg>\n )}\n </div>\n {marquee && (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramStyles.marquee,\n diagramDynamicStyles.box(marquee.x, marquee.y, marquee.width, marquee.height),\n ],\n },\n propsMarquee,\n )}\n />\n )}\n {overlay != null && (\n <div {...css.attrs(diagramStyles.overlay)} data-diagram-overlay=\"\">\n {overlay}\n </div>\n )}\n </div>\n );\n };\n },\n);\n\n/** 连线自己给了折线 */\nconst hasPoints = (\n edge: DiagramEdgeItem,\n): edge is DiagramEdgeItem & { points: readonly DiagramPoint[] } =>\n !!edge.points && edge.points.length >= 2;\n\n/** 两组标识合在一起,去掉重复 */\nconst union = (a: readonly string[], b: readonly string[]) => [...new Set([...a, ...b])];\n\n/** 两组标识是否相同(顺序无关) */\nfunction sameIds(a: readonly string[], b: readonly string[]): boolean {\n if (a.length !== b.length) return false;\n const set = new Set(a);\n return b.every((id) => set.has(id));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Diagram.js","names":["_vtp_readonlyProp","_createVNode","_mergeProps","_vtp_childrenProp","_vtp_bindable","_vtp_restProps","_vtp_untrack","_vue_shallowRef","_vue_computed"],"sources":["../../src/diagram/Diagram.tsx"],"sourcesContent":["/**\n * 画布:在一块能平移、缩放的视口里摆放节点(HTML)与连线(SVG)。流程图、组织架构图、关系图都建在它上面:\n * 画布负责定位、视口、选择、拖动、连线与焦点;节点默认画成 DiagramNode(标题是 getNodeLabel),\n * 要别的样子时 children 给渲染函数,常见的是换 DiagramNode 的属性(说明、图标、色调、形状)。\n *\n * let selection = _state<DiagramSelection>({ nodes: [], edges: [] });\n * <Diagram nodes={nodes} edges={edges} getNodeLabel={(node) => node.name} selectable _selected={selection} fitView aria-label=\"组织架构\">\n * {(node) => <DiagramNode title={node.name} description={node.title} />}\n * </Diagram>\n *\n * - 视口(见 useDiagram):滚轮平移,按住 Ctrl / ⌘ 或触控板捏合缩放;拖动空白处平移,dragMode=\"select\" 时改为框选、\n * 按住空格再拖动才平移;视口有焦点时方向键平移、+ / − 缩放、0 回到适应内容。fitView 在第一次有尺寸时把内容放进视口。\n * - 选择(selectable):点节点或连线选中它,按住 Shift / Ctrl / ⌘ 再点加选或取消;按住 Shift 拖动空白处框选\n * (selectionMode:整个框住才算,或碰到就算),按住 Ctrl / ⌘ 时框到的加进原来的选择;点空白处、Esc 清空,\n * Ctrl / ⌘ + A 全选。_selected 双向绑定。\n * - 拖动(draggable):拖节点(选中的一起拖),snapToGrid 吸附网格,guides 与别的节点对齐时吸过去并画对齐线,\n * 拖到视口边上自动平移,Esc 取消;聚焦的节点按方向键挪一步(Shift 五步)。位置由使用方保存:松开后 onNodesMove 给出新位置。\n * - 连线(connectable):悬停或选中的节点四条边上出现端口,从端口拖到另一个节点上松开调用 onConnect;\n * 选中的连线两端出现把手,拖到别的节点上调用 onReconnect。canConnect 决定能不能连,不能连的节点不高亮。\n * - 连线的画法:points 是折线(排布、路由的结果),没给时按 routing 画:straight 是两个节点之间的直线,\n * orthogonal 是绕开节点的正交折线(routeEdges);拖动时相连的线按 routing 实时重画。终点画箭头,拐角是圆角;\n * 连线的 tone 改线与文字的颜色(退回、驳回用 danger),dashed 画虚线。backdrop 里放泳道 DiagramLanes。\n * - 键盘:节点(可选择时连线也是)按数组顺序用 Tab 聚焦,Enter / 空格选中;键盘聚焦到视口外的节点时自动平移过去。\n * 拖动、连线都有不用指针的做法:方向键挪节点,连线交给设计器的属性面板(WCAG 2.5.7)。\n * - overlay 里的内容(DiagramControls、DiagramMinimap、图例)浮在最上面、不随视口动,经 DiagramContext 拿到控制器。\n * 部件:Root(视口)、World(随视口平移缩放的一层)、Node(节点框)、Port(端口)、Edge(每条连线的 g)、EdgeText(连线上的文字)、\n * Marquee(框选框)、Guide(对齐线)。\n */\nimport { _component, createContext } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { useMessages } from '../config/lang/messages';\nimport { t } from '../config/theme/tokens';\nimport { startMove } from '../utils/dom/move';\nimport { useResizeObserver } from '../utils/dom/resize';\nimport { dataAttrs, mergeAttrs, type PartProps } from '../utils/props';\nimport { interactionTransitions } from '../utils/style/transitions';\nimport type { StatusTone } from '../utils/style/tone-styles';\nimport { diagramInternals, useDiagram, type DiagramController } from './controller';\nimport { DiagramNode } from './DiagramNode';\nimport {\n alignToGuides,\n arrowHead,\n boundsOf,\n polylineMidpoint,\n polylinePath,\n rectAt,\n rectContains,\n rectFromCorners,\n rectsIntersect,\n trimEnd,\n type DiagramGuide,\n type DiagramPoint,\n type DiagramRect,\n} from './geometry';\nimport { diagramMessages } from './messages';\nimport { nearestSide, routeEdges, sidePoint, straightRoute, type DiagramSide } from './route';\n\n/** 画布上的一个节点:位置与大小(画布坐标),其余字段使用方自己用 */\nexport interface DiagramNodeItem extends DiagramRect {\n /** 节点的标识:连线的 from、to 与选择里用它 */\n id: string;\n}\n\n/** 画布上的一条连线 */\nexport interface DiagramEdgeItem {\n /** 连线的标识 */\n id: string;\n /** 起点节点 */\n from: string;\n /** 终点节点 */\n to: string;\n /** 折线经过的点(画布坐标,含两端);不给时按 routing 画 */\n points?: readonly DiagramPoint[];\n /** 从起点的哪条边出去(routing=\"orthogonal\" 时用);不写时自动选 */\n fromSide?: DiagramSide;\n /** 从终点的哪条边进来;不写时自动选 */\n toSide?: DiagramSide;\n /** 连线文字的位置;不给时放在折线走到一半的地方 */\n labelAt?: DiagramPoint;\n /** 色调:线、箭头与连线文字的颜色(退回、驳回用 danger,走过的路径用 success),默认中性的灰 */\n tone?: StatusTone;\n /** 画成虚线:可选的、还没生效的连线 */\n dashed?: boolean;\n}\n\n/** 选中的节点与连线(标识) */\nexport interface DiagramSelection {\n /** 选中的节点 */\n readonly nodes: readonly string[];\n /** 选中的连线 */\n readonly edges: readonly string[];\n}\n\n/** 节点、连线渲染时的状态 */\nexport interface DiagramItemState {\n /** 已选中 */\n readonly selected: boolean;\n}\n\n/** 拖动结束后一个节点的新位置 */\nexport interface DiagramNodeMove {\n /** 节点的标识 */\n readonly id: string;\n /** 新的横坐标 */\n readonly x: number;\n /** 新的纵坐标 */\n readonly y: number;\n}\n\n/** 从端口拖出的一条新连线 */\nexport interface DiagramConnection {\n /** 起点节点 */\n readonly from: string;\n /** 终点节点 */\n readonly to: string;\n /** 从起点的哪条边出去 */\n readonly fromSide: DiagramSide;\n /** 从终点的哪条边进来(松开时离指针最近的边) */\n readonly toSide: DiagramSide;\n}\n\n/** 拖动连线的一端改接到别的节点 */\nexport interface DiagramReconnection {\n /** 连线的标识 */\n readonly edge: string;\n /** 改的是哪一端 */\n readonly end: 'from' | 'to';\n /** 改接到的节点 */\n readonly node: string;\n /** 从这个节点的哪条边进出 */\n readonly side: DiagramSide;\n}\n\n/** 拖动空白处做什么 */\nexport interface DiagramDragModes {\n /** 平移视口;按住 Shift 拖动是框选(看图为主:流程图、组织架构图) */\n pan: unknown;\n /** 框选;按住空格拖动、滚轮平移(编辑为主:设计器) */\n select: unknown;\n}\n\n/** 框选时怎样算选中 */\nexport interface DiagramSelectionModes {\n /** 整个在框里才选中 */\n full: unknown;\n /** 碰到框就选中 */\n partial: unknown;\n}\n\n/** 背景的网格 */\nexport interface DiagramGrids {\n /** 不画 */\n none: unknown;\n /** 点阵(设计器) */\n dots: unknown;\n /** 线格 */\n lines: unknown;\n}\n\n/** 没给折线的连线怎样画 */\nexport interface DiagramRoutings {\n /** 两个节点之间的直线,两端落在边框上 */\n straight: unknown;\n /** 绕开节点的正交折线(横竖两个方向,拐弯少,同一条边上的几条线排开) */\n orthogonal: unknown;\n}\n\n/** 未声明的属性落到视口(Root)上:aria-label 写画布画的是什么 */\nexport interface DiagramProps<\n N extends DiagramNodeItem,\n E extends DiagramEdgeItem,\n> extends PartProps<'div', 'role' | 'tabindex' | 'draggable'> {\n /** 节点:位置与大小由使用方给(排布的结果或用户摆的位置) */\n nodes: readonly N[];\n /** 连线 */\n edges?: readonly E[];\n /** 节点的内容:节点框(定位、选中、焦点)由画布画,里面画什么由这里给,内容拉伸到节点的大小。默认是标题为 getNodeLabel 的 DiagramNode */\n children?: (node: N, state: DiagramItemState) => VNodeChild;\n /** 节点的无障碍名称(读屏念的;连线的默认名称“从 A 到 B”也用它)。节点里画了文字时按同样的先后写进来(如“姓名,岗位”),语音控制才能按看得见的字找到它 */\n getNodeLabel: (node: N) => string;\n /** 连线的无障碍名称,默认“从 A 到 B” */\n getEdgeLabel?: (edge: E) => string;\n /** 连线上的文字(处理结果、条件);返回空时不画 */\n edgeText?: (edge: E, state: DiagramItemState) => VNodeChild;\n /**\n * 视口的高(数字是 px)\n * @default 360\n */\n height?: number | string;\n /** 控制器(useDiagram):画布外的按钮要缩放、适应内容时传进来;不传时画布自己建一个 */\n controller?: DiagramController;\n /** 节点与连线可以点选、框选 */\n selectable?: boolean;\n /** 选中的节点与连线:父级写 _selected={selection} 双向绑定 */\n _selected?: DiagramSelection;\n /** 拖动空白处做什么,默认 pan */\n dragMode?: keyof DiagramDragModes;\n /** 框选时怎样算选中,默认 full */\n selectionMode?: keyof DiagramSelectionModes;\n /** 背景的网格,默认 none */\n grid?: keyof DiagramGrids;\n /** 网格的间距(画布坐标),默认 20;snapToGrid 也按它吸附 */\n gridSize?: number;\n /** 第一次有尺寸时把全部内容放进视口(不超过原大);用户动过视口之前,尺寸变了也重新适应。默认 false:从原点、原大开始 */\n fitView?: boolean;\n /** 内容的范围(画布坐标):适应画布按它算。默认包住全部节点与连线;backdrop 比节点占得大时(泳道)写上它 */\n extent?: DiagramRect;\n /** 没给折线的连线怎样画,默认 straight;拖动时相连的线也按它重画 */\n routing?: keyof DiagramRoutings;\n /** 折线拐角的圆角半径,默认 6;0 为直角 */\n edgeRadius?: number;\n /** 节点可以拖动(可以按节点判断);松开后 onNodesMove 给出新位置 */\n draggable?: boolean | ((node: N) => boolean);\n /** 拖动、方向键挪动时吸附到网格(gridSize) */\n snapToGrid?: boolean;\n /** 拖动时与别的节点的边、中线对齐就吸过去并画对齐线,默认 true */\n guides?: boolean;\n /** 拖动或方向键挪动后节点的新位置:使用方写回自己的数据(顺带记一步撤销) */\n onNodesMove?: (moves: DiagramNodeMove[]) => void;\n /** 能从节点的端口拖出连线;选中的连线两端可以拖去改接 */\n connectable?: boolean;\n /** 能不能从 from 连到 to(拖动时只高亮能连的节点);默认除了自己都能连 */\n canConnect?: (from: N, to: N) => boolean;\n /** 从端口拖出连线、在另一个节点上松开 */\n onConnect?: (connection: DiagramConnection) => void;\n /** 拖动选中连线的一端、在别的节点上松开 */\n onReconnect?: (change: DiagramReconnection) => void;\n /** 画在连线下面、随视口平移缩放的内容(画布坐标的 HTML):泳道、分区、背景标注 */\n backdrop?: VNodeChild;\n /** 浮在最上面、不随视口动的内容(视口坐标):缩放按钮 DiagramControls、小地图 DiagramMinimap、图例 */\n overlay?: VNodeChild;\n /** 随视口平移缩放的那一层的部件属性 */\n propsWorld?: PartProps<'div'>;\n /** 节点框的部件属性,可以按节点计算 */\n propsNode?: PartProps<'div'> | ((node: N, state: DiagramItemState) => PartProps<'div'>);\n /** 端口的部件属性 */\n propsPort?: PartProps<'span'>;\n /** 连线(g)的部件属性,可以按连线计算(颜色、虚线用连线的 tone、dashed) */\n propsEdge?: PartProps<'g'> | ((edge: E, state: DiagramItemState) => PartProps<'g'>);\n /** 连线文字的部件属性,可以按连线计算 */\n propsEdgeText?: PartProps<'div'> | ((edge: E, state: DiagramItemState) => PartProps<'div'>);\n /** 框选框的部件属性 */\n propsMarquee?: PartProps<'div'>;\n /** 对齐线的部件属性 */\n propsGuide?: PartProps<'line'>;\n}\n\n/** 画布里的部件(DiagramControls、DiagramMinimap)取控制器 */\nexport const DiagramContext = createContext<DiagramController>('Diagram');\n\n/** 箭头的长度(画布坐标) */\nconst ARROW = 9;\n/** 网格的间距在屏幕上小于这么多 px 时放大四倍,缩得很小时不糊成一片 */\nconst MIN_GRID = 8;\n/** 对齐线吸附的距离(屏幕 px) */\nconst GUIDE_TOLERANCE = 6;\n/** 拖到离视口边多近开始自动平移(px) */\nconst EDGE_PAN = 32;\n/** 没吸附网格时方向键一次挪多少(画布坐标) */\nconst NUDGE = 8;\nconst NO_SELECTION: DiagramSelection = { nodes: [], edges: [] };\nconst SIDES: readonly DiagramSide[] = ['top', 'right', 'bottom', 'left'];\n\n/** Diagram 的样式 */\nexport const diagramStyles = css.create({\n root: {\n position: 'relative',\n overflow: 'hidden',\n backgroundColor: '_surface',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_border',\n borderRadius: '_md',\n fontSize: '_sm',\n color: '_text',\n // 画布上点选、框选、按着 Shift 加选时不选中文字(节点里要能选中复制的内容自己写 userSelect: 'text')\n userSelect: 'none',\n cursor: { default: 'grab', ':active': 'grabbing' },\n outlineStyle: { default: 'none', ':focus-visible': 'solid' },\n outlineWidth: '_sm',\n outlineColor: '_focusRing',\n outlineOffset: '_borderWidths.sm',\n },\n rootSelect: { cursor: 'default' },\n world: {\n position: 'absolute',\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n transformOrigin: '0 0',\n // 画布坐标与方向无关:从右到左的页面里节点的位置不镜像,节点里的文字照常跟随页面\n direction: 'ltr',\n },\n edges: {\n position: 'absolute',\n left: 0,\n top: 0,\n zIndex: 1,\n overflow: 'visible',\n pointerEvents: 'none',\n },\n // 对齐线、拖出来的连线、改接把手:画在节点上面,除了把手都不挡指针\n above: { zIndex: 3 },\n edge: {\n color: { default: '_borderStrong', _pressed: '_accent', ':focus-visible': '_accent' },\n strokeWidth: { default: 1.5, _pressed: 2.5, ':focus-visible': 2.5 },\n outlineStyle: 'none',\n },\n edgeSelectable: {\n cursor: 'pointer',\n // :hover 的优先级高过 aria-pressed:悬停在选中的线上时还要是强调色\n color: {\n default: '_borderStrong',\n ':hover': { default: '_textMuted', _pressed: '_accent' },\n _pressed: '_accent',\n ':focus-visible': '_accent',\n },\n },\n edgeDashed: { strokeDasharray: '6 4' },\n edgeLine: {\n fill: 'none',\n stroke: 'currentColor',\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n },\n edgeArrow: { fill: 'currentColor', stroke: 'none' },\n // 加粗的透明命中区域:细线也好点中\n edgeHit: { fill: 'none', stroke: 'transparent', strokeWidth: 14, pointerEvents: 'stroke' },\n edgeEnd: {\n fill: '_surface',\n stroke: '_accent',\n strokeWidth: 2,\n cursor: 'crosshair',\n pointerEvents: 'all',\n },\n preview: {\n color: '_accent',\n strokeWidth: 2,\n strokeDasharray: '6 4',\n },\n guide: { stroke: '_accent', strokeWidth: 1, strokeDasharray: '4 3' },\n edgeText: {\n position: 'absolute',\n left: 0,\n top: 0,\n zIndex: 1,\n paddingInline: '4px',\n borderRadius: '_sm',\n fontSize: '0.85em',\n lineHeight: '_tight',\n whiteSpace: 'nowrap',\n color: '_textMuted',\n backgroundColor: '_surface',\n pointerEvents: 'none',\n },\n node: {\n position: 'absolute',\n left: 0,\n top: 0,\n zIndex: 2,\n display: 'grid',\n boxSizing: 'border-box',\n // 选中、焦点的描边跟着节点的形状走(DiagramNode 的 shape)\n borderRadius: { default: '_md', ':has(> [data-diagram-shape=\"pill\"])': '_full' },\n outlineStyle: {\n default: 'none',\n _pressed: 'solid',\n ':focus-visible': 'solid',\n '[data-link-target]': 'dashed',\n },\n outlineWidth: '2px',\n outlineColor: { default: '_accent', ':focus-visible': '_focusRing' },\n outlineOffset: '3px',\n },\n nodeSelectable: { cursor: 'pointer' },\n nodeDraggable: { cursor: { default: 'grab', ':active': 'grabbing' } },\n nodeDragging: { cursor: 'grabbing', opacity: 0.9 },\n port: {\n position: 'absolute',\n width: '10px',\n height: '10px',\n boxSizing: 'border-box',\n borderRadius: '_full',\n borderWidth: '2px',\n borderStyle: 'solid',\n borderColor: '_accent',\n backgroundColor: '_surface',\n cursor: 'crosshair',\n transform: { default: 'translate(-50%, -50%)', ':hover': 'translate(-50%, -50%) scale(1.3)' },\n transition: `transform ${t.durations.sm} ${t.easings.standard}`,\n },\n portTop: { left: '50%', top: 0 },\n portRight: { left: '100%', top: '50%' },\n portBottom: { left: '50%', top: '100%' },\n portLeft: { left: 0, top: '50%' },\n marquee: {\n position: 'absolute',\n left: 0,\n top: 0,\n zIndex: 3,\n pointerEvents: 'none',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_accent',\n borderRadius: '_xs',\n backgroundColor: `color-mix(in srgb, ${t.colors.accent} 10%, transparent)`,\n },\n overlay: { position: 'absolute', inset: 0, zIndex: 4, pointerEvents: 'none' },\n});\n\n/** 有色调的连线:选中、焦点时照样是强调色 */\nconst toned = (color: string) => ({\n color: { default: color, _pressed: '_accent', ':focus-visible': '_accent' },\n});\n\n/** 连线的色调(neutral 用默认的灰) */\nconst edgeToneStyles = css.create({\n neutral: {},\n accent: toned('_accent'),\n info: toned('_infoText'),\n success: toned('_successText'),\n warning: toned('_warningText'),\n danger: toned('_dangerText'),\n});\n\n/** 连线文字的色调 */\nconst edgeTextToneStyles = css.create({\n neutral: {},\n accent: { color: '_accentText' },\n info: { color: '_infoText' },\n success: { color: '_successText' },\n warning: { color: '_warningText' },\n danger: { color: '_dangerText' },\n});\n\nconst portStyles: Record<DiagramSide, typeof diagramStyles.portTop> = {\n top: diagramStyles.portTop,\n right: diagramStyles.portRight,\n bottom: diagramStyles.portBottom,\n left: diagramStyles.portLeft,\n};\n\n/** 网格的图案:点阵、线格 */\nconst gridImages: Record<keyof DiagramGrids, string> = {\n none: 'none',\n dots: `radial-gradient(circle, ${t.colors.borderStrong} 1px, transparent 1.5px)`,\n lines: `linear-gradient(${t.colors.borderMuted} 1px, transparent 1px), linear-gradient(90deg, ${t.colors.borderMuted} 1px, transparent 1px)`,\n};\n\n/** 随视口变的样式:平移缩放、网格、节点与文字的位置(值变化只改元素上的变量,画布不重新渲染) */\nexport const diagramDynamicStyles = css.create({\n world: (x: number, y: number, scale: number) => ({\n transform: `translate(${x}px, ${y}px) scale(${scale})`,\n }),\n grid: (kind: keyof DiagramGrids, x: number, y: number, scale: number, gridSize: number) => {\n const step = gridSize * scale < MIN_GRID ? gridSize * scale * 4 : gridSize * scale;\n return {\n backgroundImage: gridImages[kind],\n backgroundSize: `${step}px ${step}px`,\n backgroundPosition: `${x}px ${y}px`,\n };\n },\n box: (x: number, y: number, width: number, height: number) => ({\n transform: `translate(${x}px, ${y}px)`,\n width,\n height,\n }),\n at: (x: number, y: number) => ({ transform: `translate(${x}px, ${y}px) translate(-50%, -50%)` }),\n height: (height: number | string) => ({ height }),\n});\n\n/** 部件属性可以是对象,也可以按节点、连线计算 */\nfunction partOf<T, A extends unknown[]>(part: T | ((...args: A) => T) | undefined, ...args: A) {\n return typeof part === 'function' ? (part as (...args: A) => T)(...args) : part;\n}\n\n/** 按着加选键:Shift、Ctrl、⌘ */\nconst toggles = (event: MouseEvent | KeyboardEvent) =>\n event.shiftKey || event.ctrlKey || event.metaKey;\n\n/** 方向键 → 挪动的方向 */\nconst ARROWS: Record<string, readonly [number, number]> = {\n ArrowLeft: [-1, 0],\n ArrowRight: [1, 0],\n ArrowUp: [0, -1],\n ArrowDown: [0, 1],\n};\n\n/** 一条连线画出来的折线 */\ninterface Route<E> {\n edge: E;\n points: readonly DiagramPoint[];\n}\n\n/** 拖动中的节点:哪些在动、挪了多少、要画的对齐线 */\ninterface DragState {\n ids: ReadonlySet<string>;\n dx: number;\n dy: number;\n guides: DiagramGuide[];\n}\n\n/** 正在拖的连线:从哪一点到哪一点,指针下能连的节点 */\ninterface LinkState {\n from: DiagramPoint;\n to: DiagramPoint;\n target: string | null;\n}\n\n/**\n * 节点、连线视图收到的事件处理:画布在 setup 里建一次,传给每个视图的都是同一个对象,\n * 视图的 props 不因事件处理重新生成而变化(拖动、悬停时只有变了的节点与连线重新渲染)\n */\ninterface ItemActions {\n nodeDown(id: string, event: PointerEvent): void;\n nodeClick(id: string, event: MouseEvent): void;\n nodeKey(id: string, event: KeyboardEvent): void;\n nodeEnter(id: string): void;\n nodeLeave(id: string): void;\n portDown(id: string, side: DiagramSide, event: PointerEvent): void;\n edgeClick(id: string, event: MouseEvent): void;\n edgeKey(id: string, event: KeyboardEvent): void;\n endDown(id: string, end: 'from' | 'to', event: PointerEvent): void;\n focus(rect: DiagramRect, event: FocusEvent): void;\n}\n\n/** 节点视图的属性:位置单独给(拖动中只有动着的节点位置变),状态都是原始值,比较时不会每次都“变了” */\ninterface NodeViewProps {\n item: DiagramNodeItem;\n x: number;\n y: number;\n label: string;\n roleDescription: string;\n selected: boolean;\n selectable: boolean;\n focusable: boolean;\n movable: boolean;\n dragging: boolean;\n ports: boolean;\n linkTarget: boolean;\n render: (node: never, state: DiagramItemState) => VNodeChild;\n part?: PartProps<'div'> | ((node: never, state: DiagramItemState) => PartProps<'div'>);\n portPart?: PartProps<'span'>;\n actions: ItemActions;\n}\n\n/** 一个节点:节点框(定位、选中、焦点、拖动)、使用方画的内容、端口 */\nconst NodeView = _component(\n ({\n item,\n x,\n y,\n label,\n roleDescription,\n selected,\n selectable,\n focusable,\n movable,\n dragging,\n ports,\n linkTarget,\n render,\n part,\n portPart,\n actions,\n }: NodeViewProps) =>\n () => {\n const state: DiagramItemState = { selected };\n const id = item.id;\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramStyles.node,\n selectable && diagramStyles.nodeSelectable,\n selectable && interactionTransitions.colors,\n movable && diagramStyles.nodeDraggable,\n dragging && diagramStyles.nodeDragging,\n diagramDynamicStyles.box(x, y, item.width, item.height),\n ],\n },\n partOf(part, item as never, state),\n {\n ...dataAttrs({\n 'data-diagram-item': 'node',\n 'data-node': id,\n 'data-link-target': linkTarget || undefined,\n }),\n 'aria-roledescription': roleDescription,\n 'aria-label': label,\n onPointerdown: (event: PointerEvent) => actions.nodeDown(id, event),\n onPointerenter: () => actions.nodeEnter(id),\n onPointerleave: () => actions.nodeLeave(id),\n ...(focusable\n ? {\n role: 'button',\n tabindex: 0,\n 'aria-pressed': selectable ? selected : undefined,\n onClick: (event: MouseEvent) => actions.nodeClick(id, event),\n onKeydown: (event: KeyboardEvent) => actions.nodeKey(id, event),\n onFocus: (event: FocusEvent) =>\n actions.focus({ x, y, width: item.width, height: item.height }, event),\n }\n : { role: 'img' }),\n },\n )}\n >\n {render(item as never, state)}\n {ports &&\n SIDES.map((side) => (\n <span\n key={side}\n {...mergeAttrs<'span'>({ sx: [diagramStyles.port, portStyles[side]] }, portPart, {\n ...dataAttrs({ 'data-diagram-port': side }),\n 'aria-hidden': 'true',\n onPointerdown: (event: PointerEvent) => actions.portDown(id, side, event),\n })}\n />\n ))}\n </div>\n );\n },\n);\n\n/** 连线视图的属性:折线的数组只在这条线真的变了时才换(不动的线一直是同一个数组) */\ninterface EdgeViewProps {\n item: DiagramEdgeItem;\n points: readonly DiagramPoint[];\n label: string;\n roleDescription: string;\n radius: number;\n selected: boolean;\n selectable: boolean;\n part?: PartProps<'g'> | ((edge: never, state: DiagramItemState) => PartProps<'g'>);\n actions: ItemActions;\n}\n\n/** 一条连线:加粗的透明命中区域、线、箭头(改接的把手画在节点上面那层,见 Diagram) */\nconst EdgeView = _component(\n ({\n item,\n points,\n label,\n roleDescription,\n radius,\n selected,\n selectable,\n part,\n actions,\n }: EdgeViewProps) =>\n () => {\n const state: DiagramItemState = { selected };\n const path = polylinePath(trimEnd(points, ARROW * 0.7), radius);\n return (\n <g\n {...mergeAttrs<'g'>(\n {\n sx: [\n diagramStyles.edge,\n selectable && diagramStyles.edgeSelectable,\n item.tone && edgeToneStyles[item.tone],\n item.dashed && diagramStyles.edgeDashed,\n ],\n },\n partOf(part, item as never, state),\n {\n ...dataAttrs({ 'data-diagram-item': 'edge', 'data-edge': item.id }),\n ...(selectable\n ? {\n role: 'button',\n tabindex: 0,\n 'aria-roledescription': roleDescription,\n 'aria-label': label,\n 'aria-pressed': selected,\n onClick: (event: MouseEvent) => actions.edgeClick(item.id, event),\n onKeydown: (event: KeyboardEvent) => actions.edgeKey(item.id, event),\n onFocus: (event: FocusEvent) => actions.focus(boundsOf([], points)!, event),\n }\n : {}),\n },\n )}\n >\n {selectable && <path d={path} {...css.attrs(diagramStyles.edgeHit)} />}\n <path d={path} {...css.attrs(diagramStyles.edgeLine)} />\n <polygon points={arrowHead(points, ARROW)} {...css.attrs(diagramStyles.edgeArrow)} />\n </g>\n );\n },\n);\n\n/** 连线文字视图的属性 */\ninterface EdgeTextViewProps {\n item: DiagramEdgeItem;\n x: number;\n y: number;\n selected: boolean;\n render: (edge: never, state: DiagramItemState) => VNodeChild;\n part?: PartProps<'div'> | ((edge: never, state: DiagramItemState) => PartProps<'div'>);\n}\n\n/** 连线上的文字(HTML,画在连线上面);渲染函数返回空时不画 */\nconst EdgeTextView = _component(\n ({ item, x, y, selected, render, part }: EdgeTextViewProps) =>\n () => {\n const state: DiagramItemState = { selected };\n const text = render(item as never, state);\n if (text == null || text === false || text === '') return null;\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramStyles.edgeText,\n item.tone && edgeTextToneStyles[item.tone],\n diagramDynamicStyles.at(x, y),\n ],\n },\n partOf(part, item as never, state),\n { 'aria-hidden': 'true' },\n )}\n >\n {text}\n </div>\n );\n },\n);\n\n/** 画布 */\nexport const Diagram = _component(\n <N extends DiagramNodeItem, E extends DiagramEdgeItem>({\n nodes,\n edges = [],\n children,\n getNodeLabel,\n getEdgeLabel,\n edgeText,\n height = 360,\n controller,\n selectable = false,\n _selected: selected = _bindable<DiagramSelection>(NO_SELECTION),\n dragMode = 'pan',\n selectionMode = 'full',\n grid = 'none',\n gridSize = 20,\n fitView = false,\n extent,\n routing = 'straight',\n edgeRadius = 6,\n draggable = false,\n snapToGrid = false,\n guides = true,\n onNodesMove,\n connectable = false,\n canConnect,\n onConnect,\n onReconnect,\n backdrop,\n overlay,\n propsWorld,\n propsNode,\n propsPort,\n propsEdge,\n propsEdgeText,\n propsMarquee,\n propsGuide,\n ...rest\n }: DiagramProps<N, E>) => {\n const messages = useMessages('diagram', diagramMessages);\n // 控制器只在创建时取:换控制器要换一个画布\n const diagram = _untrack(controller) ?? useDiagram();\n const internal = diagramInternals(diagram);\n DiagramContext.provide(diagram);\n\n // 框选框(视口坐标)、拖动中的节点、拖出来的连线、指针下的节点\n let marquee = _state.raw<DiagramRect | null>(null);\n let drag = _state.raw<DragState | null>(null);\n let link = _state.raw<LinkState | null>(null);\n let hovered = _state.raw<string | null>(null);\n // 按着空格:拖动一律平移(框选模式里平移的办法)\n let space = false;\n // 用户自己动过视口之后,尺寸变化不再自动适应\n let moved = false;\n\n /** 没给 children 时的节点:标题是无障碍名称的 DiagramNode */\n const defaultNode = (node: N) => <DiagramNode title={getNodeLabel(node)} />;\n const nodeById = _derived(new Map(nodes.map((node) => [node.id, node])));\n const draggableOf = (node: N) =>\n typeof draggable === 'function' ? draggable(node) : draggable;\n /** 节点现在的位置:拖动中的按拖到的位置 */\n const placed = (node: N): N =>\n drag?.ids.has(node.id) ? { ...node, x: node.x + drag.dx, y: node.y + drag.dy } : node;\n\n /** 不拖动时每条连线的折线:给了 points 用它,没给时按 routing 画;两端的节点缺了不画 */\n const restingRoutes = _derived.by(() => {\n const automatic = edges.filter((edge) => !hasPoints(edge));\n const routed = routing === 'orthogonal' ? routeEdges(nodes, automatic) : undefined;\n return edges.flatMap((edge): Route<E>[] => {\n if (hasPoints(edge)) return [{ edge, points: edge.points }];\n const from = nodeById.get(edge.from);\n const to = nodeById.get(edge.to);\n if (!from || !to) return [];\n return [{ edge, points: routed?.get(edge.id) ?? straightRoute(from, to) }];\n });\n });\n /** 拖动中:与动着的节点相连的线按 routing 实时重画,别的线不动 */\n const routes = _derived.by(() => {\n if (!drag) return restingRoutes;\n const moving = drag.ids;\n const touches = (edge: E) => moving.has(edge.from) || moving.has(edge.to);\n const list = nodes.map(placed);\n const byId = new Map(list.map((node) => [node.id, node]));\n const touched = edges.filter(touches);\n const routed = routing === 'orthogonal' ? routeEdges(list, touched) : undefined;\n return restingRoutes.map((route): Route<E> => {\n if (!touches(route.edge)) return route;\n const from = byId.get(route.edge.from);\n const to = byId.get(route.edge.to);\n if (!from || !to) return route;\n return { edge: route.edge, points: routed?.get(route.edge.id) ?? straightRoute(from, to) };\n });\n });\n const bounds = _derived(\n boundsOf(\n nodes,\n restingRoutes.flatMap((route) => route.points),\n ),\n );\n const selectedNodes = _derived(new Set(selected.nodes));\n const selectedEdges = _derived(new Set(selected.edges));\n\n internal.content = () => extent ?? bounds;\n internal.nodes = () => nodes.map(placed);\n const root = () => internal.element.value;\n const inOverlay = (target: EventTarget | null) =>\n target instanceof Element && target.closest('[data-diagram-overlay]') !== null;\n /** 事件发生在空白处:不在节点、连线、浮层里 */\n const onBackground = (target: EventTarget | null) =>\n target instanceof Element && !target.closest('[data-diagram-item],[data-diagram-overlay]');\n /** 这次按下要框选:可选择、在空白处、按的是主键,拖动方式是框选或按着 Shift */\n const startsMarquee = (event: PointerEvent) =>\n selectable &&\n !space &&\n event.button === 0 &&\n onBackground(event.target) &&\n (dragMode === 'select' || event.shiftKey);\n\n /** 视口(平移缩放)要不要处理这个事件;处理了就算用户动过视口 */\n function handlesViewport(event: PointerEvent | WheelEvent | MouseEvent | KeyboardEvent) {\n if (inOverlay(event.target)) return false;\n // 视口自己的按键(方向键平移、+ − 缩放)只在焦点就在视口上时生效,节点上的按键留给节点\n const handles =\n event.type === 'wheel'\n ? true\n : event.type === 'keydown'\n ? event.target === root()\n : space ||\n (onBackground(event.target) &&\n !(\n event.type === 'pointerdown' &&\n (dragMode === 'select' || (event as PointerEvent).shiftKey)\n ));\n if (handles) moved = true;\n return handles;\n }\n internal.filter = handlesViewport;\n\n // 量视口的大小(小地图用);fitView 时第一次有尺寸就适应内容,用户没动过视口时尺寸变化也重新适应\n useResizeObserver(root, () => {\n const element = root();\n if (!element) return;\n internal.size.value = { width: element.clientWidth, height: element.clientHeight };\n if (fitView && !moved && element.clientWidth > 0) diagram.fit();\n });\n\n /** 点了一项:加选键按着时切换它,否则只选它 */\n function choose(kind: 'nodes' | 'edges', id: string, toggle: boolean) {\n if (!selectable) return;\n if (!toggle) {\n selected = { nodes: kind === 'nodes' ? [id] : [], edges: kind === 'edges' ? [id] : [] };\n return;\n }\n const list = selected[kind];\n selected = {\n ...selected,\n [kind]: list.includes(id) ? list.filter((item) => item !== id) : [...list, id],\n };\n }\n\n const clear = () => {\n if (selected.nodes.length || selected.edges.length) selected = NO_SELECTION;\n };\n const selectAll = () => {\n selected = {\n nodes: nodes.map((node) => node.id),\n edges: routes.map((route) => route.edge.id),\n };\n };\n\n /**\n * 拖到视口边上时自动平移:指针停着不动也继续移,每移一帧调 onPan 让拖着的东西跟上指针\n * (拖动按指针的画布坐标算,视口挪了画布坐标就变了)\n */\n function edgePan(onPan: () => void) {\n let frame = 0;\n let speed = { x: 0, y: 0 };\n const tick = () => {\n frame = 0;\n if (!speed.x && !speed.y) return;\n internal.view.panTo(diagram.x + speed.x, diagram.y + speed.y);\n onPan();\n frame = requestAnimationFrame(tick);\n };\n return {\n follow(point: { clientX: number; clientY: number }) {\n const box = root()?.getBoundingClientRect();\n if (!box) return;\n const near = (distance: number) =>\n distance < EDGE_PAN ? Math.ceil((EDGE_PAN - distance) / 3) : 0;\n speed = {\n x: near(point.clientX - box.left) - near(box.right - point.clientX),\n y: near(point.clientY - box.top) - near(box.bottom - point.clientY),\n };\n if ((speed.x || speed.y) && !frame) frame = requestAnimationFrame(tick);\n },\n stop() {\n speed = { x: 0, y: 0 };\n if (frame) cancelAnimationFrame(frame);\n frame = 0;\n },\n };\n }\n\n /** 拖动期间按 Esc 取消:在捕获阶段拦下,不让它再去清空选择 */\n function cancelOnEscape(cancel: () => void) {\n const onKey = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopPropagation();\n cancel();\n };\n window.addEventListener('keydown', onKey, true);\n return () => window.removeEventListener('keydown', onKey, true);\n }\n\n function startMarquee(event: PointerEvent) {\n const element = root();\n if (!element || !startsMarquee(event)) return;\n const box = element.getBoundingClientRect();\n const origin = { x: event.clientX - box.left, y: event.clientY - box.top };\n const additive = event.ctrlKey || event.metaKey || (dragMode === 'select' && event.shiftKey);\n const base = additive ? selected : NO_SELECTION;\n const covers = (area: DiagramRect, rect: DiagramRect) =>\n selectionMode === 'partial' ? rectsIntersect(area, rect) : rectContains(area, rect);\n startMove(event, {\n threshold: 3,\n onMove: (point) => {\n const screen = rectFromCorners(origin, {\n x: point.clientX - box.left,\n y: point.clientY - box.top,\n });\n marquee = screen;\n const { x, y, scale } = diagram;\n const area = {\n x: (screen.x - x) / scale,\n y: (screen.y - y) / scale,\n width: screen.width / scale,\n height: screen.height / scale,\n };\n const next = {\n nodes: union(\n base.nodes,\n nodes.filter((node) => covers(area, node)).map((node) => node.id),\n ),\n edges: union(\n base.edges,\n routes\n .filter((route) => covers(area, boundsOf([], route.points)!))\n .map((route) => route.edge.id),\n ),\n };\n // 框到的没变时不写:画布只在选择真的变了才重新渲染\n if (!sameIds(next.nodes, selected.nodes) || !sameIds(next.edges, selected.edges)) {\n selected = next;\n }\n },\n onEnd: () => (marquee = null),\n });\n }\n\n /** 按在节点上:拖动它(选中的一起拖);按在节点里的输入框、按钮、端口上时不拖 */\n function startDrag(node: N, event: PointerEvent) {\n if (event.button !== 0 || space || !draggableOf(node)) return;\n const target = event.target as Element;\n if (\n target.closest(\n '[data-diagram-port],input,textarea,select,button,a,[contenteditable=\"true\"]',\n )\n ) {\n return;\n }\n const additive = toggles(event);\n const ids = selectedNodes.has(node.id)\n ? selected.nodes\n : additive\n ? [...selected.nodes, node.id]\n : [node.id];\n const moving = ids.flatMap((id) => {\n const item = nodeById.get(id);\n return item && draggableOf(item) ? [item] : [];\n });\n const others = nodes.filter((item) => !ids.includes(item.id));\n const start = diagram.toDiagram(event.clientX, event.clientY);\n let pointer = { clientX: event.clientX, clientY: event.clientY };\n let begun = false;\n let release = () => {};\n\n // 以按住的节点为准吸附网格与对齐线,算出整组挪多少\n const update = () => {\n const now = diagram.toDiagram(pointer.clientX, pointer.clientY);\n let x = node.x + now.x - start.x;\n let y = node.y + now.y - start.y;\n if (snapToGrid) {\n x = Math.round(x / gridSize) * gridSize;\n y = Math.round(y / gridSize) * gridSize;\n }\n let lines: DiagramGuide[] = [];\n if (guides) {\n const aligned = alignToGuides({ ...node, x, y }, others, GUIDE_TOLERANCE / diagram.scale);\n ({ x, y } = aligned);\n lines = aligned.guides;\n }\n drag = {\n ids: new Set(moving.map((item) => item.id)),\n dx: x - node.x,\n dy: y - node.y,\n guides: lines,\n };\n };\n const pan = edgePan(update);\n const cancel = startMove(event, {\n threshold: 3,\n onMove: (point) => {\n pointer = point;\n if (!begun) {\n begun = true;\n // 拖一个没选中的节点:选中它(按着加选键时加进原来的选择)\n if (selectable && !selectedNodes.has(node.id)) {\n selected = { nodes: ids, edges: additive ? selected.edges : [] };\n }\n release = cancelOnEscape(() => cancel());\n }\n update();\n pan.follow(point);\n },\n onEnd: ({ moved: dragged, cancelled }) => {\n pan.stop();\n release();\n const result = drag;\n drag = null;\n if (!dragged || cancelled || !result || (result.dx === 0 && result.dy === 0)) return;\n onNodesMove?.(\n moving.map((item) => ({ id: item.id, x: item.x + result.dx, y: item.y + result.dy })),\n );\n },\n });\n }\n\n /**\n * 拖一条连线:从 anchor 拉出来,松开在能连的节点上时 done(节点, 离指针最近的边)。\n * fixed 是不动的那一端的节点(连到它自己不算);fixedIsSource 时它是起点、箭头在指针一端\n */\n function startLink(\n event: PointerEvent,\n anchor: DiagramPoint,\n fixed: N,\n fixedIsSource: boolean,\n done: (target: N, side: DiagramSide) => void,\n ) {\n if (event.button !== 0) return;\n event.stopPropagation();\n event.preventDefault();\n let pointer = { clientX: event.clientX, clientY: event.clientY };\n let release = () => {};\n let landing: { node: N; side: DiagramSide } | null = null;\n const allowed = (candidate: N) =>\n candidate.id !== fixed.id &&\n (canConnect?.(fixedIsSource ? fixed : candidate, fixedIsSource ? candidate : fixed) ??\n true);\n const update = () => {\n const point = diagram.toDiagram(pointer.clientX, pointer.clientY);\n const hit = rectAt(nodes, point);\n landing = hit && allowed(hit) ? { node: hit, side: nearestSide(hit, point) } : null;\n const end = landing ? sidePoint(landing.node, landing.side) : point;\n link = {\n from: fixedIsSource ? anchor : end,\n to: fixedIsSource ? end : anchor,\n target: landing?.node.id ?? null,\n };\n };\n const pan = edgePan(update);\n update();\n const cancel = startMove(event, {\n // 端口、改接把手拖动中会消失:捕获放在画布上;松开时的 click 也落在画布上,不能当成点空白处\n captureTarget: root() ?? undefined,\n swallowClick: true,\n onMove: (point) => {\n pointer = point;\n update();\n pan.follow(point);\n },\n onEnd: ({ cancelled }) => {\n pan.stop();\n release();\n link = null;\n if (!cancelled && landing) done(landing.node, landing.side);\n },\n });\n release = cancelOnEscape(() => cancel());\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (event.key === ' ' && event.target === root()) space = true;\n if (!selectable) return;\n if (event.key === 'Escape') clear();\n if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') {\n event.preventDefault();\n selectAll();\n }\n }\n\n /** 节点上的方向键:挪动(选中的一起挪,Shift 五步) */\n function nudge(node: N, event: KeyboardEvent) {\n const arrow = ARROWS[event.key];\n if (!arrow || !onNodesMove || !draggableOf(node)) return;\n event.preventDefault();\n const step = (snapToGrid ? gridSize : NUDGE) * (event.shiftKey ? 5 : 1);\n const ids = selectedNodes.has(node.id) ? selected.nodes : [node.id];\n onNodesMove(\n ids.flatMap((id) => {\n const item = nodeById.get(id);\n return item && draggableOf(item)\n ? [{ id, x: item.x + arrow[0] * step, y: item.y + arrow[1] * step }]\n : [];\n }),\n );\n }\n\n /** Enter / 空格:选中(同点击) */\n function activates(event: KeyboardEvent) {\n if (event.key !== 'Enter' && event.key !== ' ') return false;\n event.preventDefault();\n return true;\n }\n\n const actions: ItemActions = {\n nodeDown(id, event) {\n const node = nodeById.get(id);\n if (node) startDrag(node, event);\n },\n nodeClick: (id, event) => choose('nodes', id, toggles(event)),\n nodeKey(id, event) {\n const node = nodeById.get(id);\n if (!node) return;\n if (activates(event)) choose('nodes', id, toggles(event));\n else nudge(node, event);\n },\n nodeEnter: (id) => (hovered = id),\n nodeLeave(id) {\n if (hovered === id) hovered = null;\n },\n portDown(id, side, event) {\n const node = nodeById.get(id);\n if (!node) return;\n startLink(event, sidePoint(node, side), node, true, (target, toSide) =>\n onConnect?.({ from: id, to: target.id, fromSide: side, toSide }),\n );\n },\n edgeClick: (id, event) => choose('edges', id, toggles(event)),\n edgeKey(id, event) {\n if (activates(event)) choose('edges', id, toggles(event));\n },\n endDown(id, end, event) {\n const route = routes.find((item) => item.edge.id === id);\n const from = route && nodeById.get(route.edge.from);\n const to = route && nodeById.get(route.edge.to);\n if (!route || !from || !to || !onReconnect) return;\n const { points } = route;\n // 拖的是终点:不动的是起点,箭头在指针一端;拖的是起点:反过来\n const anchor = end === 'to' ? points[0]! : points[points.length - 1]!;\n startLink(event, anchor, end === 'to' ? from : to, end === 'to', (target, side) =>\n onReconnect({ edge: id, end, node: target.id, side }),\n );\n },\n // 键盘把焦点移到视口外的节点、连线时平移过去(鼠标点到的本来就看得见)\n focus(rect, event) {\n if (event.target instanceof Element && event.target.matches(':focus-visible')) {\n diagram.reveal(rect);\n }\n },\n };\n\n return () => {\n const { view } = internal;\n const focusable = selectable || !!onNodesMove;\n // 选中的连线两端的改接把手:两端的节点都在时才能改接\n const ends =\n connectable && onReconnect && !drag && !link\n ? routes.filter(\n ({ edge }) =>\n selectedEdges.has(edge.id) && nodeById.has(edge.from) && nodeById.has(edge.to),\n )\n : [];\n return (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramStyles.root,\n diagramDynamicStyles.height(height),\n dragMode === 'select' && diagramStyles.rootSelect,\n diagramDynamicStyles.grid(grid, diagram.x, diagram.y, diagram.scale, gridSize),\n ],\n },\n rest,\n {\n ...view.viewportProps,\n ref: (element: unknown) => (internal.element.value = element as HTMLElement | null),\n role: 'group',\n tabindex: 0,\n 'aria-roledescription': messages.canvas,\n onPointerdown: (event: PointerEvent) => {\n startMarquee(event);\n (view.viewportProps.onPointerdown as (event: PointerEvent) => void)(event);\n },\n onClick: (event: MouseEvent) => {\n if (selectable && onBackground(event.target)) clear();\n },\n onKeydown: (event: KeyboardEvent) => {\n onKeydown(event);\n (view.viewportProps.onKeydown as (event: KeyboardEvent) => void)(event);\n },\n onKeyup: (event: KeyboardEvent) => {\n if (event.key === ' ') space = false;\n },\n onBlur: () => (space = false),\n // 焦点移到视口外的节点时浏览器会滚动视口(overflow: hidden 也能被滚动),视口的位置只由平移决定\n onScroll: (event: Event) => {\n const element = event.currentTarget as HTMLElement;\n element.scrollTop = 0;\n element.scrollLeft = 0;\n },\n },\n )}\n >\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramStyles.world,\n diagramDynamicStyles.world(diagram.x, diagram.y, diagram.scale),\n ],\n },\n propsWorld,\n dataAttrs({ 'data-diagram-world': true }),\n )}\n >\n {backdrop}\n {nodes.map((node) => {\n const at = placed(node);\n const isSelected = selectedNodes.has(node.id);\n return (\n <NodeView\n key={node.id}\n item={node}\n x={at.x}\n y={at.y}\n label={getNodeLabel(node)}\n roleDescription={messages.node}\n selected={isSelected}\n selectable={selectable}\n focusable={focusable}\n movable={draggableOf(node)}\n dragging={drag?.ids.has(node.id) ?? false}\n ports={\n connectable &&\n !drag &&\n (hovered === node.id || isSelected || link?.target === node.id)\n }\n linkTarget={link?.target === node.id}\n render={(children ?? defaultNode) as NodeViewProps['render']}\n part={propsNode as NodeViewProps['part']}\n portPart={propsPort}\n actions={actions}\n />\n );\n })}\n <svg\n {...css.attrs(diagramStyles.edges)}\n width=\"1\"\n height=\"1\"\n aria-hidden={selectable ? undefined : 'true'}\n >\n {routes.map(({ edge, points }) => {\n const from = nodeById.get(edge.from);\n const to = nodeById.get(edge.to);\n const isSelected = selectedEdges.has(edge.id);\n return (\n <EdgeView\n key={edge.id}\n item={edge}\n points={points}\n label={\n getEdgeLabel?.(edge) ??\n messages.edgeBetween(\n from ? getNodeLabel(from) : edge.from,\n to ? getNodeLabel(to) : edge.to,\n )\n }\n roleDescription={messages.edge}\n radius={edgeRadius}\n selected={isSelected}\n selectable={selectable}\n part={propsEdge as EdgeViewProps['part']}\n actions={actions}\n />\n );\n })}\n </svg>\n {edgeText &&\n routes.map(({ edge, points }) => {\n const at = drag || !edge.labelAt ? polylineMidpoint(points) : edge.labelAt;\n return (\n <EdgeTextView\n key={edge.id}\n item={edge}\n x={at.x}\n y={at.y}\n selected={selectedEdges.has(edge.id)}\n render={edgeText as EdgeTextViewProps['render']}\n part={propsEdgeText as EdgeTextViewProps['part']}\n />\n );\n })}\n {(!!drag?.guides.length || !!link || ends.length > 0) && (\n <svg\n {...css.attrs(diagramStyles.edges, diagramStyles.above)}\n width=\"1\"\n height=\"1\"\n aria-hidden=\"true\"\n data-diagram-transient=\"\"\n >\n {drag?.guides.map((guide, index) => (\n <line\n key={index}\n {...mergeAttrs<'line'>({ sx: diagramStyles.guide }, propsGuide, {\n x1: guide.from.x,\n y1: guide.from.y,\n x2: guide.to.x,\n y2: guide.to.y,\n })}\n />\n ))}\n {ends.flatMap(({ edge, points }) =>\n (['from', 'to'] as const).map((end) => {\n const at = end === 'from' ? points[0]! : points[points.length - 1]!;\n return (\n <circle\n key={`${edge.id}:${end}`}\n cx={at.x}\n cy={at.y}\n r={5}\n {...css.attrs(diagramStyles.edgeEnd)}\n data-diagram-end={end}\n onPointerdown={(event: PointerEvent) =>\n actions.endDown(edge.id, end, event)\n }\n />\n );\n }),\n )}\n {link && (\n <g {...css.attrs(diagramStyles.preview)}>\n <path\n d={polylinePath(trimEnd([link.from, link.to], ARROW * 0.7))}\n {...css.attrs(diagramStyles.edgeLine)}\n />\n <polygon\n points={arrowHead([link.from, link.to], ARROW)}\n {...css.attrs(diagramStyles.edgeArrow)}\n />\n </g>\n )}\n </svg>\n )}\n </div>\n {marquee && (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramStyles.marquee,\n diagramDynamicStyles.box(marquee.x, marquee.y, marquee.width, marquee.height),\n ],\n },\n propsMarquee,\n )}\n />\n )}\n {overlay != null && (\n <div {...css.attrs(diagramStyles.overlay)} data-diagram-overlay=\"\">\n {overlay}\n </div>\n )}\n </div>\n );\n };\n },\n);\n\n/** 连线自己给了折线 */\nconst hasPoints = (\n edge: DiagramEdgeItem,\n): edge is DiagramEdgeItem & { points: readonly DiagramPoint[] } =>\n !!edge.points && edge.points.length >= 2;\n\n/** 两组标识合在一起,去掉重复 */\nconst union = (a: readonly string[], b: readonly string[]) => [...new Set([...a, ...b])];\n\n/** 两组标识是否相同(顺序无关) */\nfunction sameIds(a: readonly string[], b: readonly string[]): boolean {\n if (a.length !== b.length) return false;\n const set = new Set(a);\n return b.every((id) => set.has(id));\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mergeAttrs } from "../utils/props.js";
|
|
2
|
-
import { createVNode
|
|
3
|
-
import { _component, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
2
|
+
import { createVNode } from "vue";
|
|
3
|
+
import { _component, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
4
4
|
import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
5
5
|
//#region src/diagram/DiagramLanes.tsx
|
|
6
6
|
/** 一条泳道 */
|
|
@@ -72,7 +72,7 @@ var DiagramLanes = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
72
72
|
diagramLanesStyles.root,
|
|
73
73
|
css.bind(diagramLanesDynamicStyles.at, () => [x.value, y.value], true),
|
|
74
74
|
css.bind(diagramLanesDynamicStyles.width, () => [width.value], true)
|
|
75
|
-
] }, rest), [lanes.value.map((lane, index) => createVNode("div",
|
|
75
|
+
] }, rest), [lanes.value.map((lane, index) => createVNode("div", mergeJsxProps({ "key": index }, mergeAttrs({ sx: [diagramLanesStyles.lane, css.bind(diagramLanesDynamicStyles.height, () => [lane.size ?? laneSize.value])] }, propsLane.value)), [createVNode("div", mergeAttrs({ sx: [diagramLanesStyles.header, css.bind(diagramLanesDynamicStyles.width, () => [header.value], true)] }, propsHeader.value), [lane.name])]))]);
|
|
76
76
|
}, {
|
|
77
77
|
name: "DiagramLanes",
|
|
78
78
|
props: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiagramLanes.js","names":["_vtp_readonlyProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/diagram/DiagramLanes.tsx"],"sourcesContent":["/**\n * 泳道:虚线框出的一组横向泳道,左边一栏是泳道名(岗位、部门、系统),不着底色(画布的网格透过来)。放在 Diagram 的 backdrop 里,\n * 用画布坐标、随视口平移缩放;extent 写上泳道的范围,适应画布时整个放进来:\n *\n * const lanes = [{ name: '申请人' }, { name: '部门经理' }, { name: '财务', size: 160 }];\n * <Diagram backdrop={<DiagramLanes lanes={lanes} width={860} />} extent={lanesExtent(lanes, { width: 860 })} … />\n *\n * 泳道从 (x, y) 开始往下排,每条的高是它的 size,没写时用 laneSize;节点的纵坐标落在哪条泳道的范围里由使用方排。\n * 部件:Root(div)、Lane(每条泳道)、Header(泳道名)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport type { DiagramRect } from './geometry';\n\n/** 一条泳道 */\nexport interface DiagramLane {\n /** 泳道名 */\n name: VNodeChild;\n /** 这条泳道的高(画布坐标);不写时用 DiagramLanes 的 laneSize */\n size?: number;\n}\n\n/** 泳道的排法:起点、长度与默认的高 */\nexport interface DiagramLanesLayout {\n /** 泳道的长度(含泳道名那一栏,画布坐标) */\n width: number;\n /** 没写 size 的泳道的高,默认 120 */\n laneSize?: number;\n /** 左上角的横坐标,默认 0 */\n x?: number;\n /** 左上角的纵坐标,默认 0 */\n y?: number;\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface DiagramLanesProps extends PartProps<'div'>, DiagramLanesLayout {\n /** 泳道,从上往下 */\n lanes: readonly DiagramLane[];\n /** 泳道名那一栏的宽(画布坐标),默认 88 */\n header?: number;\n /** 每条泳道的部件属性 */\n propsLane?: PartProps<'div'>;\n /** 泳道名的部件属性 */\n propsHeader?: PartProps<'div'>;\n}\n\n/** 泳道整体占的范围(画布坐标):交给 Diagram 的 extent */\nexport function lanesExtent(\n lanes: readonly DiagramLane[],\n { width, laneSize = 120, x = 0, y = 0 }: DiagramLanesLayout,\n): DiagramRect {\n const height = lanes.reduce((sum, lane) => sum + (lane.size ?? laneSize), 0);\n return { x, y, width, height };\n}\n\n/** DiagramLanes 的样式:root、lane、header */\nexport const diagramLanesStyles = css.create({\n // 虚线、不着底色:画布的点阵透过来,泳道只是分区,不像一张压在画布上的表\n root: {\n position: 'absolute',\n left: 0,\n top: 0,\n borderRadius: '_md',\n // 外框用 outline 画:不占位置,泳道的坐标与 lanesExtent 一致\n outlineWidth: '_xs',\n outlineStyle: 'dashed',\n outlineColor: '_borderStrong',\n },\n lane: {\n display: 'flex',\n boxSizing: 'border-box',\n borderBlockEndWidth: { default: '_xs', ':last-child': 0 },\n borderBlockEndStyle: 'dashed',\n borderBlockEndColor: '_borderStrong',\n },\n header: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n boxSizing: 'border-box',\n paddingInline: '_space.xs',\n textAlign: 'center',\n fontWeight: '_semibold',\n color: '_textMuted',\n borderInlineEndWidth: '_xs',\n borderInlineEndStyle: 'dashed',\n borderInlineEndColor: '_borderStrong',\n },\n});\n\n/** 随数据变的样式:位置与大小 */\nexport const diagramLanesDynamicStyles = css.create({\n at: (x: number, y: number) => ({ transform: `translate(${x}px, ${y}px)` }),\n width: (width: number) => ({ width }),\n height: (height: number) => ({ height }),\n});\n\n/** 泳道 */\nexport const DiagramLanes = _component(\n ({\n lanes,\n width,\n laneSize = 120,\n x = 0,\n y = 0,\n header = 88,\n propsLane,\n propsHeader,\n ...rest\n }: DiagramLanesProps) =>\n () => (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramLanesStyles.root,\n diagramLanesDynamicStyles.at(x, y),\n diagramLanesDynamicStyles.width(width),\n ],\n },\n rest,\n )}\n >\n {lanes.map((lane, index) => (\n <div\n key={index}\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramLanesStyles.lane,\n diagramLanesDynamicStyles.height(lane.size ?? laneSize),\n ],\n },\n propsLane,\n )}\n >\n <div\n {...mergeAttrs<'div'>(\n { sx: [diagramLanesStyles.header, diagramLanesDynamicStyles.width(header)] },\n propsHeader,\n )}\n >\n {lane.name}\n </div>\n </div>\n ))}\n </div>\n ),\n);\n"],"mappings":";;;;;;;;;AAiDA,SAAgB,YACd,OACA,EAAE,OAAO,WAAW,KAAK,IAAI,GAAG,IAAI,KACvB;CAEb,OAAO;EAAE;EAAG;EAAG;EAAO,QADP,MAAM,QAAQ,KAAK,SAAS,OAAO,KAAK,QAAQ,WAAW,CACpD;CAAO;AAC/B;;AAGA,IAAa,qBAAqB,IAAI,OAAO;CAE3C,MAAM;EACJ,UAAU;EACV,MAAM;EACN,KAAK;EACL,cAAc;EAEd,cAAc;EACd,cAAc;EACd,cAAc;CAChB;CACA,MAAM;EACJ,SAAS;EACT,WAAW;EACX,qBAAqB;GAAE,SAAS;GAAO,eAAe;EAAE;EACxD,qBAAqB;EACrB,qBAAqB;CACvB;CACA,QAAQ;EACN,SAAS;EACT,YAAY;EACZ,gBAAgB;EAChB,YAAY;EACZ,WAAW;EACX,eAAe;EACf,WAAW;EACX,YAAY;EACZ,OAAO;EACP,sBAAsB;EACtB,sBAAsB;EACtB,sBAAsB;CACxB;AACF,CAAC;;AAGD,IAAa,4BAA4B,IAAI,OAAO;CAClD,KAAK,GAAW,OAAe,EAAE,WAAW,aAAa,EAAC,MAAO,EAAC,KAAM;CACxE,QAAQ,WAAmB,EAAE,MAAM;CACnC,SAAS,YAAoB,EAAE,OAAO;AACxC,CAAC;;AAGD,IAAa,eAAe,0BAC1B,QAAA,SAAA;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,YAGa,GAAG;CAAA,MAAA,IAAAA,aAAA,QAAA,KACV,CAAC;CAAA,MAAA,IAAAA,aAAA,QAAA,KACD,CAAC;CAAA,MAAA,SAAAA,aAAA,QAAA,UACI,EAAE;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAGR,OAAIC,UAAA,QAAA,MAAA,IAAA;CAAA,aAEPC,YAAA,OAEQ,WACF,EACE,IAAI;EACF,mBAAmB;EAAI,IAAA,KACvB,0BAA0B,UAAE,CAAA,EAAA,OAAA,EAAA,KAAA,GAAA,IAAA;EAAA,IAAA,KAC5B,0BAA0B,aAAK,CAAA,MAAA,KAAA,GAAA,IAAA;CAAA,EAEnC,GACA,IACF,GAAC,CAEA,MAAA,MAAM,KAAK,MAAM,UAAKA,YAAA,OAAAC,
|
|
1
|
+
{"version":3,"file":"DiagramLanes.js","names":["_vtp_readonlyProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/diagram/DiagramLanes.tsx"],"sourcesContent":["/**\n * 泳道:虚线框出的一组横向泳道,左边一栏是泳道名(岗位、部门、系统),不着底色(画布的网格透过来)。放在 Diagram 的 backdrop 里,\n * 用画布坐标、随视口平移缩放;extent 写上泳道的范围,适应画布时整个放进来:\n *\n * const lanes = [{ name: '申请人' }, { name: '部门经理' }, { name: '财务', size: 160 }];\n * <Diagram backdrop={<DiagramLanes lanes={lanes} width={860} />} extent={lanesExtent(lanes, { width: 860 })} … />\n *\n * 泳道从 (x, y) 开始往下排,每条的高是它的 size,没写时用 laneSize;节点的纵坐标落在哪条泳道的范围里由使用方排。\n * 部件:Root(div)、Lane(每条泳道)、Header(泳道名)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport type { DiagramRect } from './geometry';\n\n/** 一条泳道 */\nexport interface DiagramLane {\n /** 泳道名 */\n name: VNodeChild;\n /** 这条泳道的高(画布坐标);不写时用 DiagramLanes 的 laneSize */\n size?: number;\n}\n\n/** 泳道的排法:起点、长度与默认的高 */\nexport interface DiagramLanesLayout {\n /** 泳道的长度(含泳道名那一栏,画布坐标) */\n width: number;\n /** 没写 size 的泳道的高,默认 120 */\n laneSize?: number;\n /** 左上角的横坐标,默认 0 */\n x?: number;\n /** 左上角的纵坐标,默认 0 */\n y?: number;\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface DiagramLanesProps extends PartProps<'div'>, DiagramLanesLayout {\n /** 泳道,从上往下 */\n lanes: readonly DiagramLane[];\n /** 泳道名那一栏的宽(画布坐标),默认 88 */\n header?: number;\n /** 每条泳道的部件属性 */\n propsLane?: PartProps<'div'>;\n /** 泳道名的部件属性 */\n propsHeader?: PartProps<'div'>;\n}\n\n/** 泳道整体占的范围(画布坐标):交给 Diagram 的 extent */\nexport function lanesExtent(\n lanes: readonly DiagramLane[],\n { width, laneSize = 120, x = 0, y = 0 }: DiagramLanesLayout,\n): DiagramRect {\n const height = lanes.reduce((sum, lane) => sum + (lane.size ?? laneSize), 0);\n return { x, y, width, height };\n}\n\n/** DiagramLanes 的样式:root、lane、header */\nexport const diagramLanesStyles = css.create({\n // 虚线、不着底色:画布的点阵透过来,泳道只是分区,不像一张压在画布上的表\n root: {\n position: 'absolute',\n left: 0,\n top: 0,\n borderRadius: '_md',\n // 外框用 outline 画:不占位置,泳道的坐标与 lanesExtent 一致\n outlineWidth: '_xs',\n outlineStyle: 'dashed',\n outlineColor: '_borderStrong',\n },\n lane: {\n display: 'flex',\n boxSizing: 'border-box',\n borderBlockEndWidth: { default: '_xs', ':last-child': 0 },\n borderBlockEndStyle: 'dashed',\n borderBlockEndColor: '_borderStrong',\n },\n header: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n boxSizing: 'border-box',\n paddingInline: '_space.xs',\n textAlign: 'center',\n fontWeight: '_semibold',\n color: '_textMuted',\n borderInlineEndWidth: '_xs',\n borderInlineEndStyle: 'dashed',\n borderInlineEndColor: '_borderStrong',\n },\n});\n\n/** 随数据变的样式:位置与大小 */\nexport const diagramLanesDynamicStyles = css.create({\n at: (x: number, y: number) => ({ transform: `translate(${x}px, ${y}px)` }),\n width: (width: number) => ({ width }),\n height: (height: number) => ({ height }),\n});\n\n/** 泳道 */\nexport const DiagramLanes = _component(\n ({\n lanes,\n width,\n laneSize = 120,\n x = 0,\n y = 0,\n header = 88,\n propsLane,\n propsHeader,\n ...rest\n }: DiagramLanesProps) =>\n () => (\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramLanesStyles.root,\n diagramLanesDynamicStyles.at(x, y),\n diagramLanesDynamicStyles.width(width),\n ],\n },\n rest,\n )}\n >\n {lanes.map((lane, index) => (\n <div\n key={index}\n {...mergeAttrs<'div'>(\n {\n sx: [\n diagramLanesStyles.lane,\n diagramLanesDynamicStyles.height(lane.size ?? laneSize),\n ],\n },\n propsLane,\n )}\n >\n <div\n {...mergeAttrs<'div'>(\n { sx: [diagramLanesStyles.header, diagramLanesDynamicStyles.width(header)] },\n propsHeader,\n )}\n >\n {lane.name}\n </div>\n </div>\n ))}\n </div>\n ),\n);\n"],"mappings":";;;;;;;;;AAiDA,SAAgB,YACd,OACA,EAAE,OAAO,WAAW,KAAK,IAAI,GAAG,IAAI,KACvB;CAEb,OAAO;EAAE;EAAG;EAAG;EAAO,QADP,MAAM,QAAQ,KAAK,SAAS,OAAO,KAAK,QAAQ,WAAW,CACpD;CAAO;AAC/B;;AAGA,IAAa,qBAAqB,IAAI,OAAO;CAE3C,MAAM;EACJ,UAAU;EACV,MAAM;EACN,KAAK;EACL,cAAc;EAEd,cAAc;EACd,cAAc;EACd,cAAc;CAChB;CACA,MAAM;EACJ,SAAS;EACT,WAAW;EACX,qBAAqB;GAAE,SAAS;GAAO,eAAe;EAAE;EACxD,qBAAqB;EACrB,qBAAqB;CACvB;CACA,QAAQ;EACN,SAAS;EACT,YAAY;EACZ,gBAAgB;EAChB,YAAY;EACZ,WAAW;EACX,eAAe;EACf,WAAW;EACX,YAAY;EACZ,OAAO;EACP,sBAAsB;EACtB,sBAAsB;EACtB,sBAAsB;CACxB;AACF,CAAC;;AAGD,IAAa,4BAA4B,IAAI,OAAO;CAClD,KAAK,GAAW,OAAe,EAAE,WAAW,aAAa,EAAC,MAAO,EAAC,KAAM;CACxE,QAAQ,WAAmB,EAAE,MAAM;CACnC,SAAS,YAAoB,EAAE,OAAO;AACxC,CAAC;;AAGD,IAAa,eAAe,0BAC1B,QAAA,SAAA;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,QAAAA,aAAA,QAAA,OAAA;CAAA,MAAA,WAAAA,aAAA,QAAA,YAGa,GAAG;CAAA,MAAA,IAAAA,aAAA,QAAA,KACV,CAAC;CAAA,MAAA,IAAAA,aAAA,QAAA,KACD,CAAC;CAAA,MAAA,SAAAA,aAAA,QAAA,UACI,EAAE;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,cAAAA,aAAA,QAAA,aAAA;CAAA,MAGR,OAAIC,UAAA,QAAA,MAAA,IAAA;CAAA,aAEPC,YAAA,OAEQ,WACF,EACE,IAAI;EACF,mBAAmB;EAAI,IAAA,KACvB,0BAA0B,UAAE,CAAA,EAAA,OAAA,EAAA,KAAA,GAAA,IAAA;EAAA,IAAA,KAC5B,0BAA0B,aAAK,CAAA,MAAA,KAAA,GAAA,IAAA;CAAA,EAEnC,GACA,IACF,GAAC,CAEA,MAAA,MAAM,KAAK,MAAM,UAAKA,YAAA,OAAAC,cAAA,EAAA,OAEd,MAAK,GACN,WACF,EACE,IAAI,CACF,mBAAmB,MAAI,IAAA,KACvB,0BAA0B,cAAM,CAAC,KAAK,QAAI,SAAA,KAAY,CAAA,CAAA,EAE1D,GAAC,UAAA,KAEH,CAAC,GAAA,CAAAD,YAAA,OAGK,WACF,EAAE,IAAI,CAAC,mBAAmB,QAAM,IAAA,KAAE,0BAA0B,aAAK,CAAA,OAAA,KAAA,GAAA,IAAA,CAAA,EAAU,GAAC,YAAA,KAE9E,GAAC,CAEA,KAAK,IAAI,CAAA,CAAA,CAAA,CAGf,CAAC,CAAA;AAEL,GAAA;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACL"}
|
|
@@ -3,8 +3,8 @@ import { startMove } from "../utils/dom/move.js";
|
|
|
3
3
|
import { diagramInternals } from "./controller.js";
|
|
4
4
|
import { boundsOf } from "./geometry.js";
|
|
5
5
|
import { DiagramContext } from "./Diagram.js";
|
|
6
|
-
import { createVNode
|
|
7
|
-
import { _component, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
6
|
+
import { createVNode } from "vue";
|
|
7
|
+
import { _component, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
8
8
|
import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
9
9
|
//#region src/diagram/DiagramMinimap.tsx
|
|
10
10
|
/** 小地图放在画布的哪个角 */
|
|
@@ -98,12 +98,12 @@ var DiagramMinimap = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
98
98
|
return createVNode("div", mergeAttrs({ sx: [diagramMinimapStyles.root, diagramMinimapStyles[placement.value]] }, rest, {
|
|
99
99
|
"aria-hidden": "true",
|
|
100
100
|
onPointerdown
|
|
101
|
-
}), [createVNode("svg",
|
|
101
|
+
}), [createVNode("svg", mergeJsxProps({ "ref": _cache[0] || (_cache[0] = (element) => svg = element) }, css.attrs(diagramMinimapStyles.svg), {
|
|
102
102
|
"width": width.value,
|
|
103
103
|
"height": height.value,
|
|
104
104
|
"viewBox": `${frame.x - pad} ${frame.y - pad} ${frame.width + pad * 2} ${frame.height + pad * 2}`,
|
|
105
105
|
"preserveAspectRatio": "xMidYMid meet"
|
|
106
|
-
}), [nodes.map((node, index) => createVNode("rect",
|
|
106
|
+
}), [nodes.map((node, index) => createVNode("rect", mergeJsxProps({ "key": index }, mergeAttrs({ sx: diagramMinimapStyles.node }, propsNode.value, {
|
|
107
107
|
x: node.x,
|
|
108
108
|
y: node.y,
|
|
109
109
|
width: node.width,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiagramMinimap.js","names":["_vtp_readonlyProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/diagram/DiagramMinimap.tsx"],"sourcesContent":["/**\n * 小地图:整张图的缩略(节点画成小方块)与当前视口的框,点或拖小地图把视口移过去。放在 Diagram 的 overlay 里:\n *\n * <Diagram overlay={<><DiagramControls /><DiagramMinimap /></>} … />\n *\n * 只是指针用户的便利:键盘用户用视口的方向键平移,读屏不念它(aria-hidden)。\n * 部件:Root(div)、Node(每个节点的方块)、Viewport(视口的框)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { startMove } from '../utils/dom/move';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { diagramInternals } from './controller';\nimport { DiagramContext } from './Diagram';\nimport { boundsOf } from './geometry';\n\n/** 小地图放在画布的哪个角 */\nexport interface DiagramMinimapPlacements {\n /** 右下(从右到左时左下),默认 */\n 'bottom-end': unknown;\n /** 左下 */\n 'bottom-start': unknown;\n /** 右上 */\n 'top-end': unknown;\n /** 左上 */\n 'top-start': unknown;\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface DiagramMinimapProps extends PartProps<'div'> {\n /** 放在画布的哪个角,默认 bottom-end */\n placement?: keyof DiagramMinimapPlacements;\n /** 宽(px),默认 168 */\n width?: number;\n /** 高(px),默认 112 */\n height?: number;\n /** 节点方块的部件属性 */\n propsNode?: PartProps<'rect'>;\n /** 视口框的部件属性 */\n propsViewport?: PartProps<'rect'>;\n}\n\n/** DiagramMinimap 的样式 */\nexport const diagramMinimapStyles = css.create({\n root: {\n position: 'absolute',\n pointerEvents: 'auto',\n overflow: 'hidden',\n backgroundColor: '_surface',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_border',\n borderRadius: '_md',\n boxShadow: '_sm',\n cursor: 'pointer',\n touchAction: 'none',\n },\n 'bottom-end': { insetBlockEnd: '_space.sm', insetInlineEnd: '_space.sm' },\n 'bottom-start': { insetBlockEnd: '_space.sm', insetInlineStart: '_space.sm' },\n 'top-end': { insetBlockStart: '_space.sm', insetInlineEnd: '_space.sm' },\n 'top-start': { insetBlockStart: '_space.sm', insetInlineStart: '_space.sm' },\n svg: { display: 'block' },\n node: { fill: '_borderStrong' },\n viewport: {\n fill: `color-mix(in srgb, currentColor 6%, transparent)`,\n stroke: '_accent',\n strokeWidth: 1.5,\n color: '_accent',\n },\n});\n\n/** 小地图 */\nexport const DiagramMinimap = _component(\n ({\n placement = 'bottom-end',\n width = 168,\n height = 112,\n propsNode,\n propsViewport,\n ...rest\n }: DiagramMinimapProps) => {\n const diagram = DiagramContext.inject();\n const internal = diagramInternals(diagram);\n let svg: SVGSVGElement | null = null;\n\n /** 视口在画布坐标里的范围 */\n const visible = () => {\n const { width: viewWidth, height: viewHeight } = internal.size.value;\n return {\n x: -diagram.x / diagram.scale,\n y: -diagram.y / diagram.scale,\n width: viewWidth / diagram.scale,\n height: viewHeight / diagram.scale,\n };\n };\n\n /** 把视口的中心移到小地图上点到的位置 */\n function centerAt(clientX: number, clientY: number) {\n const matrix = svg?.getScreenCTM()?.inverse();\n if (!matrix) return;\n const point = new DOMPoint(clientX, clientY).matrixTransform(matrix);\n const { width: viewWidth, height: viewHeight } = internal.size.value;\n internal.view.panTo(\n viewWidth / 2 - point.x * diagram.scale,\n viewHeight / 2 - point.y * diagram.scale,\n );\n }\n\n function onPointerdown(event: PointerEvent) {\n if (event.button !== 0) return;\n event.preventDefault();\n centerAt(event.clientX, event.clientY);\n startMove(event, { onMove: (point) => centerAt(point.clientX, point.clientY) });\n }\n\n return () => {\n const nodes = internal.nodes();\n const view = visible();\n // 视口也算进范围:拖到很远时框也一直看得见\n const frame = boundsOf([...nodes, view]) ?? { x: 0, y: 0, width: 1, height: 1 };\n const pad = Math.max(frame.width, frame.height) * 0.04;\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [diagramMinimapStyles.root, diagramMinimapStyles[placement]] },\n rest,\n { 'aria-hidden': 'true', onPointerdown },\n )}\n >\n <svg\n ref={(element: unknown) => (svg = element as SVGSVGElement | null)}\n {...css.attrs(diagramMinimapStyles.svg)}\n width={width}\n height={height}\n viewBox={`${frame.x - pad} ${frame.y - pad} ${frame.width + pad * 2} ${frame.height + pad * 2}`}\n preserveAspectRatio=\"xMidYMid meet\"\n >\n {nodes.map((node, index) => (\n <rect\n key={index}\n {...mergeAttrs<'rect'>({ sx: diagramMinimapStyles.node }, propsNode, {\n x: node.x,\n y: node.y,\n width: node.width,\n height: node.height,\n rx: Math.min(node.width, node.height) * 0.12,\n })}\n />\n ))}\n <rect\n {...mergeAttrs<'rect'>({ sx: diagramMinimapStyles.viewport }, propsViewport, {\n x: view.x,\n y: view.y,\n width: view.width,\n height: view.height,\n // 小地图按比例缩得很小,描边不跟着缩\n 'vector-effect': 'non-scaling-stroke',\n })}\n />\n </svg>\n </div>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;;;;AA2CA,IAAa,uBAAuB,IAAI,OAAO;CAC7C,MAAM;EACJ,UAAU;EACV,eAAe;EACf,UAAU;EACV,iBAAiB;EACjB,aAAa;EACb,aAAa;EACb,aAAa;EACb,cAAc;EACd,WAAW;EACX,QAAQ;EACR,aAAa;CACf;CACA,cAAc;EAAE,eAAe;EAAa,gBAAgB;CAAY;CACxE,gBAAgB;EAAE,eAAe;EAAa,kBAAkB;CAAY;CAC5E,WAAW;EAAE,iBAAiB;EAAa,gBAAgB;CAAY;CACvE,aAAa;EAAE,iBAAiB;EAAa,kBAAkB;CAAY;CAC3E,KAAK,EAAE,SAAS,QAAQ;CACxB,MAAM,EAAE,MAAM,gBAAgB;CAC9B,UAAU;EACR,MAAM;EACN,QAAQ;EACR,aAAa;EACb,OAAO;CACT;AACF,CAAC;;AAGD,IAAa,iBAAiB,0BAC5B,QAAA,SAO2B;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,aANb,YAAY;CAAA,MAAA,QAAAA,aAAA,QAAA,SAChB,GAAG;CAAA,MAAA,SAAAA,aAAA,QAAA,UACF,GAAG;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,gBAAAA,aAAA,QAAA,eAAA;CAAA,MAGT,OAAIC,UAAA,QAAA,MAAA,IAAA;CAEP,MAAM,UAAU,eAAe,OAAO;CACtC,MAAM,WAAW,iBAAiB,OAAO;CACzC,IAAI,MAA4B;;CAGhC,MAAM,gBAAgB;EACpB,MAAM,EAAE,OAAO,WAAW,QAAQ,eAAe,SAAS,KAAK;EAC/D,OAAO;GACL,GAAG,CAAC,QAAQ,IAAI,QAAQ;GACxB,GAAG,CAAC,QAAQ,IAAI,QAAQ;GACxB,OAAO,YAAY,QAAQ;GAC3B,QAAQ,aAAa,QAAQ;EAC/B;CACF;;CAGA,SAAS,SAAS,SAAiB,SAAiB;EAClD,MAAM,SAAS,KAAK,aAAa,CAAC,EAAE,QAAQ;EAC5C,IAAI,CAAC,QAAQ;EACb,MAAM,QAAQ,IAAI,SAAS,SAAS,OAAO,CAAC,CAAC,gBAAgB,MAAM;EACnE,MAAM,EAAE,OAAO,WAAW,QAAQ,eAAe,SAAS,KAAK;EAC/D,SAAS,KAAK,MACZ,YAAY,IAAI,MAAM,IAAI,QAAQ,OAClC,aAAa,IAAI,MAAM,IAAI,QAAQ,KACrC;CACF;CAEA,SAAS,cAAc,OAAqB;EAC1C,IAAI,MAAM,WAAW,GAAG;EACxB,MAAM,eAAe;EACrB,SAAS,MAAM,SAAS,MAAM,OAAO;EACrC,UAAU,OAAO,EAAE,SAAS,UAAU,SAAS,MAAM,SAAS,MAAM,OAAO,EAAE,CAAC;CAChF;CAEA,aAAa;EACX,MAAM,QAAQ,SAAS,MAAM;EAC7B,MAAM,OAAO,QAAQ;EAErB,MAAM,QAAQ,SAAS,CAAC,GAAG,OAAO,IAAI,CAAC,KAAK;GAAE,GAAG;GAAG,GAAG;GAAG,OAAO;GAAG,QAAQ;EAAE;EAC9E,MAAM,MAAM,KAAK,IAAI,MAAM,OAAO,MAAM,MAAM,IAAI;EAClD,OAAAC,YAAA,OAEQ,WACF,EAAE,IAAI,CAAC,qBAAqB,MAAM,qBAAoB,UAAA,MAAW,EAAE,GACnE,MACA;GAAE,eAAe;GAAQ;EAAc,CACzC,GAAC,CAAAA,YAAA,OAAAC,
|
|
1
|
+
{"version":3,"file":"DiagramMinimap.js","names":["_vtp_readonlyProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/diagram/DiagramMinimap.tsx"],"sourcesContent":["/**\n * 小地图:整张图的缩略(节点画成小方块)与当前视口的框,点或拖小地图把视口移过去。放在 Diagram 的 overlay 里:\n *\n * <Diagram overlay={<><DiagramControls /><DiagramMinimap /></>} … />\n *\n * 只是指针用户的便利:键盘用户用视口的方向键平移,读屏不念它(aria-hidden)。\n * 部件:Root(div)、Node(每个节点的方块)、Viewport(视口的框)。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { startMove } from '../utils/dom/move';\nimport { mergeAttrs, type PartProps } from '../utils/props';\nimport { diagramInternals } from './controller';\nimport { DiagramContext } from './Diagram';\nimport { boundsOf } from './geometry';\n\n/** 小地图放在画布的哪个角 */\nexport interface DiagramMinimapPlacements {\n /** 右下(从右到左时左下),默认 */\n 'bottom-end': unknown;\n /** 左下 */\n 'bottom-start': unknown;\n /** 右上 */\n 'top-end': unknown;\n /** 左上 */\n 'top-start': unknown;\n}\n\n/** 未声明的属性落到外层 div 上 */\nexport interface DiagramMinimapProps extends PartProps<'div'> {\n /** 放在画布的哪个角,默认 bottom-end */\n placement?: keyof DiagramMinimapPlacements;\n /** 宽(px),默认 168 */\n width?: number;\n /** 高(px),默认 112 */\n height?: number;\n /** 节点方块的部件属性 */\n propsNode?: PartProps<'rect'>;\n /** 视口框的部件属性 */\n propsViewport?: PartProps<'rect'>;\n}\n\n/** DiagramMinimap 的样式 */\nexport const diagramMinimapStyles = css.create({\n root: {\n position: 'absolute',\n pointerEvents: 'auto',\n overflow: 'hidden',\n backgroundColor: '_surface',\n borderWidth: '_xs',\n borderStyle: 'solid',\n borderColor: '_border',\n borderRadius: '_md',\n boxShadow: '_sm',\n cursor: 'pointer',\n touchAction: 'none',\n },\n 'bottom-end': { insetBlockEnd: '_space.sm', insetInlineEnd: '_space.sm' },\n 'bottom-start': { insetBlockEnd: '_space.sm', insetInlineStart: '_space.sm' },\n 'top-end': { insetBlockStart: '_space.sm', insetInlineEnd: '_space.sm' },\n 'top-start': { insetBlockStart: '_space.sm', insetInlineStart: '_space.sm' },\n svg: { display: 'block' },\n node: { fill: '_borderStrong' },\n viewport: {\n fill: `color-mix(in srgb, currentColor 6%, transparent)`,\n stroke: '_accent',\n strokeWidth: 1.5,\n color: '_accent',\n },\n});\n\n/** 小地图 */\nexport const DiagramMinimap = _component(\n ({\n placement = 'bottom-end',\n width = 168,\n height = 112,\n propsNode,\n propsViewport,\n ...rest\n }: DiagramMinimapProps) => {\n const diagram = DiagramContext.inject();\n const internal = diagramInternals(diagram);\n let svg: SVGSVGElement | null = null;\n\n /** 视口在画布坐标里的范围 */\n const visible = () => {\n const { width: viewWidth, height: viewHeight } = internal.size.value;\n return {\n x: -diagram.x / diagram.scale,\n y: -diagram.y / diagram.scale,\n width: viewWidth / diagram.scale,\n height: viewHeight / diagram.scale,\n };\n };\n\n /** 把视口的中心移到小地图上点到的位置 */\n function centerAt(clientX: number, clientY: number) {\n const matrix = svg?.getScreenCTM()?.inverse();\n if (!matrix) return;\n const point = new DOMPoint(clientX, clientY).matrixTransform(matrix);\n const { width: viewWidth, height: viewHeight } = internal.size.value;\n internal.view.panTo(\n viewWidth / 2 - point.x * diagram.scale,\n viewHeight / 2 - point.y * diagram.scale,\n );\n }\n\n function onPointerdown(event: PointerEvent) {\n if (event.button !== 0) return;\n event.preventDefault();\n centerAt(event.clientX, event.clientY);\n startMove(event, { onMove: (point) => centerAt(point.clientX, point.clientY) });\n }\n\n return () => {\n const nodes = internal.nodes();\n const view = visible();\n // 视口也算进范围:拖到很远时框也一直看得见\n const frame = boundsOf([...nodes, view]) ?? { x: 0, y: 0, width: 1, height: 1 };\n const pad = Math.max(frame.width, frame.height) * 0.04;\n return (\n <div\n {...mergeAttrs<'div'>(\n { sx: [diagramMinimapStyles.root, diagramMinimapStyles[placement]] },\n rest,\n { 'aria-hidden': 'true', onPointerdown },\n )}\n >\n <svg\n ref={(element: unknown) => (svg = element as SVGSVGElement | null)}\n {...css.attrs(diagramMinimapStyles.svg)}\n width={width}\n height={height}\n viewBox={`${frame.x - pad} ${frame.y - pad} ${frame.width + pad * 2} ${frame.height + pad * 2}`}\n preserveAspectRatio=\"xMidYMid meet\"\n >\n {nodes.map((node, index) => (\n <rect\n key={index}\n {...mergeAttrs<'rect'>({ sx: diagramMinimapStyles.node }, propsNode, {\n x: node.x,\n y: node.y,\n width: node.width,\n height: node.height,\n rx: Math.min(node.width, node.height) * 0.12,\n })}\n />\n ))}\n <rect\n {...mergeAttrs<'rect'>({ sx: diagramMinimapStyles.viewport }, propsViewport, {\n x: view.x,\n y: view.y,\n width: view.width,\n height: view.height,\n // 小地图按比例缩得很小,描边不跟着缩\n 'vector-effect': 'non-scaling-stroke',\n })}\n />\n </svg>\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
@@ -5,8 +5,8 @@ import { disclosureStyles } from "../utils/style/transitions.js";
|
|
|
5
5
|
import { ButtonBase } from "../base/ButtonBase.js";
|
|
6
6
|
import { selectedValues, toggleSelection } from "../utils/data/selection.js";
|
|
7
7
|
import { Collapse } from "./Collapse.js";
|
|
8
|
-
import { computed, createVNode, h, isVNode,
|
|
9
|
-
import { _component, bindable, childrenProp, createContext, forwardChildren, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
8
|
+
import { computed, createVNode, h, isVNode, shallowRef, useId } from "vue";
|
|
9
|
+
import { _component, bindable, childrenProp, createContext, forwardChildren, 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 { ChevronDown } from "@lucide/icons";
|
|
12
12
|
//#region src/display/Accordion.tsx
|
|
@@ -123,7 +123,7 @@ var Accordion = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
|
123
123
|
event.preventDefault();
|
|
124
124
|
next.focus();
|
|
125
125
|
}
|
|
126
|
-
return () => createVNode("div",
|
|
126
|
+
return () => createVNode("div", mergeJsxProps(mergeAttrs({ sx: [accordionStyles.root, size.value && fontSizeStyles[size.value]] }, rest, {
|
|
127
127
|
ref: root,
|
|
128
128
|
onKeydown
|
|
129
129
|
}), {
|
|
@@ -172,7 +172,7 @@ var AccordionItem = /*#__PURE__*/ _component((_props2, _ctx2) => {
|
|
|
172
172
|
const open = model.open;
|
|
173
173
|
const off = disabled.value || accordion.disabled;
|
|
174
174
|
const state = open ? "open" : "closed";
|
|
175
|
-
const trigger = createVNode(ButtonBase,
|
|
175
|
+
const trigger = createVNode(ButtonBase, mergeJsxProps(mergePartProps({ sx: [accordionStyles.trigger, off && accordionStyles.triggerDisabled] }, propsTrigger.value, {
|
|
176
176
|
id: triggerId,
|
|
177
177
|
disabled: off,
|
|
178
178
|
"aria-expanded": open,
|
|
@@ -189,10 +189,10 @@ var AccordionItem = /*#__PURE__*/ _component((_props2, _ctx2) => {
|
|
|
189
189
|
open && accordionStyles.chevronOpen
|
|
190
190
|
]
|
|
191
191
|
}, propsChevron.value), null)] });
|
|
192
|
-
return createVNode("div",
|
|
192
|
+
return createVNode("div", mergeJsxProps(mergeAttrs({ sx: accordionStyles.item }, rest), {
|
|
193
193
|
"data-state": state,
|
|
194
194
|
"data-disabled": off || void 0
|
|
195
|
-
}), [h(`h${accordion.headingLevel}`, mergeAttrs({ sx: accordionStyles.heading }, propsHeading.value), [trigger]), createVNode(Collapse,
|
|
195
|
+
}), [h(`h${accordion.headingLevel}`, mergeAttrs({ sx: accordionStyles.heading }, propsHeading.value), [trigger]), createVNode(Collapse, mergeJsxProps(mergePartProps({ propsContent: { sx: accordionStyles.content } }, propsContent.value, {
|
|
196
196
|
id: contentId,
|
|
197
197
|
role: "region",
|
|
198
198
|
"aria-labelledby": triggerId
|