@pixerate/editor-svelte 0.15.3 → 0.16.1

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 (150) hide show
  1. package/README.md +83 -0
  2. package/dist/BubbleMenu.svelte.d.ts +14 -0
  3. package/dist/BubbleMenu.svelte.d.ts.map +1 -0
  4. package/{src → dist}/EditableTextNodeEditor.svelte +1 -1
  5. package/dist/EditableTextNodeEditor.svelte.d.ts +26 -0
  6. package/dist/EditableTextNodeEditor.svelte.d.ts.map +1 -0
  7. package/dist/TemplateRenderer.svelte.d.ts +14 -0
  8. package/dist/TemplateRenderer.svelte.d.ts.map +1 -0
  9. package/dist/canvas/AgentPresenceLayer.svelte.d.ts +9 -0
  10. package/dist/canvas/AgentPresenceLayer.svelte.d.ts.map +1 -0
  11. package/dist/canvas/FloatingHorizontalScrollbar.svelte.d.ts +9 -0
  12. package/dist/canvas/FloatingHorizontalScrollbar.svelte.d.ts.map +1 -0
  13. package/dist/canvas/createCanvasClipboard.svelte.d.ts +32 -0
  14. package/dist/canvas/createCanvasClipboard.svelte.d.ts.map +1 -0
  15. package/dist/canvas/createCanvasClipboard.svelte.js +171 -0
  16. package/dist/canvas/createCanvasDisplacement.d.ts +32 -0
  17. package/dist/canvas/createCanvasDisplacement.d.ts.map +1 -0
  18. package/dist/canvas/createCanvasDisplacement.js +170 -0
  19. package/dist/canvas/createCanvasDocking.svelte.d.ts +56 -0
  20. package/dist/canvas/createCanvasDocking.svelte.d.ts.map +1 -0
  21. package/dist/canvas/createCanvasDocking.svelte.js +227 -0
  22. package/dist/canvas/createCanvasExplosion.svelte.d.ts +31 -0
  23. package/dist/canvas/createCanvasExplosion.svelte.d.ts.map +1 -0
  24. package/dist/canvas/createCanvasExplosion.svelte.js +346 -0
  25. package/dist/canvas/createCanvasGraph.svelte.d.ts +62 -0
  26. package/dist/canvas/createCanvasGraph.svelte.d.ts.map +1 -0
  27. package/dist/canvas/createCanvasGraph.svelte.js +223 -0
  28. package/dist/canvas/createCanvasInteractions.svelte.d.ts +28 -0
  29. package/dist/canvas/createCanvasInteractions.svelte.d.ts.map +1 -0
  30. package/dist/canvas/createCanvasInteractions.svelte.js +95 -0
  31. package/dist/canvas/createCanvasLayout.d.ts +22 -0
  32. package/dist/canvas/createCanvasLayout.d.ts.map +1 -0
  33. package/dist/canvas/createCanvasLayout.js +76 -0
  34. package/dist/canvas/createCanvasMultiDrag.svelte.d.ts +61 -0
  35. package/dist/canvas/createCanvasMultiDrag.svelte.d.ts.map +1 -0
  36. package/dist/canvas/createCanvasMultiDrag.svelte.js +105 -0
  37. package/dist/canvas/createCanvasNodeSync.svelte.d.ts +58 -0
  38. package/dist/canvas/createCanvasNodeSync.svelte.d.ts.map +1 -0
  39. package/dist/canvas/createCanvasNodeSync.svelte.js +82 -0
  40. package/dist/canvas/createCanvasSelection.svelte.d.ts +26 -0
  41. package/dist/canvas/createCanvasSelection.svelte.d.ts.map +1 -0
  42. package/dist/canvas/createCanvasSelection.svelte.js +26 -0
  43. package/dist/canvas/createCanvasShortcuts.d.ts +9 -0
  44. package/dist/canvas/createCanvasShortcuts.d.ts.map +1 -0
  45. package/dist/canvas/createCanvasShortcuts.js +97 -0
  46. package/dist/canvas/createCanvasTrajectory.d.ts +31 -0
  47. package/dist/canvas/createCanvasTrajectory.d.ts.map +1 -0
  48. package/dist/canvas/createCanvasTrajectory.js +141 -0
  49. package/dist/canvas/createStreamingCanvas.svelte.d.ts +19 -0
  50. package/dist/canvas/createStreamingCanvas.svelte.d.ts.map +1 -0
  51. package/dist/canvas/createStreamingCanvas.svelte.js +32 -0
  52. package/dist/canvas/index.d.ts +18 -688
  53. package/dist/canvas/index.d.ts.map +1 -0
  54. package/dist/canvas/index.js +34 -1839
  55. package/dist/canvas/types.d.ts +183 -0
  56. package/dist/canvas/types.d.ts.map +1 -0
  57. package/dist/canvas/types.js +1 -0
  58. package/dist/createNavigationGuard.svelte.d.ts +24 -0
  59. package/dist/createNavigationGuard.svelte.d.ts.map +1 -0
  60. package/dist/createNavigationGuard.svelte.js +65 -0
  61. package/dist/editor.svelte.d.ts +23 -0
  62. package/dist/editor.svelte.d.ts.map +1 -0
  63. package/dist/editor.svelte.js +41 -0
  64. package/dist/history/createHistoryShortcuts.d.ts +24 -0
  65. package/dist/history/createHistoryShortcuts.d.ts.map +1 -0
  66. package/dist/history/createHistoryShortcuts.js +57 -0
  67. package/dist/history/history.svelte.d.ts +18 -0
  68. package/dist/history/history.svelte.d.ts.map +1 -0
  69. package/dist/history/history.svelte.js +43 -0
  70. package/dist/history/index.d.ts +3 -0
  71. package/dist/history/index.d.ts.map +1 -0
  72. package/dist/history/index.js +2 -0
  73. package/{src → dist}/image-editor/ImageEditor.svelte +1 -1
  74. package/dist/image-editor/ImageEditor.svelte.d.ts +17 -0
  75. package/dist/image-editor/ImageEditor.svelte.d.ts.map +1 -0
  76. package/dist/image-editor/imageEditorState.svelte.d.ts +50 -0
  77. package/dist/image-editor/imageEditorState.svelte.d.ts.map +1 -0
  78. package/dist/image-editor/imageEditorState.svelte.js +132 -0
  79. package/dist/image-editor/index.d.ts +6 -16
  80. package/dist/image-editor/index.d.ts.map +1 -0
  81. package/dist/image-editor/index.js +2 -9
  82. package/dist/index.d.ts +20 -249
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +10 -1119
  85. package/dist/navigationGuard.d.ts +21 -0
  86. package/dist/navigationGuard.d.ts.map +1 -0
  87. package/dist/navigationGuard.js +59 -0
  88. package/{src → dist}/spreadsheet/FormulaBar.svelte +1 -1
  89. package/dist/spreadsheet/FormulaBar.svelte.d.ts +17 -0
  90. package/dist/spreadsheet/FormulaBar.svelte.d.ts.map +1 -0
  91. package/{src → dist}/spreadsheet/SpreadsheetEditor.svelte +1 -1
  92. package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts +22 -0
  93. package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts.map +1 -0
  94. package/dist/spreadsheet/index.d.ts +9 -0
  95. package/dist/spreadsheet/index.d.ts.map +1 -0
  96. package/{src/spreadsheet/index.ts → dist/spreadsheet/index.js} +1 -1
  97. package/dist/spreadsheet/spreadsheet.svelte.d.ts +33 -0
  98. package/dist/spreadsheet/spreadsheet.svelte.d.ts.map +1 -0
  99. package/dist/spreadsheet/spreadsheet.svelte.js +160 -0
  100. package/package.json +14 -16
  101. package/dist/canvas/index.js.map +0 -1
  102. package/dist/chunk-HEOI4UNF.js +0 -1191
  103. package/dist/chunk-HEOI4UNF.js.map +0 -1
  104. package/dist/image-editor/index.js.map +0 -1
  105. package/dist/index.css +0 -50
  106. package/dist/index.css.map +0 -1
  107. package/dist/index.js.map +0 -1
  108. package/src/canvas/__tests__/canvas-clipboard.test.ts +0 -154
  109. package/src/canvas/__tests__/canvas-docking.test.ts +0 -288
  110. package/src/canvas/__tests__/canvas-explosion.test.ts +0 -634
  111. package/src/canvas/__tests__/canvas-graph.test.ts +0 -159
  112. package/src/canvas/__tests__/canvas-interactions.test.ts +0 -86
  113. package/src/canvas/__tests__/canvas-layout.test.ts +0 -75
  114. package/src/canvas/__tests__/canvas-multi-drag.test.ts +0 -112
  115. package/src/canvas/__tests__/canvas-node-sync.svelte.test.ts +0 -104
  116. package/src/canvas/__tests__/canvas-shortcuts.test.ts +0 -59
  117. package/src/canvas/createCanvasClipboard.svelte.ts +0 -219
  118. package/src/canvas/createCanvasDisplacement.ts +0 -253
  119. package/src/canvas/createCanvasDocking.svelte.ts +0 -355
  120. package/src/canvas/createCanvasExplosion.svelte.ts +0 -457
  121. package/src/canvas/createCanvasGraph.svelte.ts +0 -330
  122. package/src/canvas/createCanvasInteractions.svelte.ts +0 -112
  123. package/src/canvas/createCanvasLayout.ts +0 -129
  124. package/src/canvas/createCanvasMultiDrag.svelte.ts +0 -175
  125. package/src/canvas/createCanvasNodeSync.svelte.ts +0 -150
  126. package/src/canvas/createCanvasSelection.svelte.ts +0 -51
  127. package/src/canvas/createCanvasShortcuts.ts +0 -99
  128. package/src/canvas/createCanvasTrajectory.ts +0 -207
  129. package/src/canvas/createStreamingCanvas.svelte.ts +0 -56
  130. package/src/canvas/index.d.ts +0 -688
  131. package/src/canvas/index.ts +0 -126
  132. package/src/canvas/types.ts +0 -223
  133. package/src/createNavigationGuard.svelte.ts +0 -97
  134. package/src/editor.svelte.ts +0 -65
  135. package/src/history/createHistoryShortcuts.ts +0 -95
  136. package/src/history/history.svelte.ts +0 -68
  137. package/src/history/index.ts +0 -2
  138. package/src/image-editor/imageEditorState.svelte.ts +0 -151
  139. package/src/image-editor/index.d.ts +0 -16
  140. package/src/image-editor/index.ts +0 -2
  141. package/src/index.d.ts +0 -249
  142. package/src/index.ts +0 -89
  143. package/src/navigationGuard.ts +0 -82
  144. package/src/spreadsheet/spreadsheet.svelte.ts +0 -176
  145. package/src/svelte.d.ts +0 -5
  146. /package/{src → dist}/BubbleMenu.svelte +0 -0
  147. /package/{src → dist}/TemplateRenderer.svelte +0 -0
  148. /package/{src → dist}/canvas/AgentPresenceLayer.svelte +0 -0
  149. /package/{src → dist}/canvas/FloatingHorizontalScrollbar.svelte +0 -0
  150. /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
- }