@pixerate/editor-svelte 0.15.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/dist/BubbleMenu.svelte.d.ts +14 -0
  2. package/dist/BubbleMenu.svelte.d.ts.map +1 -0
  3. package/{src → dist}/EditableTextNodeEditor.svelte +1 -1
  4. package/dist/EditableTextNodeEditor.svelte.d.ts +26 -0
  5. package/dist/EditableTextNodeEditor.svelte.d.ts.map +1 -0
  6. package/dist/TemplateRenderer.svelte.d.ts +14 -0
  7. package/dist/TemplateRenderer.svelte.d.ts.map +1 -0
  8. package/dist/canvas/AgentPresenceLayer.svelte.d.ts +9 -0
  9. package/dist/canvas/AgentPresenceLayer.svelte.d.ts.map +1 -0
  10. package/dist/canvas/FloatingHorizontalScrollbar.svelte.d.ts +9 -0
  11. package/dist/canvas/FloatingHorizontalScrollbar.svelte.d.ts.map +1 -0
  12. package/dist/canvas/createCanvasClipboard.svelte.d.ts +32 -0
  13. package/dist/canvas/createCanvasClipboard.svelte.d.ts.map +1 -0
  14. package/dist/canvas/createCanvasClipboard.svelte.js +171 -0
  15. package/dist/canvas/createCanvasDisplacement.d.ts +32 -0
  16. package/dist/canvas/createCanvasDisplacement.d.ts.map +1 -0
  17. package/dist/canvas/createCanvasDisplacement.js +170 -0
  18. package/dist/canvas/createCanvasDocking.svelte.d.ts +56 -0
  19. package/dist/canvas/createCanvasDocking.svelte.d.ts.map +1 -0
  20. package/dist/canvas/createCanvasDocking.svelte.js +227 -0
  21. package/dist/canvas/createCanvasExplosion.svelte.d.ts +31 -0
  22. package/dist/canvas/createCanvasExplosion.svelte.d.ts.map +1 -0
  23. package/dist/canvas/createCanvasExplosion.svelte.js +346 -0
  24. package/dist/canvas/createCanvasGraph.svelte.d.ts +62 -0
  25. package/dist/canvas/createCanvasGraph.svelte.d.ts.map +1 -0
  26. package/dist/canvas/createCanvasGraph.svelte.js +223 -0
  27. package/dist/canvas/createCanvasInteractions.svelte.d.ts +28 -0
  28. package/dist/canvas/createCanvasInteractions.svelte.d.ts.map +1 -0
  29. package/dist/canvas/createCanvasInteractions.svelte.js +95 -0
  30. package/dist/canvas/createCanvasLayout.d.ts +22 -0
  31. package/dist/canvas/createCanvasLayout.d.ts.map +1 -0
  32. package/dist/canvas/createCanvasLayout.js +76 -0
  33. package/dist/canvas/createCanvasMultiDrag.svelte.d.ts +61 -0
  34. package/dist/canvas/createCanvasMultiDrag.svelte.d.ts.map +1 -0
  35. package/dist/canvas/createCanvasMultiDrag.svelte.js +105 -0
  36. package/dist/canvas/createCanvasNodeSync.svelte.d.ts +58 -0
  37. package/dist/canvas/createCanvasNodeSync.svelte.d.ts.map +1 -0
  38. package/dist/canvas/createCanvasNodeSync.svelte.js +82 -0
  39. package/dist/canvas/createCanvasSelection.svelte.d.ts +26 -0
  40. package/dist/canvas/createCanvasSelection.svelte.d.ts.map +1 -0
  41. package/dist/canvas/createCanvasSelection.svelte.js +26 -0
  42. package/dist/canvas/createCanvasShortcuts.d.ts +9 -0
  43. package/dist/canvas/createCanvasShortcuts.d.ts.map +1 -0
  44. package/dist/canvas/createCanvasShortcuts.js +97 -0
  45. package/dist/canvas/createCanvasTrajectory.d.ts +31 -0
  46. package/dist/canvas/createCanvasTrajectory.d.ts.map +1 -0
  47. package/dist/canvas/createCanvasTrajectory.js +141 -0
  48. package/dist/canvas/createStreamingCanvas.svelte.d.ts +19 -0
  49. package/dist/canvas/createStreamingCanvas.svelte.d.ts.map +1 -0
  50. package/dist/canvas/createStreamingCanvas.svelte.js +32 -0
  51. package/dist/canvas/index.d.ts +18 -688
  52. package/dist/canvas/index.d.ts.map +1 -0
  53. package/dist/canvas/index.js +34 -1839
  54. package/dist/canvas/types.d.ts +183 -0
  55. package/dist/canvas/types.d.ts.map +1 -0
  56. package/dist/canvas/types.js +1 -0
  57. package/dist/createNavigationGuard.svelte.d.ts +24 -0
  58. package/dist/createNavigationGuard.svelte.d.ts.map +1 -0
  59. package/dist/createNavigationGuard.svelte.js +65 -0
  60. package/dist/editor.svelte.d.ts +23 -0
  61. package/dist/editor.svelte.d.ts.map +1 -0
  62. package/dist/editor.svelte.js +41 -0
  63. package/dist/history/createHistoryShortcuts.d.ts +24 -0
  64. package/dist/history/createHistoryShortcuts.d.ts.map +1 -0
  65. package/dist/history/createHistoryShortcuts.js +57 -0
  66. package/dist/history/history.svelte.d.ts +18 -0
  67. package/dist/history/history.svelte.d.ts.map +1 -0
  68. package/dist/history/history.svelte.js +43 -0
  69. package/dist/history/index.d.ts +3 -0
  70. package/dist/history/index.d.ts.map +1 -0
  71. package/dist/history/index.js +2 -0
  72. package/{src → dist}/image-editor/ImageEditor.svelte +1 -1
  73. package/dist/image-editor/ImageEditor.svelte.d.ts +17 -0
  74. package/dist/image-editor/ImageEditor.svelte.d.ts.map +1 -0
  75. package/dist/image-editor/imageEditorState.svelte.d.ts +50 -0
  76. package/dist/image-editor/imageEditorState.svelte.d.ts.map +1 -0
  77. package/dist/image-editor/imageEditorState.svelte.js +132 -0
  78. package/dist/image-editor/index.d.ts +6 -16
  79. package/dist/image-editor/index.d.ts.map +1 -0
  80. package/dist/image-editor/index.js +2 -9
  81. package/dist/index.d.ts +20 -249
  82. package/dist/index.d.ts.map +1 -0
  83. package/dist/index.js +10 -1119
  84. package/dist/navigationGuard.d.ts +21 -0
  85. package/dist/navigationGuard.d.ts.map +1 -0
  86. package/dist/navigationGuard.js +59 -0
  87. package/{src → dist}/spreadsheet/FormulaBar.svelte +1 -1
  88. package/dist/spreadsheet/FormulaBar.svelte.d.ts +17 -0
  89. package/dist/spreadsheet/FormulaBar.svelte.d.ts.map +1 -0
  90. package/{src → dist}/spreadsheet/SpreadsheetEditor.svelte +1 -1
  91. package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts +22 -0
  92. package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts.map +1 -0
  93. package/dist/spreadsheet/index.d.ts +9 -0
  94. package/dist/spreadsheet/index.d.ts.map +1 -0
  95. package/{src/spreadsheet/index.ts → dist/spreadsheet/index.js} +1 -1
  96. package/dist/spreadsheet/spreadsheet.svelte.d.ts +33 -0
  97. package/dist/spreadsheet/spreadsheet.svelte.d.ts.map +1 -0
  98. package/dist/spreadsheet/spreadsheet.svelte.js +160 -0
  99. package/package.json +14 -16
  100. package/dist/canvas/index.js.map +0 -1
  101. package/dist/chunk-HEOI4UNF.js +0 -1191
  102. package/dist/chunk-HEOI4UNF.js.map +0 -1
  103. package/dist/image-editor/index.js.map +0 -1
  104. package/dist/index.css +0 -50
  105. package/dist/index.css.map +0 -1
  106. package/dist/index.js.map +0 -1
  107. package/src/canvas/__tests__/canvas-clipboard.test.ts +0 -154
  108. package/src/canvas/__tests__/canvas-docking.test.ts +0 -288
  109. package/src/canvas/__tests__/canvas-explosion.test.ts +0 -634
  110. package/src/canvas/__tests__/canvas-graph.test.ts +0 -159
  111. package/src/canvas/__tests__/canvas-interactions.test.ts +0 -86
  112. package/src/canvas/__tests__/canvas-layout.test.ts +0 -75
  113. package/src/canvas/__tests__/canvas-multi-drag.test.ts +0 -112
  114. package/src/canvas/__tests__/canvas-node-sync.svelte.test.ts +0 -104
  115. package/src/canvas/__tests__/canvas-shortcuts.test.ts +0 -59
  116. package/src/canvas/createCanvasClipboard.svelte.ts +0 -219
  117. package/src/canvas/createCanvasDisplacement.ts +0 -253
  118. package/src/canvas/createCanvasDocking.svelte.ts +0 -355
  119. package/src/canvas/createCanvasExplosion.svelte.ts +0 -457
  120. package/src/canvas/createCanvasGraph.svelte.ts +0 -330
  121. package/src/canvas/createCanvasInteractions.svelte.ts +0 -112
  122. package/src/canvas/createCanvasLayout.ts +0 -129
  123. package/src/canvas/createCanvasMultiDrag.svelte.ts +0 -175
  124. package/src/canvas/createCanvasNodeSync.svelte.ts +0 -150
  125. package/src/canvas/createCanvasSelection.svelte.ts +0 -51
  126. package/src/canvas/createCanvasShortcuts.ts +0 -99
  127. package/src/canvas/createCanvasTrajectory.ts +0 -207
  128. package/src/canvas/createStreamingCanvas.svelte.ts +0 -56
  129. package/src/canvas/index.d.ts +0 -688
  130. package/src/canvas/index.ts +0 -126
  131. package/src/canvas/types.ts +0 -223
  132. package/src/createNavigationGuard.svelte.ts +0 -97
  133. package/src/editor.svelte.ts +0 -65
  134. package/src/history/createHistoryShortcuts.ts +0 -95
  135. package/src/history/history.svelte.ts +0 -68
  136. package/src/history/index.ts +0 -2
  137. package/src/image-editor/imageEditorState.svelte.ts +0 -151
  138. package/src/image-editor/index.d.ts +0 -16
  139. package/src/image-editor/index.ts +0 -2
  140. package/src/index.d.ts +0 -249
  141. package/src/index.ts +0 -89
  142. package/src/navigationGuard.ts +0 -82
  143. package/src/spreadsheet/spreadsheet.svelte.ts +0 -176
  144. package/src/svelte.d.ts +0 -5
  145. /package/{src → dist}/BubbleMenu.svelte +0 -0
  146. /package/{src → dist}/TemplateRenderer.svelte +0 -0
  147. /package/{src → dist}/canvas/AgentPresenceLayer.svelte +0 -0
  148. /package/{src → dist}/canvas/FloatingHorizontalScrollbar.svelte +0 -0
  149. /package/{src → dist}/canvas/README.md +0 -0
@@ -1,457 +0,0 @@
1
- import { cubicOut } from 'svelte/easing';
2
- import type { Rect, XYPosition } from '@xyflow/svelte';
3
- import type {
4
- CanvasEdge,
5
- CanvasNode,
6
- CollapseNodeOptions,
7
- ExplodeNodeOptions,
8
- ExplosionSnapshot,
9
- NodeTransition
10
- } from './types.js';
11
- import {
12
- calculateDirectionalDisplacement,
13
- calculateReflowDisplacement
14
- } from './createCanvasDisplacement.js';
15
- import {
16
- createFanOutTrajectory,
17
- linearPositionTrajectory,
18
- linearTrajectory,
19
- runMultiNodeTransition
20
- } from './createCanvasTrajectory.js';
21
-
22
- export interface CanvasGraphTarget<
23
- TNode extends CanvasNode = CanvasNode,
24
- TEdge extends CanvasEdge = CanvasEdge
25
- > {
26
- nodes: TNode[];
27
- edges: TEdge[];
28
- setNodes: (nodes: TNode[], triggerCallback?: boolean) => void;
29
- setEdges: (edges: TEdge[], triggerCallback?: boolean) => void;
30
- addNodeOrNodes: (nodes: TNode | TNode[], animateFrom?: XYPosition, save?: boolean) => void;
31
- addEdges: (edges: TEdge[], save?: boolean) => void;
32
- removeNodes: (nodes: TNode[], save?: boolean) => void;
33
- removeEdges: (edges: TEdge[], save?: boolean) => void;
34
- createEdge?: (sourceId: string, targetId: string, options?: any) => TEdge;
35
- onSave?: () => void;
36
- }
37
-
38
- export interface CreateCanvasExplosionOptions<TNode extends CanvasNode = CanvasNode> {
39
- getNodesBounds?: (nodes: TNode[]) => Rect;
40
- onSave?: () => void;
41
- }
42
-
43
- /**
44
- * Headless Svelte 5 rune managing canvas node explosion, spatial layout displacement,
45
- * coordinated multi-node animation paths, and reversible collapsing.
46
- */
47
- export function createCanvasExplosion<
48
- TNode extends CanvasNode = CanvasNode,
49
- TEdge extends CanvasEdge = CanvasEdge
50
- >(
51
- graph: CanvasGraphTarget<TNode, TEdge>,
52
- options: CreateCanvasExplosionOptions<TNode> = {}
53
- ) {
54
- let explodedNodeIds = $state<string[]>([]);
55
- const snapshots = new Map<string, ExplosionSnapshot<TNode, TEdge>>();
56
- let activeAnimationCancel: (() => void) | null = null;
57
-
58
- function isExploded(nodeId: string): boolean {
59
- return explodedNodeIds.includes(nodeId);
60
- }
61
-
62
- function explodeNode(
63
- parentId: string,
64
- explodeOptions: ExplodeNodeOptions<TNode, TEdge>
65
- ): boolean {
66
- if (isExploded(parentId)) {
67
- return false;
68
- }
69
-
70
- const parentNode = graph.nodes.find((n) => n.id === parentId);
71
- if (!parentNode) {
72
- return false;
73
- }
74
-
75
- const {
76
- childNodes,
77
- childEdges = [],
78
- connectParentToChildren = 'all',
79
- displacementStrategy = 'directional',
80
- directionalOptions = {},
81
- reflowOptions = {},
82
- trajectory,
83
- duration = 500,
84
- staggerDelay = 20,
85
- easing = cubicOut,
86
- onComplete
87
- } = explodeOptions;
88
-
89
- if (childNodes.length === 0) {
90
- return false;
91
- }
92
-
93
- // 1. Calculate displacement for existing nodes
94
- let displacementMap: Map<string, XYPosition>;
95
- if (displacementStrategy === 'dagre') {
96
- displacementMap = calculateReflowDisplacement({
97
- existingNodes: graph.nodes,
98
- existingEdges: graph.edges,
99
- originNode: parentNode,
100
- childNodes,
101
- childEdges,
102
- getNodesBounds: options.getNodesBounds,
103
- options: {
104
- ...reflowOptions,
105
- direction: (reflowOptions.direction as any) ?? 'LR'
106
- }
107
- });
108
- } else if (displacementStrategy === 'none') {
109
- displacementMap = new Map();
110
- } else {
111
- displacementMap = calculateDirectionalDisplacement({
112
- existingNodes: graph.nodes,
113
- originNode: parentNode,
114
- childNodes,
115
- getNodesBounds: options.getNodesBounds,
116
- options: directionalOptions
117
- });
118
- }
119
-
120
- // 2. Build snapshot of displaced nodes before mutating positions
121
- const displacedNodesSnapshot = Array.from(displacementMap.entries()).map(([id]) => {
122
- const node = graph.nodes.find((n) => n.id === id);
123
- return {
124
- id,
125
- originalPosition: { ...(node?.position ?? { x: 0, y: 0 }) }
126
- };
127
- });
128
-
129
- // 3. Prepare child edges & parent connection edges
130
- const edgesToAdd: TEdge[] = [...childEdges];
131
- const defaultCreateEdge = (sourceId: string, targetId: string): TEdge => {
132
- if (graph.createEdge) {
133
- return graph.createEdge(sourceId, targetId);
134
- }
135
- return {
136
- id: crypto.randomUUID(),
137
- type: 'default',
138
- source: sourceId,
139
- target: targetId
140
- } as unknown as TEdge;
141
- };
142
-
143
- if (connectParentToChildren === 'all' || connectParentToChildren === true) {
144
- childNodes.forEach((child) => {
145
- const exists = edgesToAdd.some((e) => e.source === parentId && e.target === child.id);
146
- if (!exists) {
147
- edgesToAdd.push(defaultCreateEdge(parentId, child.id));
148
- }
149
- });
150
- } else if (connectParentToChildren === 'first' && childNodes.length > 0) {
151
- const firstChild = childNodes[0];
152
- const exists = edgesToAdd.some((e) => e.source === parentId && e.target === firstChild.id);
153
- if (!exists) {
154
- edgesToAdd.push(defaultCreateEdge(parentId, firstChild.id));
155
- }
156
- }
157
-
158
- const snapshot: ExplosionSnapshot<TNode, TEdge> = {
159
- parentId,
160
- childNodeIds: childNodes.map((n) => n.id),
161
- childEdgeIds: edgesToAdd.map((e) => e.id),
162
- displacedNodes: displacedNodesSnapshot,
163
- timestamp: Date.now()
164
- };
165
- snapshots.set(parentId, snapshot);
166
-
167
- // 4. Position child nodes initially at origin node coordinate
168
- const originPos = { ...parentNode.position };
169
- const targetPositions = childNodes.map((child) => ({ ...child.position }));
170
-
171
- childNodes.forEach((child) => {
172
- child.position = { ...originPos };
173
- if (!child.data) child.data = {} as any;
174
- (child.data as any).scale = 0;
175
- (child.data as any).opacity = 0;
176
- const currentStyle = (child.style || '').replace(/opacity:\s*[^;]+;?/g, '').trim();
177
- child.style = `${currentStyle ? currentStyle + '; ' : ''}opacity: 0;`;
178
- });
179
-
180
- edgesToAdd.forEach((edge) => {
181
- const currentStyle = (edge.style || '').replace(/opacity:\s*[^;]+;?/g, '').trim();
182
- edge.style = `${currentStyle ? currentStyle + '; ' : ''}opacity: 0;`;
183
- });
184
-
185
- // Add nodes and edges to graph without saving yet
186
- graph.addNodeOrNodes(childNodes, undefined, false);
187
- if (edgesToAdd.length > 0) {
188
- graph.addEdges(edgesToAdd, false);
189
- }
190
-
191
- // 5. Build transition list
192
- const chosenTrajectory = trajectory ?? createFanOutTrajectory({ curvature: 0.35 });
193
- const transitions: NodeTransition<TNode>[] = [];
194
- const effectiveStagger = duration === 0 ? 0 : staggerDelay;
195
-
196
- // Expanding child transitions
197
- childNodes.forEach((child, i) => {
198
- transitions.push({
199
- node: child,
200
- from: originPos,
201
- to: targetPositions[i],
202
- trajectory: chosenTrajectory,
203
- delay: i * effectiveStagger,
204
- duration,
205
- easing,
206
- index: i,
207
- total: childNodes.length
208
- });
209
- });
210
-
211
- // Displaced node transitions
212
- displacementMap.forEach((targetPos, nodeId) => {
213
- const node = graph.nodes.find((n) => n.id === nodeId);
214
- if (node) {
215
- transitions.push({
216
- node,
217
- from: { ...node.position },
218
- to: targetPos,
219
- trajectory: linearPositionTrajectory,
220
- duration,
221
- easing
222
- });
223
- }
224
- });
225
-
226
- // 6. Run coordinated animation
227
- if (activeAnimationCancel) {
228
- activeAnimationCancel();
229
- }
230
-
231
- activeAnimationCancel = runMultiNodeTransition(transitions, {
232
- defaultDuration: duration,
233
- defaultEasing: easing,
234
- onUpdate: () => {
235
- if (edgesToAdd.length > 0) {
236
- const childIdSet = new Set(childNodes.map((c) => c.id));
237
- const childEdgesInGraph = graph.edges.filter((e) => childIdSet.has(e.target));
238
- if (childEdgesInGraph.length > 0) {
239
- childEdgesInGraph.forEach((edge) => {
240
- const child = childNodes.find((c) => c.id === edge.target);
241
- const childOpacity = (child?.data as any)?.opacity ?? 1;
242
- const currentStyle = (edge.style || '').replace(/opacity:\s*[^;]+;?/g, '').trim();
243
- edge.style = `${currentStyle ? currentStyle + '; ' : ''}opacity: ${childOpacity};`;
244
- });
245
- graph.setEdges([...graph.edges]);
246
- }
247
- }
248
-
249
- // Sync any mismatched node references in graph.nodes from transitions
250
- transitions.forEach((t) => {
251
- const graphNode = graph.nodes.find((n) => n.id === t.node.id);
252
- if (graphNode && graphNode !== t.node) {
253
- graphNode.position = { ...t.node.position };
254
- graphNode.style = t.node.style;
255
- if (t.node.data) {
256
- graphNode.data = { ...graphNode.data, ...t.node.data };
257
- }
258
- }
259
- });
260
-
261
- graph.setNodes([...graph.nodes]);
262
- },
263
- onComplete: () => {
264
- childNodes.forEach((child, i) => {
265
- const node = graph.nodes.find((n) => n.id === child.id);
266
- if (node) {
267
- node.position = { ...targetPositions[i] };
268
- node.style = (node.style || '').replace(/opacity:\s*[^;]+;?/g, '').trim() || undefined;
269
- if (node.data) {
270
- (node.data as any).opacity = 1;
271
- }
272
- }
273
- });
274
- displacementMap.forEach((targetPos, nodeId) => {
275
- const graphNode = graph.nodes.find((n) => n.id === nodeId);
276
- if (graphNode) {
277
- graphNode.position = { ...targetPos };
278
- }
279
- });
280
- edgesToAdd.forEach((edge) => {
281
- const graphEdge = graph.edges.find((e) => e.id === edge.id);
282
- if (graphEdge) {
283
- graphEdge.style = (graphEdge.style || '').replace(/opacity:\s*[^;]+;?/g, '').trim() || undefined;
284
- }
285
- });
286
- graph.setNodes([...graph.nodes]);
287
- graph.setEdges([...graph.edges]);
288
- explodedNodeIds = [...explodedNodeIds, parentId];
289
- activeAnimationCancel = null;
290
- options.onSave?.();
291
- graph.onSave?.();
292
- onComplete?.();
293
- }
294
- });
295
-
296
- return true;
297
- }
298
-
299
- function collapseNode(
300
- parentId: string,
301
- collapseOptions: CollapseNodeOptions = {}
302
- ): boolean {
303
- const snapshot = snapshots.get(parentId);
304
- if (!snapshot) {
305
- return false;
306
- }
307
-
308
- const parentNode = graph.nodes.find((n) => n.id === parentId);
309
- if (!parentNode) {
310
- return false;
311
- }
312
-
313
- const {
314
- duration = 400,
315
- staggerDelay = 15,
316
- easing = cubicOut,
317
- trajectory,
318
- onComplete
319
- } = collapseOptions;
320
-
321
- const childIdSet = new Set(snapshot.childNodeIds);
322
- const activeChildNodes = graph.nodes.filter((n) => childIdSet.has(n.id));
323
- const originPos = { ...parentNode.position };
324
-
325
- // Reverse trajectory pulls nodes back toward parent while collapsing scale
326
- const reverseTrajectory = trajectory ?? createFanOutTrajectory({
327
- curvature: 0.2,
328
- startScale: 1,
329
- endScale: 0,
330
- startOpacity: 1,
331
- endOpacity: 0
332
- });
333
-
334
- const transitions: NodeTransition<TNode>[] = [];
335
- const effectiveStagger = duration === 0 ? 0 : staggerDelay;
336
-
337
- // Collapsing child transitions back into origin
338
- activeChildNodes.forEach((child, i) => {
339
- transitions.push({
340
- node: child,
341
- from: { ...child.position },
342
- to: originPos,
343
- trajectory: reverseTrajectory,
344
- delay: (activeChildNodes.length - 1 - i) * effectiveStagger,
345
- duration,
346
- easing,
347
- index: i,
348
- total: activeChildNodes.length
349
- });
350
- });
351
-
352
- // Displaced node restore transitions
353
- snapshot.displacedNodes.forEach(({ id, originalPosition }) => {
354
- const node = graph.nodes.find((n) => n.id === id);
355
- if (node) {
356
- transitions.push({
357
- node,
358
- from: { ...node.position },
359
- to: originalPosition,
360
- trajectory: linearPositionTrajectory,
361
- duration,
362
- easing
363
- });
364
- }
365
- });
366
-
367
- if (activeAnimationCancel) {
368
- activeAnimationCancel();
369
- }
370
-
371
- activeAnimationCancel = runMultiNodeTransition(transitions, {
372
- defaultDuration: duration,
373
- defaultEasing: easing,
374
- onUpdate: () => {
375
- const edgeIdSet = new Set(snapshot.childEdgeIds);
376
- const childEdgesInGraph = graph.edges.filter((e) => edgeIdSet.has(e.id));
377
- if (childEdgesInGraph.length > 0) {
378
- childEdgesInGraph.forEach((edge) => {
379
- const child = activeChildNodes.find((c) => c.id === edge.target);
380
- const childOpacity = (child?.data as any)?.opacity ?? 0;
381
- const currentStyle = (edge.style || '').replace(/opacity:\s*[^;]+;?/g, '').trim();
382
- edge.style = `${currentStyle ? currentStyle + '; ' : ''}opacity: ${childOpacity};`;
383
- });
384
- graph.setEdges([...graph.edges]);
385
- }
386
-
387
- // Sync any mismatched node references in graph.nodes from transitions
388
- transitions.forEach((t) => {
389
- const graphNode = graph.nodes.find((n) => n.id === t.node.id);
390
- if (graphNode && graphNode !== t.node) {
391
- graphNode.position = { ...t.node.position };
392
- graphNode.style = t.node.style;
393
- if (t.node.data) {
394
- graphNode.data = { ...graphNode.data, ...t.node.data };
395
- }
396
- }
397
- });
398
-
399
- graph.setNodes([...graph.nodes]);
400
- },
401
- onComplete: () => {
402
- // Animation completed: prune child nodes and edges
403
- graph.removeNodes(activeChildNodes, false);
404
-
405
- const edgeIdSet = new Set(snapshot.childEdgeIds);
406
- const edgesToRemove = graph.edges.filter((e) => edgeIdSet.has(e.id));
407
- if (edgesToRemove.length > 0) {
408
- graph.removeEdges(edgesToRemove, false);
409
- }
410
-
411
- snapshot.displacedNodes.forEach(({ id, originalPosition }) => {
412
- const graphNode = graph.nodes.find((n) => n.id === id);
413
- if (graphNode) {
414
- graphNode.position = { ...originalPosition };
415
- }
416
- });
417
- graph.setNodes([...graph.nodes]);
418
-
419
- snapshots.delete(parentId);
420
- explodedNodeIds = explodedNodeIds.filter((id) => id !== parentId);
421
- activeAnimationCancel = null;
422
-
423
- options.onSave?.();
424
- graph.onSave?.();
425
- onComplete?.();
426
- }
427
- });
428
-
429
- return true;
430
- }
431
-
432
- function toggleExplode(
433
- parentId: string,
434
- explodeOptions: ExplodeNodeOptions<TNode, TEdge>,
435
- collapseOptions?: CollapseNodeOptions
436
- ): boolean {
437
- if (isExploded(parentId)) {
438
- return collapseNode(parentId, collapseOptions);
439
- }
440
- return explodeNode(parentId, explodeOptions);
441
- }
442
-
443
- function getSnapshot(parentId: string) {
444
- return snapshots.get(parentId);
445
- }
446
-
447
- return {
448
- get explodedNodeIds() {
449
- return explodedNodeIds;
450
- },
451
- isExploded,
452
- explodeNode,
453
- collapseNode,
454
- toggleExplode,
455
- getSnapshot
456
- };
457
- }