@yh-ui/flow 1.0.51 → 1.0.53
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/Flow.d.vue.ts +25 -2
- package/dist/Flow.vue +221 -40
- package/dist/Flow.vue.d.ts +25 -2
- package/dist/core/useAlignment.cjs +32 -12
- package/dist/core/useAlignment.mjs +49 -19
- package/dist/core/useKeyboard.cjs +3 -1
- package/dist/core/useKeyboard.mjs +3 -1
- package/dist/core/useNodeDistribution.cjs +16 -16
- package/dist/core/useNodeDistribution.mjs +30 -16
- package/dist/core/useSelection.cjs +6 -3
- package/dist/core/useSelection.mjs +6 -3
- package/dist/core/useViewport.cjs +4 -4
- package/dist/core/useViewport.d.ts +8 -0
- package/dist/core/useViewport.mjs +4 -4
- package/dist/plugins/plugins/layout.cjs +6 -6
- package/dist/plugins/plugins/layout.mjs +6 -6
- package/dist/plugins/plugins/node-group.cjs +10 -2
- package/dist/plugins/plugins/node-group.mjs +10 -2
- package/dist/renderer/AlignmentLines.vue +26 -16
- package/dist/renderer/EdgeHandlesRenderer.vue +11 -2
- package/dist/renderer/EdgeRenderer.vue +5 -3
- package/dist/renderer/Minimap.vue +28 -18
- package/dist/renderer/NodeRenderer.d.vue.ts +2 -0
- package/dist/renderer/NodeRenderer.vue +74 -13
- package/dist/renderer/NodeRenderer.vue.d.ts +2 -0
- package/dist/types/index.d.ts +27 -0
- package/dist/utils/custom-types.cjs +21 -0
- package/dist/utils/custom-types.d.ts +25 -0
- package/dist/utils/custom-types.mjs +17 -0
- package/dist/utils/edge.cjs +40 -2
- package/dist/utils/edge.d.ts +11 -1
- package/dist/utils/edge.mjs +31 -2
- package/package.json +18 -4
package/dist/Flow.d.vue.ts
CHANGED
|
@@ -60,11 +60,11 @@ type __VLS_Props = {
|
|
|
60
60
|
/** Export file name prefix */
|
|
61
61
|
exportFileName?: string;
|
|
62
62
|
};
|
|
63
|
-
declare var __VLS_15: any,
|
|
63
|
+
declare var __VLS_15: any, __VLS_39: any;
|
|
64
64
|
type __VLS_Slots = {} & {
|
|
65
65
|
edge?: (props: typeof __VLS_15) => any;
|
|
66
66
|
} & {
|
|
67
|
-
node?: (props: typeof
|
|
67
|
+
node?: (props: typeof __VLS_39) => any;
|
|
68
68
|
};
|
|
69
69
|
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {
|
|
70
70
|
nodes: import("vue").Ref<Node[]>;
|
|
@@ -135,6 +135,29 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {
|
|
|
135
135
|
exportJson?: () => string;
|
|
136
136
|
exportImage?: (options?: import("./types").ScreenshotOptions | HTMLElement) => Promise<import("./types").ScreenshotResult>;
|
|
137
137
|
applyLayout?: (options?: unknown) => void | Promise<void>;
|
|
138
|
+
groupSelectedNodes?: (label?: string) => string | null;
|
|
139
|
+
ungroupNodes?: (groupId: string) => void;
|
|
140
|
+
toggleGroupCollapse?: (groupId: string) => void;
|
|
141
|
+
isGroupCollapsed?: (groupId: string) => boolean;
|
|
142
|
+
getGroupChildren?: (groupId: string) => Node[];
|
|
143
|
+
getGroupRegistry?: () => Map<string, {
|
|
144
|
+
groupId: string;
|
|
145
|
+
childIds: string[];
|
|
146
|
+
collapsed: boolean;
|
|
147
|
+
originalPositions: Record<string, {
|
|
148
|
+
x: number;
|
|
149
|
+
y: number;
|
|
150
|
+
}>;
|
|
151
|
+
}>;
|
|
152
|
+
undo?: () => void;
|
|
153
|
+
redo?: () => void;
|
|
154
|
+
saveSnapshot?: (description?: string) => void;
|
|
155
|
+
canUndo?: import("vue").Ref<boolean>;
|
|
156
|
+
canRedo?: import("vue").Ref<boolean>;
|
|
157
|
+
historyLength?: import("vue").Ref<number>;
|
|
158
|
+
clearHistory?: () => void;
|
|
159
|
+
getHistory?: () => unknown[];
|
|
160
|
+
jumpToStep?: (index: number) => void;
|
|
138
161
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
139
162
|
"update:modelValue": (value: ViewportTransform) => any;
|
|
140
163
|
"update:nodes": (nodes: Node<import("./types").NodeData>[]) => any;
|
package/dist/Flow.vue
CHANGED
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
@node-drag-end="handleNodeDragEnd"
|
|
60
60
|
@connect-start="handleConnectStart"
|
|
61
61
|
@node-select-toggle="handleNodeSelectToggle"
|
|
62
|
+
@nodes-measured="handleNodesMeasured"
|
|
62
63
|
>
|
|
63
64
|
<template #node="nodeProps">
|
|
64
65
|
<slot name="node" v-bind="nodeProps" />
|
|
@@ -134,7 +135,8 @@ import {
|
|
|
134
135
|
createControlsPlugin,
|
|
135
136
|
createSnapPlugin,
|
|
136
137
|
createExportPlugin,
|
|
137
|
-
createLayoutPlugin
|
|
138
|
+
createLayoutPlugin,
|
|
139
|
+
createHistoryPlugin
|
|
138
140
|
} from "./plugins/plugins";
|
|
139
141
|
import { useViewport } from "./core/useViewport";
|
|
140
142
|
import { useNodes } from "./core/useNodes";
|
|
@@ -152,7 +154,8 @@ import {
|
|
|
152
154
|
getNodeChildren,
|
|
153
155
|
getNodeParent,
|
|
154
156
|
exportFlowData,
|
|
155
|
-
importFlowData
|
|
157
|
+
importFlowData,
|
|
158
|
+
getNodeAbsolutePosition
|
|
156
159
|
} from "./utils/custom-types";
|
|
157
160
|
import { provideFlowContext } from "./core/FlowContext";
|
|
158
161
|
import { createEventBus } from "./utils/event-bus";
|
|
@@ -241,8 +244,10 @@ const usePlugin = (plugin) => {
|
|
|
241
244
|
registeredPlugins.value = pluginManager.getPlugins();
|
|
242
245
|
};
|
|
243
246
|
const removePlugin = (pluginId) => {
|
|
244
|
-
pluginManager.
|
|
245
|
-
|
|
247
|
+
if (pluginManager.hasPlugin(pluginId)) {
|
|
248
|
+
pluginManager.unregister(pluginId);
|
|
249
|
+
registeredPlugins.value = pluginManager.getPlugins();
|
|
250
|
+
}
|
|
246
251
|
};
|
|
247
252
|
const nodesManager = useNodes(viewportRef, {
|
|
248
253
|
nodes: nodesRef,
|
|
@@ -257,16 +262,60 @@ const selectionManager = useSelection({
|
|
|
257
262
|
nodes: nodesRef,
|
|
258
263
|
edges: edgesRef
|
|
259
264
|
});
|
|
260
|
-
const
|
|
265
|
+
const localHistoryManager = useHistory(nodesRef, edgesRef, {
|
|
261
266
|
maxHistory: props.maxHistory || 50,
|
|
262
267
|
onHistoryChange: (canUndo, canRedo) => {
|
|
263
268
|
emit("historyChange", { canUndo, canRedo });
|
|
264
269
|
}
|
|
265
270
|
});
|
|
271
|
+
const getHistoryPlugin = () => {
|
|
272
|
+
return pluginManager.getPlugin("history");
|
|
273
|
+
};
|
|
274
|
+
const historyManager = {
|
|
275
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
276
|
+
push: (state) => {
|
|
277
|
+
const plugin = getHistoryPlugin();
|
|
278
|
+
if (plugin) {
|
|
279
|
+
plugin.saveSnapshot();
|
|
280
|
+
} else {
|
|
281
|
+
localHistoryManager.push(state);
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
undo: () => {
|
|
285
|
+
const plugin = getHistoryPlugin();
|
|
286
|
+
if (plugin) {
|
|
287
|
+
plugin.undo();
|
|
288
|
+
} else {
|
|
289
|
+
localHistoryManager.undo();
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
redo: () => {
|
|
293
|
+
const plugin = getHistoryPlugin();
|
|
294
|
+
if (plugin) {
|
|
295
|
+
plugin.redo();
|
|
296
|
+
} else {
|
|
297
|
+
localHistoryManager.redo();
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
clear: () => {
|
|
301
|
+
const plugin = getHistoryPlugin();
|
|
302
|
+
if (plugin) {
|
|
303
|
+
plugin.clearHistory();
|
|
304
|
+
} else {
|
|
305
|
+
localHistoryManager.clear();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
historyManager.push({ nodes: nodesRef.value, edges: edgesRef.value });
|
|
266
310
|
const alignmentManager = useAlignment({
|
|
267
311
|
nodes: nodesRef,
|
|
268
312
|
snapThreshold: snapThreshold.value
|
|
269
313
|
});
|
|
314
|
+
const nodeMap = computed(() => {
|
|
315
|
+
const m = /* @__PURE__ */ new Map();
|
|
316
|
+
nodesRef.value.forEach((n) => m.set(n.id, n));
|
|
317
|
+
return m;
|
|
318
|
+
});
|
|
270
319
|
const visibleNodes = computed(() => {
|
|
271
320
|
if (!containerRef.value) return nodesRef.value;
|
|
272
321
|
const padding = 100;
|
|
@@ -277,9 +326,10 @@ const visibleNodes = computed(() => {
|
|
|
277
326
|
height: containerHeight.value / viewportRef.value.zoom + padding * 2
|
|
278
327
|
};
|
|
279
328
|
return nodesRef.value.filter((node) => {
|
|
280
|
-
const width = node.width
|
|
281
|
-
const height = node.height
|
|
282
|
-
|
|
329
|
+
const width = node.measured?.width ?? node.width ?? 200;
|
|
330
|
+
const height = node.measured?.height ?? node.height ?? 50;
|
|
331
|
+
const absPos = getNodeAbsolutePosition(node, nodeMap.value);
|
|
332
|
+
return !(absPos.x + width < visibleBounds.x || absPos.x > visibleBounds.x + visibleBounds.width || absPos.y + height < visibleBounds.y || absPos.y > visibleBounds.y + visibleBounds.height);
|
|
283
333
|
});
|
|
284
334
|
});
|
|
285
335
|
const contentStyle = computed(() => ({
|
|
@@ -384,6 +434,63 @@ const handleMouseMove = (event) => {
|
|
|
384
434
|
}
|
|
385
435
|
}
|
|
386
436
|
};
|
|
437
|
+
const getNodeHandles = (node, type) => {
|
|
438
|
+
if (node.handleBounds) {
|
|
439
|
+
const handles = [];
|
|
440
|
+
if (node.handleBounds.top) handles.push(...node.handleBounds.top);
|
|
441
|
+
if (node.handleBounds.right) handles.push(...node.handleBounds.right);
|
|
442
|
+
if (node.handleBounds.bottom) handles.push(...node.handleBounds.bottom);
|
|
443
|
+
if (node.handleBounds.left) handles.push(...node.handleBounds.left);
|
|
444
|
+
return handles.filter((h) => h.type === type);
|
|
445
|
+
}
|
|
446
|
+
if (node.type === "group") return [];
|
|
447
|
+
if (node.type === "input") {
|
|
448
|
+
return type === "source" ? [{ id: void 0, type: "source", position: "right" }] : [];
|
|
449
|
+
}
|
|
450
|
+
if (node.type === "output") {
|
|
451
|
+
return type === "target" ? [{ id: void 0, type: "target", position: "left" }] : [];
|
|
452
|
+
}
|
|
453
|
+
if (node.type === "bpmn-start") {
|
|
454
|
+
return type === "source" ? [{ id: void 0, type: "source", position: "right" }] : [];
|
|
455
|
+
}
|
|
456
|
+
if (node.type === "bpmn-end") {
|
|
457
|
+
return type === "target" ? [{ id: void 0, type: "target", position: "left" }] : [];
|
|
458
|
+
}
|
|
459
|
+
if (node.type === "bpmn-task" || node.type === "bpmn-service-task" || node.type === "bpmn-user-task") {
|
|
460
|
+
if (type === "source") return [{ id: void 0, type: "source", position: "right" }];
|
|
461
|
+
return [{ id: void 0, type: "target", position: "left" }];
|
|
462
|
+
}
|
|
463
|
+
if (node.type === "bpmn-exclusive-gateway" || node.type === "bpmn-parallel-gateway" || node.type === "bpmn-inclusive-gateway") {
|
|
464
|
+
if (type === "source") {
|
|
465
|
+
return [
|
|
466
|
+
{ id: void 0, type: "source", position: "right" },
|
|
467
|
+
{ id: void 0, type: "source", position: "bottom" }
|
|
468
|
+
];
|
|
469
|
+
}
|
|
470
|
+
return [{ id: void 0, type: "target", position: "left" }];
|
|
471
|
+
}
|
|
472
|
+
if (node.type === "ai-start") {
|
|
473
|
+
return type === "source" ? [{ id: void 0, type: "source", position: "right" }] : [];
|
|
474
|
+
}
|
|
475
|
+
if (node.type === "ai-end") {
|
|
476
|
+
return type === "target" ? [{ id: void 0, type: "target", position: "left" }] : [];
|
|
477
|
+
}
|
|
478
|
+
if (node.type === "ai-llm" || node.type === "ai-prompt" || node.type === "ai-agent" || node.type === "ai-tool" || node.type === "ai-memory") {
|
|
479
|
+
if (type === "source") return [{ id: void 0, type: "source", position: "right" }];
|
|
480
|
+
return [{ id: void 0, type: "target", position: "left" }];
|
|
481
|
+
}
|
|
482
|
+
if (node.type === "ai-condition") {
|
|
483
|
+
if (type === "source") {
|
|
484
|
+
return [
|
|
485
|
+
{ id: void 0, type: "source", position: "right" },
|
|
486
|
+
{ id: void 0, type: "source", position: "bottom" }
|
|
487
|
+
];
|
|
488
|
+
}
|
|
489
|
+
return [{ id: void 0, type: "target", position: "left" }];
|
|
490
|
+
}
|
|
491
|
+
if (type === "source") return [{ id: void 0, type: "source", position: "right" }];
|
|
492
|
+
return [{ id: void 0, type: "target", position: "left" }];
|
|
493
|
+
};
|
|
387
494
|
const handleMouseUp = (event) => {
|
|
388
495
|
isPanning.value = false;
|
|
389
496
|
if (isSelecting.value) {
|
|
@@ -403,17 +510,37 @@ const handleMouseUp = (event) => {
|
|
|
403
510
|
if (targetNode) {
|
|
404
511
|
const sourceNodeId = updatingEdge.value ? updatingEdge.value.handleType === "source" ? targetNode.id : updatingEdge.value.edge.source : connectionStart.value.nodeId;
|
|
405
512
|
const targetNodeId = updatingEdge.value ? updatingEdge.value.handleType === "target" ? targetNode.id : updatingEdge.value.edge.target : targetNode.id;
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
513
|
+
let dropHandleId = void 0;
|
|
514
|
+
let dropHandleType = void 0;
|
|
515
|
+
const element = document.elementFromPoint(event.clientX, event.clientY);
|
|
516
|
+
const handleEl = element?.closest(".yh-flow-handle");
|
|
517
|
+
if (handleEl) {
|
|
518
|
+
dropHandleId = handleEl.getAttribute("data-handle-id") || void 0;
|
|
519
|
+
dropHandleType = handleEl.getAttribute("data-handle-type") || void 0;
|
|
520
|
+
}
|
|
521
|
+
let finalSourceHandle = void 0;
|
|
522
|
+
let finalTargetHandle = void 0;
|
|
523
|
+
if (updatingEdge.value) {
|
|
524
|
+
const { edge, handleType } = updatingEdge.value;
|
|
525
|
+
if (handleType === "source") {
|
|
526
|
+
finalSourceHandle = dropHandleType === "source" ? dropHandleId : getNodeHandles(targetNode, "source")[0]?.id || void 0;
|
|
527
|
+
finalTargetHandle = edge.targetHandle || void 0;
|
|
528
|
+
} else {
|
|
529
|
+
finalSourceHandle = edge.sourceHandle || void 0;
|
|
530
|
+
finalTargetHandle = dropHandleType === "target" ? dropHandleId : getNodeHandles(targetNode, "target")[0]?.id || void 0;
|
|
415
531
|
}
|
|
416
|
-
|
|
532
|
+
} else {
|
|
533
|
+
finalSourceHandle = connectionStart.value?.handleId || void 0;
|
|
534
|
+
finalTargetHandle = dropHandleType === "target" ? dropHandleId : getNodeHandles(targetNode, "target")[0]?.id || void 0;
|
|
535
|
+
}
|
|
536
|
+
const sourceNode = nodesRef.value.find((n) => n.id === sourceNodeId);
|
|
537
|
+
const targetNodeObj = nodesRef.value.find((n) => n.id === targetNodeId);
|
|
538
|
+
const validationResult = validateConnection(sourceNode, targetNodeObj, {
|
|
539
|
+
source: sourceNodeId,
|
|
540
|
+
target: targetNodeId,
|
|
541
|
+
sourceHandle: finalSourceHandle,
|
|
542
|
+
targetHandle: finalTargetHandle
|
|
543
|
+
});
|
|
417
544
|
if (!validationResult.isValid) {
|
|
418
545
|
console.warn("Invalid connection:", validationResult.message);
|
|
419
546
|
isConnecting.value = false;
|
|
@@ -422,12 +549,12 @@ const handleMouseUp = (event) => {
|
|
|
422
549
|
return;
|
|
423
550
|
}
|
|
424
551
|
if (updatingEdge.value) {
|
|
425
|
-
const { edge
|
|
552
|
+
const { edge } = updatingEdge.value;
|
|
426
553
|
const connection = {
|
|
427
|
-
source:
|
|
428
|
-
target:
|
|
429
|
-
sourceHandle:
|
|
430
|
-
targetHandle:
|
|
554
|
+
source: sourceNodeId,
|
|
555
|
+
target: targetNodeId,
|
|
556
|
+
sourceHandle: finalSourceHandle,
|
|
557
|
+
targetHandle: finalTargetHandle
|
|
431
558
|
};
|
|
432
559
|
edgesManager.updateEdge(edge.id, connection);
|
|
433
560
|
emit("edgeUpdate", { edge, connection });
|
|
@@ -435,10 +562,10 @@ const handleMouseUp = (event) => {
|
|
|
435
562
|
} else {
|
|
436
563
|
const newEdge = {
|
|
437
564
|
id: `edge-${Date.now()}`,
|
|
438
|
-
source:
|
|
439
|
-
target:
|
|
440
|
-
sourceHandle:
|
|
441
|
-
targetHandle:
|
|
565
|
+
source: sourceNodeId,
|
|
566
|
+
target: targetNodeId,
|
|
567
|
+
sourceHandle: finalSourceHandle,
|
|
568
|
+
targetHandle: finalTargetHandle,
|
|
442
569
|
type: "bezier"
|
|
443
570
|
};
|
|
444
571
|
edgesManager.addEdge(newEdge);
|
|
@@ -466,9 +593,10 @@ const handleMouseUp = (event) => {
|
|
|
466
593
|
};
|
|
467
594
|
const findTargetNode = (canvasPos) => {
|
|
468
595
|
for (const node of nodesRef.value) {
|
|
469
|
-
const width = node.width
|
|
470
|
-
const height = node.height
|
|
471
|
-
|
|
596
|
+
const width = node.measured?.width ?? node.width ?? 200;
|
|
597
|
+
const height = node.measured?.height ?? node.height ?? 50;
|
|
598
|
+
const absPos = getNodeAbsolutePosition(node, nodeMap.value);
|
|
599
|
+
if (canvasPos.x >= absPos.x && canvasPos.x <= absPos.x + width && canvasPos.y >= absPos.y && canvasPos.y <= absPos.y + height) {
|
|
472
600
|
if (connectionStart.value && node.id !== connectionStart.value.nodeId) {
|
|
473
601
|
return node;
|
|
474
602
|
}
|
|
@@ -476,6 +604,9 @@ const findTargetNode = (canvasPos) => {
|
|
|
476
604
|
}
|
|
477
605
|
return null;
|
|
478
606
|
};
|
|
607
|
+
const handleNodesMeasured = () => {
|
|
608
|
+
emit("update:nodes", nodesRef.value);
|
|
609
|
+
};
|
|
479
610
|
const handleNodeClick = (event, node) => {
|
|
480
611
|
const multi = event.shiftKey || event.metaKey || event.ctrlKey;
|
|
481
612
|
if (!multi) edgesManager.clearSelection();
|
|
@@ -567,7 +698,8 @@ const handleEdgeUpdateStart = (event, edge, handleType) => {
|
|
|
567
698
|
const node = nodesRef.value.find((n) => n.id === anchorNodeId);
|
|
568
699
|
if (!node) return;
|
|
569
700
|
const position = handleType === "source" ? anchorHandleId ?? "left" : anchorHandleId ?? "right";
|
|
570
|
-
const
|
|
701
|
+
const absNode = { ...node, position: getNodeAbsolutePosition(node, nodeMap.value) };
|
|
702
|
+
const startPos = getHandlePosition(absNode, position, anchorHandleId);
|
|
571
703
|
isConnecting.value = true;
|
|
572
704
|
connectionStart.value = {
|
|
573
705
|
nodeId: anchorNodeId,
|
|
@@ -589,7 +721,8 @@ const handleConnectStart = (event, nodeId, handleId, handleType) => {
|
|
|
589
721
|
const rect = containerRef.value?.getBoundingClientRect();
|
|
590
722
|
if (!rect) return;
|
|
591
723
|
const position = handleId || (handleType === "source" ? "right" : "left");
|
|
592
|
-
const
|
|
724
|
+
const absNode = { ...node, position: getNodeAbsolutePosition(node, nodeMap.value) };
|
|
725
|
+
const startPos = getHandlePosition(absNode, position, handleId);
|
|
593
726
|
isConnecting.value = true;
|
|
594
727
|
connectionStart.value = {
|
|
595
728
|
nodeId,
|
|
@@ -654,12 +787,16 @@ const flowInstance = {
|
|
|
654
787
|
setViewport: (transform) => viewport.setViewport(transform.x, transform.y, transform.zoom),
|
|
655
788
|
fitView: (options) => viewport.fitView(
|
|
656
789
|
{ width: containerWidth.value, height: containerHeight.value },
|
|
657
|
-
nodesRef.value,
|
|
790
|
+
nodesRef.value.map((n) => ({ ...n, position: getNodeAbsolutePosition(n, nodeMap.value) })),
|
|
658
791
|
options
|
|
659
792
|
),
|
|
660
793
|
zoomIn: viewport.zoomIn,
|
|
661
794
|
zoomOut: viewport.zoomOut,
|
|
662
|
-
centerView: viewport.center
|
|
795
|
+
centerView: (options) => viewport.center(
|
|
796
|
+
{ width: containerWidth.value, height: containerHeight.value },
|
|
797
|
+
nodesRef.value.map((n) => ({ ...n, position: getNodeAbsolutePosition(n, nodeMap.value) })),
|
|
798
|
+
options
|
|
799
|
+
),
|
|
663
800
|
selectNode: nodesManager.selectNode,
|
|
664
801
|
selectEdge: edgesManager.selectEdge,
|
|
665
802
|
clearSelection: selectionManager.clearSelection,
|
|
@@ -699,7 +836,24 @@ const flowInstance = {
|
|
|
699
836
|
// Placeholders for plugin methods to be exposed via defineExpose
|
|
700
837
|
exportJson: void 0,
|
|
701
838
|
exportImage: void 0,
|
|
702
|
-
applyLayout: void 0
|
|
839
|
+
applyLayout: void 0,
|
|
840
|
+
// Node grouping placeholders
|
|
841
|
+
groupSelectedNodes: void 0,
|
|
842
|
+
ungroupNodes: void 0,
|
|
843
|
+
toggleGroupCollapse: void 0,
|
|
844
|
+
isGroupCollapsed: void 0,
|
|
845
|
+
getGroupChildren: void 0,
|
|
846
|
+
getGroupRegistry: void 0,
|
|
847
|
+
// History placeholders
|
|
848
|
+
undo: void 0,
|
|
849
|
+
redo: void 0,
|
|
850
|
+
saveSnapshot: void 0,
|
|
851
|
+
canUndo: void 0,
|
|
852
|
+
canRedo: void 0,
|
|
853
|
+
historyLength: void 0,
|
|
854
|
+
clearHistory: void 0,
|
|
855
|
+
getHistory: void 0,
|
|
856
|
+
jumpToStep: void 0
|
|
703
857
|
};
|
|
704
858
|
provideFlowContext(flowInstance);
|
|
705
859
|
pluginManager.init(flowInstance);
|
|
@@ -771,13 +925,14 @@ watch(
|
|
|
771
925
|
{ deep: true }
|
|
772
926
|
);
|
|
773
927
|
let handleKeyDown;
|
|
928
|
+
let resizeObserver = null;
|
|
774
929
|
onMounted(() => {
|
|
775
930
|
document.addEventListener("mousemove", handleMouseMove);
|
|
776
931
|
document.addEventListener("mouseup", handleMouseUp);
|
|
777
932
|
if (containerRef.value) {
|
|
778
933
|
containerWidth.value = containerRef.value.clientWidth;
|
|
779
934
|
containerHeight.value = containerRef.value.clientHeight;
|
|
780
|
-
|
|
935
|
+
resizeObserver = new ResizeObserver((entries) => {
|
|
781
936
|
for (const entry of entries) {
|
|
782
937
|
containerWidth.value = entry.contentRect.width;
|
|
783
938
|
containerHeight.value = entry.contentRect.height;
|
|
@@ -920,16 +1075,38 @@ onMounted(() => {
|
|
|
920
1075
|
}
|
|
921
1076
|
}
|
|
922
1077
|
);
|
|
1078
|
+
watch(
|
|
1079
|
+
() => [props.history, props.maxHistory],
|
|
1080
|
+
([history, maxHistory]) => {
|
|
1081
|
+
removePlugin("history");
|
|
1082
|
+
if (history) {
|
|
1083
|
+
usePlugin(
|
|
1084
|
+
createHistoryPlugin({
|
|
1085
|
+
enabled: true,
|
|
1086
|
+
maxHistory: maxHistory || 50,
|
|
1087
|
+
enableKeyboard: false,
|
|
1088
|
+
onHistoryChange: (canUndo, canRedo) => {
|
|
1089
|
+
emit("historyChange", { canUndo, canRedo });
|
|
1090
|
+
}
|
|
1091
|
+
})
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
},
|
|
1095
|
+
{ immediate: true }
|
|
1096
|
+
);
|
|
923
1097
|
if (props.keyboardShortcuts) {
|
|
924
1098
|
const keyboard = useKeyboard({
|
|
925
1099
|
enabled: true,
|
|
926
1100
|
onDelete: () => {
|
|
927
1101
|
const selectedNodes = nodesRef.value.filter((n) => n.selected);
|
|
928
1102
|
const selectedEdges = edgesRef.value.filter((e) => e.selected);
|
|
929
|
-
selectedNodes.
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1103
|
+
if (selectedNodes.length > 0 || selectedEdges.length > 0) {
|
|
1104
|
+
historyManager.push({ nodes: nodesRef.value, edges: edgesRef.value });
|
|
1105
|
+
selectedNodes.forEach((node) => nodesManager.removeNode(node.id));
|
|
1106
|
+
selectedEdges.forEach((edge) => edgesManager.removeEdge(edge.id));
|
|
1107
|
+
emit("update:nodes", nodesRef.value);
|
|
1108
|
+
emit("update:edges", edgesRef.value);
|
|
1109
|
+
}
|
|
933
1110
|
},
|
|
934
1111
|
onUndo: () => historyManager.undo(),
|
|
935
1112
|
onRedo: () => historyManager.redo(),
|
|
@@ -948,6 +1125,10 @@ onMounted(() => {
|
|
|
948
1125
|
}
|
|
949
1126
|
});
|
|
950
1127
|
onBeforeUnmount(() => {
|
|
1128
|
+
if (resizeObserver) {
|
|
1129
|
+
resizeObserver.disconnect();
|
|
1130
|
+
resizeObserver = null;
|
|
1131
|
+
}
|
|
951
1132
|
if (props.keyboardShortcuts && handleKeyDown) {
|
|
952
1133
|
document.removeEventListener("keydown", handleKeyDown);
|
|
953
1134
|
}
|
package/dist/Flow.vue.d.ts
CHANGED
|
@@ -60,11 +60,11 @@ type __VLS_Props = {
|
|
|
60
60
|
/** Export file name prefix */
|
|
61
61
|
exportFileName?: string;
|
|
62
62
|
};
|
|
63
|
-
declare var __VLS_15: any,
|
|
63
|
+
declare var __VLS_15: any, __VLS_39: any;
|
|
64
64
|
type __VLS_Slots = {} & {
|
|
65
65
|
edge?: (props: typeof __VLS_15) => any;
|
|
66
66
|
} & {
|
|
67
|
-
node?: (props: typeof
|
|
67
|
+
node?: (props: typeof __VLS_39) => any;
|
|
68
68
|
};
|
|
69
69
|
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {
|
|
70
70
|
nodes: import("vue").Ref<Node[]>;
|
|
@@ -135,6 +135,29 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {
|
|
|
135
135
|
exportJson?: () => string;
|
|
136
136
|
exportImage?: (options?: import("./types").ScreenshotOptions | HTMLElement) => Promise<import("./types").ScreenshotResult>;
|
|
137
137
|
applyLayout?: (options?: unknown) => void | Promise<void>;
|
|
138
|
+
groupSelectedNodes?: (label?: string) => string | null;
|
|
139
|
+
ungroupNodes?: (groupId: string) => void;
|
|
140
|
+
toggleGroupCollapse?: (groupId: string) => void;
|
|
141
|
+
isGroupCollapsed?: (groupId: string) => boolean;
|
|
142
|
+
getGroupChildren?: (groupId: string) => Node[];
|
|
143
|
+
getGroupRegistry?: () => Map<string, {
|
|
144
|
+
groupId: string;
|
|
145
|
+
childIds: string[];
|
|
146
|
+
collapsed: boolean;
|
|
147
|
+
originalPositions: Record<string, {
|
|
148
|
+
x: number;
|
|
149
|
+
y: number;
|
|
150
|
+
}>;
|
|
151
|
+
}>;
|
|
152
|
+
undo?: () => void;
|
|
153
|
+
redo?: () => void;
|
|
154
|
+
saveSnapshot?: (description?: string) => void;
|
|
155
|
+
canUndo?: import("vue").Ref<boolean>;
|
|
156
|
+
canRedo?: import("vue").Ref<boolean>;
|
|
157
|
+
historyLength?: import("vue").Ref<number>;
|
|
158
|
+
clearHistory?: () => void;
|
|
159
|
+
getHistory?: () => unknown[];
|
|
160
|
+
jumpToStep?: (index: number) => void;
|
|
138
161
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
139
162
|
"update:modelValue": (value: ViewportTransform) => any;
|
|
140
163
|
"update:nodes": (nodes: Node<import("./types").NodeData>[]) => any;
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.useAlignment = useAlignment;
|
|
7
7
|
var _vue = require("vue");
|
|
8
|
+
var _customTypes = require("../utils/custom-types.cjs");
|
|
8
9
|
function useAlignment(options) {
|
|
9
10
|
const {
|
|
10
11
|
nodes,
|
|
@@ -22,19 +23,37 @@ function useAlignment(options) {
|
|
|
22
23
|
snappedY: false
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
|
-
const nodeWidth = node.width
|
|
26
|
-
const nodeHeight = node.height
|
|
26
|
+
const nodeWidth = node.measured?.width ?? node.width ?? 200;
|
|
27
|
+
const nodeHeight = node.measured?.height ?? node.height ?? 50;
|
|
27
28
|
const otherNodes = nodes.value.filter(n => n.id !== nodeId);
|
|
28
29
|
let snappedX = false;
|
|
29
30
|
let snappedY = false;
|
|
30
|
-
const
|
|
31
|
+
const nodeMap = new Map(nodes.value.map(n => [n.id, n]));
|
|
32
|
+
const absPosOffset = {
|
|
33
|
+
x: 0,
|
|
34
|
+
y: 0
|
|
35
|
+
};
|
|
36
|
+
if (node.parentId) {
|
|
37
|
+
const parent = nodeMap.get(node.parentId);
|
|
38
|
+
if (parent) {
|
|
39
|
+
const parentAbsPos = (0, _customTypes.getNodeAbsolutePosition)(parent, nodeMap);
|
|
40
|
+
absPosOffset.x = parentAbsPos.x;
|
|
41
|
+
absPosOffset.y = parentAbsPos.y;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const proposedAbsPos = {
|
|
45
|
+
x: position.x + absPosOffset.x,
|
|
46
|
+
y: position.y + absPosOffset.y
|
|
47
|
+
};
|
|
48
|
+
const dragYPositions = [proposedAbsPos.y, proposedAbsPos.y + nodeHeight / 2, proposedAbsPos.y + nodeHeight];
|
|
31
49
|
for (const otherNode of otherNodes) {
|
|
32
|
-
const otherHeight = otherNode.height
|
|
33
|
-
const
|
|
50
|
+
const otherHeight = otherNode.measured?.height ?? otherNode.height ?? 50;
|
|
51
|
+
const otherAbsPos = (0, _customTypes.getNodeAbsolutePosition)(otherNode, nodeMap);
|
|
52
|
+
const otherYPositions = [otherAbsPos.y, otherAbsPos.y + otherHeight / 2, otherAbsPos.y + otherHeight];
|
|
34
53
|
for (let i = 0; i < dragYPositions.length; i++) {
|
|
35
54
|
for (const otherY of otherYPositions) {
|
|
36
55
|
if (Math.abs(dragYPositions[i] - otherY) < snapThreshold) {
|
|
37
|
-
if (i === 0)
|
|
56
|
+
if (i === 0) proposedAbsPos.y = otherY;else if (i === 1) proposedAbsPos.y = otherY - nodeHeight / 2;else proposedAbsPos.y = otherY - nodeHeight;
|
|
38
57
|
snappedY = true;
|
|
39
58
|
break;
|
|
40
59
|
}
|
|
@@ -43,14 +62,15 @@ function useAlignment(options) {
|
|
|
43
62
|
}
|
|
44
63
|
if (snappedY) break;
|
|
45
64
|
}
|
|
46
|
-
const dragXPositions = [
|
|
65
|
+
const dragXPositions = [proposedAbsPos.x, proposedAbsPos.x + nodeWidth / 2, proposedAbsPos.x + nodeWidth];
|
|
47
66
|
for (const otherNode of otherNodes) {
|
|
48
|
-
const otherWidth = otherNode.width
|
|
49
|
-
const
|
|
67
|
+
const otherWidth = otherNode.measured?.width ?? otherNode.width ?? 200;
|
|
68
|
+
const otherAbsPos = (0, _customTypes.getNodeAbsolutePosition)(otherNode, nodeMap);
|
|
69
|
+
const otherXPositions = [otherAbsPos.x, otherAbsPos.x + otherWidth / 2, otherAbsPos.x + otherWidth];
|
|
50
70
|
for (let i = 0; i < dragXPositions.length; i++) {
|
|
51
71
|
for (const otherX of otherXPositions) {
|
|
52
72
|
if (Math.abs(dragXPositions[i] - otherX) < snapThreshold) {
|
|
53
|
-
if (i === 0)
|
|
73
|
+
if (i === 0) proposedAbsPos.x = otherX;else if (i === 1) proposedAbsPos.x = otherX - nodeWidth / 2;else proposedAbsPos.x = otherX - nodeWidth;
|
|
54
74
|
snappedX = true;
|
|
55
75
|
break;
|
|
56
76
|
}
|
|
@@ -59,8 +79,8 @@ function useAlignment(options) {
|
|
|
59
79
|
}
|
|
60
80
|
}
|
|
61
81
|
return {
|
|
62
|
-
x:
|
|
63
|
-
y:
|
|
82
|
+
x: proposedAbsPos.x - absPosOffset.x,
|
|
83
|
+
y: proposedAbsPos.y - absPosOffset.y,
|
|
64
84
|
snappedX,
|
|
65
85
|
snappedY
|
|
66
86
|
};
|