@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.
@@ -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, __VLS_38: 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 __VLS_38) => any;
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.unregister(pluginId);
245
- registeredPlugins.value = pluginManager.getPlugins();
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 historyManager = useHistory(nodesRef, edgesRef, {
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 || 200;
281
- const height = node.height || 50;
282
- 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);
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
- const sourceNode = nodesRef.value.find((n) => n.id === sourceNodeId);
407
- const validationResult = validateConnection(
408
- sourceNode,
409
- nodesRef.value.find((n) => n.id === targetNodeId),
410
- {
411
- source: sourceNodeId,
412
- target: targetNodeId,
413
- sourceHandle: updatingEdge.value && updatingEdge.value.handleType === "source" ? void 0 : updatingEdge.value?.edge.sourceHandle || connectionStart.value?.handleId,
414
- targetHandle: updatingEdge.value && updatingEdge.value.handleType === "target" ? void 0 : updatingEdge.value?.edge.targetHandle
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, handleType } = updatingEdge.value;
552
+ const { edge } = updatingEdge.value;
426
553
  const connection = {
427
- source: handleType === "source" ? targetNode.id : edge.source,
428
- target: handleType === "target" ? targetNode.id : edge.target,
429
- sourceHandle: handleType === "source" ? void 0 : edge.sourceHandle,
430
- targetHandle: handleType === "target" ? void 0 : edge.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: connectionStart.value.nodeId,
439
- target: targetNode.id,
440
- sourceHandle: connectionStart.value.handleId || void 0,
441
- targetHandle: void 0,
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 || 200;
470
- const height = node.height || 50;
471
- if (canvasPos.x >= node.position.x && canvasPos.x <= node.position.x + width && canvasPos.y >= node.position.y && canvasPos.y <= node.position.y + height) {
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 startPos = getHandlePosition(node, position, anchorHandleId);
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 startPos = getHandlePosition(node, position, handleId);
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
- const resizeObserver = new ResizeObserver((entries) => {
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.forEach((node) => nodesManager.removeNode(node.id));
930
- selectedEdges.forEach((edge) => edgesManager.removeEdge(edge.id));
931
- emit("update:nodes", nodesRef.value);
932
- emit("update:edges", edgesRef.value);
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
  }
@@ -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, __VLS_38: 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 __VLS_38) => any;
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 || 200;
26
- const nodeHeight = node.height || 50;
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 dragYPositions = [position.y, position.y + nodeHeight / 2, position.y + nodeHeight];
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 || 50;
33
- const otherYPositions = [otherNode.position.y, otherNode.position.y + otherHeight / 2, otherNode.position.y + otherHeight];
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) position.y = otherY;else if (i === 1) position.y = otherY - nodeHeight / 2;else position.y = otherY - nodeHeight;
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 = [position.x, position.x + nodeWidth / 2, position.x + nodeWidth];
65
+ const dragXPositions = [proposedAbsPos.x, proposedAbsPos.x + nodeWidth / 2, proposedAbsPos.x + nodeWidth];
47
66
  for (const otherNode of otherNodes) {
48
- const otherWidth = otherNode.width || 200;
49
- const otherXPositions = [otherNode.position.x, otherNode.position.x + otherWidth / 2, otherNode.position.x + otherWidth];
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) position.x = otherX;else if (i === 1) position.x = otherX - nodeWidth / 2;else position.x = otherX - otherWidth;
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: position.x,
63
- y: position.y,
82
+ x: proposedAbsPos.x - absPosOffset.x,
83
+ y: proposedAbsPos.y - absPosOffset.y,
64
84
  snappedX,
65
85
  snappedY
66
86
  };