@yh-ui/flow 0.1.21
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/LICENSE +21 -0
- package/README.md +234 -0
- package/dist/Flow.d.vue.ts +306 -0
- package/dist/Flow.vue +959 -0
- package/dist/Flow.vue.d.ts +306 -0
- package/dist/__tests__/ai-workflow.ssr.test.cjs +352 -0
- package/dist/__tests__/ai-workflow.ssr.test.d.ts +1 -0
- package/dist/__tests__/ai-workflow.ssr.test.mjs +283 -0
- package/dist/__tests__/ai-workflow.test.cjs +109 -0
- package/dist/__tests__/ai-workflow.test.d.ts +1 -0
- package/dist/__tests__/ai-workflow.test.mjs +112 -0
- package/dist/__tests__/bpmn.ssr.test.cjs +278 -0
- package/dist/__tests__/bpmn.ssr.test.d.ts +1 -0
- package/dist/__tests__/bpmn.ssr.test.mjs +237 -0
- package/dist/__tests__/bpmn.test.cjs +103 -0
- package/dist/__tests__/bpmn.test.d.ts +1 -0
- package/dist/__tests__/bpmn.test.mjs +106 -0
- package/dist/__tests__/custom-types.test.cjs +300 -0
- package/dist/__tests__/custom-types.test.d.ts +1 -0
- package/dist/__tests__/custom-types.test.mjs +248 -0
- package/dist/__tests__/edge.test.cjs +56 -0
- package/dist/__tests__/edge.test.d.ts +1 -0
- package/dist/__tests__/edge.test.mjs +69 -0
- package/dist/__tests__/event-bus.test.cjs +80 -0
- package/dist/__tests__/event-bus.test.d.ts +1 -0
- package/dist/__tests__/event-bus.test.mjs +51 -0
- package/dist/__tests__/flow.ssr.test.cjs +156 -0
- package/dist/__tests__/flow.ssr.test.d.ts +1 -0
- package/dist/__tests__/flow.ssr.test.mjs +112 -0
- package/dist/__tests__/geometry.test.cjs +191 -0
- package/dist/__tests__/geometry.test.d.ts +1 -0
- package/dist/__tests__/geometry.test.mjs +105 -0
- package/dist/__tests__/graph.test.cjs +115 -0
- package/dist/__tests__/graph.test.d.ts +1 -0
- package/dist/__tests__/graph.test.mjs +85 -0
- package/dist/__tests__/history-plugin.test.cjs +191 -0
- package/dist/__tests__/history-plugin.test.d.ts +1 -0
- package/dist/__tests__/history-plugin.test.mjs +161 -0
- package/dist/__tests__/history.test.cjs +81 -0
- package/dist/__tests__/history.test.d.ts +1 -0
- package/dist/__tests__/history.test.mjs +43 -0
- package/dist/__tests__/layout.test.cjs +213 -0
- package/dist/__tests__/layout.test.d.ts +1 -0
- package/dist/__tests__/layout.test.mjs +170 -0
- package/dist/__tests__/node-edit-panel.ssr.test.cjs +168 -0
- package/dist/__tests__/node-edit-panel.ssr.test.d.ts +1 -0
- package/dist/__tests__/node-edit-panel.ssr.test.mjs +118 -0
- package/dist/__tests__/node-group-plugin.test.cjs +235 -0
- package/dist/__tests__/node-group-plugin.test.d.ts +1 -0
- package/dist/__tests__/node-group-plugin.test.mjs +187 -0
- package/dist/__tests__/node-handles.test.cjs +340 -0
- package/dist/__tests__/node-handles.test.d.ts +1 -0
- package/dist/__tests__/node-handles.test.mjs +230 -0
- package/dist/__tests__/plugin.test.cjs +151 -0
- package/dist/__tests__/plugin.test.d.ts +1 -0
- package/dist/__tests__/plugin.test.mjs +116 -0
- package/dist/__tests__/transform.test.cjs +58 -0
- package/dist/__tests__/transform.test.d.ts +1 -0
- package/dist/__tests__/transform.test.mjs +38 -0
- package/dist/__tests__/useAlignment.test.cjs +91 -0
- package/dist/__tests__/useAlignment.test.d.ts +1 -0
- package/dist/__tests__/useAlignment.test.mjs +52 -0
- package/dist/__tests__/useEdges.test.cjs +117 -0
- package/dist/__tests__/useEdges.test.d.ts +1 -0
- package/dist/__tests__/useEdges.test.mjs +80 -0
- package/dist/__tests__/useKeyboard.test.cjs +88 -0
- package/dist/__tests__/useKeyboard.test.d.ts +1 -0
- package/dist/__tests__/useKeyboard.test.mjs +56 -0
- package/dist/__tests__/useNodes.test.cjs +150 -0
- package/dist/__tests__/useNodes.test.d.ts +1 -0
- package/dist/__tests__/useNodes.test.mjs +80 -0
- package/dist/__tests__/useSelection.test.cjs +112 -0
- package/dist/__tests__/useSelection.test.d.ts +1 -0
- package/dist/__tests__/useSelection.test.mjs +76 -0
- package/dist/__tests__/useViewport.test.cjs +171 -0
- package/dist/__tests__/useViewport.test.d.ts +1 -0
- package/dist/__tests__/useViewport.test.mjs +82 -0
- package/dist/__tests__/utils/ssr.cjs +124 -0
- package/dist/__tests__/utils/ssr.d.ts +33 -0
- package/dist/__tests__/utils/ssr.mjs +129 -0
- package/dist/__tests__/validation.test.cjs +95 -0
- package/dist/__tests__/validation.test.d.ts +1 -0
- package/dist/__tests__/validation.test.mjs +36 -0
- package/dist/components/AiNodeEditPanel.d.vue.ts +13 -0
- package/dist/components/AiNodeEditPanel.vue +413 -0
- package/dist/components/AiNodeEditPanel.vue.d.ts +13 -0
- package/dist/components/EdgeEditPanel.d.vue.ts +14 -0
- package/dist/components/EdgeEditPanel.vue +205 -0
- package/dist/components/EdgeEditPanel.vue.d.ts +14 -0
- package/dist/components/NodeEditPanel.d.vue.ts +13 -0
- package/dist/components/NodeEditPanel.vue +214 -0
- package/dist/components/NodeEditPanel.vue.d.ts +13 -0
- package/dist/components/edges/BaseEdge.d.vue.ts +23 -0
- package/dist/components/edges/BaseEdge.vue +55 -0
- package/dist/components/edges/BaseEdge.vue.d.ts +23 -0
- package/dist/components/edges/BezierEdge.d.vue.ts +22 -0
- package/dist/components/edges/BezierEdge.vue +57 -0
- package/dist/components/edges/BezierEdge.vue.d.ts +22 -0
- package/dist/components/edges/DataFlowEdge.d.vue.ts +41 -0
- package/dist/components/edges/DataFlowEdge.vue +211 -0
- package/dist/components/edges/DataFlowEdge.vue.d.ts +41 -0
- package/dist/components/edges/SmoothEdge.d.vue.ts +22 -0
- package/dist/components/edges/SmoothEdge.vue +53 -0
- package/dist/components/edges/SmoothEdge.vue.d.ts +22 -0
- package/dist/components/edges/StepEdge.d.vue.ts +22 -0
- package/dist/components/edges/StepEdge.vue +42 -0
- package/dist/components/edges/StepEdge.vue.d.ts +22 -0
- package/dist/components/edges/index.cjs +41 -0
- package/dist/components/edges/index.d.ts +5 -0
- package/dist/components/edges/index.mjs +5 -0
- package/dist/components/nodes/BaseNode.d.vue.ts +25 -0
- package/dist/components/nodes/BaseNode.vue +93 -0
- package/dist/components/nodes/BaseNode.vue.d.ts +25 -0
- package/dist/components/nodes/CustomNode.d.vue.ts +36 -0
- package/dist/components/nodes/CustomNode.vue +44 -0
- package/dist/components/nodes/CustomNode.vue.d.ts +36 -0
- package/dist/components/nodes/DatabaseNode.d.vue.ts +19 -0
- package/dist/components/nodes/DatabaseNode.vue +62 -0
- package/dist/components/nodes/DatabaseNode.vue.d.ts +19 -0
- package/dist/components/nodes/DiamondNode.d.vue.ts +19 -0
- package/dist/components/nodes/DiamondNode.vue +62 -0
- package/dist/components/nodes/DiamondNode.vue.d.ts +19 -0
- package/dist/components/nodes/GroupNode.d.vue.ts +31 -0
- package/dist/components/nodes/GroupNode.vue +48 -0
- package/dist/components/nodes/GroupNode.vue.d.ts +31 -0
- package/dist/components/nodes/InputNode.d.vue.ts +23 -0
- package/dist/components/nodes/InputNode.vue +63 -0
- package/dist/components/nodes/InputNode.vue.d.ts +23 -0
- package/dist/components/nodes/NodeResizer.d.vue.ts +27 -0
- package/dist/components/nodes/NodeResizer.vue +89 -0
- package/dist/components/nodes/NodeResizer.vue.d.ts +27 -0
- package/dist/components/nodes/NodeToolbar.d.vue.ts +32 -0
- package/dist/components/nodes/NodeToolbar.vue +101 -0
- package/dist/components/nodes/NodeToolbar.vue.d.ts +32 -0
- package/dist/components/nodes/OutputNode.d.vue.ts +21 -0
- package/dist/components/nodes/OutputNode.vue +53 -0
- package/dist/components/nodes/OutputNode.vue.d.ts +21 -0
- package/dist/components/nodes/ai-workflow/AiAgentNode.d.vue.ts +20 -0
- package/dist/components/nodes/ai-workflow/AiAgentNode.vue +59 -0
- package/dist/components/nodes/ai-workflow/AiAgentNode.vue.d.ts +20 -0
- package/dist/components/nodes/ai-workflow/AiConditionNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiConditionNode.vue +65 -0
- package/dist/components/nodes/ai-workflow/AiConditionNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiEndNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiEndNode.vue +47 -0
- package/dist/components/nodes/ai-workflow/AiEndNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiLlmNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiLlmNode.vue +64 -0
- package/dist/components/nodes/ai-workflow/AiLlmNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiMemoryNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiMemoryNode.vue +59 -0
- package/dist/components/nodes/ai-workflow/AiMemoryNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiPromptNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiPromptNode.vue +61 -0
- package/dist/components/nodes/ai-workflow/AiPromptNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiStartNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiStartNode.vue +47 -0
- package/dist/components/nodes/ai-workflow/AiStartNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiToolNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiToolNode.vue +59 -0
- package/dist/components/nodes/ai-workflow/AiToolNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/index.cjs +109 -0
- package/dist/components/nodes/ai-workflow/index.d.ts +23 -0
- package/dist/components/nodes/ai-workflow/index.mjs +37 -0
- package/dist/components/nodes/bpmn/BpmnEndEvent.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnEndEvent.vue +50 -0
- package/dist/components/nodes/bpmn/BpmnEndEvent.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnExclusiveGateway.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnExclusiveGateway.vue +60 -0
- package/dist/components/nodes/bpmn/BpmnExclusiveGateway.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnInclusiveGateway.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnInclusiveGateway.vue +60 -0
- package/dist/components/nodes/bpmn/BpmnInclusiveGateway.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnParallelGateway.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnParallelGateway.vue +60 -0
- package/dist/components/nodes/bpmn/BpmnParallelGateway.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnServiceTask.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnServiceTask.vue +55 -0
- package/dist/components/nodes/bpmn/BpmnServiceTask.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnStartEvent.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnStartEvent.vue +50 -0
- package/dist/components/nodes/bpmn/BpmnStartEvent.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnTask.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnTask.vue +54 -0
- package/dist/components/nodes/bpmn/BpmnTask.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnUserTask.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnUserTask.vue +55 -0
- package/dist/components/nodes/bpmn/BpmnUserTask.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/index.cjs +109 -0
- package/dist/components/nodes/bpmn/index.d.ts +23 -0
- package/dist/components/nodes/bpmn/index.mjs +37 -0
- package/dist/components/nodes/index.cjs +246 -0
- package/dist/components/nodes/index.d.ts +13 -0
- package/dist/components/nodes/index.mjs +44 -0
- package/dist/core/FlowContext.cjs +21 -0
- package/dist/core/FlowContext.d.ts +10 -0
- package/dist/core/FlowContext.mjs +13 -0
- package/dist/core/index.cjs +104 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.mjs +9 -0
- package/dist/core/useAlignment.cjs +81 -0
- package/dist/core/useAlignment.d.ts +33 -0
- package/dist/core/useAlignment.mjs +71 -0
- package/dist/core/useEdges.cjs +132 -0
- package/dist/core/useEdges.d.ts +29 -0
- package/dist/core/useEdges.mjs +89 -0
- package/dist/core/useFlow.cjs +40 -0
- package/dist/core/useFlow.d.ts +31 -0
- package/dist/core/useFlow.mjs +32 -0
- package/dist/core/useHistory.cjs +63 -0
- package/dist/core/useHistory.d.ts +15 -0
- package/dist/core/useHistory.mjs +54 -0
- package/dist/core/useKeyboard.cjs +54 -0
- package/dist/core/useKeyboard.d.ts +18 -0
- package/dist/core/useKeyboard.mjs +45 -0
- package/dist/core/useNodeDistribution.cjs +171 -0
- package/dist/core/useNodeDistribution.d.ts +12 -0
- package/dist/core/useNodeDistribution.mjs +145 -0
- package/dist/core/useNodes.cjs +146 -0
- package/dist/core/useNodes.d.ts +26 -0
- package/dist/core/useNodes.mjs +101 -0
- package/dist/core/useSelection.cjs +83 -0
- package/dist/core/useSelection.d.ts +18 -0
- package/dist/core/useSelection.mjs +53 -0
- package/dist/core/useViewport.cjs +157 -0
- package/dist/core/useViewport.d.ts +65 -0
- package/dist/core/useViewport.mjs +125 -0
- package/dist/flow.cjs +240 -0
- package/dist/flow.d.ts +276 -0
- package/dist/flow.mjs +230 -0
- package/dist/index.cjs +378 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.mjs +50 -0
- package/dist/plugins/index.cjs +96 -0
- package/dist/plugins/index.d.ts +34 -0
- package/dist/plugins/index.mjs +47 -0
- package/dist/plugins/plugin.cjs +117 -0
- package/dist/plugins/plugin.d.ts +72 -0
- package/dist/plugins/plugin.mjs +110 -0
- package/dist/plugins/plugins/controls.cjs +38 -0
- package/dist/plugins/plugins/controls.d.ts +12 -0
- package/dist/plugins/plugins/controls.mjs +28 -0
- package/dist/plugins/plugins/export.cjs +102 -0
- package/dist/plugins/plugins/export.d.ts +12 -0
- package/dist/plugins/plugins/export.mjs +89 -0
- package/dist/plugins/plugins/grid.cjs +36 -0
- package/dist/plugins/plugins/grid.d.ts +11 -0
- package/dist/plugins/plugins/grid.mjs +26 -0
- package/dist/plugins/plugins/history.cjs +140 -0
- package/dist/plugins/plugins/history.d.ts +53 -0
- package/dist/plugins/plugins/history.mjs +132 -0
- package/dist/plugins/plugins/index.cjs +104 -0
- package/dist/plugins/plugins/index.d.ts +9 -0
- package/dist/plugins/plugins/index.mjs +9 -0
- package/dist/plugins/plugins/keyboard.cjs +27 -0
- package/dist/plugins/plugins/keyboard.d.ts +10 -0
- package/dist/plugins/plugins/keyboard.mjs +18 -0
- package/dist/plugins/plugins/layout.cjs +275 -0
- package/dist/plugins/plugins/layout.d.ts +34 -0
- package/dist/plugins/plugins/layout.mjs +246 -0
- package/dist/plugins/plugins/minimap.cjs +60 -0
- package/dist/plugins/plugins/minimap.d.ts +25 -0
- package/dist/plugins/plugins/minimap.mjs +50 -0
- package/dist/plugins/plugins/node-group.cjs +209 -0
- package/dist/plugins/plugins/node-group.d.ts +26 -0
- package/dist/plugins/plugins/node-group.mjs +178 -0
- package/dist/plugins/plugins/snap.cjs +36 -0
- package/dist/plugins/plugins/snap.d.ts +12 -0
- package/dist/plugins/plugins/snap.mjs +26 -0
- package/dist/renderer/AlignmentLines.d.vue.ts +5 -0
- package/dist/renderer/AlignmentLines.vue +113 -0
- package/dist/renderer/AlignmentLines.vue.d.ts +5 -0
- package/dist/renderer/Background.d.vue.ts +7 -0
- package/dist/renderer/Background.vue +86 -0
- package/dist/renderer/Background.vue.d.ts +7 -0
- package/dist/renderer/Controls.d.vue.ts +13 -0
- package/dist/renderer/Controls.vue +82 -0
- package/dist/renderer/Controls.vue.d.ts +13 -0
- package/dist/renderer/EdgeHandlesRenderer.d.vue.ts +11 -0
- package/dist/renderer/EdgeHandlesRenderer.vue +75 -0
- package/dist/renderer/EdgeHandlesRenderer.vue.d.ts +11 -0
- package/dist/renderer/EdgeRenderer.d.vue.ts +39 -0
- package/dist/renderer/EdgeRenderer.vue +204 -0
- package/dist/renderer/EdgeRenderer.vue.d.ts +39 -0
- package/dist/renderer/FlowBackground.d.vue.ts +11 -0
- package/dist/renderer/FlowBackground.vue +82 -0
- package/dist/renderer/FlowBackground.vue.d.ts +11 -0
- package/dist/renderer/Minimap.d.vue.ts +30 -0
- package/dist/renderer/Minimap.vue +290 -0
- package/dist/renderer/Minimap.vue.d.ts +30 -0
- package/dist/renderer/NodeRenderer.d.vue.ts +56 -0
- package/dist/renderer/NodeRenderer.vue +328 -0
- package/dist/renderer/NodeRenderer.vue.d.ts +56 -0
- package/dist/renderer/SelectionBox.d.vue.ts +11 -0
- package/dist/renderer/SelectionBox.vue +28 -0
- package/dist/renderer/SelectionBox.vue.d.ts +11 -0
- package/dist/types/edge.cjs +13 -0
- package/dist/types/edge.d.ts +65 -0
- package/dist/types/edge.mjs +6 -0
- package/dist/types/events.cjs +1 -0
- package/dist/types/events.d.ts +115 -0
- package/dist/types/events.mjs +0 -0
- package/dist/types/index.cjs +1 -0
- package/dist/types/index.d.ts +366 -0
- package/dist/types/index.mjs +0 -0
- package/dist/types/node.cjs +9 -0
- package/dist/types/node.d.ts +90 -0
- package/dist/types/node.mjs +3 -0
- package/dist/types/viewport.cjs +42 -0
- package/dist/types/viewport.d.ts +62 -0
- package/dist/types/viewport.mjs +36 -0
- package/dist/utils/bpmn-engine.cjs +390 -0
- package/dist/utils/bpmn-engine.d.ts +164 -0
- package/dist/utils/bpmn-engine.mjs +378 -0
- package/dist/utils/bpmn.cjs +492 -0
- package/dist/utils/bpmn.d.ts +53 -0
- package/dist/utils/bpmn.mjs +430 -0
- package/dist/utils/collaboration.cjs +537 -0
- package/dist/utils/collaboration.d.ts +189 -0
- package/dist/utils/collaboration.mjs +521 -0
- package/dist/utils/custom-types.cjs +138 -0
- package/dist/utils/custom-types.d.ts +78 -0
- package/dist/utils/custom-types.mjs +108 -0
- package/dist/utils/edge.cjs +235 -0
- package/dist/utils/edge.d.ts +79 -0
- package/dist/utils/edge.mjs +172 -0
- package/dist/utils/event-bus.cjs +91 -0
- package/dist/utils/event-bus.d.ts +39 -0
- package/dist/utils/event-bus.mjs +82 -0
- package/dist/utils/geometry.cjs +178 -0
- package/dist/utils/geometry.d.ts +186 -0
- package/dist/utils/geometry.mjs +144 -0
- package/dist/utils/graph.cjs +158 -0
- package/dist/utils/graph.d.ts +40 -0
- package/dist/utils/graph.mjs +147 -0
- package/dist/utils/index.cjs +137 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.mjs +12 -0
- package/dist/utils/performance.cjs +94 -0
- package/dist/utils/performance.d.ts +18 -0
- package/dist/utils/performance.mjs +82 -0
- package/dist/utils/screenshot.cjs +87 -0
- package/dist/utils/screenshot.d.ts +22 -0
- package/dist/utils/screenshot.mjs +66 -0
- package/dist/utils/theme.cjs +228 -0
- package/dist/utils/theme.d.ts +92 -0
- package/dist/utils/theme.mjs +217 -0
- package/dist/utils/transform.cjs +76 -0
- package/dist/utils/transform.d.ts +45 -0
- package/dist/utils/transform.mjs +57 -0
- package/dist/utils/validation.cjs +107 -0
- package/dist/utils/validation.d.ts +29 -0
- package/dist/utils/validation.mjs +85 -0
- package/package.json +61 -0
package/dist/Flow.vue
ADDED
|
@@ -0,0 +1,959 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="containerRef"
|
|
4
|
+
class="yh-flow"
|
|
5
|
+
:class="{
|
|
6
|
+
'is-readonly': readonly,
|
|
7
|
+
'is-panning': isPanning
|
|
8
|
+
}"
|
|
9
|
+
tabindex="0"
|
|
10
|
+
@wheel.prevent="handleWheel"
|
|
11
|
+
@mousedown="handlePaneMouseDown"
|
|
12
|
+
>
|
|
13
|
+
<!-- Plugin Components (Background, etc.) -->
|
|
14
|
+
<template v-for="plugin in uiPlugins" :key="plugin.id">
|
|
15
|
+
<component v-if="plugin.component" :is="plugin.component" v-bind="plugin.componentProps" />
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<!-- Main Content -->
|
|
19
|
+
<div class="yh-flow__content" :style="contentStyle">
|
|
20
|
+
<!-- Edges -->
|
|
21
|
+
<EdgeRenderer
|
|
22
|
+
:edges="edgesRef || []"
|
|
23
|
+
:nodes="nodesRef || []"
|
|
24
|
+
:edge-types="edgeTypes"
|
|
25
|
+
:transform="viewportRef"
|
|
26
|
+
:connecting-edge="connectingEdge"
|
|
27
|
+
@edge-click="handleEdgeClick"
|
|
28
|
+
@edge-dblclick="handleEdgeDblClick"
|
|
29
|
+
@edge-contextmenu="handleEdgeContextMenu"
|
|
30
|
+
@edge-update-start="handleEdgeUpdateStart"
|
|
31
|
+
:updating-edge-id="updatingEdge?.edge.id"
|
|
32
|
+
>
|
|
33
|
+
<template #edge="edgeProps">
|
|
34
|
+
<slot name="edge" v-bind="edgeProps" />
|
|
35
|
+
</template>
|
|
36
|
+
</EdgeRenderer>
|
|
37
|
+
|
|
38
|
+
<!-- Edge Handles (for updating/reconnecting edges) -->
|
|
39
|
+
<EdgeHandlesRenderer
|
|
40
|
+
:edges="edgesRef || []"
|
|
41
|
+
:nodes="nodesRef || []"
|
|
42
|
+
@edge-update-start="handleEdgeUpdateStart"
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
<!-- Nodes -->
|
|
46
|
+
<NodeRenderer
|
|
47
|
+
:nodes="visibleNodes || []"
|
|
48
|
+
:node-types="nodeTypes"
|
|
49
|
+
:transform="viewportRef"
|
|
50
|
+
:draggable="nodesDraggable && !readonly"
|
|
51
|
+
:readonly="readonly"
|
|
52
|
+
@node-click="handleNodeClick"
|
|
53
|
+
@node-dblclick="handleNodeDblClick"
|
|
54
|
+
@node-contextmenu="handleNodeContextMenu"
|
|
55
|
+
@node-drag-start="handleNodeDragStart"
|
|
56
|
+
@node-drag="handleNodeDrag"
|
|
57
|
+
@node-drag-end="handleNodeDragEnd"
|
|
58
|
+
@connect-start="handleConnectStart"
|
|
59
|
+
@node-select-toggle="handleNodeSelectToggle"
|
|
60
|
+
>
|
|
61
|
+
<template #node="nodeProps">
|
|
62
|
+
<slot name="node" v-bind="nodeProps" />
|
|
63
|
+
</template>
|
|
64
|
+
</NodeRenderer>
|
|
65
|
+
|
|
66
|
+
<!-- Selection Box -->
|
|
67
|
+
<SelectionBox
|
|
68
|
+
:selection-rect="selectionManager.selectionRect.value"
|
|
69
|
+
:transform="viewportRef"
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<!-- UI Overlay Plugin Components (Controls, Minimap, etc.) -->
|
|
74
|
+
<template v-for="plugin in overlayPlugins" :key="plugin.id">
|
|
75
|
+
<component v-if="plugin.component" :is="plugin.component" v-bind="plugin.componentProps" />
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<!-- Connection Line (dragging) -->
|
|
79
|
+
<svg v-if="isConnecting" class="yh-flow__connection-line">
|
|
80
|
+
<path
|
|
81
|
+
:d="connectionLinePath"
|
|
82
|
+
stroke="var(--flow-edge-animated-stroke, #409eff)"
|
|
83
|
+
stroke-width="2"
|
|
84
|
+
fill="none"
|
|
85
|
+
stroke-dasharray="5,5"
|
|
86
|
+
/>
|
|
87
|
+
</svg>
|
|
88
|
+
|
|
89
|
+
<!-- Node Edit Panel -->
|
|
90
|
+
<!-- AI 工作流节点使用 AI 配置面板 -->
|
|
91
|
+
<AiNodeEditPanel
|
|
92
|
+
v-if="editingNode?.type?.startsWith('ai-')"
|
|
93
|
+
:node="editingNode"
|
|
94
|
+
:visible="showNodeEditPanel"
|
|
95
|
+
@update="handleNodeEditUpdate"
|
|
96
|
+
@close="closeNodeEditPanel"
|
|
97
|
+
/>
|
|
98
|
+
<!-- 普通节点使用基础编辑面板 -->
|
|
99
|
+
<NodeEditPanel
|
|
100
|
+
v-else
|
|
101
|
+
:node="editingNode"
|
|
102
|
+
:visible="showNodeEditPanel"
|
|
103
|
+
@update="handleNodeEditUpdate"
|
|
104
|
+
@close="closeNodeEditPanel"
|
|
105
|
+
/>
|
|
106
|
+
|
|
107
|
+
<!-- Edge Edit Panel -->
|
|
108
|
+
<EdgeEditPanel
|
|
109
|
+
:edge="editingEdge"
|
|
110
|
+
:visible="showEdgeEditPanel"
|
|
111
|
+
:edge-types="edgeTypes"
|
|
112
|
+
@update="handleEdgeEditUpdate"
|
|
113
|
+
@close="closeEdgeEditPanel"
|
|
114
|
+
/>
|
|
115
|
+
</div>
|
|
116
|
+
</template>
|
|
117
|
+
|
|
118
|
+
<script setup>
|
|
119
|
+
import { ref, computed, watch, onMounted, onBeforeUnmount, shallowRef } from "vue";
|
|
120
|
+
if (typeof window !== "undefined") window.__YH_FLOW_VERSION__ = "1.0.1";
|
|
121
|
+
import EdgeRenderer from "./renderer/EdgeRenderer.vue";
|
|
122
|
+
import EdgeHandlesRenderer from "./renderer/EdgeHandlesRenderer.vue";
|
|
123
|
+
import NodeRenderer from "./renderer/NodeRenderer.vue";
|
|
124
|
+
import SelectionBox from "./renderer/SelectionBox.vue";
|
|
125
|
+
import NodeEditPanel from "./components/NodeEditPanel.vue";
|
|
126
|
+
import AiNodeEditPanel from "./components/AiNodeEditPanel.vue";
|
|
127
|
+
import EdgeEditPanel from "./components/EdgeEditPanel.vue";
|
|
128
|
+
import {
|
|
129
|
+
createGridPlugin,
|
|
130
|
+
createMiniMapPlugin,
|
|
131
|
+
createControlsPlugin,
|
|
132
|
+
createSnapPlugin,
|
|
133
|
+
createExportPlugin,
|
|
134
|
+
createLayoutPlugin
|
|
135
|
+
} from "./plugins/plugins";
|
|
136
|
+
import { useViewport } from "./core/useViewport";
|
|
137
|
+
import { useNodes } from "./core/useNodes";
|
|
138
|
+
import { useEdges } from "./core/useEdges";
|
|
139
|
+
import { useSelection } from "./core/useSelection";
|
|
140
|
+
import { useHistory } from "./core/useHistory";
|
|
141
|
+
import { useKeyboard } from "./core/useKeyboard";
|
|
142
|
+
import { useAlignment } from "./core/useAlignment";
|
|
143
|
+
import { getEdgePath, getHandlePosition } from "./utils/edge";
|
|
144
|
+
import { screenToCanvas, canvasToScreen } from "./utils/transform";
|
|
145
|
+
import { isValidConnection, detectCycles } from "./utils/validation";
|
|
146
|
+
import {
|
|
147
|
+
createNodeFromTemplate,
|
|
148
|
+
isNestedNode,
|
|
149
|
+
getNodeChildren,
|
|
150
|
+
getNodeParent,
|
|
151
|
+
exportFlowData,
|
|
152
|
+
importFlowData
|
|
153
|
+
} from "./utils/custom-types";
|
|
154
|
+
import { provideFlowContext } from "./core/FlowContext";
|
|
155
|
+
import { createEventBus } from "./utils/event-bus";
|
|
156
|
+
import { PluginManager } from "./plugins/plugin";
|
|
157
|
+
const validateConnection = (sourceNode, targetNode, connection) => {
|
|
158
|
+
const basicResult = isValidConnection(sourceNode, targetNode, connection);
|
|
159
|
+
if (!basicResult.isValid) {
|
|
160
|
+
return basicResult;
|
|
161
|
+
}
|
|
162
|
+
if (props.connectionValidator && !props.connectionValidator(connection)) {
|
|
163
|
+
return { isValid: false, message: "Connection not allowed by custom validator" };
|
|
164
|
+
}
|
|
165
|
+
if (!props.noCycleValidation) {
|
|
166
|
+
const wouldCreateCycle = detectCycles(edgesRef.value, {
|
|
167
|
+
source: connection.source,
|
|
168
|
+
target: connection.target
|
|
169
|
+
});
|
|
170
|
+
if (wouldCreateCycle) {
|
|
171
|
+
return { isValid: false, message: "Connection would create a cycle" };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { isValid: true };
|
|
175
|
+
};
|
|
176
|
+
const props = defineProps({
|
|
177
|
+
nodes: { type: Array, required: false, default: () => [] },
|
|
178
|
+
edges: { type: Array, required: false, default: () => [] },
|
|
179
|
+
modelValue: { type: Object, required: false, default: () => ({ x: 0, y: 0, zoom: 1 }) },
|
|
180
|
+
minZoom: { type: Number, required: false, default: 0.1 },
|
|
181
|
+
maxZoom: { type: Number, required: false, default: 2 },
|
|
182
|
+
zoomStep: { type: Number, required: false, default: 0.1 },
|
|
183
|
+
nodesDraggable: { type: Boolean, required: false, default: true },
|
|
184
|
+
edgesConnectable: { type: Boolean, required: false, default: true },
|
|
185
|
+
selectable: { type: Boolean, required: false, default: true },
|
|
186
|
+
background: { type: String, required: false, default: "none" },
|
|
187
|
+
backgroundColor: { type: String, required: false, default: "transparent" },
|
|
188
|
+
gridSize: { type: Number, required: false, default: 20 },
|
|
189
|
+
snapToGrid: { type: Boolean, required: false, default: false },
|
|
190
|
+
snapGrid: { type: Array, required: false, default: () => [20, 20] },
|
|
191
|
+
readonly: { type: Boolean, required: false, default: false },
|
|
192
|
+
showControls: { type: Boolean, required: false, default: false },
|
|
193
|
+
showMinimap: { type: Boolean, required: false, default: false },
|
|
194
|
+
minimapNodeColor: { type: String, required: false, default: "#cbd5e1" },
|
|
195
|
+
history: { type: Boolean, required: false, default: false },
|
|
196
|
+
maxHistory: { type: Number, required: false, default: 50 },
|
|
197
|
+
keyboardShortcuts: { type: Boolean, required: false, default: true },
|
|
198
|
+
connectionValidator: { type: Function, required: false, default: void 0 },
|
|
199
|
+
noCycleValidation: { type: Boolean, required: false, default: false },
|
|
200
|
+
showAlignmentLines: { type: Boolean, required: false, default: false },
|
|
201
|
+
snapThreshold: { type: Number, required: false, default: 5 },
|
|
202
|
+
customNodeTemplates: { type: Object, required: false, default: () => ({}) },
|
|
203
|
+
nodeTypes: { type: Object, required: false, default: () => ({}) },
|
|
204
|
+
edgeTypes: { type: Object, required: false, default: () => ({}) },
|
|
205
|
+
interactiveMinimap: { type: Boolean, required: false, default: false },
|
|
206
|
+
showLayoutControls: { type: Boolean, required: false, default: false },
|
|
207
|
+
layoutType: { type: String, required: false, default: "none" },
|
|
208
|
+
layoutDirection: { type: String, required: false, default: "TB" },
|
|
209
|
+
enableExport: { type: Boolean, required: false, default: false },
|
|
210
|
+
exportFileName: { type: String, required: false, default: "flow-chart" }
|
|
211
|
+
});
|
|
212
|
+
const emit = defineEmits(["update:modelValue", "update:nodes", "update:edges", "nodeClick", "nodeDblClick", "nodeDragStart", "nodeDrag", "nodeDragEnd", "nodeContextMenu", "edgeClick", "edgeDblClick", "edgeContextMenu", "edgeConnect", "selectionChange", "historyChange", "viewportChange", "edgeUpdate"]);
|
|
213
|
+
const containerRef = ref();
|
|
214
|
+
const containerWidth = ref(800);
|
|
215
|
+
const containerHeight = ref(600);
|
|
216
|
+
const nodesRef = ref(props.nodes || []);
|
|
217
|
+
const edgesRef = ref(props.edges || []);
|
|
218
|
+
const viewportRef = shallowRef(props.modelValue || { x: 0, y: 0, zoom: 1 });
|
|
219
|
+
const readonly = ref(props.readonly || false);
|
|
220
|
+
const eventBus = createEventBus();
|
|
221
|
+
const pluginManager = new PluginManager();
|
|
222
|
+
const snapThreshold = ref(props.snapThreshold ?? 10);
|
|
223
|
+
const viewport = useViewport(viewportRef, {
|
|
224
|
+
minZoom: props.minZoom || 0.1,
|
|
225
|
+
maxZoom: props.maxZoom || 5,
|
|
226
|
+
zoomStep: props.zoomStep || 0.1
|
|
227
|
+
});
|
|
228
|
+
const registeredPlugins = ref([]);
|
|
229
|
+
const uiPlugins = computed(
|
|
230
|
+
() => registeredPlugins.value.filter((p) => !p.id.includes("minimap") && !p.id.includes("controls"))
|
|
231
|
+
);
|
|
232
|
+
const overlayPlugins = computed(
|
|
233
|
+
() => registeredPlugins.value.filter((p) => p.id.includes("minimap") || p.id.includes("controls"))
|
|
234
|
+
);
|
|
235
|
+
const usePlugin = (plugin) => {
|
|
236
|
+
pluginManager.register(plugin);
|
|
237
|
+
registeredPlugins.value = pluginManager.getPlugins();
|
|
238
|
+
};
|
|
239
|
+
const removePlugin = (pluginId) => {
|
|
240
|
+
pluginManager.unregister(pluginId);
|
|
241
|
+
registeredPlugins.value = pluginManager.getPlugins();
|
|
242
|
+
};
|
|
243
|
+
const nodesManager = useNodes(viewportRef, {
|
|
244
|
+
nodes: nodesRef,
|
|
245
|
+
snapToGrid: props.snapToGrid || false,
|
|
246
|
+
snapGrid: props.snapGrid || [15, 15]
|
|
247
|
+
});
|
|
248
|
+
const edgesManager = useEdges({
|
|
249
|
+
edges: edgesRef,
|
|
250
|
+
nodes: nodesRef
|
|
251
|
+
});
|
|
252
|
+
const selectionManager = useSelection({
|
|
253
|
+
nodes: nodesRef,
|
|
254
|
+
edges: edgesRef
|
|
255
|
+
});
|
|
256
|
+
const historyManager = useHistory(nodesRef, edgesRef, {
|
|
257
|
+
maxHistory: props.maxHistory || 50,
|
|
258
|
+
onHistoryChange: (canUndo, canRedo) => {
|
|
259
|
+
emit("historyChange", { canUndo, canRedo });
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
const alignmentManager = useAlignment({
|
|
263
|
+
nodes: nodesRef,
|
|
264
|
+
snapThreshold: snapThreshold.value
|
|
265
|
+
});
|
|
266
|
+
const visibleNodes = computed(() => {
|
|
267
|
+
if (!containerRef.value) return nodesRef.value;
|
|
268
|
+
const padding = 100;
|
|
269
|
+
const visibleBounds = {
|
|
270
|
+
x: -viewportRef.value.x / viewportRef.value.zoom - padding,
|
|
271
|
+
y: -viewportRef.value.y / viewportRef.value.zoom - padding,
|
|
272
|
+
width: containerWidth.value / viewportRef.value.zoom + padding * 2,
|
|
273
|
+
height: containerHeight.value / viewportRef.value.zoom + padding * 2
|
|
274
|
+
};
|
|
275
|
+
return nodesRef.value.filter((node) => {
|
|
276
|
+
const width = node.width || 200;
|
|
277
|
+
const height = node.height || 50;
|
|
278
|
+
return !(node.position.x + width < visibleBounds.x || node.position.x > visibleBounds.x + visibleBounds.width || node.position.y + height < visibleBounds.y || node.position.y > visibleBounds.y + visibleBounds.height);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
const contentStyle = computed(() => ({
|
|
282
|
+
transform: `translate(${viewportRef.value.x}px, ${viewportRef.value.y}px) scale(${viewportRef.value.zoom})`,
|
|
283
|
+
transformOrigin: "0 0"
|
|
284
|
+
}));
|
|
285
|
+
const isPanning = ref(false);
|
|
286
|
+
const panStart = ref({ x: 0, y: 0 });
|
|
287
|
+
const isSelecting = ref(false);
|
|
288
|
+
const draggingNodeId = ref(null);
|
|
289
|
+
const draggingPosition = ref(null);
|
|
290
|
+
const isConnecting = ref(false);
|
|
291
|
+
const connectionStart = ref(null);
|
|
292
|
+
const connectionEnd = ref({ x: 0, y: 0 });
|
|
293
|
+
const updatingEdge = ref(null);
|
|
294
|
+
const showNodeEditPanel = ref(false);
|
|
295
|
+
const editingNode = ref(null);
|
|
296
|
+
const showEdgeEditPanel = ref(false);
|
|
297
|
+
const editingEdge = ref(null);
|
|
298
|
+
const connectingEdge = computed(() => {
|
|
299
|
+
if (!isConnecting.value || !connectionStart.value) return null;
|
|
300
|
+
return {
|
|
301
|
+
path: connectionLinePath.value,
|
|
302
|
+
tx: connectionEnd.value.x,
|
|
303
|
+
ty: connectionEnd.value.y
|
|
304
|
+
};
|
|
305
|
+
});
|
|
306
|
+
const connectionLinePath = computed(() => {
|
|
307
|
+
if (!connectionStart.value) return "";
|
|
308
|
+
return getEdgePath("bezier", {
|
|
309
|
+
sourceX: connectionStart.value.x * viewportRef.value.zoom + viewportRef.value.x,
|
|
310
|
+
sourceY: connectionStart.value.y * viewportRef.value.zoom + viewportRef.value.y,
|
|
311
|
+
targetX: connectionEnd.value.x,
|
|
312
|
+
targetY: connectionEnd.value.y,
|
|
313
|
+
sourcePosition: connectionStart.value.position,
|
|
314
|
+
targetPosition: "left"
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
const handleWheel = (event) => {
|
|
318
|
+
event.preventDefault();
|
|
319
|
+
const delta = event.deltaY > 0 ? 0.9 : 1.1;
|
|
320
|
+
const rect = containerRef.value?.getBoundingClientRect();
|
|
321
|
+
if (rect) {
|
|
322
|
+
viewport.zoomTo(viewportRef.value.zoom * delta, {
|
|
323
|
+
x: event.clientX - rect.left,
|
|
324
|
+
y: event.clientY - rect.top
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
const handlePaneMouseDown = (event) => {
|
|
329
|
+
const target = event.target;
|
|
330
|
+
if (!containerRef.value?.contains(target)) return;
|
|
331
|
+
if (target.closest(".yh-flow-node")) return;
|
|
332
|
+
if (target.closest(".yh-flow-handle")) return;
|
|
333
|
+
if (target.closest(".yh-flow-edge-group")) return;
|
|
334
|
+
if (target.closest(".yh-flow__connection-line")) return;
|
|
335
|
+
if (target.closest(".yh-flow-controls")) return;
|
|
336
|
+
if (target.closest(".yh-flow-minimap")) return;
|
|
337
|
+
const rect = containerRef.value?.getBoundingClientRect();
|
|
338
|
+
if (!rect) return;
|
|
339
|
+
const mouseX = event.clientX - rect.left;
|
|
340
|
+
const mouseY = event.clientY - rect.top;
|
|
341
|
+
if (event.altKey && props.selectable && !readonly.value) {
|
|
342
|
+
const canvasPos = {
|
|
343
|
+
x: (mouseX - viewportRef.value.x) / viewportRef.value.zoom,
|
|
344
|
+
y: (mouseY - viewportRef.value.y) / viewportRef.value.zoom
|
|
345
|
+
};
|
|
346
|
+
isSelecting.value = true;
|
|
347
|
+
selectionManager.startSelection(canvasPos.x, canvasPos.y);
|
|
348
|
+
selectionManager.clearSelection();
|
|
349
|
+
} else if (!readonly.value) {
|
|
350
|
+
isPanning.value = true;
|
|
351
|
+
panStart.value = { x: event.clientX, y: event.clientY };
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
const handleMouseMove = (event) => {
|
|
355
|
+
if (isPanning.value) {
|
|
356
|
+
const dx = event.clientX - panStart.value.x;
|
|
357
|
+
const dy = event.clientY - panStart.value.y;
|
|
358
|
+
viewport.pan(dx, dy);
|
|
359
|
+
panStart.value = { x: event.clientX, y: event.clientY };
|
|
360
|
+
}
|
|
361
|
+
if (isSelecting.value) {
|
|
362
|
+
const rect = containerRef.value?.getBoundingClientRect();
|
|
363
|
+
if (rect) {
|
|
364
|
+
const mouseX = event.clientX - rect.left;
|
|
365
|
+
const mouseY = event.clientY - rect.top;
|
|
366
|
+
const canvasPos = {
|
|
367
|
+
x: (mouseX - viewportRef.value.x) / viewportRef.value.zoom,
|
|
368
|
+
y: (mouseY - viewportRef.value.y) / viewportRef.value.zoom
|
|
369
|
+
};
|
|
370
|
+
selectionManager.updateSelection(canvasPos.x, canvasPos.y);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (isConnecting.value) {
|
|
374
|
+
const rect = containerRef.value?.getBoundingClientRect();
|
|
375
|
+
if (rect) {
|
|
376
|
+
connectionEnd.value = {
|
|
377
|
+
x: event.clientX - rect.left,
|
|
378
|
+
y: event.clientY - rect.top
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
const handleMouseUp = (event) => {
|
|
384
|
+
isPanning.value = false;
|
|
385
|
+
if (isSelecting.value) {
|
|
386
|
+
isSelecting.value = false;
|
|
387
|
+
selectionManager.endSelection();
|
|
388
|
+
}
|
|
389
|
+
if (isConnecting.value && connectionStart.value) {
|
|
390
|
+
const rect = containerRef.value?.getBoundingClientRect();
|
|
391
|
+
if (rect) {
|
|
392
|
+
const mouseX = event.clientX - rect.left;
|
|
393
|
+
const mouseY = event.clientY - rect.top;
|
|
394
|
+
const canvasPos = {
|
|
395
|
+
x: (mouseX - viewportRef.value.x) / viewportRef.value.zoom,
|
|
396
|
+
y: (mouseY - viewportRef.value.y) / viewportRef.value.zoom
|
|
397
|
+
};
|
|
398
|
+
const targetNode = findTargetNode(canvasPos);
|
|
399
|
+
if (targetNode) {
|
|
400
|
+
const sourceNodeId = updatingEdge.value ? updatingEdge.value.handleType === "source" ? targetNode.id : updatingEdge.value.edge.source : connectionStart.value.nodeId;
|
|
401
|
+
const targetNodeId = updatingEdge.value ? updatingEdge.value.handleType === "target" ? targetNode.id : updatingEdge.value.edge.target : targetNode.id;
|
|
402
|
+
const sourceNode = nodesRef.value.find((n) => n.id === sourceNodeId);
|
|
403
|
+
const validationResult = validateConnection(
|
|
404
|
+
sourceNode,
|
|
405
|
+
nodesRef.value.find((n) => n.id === targetNodeId),
|
|
406
|
+
{
|
|
407
|
+
source: sourceNodeId,
|
|
408
|
+
target: targetNodeId,
|
|
409
|
+
sourceHandle: updatingEdge.value && updatingEdge.value.handleType === "source" ? void 0 : updatingEdge.value?.edge.sourceHandle || connectionStart.value?.handleId,
|
|
410
|
+
targetHandle: updatingEdge.value && updatingEdge.value.handleType === "target" ? void 0 : updatingEdge.value?.edge.targetHandle
|
|
411
|
+
}
|
|
412
|
+
);
|
|
413
|
+
if (!validationResult.isValid) {
|
|
414
|
+
console.warn("Invalid connection:", validationResult.message);
|
|
415
|
+
isConnecting.value = false;
|
|
416
|
+
connectionStart.value = null;
|
|
417
|
+
updatingEdge.value = null;
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
if (updatingEdge.value) {
|
|
421
|
+
const { edge, handleType } = updatingEdge.value;
|
|
422
|
+
const connection = {
|
|
423
|
+
source: handleType === "source" ? targetNode.id : edge.source,
|
|
424
|
+
target: handleType === "target" ? targetNode.id : edge.target,
|
|
425
|
+
sourceHandle: handleType === "source" ? void 0 : edge.sourceHandle,
|
|
426
|
+
targetHandle: handleType === "target" ? void 0 : edge.targetHandle
|
|
427
|
+
};
|
|
428
|
+
edgesManager.updateEdge(edge.id, connection);
|
|
429
|
+
emit("edgeUpdate", { edge, connection });
|
|
430
|
+
eventBus.emit("edge:update", { edge, connection });
|
|
431
|
+
} else {
|
|
432
|
+
const newEdge = {
|
|
433
|
+
id: `edge-${Date.now()}`,
|
|
434
|
+
source: connectionStart.value.nodeId,
|
|
435
|
+
target: targetNode.id,
|
|
436
|
+
sourceHandle: connectionStart.value.handleId || void 0,
|
|
437
|
+
targetHandle: void 0,
|
|
438
|
+
type: "bezier"
|
|
439
|
+
};
|
|
440
|
+
edgesManager.addEdge(newEdge);
|
|
441
|
+
emit("edgeConnect", {
|
|
442
|
+
source: newEdge.source,
|
|
443
|
+
target: newEdge.target,
|
|
444
|
+
sourceHandle: newEdge.sourceHandle,
|
|
445
|
+
targetHandle: newEdge.targetHandle
|
|
446
|
+
});
|
|
447
|
+
eventBus.emit("edge:connect", {
|
|
448
|
+
connection: {
|
|
449
|
+
source: newEdge.source,
|
|
450
|
+
target: newEdge.target,
|
|
451
|
+
sourceHandle: newEdge.sourceHandle,
|
|
452
|
+
targetHandle: newEdge.targetHandle
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
isConnecting.value = false;
|
|
459
|
+
connectionStart.value = null;
|
|
460
|
+
updatingEdge.value = null;
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
const findTargetNode = (canvasPos) => {
|
|
464
|
+
for (const node of nodesRef.value) {
|
|
465
|
+
const width = node.width || 200;
|
|
466
|
+
const height = node.height || 50;
|
|
467
|
+
if (canvasPos.x >= node.position.x && canvasPos.x <= node.position.x + width && canvasPos.y >= node.position.y && canvasPos.y <= node.position.y + height) {
|
|
468
|
+
if (connectionStart.value && node.id !== connectionStart.value.nodeId) {
|
|
469
|
+
return node;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return null;
|
|
474
|
+
};
|
|
475
|
+
const handleNodeClick = (event, node) => {
|
|
476
|
+
const multi = event.shiftKey || event.metaKey || event.ctrlKey;
|
|
477
|
+
if (!multi) edgesManager.clearSelection();
|
|
478
|
+
nodesManager.selectNode(node.id, true, multi);
|
|
479
|
+
emit("nodeClick", { node, nativeEvent: event });
|
|
480
|
+
eventBus.emit("node:click", { node, nativeEvent: event });
|
|
481
|
+
};
|
|
482
|
+
const handleNodeSelectToggle = (nodeId) => {
|
|
483
|
+
const node = nodesRef.value.find((n) => n.id === nodeId);
|
|
484
|
+
if (node) {
|
|
485
|
+
node.selected = !node.selected;
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
const handleNodeDblClick = (event, node) => {
|
|
489
|
+
emit("nodeDblClick", { node, nativeEvent: event });
|
|
490
|
+
eventBus.emit("node:dblclick", { node, nativeEvent: event });
|
|
491
|
+
if (!readonly.value) {
|
|
492
|
+
showEdgeEditPanel.value = false;
|
|
493
|
+
editingNode.value = node;
|
|
494
|
+
showNodeEditPanel.value = true;
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
const handleNodeContextMenu = (event, node) => {
|
|
498
|
+
emit("nodeContextMenu", { node, nativeEvent: event });
|
|
499
|
+
eventBus.emit("node:contextmenu", { node, nativeEvent: event });
|
|
500
|
+
};
|
|
501
|
+
const handleNodeDragStart = (event, node) => {
|
|
502
|
+
historyManager.push({ nodes: nodesRef.value, edges: edgesRef.value });
|
|
503
|
+
draggingNodeId.value = node.id;
|
|
504
|
+
draggingPosition.value = { ...node.position };
|
|
505
|
+
emit("nodeDragStart", { node, nativeEvent: event });
|
|
506
|
+
eventBus.emit("node:dragstart", { node, nativeEvent: event });
|
|
507
|
+
};
|
|
508
|
+
const handleNodeDrag = (event, node, position) => {
|
|
509
|
+
const snappedPosition = alignmentManager.getAlignmentSnap(node.id, position);
|
|
510
|
+
nodesManager.updateNodePosition(node.id, snappedPosition, { dragging: true });
|
|
511
|
+
draggingPosition.value = snappedPosition;
|
|
512
|
+
emit("nodeDrag", { node, nativeEvent: event, position: snappedPosition });
|
|
513
|
+
eventBus.emit("node:drag", { node, nativeEvent: event, position: snappedPosition });
|
|
514
|
+
emit("update:nodes", nodesRef.value);
|
|
515
|
+
};
|
|
516
|
+
const handleNodeDragEnd = (event, node) => {
|
|
517
|
+
nodesManager.updateNodePosition(node.id, node.position, { dragging: false });
|
|
518
|
+
draggingNodeId.value = null;
|
|
519
|
+
draggingPosition.value = null;
|
|
520
|
+
emit("nodeDragEnd", { node, nativeEvent: event });
|
|
521
|
+
eventBus.emit("node:dragend", { node, nativeEvent: event });
|
|
522
|
+
emit("update:nodes", nodesRef.value);
|
|
523
|
+
emit("update:edges", edgesRef.value);
|
|
524
|
+
};
|
|
525
|
+
const handleEdgeClick = (event, edge) => {
|
|
526
|
+
console.log("Edge click:", edge.id);
|
|
527
|
+
event.stopPropagation();
|
|
528
|
+
if (!event.ctrlKey && !event.metaKey && !event.shiftKey) {
|
|
529
|
+
edgesRef.value.forEach((e) => {
|
|
530
|
+
if (e.id !== edge.id) e.selected = false;
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
edge.selected = !edge.selected;
|
|
534
|
+
emit("edgeClick", { edge, nativeEvent: event });
|
|
535
|
+
if (!readonly.value) {
|
|
536
|
+
showNodeEditPanel.value = false;
|
|
537
|
+
editingEdge.value = edge;
|
|
538
|
+
showEdgeEditPanel.value = true;
|
|
539
|
+
}
|
|
540
|
+
eventBus.emit("edge:click", { edge, nativeEvent: event });
|
|
541
|
+
};
|
|
542
|
+
const handleEdgeDblClick = (event, edge) => {
|
|
543
|
+
console.log("Edge dblclick:", edge.id);
|
|
544
|
+
emit("edgeDblClick", { edge, nativeEvent: event });
|
|
545
|
+
eventBus.emit("edge:dblclick", { edge, nativeEvent: event });
|
|
546
|
+
if (!readonly.value) {
|
|
547
|
+
showNodeEditPanel.value = false;
|
|
548
|
+
editingEdge.value = edge;
|
|
549
|
+
showEdgeEditPanel.value = true;
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
const handleEdgeContextMenu = (event, edge) => {
|
|
553
|
+
emit("edgeContextMenu", { edge, nativeEvent: event });
|
|
554
|
+
eventBus.emit("edge:contextmenu", { edge, nativeEvent: event });
|
|
555
|
+
};
|
|
556
|
+
const handleEdgeUpdateStart = (event, edge, handleType) => {
|
|
557
|
+
if (readonly.value) return;
|
|
558
|
+
const rect = containerRef.value?.getBoundingClientRect();
|
|
559
|
+
if (!rect) return;
|
|
560
|
+
updatingEdge.value = { edge, handleType };
|
|
561
|
+
const anchorNodeId = handleType === "source" ? edge.target : edge.source;
|
|
562
|
+
const anchorHandleId = handleType === "source" ? edge.targetHandle : edge.sourceHandle;
|
|
563
|
+
const node = nodesRef.value.find((n) => n.id === anchorNodeId);
|
|
564
|
+
if (!node) return;
|
|
565
|
+
const position = handleType === "source" ? anchorHandleId ?? "left" : anchorHandleId ?? "right";
|
|
566
|
+
const startPos = getHandlePosition(node, position, anchorHandleId);
|
|
567
|
+
isConnecting.value = true;
|
|
568
|
+
connectionStart.value = {
|
|
569
|
+
nodeId: anchorNodeId,
|
|
570
|
+
handleId: anchorHandleId || "",
|
|
571
|
+
handleType: handleType === "source" ? "target" : "source",
|
|
572
|
+
// 反转类型
|
|
573
|
+
position,
|
|
574
|
+
x: startPos.x,
|
|
575
|
+
y: startPos.y
|
|
576
|
+
};
|
|
577
|
+
connectionEnd.value = {
|
|
578
|
+
x: event.clientX - rect.left,
|
|
579
|
+
y: event.clientY - rect.top
|
|
580
|
+
};
|
|
581
|
+
};
|
|
582
|
+
const handleConnectStart = (event, nodeId, handleId, handleType) => {
|
|
583
|
+
const node = nodesRef.value.find((n) => n.id === nodeId);
|
|
584
|
+
if (!node) return;
|
|
585
|
+
const rect = containerRef.value?.getBoundingClientRect();
|
|
586
|
+
if (!rect) return;
|
|
587
|
+
const position = handleId || (handleType === "source" ? "right" : "left");
|
|
588
|
+
const startPos = getHandlePosition(node, position, handleId);
|
|
589
|
+
isConnecting.value = true;
|
|
590
|
+
connectionStart.value = {
|
|
591
|
+
nodeId,
|
|
592
|
+
handleId,
|
|
593
|
+
handleType,
|
|
594
|
+
position,
|
|
595
|
+
x: startPos.x,
|
|
596
|
+
y: startPos.y
|
|
597
|
+
};
|
|
598
|
+
connectionEnd.value = {
|
|
599
|
+
x: event.clientX - rect.left,
|
|
600
|
+
y: event.clientY - rect.top
|
|
601
|
+
};
|
|
602
|
+
};
|
|
603
|
+
const handleNodeEditUpdate = (updates) => {
|
|
604
|
+
if (editingNode.value) {
|
|
605
|
+
historyManager.push({ nodes: nodesRef.value, edges: edgesRef.value });
|
|
606
|
+
nodesManager.updateNode(editingNode.value.id, updates);
|
|
607
|
+
editingNode.value = nodesRef.value.find((n) => n.id === editingNode.value?.id) || null;
|
|
608
|
+
emit("update:nodes", nodesRef.value);
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
const closeNodeEditPanel = () => {
|
|
612
|
+
showNodeEditPanel.value = false;
|
|
613
|
+
editingNode.value = null;
|
|
614
|
+
};
|
|
615
|
+
const handleEdgeEditUpdate = (updates) => {
|
|
616
|
+
if (editingEdge.value) {
|
|
617
|
+
historyManager.push({ nodes: nodesRef.value, edges: edgesRef.value });
|
|
618
|
+
edgesManager.updateEdge(editingEdge.value.id, updates);
|
|
619
|
+
editingEdge.value = edgesRef.value.find((e) => e.id === editingEdge.value?.id) || null;
|
|
620
|
+
emit("update:edges", edgesRef.value);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
const closeEdgeEditPanel = () => {
|
|
624
|
+
showEdgeEditPanel.value = false;
|
|
625
|
+
editingEdge.value = null;
|
|
626
|
+
};
|
|
627
|
+
const getNodes = () => nodesRef.value;
|
|
628
|
+
const getEdges = () => edgesRef.value;
|
|
629
|
+
const onEvent = (event, handler) => {
|
|
630
|
+
eventBus.on(event, handler);
|
|
631
|
+
};
|
|
632
|
+
const offEvent = (event, handler) => {
|
|
633
|
+
eventBus.off(event, handler);
|
|
634
|
+
};
|
|
635
|
+
const emitEvent = (event, payload) => {
|
|
636
|
+
eventBus.emit(event, payload);
|
|
637
|
+
};
|
|
638
|
+
const flowInstance = {
|
|
639
|
+
nodes: nodesRef,
|
|
640
|
+
edges: edgesRef,
|
|
641
|
+
viewport: viewportRef,
|
|
642
|
+
addNode: nodesManager.addNode,
|
|
643
|
+
removeNode: nodesManager.removeNode,
|
|
644
|
+
updateNode: nodesManager.updateNode,
|
|
645
|
+
getNode: nodesManager.getNode,
|
|
646
|
+
addEdge: edgesManager.addEdge,
|
|
647
|
+
removeEdge: edgesManager.removeEdge,
|
|
648
|
+
updateEdge: edgesManager.updateEdge,
|
|
649
|
+
getEdge: edgesManager.getEdge,
|
|
650
|
+
setViewport: (transform) => viewport.setViewport(transform.x, transform.y, transform.zoom),
|
|
651
|
+
fitView: (options) => viewport.fitView(
|
|
652
|
+
{ width: containerWidth.value, height: containerHeight.value },
|
|
653
|
+
nodesRef.value,
|
|
654
|
+
options
|
|
655
|
+
),
|
|
656
|
+
zoomIn: viewport.zoomIn,
|
|
657
|
+
zoomOut: viewport.zoomOut,
|
|
658
|
+
centerView: viewport.center,
|
|
659
|
+
selectNode: nodesManager.selectNode,
|
|
660
|
+
selectEdge: edgesManager.selectEdge,
|
|
661
|
+
clearSelection: selectionManager.clearSelection,
|
|
662
|
+
on: onEvent,
|
|
663
|
+
off: offEvent,
|
|
664
|
+
emit: emitEvent,
|
|
665
|
+
isValidConnection: (connection) => isValidConnection(
|
|
666
|
+
nodesRef.value.find((n) => n.id === connection.source),
|
|
667
|
+
nodesRef.value.find((n) => n.id === connection.target),
|
|
668
|
+
connection
|
|
669
|
+
).isValid,
|
|
670
|
+
getNodes,
|
|
671
|
+
getEdges,
|
|
672
|
+
getViewport: () => viewportRef.value,
|
|
673
|
+
screenToCanvas: (x, y) => screenToCanvas(x, y, viewportRef.value),
|
|
674
|
+
canvasToScreen: (x, y) => canvasToScreen(x, y, viewportRef.value),
|
|
675
|
+
// ============================================
|
|
676
|
+
// New 5-star feature methods
|
|
677
|
+
// ============================================
|
|
678
|
+
createNodeFromTemplate: (type, id, position, overrides) => createNodeFromTemplate(type, id, position, overrides),
|
|
679
|
+
exportFlowData: (viewport2) => exportFlowData(nodesRef.value, edgesRef.value, viewport2),
|
|
680
|
+
importFlowData: (json) => importFlowData(json),
|
|
681
|
+
isNestedNode: (node) => isNestedNode(node),
|
|
682
|
+
getNodeChildren: (node) => getNodeChildren(node, nodesRef.value),
|
|
683
|
+
getNodeParent: (node) => getNodeParent(node, nodesRef.value),
|
|
684
|
+
get $el() {
|
|
685
|
+
return containerRef.value;
|
|
686
|
+
},
|
|
687
|
+
draggingNodeId,
|
|
688
|
+
draggingPosition,
|
|
689
|
+
isLocked: readonly,
|
|
690
|
+
setInteractive: (interactive) => {
|
|
691
|
+
readonly.value = !interactive;
|
|
692
|
+
},
|
|
693
|
+
usePlugin,
|
|
694
|
+
removePlugin,
|
|
695
|
+
// Placeholders for plugin methods to be exposed via defineExpose
|
|
696
|
+
exportJson: void 0,
|
|
697
|
+
exportImage: void 0,
|
|
698
|
+
applyLayout: void 0
|
|
699
|
+
};
|
|
700
|
+
provideFlowContext(flowInstance);
|
|
701
|
+
pluginManager.init(flowInstance);
|
|
702
|
+
defineExpose(flowInstance);
|
|
703
|
+
watch(
|
|
704
|
+
() => props.nodes,
|
|
705
|
+
(newNodes) => {
|
|
706
|
+
if (draggingNodeId.value) return;
|
|
707
|
+
nodesRef.value = newNodes || [];
|
|
708
|
+
},
|
|
709
|
+
{ deep: true }
|
|
710
|
+
);
|
|
711
|
+
watch(
|
|
712
|
+
() => props.edges,
|
|
713
|
+
(newEdges) => {
|
|
714
|
+
edgesRef.value = newEdges || [];
|
|
715
|
+
},
|
|
716
|
+
{ deep: true }
|
|
717
|
+
);
|
|
718
|
+
const prevSelectedNodeIds = ref(/* @__PURE__ */ new Set());
|
|
719
|
+
const prevSelectedEdgeIds = ref(/* @__PURE__ */ new Set());
|
|
720
|
+
watch(
|
|
721
|
+
[nodesRef, edgesRef],
|
|
722
|
+
([nodes, edges]) => {
|
|
723
|
+
const selectedNodes = nodes.filter((n) => n.selected);
|
|
724
|
+
const selectedEdges = edges.filter((e) => e.selected);
|
|
725
|
+
const nextNodeIds = new Set(selectedNodes.map((n) => n.id));
|
|
726
|
+
const nextEdgeIds = new Set(selectedEdges.map((e) => e.id));
|
|
727
|
+
for (const id of nextNodeIds) {
|
|
728
|
+
if (!prevSelectedNodeIds.value.has(id)) {
|
|
729
|
+
const node = nodes.find((n) => n.id === id);
|
|
730
|
+
if (node) eventBus.emit("node:selected", { node });
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
for (const id of prevSelectedNodeIds.value) {
|
|
734
|
+
if (!nextNodeIds.has(id)) {
|
|
735
|
+
const node = nodes.find((n) => n.id === id);
|
|
736
|
+
if (node) eventBus.emit("node:unselected", { node });
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
for (const id of nextEdgeIds) {
|
|
740
|
+
if (!prevSelectedEdgeIds.value.has(id)) {
|
|
741
|
+
const edge = edges.find((e) => e.id === id);
|
|
742
|
+
if (edge) eventBus.emit("edge:selected", { edge });
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
for (const id of prevSelectedEdgeIds.value) {
|
|
746
|
+
if (!nextEdgeIds.has(id)) {
|
|
747
|
+
const edge = edges.find((e) => e.id === id);
|
|
748
|
+
if (edge) eventBus.emit("edge:unselected", { edge });
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
eventBus.emit("selection:change", { selectedNodes, selectedEdges });
|
|
752
|
+
emit("selectionChange", { selectedNodes, selectedEdges });
|
|
753
|
+
emit("update:nodes", nodes);
|
|
754
|
+
emit("update:edges", edges);
|
|
755
|
+
prevSelectedNodeIds.value = nextNodeIds;
|
|
756
|
+
prevSelectedEdgeIds.value = nextEdgeIds;
|
|
757
|
+
},
|
|
758
|
+
{ deep: true }
|
|
759
|
+
);
|
|
760
|
+
watch(
|
|
761
|
+
viewportRef,
|
|
762
|
+
(newViewport) => {
|
|
763
|
+
emit("update:modelValue", newViewport);
|
|
764
|
+
emit("viewportChange", newViewport);
|
|
765
|
+
eventBus.emit("viewport:change", { transform: newViewport });
|
|
766
|
+
},
|
|
767
|
+
{ deep: true }
|
|
768
|
+
);
|
|
769
|
+
let handleKeyDown;
|
|
770
|
+
onMounted(() => {
|
|
771
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
772
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
773
|
+
if (containerRef.value) {
|
|
774
|
+
containerWidth.value = containerRef.value.clientWidth;
|
|
775
|
+
containerHeight.value = containerRef.value.clientHeight;
|
|
776
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
|
777
|
+
for (const entry of entries) {
|
|
778
|
+
containerWidth.value = entry.contentRect.width;
|
|
779
|
+
containerHeight.value = entry.contentRect.height;
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
resizeObserver.observe(containerRef.value);
|
|
783
|
+
}
|
|
784
|
+
if (props.background && props.background !== "none") {
|
|
785
|
+
usePlugin(
|
|
786
|
+
createGridPlugin({
|
|
787
|
+
type: props.background === "dots" ? "dots" : "grid",
|
|
788
|
+
color: props.backgroundColor,
|
|
789
|
+
gap: props.gridSize
|
|
790
|
+
})
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
if (props.showControls) {
|
|
794
|
+
usePlugin(createControlsPlugin({}));
|
|
795
|
+
}
|
|
796
|
+
if (props.showMinimap) {
|
|
797
|
+
usePlugin(
|
|
798
|
+
createMiniMapPlugin({
|
|
799
|
+
nodeColor: props.minimapNodeColor ? () => props.minimapNodeColor : void 0,
|
|
800
|
+
interactive: props.interactiveMinimap,
|
|
801
|
+
showLayoutControls: props.showLayoutControls,
|
|
802
|
+
layoutType: props.layoutType,
|
|
803
|
+
layoutDirection: props.layoutDirection
|
|
804
|
+
})
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
if (props.showAlignmentLines) {
|
|
808
|
+
usePlugin(
|
|
809
|
+
createSnapPlugin({
|
|
810
|
+
showAlignmentLines: true,
|
|
811
|
+
snapThreshold: props.snapThreshold
|
|
812
|
+
})
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
if (props.enableExport) {
|
|
816
|
+
usePlugin(
|
|
817
|
+
createExportPlugin({
|
|
818
|
+
fileName: props.exportFileName,
|
|
819
|
+
enabled: true
|
|
820
|
+
})
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
if (props.layoutType && props.layoutType !== "none") {
|
|
824
|
+
usePlugin(
|
|
825
|
+
createLayoutPlugin({
|
|
826
|
+
type: props.layoutType,
|
|
827
|
+
direction: props.layoutDirection
|
|
828
|
+
})
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
watch(
|
|
832
|
+
() => [props.background, props.backgroundColor, props.gridSize],
|
|
833
|
+
([bg, color, gap]) => {
|
|
834
|
+
removePlugin("grid");
|
|
835
|
+
if (bg && bg !== "none") {
|
|
836
|
+
usePlugin(
|
|
837
|
+
createGridPlugin({
|
|
838
|
+
type: bg === "dots" ? "dots" : "grid",
|
|
839
|
+
color,
|
|
840
|
+
gap: gap || 20
|
|
841
|
+
})
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
);
|
|
846
|
+
watch(
|
|
847
|
+
() => props.showControls,
|
|
848
|
+
(val) => {
|
|
849
|
+
removePlugin("controls");
|
|
850
|
+
if (val) usePlugin(createControlsPlugin({}));
|
|
851
|
+
}
|
|
852
|
+
);
|
|
853
|
+
watch(
|
|
854
|
+
() => [
|
|
855
|
+
props.showMinimap,
|
|
856
|
+
props.minimapNodeColor,
|
|
857
|
+
props.interactiveMinimap,
|
|
858
|
+
props.showLayoutControls,
|
|
859
|
+
props.layoutType,
|
|
860
|
+
props.layoutDirection
|
|
861
|
+
],
|
|
862
|
+
([show, color, interactive, showLayout, type, dir]) => {
|
|
863
|
+
removePlugin("minimap");
|
|
864
|
+
if (show) {
|
|
865
|
+
usePlugin(
|
|
866
|
+
createMiniMapPlugin({
|
|
867
|
+
nodeColor: color ? () => color : void 0,
|
|
868
|
+
interactive,
|
|
869
|
+
showLayoutControls: showLayout,
|
|
870
|
+
layoutType: type,
|
|
871
|
+
layoutDirection: dir
|
|
872
|
+
})
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
);
|
|
877
|
+
watch(
|
|
878
|
+
() => [props.showAlignmentLines, props.snapThreshold],
|
|
879
|
+
([show, threshold]) => {
|
|
880
|
+
removePlugin("snap");
|
|
881
|
+
if (show) {
|
|
882
|
+
usePlugin(
|
|
883
|
+
createSnapPlugin({
|
|
884
|
+
showAlignmentLines: true,
|
|
885
|
+
snapThreshold: threshold || 10
|
|
886
|
+
})
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
);
|
|
891
|
+
watch(
|
|
892
|
+
() => [props.enableExport, props.exportFileName],
|
|
893
|
+
([enable, fileName]) => {
|
|
894
|
+
removePlugin("export");
|
|
895
|
+
if (enable) {
|
|
896
|
+
usePlugin(
|
|
897
|
+
createExportPlugin({
|
|
898
|
+
fileName,
|
|
899
|
+
enabled: true
|
|
900
|
+
})
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
);
|
|
905
|
+
watch(
|
|
906
|
+
() => [props.layoutType, props.layoutDirection],
|
|
907
|
+
([type, dir]) => {
|
|
908
|
+
removePlugin("layout");
|
|
909
|
+
if (type && type !== "none") {
|
|
910
|
+
usePlugin(
|
|
911
|
+
createLayoutPlugin({
|
|
912
|
+
type,
|
|
913
|
+
direction: dir
|
|
914
|
+
})
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
);
|
|
919
|
+
if (props.keyboardShortcuts) {
|
|
920
|
+
const keyboard = useKeyboard({
|
|
921
|
+
enabled: true,
|
|
922
|
+
onDelete: () => {
|
|
923
|
+
const selectedNodes = nodesRef.value.filter((n) => n.selected);
|
|
924
|
+
const selectedEdges = edgesRef.value.filter((e) => e.selected);
|
|
925
|
+
selectedNodes.forEach((node) => nodesManager.removeNode(node.id));
|
|
926
|
+
selectedEdges.forEach((edge) => edgesManager.removeEdge(edge.id));
|
|
927
|
+
emit("update:nodes", nodesRef.value);
|
|
928
|
+
emit("update:edges", edgesRef.value);
|
|
929
|
+
},
|
|
930
|
+
onUndo: () => historyManager.undo(),
|
|
931
|
+
onRedo: () => historyManager.redo(),
|
|
932
|
+
onSelectAll: () => {
|
|
933
|
+
nodesRef.value.forEach((n) => {
|
|
934
|
+
n.selected = true;
|
|
935
|
+
});
|
|
936
|
+
edgesRef.value.forEach((e) => {
|
|
937
|
+
e.selected = true;
|
|
938
|
+
});
|
|
939
|
+
},
|
|
940
|
+
onEscape: () => selectionManager.clearSelection()
|
|
941
|
+
});
|
|
942
|
+
handleKeyDown = keyboard.handleKeyDown;
|
|
943
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
onBeforeUnmount(() => {
|
|
947
|
+
if (props.keyboardShortcuts && handleKeyDown) {
|
|
948
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
949
|
+
}
|
|
950
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
951
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
952
|
+
pluginManager.destroyAll();
|
|
953
|
+
eventBus.clear();
|
|
954
|
+
});
|
|
955
|
+
</script>
|
|
956
|
+
|
|
957
|
+
<style scoped>
|
|
958
|
+
.yh-flow{background:var(--flow-background-color,#f8f9fa);cursor:grab;height:100%;overflow:hidden;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.yh-flow.is-panning{cursor:grabbing}.yh-flow.is-readonly{cursor:default}.yh-flow__content{height:100%;left:0;pointer-events:none;position:absolute;top:0;width:100%}.yh-flow__content>*{pointer-events:auto}.yh-flow__connection-line{height:100%;left:0;overflow:visible;pointer-events:none;position:absolute;top:0;width:100%;z-index:1000}
|
|
959
|
+
</style>
|