@pixerate/editor 0.17.0 → 0.19.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.
- package/dist/agent/index.cjs +32 -29
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +9 -3
- package/dist/agent/index.d.ts +9 -3
- package/dist/agent/index.js +31 -28
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +133 -65
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +64 -11
- package/dist/canvas/index.d.ts +64 -11
- package/dist/canvas/index.js +128 -60
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-33UVEDOS.cjs → chunk-2TWGLC5K.cjs} +58 -29
- package/dist/chunk-2TWGLC5K.cjs.map +1 -0
- package/dist/{chunk-GWHJVZPI.js → chunk-KAADNAPF.js} +58 -29
- package/dist/chunk-KAADNAPF.js.map +1 -0
- package/dist/history/index.cjs +2 -2
- package/dist/history/index.d.cts +5 -0
- package/dist/history/index.d.ts +5 -0
- package/dist/history/index.js +1 -1
- package/dist/image-editor/index.cjs +732 -497
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +105 -9
- package/dist/image-editor/index.d.ts +105 -9
- package/dist/image-editor/index.js +721 -486
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/dist/{types-DC8b2TsA.d.cts → types-JV3S8VeR.d.cts} +6 -2
- package/dist/{types-DC8b2TsA.d.ts → types-JV3S8VeR.d.ts} +6 -2
- package/package.json +1 -1
- package/dist/chunk-33UVEDOS.cjs.map +0 -1
- package/dist/chunk-GWHJVZPI.js.map +0 -1
package/dist/canvas/index.cjs
CHANGED
|
@@ -148,9 +148,19 @@ function createBezierTrajectory(getControlPoint) {
|
|
|
148
148
|
};
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
|
+
function withStyleOpacity(style, opacity, emptyFormat = "string") {
|
|
152
|
+
if (style !== null && typeof style === "object") {
|
|
153
|
+
return { ...style, opacity };
|
|
154
|
+
}
|
|
155
|
+
if (typeof style === "string" && style.trim() !== "") {
|
|
156
|
+
const rest = style.replace(/(^|;)\s*opacity\s*:\s*[^;]*;?/gi, "$1").trim().replace(/;+\s*$/, "").trim();
|
|
157
|
+
return `${rest ? rest + "; " : ""}opacity: ${opacity};`;
|
|
158
|
+
}
|
|
159
|
+
return emptyFormat === "object" ? { opacity } : `opacity: ${opacity};`;
|
|
160
|
+
}
|
|
151
161
|
function runMultiNodeTransition(transitions, options = {}) {
|
|
152
162
|
if (transitions.length === 0) {
|
|
153
|
-
_optionalChain([options, 'access', _ => _.onComplete, 'optionalCall', _2 => _2()]);
|
|
163
|
+
_optionalChain([options, 'access', _ => _.onComplete, 'optionalCall', _2 => _2([])]);
|
|
154
164
|
return () => {
|
|
155
165
|
};
|
|
156
166
|
}
|
|
@@ -158,6 +168,7 @@ function runMultiNodeTransition(transitions, options = {}) {
|
|
|
158
168
|
defaultDuration = 400,
|
|
159
169
|
defaultEasing: easingFunc = defaultEasing,
|
|
160
170
|
clock = realClock,
|
|
171
|
+
styleFormat = "string",
|
|
161
172
|
onUpdate,
|
|
162
173
|
onComplete
|
|
163
174
|
} = options;
|
|
@@ -172,6 +183,7 @@ function runMultiNodeTransition(transitions, options = {}) {
|
|
|
172
183
|
delay: _nullishCoalesce(tr.delay, () => ( 0)),
|
|
173
184
|
trajectory: _nullishCoalesce(tr.trajectory, () => ( linearTrajectory))
|
|
174
185
|
}));
|
|
186
|
+
const current = items.map((item) => item.node);
|
|
175
187
|
function frame() {
|
|
176
188
|
if (isCancelled) return;
|
|
177
189
|
const now = clock.now();
|
|
@@ -186,29 +198,28 @@ function runMultiNodeTransition(transitions, options = {}) {
|
|
|
186
198
|
const rawProgress = item.duration <= 0 ? 1 : Math.min(elapsed / item.duration, 1);
|
|
187
199
|
const progress = item.duration <= 0 ? 1 : item.easing(rawProgress);
|
|
188
200
|
const point = item.trajectory(item.from, item.to, progress, item.index, item.total);
|
|
189
|
-
item.node
|
|
201
|
+
const next = { ...item.node, position: { ...point.position } };
|
|
190
202
|
if (point.scale !== void 0 || point.opacity !== void 0) {
|
|
191
|
-
|
|
192
|
-
item.node.data = {};
|
|
193
|
-
}
|
|
203
|
+
const data = { ..._nullishCoalesce(item.node.data, () => ( {})) };
|
|
194
204
|
if (point.scale !== void 0) {
|
|
195
|
-
|
|
205
|
+
data.scale = point.scale;
|
|
196
206
|
}
|
|
197
207
|
if (point.opacity !== void 0) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
item.node.style = `${currentStyle ? currentStyle + "; " : ""}opacity: ${point.opacity};`;
|
|
208
|
+
data.opacity = point.opacity;
|
|
209
|
+
next.style = withStyleOpacity(item.node.style, point.opacity, styleFormat);
|
|
201
210
|
}
|
|
211
|
+
next.data = data;
|
|
202
212
|
}
|
|
213
|
+
current[i] = next;
|
|
203
214
|
if (rawProgress < 1) {
|
|
204
215
|
allCompleted = false;
|
|
205
216
|
}
|
|
206
217
|
}
|
|
207
|
-
_optionalChain([onUpdate, 'optionalCall', _3 => _3()]);
|
|
218
|
+
_optionalChain([onUpdate, 'optionalCall', _3 => _3(current.slice())]);
|
|
208
219
|
if (!allCompleted) {
|
|
209
220
|
clock.frame().then(frame);
|
|
210
221
|
} else {
|
|
211
|
-
_optionalChain([onComplete, 'optionalCall', _4 => _4()]);
|
|
222
|
+
_optionalChain([onComplete, 'optionalCall', _4 => _4(current.slice())]);
|
|
212
223
|
}
|
|
213
224
|
}
|
|
214
225
|
frame();
|
|
@@ -417,7 +428,16 @@ function isEventFromTextInput(event) {
|
|
|
417
428
|
return false;
|
|
418
429
|
}
|
|
419
430
|
function isValidCanvasNode(obj) {
|
|
420
|
-
|
|
431
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
432
|
+
const candidate = obj;
|
|
433
|
+
if (typeof candidate.id !== "string") return false;
|
|
434
|
+
const position = candidate.position;
|
|
435
|
+
return typeof position === "object" && position !== null && typeof position.x === "number" && Number.isFinite(position.x) && typeof position.y === "number" && Number.isFinite(position.y);
|
|
436
|
+
}
|
|
437
|
+
function isValidCanvasEdge(obj) {
|
|
438
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
439
|
+
const candidate = obj;
|
|
440
|
+
return typeof candidate.id === "string" && typeof candidate.source === "string" && typeof candidate.target === "string";
|
|
421
441
|
}
|
|
422
442
|
function isValidUrl(url) {
|
|
423
443
|
try {
|
|
@@ -439,28 +459,46 @@ function parseCanvasClipboardData(raw) {
|
|
|
439
459
|
try {
|
|
440
460
|
const parsed = JSON.parse(raw);
|
|
441
461
|
if (typeof parsed === "object" && parsed !== null && Array.isArray(parsed.nodes) && parsed.nodes.length > 0 && parsed.nodes.every(isValidCanvasNode)) {
|
|
442
|
-
|
|
462
|
+
const edges = Array.isArray(parsed.edges) ? parsed.edges.filter(isValidCanvasEdge) : void 0;
|
|
463
|
+
return { ...parsed, edges };
|
|
443
464
|
}
|
|
444
465
|
} catch (e3) {
|
|
445
466
|
}
|
|
446
467
|
return null;
|
|
447
468
|
}
|
|
448
469
|
function remapPastedNodes(nodes, edges = [], offset = { x: 30, y: 30 }, idGenerator = () => `node-${Math.random().toString(36).substring(2, 9)}`) {
|
|
470
|
+
const validNodes = (Array.isArray(nodes) ? nodes : []).filter(isValidCanvasNode);
|
|
471
|
+
const validEdges = (Array.isArray(edges) ? edges : []).filter(isValidCanvasEdge);
|
|
472
|
+
const dx = Number.isFinite(_optionalChain([offset, 'optionalAccess', _29 => _29.x])) ? offset.x : 0;
|
|
473
|
+
const dy = Number.isFinite(_optionalChain([offset, 'optionalAccess', _30 => _30.y])) ? offset.y : 0;
|
|
449
474
|
const idMap = /* @__PURE__ */ new Map();
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
475
|
+
for (const node of validNodes) {
|
|
476
|
+
idMap.set(node.id, idGenerator());
|
|
477
|
+
}
|
|
478
|
+
const newNodes = validNodes.map((node) => {
|
|
479
|
+
const next = {
|
|
454
480
|
...node,
|
|
455
|
-
id:
|
|
481
|
+
id: idMap.get(node.id),
|
|
456
482
|
position: {
|
|
457
|
-
x: node.position.x +
|
|
458
|
-
y: node.position.y +
|
|
483
|
+
x: node.position.x + dx,
|
|
484
|
+
y: node.position.y + dy
|
|
459
485
|
},
|
|
460
486
|
selected: true
|
|
461
487
|
};
|
|
488
|
+
let parentRemapped = false;
|
|
489
|
+
for (const key of ["parentId", "parentNode"]) {
|
|
490
|
+
const parent = node[key];
|
|
491
|
+
if (typeof parent === "string" && idMap.has(parent)) {
|
|
492
|
+
next[key] = idMap.get(parent);
|
|
493
|
+
parentRemapped = true;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (parentRemapped) {
|
|
497
|
+
next.position = { x: node.position.x, y: node.position.y };
|
|
498
|
+
}
|
|
499
|
+
return next;
|
|
462
500
|
});
|
|
463
|
-
const newEdges =
|
|
501
|
+
const newEdges = validEdges.filter((e) => idMap.has(e.source) && idMap.has(e.target)).map((edge) => ({
|
|
464
502
|
...edge,
|
|
465
503
|
id: `edge-${Math.random().toString(36).substring(2, 9)}`,
|
|
466
504
|
source: idMap.get(edge.source),
|
|
@@ -509,7 +547,7 @@ function layoutBounds(nodes) {
|
|
|
509
547
|
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
510
548
|
}
|
|
511
549
|
function canvasHeight(nodes, options) {
|
|
512
|
-
return clampHeight(_nullishCoalesce(_optionalChain([layoutBounds, 'call',
|
|
550
|
+
return clampHeight(_nullishCoalesce(_optionalChain([layoutBounds, 'call', _31 => _31(nodes), 'optionalAccess', _32 => _32.height]), () => ( 0)), options);
|
|
513
551
|
}
|
|
514
552
|
var DEFAULT_RANK_HEIGHT = 80 + 72;
|
|
515
553
|
var NODES_PER_RANK = 2;
|
|
@@ -557,9 +595,11 @@ var StreamingLayoutManager = (_class2 = class {
|
|
|
557
595
|
|
|
558
596
|
|
|
559
597
|
__init5() {this.pendingTimer = null}
|
|
560
|
-
__init6() {this.
|
|
561
|
-
__init7() {this.
|
|
562
|
-
|
|
598
|
+
__init6() {this.pendingArgs = null}
|
|
599
|
+
__init7() {this.activeTransitionCancel = null}
|
|
600
|
+
__init8() {this.targetPositions = /* @__PURE__ */ new Map()}
|
|
601
|
+
__init9() {this.livePositions = /* @__PURE__ */ new Map()}
|
|
602
|
+
constructor(options = {}) {;_class2.prototype.__init5.call(this);_class2.prototype.__init6.call(this);_class2.prototype.__init7.call(this);_class2.prototype.__init8.call(this);_class2.prototype.__init9.call(this);
|
|
563
603
|
this.throttleMs = _nullishCoalesce(options.throttleMs, () => ( 200));
|
|
564
604
|
this.glideDurationMs = _nullishCoalesce(options.glideDurationMs, () => ( 300));
|
|
565
605
|
this.connectedOnly = _nullishCoalesce(options.connectedOnly, () => ( false));
|
|
@@ -569,52 +609,70 @@ var StreamingLayoutManager = (_class2 = class {
|
|
|
569
609
|
}
|
|
570
610
|
/**
|
|
571
611
|
* Feed incoming nodes and edges into the streaming manager.
|
|
572
|
-
*
|
|
612
|
+
* Throttles rapid streaming bursts (leading + trailing edge) and triggers smooth layout gliding.
|
|
573
613
|
*/
|
|
574
614
|
pushStreamUpdate(nodes, edges, currentPositions) {
|
|
575
|
-
if (this.pendingTimer) {
|
|
576
|
-
|
|
615
|
+
if (this.pendingTimer !== null) {
|
|
616
|
+
this.pendingArgs = [nodes, edges, currentPositions];
|
|
617
|
+
return;
|
|
577
618
|
}
|
|
619
|
+
this.recalculateAndGlide(nodes, edges, currentPositions);
|
|
620
|
+
this.startWindow();
|
|
621
|
+
}
|
|
622
|
+
startWindow() {
|
|
578
623
|
this.pendingTimer = setTimeout(() => {
|
|
579
624
|
this.pendingTimer = null;
|
|
580
|
-
this.
|
|
581
|
-
|
|
625
|
+
const args = this.pendingArgs;
|
|
626
|
+
this.pendingArgs = null;
|
|
627
|
+
if (args) {
|
|
628
|
+
this.recalculateAndGlide(...args);
|
|
629
|
+
this.startWindow();
|
|
630
|
+
}
|
|
631
|
+
}, Math.max(0, this.throttleMs));
|
|
582
632
|
}
|
|
583
633
|
/**
|
|
584
634
|
* Forces immediate calculation and cancels pending throttled timers.
|
|
585
635
|
*/
|
|
586
636
|
flush(nodes, edges, currentPositions) {
|
|
587
|
-
|
|
637
|
+
this.clearPending();
|
|
638
|
+
this.recalculateAndGlide(nodes, edges, currentPositions);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Latest computed layout targets (the positions nodes are gliding towards).
|
|
642
|
+
*/
|
|
643
|
+
getTargetPositions() {
|
|
644
|
+
return new Map(this.targetPositions);
|
|
645
|
+
}
|
|
646
|
+
clearPending() {
|
|
647
|
+
if (this.pendingTimer !== null) {
|
|
588
648
|
clearTimeout(this.pendingTimer);
|
|
589
649
|
this.pendingTimer = null;
|
|
590
650
|
}
|
|
591
|
-
this.
|
|
651
|
+
this.pendingArgs = null;
|
|
592
652
|
}
|
|
593
653
|
recalculateAndGlide(nodes, edges, currentPositions) {
|
|
594
654
|
const targetNodes = this.connectedOnly ? connectedOnly(nodes, edges) : nodes;
|
|
595
655
|
if (targetNodes.length === 0) return;
|
|
656
|
+
const startPositions = new Map(currentPositions);
|
|
596
657
|
if (this.activeTransitionCancel) {
|
|
658
|
+
for (const [id, pos] of this.livePositions) {
|
|
659
|
+
startPositions.set(id, pos);
|
|
660
|
+
}
|
|
597
661
|
this.activeTransitionCancel();
|
|
598
662
|
this.activeTransitionCancel = null;
|
|
599
663
|
}
|
|
600
|
-
const
|
|
601
|
-
for (const [id, pos] of currentPositions.entries()) {
|
|
602
|
-
stored[id] = pos;
|
|
603
|
-
}
|
|
604
|
-
const layouted = _chunkWADCJ7A7cjs.ensureLayout.call(void 0, targetNodes, edges, {
|
|
605
|
-
...this.layoutOptions,
|
|
606
|
-
storedPositions: stored
|
|
607
|
-
});
|
|
664
|
+
const layouted = _chunkWADCJ7A7cjs.ensureLayout.call(void 0, targetNodes, edges, this.layoutOptions);
|
|
608
665
|
const nextPositions = /* @__PURE__ */ new Map();
|
|
609
666
|
const transitions = [];
|
|
610
667
|
for (const node of layouted) {
|
|
611
|
-
const target = node.position;
|
|
668
|
+
const target = { ...node.position };
|
|
612
669
|
nextPositions.set(node.id, target);
|
|
613
|
-
const current =
|
|
670
|
+
const current = startPositions.get(node.id);
|
|
671
|
+
if (!current) continue;
|
|
614
672
|
const distance = Math.hypot(target.x - current.x, target.y - current.y);
|
|
615
673
|
if (distance > 2) {
|
|
616
674
|
transitions.push({
|
|
617
|
-
node,
|
|
675
|
+
node: { ...node, position: { ...current } },
|
|
618
676
|
from: current,
|
|
619
677
|
to: target,
|
|
620
678
|
trajectory: linearPositionTrajectory,
|
|
@@ -623,30 +681,38 @@ var StreamingLayoutManager = (_class2 = class {
|
|
|
623
681
|
}
|
|
624
682
|
}
|
|
625
683
|
this.targetPositions = nextPositions;
|
|
626
|
-
if (transitions.length
|
|
627
|
-
this.
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
const liveMap = new Map(currentPositions);
|
|
631
|
-
for (const trans of transitions) {
|
|
632
|
-
liveMap.set(trans.node.id, { ...trans.node.position });
|
|
633
|
-
}
|
|
634
|
-
_optionalChain([this, 'access', _31 => _31.onLayoutUpdated, 'optionalCall', _32 => _32(liveMap)]);
|
|
635
|
-
},
|
|
636
|
-
onComplete: () => {
|
|
637
|
-
this.activeTransitionCancel = null;
|
|
638
|
-
_optionalChain([this, 'access', _33 => _33.onLayoutUpdated, 'optionalCall', _34 => _34(nextPositions)]);
|
|
639
|
-
}
|
|
640
|
-
});
|
|
641
|
-
} else {
|
|
642
|
-
_optionalChain([this, 'access', _35 => _35.onLayoutUpdated, 'optionalCall', _36 => _36(nextPositions)]);
|
|
684
|
+
if (transitions.length === 0) {
|
|
685
|
+
this.livePositions = new Map(nextPositions);
|
|
686
|
+
_optionalChain([this, 'access', _33 => _33.onLayoutUpdated, 'optionalCall', _34 => _34(nextPositions)]);
|
|
687
|
+
return;
|
|
643
688
|
}
|
|
689
|
+
const live = new Map(nextPositions);
|
|
690
|
+
for (const trans of transitions) {
|
|
691
|
+
live.set(trans.node.id, { ...trans.from });
|
|
692
|
+
}
|
|
693
|
+
this.livePositions = live;
|
|
694
|
+
let finished = false;
|
|
695
|
+
const cancel = runMultiNodeTransition(transitions, {
|
|
696
|
+
clock: this.clock,
|
|
697
|
+
onUpdate: (updated) => {
|
|
698
|
+
const frame = new Map(this.livePositions);
|
|
699
|
+
for (const node of updated) {
|
|
700
|
+
frame.set(node.id, { ...node.position });
|
|
701
|
+
}
|
|
702
|
+
this.livePositions = frame;
|
|
703
|
+
_optionalChain([this, 'access', _35 => _35.onLayoutUpdated, 'optionalCall', _36 => _36(frame)]);
|
|
704
|
+
},
|
|
705
|
+
onComplete: () => {
|
|
706
|
+
finished = true;
|
|
707
|
+
this.activeTransitionCancel = null;
|
|
708
|
+
this.livePositions = new Map(nextPositions);
|
|
709
|
+
_optionalChain([this, 'access', _37 => _37.onLayoutUpdated, 'optionalCall', _38 => _38(nextPositions)]);
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
this.activeTransitionCancel = finished ? null : cancel;
|
|
644
713
|
}
|
|
645
714
|
destroy() {
|
|
646
|
-
|
|
647
|
-
clearTimeout(this.pendingTimer);
|
|
648
|
-
this.pendingTimer = null;
|
|
649
|
-
}
|
|
715
|
+
this.clearPending();
|
|
650
716
|
if (this.activeTransitionCancel) {
|
|
651
717
|
this.activeTransitionCancel();
|
|
652
718
|
this.activeTransitionCancel = null;
|
|
@@ -692,5 +758,7 @@ var StreamingLayoutManager = (_class2 = class {
|
|
|
692
758
|
|
|
693
759
|
|
|
694
760
|
|
|
695
|
-
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
exports.DEFAULT_NODE_HEIGHT = _chunkWADCJ7A7cjs.DEFAULT_NODE_HEIGHT; exports.DEFAULT_NODE_WIDTH = _chunkWADCJ7A7cjs.DEFAULT_NODE_WIDTH; exports.DEFAULT_PLACEMENT_GAP = _chunkWADCJ7A7cjs.DEFAULT_PLACEMENT_GAP; exports.ManualClock = ManualClock; exports.StreamingLayoutManager = StreamingLayoutManager; exports.blendLayout = blendLayout; exports.boundsOf = _chunkWADCJ7A7cjs.boundsOf; exports.calculateDagreReflowDisplacement = calculateDagreReflowDisplacement; exports.calculateDirectionalDisplacement = calculateDirectionalDisplacement; exports.canvasHeight = canvasHeight; exports.centerNodes = _chunkWADCJ7A7cjs.centerNodes; exports.centre = _chunkWADCJ7A7cjs.centre; exports.computeNodesBoundingBox = computeNodesBoundingBox; exports.connectedOnly = connectedOnly; exports.createBezierTrajectory = createBezierTrajectory; exports.createFanOutTrajectory = createFanOutTrajectory; exports.defaultEasing = defaultEasing; exports.ensureLayout = _chunkWADCJ7A7cjs.ensureLayout; exports.estimateCanvasHeight = estimateCanvasHeight; exports.estimateNodeSize = _chunkWADCJ7A7cjs.estimateNodeSize; exports.flowSide = _chunkWADCJ7A7cjs.flowSide; exports.getCenteredNodePosition = _chunkWADCJ7A7cjs.getCenteredNodePosition; exports.getLayoutedNodes = _chunkWADCJ7A7cjs.getLayoutedNodes; exports.isEventFromTextInput = isEventFromTextInput; exports.isValidCanvasEdge = isValidCanvasEdge; exports.isValidCanvasNode = isValidCanvasNode; exports.isValidUrl = isValidUrl; exports.layoutBounds = layoutBounds; exports.linearPositionTrajectory = linearPositionTrajectory; exports.linearTrajectory = linearTrajectory; exports.overlaps = _chunkWADCJ7A7cjs.overlaps; exports.pageHidden = pageHidden; exports.parseCanvasClipboardData = parseCanvasClipboardData; exports.placeBeside = _chunkWADCJ7A7cjs.placeBeside; exports.realClock = realClock; exports.remapPastedNodes = remapPastedNodes; exports.repositionNodesTo = repositionNodesTo; exports.runMultiNodeTransition = runMultiNodeTransition; exports.serializeCanvasNodes = serializeCanvasNodes; exports.withStyleOpacity = withStyleOpacity;
|
|
696
764
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/canvas/index.cjs","../../src/canvas/clock.ts","../../src/canvas/trajectory.ts","../../src/canvas/displacement.ts","../../src/canvas/clipboard.ts","../../src/canvas/view.ts","../../src/canvas/streaming.ts"],"names":[],"mappings":"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AAGP,IAAA;AACH,MAAA;AACA,MAAA;AACN,IAAA;AAG4C,IAAA;AACpB,IAAA;AACV,MAAA;AACd,IAAA;AAEiB,IAAA;AACR,MAAA;AACS,MAAA;AACjB,IAAA;AAEqB,IAAA;AACwB,IAAA;AAE3B,IAAA;AACE,MAAA;AACG,MAAA;AAEP,MAAA;AACM,MAAA;AAEJ,MAAA;AACA,QAAA;AAChB,UAAA;AACM,UAAA;AACF,UAAA;AACQ,UAAA;AACG,UAAA;AACf,QAAA;AACF,MAAA;AACD,IAAA;AAEuB,IAAA;AAEE,IAAA;AACnB,MAAA;AACQ,QAAA;AACI,QAAA;AAEC,UAAA;AACL,UAAA;AACE,YAAA;AACb,UAAA;AACK,0BAAA;AACN,QAAA;AACkB,QAAA;AACZ,UAAA;AACA,0BAAA;AACN,QAAA;AACA,MAAA;AACK,IAAA;AACiB,sBAAA;AACxB,IAAA;AACD,EAAA;AAEuB,EAAA;AACC,IAAA;AACJ,MAAA;AACE,MAAA;AACrB,IAAA;AACS,IAAA;AACH,MAAA;AACA,MAAA;AACN,IAAA;AACD,EAAA;AACD;ANmf6B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/canvas/index.cjs","sourcesContent":[null,"/**\n * The time source that canvas animations and agent performances play on.\n *\n * Defaults to `realClock` (requestAnimationFrame and setTimeout).\n * A `ManualClock` moves only when told to via `advance(ms)` or `tick(fps)`,\n * enabling deterministic frame-by-frame stepping for testing, video generation,\n * or headless server environments.\n */\n\nexport interface Clock {\n\t/** Current time in milliseconds. */\n\tnow(): number;\n\t/** Resolves on the next animation frame. */\n\tframe(): Promise<void>;\n\t/** Resolves after `ms` milliseconds of this clock's time. */\n\tsleep(ms: number): Promise<void>;\n\t/**\n\t * Whether the clock follows wall time. Live clocks stop or degrade when the\n\t * tab is in the background (browsers pause animation frames), so transitions\n\t * can commit immediately rather than leaving operations hanging.\n\t */\n\treadonly live: boolean;\n}\n\n/** Whether the browser tab is hidden (where RAF pauses). */\nexport const pageHidden = (): boolean =>\n\ttypeof document !== 'undefined' && document.hidden;\n\n/** Real-time clock using requestAnimationFrame and setTimeout. */\nexport const realClock: Clock = {\n\tlive: true,\n\tnow: () => (typeof performance !== 'undefined' ? performance.now() : Date.now()),\n\tframe: () =>\n\t\tnew Promise<void>((resolve) => {\n\t\t\tif (typeof requestAnimationFrame === 'function' && !pageHidden()) {\n\t\t\t\trequestAnimationFrame(() => resolve());\n\t\t\t} else {\n\t\t\t\tsetTimeout(resolve, 16);\n\t\t\t}\n\t\t}),\n\tsleep: (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, Math.max(0, ms)))\n};\n\nconst settle = () => new Promise<void>((resolve) => setTimeout(resolve, 0));\n\n/**\n * A deterministic clock that only moves forward when `advance` or `tick` is called.\n * Allows step-by-step frame testing and video rendering without waiting for real time.\n */\nexport class ManualClock implements Clock {\n\treadonly live = false;\n\tprivate time: number;\n\tprivate frames: (() => void)[] = [];\n\tprivate sleepers: { at: number; seq: number; resolve: () => void }[] = [];\n\tprivate seq = 0;\n\n\tconstructor(start = 0) {\n\t\tthis.time = start;\n\t}\n\n\tpublic now(): number {\n\t\treturn this.time;\n\t}\n\n\tpublic frame(): Promise<void> {\n\t\treturn new Promise<void>((resolve) => this.frames.push(resolve));\n\t}\n\n\tpublic sleep(ms: number): Promise<void> {\n\t\treturn new Promise<void>((resolve) =>\n\t\t\tthis.sleepers.push({\n\t\t\t\tat: this.time + Math.max(0, ms),\n\t\t\t\tseq: this.seq++,\n\t\t\t\tresolve\n\t\t\t})\n\t\t);\n\t}\n\n\t/** Whether any frames or sleep timers are currently pending. */\n\tpublic get pending(): boolean {\n\t\treturn this.frames.length > 0 || this.sleepers.length > 0;\n\t}\n\n\t/** Advances time by `ms`, resolving due sleep timers in order, followed by queued frames. */\n\tpublic async advance(ms: number): Promise<void> {\n\t\tconst end = this.time + Math.max(0, ms);\n\t\tawait settle();\n\n\t\twhile (true) {\n\t\t\tlet next: (typeof this.sleepers)[number] | undefined;\n\t\t\tfor (const s of this.sleepers) {\n\t\t\t\tif (s.at <= end && (!next || s.at < next.at || (s.at === next.at && s.seq < next.seq))) {\n\t\t\t\t\tnext = s;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!next) break;\n\n\t\t\tthis.sleepers.splice(this.sleepers.indexOf(next), 1);\n\t\t\tthis.time = Math.max(this.time, next.at);\n\t\t\tnext.resolve();\n\t\t\tawait settle();\n\t\t}\n\n\t\tthis.time = end;\n\t\tconst dueFrames = this.frames.splice(0, this.frames.length);\n\t\tfor (const resolveFrame of dueFrames) {\n\t\t\tresolveFrame();\n\t\t}\n\t\tawait settle();\n\t}\n\n\t/** Convenience method to advance by 1 frame at a given fps (default: 60fps = 16.67ms). */\n\tpublic async tick(fps = 60): Promise<void> {\n\t\tawait this.advance(Math.round(1000 / fps));\n\t}\n}\n","import type {\n\tCanvasNode,\n\tFanOutTrajectoryOptions,\n\tNodeTransition,\n\tTrajectoryFunction,\n\tTrajectoryPoint,\n\tXYPosition\n} from './types.js';\n\n/**\n * Standard cubic ease-out function (pure math, framework-agnostic).\n */\nexport const defaultEasing = (t: number): number => --t * t * t + 1;\n\n/**\n * Standard linear trajectory: straight line interpolation with linear scale & opacity progression.\n */\nexport const linearTrajectory: TrajectoryFunction = (\n\torigin: XYPosition,\n\ttarget: XYPosition,\n\tprogress: number\n): TrajectoryPoint => {\n\treturn {\n\t\tposition: {\n\t\t\tx: origin.x + (target.x - origin.x) * progress,\n\t\t\ty: origin.y + (target.y - origin.y) * progress\n\t\t},\n\t\tscale: progress,\n\t\topacity: Math.min(1, progress * 1.5)\n\t};\n};\n\n/**\n * Linear position trajectory: pure position interpolation without altering scale or opacity.\n */\nexport const linearPositionTrajectory: TrajectoryFunction = (\n\torigin: XYPosition,\n\ttarget: XYPosition,\n\tprogress: number\n): TrajectoryPoint => {\n\treturn {\n\t\tposition: {\n\t\t\tx: origin.x + (target.x - origin.x) * progress,\n\t\t\ty: origin.y + (target.y - origin.y) * progress\n\t\t}\n\t};\n};\n\n/**\n * Creates a fan-out trajectory where nodes arc outward from origin to target.\n */\nexport function createFanOutTrajectory(options: FanOutTrajectoryOptions = {}): TrajectoryFunction {\n\tconst {\n\t\tcurvature = 0.4,\n\t\tstartScale = 0,\n\t\tendScale = 1,\n\t\tstartOpacity = 0,\n\t\tendOpacity = 1\n\t} = options;\n\n\treturn (\n\t\torigin: XYPosition,\n\t\ttarget: XYPosition,\n\t\tprogress: number,\n\t\tindex: number,\n\t\ttotal: number\n\t): TrajectoryPoint => {\n\t\tconst dx = target.x - origin.x;\n\t\tconst dy = target.y - origin.y;\n\n\t\t// Normalized index from -1 (top) to +1 (bottom)\n\t\tconst normIndex = total > 1 ? (index - (total - 1) / 2) / ((total - 1) / 2) : 0;\n\n\t\t// Perpendicular control point offset to create smooth fan arc\n\t\tconst midX = origin.x + dx * 0.4;\n\t\tconst midY = origin.y + dy * 0.1 - normIndex * Math.abs(dx) * 0.15 * curvature;\n\n\t\t// Quadratic Bezier interpolation: B(t) = (1-t)^2 * P0 + 2(1-t)t * P1 + t^2 * P2\n\t\tconst t = progress;\n\t\tconst oneMinusT = 1 - t;\n\n\t\tconst x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * midX + t * t * target.x;\n\t\tconst y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * midY + t * t * target.y;\n\n\t\tconst scale = startScale + (endScale - startScale) * progress;\n\t\tconst opacity = startOpacity + (endOpacity - startOpacity) * progress;\n\n\t\treturn {\n\t\t\tposition: { x, y },\n\t\t\tscale,\n\t\t\topacity\n\t\t};\n\t};\n}\n\n/**\n * Creates a custom quadratic Bezier trajectory with a specified control point resolver.\n */\nexport function createBezierTrajectory(\n\tgetControlPoint: (origin: XYPosition, target: XYPosition) => XYPosition\n): TrajectoryFunction {\n\treturn (origin: XYPosition, target: XYPosition, progress: number): TrajectoryPoint => {\n\t\tconst cp = getControlPoint(origin, target);\n\t\tconst t = progress;\n\t\tconst oneMinusT = 1 - t;\n\n\t\tconst x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * cp.x + t * t * target.x;\n\t\tconst y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * cp.y + t * t * target.y;\n\n\t\treturn {\n\t\t\tposition: { x, y },\n\t\t\tscale: progress,\n\t\t\topacity: progress\n\t\t};\n\t};\n}\n\nimport { realClock, type Clock } from './clock.js';\n\n/**\n * Coordinates and animates multiple node transitions simultaneously with zero per-frame array allocations.\n */\nexport function runMultiNodeTransition<TNode extends CanvasNode = CanvasNode>(\n\ttransitions: NodeTransition<TNode>[],\n\toptions: {\n\t\tdefaultDuration?: number;\n\t\tdefaultEasing?: (t: number) => number;\n\t\tclock?: Clock;\n\t\tonUpdate?: () => void;\n\t\tonComplete?: () => void;\n\t} = {}\n): () => void {\n\tif (transitions.length === 0) {\n\t\toptions.onComplete?.();\n\t\treturn () => {};\n\t}\n\n\tconst {\n\t\tdefaultDuration = 400,\n\t\tdefaultEasing: easingFunc = defaultEasing,\n\t\tclock = realClock,\n\t\tonUpdate,\n\t\tonComplete\n\t} = options;\n\n\tlet isCancelled = false;\n\tconst startTime = clock.now();\n\n\tconst items = transitions.map((tr, i) => ({\n\t\t...tr,\n\t\tindex: tr.index ?? i,\n\t\ttotal: tr.total ?? transitions.length,\n\t\tduration: tr.duration ?? defaultDuration,\n\t\teasing: tr.easing ?? easingFunc,\n\t\tdelay: tr.delay ?? 0,\n\t\ttrajectory: tr.trajectory ?? linearTrajectory\n\t}));\n\n\tfunction frame() {\n\t\tif (isCancelled) return;\n\n\t\tconst now = clock.now();\n\t\tlet allCompleted = true;\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst item = items[i];\n\t\t\tconst elapsed = now - (startTime + item.delay);\n\n\t\t\tif (elapsed < 0) {\n\t\t\t\tallCompleted = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Guard zero duration and division by zero (referenced in GOTCHAS.md)\n\t\t\tconst rawProgress = item.duration <= 0 ? 1 : Math.min(elapsed / item.duration, 1);\n\t\t\tconst progress = item.duration <= 0 ? 1 : item.easing(rawProgress);\n\n\t\t\tconst point = item.trajectory(item.from, item.to, progress, item.index, item.total);\n\n\t\t\titem.node.position = { ...point.position };\n\n\t\t\tif (point.scale !== undefined || point.opacity !== undefined) {\n\t\t\t\tif (!item.node.data) {\n\t\t\t\t\titem.node.data = {} as any;\n\t\t\t\t}\n\t\t\t\tif (point.scale !== undefined) {\n\t\t\t\t\t(item.node.data as any).scale = point.scale;\n\t\t\t\t}\n\t\t\t\tif (point.opacity !== undefined) {\n\t\t\t\t\t(item.node.data as any).opacity = point.opacity;\n\t\t\t\t\tconst currentStyle = (item.node.style || '').replace(/opacity:\\s*[^;]+;?/g, '').trim();\n\t\t\t\t\titem.node.style = `${currentStyle ? currentStyle + '; ' : ''}opacity: ${point.opacity};`;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (rawProgress < 1) {\n\t\t\t\tallCompleted = false;\n\t\t\t}\n\t\t}\n\n\t\tonUpdate?.();\n\n\t\tif (!allCompleted) {\n\t\t\tclock.frame().then(frame);\n\t\t} else {\n\t\t\tonComplete?.();\n\t\t}\n\t}\n\n\tframe();\n\n\treturn () => {\n\t\tisCancelled = true;\n\t};\n}\n","import dagre from '@dagrejs/dagre';\nimport type {\n\tCanvasEdge,\n\tCanvasNode,\n\tDirectionalDisplacementOptions,\n\tRect,\n\tReflowDisplacementOptions,\n\tXYPosition\n} from './types.js';\n\n/**\n * Calculates a bounding rectangle for a set of nodes if not provided by getNodesBounds.\n */\nexport function computeNodesBoundingBox<TNode extends CanvasNode = CanvasNode>(\n\tnodes: TNode[],\n\tdefaultWidth = 200,\n\tdefaultHeight = 60\n): Rect {\n\tif (nodes.length === 0) {\n\t\treturn { x: 0, y: 0, width: 0, height: 0 };\n\t}\n\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\n\tfor (const node of nodes) {\n\t\tconst width = node.measured?.width ?? (node as any).width ?? defaultWidth;\n\t\tconst height = node.measured?.height ?? (node as any).height ?? defaultHeight;\n\n\t\tminX = Math.min(minX, node.position.x);\n\t\tminY = Math.min(minY, node.position.y);\n\t\tmaxX = Math.max(maxX, node.position.x + width);\n\t\tmaxY = Math.max(maxY, node.position.y + height);\n\t}\n\n\treturn {\n\t\tx: minX,\n\t\ty: minY,\n\t\twidth: maxX - minX,\n\t\theight: maxY - minY\n\t};\n}\n\n/**\n * Pure directional displacement calculation.\n * Shifts downstream or surrounding nodes along an axis to clear space for newly inserted child nodes.\n */\nexport function calculateDirectionalDisplacement<TNode extends CanvasNode = CanvasNode>(params: {\n\texistingNodes: TNode[];\n\toriginNode: TNode;\n\tchildNodes: TNode[];\n\tgetNodesBounds?: (nodes: TNode[]) => Rect;\n\toptions?: DirectionalDisplacementOptions;\n}): Map<string, XYPosition> {\n\tconst {\n\t\texistingNodes,\n\t\toriginNode,\n\t\tchildNodes,\n\t\tgetNodesBounds,\n\t\toptions = {}\n\t} = params;\n\n\tconst {\n\t\tdirection = 'right',\n\t\tgap = 40,\n\t\tspreadSiblingLanes = false,\n\t\tsiblingTolerance = 50,\n\t\tminY\n\t} = options;\n\n\tconst displacedMap = new Map<string, XYPosition>();\n\tif (childNodes.length === 0 || existingNodes.length === 0) {\n\t\treturn displacedMap;\n\t}\n\n\tconst childBounds = getNodesBounds\n\t\t? getNodesBounds(childNodes)\n\t\t: computeNodesBoundingBox(childNodes);\n\n\tconst originWidth = originNode.measured?.width ?? (originNode as any).width ?? 200;\n\tconst originHeight = originNode.measured?.height ?? (originNode as any).height ?? 60;\n\n\t// The delta space required along primary axis\n\tconst deltaPrimary =\n\t\tdirection === 'right' || direction === 'left'\n\t\t\t? childBounds.width + gap\n\t\t\t: childBounds.height + gap;\n\n\t// Vertical displacement parameters: upward and downward row clearance\n\tconst deltaUp = Math.max(0, originNode.position.y - childBounds.y + gap);\n\tconst deltaDown = Math.max(\n\t\t0,\n\t\tchildBounds.y + childBounds.height - (originNode.position.y + originHeight) + gap\n\t);\n\n\t// Both above and below displace equally so the row expands symmetrically\n\tconst equalDelta = Math.max(deltaUp, deltaDown);\n\n\tfor (const node of existingNodes) {\n\t\tif (node.id === originNode.id) continue;\n\n\t\tconst isSiblingRow =\n\t\t\tMath.abs(node.position.y - originNode.position.y) < siblingTolerance;\n\n\t\tswitch (direction) {\n\t\t\tcase 'right': {\n\t\t\t\tif (node.position.x > originNode.position.x) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x + deltaPrimary,\n\t\t\t\t\t\ty: node.position.y\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\tif (node.position.x < originNode.position.x) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x - deltaPrimary,\n\t\t\t\t\t\ty: node.position.y\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'down': {\n\t\t\t\tif (node.position.y > originNode.position.y) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x,\n\t\t\t\t\t\ty: node.position.y + deltaPrimary\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'up': {\n\t\t\t\tif (node.position.y < originNode.position.y) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x,\n\t\t\t\t\t\ty: node.position.y - deltaPrimary\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'vertical': {\n\t\t\t\tif (isSiblingRow) break;\n\n\t\t\t\tif (node.position.y < originNode.position.y) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x,\n\t\t\t\t\t\ty: node.position.y - equalDelta\n\t\t\t\t\t});\n\t\t\t\t} else if (node.position.y > originNode.position.y) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x,\n\t\t\t\t\t\ty: node.position.y + equalDelta\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Sibling lane spreading to avoid overlap among child nodes\n\tif (spreadSiblingLanes && (direction === 'right' || direction === 'left')) {\n\t\tfor (const [nodeId, pos] of displacedMap.entries()) {\n\t\t\tconst node = existingNodes.find((n) => n.id === nodeId);\n\t\t\tif (node && Math.abs(node.position.y - originNode.position.y) < siblingTolerance) {\n\t\t\t\tconst isAbove = node.position.y < originNode.position.y;\n\t\t\t\tdisplacedMap.set(nodeId, {\n\t\t\t\t\tx: pos.x,\n\t\t\t\t\ty: pos.y + (isAbove ? -deltaUp : deltaDown)\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Floor constraint\n\tif (minY !== undefined) {\n\t\tfor (const [nodeId, pos] of displacedMap.entries()) {\n\t\t\tif (pos.y < minY) {\n\t\t\t\tdisplacedMap.set(nodeId, { x: pos.x, y: minY });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn displacedMap;\n}\n\n/**\n * Calculates Dagre reflow displacement preserving the position of an anchor node.\n */\nexport function calculateDagreReflowDisplacement<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(params: {\n\tcurrentNodes: TNode[];\n\tcurrentEdges: TEdge[];\n\tfutureNodes: TNode[];\n\tfutureEdges: TEdge[];\n\toptions: ReflowDisplacementOptions;\n\tgetNodesBounds?: (nodes: TNode[]) => Rect;\n}): Map<string, XYPosition> {\n\tconst {\n\t\tcurrentNodes,\n\t\tfutureNodes,\n\t\tfutureEdges,\n\t\toptions\n\t} = params;\n\n\tconst {\n\t\tanchorNodeId,\n\t\tdirection = 'LR',\n\t\tranksep = 100,\n\t\tnodesep = 25,\n\t\tdefaultNodeWidth = 200,\n\t\tdefaultNodeHeight = 60\n\t} = options;\n\n\tconst anchorNode = currentNodes.find((n) => n.id === anchorNodeId);\n\tif (!anchorNode) return new Map();\n\n\tconst g = new dagre.graphlib.Graph();\n\tg.setDefaultEdgeLabel(() => ({}));\n\tg.setGraph({ rankdir: direction, ranksep, nodesep });\n\n\tconst nodeIds = new Set(futureNodes.map((n) => n.id));\n\n\tfutureNodes.forEach((node) => {\n\t\tconst nodeWidth = node.measured?.width ?? (node as any).width ?? defaultNodeWidth;\n\t\tconst nodeHeight = node.measured?.height ?? (node as any).height ?? defaultNodeHeight;\n\t\tg.setNode(node.id, { width: nodeWidth, height: nodeHeight });\n\t});\n\n\tfutureEdges.forEach((edge) => {\n\t\tif (nodeIds.has(edge.source) && nodeIds.has(edge.target)) {\n\t\t\tg.setEdge(edge.source, edge.target);\n\t\t}\n\t});\n\n\tdagre.layout(g);\n\n\tconst anchorLayoutPos = g.node(anchorNodeId);\n\tif (!anchorLayoutPos) return new Map();\n\n\tconst anchorWidth = anchorNode.measured?.width ?? (anchorNode as any).width ?? defaultNodeWidth;\n\tconst anchorHeight = anchorNode.measured?.height ?? (anchorNode as any).height ?? defaultNodeHeight;\n\n\tconst anchorLayoutUpperLeft = {\n\t\tx: anchorLayoutPos.x - anchorWidth / 2,\n\t\ty: anchorLayoutPos.y - anchorHeight / 2\n\t};\n\n\tconst deltaX = anchorNode.position.x - anchorLayoutUpperLeft.x;\n\tconst deltaY = anchorNode.position.y - anchorLayoutUpperLeft.y;\n\n\tconst displacementMap = new Map<string, XYPosition>();\n\n\tcurrentNodes.forEach((node) => {\n\t\tif (node.id === anchorNodeId) return;\n\n\t\tconst layoutNode = g.node(node.id);\n\t\tif (!layoutNode) return;\n\n\t\tconst nodeWidth = node.measured?.width ?? (node as any).width ?? defaultNodeWidth;\n\t\tconst nodeHeight = node.measured?.height ?? (node as any).height ?? defaultNodeHeight;\n\n\t\tconst upperLeftX = layoutNode.x - nodeWidth / 2 + deltaX;\n\t\tconst upperLeftY = layoutNode.y - nodeHeight / 2 + deltaY;\n\n\t\tif (\n\t\t\tMath.abs(upperLeftX - node.position.x) > 1 ||\n\t\t\tMath.abs(upperLeftY - node.position.y) > 1\n\t\t) {\n\t\t\tdisplacementMap.set(node.id, { x: upperLeftX, y: upperLeftY });\n\t\t}\n\t});\n\n\treturn displacementMap;\n}\n","import type {\n\tCanvasClipboardPayload,\n\tCanvasEdge,\n\tCanvasNode,\n\tXYPosition\n} from './types.js';\n\n/**\n * Checks if an event originated from a text input, textarea, contenteditable element, or rich editor.\n */\nexport function isEventFromTextInput(event: Event | { target: EventTarget | null }): boolean {\n\tconst target = (event as any).target as HTMLElement | null;\n\tif (!target) return false;\n\tif (\n\t\ttarget.tagName === 'INPUT' ||\n\t\ttarget.tagName === 'TEXTAREA' ||\n\t\ttarget.tagName === 'SELECT' ||\n\t\ttarget.isContentEditable ||\n\t\ttarget.closest?.('[contenteditable=\"true\"]') ||\n\t\ttarget.closest?.('.ProseMirror')\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Validates that an object conforms to minimal CanvasNode shape.\n */\nexport function isValidCanvasNode(obj: unknown): obj is CanvasNode {\n\treturn (\n\t\ttypeof obj === 'object' &&\n\t\tobj !== null &&\n\t\t'id' in obj &&\n\t\ttypeof (obj as any).id === 'string' &&\n\t\t'position' in obj &&\n\t\ttypeof (obj as any).position === 'object' &&\n\t\t(obj as any).position !== null &&\n\t\t'x' in (obj as any).position &&\n\t\t'y' in (obj as any).position\n\t);\n}\n\n/**\n * Checks if a string is a valid HTTP/HTTPS URL.\n */\nexport function isValidUrl(url: string): boolean {\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\treturn parsed.protocol === 'http:' || parsed.protocol === 'https:';\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Serializes nodes and optional edges into clipboard JSON payload.\n */\nexport function serializeCanvasNodes<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(nodes: TNode[], edges?: TEdge[]): string {\n\tconst payload: CanvasClipboardPayload<TNode, TEdge> = {\n\t\tversion: 1,\n\t\tnodes,\n\t\tedges\n\t};\n\treturn JSON.stringify(payload);\n}\n\n/**\n * Parses raw JSON string into a CanvasClipboardPayload if valid.\n */\nexport function parseCanvasClipboardData<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(raw: string): CanvasClipboardPayload<TNode, TEdge> | null {\n\ttry {\n\t\tconst parsed = JSON.parse(raw);\n\t\tif (\n\t\t\ttypeof parsed === 'object' &&\n\t\t\tparsed !== null &&\n\t\t\tArray.isArray(parsed.nodes) &&\n\t\t\tparsed.nodes.length > 0 &&\n\t\t\tparsed.nodes.every(isValidCanvasNode)\n\t\t) {\n\t\t\treturn parsed as CanvasClipboardPayload<TNode, TEdge>;\n\t\t}\n\t} catch {\n\t\t// Not JSON or invalid payload\n\t}\n\treturn null;\n}\n\n/**\n * Generates unique new IDs for pasted nodes and updates edge references accordingly.\n */\nexport function remapPastedNodes<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(\n\tnodes: TNode[],\n\tedges: TEdge[] = [],\n\toffset: XYPosition = { x: 30, y: 30 },\n\tidGenerator: () => string = () => `node-${Math.random().toString(36).substring(2, 9)}`\n): { nodes: TNode[]; edges: TEdge[] } {\n\tconst idMap = new Map<string, string>();\n\n\tconst newNodes = nodes.map((node) => {\n\t\tconst newId = idGenerator();\n\t\tidMap.set(node.id, newId);\n\t\treturn {\n\t\t\t...node,\n\t\t\tid: newId,\n\t\t\tposition: {\n\t\t\t\tx: node.position.x + offset.x,\n\t\t\t\ty: node.position.y + offset.y\n\t\t\t},\n\t\t\tselected: true\n\t\t};\n\t});\n\n\tconst newEdges = edges\n\t\t.filter((e) => idMap.has(e.source) && idMap.has(e.target))\n\t\t.map((edge) => ({\n\t\t\t...edge,\n\t\t\tid: `edge-${Math.random().toString(36).substring(2, 9)}`,\n\t\t\tsource: idMap.get(edge.source)!,\n\t\t\ttarget: idMap.get(edge.target)!,\n\t\t\tselected: false\n\t\t}));\n\n\treturn { nodes: newNodes, edges: newEdges };\n}\n\n/**\n * Repositions nodes so their bounding box origin matches the given target position.\n */\nexport function repositionNodesTo<TNode extends CanvasNode = CanvasNode>(\n\tnodes: TNode[],\n\ttargetOrigin: XYPosition\n): TNode[] {\n\tif (nodes.length === 0) return [];\n\tconst minX = Math.min(...nodes.map((n) => n.position.x));\n\tconst minY = Math.min(...nodes.map((n) => n.position.y));\n\tconst deltaX = targetOrigin.x - minX;\n\tconst deltaY = targetOrigin.y - minY;\n\n\treturn nodes.map((n) => ({\n\t\t...n,\n\t\tposition: {\n\t\t\tx: n.position.x + deltaX,\n\t\t\ty: n.position.y + deltaY\n\t\t}\n\t}));\n}\n","import type { CanvasEdge, CanvasNode, Rect } from './types.js';\n\nexport interface CanvasHeightOptions {\n\t/** Smallest height returned (default 320). */\n\tmin?: number;\n\t/** Largest height returned; taller content is scaled/zoomed (default 560). */\n\tmax?: number;\n\t/** Extra padding around the content (default 48). */\n\tpadding?: number;\n}\n\nfunction clampHeight(contentHeight: number, options: CanvasHeightOptions = {}): number {\n\tconst { min = 320, max = 560, padding = 48 } = options;\n\treturn Math.round(Math.min(max, Math.max(min, contentHeight + padding)));\n}\n\n/**\n * Calculates the bounding box extent of all positioned nodes, or `null` for an empty graph.\n */\nexport function layoutBounds<TNode extends CanvasNode = CanvasNode>(\n\tnodes: TNode[]\n): Rect | null {\n\tif (nodes.length === 0) return null;\n\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\n\tfor (const node of nodes) {\n\t\tconst x = node.position.x;\n\t\tconst y = node.position.y;\n\t\tconst width = node.width ?? 180;\n\t\tconst height = node.height ?? 80;\n\n\t\tminX = Math.min(minX, x);\n\t\tminY = Math.min(minY, y);\n\t\tmaxX = Math.max(maxX, x + width);\n\t\tmaxY = Math.max(maxY, y + height);\n\t}\n\n\tif (minX === Infinity) return null;\n\treturn { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/**\n * Returns a clamped container height that fits the layout at 1:1 scale without overflow.\n */\nexport function canvasHeight<TNode extends CanvasNode = CanvasNode>(\n\tnodes: TNode[],\n\toptions?: CanvasHeightOptions\n): number {\n\treturn clampHeight(layoutBounds(nodes)?.height ?? 0, options);\n}\n\nconst DEFAULT_RANK_HEIGHT = 80 + 72; // Average node height + default rank separation\nconst NODES_PER_RANK = 2;\n\n/**\n * Estimates the container height to reserve before layout calculation finishes,\n * based on node and edge counts alone. Prevents layout shift (CLS).\n */\nexport function estimateCanvasHeight<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(\n\tnodes: TNode[],\n\tedges: TEdge[],\n\toptions?: CanvasHeightOptions\n): number {\n\tconst ranks = Math.max(1, Math.ceil(nodes.length / NODES_PER_RANK));\n\treturn clampHeight(ranks * DEFAULT_RANK_HEIGHT, options);\n}\n\nfunction mix(a: number, b: number, t: number): number {\n\treturn a + (b - a) * t;\n}\n\n/**\n * Interpolates node positions and sizes between two layouts partway at progress `t` (0 = from, 1 = to).\n * Nodes present in both interpolate smoothly; nodes newly added in `to` snap to target.\n */\nexport function blendLayout<TNode extends CanvasNode = CanvasNode>(\n\tfrom: TNode[],\n\tto: TNode[],\n\tt: number\n): TNode[] {\n\tif (t >= 1) return to;\n\n\tconst fromMap = new Map<string, TNode>(from.map((n) => [n.id, n]));\n\n\treturn to.map((target) => {\n\t\tconst origin = fromMap.get(target.id);\n\t\tif (!origin) return target;\n\n\t\treturn {\n\t\t\t...target,\n\t\t\tposition: {\n\t\t\t\tx: mix(origin.position.x, target.position.x, t),\n\t\t\t\ty: mix(origin.position.y, target.position.y, t)\n\t\t\t},\n\t\t\twidth:\n\t\t\t\torigin.width !== undefined && target.width !== undefined\n\t\t\t\t\t? mix(origin.width, target.width, t)\n\t\t\t\t\t: target.width,\n\t\t\theight:\n\t\t\t\torigin.height !== undefined && target.height !== undefined\n\t\t\t\t\t? mix(origin.height, target.height, t)\n\t\t\t\t\t: target.height\n\t\t};\n\t});\n}\n\n/**\n * Filters out nodes that are not touched by any edge.\n *\n * During LLM streaming, nodes often arrive a chunk or token before the edge\n * that connects them. Displaying them immediately causes them to be placed as root\n * nodes only to jump into their correct position once the edge arrives.\n * Hiding orphan nodes during active streaming keeps the layout calm and jitter-free.\n */\nexport function connectedOnly<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(\n\tnodes: TNode[],\n\tedges: TEdge[]\n): TNode[] {\n\tif (edges.length === 0) return nodes;\n\n\tconst linkedNodeIds = new Set<string>();\n\tfor (const edge of edges) {\n\t\tlinkedNodeIds.add(edge.source);\n\t\tlinkedNodeIds.add(edge.target);\n\t}\n\n\tconst filtered = nodes.filter((node) => linkedNodeIds.has(node.id));\n\t// If filtering would remove everything, return the original nodes\n\treturn filtered.length > 0 ? filtered : nodes;\n}\n","import { realClock, type Clock } from './clock.js';\nimport { ensureLayout } from './layout.js';\nimport { linearPositionTrajectory, runMultiNodeTransition } from './trajectory.js';\nimport type { CanvasEdge, CanvasNode, IncrementalLayoutOptions, NodeTransition, XYPosition } from './types.js';\nimport { connectedOnly } from './view.js';\n\nexport interface StreamingLayoutManagerOptions {\n\tthrottleMs?: number;\n\tglideDurationMs?: number;\n\tconnectedOnly?: boolean;\n\tclock?: Clock;\n\tlayoutOptions?: IncrementalLayoutOptions;\n\tonLayoutUpdated?: (positions: Map<string, XYPosition>) => void;\n}\n\n/**\n * Manages throttled incremental layout recalculation and smooth tweened node gliding\n * during active streaming (e.g. LLM streaming or graph generation).\n */\nexport class StreamingLayoutManager<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n> {\n\tprivate throttleMs: number;\n\tprivate glideDurationMs: number;\n\tprivate connectedOnly: boolean;\n\tprivate clock: Clock;\n\tprivate layoutOptions: IncrementalLayoutOptions;\n\tprivate onLayoutUpdated?: (positions: Map<string, XYPosition>) => void;\n\n\tprivate pendingTimer: any = null;\n\tprivate activeTransitionCancel: (() => void) | null = null;\n\tprivate targetPositions = new Map<string, XYPosition>();\n\n\tconstructor(options: StreamingLayoutManagerOptions = {}) {\n\t\tthis.throttleMs = options.throttleMs ?? 200;\n\t\tthis.glideDurationMs = options.glideDurationMs ?? 300;\n\t\tthis.connectedOnly = options.connectedOnly ?? false;\n\t\tthis.clock = options.clock ?? realClock;\n\t\tthis.layoutOptions = options.layoutOptions ?? { direction: 'LR' };\n\t\tthis.onLayoutUpdated = options.onLayoutUpdated;\n\t}\n\n\t/**\n\t * Feed incoming nodes and edges into the streaming manager.\n\t * Coalesces rapid streaming bursts and triggers smooth layout gliding.\n\t */\n\tpublic pushStreamUpdate(\n\t\tnodes: TNode[],\n\t\tedges: TEdge[],\n\t\tcurrentPositions: Map<string, XYPosition>\n\t): void {\n\t\tif (this.pendingTimer) {\n\t\t\tclearTimeout(this.pendingTimer);\n\t\t}\n\n\t\tthis.pendingTimer = setTimeout(() => {\n\t\t\tthis.pendingTimer = null;\n\t\t\tthis.recalculateAndGlide(nodes, edges, currentPositions);\n\t\t}, this.throttleMs);\n\t}\n\n\t/**\n\t * Forces immediate calculation and cancels pending throttled timers.\n\t */\n\tpublic flush(\n\t\tnodes: TNode[],\n\t\tedges: TEdge[],\n\t\tcurrentPositions: Map<string, XYPosition>\n\t): void {\n\t\tif (this.pendingTimer) {\n\t\t\tclearTimeout(this.pendingTimer);\n\t\t\tthis.pendingTimer = null;\n\t\t}\n\t\tthis.recalculateAndGlide(nodes, edges, currentPositions);\n\t}\n\n\tprivate recalculateAndGlide(\n\t\tnodes: TNode[],\n\t\tedges: TEdge[],\n\t\tcurrentPositions: Map<string, XYPosition>\n\t): void {\n\t\tconst targetNodes = this.connectedOnly ? connectedOnly(nodes, edges) : nodes;\n\t\tif (targetNodes.length === 0) return;\n\n\t\t// Cancel any currently running RAF glide\n\t\tif (this.activeTransitionCancel) {\n\t\t\tthis.activeTransitionCancel();\n\t\t\tthis.activeTransitionCancel = null;\n\t\t}\n\n\t\t// Incremental layout preserves existing nodes and aligns new nodes\n\t\tconst stored: Record<string, XYPosition> = {};\n\t\tfor (const [id, pos] of currentPositions.entries()) {\n\t\t\tstored[id] = pos;\n\t\t}\n\n\t\tconst layouted = ensureLayout(targetNodes, edges, {\n\t\t\t...this.layoutOptions,\n\t\t\tstoredPositions: stored\n\t\t});\n\n\t\tconst nextPositions = new Map<string, XYPosition>();\n\t\tconst transitions: NodeTransition<TNode>[] = [];\n\n\t\tfor (const node of layouted) {\n\t\t\tconst target = node.position;\n\t\t\tnextPositions.set(node.id, target);\n\n\t\t\tconst current = currentPositions.get(node.id) ?? target;\n\t\t\tconst distance = Math.hypot(target.x - current.x, target.y - current.y);\n\n\t\t\tif (distance > 2) {\n\t\t\t\ttransitions.push({\n\t\t\t\t\tnode,\n\t\t\t\t\tfrom: current,\n\t\t\t\t\tto: target,\n\t\t\t\t\ttrajectory: linearPositionTrajectory,\n\t\t\t\t\tduration: this.glideDurationMs\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis.targetPositions = nextPositions;\n\n\t\tif (transitions.length > 0) {\n\t\t\tthis.activeTransitionCancel = runMultiNodeTransition(transitions, {\n\t\t\t\tclock: this.clock,\n\t\t\t\tonUpdate: () => {\n\t\t\t\t\t// Broadcast updated positions during RAF\n\t\t\t\t\tconst liveMap = new Map<string, XYPosition>(currentPositions);\n\t\t\t\t\tfor (const trans of transitions) {\n\t\t\t\t\t\tliveMap.set(trans.node.id, { ...trans.node.position });\n\t\t\t\t\t}\n\t\t\t\t\tthis.onLayoutUpdated?.(liveMap);\n\t\t\t\t},\n\t\t\t\tonComplete: () => {\n\t\t\t\t\tthis.activeTransitionCancel = null;\n\t\t\t\t\tthis.onLayoutUpdated?.(nextPositions);\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\tthis.onLayoutUpdated?.(nextPositions);\n\t\t}\n\t}\n\n\tpublic destroy(): void {\n\t\tif (this.pendingTimer) {\n\t\t\tclearTimeout(this.pendingTimer);\n\t\t\tthis.pendingTimer = null;\n\t\t}\n\t\tif (this.activeTransitionCancel) {\n\t\t\tthis.activeTransitionCancel();\n\t\t\tthis.activeTransitionCancel = null;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/canvas/index.cjs","../../src/canvas/clock.ts","../../src/canvas/trajectory.ts","../../src/canvas/displacement.ts","../../src/canvas/clipboard.ts","../../src/canvas/view.ts","../../src/canvas/streaming.ts"],"names":[],"mappings":"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A;AAMC,EAAA;AAIK,IAAA;AACA,IAAA;AACN,EAAA;AAAA;AAAA;AAAA;AAKO,EAAA;AACC,IAAA;AACR,EAAA;AAEQ,EAAA;AACH,IAAA;AACH,MAAA;AACK,MAAA;AACN,IAAA;AACK,IAAA;AACN,EAAA;AAEQ,EAAA;AAKD,IAAA;AACF,IAAA;AAIE,IAAA;AACF,IAAA;AACH,MAAA;AACC,QAAA;AACD,MAAA;AACK,MAAA;AACA,MAAA;AACN,IAAA;AAIM,IAAA;AAEA,IAAA;AACA,IAAA;AAEN,IAAA;AACO,MAAA;AACN,MAAA;AAEM,MAAA;AACD,MAAA;AAEC,MAAA;AACF,MAAA;AACH,QAAA;AACC,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,QAAA;AACF,MAAA;AACD,IAAA;AAEK,IAAA;AAED,IAAA;AACE,MAAA;AACA,sBAAA;AACL,MAAA;AACD,IAAA;AAEM,IAAA;AACN,IAAA;AACM,MAAA;AACN,IAAA;AACK,IAAA;AAED,IAAA;AACE,IAAA;AACL,MAAA;AACA,MAAA;AACC,QAAA;AACA,QAAA;AACC,UAAA;AACD,QAAA;AACA,QAAA;AACA,wBAAA;AACD,MAAA;AACA,MAAA;AACC,QAAA;AACA,QAAA;AACA,QAAA;AACA,wBAAA;AACD,MAAA;AACA,IAAA;AAEI,IAAA;AACN,EAAA;AAEuB,EAAA;AACjB,IAAA;AACD,IAAA;AACE,MAAA;AACA,MAAA;AACN,IAAA;AACD,EAAA;AACD;ANugBY;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/canvas/index.cjs","sourcesContent":[null,"/**\n * The time source that canvas animations and agent performances play on.\n *\n * Defaults to `realClock` (requestAnimationFrame and setTimeout).\n * A `ManualClock` moves only when told to via `advance(ms)` or `tick(fps)`,\n * enabling deterministic frame-by-frame stepping for testing, video generation,\n * or headless server environments.\n */\n\nexport interface Clock {\n\t/** Current time in milliseconds. */\n\tnow(): number;\n\t/** Resolves on the next animation frame. */\n\tframe(): Promise<void>;\n\t/** Resolves after `ms` milliseconds of this clock's time. */\n\tsleep(ms: number): Promise<void>;\n\t/**\n\t * Whether the clock follows wall time. Live clocks stop or degrade when the\n\t * tab is in the background (browsers pause animation frames), so transitions\n\t * can commit immediately rather than leaving operations hanging.\n\t */\n\treadonly live: boolean;\n}\n\n/** Whether the browser tab is hidden (where RAF pauses). */\nexport const pageHidden = (): boolean =>\n\ttypeof document !== 'undefined' && document.hidden;\n\n/** Real-time clock using requestAnimationFrame and setTimeout. */\nexport const realClock: Clock = {\n\tlive: true,\n\tnow: () => (typeof performance !== 'undefined' ? performance.now() : Date.now()),\n\tframe: () =>\n\t\tnew Promise<void>((resolve) => {\n\t\t\tif (typeof requestAnimationFrame === 'function' && !pageHidden()) {\n\t\t\t\trequestAnimationFrame(() => resolve());\n\t\t\t} else {\n\t\t\t\tsetTimeout(resolve, 16);\n\t\t\t}\n\t\t}),\n\tsleep: (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, Math.max(0, ms)))\n};\n\nconst settle = () => new Promise<void>((resolve) => setTimeout(resolve, 0));\n\n/**\n * A deterministic clock that only moves forward when `advance` or `tick` is called.\n * Allows step-by-step frame testing and video rendering without waiting for real time.\n */\nexport class ManualClock implements Clock {\n\treadonly live = false;\n\tprivate time: number;\n\tprivate frames: (() => void)[] = [];\n\tprivate sleepers: { at: number; seq: number; resolve: () => void }[] = [];\n\tprivate seq = 0;\n\n\tconstructor(start = 0) {\n\t\tthis.time = start;\n\t}\n\n\tpublic now(): number {\n\t\treturn this.time;\n\t}\n\n\tpublic frame(): Promise<void> {\n\t\treturn new Promise<void>((resolve) => this.frames.push(resolve));\n\t}\n\n\tpublic sleep(ms: number): Promise<void> {\n\t\treturn new Promise<void>((resolve) =>\n\t\t\tthis.sleepers.push({\n\t\t\t\tat: this.time + Math.max(0, ms),\n\t\t\t\tseq: this.seq++,\n\t\t\t\tresolve\n\t\t\t})\n\t\t);\n\t}\n\n\t/** Whether any frames or sleep timers are currently pending. */\n\tpublic get pending(): boolean {\n\t\treturn this.frames.length > 0 || this.sleepers.length > 0;\n\t}\n\n\t/** Advances time by `ms`, resolving due sleep timers in order, followed by queued frames. */\n\tpublic async advance(ms: number): Promise<void> {\n\t\tconst end = this.time + Math.max(0, ms);\n\t\tawait settle();\n\n\t\twhile (true) {\n\t\t\tlet next: (typeof this.sleepers)[number] | undefined;\n\t\t\tfor (const s of this.sleepers) {\n\t\t\t\tif (s.at <= end && (!next || s.at < next.at || (s.at === next.at && s.seq < next.seq))) {\n\t\t\t\t\tnext = s;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!next) break;\n\n\t\t\tthis.sleepers.splice(this.sleepers.indexOf(next), 1);\n\t\t\tthis.time = Math.max(this.time, next.at);\n\t\t\tnext.resolve();\n\t\t\tawait settle();\n\t\t}\n\n\t\tthis.time = end;\n\t\tconst dueFrames = this.frames.splice(0, this.frames.length);\n\t\tfor (const resolveFrame of dueFrames) {\n\t\t\tresolveFrame();\n\t\t}\n\t\tawait settle();\n\t}\n\n\t/** Convenience method to advance by 1 frame at a given fps (default: 60fps = 16.67ms). */\n\tpublic async tick(fps = 60): Promise<void> {\n\t\tawait this.advance(Math.round(1000 / fps));\n\t}\n}\n","import type {\n\tCanvasNode,\n\tCanvasNodeStyle,\n\tFanOutTrajectoryOptions,\n\tNodeTransition,\n\tTrajectoryFunction,\n\tTrajectoryPoint,\n\tXYPosition\n} from './types.js';\n\n/**\n * Standard cubic ease-out function (pure math, framework-agnostic).\n */\nexport const defaultEasing = (t: number): number => --t * t * t + 1;\n\n/**\n * Standard linear trajectory: straight line interpolation with linear scale & opacity progression.\n */\nexport const linearTrajectory: TrajectoryFunction = (\n\torigin: XYPosition,\n\ttarget: XYPosition,\n\tprogress: number\n): TrajectoryPoint => {\n\treturn {\n\t\tposition: {\n\t\t\tx: origin.x + (target.x - origin.x) * progress,\n\t\t\ty: origin.y + (target.y - origin.y) * progress\n\t\t},\n\t\tscale: progress,\n\t\topacity: Math.min(1, progress * 1.5)\n\t};\n};\n\n/**\n * Linear position trajectory: pure position interpolation without altering scale or opacity.\n */\nexport const linearPositionTrajectory: TrajectoryFunction = (\n\torigin: XYPosition,\n\ttarget: XYPosition,\n\tprogress: number\n): TrajectoryPoint => {\n\treturn {\n\t\tposition: {\n\t\t\tx: origin.x + (target.x - origin.x) * progress,\n\t\t\ty: origin.y + (target.y - origin.y) * progress\n\t\t}\n\t};\n};\n\n/**\n * Creates a fan-out trajectory where nodes arc outward from origin to target.\n */\nexport function createFanOutTrajectory(options: FanOutTrajectoryOptions = {}): TrajectoryFunction {\n\tconst {\n\t\tcurvature = 0.4,\n\t\tstartScale = 0,\n\t\tendScale = 1,\n\t\tstartOpacity = 0,\n\t\tendOpacity = 1\n\t} = options;\n\n\treturn (\n\t\torigin: XYPosition,\n\t\ttarget: XYPosition,\n\t\tprogress: number,\n\t\tindex: number,\n\t\ttotal: number\n\t): TrajectoryPoint => {\n\t\tconst dx = target.x - origin.x;\n\t\tconst dy = target.y - origin.y;\n\n\t\t// Normalized index from -1 (top) to +1 (bottom)\n\t\tconst normIndex = total > 1 ? (index - (total - 1) / 2) / ((total - 1) / 2) : 0;\n\n\t\t// Perpendicular control point offset to create smooth fan arc\n\t\tconst midX = origin.x + dx * 0.4;\n\t\tconst midY = origin.y + dy * 0.1 - normIndex * Math.abs(dx) * 0.15 * curvature;\n\n\t\t// Quadratic Bezier interpolation: B(t) = (1-t)^2 * P0 + 2(1-t)t * P1 + t^2 * P2\n\t\tconst t = progress;\n\t\tconst oneMinusT = 1 - t;\n\n\t\tconst x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * midX + t * t * target.x;\n\t\tconst y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * midY + t * t * target.y;\n\n\t\tconst scale = startScale + (endScale - startScale) * progress;\n\t\tconst opacity = startOpacity + (endOpacity - startOpacity) * progress;\n\n\t\treturn {\n\t\t\tposition: { x, y },\n\t\t\tscale,\n\t\t\topacity\n\t\t};\n\t};\n}\n\n/**\n * Creates a custom quadratic Bezier trajectory with a specified control point resolver.\n */\nexport function createBezierTrajectory(\n\tgetControlPoint: (origin: XYPosition, target: XYPosition) => XYPosition\n): TrajectoryFunction {\n\treturn (origin: XYPosition, target: XYPosition, progress: number): TrajectoryPoint => {\n\t\tconst cp = getControlPoint(origin, target);\n\t\tconst t = progress;\n\t\tconst oneMinusT = 1 - t;\n\n\t\tconst x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * cp.x + t * t * target.x;\n\t\tconst y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * cp.y + t * t * target.y;\n\n\t\treturn {\n\t\t\tposition: { x, y },\n\t\t\tscale: progress,\n\t\t\topacity: progress\n\t\t};\n\t};\n}\n\nimport { realClock, type Clock } from './clock.js';\n\n/**\n * Returns a copy of `style` with its opacity set to `opacity`.\n *\n * Supports both CSS strings (`\"color: red; opacity: 0.5;\"`, used by SvelteFlow)\n * and style objects (`{ color: 'red', opacity: 0.5 }`, used by React Flow / xyflow).\n * When `style` is empty, `emptyFormat` decides which representation is produced.\n * Never mutates the input.\n */\nexport function withStyleOpacity(\n\tstyle: CanvasNodeStyle | undefined | null,\n\topacity: number,\n\temptyFormat: 'string' | 'object' = 'string'\n): CanvasNodeStyle {\n\tif (style !== null && typeof style === 'object') {\n\t\treturn { ...style, opacity };\n\t}\n\tif (typeof style === 'string' && style.trim() !== '') {\n\t\tconst rest = style\n\t\t\t.replace(/(^|;)\\s*opacity\\s*:\\s*[^;]*;?/gi, '$1')\n\t\t\t.trim()\n\t\t\t.replace(/;+\\s*$/, '')\n\t\t\t.trim();\n\t\treturn `${rest ? rest + '; ' : ''}opacity: ${opacity};`;\n\t}\n\treturn emptyFormat === 'object' ? { opacity } : `opacity: ${opacity};`;\n}\n\nexport interface MultiNodeTransitionOptions<TNode extends CanvasNode = CanvasNode> {\n\tdefaultDuration?: number;\n\tdefaultEasing?: (t: number) => number;\n\tclock?: Clock;\n\t/**\n\t * Style representation to create for nodes that have no `style` yet when an opacity\n\t * is applied. Defaults to `'string'` (SvelteFlow); pass `'object'` for React Flow.\n\t * Existing styles always keep their representation.\n\t */\n\tstyleFormat?: 'string' | 'object';\n\t/**\n\t * Called on every frame with updated copies of the transitioning nodes, in the same\n\t * order as the `transitions` array. Input nodes are never mutated.\n\t */\n\tonUpdate?: (nodes: TNode[]) => void;\n\t/** Called once all transitions finished, with the final node copies. */\n\tonComplete?: (nodes: TNode[]) => void;\n}\n\n/**\n * Coordinates and animates multiple node transitions simultaneously.\n *\n * The input nodes are treated as immutable: every frame produces updated copies\n * (position, `data.scale` / `data.opacity`, and `style` opacity) which are handed to\n * `onUpdate` and finally `onComplete`. Merge them into your node state by `id`.\n */\nexport function runMultiNodeTransition<TNode extends CanvasNode = CanvasNode>(\n\ttransitions: NodeTransition<TNode>[],\n\toptions: MultiNodeTransitionOptions<TNode> = {}\n): () => void {\n\tif (transitions.length === 0) {\n\t\toptions.onComplete?.([]);\n\t\treturn () => {};\n\t}\n\n\tconst {\n\t\tdefaultDuration = 400,\n\t\tdefaultEasing: easingFunc = defaultEasing,\n\t\tclock = realClock,\n\t\tstyleFormat = 'string',\n\t\tonUpdate,\n\t\tonComplete\n\t} = options;\n\n\tlet isCancelled = false;\n\tconst startTime = clock.now();\n\n\tconst items = transitions.map((tr, i) => ({\n\t\t...tr,\n\t\tindex: tr.index ?? i,\n\t\ttotal: tr.total ?? transitions.length,\n\t\tduration: tr.duration ?? defaultDuration,\n\t\teasing: tr.easing ?? easingFunc,\n\t\tdelay: tr.delay ?? 0,\n\t\ttrajectory: tr.trajectory ?? linearTrajectory\n\t}));\n\n\t// Latest copy of every node; starts out as the untouched inputs.\n\tconst current: TNode[] = items.map((item) => item.node);\n\n\tfunction frame() {\n\t\tif (isCancelled) return;\n\n\t\tconst now = clock.now();\n\t\tlet allCompleted = true;\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst item = items[i];\n\t\t\tconst elapsed = now - (startTime + item.delay);\n\n\t\t\tif (elapsed < 0) {\n\t\t\t\tallCompleted = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Guard zero duration and division by zero (referenced in GOTCHAS.md)\n\t\t\tconst rawProgress = item.duration <= 0 ? 1 : Math.min(elapsed / item.duration, 1);\n\t\t\tconst progress = item.duration <= 0 ? 1 : item.easing(rawProgress);\n\n\t\t\tconst point = item.trajectory(item.from, item.to, progress, item.index, item.total);\n\n\t\t\tconst next: TNode = { ...item.node, position: { ...point.position } };\n\n\t\t\tif (point.scale !== undefined || point.opacity !== undefined) {\n\t\t\t\tconst data: Record<string, any> = { ...(item.node.data ?? {}) };\n\t\t\t\tif (point.scale !== undefined) {\n\t\t\t\t\tdata.scale = point.scale;\n\t\t\t\t}\n\t\t\t\tif (point.opacity !== undefined) {\n\t\t\t\t\tdata.opacity = point.opacity;\n\t\t\t\t\t(next as CanvasNode).style = withStyleOpacity(item.node.style, point.opacity, styleFormat);\n\t\t\t\t}\n\t\t\t\t(next as CanvasNode).data = data;\n\t\t\t}\n\n\t\t\tcurrent[i] = next;\n\n\t\t\tif (rawProgress < 1) {\n\t\t\t\tallCompleted = false;\n\t\t\t}\n\t\t}\n\n\t\tonUpdate?.(current.slice());\n\n\t\tif (!allCompleted) {\n\t\t\tclock.frame().then(frame);\n\t\t} else {\n\t\t\tonComplete?.(current.slice());\n\t\t}\n\t}\n\n\tframe();\n\n\treturn () => {\n\t\tisCancelled = true;\n\t};\n}\n","import dagre from '@dagrejs/dagre';\nimport type {\n\tCanvasEdge,\n\tCanvasNode,\n\tDirectionalDisplacementOptions,\n\tRect,\n\tReflowDisplacementOptions,\n\tXYPosition\n} from './types.js';\n\n/**\n * Calculates a bounding rectangle for a set of nodes if not provided by getNodesBounds.\n */\nexport function computeNodesBoundingBox<TNode extends CanvasNode = CanvasNode>(\n\tnodes: TNode[],\n\tdefaultWidth = 200,\n\tdefaultHeight = 60\n): Rect {\n\tif (nodes.length === 0) {\n\t\treturn { x: 0, y: 0, width: 0, height: 0 };\n\t}\n\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\n\tfor (const node of nodes) {\n\t\tconst width = node.measured?.width ?? (node as any).width ?? defaultWidth;\n\t\tconst height = node.measured?.height ?? (node as any).height ?? defaultHeight;\n\n\t\tminX = Math.min(minX, node.position.x);\n\t\tminY = Math.min(minY, node.position.y);\n\t\tmaxX = Math.max(maxX, node.position.x + width);\n\t\tmaxY = Math.max(maxY, node.position.y + height);\n\t}\n\n\treturn {\n\t\tx: minX,\n\t\ty: minY,\n\t\twidth: maxX - minX,\n\t\theight: maxY - minY\n\t};\n}\n\n/**\n * Pure directional displacement calculation.\n * Shifts downstream or surrounding nodes along an axis to clear space for newly inserted child nodes.\n */\nexport function calculateDirectionalDisplacement<TNode extends CanvasNode = CanvasNode>(params: {\n\texistingNodes: TNode[];\n\toriginNode: TNode;\n\tchildNodes: TNode[];\n\tgetNodesBounds?: (nodes: TNode[]) => Rect;\n\toptions?: DirectionalDisplacementOptions;\n}): Map<string, XYPosition> {\n\tconst {\n\t\texistingNodes,\n\t\toriginNode,\n\t\tchildNodes,\n\t\tgetNodesBounds,\n\t\toptions = {}\n\t} = params;\n\n\tconst {\n\t\tdirection = 'right',\n\t\tgap = 40,\n\t\tspreadSiblingLanes = false,\n\t\tsiblingTolerance = 50,\n\t\tminY\n\t} = options;\n\n\tconst displacedMap = new Map<string, XYPosition>();\n\tif (childNodes.length === 0 || existingNodes.length === 0) {\n\t\treturn displacedMap;\n\t}\n\n\tconst childBounds = getNodesBounds\n\t\t? getNodesBounds(childNodes)\n\t\t: computeNodesBoundingBox(childNodes);\n\n\tconst originWidth = originNode.measured?.width ?? (originNode as any).width ?? 200;\n\tconst originHeight = originNode.measured?.height ?? (originNode as any).height ?? 60;\n\n\t// The delta space required along primary axis\n\tconst deltaPrimary =\n\t\tdirection === 'right' || direction === 'left'\n\t\t\t? childBounds.width + gap\n\t\t\t: childBounds.height + gap;\n\n\t// Vertical displacement parameters: upward and downward row clearance\n\tconst deltaUp = Math.max(0, originNode.position.y - childBounds.y + gap);\n\tconst deltaDown = Math.max(\n\t\t0,\n\t\tchildBounds.y + childBounds.height - (originNode.position.y + originHeight) + gap\n\t);\n\n\t// Both above and below displace equally so the row expands symmetrically\n\tconst equalDelta = Math.max(deltaUp, deltaDown);\n\n\tfor (const node of existingNodes) {\n\t\tif (node.id === originNode.id) continue;\n\n\t\tconst isSiblingRow =\n\t\t\tMath.abs(node.position.y - originNode.position.y) < siblingTolerance;\n\n\t\tswitch (direction) {\n\t\t\tcase 'right': {\n\t\t\t\tif (node.position.x > originNode.position.x) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x + deltaPrimary,\n\t\t\t\t\t\ty: node.position.y\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\tif (node.position.x < originNode.position.x) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x - deltaPrimary,\n\t\t\t\t\t\ty: node.position.y\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'down': {\n\t\t\t\tif (node.position.y > originNode.position.y) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x,\n\t\t\t\t\t\ty: node.position.y + deltaPrimary\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'up': {\n\t\t\t\tif (node.position.y < originNode.position.y) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x,\n\t\t\t\t\t\ty: node.position.y - deltaPrimary\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'vertical': {\n\t\t\t\tif (isSiblingRow) break;\n\n\t\t\t\tif (node.position.y < originNode.position.y) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x,\n\t\t\t\t\t\ty: node.position.y - equalDelta\n\t\t\t\t\t});\n\t\t\t\t} else if (node.position.y > originNode.position.y) {\n\t\t\t\t\tdisplacedMap.set(node.id, {\n\t\t\t\t\t\tx: node.position.x,\n\t\t\t\t\t\ty: node.position.y + equalDelta\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Sibling lane spreading to avoid overlap among child nodes\n\tif (spreadSiblingLanes && (direction === 'right' || direction === 'left')) {\n\t\tfor (const [nodeId, pos] of displacedMap.entries()) {\n\t\t\tconst node = existingNodes.find((n) => n.id === nodeId);\n\t\t\tif (node && Math.abs(node.position.y - originNode.position.y) < siblingTolerance) {\n\t\t\t\tconst isAbove = node.position.y < originNode.position.y;\n\t\t\t\tdisplacedMap.set(nodeId, {\n\t\t\t\t\tx: pos.x,\n\t\t\t\t\ty: pos.y + (isAbove ? -deltaUp : deltaDown)\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Floor constraint\n\tif (minY !== undefined) {\n\t\tfor (const [nodeId, pos] of displacedMap.entries()) {\n\t\t\tif (pos.y < minY) {\n\t\t\t\tdisplacedMap.set(nodeId, { x: pos.x, y: minY });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn displacedMap;\n}\n\n/**\n * Calculates Dagre reflow displacement preserving the position of an anchor node.\n */\nexport function calculateDagreReflowDisplacement<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(params: {\n\tcurrentNodes: TNode[];\n\tcurrentEdges: TEdge[];\n\tfutureNodes: TNode[];\n\tfutureEdges: TEdge[];\n\toptions: ReflowDisplacementOptions;\n\tgetNodesBounds?: (nodes: TNode[]) => Rect;\n}): Map<string, XYPosition> {\n\tconst {\n\t\tcurrentNodes,\n\t\tfutureNodes,\n\t\tfutureEdges,\n\t\toptions\n\t} = params;\n\n\tconst {\n\t\tanchorNodeId,\n\t\tdirection = 'LR',\n\t\tranksep = 100,\n\t\tnodesep = 25,\n\t\tdefaultNodeWidth = 200,\n\t\tdefaultNodeHeight = 60\n\t} = options;\n\n\tconst anchorNode = currentNodes.find((n) => n.id === anchorNodeId);\n\tif (!anchorNode) return new Map();\n\n\tconst g = new dagre.graphlib.Graph();\n\tg.setDefaultEdgeLabel(() => ({}));\n\tg.setGraph({ rankdir: direction, ranksep, nodesep });\n\n\tconst nodeIds = new Set(futureNodes.map((n) => n.id));\n\n\tfutureNodes.forEach((node) => {\n\t\tconst nodeWidth = node.measured?.width ?? (node as any).width ?? defaultNodeWidth;\n\t\tconst nodeHeight = node.measured?.height ?? (node as any).height ?? defaultNodeHeight;\n\t\tg.setNode(node.id, { width: nodeWidth, height: nodeHeight });\n\t});\n\n\tfutureEdges.forEach((edge) => {\n\t\tif (nodeIds.has(edge.source) && nodeIds.has(edge.target)) {\n\t\t\tg.setEdge(edge.source, edge.target);\n\t\t}\n\t});\n\n\tdagre.layout(g);\n\n\tconst anchorLayoutPos = g.node(anchorNodeId);\n\tif (!anchorLayoutPos) return new Map();\n\n\tconst anchorWidth = anchorNode.measured?.width ?? (anchorNode as any).width ?? defaultNodeWidth;\n\tconst anchorHeight = anchorNode.measured?.height ?? (anchorNode as any).height ?? defaultNodeHeight;\n\n\tconst anchorLayoutUpperLeft = {\n\t\tx: anchorLayoutPos.x - anchorWidth / 2,\n\t\ty: anchorLayoutPos.y - anchorHeight / 2\n\t};\n\n\tconst deltaX = anchorNode.position.x - anchorLayoutUpperLeft.x;\n\tconst deltaY = anchorNode.position.y - anchorLayoutUpperLeft.y;\n\n\tconst displacementMap = new Map<string, XYPosition>();\n\n\tcurrentNodes.forEach((node) => {\n\t\tif (node.id === anchorNodeId) return;\n\n\t\tconst layoutNode = g.node(node.id);\n\t\tif (!layoutNode) return;\n\n\t\tconst nodeWidth = node.measured?.width ?? (node as any).width ?? defaultNodeWidth;\n\t\tconst nodeHeight = node.measured?.height ?? (node as any).height ?? defaultNodeHeight;\n\n\t\tconst upperLeftX = layoutNode.x - nodeWidth / 2 + deltaX;\n\t\tconst upperLeftY = layoutNode.y - nodeHeight / 2 + deltaY;\n\n\t\tif (\n\t\t\tMath.abs(upperLeftX - node.position.x) > 1 ||\n\t\t\tMath.abs(upperLeftY - node.position.y) > 1\n\t\t) {\n\t\t\tdisplacementMap.set(node.id, { x: upperLeftX, y: upperLeftY });\n\t\t}\n\t});\n\n\treturn displacementMap;\n}\n","import type {\n\tCanvasClipboardPayload,\n\tCanvasEdge,\n\tCanvasNode,\n\tXYPosition\n} from './types.js';\n\n/**\n * Checks if an event originated from a text input, textarea, contenteditable element, or rich editor.\n */\nexport function isEventFromTextInput(event: Event | { target: EventTarget | null }): boolean {\n\tconst target = (event as any).target as HTMLElement | null;\n\tif (!target) return false;\n\tif (\n\t\ttarget.tagName === 'INPUT' ||\n\t\ttarget.tagName === 'TEXTAREA' ||\n\t\ttarget.tagName === 'SELECT' ||\n\t\ttarget.isContentEditable ||\n\t\ttarget.closest?.('[contenteditable=\"true\"]') ||\n\t\ttarget.closest?.('.ProseMirror')\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Validates that an object conforms to minimal CanvasNode shape:\n * a string `id` and a `position` whose `x` / `y` are finite numbers.\n */\nexport function isValidCanvasNode(obj: unknown): obj is CanvasNode {\n\tif (typeof obj !== 'object' || obj === null) return false;\n\tconst candidate = obj as { id?: unknown; position?: unknown };\n\tif (typeof candidate.id !== 'string') return false;\n\tconst position = candidate.position as { x?: unknown; y?: unknown } | null | undefined;\n\treturn (\n\t\ttypeof position === 'object' &&\n\t\tposition !== null &&\n\t\ttypeof position.x === 'number' &&\n\t\tNumber.isFinite(position.x) &&\n\t\ttypeof position.y === 'number' &&\n\t\tNumber.isFinite(position.y)\n\t);\n}\n\n/**\n * Validates that an object conforms to minimal CanvasEdge shape (string `id`, `source`, `target`).\n */\nexport function isValidCanvasEdge(obj: unknown): obj is CanvasEdge {\n\tif (typeof obj !== 'object' || obj === null) return false;\n\tconst candidate = obj as { id?: unknown; source?: unknown; target?: unknown };\n\treturn (\n\t\ttypeof candidate.id === 'string' &&\n\t\ttypeof candidate.source === 'string' &&\n\t\ttypeof candidate.target === 'string'\n\t);\n}\n\n/**\n * Checks if a string is a valid HTTP/HTTPS URL.\n */\nexport function isValidUrl(url: string): boolean {\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\treturn parsed.protocol === 'http:' || parsed.protocol === 'https:';\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Serializes nodes and optional edges into clipboard JSON payload.\n */\nexport function serializeCanvasNodes<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(nodes: TNode[], edges?: TEdge[]): string {\n\tconst payload: CanvasClipboardPayload<TNode, TEdge> = {\n\t\tversion: 1,\n\t\tnodes,\n\t\tedges\n\t};\n\treturn JSON.stringify(payload);\n}\n\n/**\n * Parses raw JSON string into a CanvasClipboardPayload if valid.\n */\nexport function parseCanvasClipboardData<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(raw: string): CanvasClipboardPayload<TNode, TEdge> | null {\n\ttry {\n\t\tconst parsed = JSON.parse(raw);\n\t\tif (\n\t\t\ttypeof parsed === 'object' &&\n\t\t\tparsed !== null &&\n\t\t\tArray.isArray(parsed.nodes) &&\n\t\t\tparsed.nodes.length > 0 &&\n\t\t\tparsed.nodes.every(isValidCanvasNode)\n\t\t) {\n\t\t\t// Untrusted input: drop malformed edges instead of crashing downstream consumers.\n\t\t\tconst edges = Array.isArray(parsed.edges)\n\t\t\t\t? (parsed.edges as unknown[]).filter(isValidCanvasEdge)\n\t\t\t\t: undefined;\n\t\t\treturn { ...parsed, edges } as CanvasClipboardPayload<TNode, TEdge>;\n\t\t}\n\t} catch {\n\t\t// Not JSON or invalid payload\n\t}\n\treturn null;\n}\n\n/**\n * Generates unique new IDs for pasted nodes and updates edge references accordingly.\n *\n * - Nodes without a valid id / finite numeric position are skipped.\n * - `parentId` (and legacy `parentNode`) references to other pasted nodes are remapped to\n * the new IDs; such children keep their parent-relative position (no extra offset).\n * References to parents outside the pasted set are left unchanged.\n * - Edges are kept only when both endpoints were pasted; a non-array `edges` is ignored.\n */\nexport function remapPastedNodes<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(\n\tnodes: TNode[],\n\tedges: TEdge[] | null | undefined = [],\n\toffset: XYPosition = { x: 30, y: 30 },\n\tidGenerator: () => string = () => `node-${Math.random().toString(36).substring(2, 9)}`\n): { nodes: TNode[]; edges: TEdge[] } {\n\tconst validNodes = (Array.isArray(nodes) ? nodes : []).filter(isValidCanvasNode) as TNode[];\n\tconst validEdges = (Array.isArray(edges) ? edges : []).filter(isValidCanvasEdge) as TEdge[];\n\n\tconst dx = Number.isFinite(offset?.x) ? offset.x : 0;\n\tconst dy = Number.isFinite(offset?.y) ? offset.y : 0;\n\n\tconst idMap = new Map<string, string>();\n\tfor (const node of validNodes) {\n\t\tidMap.set(node.id, idGenerator());\n\t}\n\n\tconst newNodes = validNodes.map((node) => {\n\t\tconst next: CanvasNode = {\n\t\t\t...node,\n\t\t\tid: idMap.get(node.id)!,\n\t\t\tposition: {\n\t\t\t\tx: node.position.x + dx,\n\t\t\t\ty: node.position.y + dy\n\t\t\t},\n\t\t\tselected: true\n\t\t};\n\n\t\tlet parentRemapped = false;\n\t\tfor (const key of ['parentId', 'parentNode'] as const) {\n\t\t\tconst parent = (node as CanvasNode)[key];\n\t\t\tif (typeof parent === 'string' && idMap.has(parent)) {\n\t\t\t\tnext[key] = idMap.get(parent)!;\n\t\t\t\tparentRemapped = true;\n\t\t\t}\n\t\t}\n\t\tif (parentRemapped) {\n\t\t\t// Position is relative to the (also pasted, also offset) parent.\n\t\t\tnext.position = { x: node.position.x, y: node.position.y };\n\t\t}\n\n\t\treturn next as TNode;\n\t});\n\n\tconst newEdges = validEdges\n\t\t.filter((e) => idMap.has(e.source) && idMap.has(e.target))\n\t\t.map((edge) => ({\n\t\t\t...edge,\n\t\t\tid: `edge-${Math.random().toString(36).substring(2, 9)}`,\n\t\t\tsource: idMap.get(edge.source)!,\n\t\t\ttarget: idMap.get(edge.target)!,\n\t\t\tselected: false\n\t\t}));\n\n\treturn { nodes: newNodes, edges: newEdges };\n}\n\n/**\n * Repositions nodes so their bounding box origin matches the given target position.\n */\nexport function repositionNodesTo<TNode extends CanvasNode = CanvasNode>(\n\tnodes: TNode[],\n\ttargetOrigin: XYPosition\n): TNode[] {\n\tif (nodes.length === 0) return [];\n\tconst minX = Math.min(...nodes.map((n) => n.position.x));\n\tconst minY = Math.min(...nodes.map((n) => n.position.y));\n\tconst deltaX = targetOrigin.x - minX;\n\tconst deltaY = targetOrigin.y - minY;\n\n\treturn nodes.map((n) => ({\n\t\t...n,\n\t\tposition: {\n\t\t\tx: n.position.x + deltaX,\n\t\t\ty: n.position.y + deltaY\n\t\t}\n\t}));\n}\n","import type { CanvasEdge, CanvasNode, Rect } from './types.js';\n\nexport interface CanvasHeightOptions {\n\t/** Smallest height returned (default 320). */\n\tmin?: number;\n\t/** Largest height returned; taller content is scaled/zoomed (default 560). */\n\tmax?: number;\n\t/** Extra padding around the content (default 48). */\n\tpadding?: number;\n}\n\nfunction clampHeight(contentHeight: number, options: CanvasHeightOptions = {}): number {\n\tconst { min = 320, max = 560, padding = 48 } = options;\n\treturn Math.round(Math.min(max, Math.max(min, contentHeight + padding)));\n}\n\n/**\n * Calculates the bounding box extent of all positioned nodes, or `null` for an empty graph.\n */\nexport function layoutBounds<TNode extends CanvasNode = CanvasNode>(\n\tnodes: TNode[]\n): Rect | null {\n\tif (nodes.length === 0) return null;\n\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\n\tfor (const node of nodes) {\n\t\tconst x = node.position.x;\n\t\tconst y = node.position.y;\n\t\tconst width = node.width ?? 180;\n\t\tconst height = node.height ?? 80;\n\n\t\tminX = Math.min(minX, x);\n\t\tminY = Math.min(minY, y);\n\t\tmaxX = Math.max(maxX, x + width);\n\t\tmaxY = Math.max(maxY, y + height);\n\t}\n\n\tif (minX === Infinity) return null;\n\treturn { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/**\n * Returns a clamped container height that fits the layout at 1:1 scale without overflow.\n */\nexport function canvasHeight<TNode extends CanvasNode = CanvasNode>(\n\tnodes: TNode[],\n\toptions?: CanvasHeightOptions\n): number {\n\treturn clampHeight(layoutBounds(nodes)?.height ?? 0, options);\n}\n\nconst DEFAULT_RANK_HEIGHT = 80 + 72; // Average node height + default rank separation\nconst NODES_PER_RANK = 2;\n\n/**\n * Estimates the container height to reserve before layout calculation finishes,\n * based on node and edge counts alone. Prevents layout shift (CLS).\n */\nexport function estimateCanvasHeight<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(\n\tnodes: TNode[],\n\tedges: TEdge[],\n\toptions?: CanvasHeightOptions\n): number {\n\tconst ranks = Math.max(1, Math.ceil(nodes.length / NODES_PER_RANK));\n\treturn clampHeight(ranks * DEFAULT_RANK_HEIGHT, options);\n}\n\nfunction mix(a: number, b: number, t: number): number {\n\treturn a + (b - a) * t;\n}\n\n/**\n * Interpolates node positions and sizes between two layouts partway at progress `t` (0 = from, 1 = to).\n * Nodes present in both interpolate smoothly; nodes newly added in `to` snap to target.\n */\nexport function blendLayout<TNode extends CanvasNode = CanvasNode>(\n\tfrom: TNode[],\n\tto: TNode[],\n\tt: number\n): TNode[] {\n\tif (t >= 1) return to;\n\n\tconst fromMap = new Map<string, TNode>(from.map((n) => [n.id, n]));\n\n\treturn to.map((target) => {\n\t\tconst origin = fromMap.get(target.id);\n\t\tif (!origin) return target;\n\n\t\treturn {\n\t\t\t...target,\n\t\t\tposition: {\n\t\t\t\tx: mix(origin.position.x, target.position.x, t),\n\t\t\t\ty: mix(origin.position.y, target.position.y, t)\n\t\t\t},\n\t\t\twidth:\n\t\t\t\torigin.width !== undefined && target.width !== undefined\n\t\t\t\t\t? mix(origin.width, target.width, t)\n\t\t\t\t\t: target.width,\n\t\t\theight:\n\t\t\t\torigin.height !== undefined && target.height !== undefined\n\t\t\t\t\t? mix(origin.height, target.height, t)\n\t\t\t\t\t: target.height\n\t\t};\n\t});\n}\n\n/**\n * Filters out nodes that are not touched by any edge.\n *\n * During LLM streaming, nodes often arrive a chunk or token before the edge\n * that connects them. Displaying them immediately causes them to be placed as root\n * nodes only to jump into their correct position once the edge arrives.\n * Hiding orphan nodes during active streaming keeps the layout calm and jitter-free.\n */\nexport function connectedOnly<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n>(\n\tnodes: TNode[],\n\tedges: TEdge[]\n): TNode[] {\n\tif (edges.length === 0) return nodes;\n\n\tconst linkedNodeIds = new Set<string>();\n\tfor (const edge of edges) {\n\t\tlinkedNodeIds.add(edge.source);\n\t\tlinkedNodeIds.add(edge.target);\n\t}\n\n\tconst filtered = nodes.filter((node) => linkedNodeIds.has(node.id));\n\t// If filtering would remove everything, return the original nodes\n\treturn filtered.length > 0 ? filtered : nodes;\n}\n","import { realClock, type Clock } from './clock.js';\nimport { ensureLayout } from './layout.js';\nimport { linearPositionTrajectory, runMultiNodeTransition } from './trajectory.js';\nimport type { CanvasEdge, CanvasNode, IncrementalLayoutOptions, NodeTransition, XYPosition } from './types.js';\nimport { connectedOnly } from './view.js';\n\nexport interface StreamingLayoutManagerOptions {\n\tthrottleMs?: number;\n\tglideDurationMs?: number;\n\tconnectedOnly?: boolean;\n\tclock?: Clock;\n\tlayoutOptions?: IncrementalLayoutOptions;\n\tonLayoutUpdated?: (positions: Map<string, XYPosition>) => void;\n}\n\n/**\n * Manages throttled incremental layout recalculation and smooth tweened node gliding\n * during active streaming (e.g. LLM streaming or graph generation).\n *\n * - `pushStreamUpdate` is a true throttle (leading + trailing edge): the first update\n * lays out immediately, further updates within `throttleMs` are coalesced and the\n * latest one is laid out when the window closes. Layouts therefore keep running at\n * most once per `throttleMs` while a stream is active, instead of being postponed\n * until the stream goes quiet.\n * - Every layout is computed from the graph (respecting `layoutOptions.storedPositions`\n * as pinned/manual coordinates) and each known node glides from its *current*\n * position (the `currentPositions` argument) to its newly computed position.\n */\nexport class StreamingLayoutManager<\n\tTNode extends CanvasNode = CanvasNode,\n\tTEdge extends CanvasEdge = CanvasEdge\n> {\n\tprivate throttleMs: number;\n\tprivate glideDurationMs: number;\n\tprivate connectedOnly: boolean;\n\tprivate clock: Clock;\n\tprivate layoutOptions: IncrementalLayoutOptions;\n\tprivate onLayoutUpdated?: (positions: Map<string, XYPosition>) => void;\n\n\tprivate pendingTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate pendingArgs: [TNode[], TEdge[], Map<string, XYPosition>] | null = null;\n\tprivate activeTransitionCancel: (() => void) | null = null;\n\tprivate targetPositions = new Map<string, XYPosition>();\n\tprivate livePositions = new Map<string, XYPosition>();\n\n\tconstructor(options: StreamingLayoutManagerOptions = {}) {\n\t\tthis.throttleMs = options.throttleMs ?? 200;\n\t\tthis.glideDurationMs = options.glideDurationMs ?? 300;\n\t\tthis.connectedOnly = options.connectedOnly ?? false;\n\t\tthis.clock = options.clock ?? realClock;\n\t\tthis.layoutOptions = options.layoutOptions ?? { direction: 'LR' };\n\t\tthis.onLayoutUpdated = options.onLayoutUpdated;\n\t}\n\n\t/**\n\t * Feed incoming nodes and edges into the streaming manager.\n\t * Throttles rapid streaming bursts (leading + trailing edge) and triggers smooth layout gliding.\n\t */\n\tpublic pushStreamUpdate(\n\t\tnodes: TNode[],\n\t\tedges: TEdge[],\n\t\tcurrentPositions: Map<string, XYPosition>\n\t): void {\n\t\tif (this.pendingTimer !== null) {\n\t\t\t// Inside the throttle window: remember the latest update for the trailing edge.\n\t\t\tthis.pendingArgs = [nodes, edges, currentPositions];\n\t\t\treturn;\n\t\t}\n\n\t\t// Leading edge: lay out immediately and open a throttle window.\n\t\tthis.recalculateAndGlide(nodes, edges, currentPositions);\n\t\tthis.startWindow();\n\t}\n\n\tprivate startWindow(): void {\n\t\tthis.pendingTimer = setTimeout(() => {\n\t\t\tthis.pendingTimer = null;\n\t\t\tconst args = this.pendingArgs;\n\t\t\tthis.pendingArgs = null;\n\t\t\tif (args) {\n\t\t\t\t// Trailing edge: lay out the latest coalesced update and keep throttling.\n\t\t\t\tthis.recalculateAndGlide(...args);\n\t\t\t\tthis.startWindow();\n\t\t\t}\n\t\t}, Math.max(0, this.throttleMs));\n\t}\n\n\t/**\n\t * Forces immediate calculation and cancels pending throttled timers.\n\t */\n\tpublic flush(\n\t\tnodes: TNode[],\n\t\tedges: TEdge[],\n\t\tcurrentPositions: Map<string, XYPosition>\n\t): void {\n\t\tthis.clearPending();\n\t\tthis.recalculateAndGlide(nodes, edges, currentPositions);\n\t}\n\n\t/**\n\t * Latest computed layout targets (the positions nodes are gliding towards).\n\t */\n\tpublic getTargetPositions(): Map<string, XYPosition> {\n\t\treturn new Map(this.targetPositions);\n\t}\n\n\tprivate clearPending(): void {\n\t\tif (this.pendingTimer !== null) {\n\t\t\tclearTimeout(this.pendingTimer);\n\t\t\tthis.pendingTimer = null;\n\t\t}\n\t\tthis.pendingArgs = null;\n\t}\n\n\tprivate recalculateAndGlide(\n\t\tnodes: TNode[],\n\t\tedges: TEdge[],\n\t\tcurrentPositions: Map<string, XYPosition>\n\t): void {\n\t\tconst targetNodes = this.connectedOnly ? connectedOnly(nodes, edges) : nodes;\n\t\tif (targetNodes.length === 0) return;\n\n\t\t// Where nodes are right now: the caller's view, overridden by any glide still in\n\t\t// flight (the caller may not have applied the latest animated frame yet).\n\t\tconst startPositions = new Map<string, XYPosition>(currentPositions);\n\t\tif (this.activeTransitionCancel) {\n\t\t\tfor (const [id, pos] of this.livePositions) {\n\t\t\t\tstartPositions.set(id, pos);\n\t\t\t}\n\t\t\tthis.activeTransitionCancel();\n\t\t\tthis.activeTransitionCancel = null;\n\t\t}\n\n\t\t// Compute fresh layout targets. Only explicitly stored (pinned/manual) positions\n\t\t// are preserved; current positions are the glide *origin*, not the destination.\n\t\tconst layouted = ensureLayout(targetNodes, edges, this.layoutOptions);\n\n\t\tconst nextPositions = new Map<string, XYPosition>();\n\t\tconst transitions: NodeTransition<TNode>[] = [];\n\n\t\tfor (const node of layouted) {\n\t\t\tconst target = { ...node.position };\n\t\t\tnextPositions.set(node.id, target);\n\n\t\t\tconst current = startPositions.get(node.id);\n\t\t\tif (!current) continue; // brand-new node: appears directly at its target\n\n\t\t\tconst distance = Math.hypot(target.x - current.x, target.y - current.y);\n\t\t\tif (distance > 2) {\n\t\t\t\ttransitions.push({\n\t\t\t\t\tnode: { ...node, position: { ...current } },\n\t\t\t\t\tfrom: current,\n\t\t\t\t\tto: target,\n\t\t\t\t\ttrajectory: linearPositionTrajectory,\n\t\t\t\t\tduration: this.glideDurationMs\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis.targetPositions = nextPositions;\n\n\t\tif (transitions.length === 0) {\n\t\t\tthis.livePositions = new Map(nextPositions);\n\t\t\tthis.onLayoutUpdated?.(nextPositions);\n\t\t\treturn;\n\t\t}\n\n\t\tconst live = new Map<string, XYPosition>(nextPositions);\n\t\tfor (const trans of transitions) {\n\t\t\tlive.set(trans.node.id, { ...trans.from });\n\t\t}\n\t\tthis.livePositions = live;\n\n\t\tlet finished = false;\n\t\tconst cancel = runMultiNodeTransition(transitions, {\n\t\t\tclock: this.clock,\n\t\t\tonUpdate: (updated) => {\n\t\t\t\tconst frame = new Map<string, XYPosition>(this.livePositions);\n\t\t\t\tfor (const node of updated) {\n\t\t\t\t\tframe.set(node.id, { ...node.position });\n\t\t\t\t}\n\t\t\t\tthis.livePositions = frame;\n\t\t\t\tthis.onLayoutUpdated?.(frame);\n\t\t\t},\n\t\t\tonComplete: () => {\n\t\t\t\tfinished = true;\n\t\t\t\tthis.activeTransitionCancel = null;\n\t\t\t\tthis.livePositions = new Map(nextPositions);\n\t\t\t\tthis.onLayoutUpdated?.(nextPositions);\n\t\t\t}\n\t\t});\n\t\t// A zero-duration glide completes synchronously; don't keep a stale canceller.\n\t\tthis.activeTransitionCancel = finished ? null : cancel;\n\t}\n\n\tpublic destroy(): void {\n\t\tthis.clearPending();\n\t\tif (this.activeTransitionCancel) {\n\t\t\tthis.activeTransitionCancel();\n\t\t\tthis.activeTransitionCancel = null;\n\t\t}\n\t}\n}\n"]}
|