@pixerate/editor 0.23.0 → 0.24.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/README.md +96 -1
- package/THIRD_PARTY_NOTICES.md +51 -0
- package/dist/agent/index.cjs +9 -8
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +4 -3
- package/dist/agent/index.d.ts +4 -3
- package/dist/agent/index.js +3 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +1210 -17
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +318 -1
- package/dist/canvas/index.d.ts +318 -1
- package/dist/canvas/index.js +1199 -6
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-QBJ22YZR.js → chunk-3CN2WD3X.js} +1354 -206
- package/dist/chunk-3CN2WD3X.js.map +1 -0
- package/dist/{chunk-JJDLPEWL.js → chunk-3LV6RRPH.js} +2 -2
- package/dist/{chunk-MJZBNWG7.js → chunk-5S3Z4PPF.js} +78 -557
- package/dist/chunk-5S3Z4PPF.js.map +1 -0
- package/dist/chunk-664LQYFJ.js +115 -0
- package/dist/chunk-664LQYFJ.js.map +1 -0
- package/dist/{chunk-AA4ZEVCC.cjs → chunk-D27YFC46.cjs} +101 -580
- package/dist/chunk-D27YFC46.cjs.map +1 -0
- package/dist/chunk-D6FH2YAX.cjs +131 -0
- package/dist/chunk-D6FH2YAX.cjs.map +1 -0
- package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
- package/dist/chunk-FD4LPFAE.cjs.map +1 -0
- package/dist/chunk-FODNLX5N.js +749 -0
- package/dist/chunk-FODNLX5N.js.map +1 -0
- package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
- package/dist/chunk-FPENXAEJ.js.map +1 -0
- package/dist/chunk-HLIMTC6N.js +1 -0
- package/dist/chunk-HLIMTC6N.js.map +1 -0
- package/dist/{chunk-QGHGJ56O.js → chunk-ITBSKI26.js} +1483 -19
- package/dist/chunk-ITBSKI26.js.map +1 -0
- package/dist/{chunk-XDMXXC4Z.cjs → chunk-MA2F5KHF.cjs} +350 -227
- package/dist/chunk-MA2F5KHF.cjs.map +1 -0
- package/dist/{chunk-RIKBJLS2.cjs → chunk-MCSJFWAO.cjs} +1356 -208
- package/dist/chunk-MCSJFWAO.cjs.map +1 -0
- package/dist/chunk-MKA3AHLV.cjs +256 -0
- package/dist/chunk-MKA3AHLV.cjs.map +1 -0
- package/dist/chunk-OLZJXL4R.cjs +749 -0
- package/dist/chunk-OLZJXL4R.cjs.map +1 -0
- package/dist/chunk-OXSV64JX.js +689 -0
- package/dist/chunk-OXSV64JX.js.map +1 -0
- package/dist/chunk-P3RQ5UJE.cjs +689 -0
- package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
- package/dist/chunk-P6ODPZ4W.js +256 -0
- package/dist/chunk-P6ODPZ4W.js.map +1 -0
- package/dist/chunk-PGNZKFQS.js +685 -0
- package/dist/chunk-PGNZKFQS.js.map +1 -0
- package/dist/chunk-PL4JB3BF.cjs +1 -0
- package/dist/chunk-PL4JB3BF.cjs.map +1 -0
- package/dist/{chunk-GVSMRPHB.cjs → chunk-SBCZ6RN5.cjs} +1568 -104
- package/dist/chunk-SBCZ6RN5.cjs.map +1 -0
- package/dist/{chunk-CL37JGFW.cjs → chunk-SML64VJG.cjs} +4 -4
- package/dist/{chunk-CL37JGFW.cjs.map → chunk-SML64VJG.cjs.map} +1 -1
- package/dist/chunk-TNNJXF46.cjs +115 -0
- package/dist/chunk-TNNJXF46.cjs.map +1 -0
- package/dist/chunk-U5HZSFCS.js +131 -0
- package/dist/chunk-U5HZSFCS.js.map +1 -0
- package/dist/{chunk-K3R5NG2D.js → chunk-U5KWZU4X.js} +251 -128
- package/dist/chunk-U5KWZU4X.js.map +1 -0
- package/dist/chunk-XNORY7M6.cjs +685 -0
- package/dist/chunk-XNORY7M6.cjs.map +1 -0
- package/dist/commands/index.d.cts +5 -353
- package/dist/commands/index.d.ts +5 -353
- package/dist/comment-store-BEMgVlAA.d.cts +135 -0
- package/dist/comment-store-BEMgVlAA.d.ts +135 -0
- package/dist/compare/index.cjs +15 -0
- package/dist/compare/index.cjs.map +1 -0
- package/dist/compare/index.d.cts +58 -0
- package/dist/compare/index.d.ts +58 -0
- package/dist/compare/index.js +15 -0
- package/dist/compare/index.js.map +1 -0
- package/dist/{controller-pePCJLT1.d.cts → controller-BhLLAoi8.d.cts} +45 -4
- package/dist/{controller-pePCJLT1.d.ts → controller-BhLLAoi8.d.ts} +45 -4
- package/dist/documents-BQjzJNe2.d.ts +76 -0
- package/dist/documents-KRTPhvst.d.cts +76 -0
- package/dist/extensions/index.cjs +53 -5
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +7 -3
- package/dist/extensions/index.d.ts +7 -3
- package/dist/extensions/index.js +52 -4
- package/dist/generation/index.cjs +1373 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +554 -0
- package/dist/generation/index.d.ts +554 -0
- package/dist/generation/index.js +1373 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/grammar/index.cjs +48 -3
- package/dist/grammar/index.cjs.map +1 -1
- package/dist/grammar/index.d.cts +322 -100
- package/dist/grammar/index.d.ts +322 -100
- package/dist/grammar/index.js +54 -9
- package/dist/image-editor/index.cjs +1831 -30
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +590 -3
- package/dist/image-editor/index.d.ts +590 -3
- package/dist/image-editor/index.js +1807 -6
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{index-CCr_z9kF.d.cts → index-BhJBSm2d.d.cts} +370 -4
- package/dist/{index-Ck6ajwXh.d.ts → index-fJrlkJCd.d.ts} +370 -4
- package/dist/index.cjs +162 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -8
- package/dist/index.d.ts +14 -8
- package/dist/index.js +174 -37
- package/dist/index.js.map +1 -1
- package/dist/migrate-iTlm3a8h.d.cts +112 -0
- package/dist/migrate-iTlm3a8h.d.ts +112 -0
- package/dist/persistence/index.cjs +676 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +347 -0
- package/dist/persistence/index.d.ts +347 -0
- package/dist/persistence/index.js +676 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/{registry-D5-R90p0.d.cts → registry-BDe-vlv3.d.ts} +2 -40
- package/dist/registry-D32LpIc4.d.cts +354 -0
- package/dist/{registry-D5-R90p0.d.ts → registry-DnzpgY27.d.cts} +2 -40
- package/dist/registry-evKTP4ls.d.ts +354 -0
- package/dist/schema-DYDGdYL9.d.cts +41 -0
- package/dist/schema-DYDGdYL9.d.ts +41 -0
- package/dist/serializers/index.cjs +4 -3
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.d.cts +2 -1
- package/dist/serializers/index.d.ts +2 -1
- package/dist/serializers/index.js +3 -2
- package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
- package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
- package/dist/spreadsheet/index.cjs +37 -3
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +188 -17
- package/dist/spreadsheet/index.d.ts +188 -17
- package/dist/spreadsheet/index.js +43 -9
- package/dist/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
- package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
- package/dist/{track-changes-BSF58RK0.d.ts → track-changes-BK5sVf4_.d.cts} +18 -136
- package/dist/{track-changes-BSF58RK0.d.cts → track-changes-CDjCrwKe.d.ts} +18 -136
- package/package.json +16 -1
- package/dist/chunk-4SUNJZWB.cjs.map +0 -1
- package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
- package/dist/chunk-AXV2ZW34.cjs +0 -118
- package/dist/chunk-AXV2ZW34.cjs.map +0 -1
- package/dist/chunk-B2ZRLN4S.js +0 -118
- package/dist/chunk-B2ZRLN4S.js.map +0 -1
- package/dist/chunk-GVSMRPHB.cjs.map +0 -1
- package/dist/chunk-K3R5NG2D.js.map +0 -1
- package/dist/chunk-MJZBNWG7.js.map +0 -1
- package/dist/chunk-OYXSKQFR.js.map +0 -1
- package/dist/chunk-QBJ22YZR.js.map +0 -1
- package/dist/chunk-QGHGJ56O.js.map +0 -1
- package/dist/chunk-RIKBJLS2.cjs.map +0 -1
- package/dist/chunk-XDMXXC4Z.cjs.map +0 -1
- /package/dist/{chunk-JJDLPEWL.js.map → chunk-3LV6RRPH.js.map} +0 -0
package/dist/canvas/index.js
CHANGED
|
@@ -1577,10 +1577,10 @@ var CanvasScenesStore = class {
|
|
|
1577
1577
|
return this.update(id, { name });
|
|
1578
1578
|
}
|
|
1579
1579
|
/** Moves a scene to `toIndex` (clamped). */
|
|
1580
|
-
move(id,
|
|
1580
|
+
move(id, toIndex2) {
|
|
1581
1581
|
const from = this.scenes.findIndex((s) => s.id === id);
|
|
1582
1582
|
if (from === -1) return;
|
|
1583
|
-
const to = Math.max(0, Math.min(this.scenes.length - 1, Math.trunc(
|
|
1583
|
+
const to = Math.max(0, Math.min(this.scenes.length - 1, Math.trunc(toIndex2)));
|
|
1584
1584
|
if (from === to) return;
|
|
1585
1585
|
const scenes = [...this.scenes];
|
|
1586
1586
|
const [scene] = scenes.splice(from, 1);
|
|
@@ -3388,6 +3388,888 @@ function getResizingNodeRect(node, lookup, options = {}) {
|
|
|
3388
3388
|
return { x, y, width: node.width ?? size.width, height: node.height ?? size.height };
|
|
3389
3389
|
}
|
|
3390
3390
|
|
|
3391
|
+
// src/canvas/autoLayout.ts
|
|
3392
|
+
var AUTO_LAYOUT_DATA_KEY = "layout";
|
|
3393
|
+
var CHILD_LAYOUT_DATA_KEY = "childLayout";
|
|
3394
|
+
var MODES = /* @__PURE__ */ new Set(["horizontal", "vertical", "grid"]);
|
|
3395
|
+
var EPS = 1e-6;
|
|
3396
|
+
var MAX_TRACKS = 1e3;
|
|
3397
|
+
var MAX_GRID_CELLS = 1e6;
|
|
3398
|
+
function clampLayoutSize(value, min, max) {
|
|
3399
|
+
let v = Number.isFinite(value) ? Math.max(value, 0) : 0;
|
|
3400
|
+
if (typeof max === "number" && Number.isFinite(max)) v = Math.min(v, max);
|
|
3401
|
+
if (typeof min === "number" && Number.isFinite(min)) v = Math.max(v, min);
|
|
3402
|
+
return v;
|
|
3403
|
+
}
|
|
3404
|
+
var finite = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
3405
|
+
function getAutoLayout(node) {
|
|
3406
|
+
const layout2 = node?.data?.[AUTO_LAYOUT_DATA_KEY];
|
|
3407
|
+
return layout2 && typeof layout2 === "object" && MODES.has(layout2.mode) ? layout2 : void 0;
|
|
3408
|
+
}
|
|
3409
|
+
function isAutoLayoutFrame(node) {
|
|
3410
|
+
return getAutoLayout(node) !== void 0;
|
|
3411
|
+
}
|
|
3412
|
+
function getChildLayout(node) {
|
|
3413
|
+
const child = node?.data?.[CHILD_LAYOUT_DATA_KEY];
|
|
3414
|
+
return child && typeof child === "object" ? child : {};
|
|
3415
|
+
}
|
|
3416
|
+
function getLayoutSizing(node, axis) {
|
|
3417
|
+
const value = getChildLayout(node).sizing?.[axis] ?? getAutoLayout(node)?.sizing?.[axis];
|
|
3418
|
+
return value === "hug" || value === "fill" ? value : "fixed";
|
|
3419
|
+
}
|
|
3420
|
+
function limitsOf(node) {
|
|
3421
|
+
const child = getChildLayout(node);
|
|
3422
|
+
const layout2 = getAutoLayout(node);
|
|
3423
|
+
const min = child.min ?? layout2?.min ?? {};
|
|
3424
|
+
const max = child.max ?? layout2?.max ?? {};
|
|
3425
|
+
return { minW: min.width, maxW: max.width, minH: min.height, maxH: max.height };
|
|
3426
|
+
}
|
|
3427
|
+
function resolvePadding(padding) {
|
|
3428
|
+
let sides;
|
|
3429
|
+
if (typeof padding === "number") sides = [padding, padding, padding, padding];
|
|
3430
|
+
else if (Array.isArray(padding)) {
|
|
3431
|
+
sides = padding.length === 2 ? [padding[0], padding[1], padding[0], padding[1]] : [padding[0], padding[1], padding[2], padding[3]];
|
|
3432
|
+
} else if (padding && typeof padding === "object") sides = [padding.top, padding.right, padding.bottom, padding.left];
|
|
3433
|
+
else sides = [0, 0, 0, 0];
|
|
3434
|
+
return sides.map((p) => Math.max(finite(p), 0));
|
|
3435
|
+
}
|
|
3436
|
+
var LayoutState = class {
|
|
3437
|
+
boxes = /* @__PURE__ */ new Map();
|
|
3438
|
+
measure;
|
|
3439
|
+
visiting = /* @__PURE__ */ new Set();
|
|
3440
|
+
original = /* @__PURE__ */ new Map();
|
|
3441
|
+
constructor(nodes, options = {}) {
|
|
3442
|
+
this.measure = options.measure ?? {};
|
|
3443
|
+
for (const node of nodes) {
|
|
3444
|
+
const size = this.measure.size?.(node) ?? getNodeSize(node, options.rectOptions);
|
|
3445
|
+
const box = {
|
|
3446
|
+
id: node.id,
|
|
3447
|
+
node,
|
|
3448
|
+
parent: node.parentId,
|
|
3449
|
+
x: finite(node.position?.x),
|
|
3450
|
+
y: finite(node.position?.y),
|
|
3451
|
+
w: finite(size.width),
|
|
3452
|
+
h: finite(size.height),
|
|
3453
|
+
kids: []
|
|
3454
|
+
};
|
|
3455
|
+
this.boxes.set(node.id, box);
|
|
3456
|
+
this.original.set(node.id, { x: box.x, y: box.y, w: box.w, h: box.h });
|
|
3457
|
+
}
|
|
3458
|
+
for (const node of nodes) {
|
|
3459
|
+
if (node.parentId && node.parentId !== node.id) this.boxes.get(node.parentId)?.kids.push(node.id);
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
updates() {
|
|
3463
|
+
const out = [];
|
|
3464
|
+
for (const [id, box] of this.boxes) {
|
|
3465
|
+
const o = this.original.get(id);
|
|
3466
|
+
const update = { id };
|
|
3467
|
+
if (Math.abs(box.x - o.x) > EPS || Math.abs(box.y - o.y) > EPS) update.position = { x: box.x, y: box.y };
|
|
3468
|
+
if (Math.abs(box.w - o.w) > EPS) update.width = box.w;
|
|
3469
|
+
if (Math.abs(box.h - o.h) > EPS) update.height = box.h;
|
|
3470
|
+
if (update.position || update.width !== void 0 || update.height !== void 0) out.push(update);
|
|
3471
|
+
}
|
|
3472
|
+
return out;
|
|
3473
|
+
}
|
|
3474
|
+
/** Runs `fn` for `id` unless it is already on the stack (guards `parentId` cycles). */
|
|
3475
|
+
guard(id, fn) {
|
|
3476
|
+
if (this.visiting.has(id)) return;
|
|
3477
|
+
this.visiting.add(id);
|
|
3478
|
+
try {
|
|
3479
|
+
fn();
|
|
3480
|
+
} finally {
|
|
3481
|
+
this.visiting.delete(id);
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
ancestors(id) {
|
|
3485
|
+
const out = [];
|
|
3486
|
+
const seen = /* @__PURE__ */ new Set([id]);
|
|
3487
|
+
let parent = this.boxes.get(id)?.parent;
|
|
3488
|
+
while (parent && !seen.has(parent) && this.boxes.has(parent)) {
|
|
3489
|
+
out.push(parent);
|
|
3490
|
+
seen.add(parent);
|
|
3491
|
+
parent = this.boxes.get(parent).parent;
|
|
3492
|
+
}
|
|
3493
|
+
return out;
|
|
3494
|
+
}
|
|
3495
|
+
};
|
|
3496
|
+
function setSize(s, id, w, h) {
|
|
3497
|
+
const b = s.boxes.get(id);
|
|
3498
|
+
if (!b) return;
|
|
3499
|
+
b.w = Number.isFinite(w) ? Math.max(w, 0) : b.w;
|
|
3500
|
+
b.h = Number.isFinite(h) ? Math.max(h, 0) : b.h;
|
|
3501
|
+
}
|
|
3502
|
+
function place(s, id, x, y) {
|
|
3503
|
+
const b = s.boxes.get(id);
|
|
3504
|
+
if (!b) return;
|
|
3505
|
+
b.x = x;
|
|
3506
|
+
b.y = y;
|
|
3507
|
+
}
|
|
3508
|
+
var isText = (s, b) => !!s.measure.textSize && s.measure.textSize(b.node) !== void 0;
|
|
3509
|
+
function flowChildren(s, frame) {
|
|
3510
|
+
const f = s.boxes.get(frame);
|
|
3511
|
+
if (!f) return [];
|
|
3512
|
+
return f.kids.filter((k) => {
|
|
3513
|
+
const n = s.boxes.get(k).node;
|
|
3514
|
+
return n.hidden !== true && !getChildLayout(n).absolute;
|
|
3515
|
+
});
|
|
3516
|
+
}
|
|
3517
|
+
function fitHugText(s, id) {
|
|
3518
|
+
const b = s.boxes.get(id);
|
|
3519
|
+
if (!b || !isText(s, b)) return;
|
|
3520
|
+
const natural = s.measure.textSize(b.node);
|
|
3521
|
+
const { minW, maxW } = limitsOf(b.node);
|
|
3522
|
+
if (getLayoutSizing(b.node, "width") === "hug") {
|
|
3523
|
+
const w = clampLayoutSize(natural.width, minW, maxW);
|
|
3524
|
+
const limited = Math.abs(w - natural.width) > EPS;
|
|
3525
|
+
const h = limited ? s.measure.textHeight?.(b.node, w) ?? natural.height : natural.height;
|
|
3526
|
+
setSize(s, id, w, h);
|
|
3527
|
+
} else if (getLayoutSizing(b.node, "height") === "hug") {
|
|
3528
|
+
setSize(s, id, b.w, s.measure.textHeight?.(b.node, b.w) ?? b.h);
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
function enforceLimits(s, id) {
|
|
3532
|
+
const b = s.boxes.get(id);
|
|
3533
|
+
if (!b) return;
|
|
3534
|
+
const { minW, maxW, minH, maxH } = limitsOf(b.node);
|
|
3535
|
+
if (minW === void 0 && maxW === void 0 && minH === void 0 && maxH === void 0) return;
|
|
3536
|
+
const nw = clampLayoutSize(b.w, minW, maxW);
|
|
3537
|
+
const nh = clampLayoutSize(b.h, minH, maxH);
|
|
3538
|
+
if (Math.abs(nw - b.w) < 1e-9 && Math.abs(nh - b.h) < 1e-9) return;
|
|
3539
|
+
if (isText(s, b)) setSize(s, id, nw, nh);
|
|
3540
|
+
else resizeChild(s, id, nw, nh);
|
|
3541
|
+
}
|
|
3542
|
+
function itemBaseline(s, id, depth) {
|
|
3543
|
+
const b = s.boxes.get(id);
|
|
3544
|
+
if (!b) return void 0;
|
|
3545
|
+
if (isText(s, b)) {
|
|
3546
|
+
const v = s.measure.textBaseline?.(b.node);
|
|
3547
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
3548
|
+
}
|
|
3549
|
+
const layout2 = getAutoLayout(b.node);
|
|
3550
|
+
if (!layout2 || layout2.mode === "grid" || depth >= 32) return void 0;
|
|
3551
|
+
for (const k of flowChildren(s, id)) {
|
|
3552
|
+
const base = itemBaseline(s, k, depth + 1);
|
|
3553
|
+
if (base !== void 0) return s.boxes.get(k).y + base;
|
|
3554
|
+
}
|
|
3555
|
+
return void 0;
|
|
3556
|
+
}
|
|
3557
|
+
function resizeChild(s, id, w, h) {
|
|
3558
|
+
const b = s.boxes.get(id);
|
|
3559
|
+
if (!b) return;
|
|
3560
|
+
if (isText(s, b) && getLayoutSizing(b.node, "height") === "hug") {
|
|
3561
|
+
setSize(s, id, w, s.measure.textHeight?.(b.node, w) ?? h);
|
|
3562
|
+
return;
|
|
3563
|
+
}
|
|
3564
|
+
const ow = b.w;
|
|
3565
|
+
const oh = b.h;
|
|
3566
|
+
setSize(s, id, w, h);
|
|
3567
|
+
if (b.kids.length > 0) constrain(s, id, ow, oh);
|
|
3568
|
+
if (getAutoLayout(b.node)) layout(s, id);
|
|
3569
|
+
}
|
|
3570
|
+
function mainOffsets(align, inner, total, n, gap) {
|
|
3571
|
+
const gaps = gap * Math.max(n - 1, 0);
|
|
3572
|
+
const free = inner - total;
|
|
3573
|
+
const k = Math.max(n, 1);
|
|
3574
|
+
switch (align) {
|
|
3575
|
+
case "center":
|
|
3576
|
+
return [(free - gaps) / 2, gap];
|
|
3577
|
+
case "end":
|
|
3578
|
+
return [free - gaps, gap];
|
|
3579
|
+
case "space-between":
|
|
3580
|
+
return [0, n > 1 ? Math.max(free / (n - 1), 0) : 0];
|
|
3581
|
+
case "space-around": {
|
|
3582
|
+
const g = Math.max(free / k, 0);
|
|
3583
|
+
return [g / 2, g];
|
|
3584
|
+
}
|
|
3585
|
+
case "space-evenly": {
|
|
3586
|
+
const g = Math.max(free / (k + 1), 0);
|
|
3587
|
+
return [g, g];
|
|
3588
|
+
}
|
|
3589
|
+
default:
|
|
3590
|
+
return [0, gap];
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
function distribute(items, open, free) {
|
|
3594
|
+
free = Math.max(free, 0);
|
|
3595
|
+
while (open.length > 0) {
|
|
3596
|
+
const share = free / open.length;
|
|
3597
|
+
const sized = open.map((i) => [i, clampLayoutSize(share, items[i].minMain, items[i].maxMain)]);
|
|
3598
|
+
const violation = sized.reduce((sum, [, v]) => sum + (v - share), 0);
|
|
3599
|
+
const frozen = (v) => Math.abs(violation) < 1e-9 || violation > 0 && v > share + 1e-9 || violation < 0 && v < share - 1e-9;
|
|
3600
|
+
for (const [i, v] of sized) {
|
|
3601
|
+
if (frozen(v)) {
|
|
3602
|
+
items[i].main = v;
|
|
3603
|
+
free -= v;
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
free = Math.max(free, 0);
|
|
3607
|
+
open = sized.filter(([, v]) => !frozen(v)).map(([i]) => i);
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
function layout(s, frame) {
|
|
3611
|
+
s.guard(frame, () => layoutFrameInner(s, frame));
|
|
3612
|
+
}
|
|
3613
|
+
function layoutFrameInner(s, frame) {
|
|
3614
|
+
const f = s.boxes.get(frame);
|
|
3615
|
+
const al = f && getAutoLayout(f.node);
|
|
3616
|
+
if (!f || !al) return;
|
|
3617
|
+
const horizontal = al.mode !== "vertical";
|
|
3618
|
+
const hugW = getLayoutSizing(f.node, "width") === "hug";
|
|
3619
|
+
const hugH = getLayoutSizing(f.node, "height") === "hug";
|
|
3620
|
+
const ow = f.w;
|
|
3621
|
+
const oh = f.h;
|
|
3622
|
+
const fl = limitsOf(f.node);
|
|
3623
|
+
const [pt, pr, pb, pl] = resolvePadding(al.padding);
|
|
3624
|
+
const fw = Math.max(clampLayoutSize(ow, fl.minW, fl.maxW), pl + pr);
|
|
3625
|
+
const fh = Math.max(clampLayoutSize(oh, fl.minH, fl.maxH), pt + pb);
|
|
3626
|
+
const kids = flowChildren(s, frame);
|
|
3627
|
+
for (const c of kids) {
|
|
3628
|
+
fitHugText(s, c);
|
|
3629
|
+
enforceLimits(s, c);
|
|
3630
|
+
}
|
|
3631
|
+
if (al.mode === "grid") {
|
|
3632
|
+
layoutGrid(s, frame, al);
|
|
3633
|
+
return;
|
|
3634
|
+
}
|
|
3635
|
+
const innerMainFixed = horizontal ? fw - pl - pr : fh - pt - pb;
|
|
3636
|
+
const innerCrossFixed = horizontal ? fh - pt - pb : fw - pl - pr;
|
|
3637
|
+
const hugMain = horizontal ? hugW : hugH;
|
|
3638
|
+
const hugCross = horizontal ? hugH : hugW;
|
|
3639
|
+
const alignCross = al.alignCross ?? "start";
|
|
3640
|
+
const baseline = horizontal && alignCross === "baseline";
|
|
3641
|
+
const stretch = alignCross === "stretch";
|
|
3642
|
+
const items = [];
|
|
3643
|
+
for (const c of kids) {
|
|
3644
|
+
const b = s.boxes.get(c);
|
|
3645
|
+
const lim = limitsOf(b.node);
|
|
3646
|
+
const sm = getLayoutSizing(b.node, horizontal ? "width" : "height");
|
|
3647
|
+
const sc = getLayoutSizing(b.node, horizontal ? "height" : "width");
|
|
3648
|
+
items.push({
|
|
3649
|
+
id: c,
|
|
3650
|
+
main: horizontal ? b.w : b.h,
|
|
3651
|
+
cross: horizontal ? b.h : b.w,
|
|
3652
|
+
// Fill needs room to fill: on an axis the frame hugs it reads as fixed.
|
|
3653
|
+
fillMain: sm === "fill" && !hugMain,
|
|
3654
|
+
fillCross: (sc === "fill" || stretch && sc !== "hug") && !hugCross,
|
|
3655
|
+
minMain: horizontal ? lim.minW : lim.minH,
|
|
3656
|
+
maxMain: horizontal ? lim.maxW : lim.maxH,
|
|
3657
|
+
minCross: horizontal ? lim.minH : lim.minW,
|
|
3658
|
+
maxCross: horizontal ? lim.maxH : lim.maxW,
|
|
3659
|
+
baseOff: 0
|
|
3660
|
+
});
|
|
3661
|
+
}
|
|
3662
|
+
const gap = finite(al.gap);
|
|
3663
|
+
const alignMain = al.alignMain ?? "start";
|
|
3664
|
+
const autoGap = alignMain === "space-between" || alignMain === "space-around" || alignMain === "space-evenly";
|
|
3665
|
+
const wraps = !!al.wrap && !hugMain;
|
|
3666
|
+
const sizeOf = (id) => {
|
|
3667
|
+
const b = s.boxes.get(id);
|
|
3668
|
+
return horizontal ? [b.w, b.h] : [b.h, b.w];
|
|
3669
|
+
};
|
|
3670
|
+
const resize = (it, main, cross) => resizeChild(s, it.id, horizontal ? main : cross, horizontal ? cross : main);
|
|
3671
|
+
if (!wraps) {
|
|
3672
|
+
for (const it of items) {
|
|
3673
|
+
if (!it.fillCross || it.fillMain) continue;
|
|
3674
|
+
resize(it, it.main, clampLayoutSize(innerCrossFixed, it.minCross, it.maxCross));
|
|
3675
|
+
it.main = sizeOf(it.id)[0];
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
const lines = [];
|
|
3679
|
+
if (wraps) {
|
|
3680
|
+
let cur = [];
|
|
3681
|
+
let used = 0;
|
|
3682
|
+
items.forEach((it, i) => {
|
|
3683
|
+
const sz = it.fillMain ? it.minMain ?? 0 : it.main;
|
|
3684
|
+
const add2 = cur.length === 0 ? sz : Math.max(gap, 0) + sz;
|
|
3685
|
+
if (cur.length > 0 && used + add2 > innerMainFixed + 1e-6) {
|
|
3686
|
+
lines.push(cur);
|
|
3687
|
+
cur = [];
|
|
3688
|
+
used = sz;
|
|
3689
|
+
} else {
|
|
3690
|
+
used += add2;
|
|
3691
|
+
}
|
|
3692
|
+
cur.push(i);
|
|
3693
|
+
});
|
|
3694
|
+
if (cur.length > 0) lines.push(cur);
|
|
3695
|
+
} else {
|
|
3696
|
+
lines.push(items.map((_, i) => i));
|
|
3697
|
+
}
|
|
3698
|
+
for (const line2 of lines) {
|
|
3699
|
+
const fixed = line2.filter((i) => !items[i].fillMain).reduce((sum, i) => sum + items[i].main, 0);
|
|
3700
|
+
const gaps = gap * Math.max(line2.length - 1, 0);
|
|
3701
|
+
const fills = line2.filter((i) => items[i].fillMain);
|
|
3702
|
+
if (fills.length > 0) distribute(items, fills, innerMainFixed - fixed - (autoGap ? 0 : gaps));
|
|
3703
|
+
}
|
|
3704
|
+
for (const it of items) {
|
|
3705
|
+
if (!it.fillMain) continue;
|
|
3706
|
+
const cross = it.fillCross && !wraps ? clampLayoutSize(innerCrossFixed, it.minCross, it.maxCross) : it.cross;
|
|
3707
|
+
resize(it, it.main, cross);
|
|
3708
|
+
it.cross = sizeOf(it.id)[1];
|
|
3709
|
+
}
|
|
3710
|
+
if (baseline) {
|
|
3711
|
+
for (const it of items) if (!it.fillCross) it.baseline = itemBaseline(s, it.id, 0);
|
|
3712
|
+
}
|
|
3713
|
+
const extents = [];
|
|
3714
|
+
for (const line2 of lines) {
|
|
3715
|
+
const gaps = gap * Math.max(line2.length - 1, 0);
|
|
3716
|
+
const lineBase = line2.reduce((m, i) => Math.max(m, items[i].baseline ?? 0), 0);
|
|
3717
|
+
for (const i of line2) items[i].baseOff = items[i].baseline !== void 0 ? lineBase - items[i].baseline : 0;
|
|
3718
|
+
const inLine = line2.map((i) => items[i]);
|
|
3719
|
+
const mainUsed = inLine.reduce((sum, it) => sum + it.main, 0) + gaps;
|
|
3720
|
+
const allFill = inLine.every((it) => it.fillCross);
|
|
3721
|
+
const cross = inLine.filter((it) => allFill || !it.fillCross).reduce((m, it) => Math.max(m, it.baseOff + it.cross), 0);
|
|
3722
|
+
extents.push([mainUsed, cross]);
|
|
3723
|
+
}
|
|
3724
|
+
const contentMain = extents.reduce((m, l) => Math.max(m, l[0]), 0);
|
|
3725
|
+
let crossGap = al.rowGap !== void 0 ? finite(al.rowGap) : gap;
|
|
3726
|
+
const contentCross = extents.reduce((sum, l) => sum + l[1], 0) + crossGap * Math.max(lines.length - 1, 0);
|
|
3727
|
+
let nw = fw;
|
|
3728
|
+
let nh = fh;
|
|
3729
|
+
if (hugMain) {
|
|
3730
|
+
const v = contentMain + (horizontal ? pl + pr : pt + pb);
|
|
3731
|
+
if (horizontal) nw = v;
|
|
3732
|
+
else nh = v;
|
|
3733
|
+
}
|
|
3734
|
+
if (hugCross) {
|
|
3735
|
+
const v = contentCross + (horizontal ? pt + pb : pl + pr);
|
|
3736
|
+
if (horizontal) nh = v;
|
|
3737
|
+
else nw = v;
|
|
3738
|
+
}
|
|
3739
|
+
nw = Math.max(clampLayoutSize(nw, fl.minW, fl.maxW), pl + pr);
|
|
3740
|
+
nh = Math.max(clampLayoutSize(nh, fl.minH, fl.maxH), pt + pb);
|
|
3741
|
+
setSize(s, frame, nw, nh);
|
|
3742
|
+
constrain(s, frame, ow, oh);
|
|
3743
|
+
const innerMain = horizontal ? nw - pl - pr : nh - pt - pb;
|
|
3744
|
+
const innerCross = horizontal ? nh - pt - pb : nw - pl - pr;
|
|
3745
|
+
let crossPos = horizontal ? pt : pl;
|
|
3746
|
+
const single = lines.length === 1;
|
|
3747
|
+
if (lines.length > 1) {
|
|
3748
|
+
const linesCross = extents.reduce((sum, l) => sum + l[1], 0);
|
|
3749
|
+
const between = lines.length - 1;
|
|
3750
|
+
const spread = (innerCross - linesCross) / between;
|
|
3751
|
+
const spaceBetween = al.alignContent === "space-between";
|
|
3752
|
+
if (spaceBetween && spread > 0) {
|
|
3753
|
+
crossGap = spread;
|
|
3754
|
+
} else {
|
|
3755
|
+
if (spaceBetween) crossGap = 0;
|
|
3756
|
+
const free = innerCross - linesCross - crossGap * between;
|
|
3757
|
+
if (free > 0 && items.every((it) => it.fillCross)) {
|
|
3758
|
+
const extra = free / lines.length;
|
|
3759
|
+
for (const l of extents) l[1] += extra;
|
|
3760
|
+
} else if (Number.isFinite(free)) {
|
|
3761
|
+
crossPos += alignCross === "center" ? free / 2 : alignCross === "end" ? free : 0;
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
lines.forEach((line2, li) => {
|
|
3766
|
+
const [used, ownCross] = extents[li];
|
|
3767
|
+
const lineCross = single ? innerCross : ownCross;
|
|
3768
|
+
const total = used - gap * Math.max(line2.length - 1, 0);
|
|
3769
|
+
let [pos, step] = mainOffsets(alignMain, innerMain, total, line2.length, gap);
|
|
3770
|
+
pos += horizontal ? pl : pt;
|
|
3771
|
+
for (const i of line2) {
|
|
3772
|
+
const it = items[i];
|
|
3773
|
+
const crossSize = it.fillCross ? clampLayoutSize(lineCross, it.minCross, it.maxCross) : it.cross;
|
|
3774
|
+
let off = 0;
|
|
3775
|
+
if (alignCross === "baseline") off = it.baseOff;
|
|
3776
|
+
else if (alignCross === "center") off = (lineCross - crossSize) / 2;
|
|
3777
|
+
else if (alignCross === "end") off = lineCross - crossSize;
|
|
3778
|
+
if (it.fillCross && wraps) resize(it, it.main, crossSize);
|
|
3779
|
+
const x = horizontal ? pos : crossPos + off;
|
|
3780
|
+
const y = horizontal ? crossPos + off : pos;
|
|
3781
|
+
place(s, it.id, finite(x), finite(y));
|
|
3782
|
+
pos += it.main + step;
|
|
3783
|
+
}
|
|
3784
|
+
crossPos += lineCross + crossGap;
|
|
3785
|
+
});
|
|
3786
|
+
}
|
|
3787
|
+
function parseTrack(track) {
|
|
3788
|
+
if (typeof track === "number") return { sizing: "fixed", value: track };
|
|
3789
|
+
if (track === "hug") return { sizing: "hug", value: 0 };
|
|
3790
|
+
if (typeof track === "string") {
|
|
3791
|
+
const match = /^\s*(-?\d*\.?\d+)\s*fr\s*$/i.exec(track);
|
|
3792
|
+
if (match) return { sizing: "fill", value: Number(match[1]) };
|
|
3793
|
+
}
|
|
3794
|
+
if (track && typeof track === "object" && "fr" in track) return { sizing: "fill", value: track.fr };
|
|
3795
|
+
return { sizing: "fill", value: 1 };
|
|
3796
|
+
}
|
|
3797
|
+
function trackList(spec, fallback) {
|
|
3798
|
+
if (Array.isArray(spec)) return { count: Math.min(Math.max(spec.length, 1), MAX_TRACKS), tracks: spec.map(parseTrack) };
|
|
3799
|
+
const n = typeof spec === "number" && Number.isFinite(spec) ? Math.floor(spec) : fallback;
|
|
3800
|
+
return { count: Math.min(Math.max(n, 1), MAX_TRACKS), tracks: [] };
|
|
3801
|
+
}
|
|
3802
|
+
function trackSpec(tracks, i) {
|
|
3803
|
+
const t = tracks[i] ?? { sizing: "fill", value: 1 };
|
|
3804
|
+
const value = Number.isFinite(t.value) ? Math.min(Math.max(t.value, 0), 1e6) : 0;
|
|
3805
|
+
return { sizing: t.sizing, value };
|
|
3806
|
+
}
|
|
3807
|
+
function cellRect(g, c) {
|
|
3808
|
+
const x0 = g.columns[c.column]?.[0] ?? 0;
|
|
3809
|
+
const x1 = g.columns[c.column + c.columnSpan - 1]?.[1] ?? x0;
|
|
3810
|
+
const y0 = g.rows[c.row]?.[0] ?? 0;
|
|
3811
|
+
const y1 = g.rows[c.row + c.rowSpan - 1]?.[1] ?? y0;
|
|
3812
|
+
return { x: x0, y: y0, width: Math.max(x1, x0) - x0, height: Math.max(y1, y0) - y0 };
|
|
3813
|
+
}
|
|
3814
|
+
var toIndex = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? Math.floor(v) : void 0;
|
|
3815
|
+
function gridPlace(s, al, kids) {
|
|
3816
|
+
const cols = trackList(al.grid?.columns, 2).count;
|
|
3817
|
+
const minRows = trackList(al.grid?.rows, 1).count;
|
|
3818
|
+
const maxRows = Math.min(Math.max(Math.floor(MAX_GRID_CELLS / cols), 1), MAX_TRACKS);
|
|
3819
|
+
const occ = [];
|
|
3820
|
+
const free = (c, r, cs, rs) => {
|
|
3821
|
+
for (let ri = r; ri < r + rs; ri++) {
|
|
3822
|
+
const row = occ[ri];
|
|
3823
|
+
if (!row) continue;
|
|
3824
|
+
for (let ci = c; ci < c + cs; ci++) if (row[ci]) return false;
|
|
3825
|
+
}
|
|
3826
|
+
return true;
|
|
3827
|
+
};
|
|
3828
|
+
const mark = (c, r, cs, rs) => {
|
|
3829
|
+
while (occ.length < r + rs) occ.push(new Array(cols).fill(false));
|
|
3830
|
+
for (let ri = r; ri < r + rs; ri++) for (let ci = c; ci < c + cs; ci++) occ[ri][ci] = true;
|
|
3831
|
+
};
|
|
3832
|
+
const spans = (id) => {
|
|
3833
|
+
const area = getChildLayout(s.boxes.get(id).node).gridArea ?? {};
|
|
3834
|
+
const cs = Math.min(Math.max(toIndex(area.columnSpan) ?? 1, 1), cols);
|
|
3835
|
+
const rs = Math.min(Math.max(toIndex(area.rowSpan) ?? 1, 1), maxRows);
|
|
3836
|
+
const col = toIndex(area.column);
|
|
3837
|
+
const row = toIndex(area.row);
|
|
3838
|
+
return {
|
|
3839
|
+
col: col === void 0 ? void 0 : Math.min(col, cols - cs),
|
|
3840
|
+
row: row === void 0 ? void 0 : Math.min(row, maxRows - rs),
|
|
3841
|
+
cs,
|
|
3842
|
+
rs
|
|
3843
|
+
};
|
|
3844
|
+
};
|
|
3845
|
+
const placed = new Array(kids.length).fill(void 0);
|
|
3846
|
+
kids.forEach((id, i) => {
|
|
3847
|
+
const { col, row, cs, rs } = spans(id);
|
|
3848
|
+
if (col !== void 0 && row !== void 0) {
|
|
3849
|
+
mark(col, row, cs, rs);
|
|
3850
|
+
placed[i] = { id, column: col, row, columnSpan: cs, rowSpan: rs };
|
|
3851
|
+
}
|
|
3852
|
+
});
|
|
3853
|
+
let cursor = [0, 0];
|
|
3854
|
+
kids.forEach((id, i) => {
|
|
3855
|
+
if (placed[i]) return;
|
|
3856
|
+
const { col, row, cs, rs } = spans(id);
|
|
3857
|
+
const lastRow = maxRows - rs;
|
|
3858
|
+
let c = 0;
|
|
3859
|
+
let r = 0;
|
|
3860
|
+
if (col !== void 0) {
|
|
3861
|
+
r = lastRow;
|
|
3862
|
+
for (let ri = 0; ri <= lastRow; ri++) if (free(col, ri, cs, rs)) {
|
|
3863
|
+
r = ri;
|
|
3864
|
+
break;
|
|
3865
|
+
}
|
|
3866
|
+
c = col;
|
|
3867
|
+
} else if (row !== void 0) {
|
|
3868
|
+
r = row;
|
|
3869
|
+
for (let ci = 0; ci <= cols - cs; ci++) if (free(ci, row, cs, rs)) {
|
|
3870
|
+
c = ci;
|
|
3871
|
+
break;
|
|
3872
|
+
}
|
|
3873
|
+
} else {
|
|
3874
|
+
let [rr, cc] = cursor;
|
|
3875
|
+
let found;
|
|
3876
|
+
while (rr <= lastRow) {
|
|
3877
|
+
if (cc + cs <= cols && free(cc, rr, cs, rs)) {
|
|
3878
|
+
found = [cc, rr];
|
|
3879
|
+
break;
|
|
3880
|
+
}
|
|
3881
|
+
cc += 1;
|
|
3882
|
+
if (cc + cs > cols) {
|
|
3883
|
+
cc = 0;
|
|
3884
|
+
rr += 1;
|
|
3885
|
+
}
|
|
3886
|
+
}
|
|
3887
|
+
[c, r] = found ?? [0, lastRow];
|
|
3888
|
+
cursor = [r, c + cs];
|
|
3889
|
+
}
|
|
3890
|
+
mark(c, r, cs, rs);
|
|
3891
|
+
placed[i] = { id, column: c, row: r, columnSpan: cs, rowSpan: rs };
|
|
3892
|
+
});
|
|
3893
|
+
const cells = placed.filter((c) => !!c);
|
|
3894
|
+
const rows = Math.max(cells.reduce((m, c) => Math.max(m, c.row + c.rowSpan), 0), minRows);
|
|
3895
|
+
return { cells, rows: Math.min(rows, MAX_TRACKS) };
|
|
3896
|
+
}
|
|
3897
|
+
function resolveTracks(tracks, content, avail) {
|
|
3898
|
+
const out = content.map((c, i) => {
|
|
3899
|
+
const t = trackSpec(tracks, i);
|
|
3900
|
+
return t.sizing === "fixed" ? t.value : c;
|
|
3901
|
+
});
|
|
3902
|
+
if (avail === void 0) return out;
|
|
3903
|
+
const fr = (i) => trackSpec(tracks, i).value;
|
|
3904
|
+
let flex = out.map((_, i) => i).filter((i) => trackSpec(tracks, i).sizing === "fill");
|
|
3905
|
+
let used = out.reduce((sum, v, i) => trackSpec(tracks, i).sizing === "fill" ? sum : sum + v, 0);
|
|
3906
|
+
while (flex.length > 0) {
|
|
3907
|
+
const total = flex.reduce((sum, i) => sum + fr(i), 0);
|
|
3908
|
+
const unit2 = total > 1e-12 ? Math.max(avail - used, 0) / total : 0;
|
|
3909
|
+
const open = flex.filter((i) => unit2 * fr(i) >= out[i]);
|
|
3910
|
+
const frozen = flex.filter((i) => unit2 * fr(i) < out[i]);
|
|
3911
|
+
if (frozen.length === 0) {
|
|
3912
|
+
for (const i of open) out[i] = unit2 * fr(i);
|
|
3913
|
+
break;
|
|
3914
|
+
}
|
|
3915
|
+
used += frozen.reduce((sum, i) => sum + out[i], 0);
|
|
3916
|
+
flex = open;
|
|
3917
|
+
}
|
|
3918
|
+
return out;
|
|
3919
|
+
}
|
|
3920
|
+
function trackContent(cells, sizes, tracks, n, gap, columns, hug) {
|
|
3921
|
+
const byContent = (i) => trackSpec(tracks, i).sizing !== "fixed";
|
|
3922
|
+
const content = Array.from({ length: n }, (_, i) => {
|
|
3923
|
+
const t = trackSpec(tracks, i);
|
|
3924
|
+
return t.sizing === "fixed" ? t.value : 0;
|
|
3925
|
+
});
|
|
3926
|
+
const span = (c) => columns ? [c.column, c.columnSpan] : [c.row, c.rowSpan];
|
|
3927
|
+
cells.forEach((c, k) => {
|
|
3928
|
+
const [start, len] = span(c);
|
|
3929
|
+
if (len === 1 && byContent(start) && start < n) content[start] = Math.max(content[start], sizes[k]);
|
|
3930
|
+
});
|
|
3931
|
+
cells.forEach((c, k) => {
|
|
3932
|
+
const [start, len] = span(c);
|
|
3933
|
+
if (len < 2) return;
|
|
3934
|
+
const range = Array.from({ length: len }, (_, j) => start + j).filter((i) => i < n);
|
|
3935
|
+
if (!hug && range.some((i) => trackSpec(tracks, i).sizing === "fill")) return;
|
|
3936
|
+
const have = range.reduce((sum, i) => sum + content[i], 0) + gap * (len - 1);
|
|
3937
|
+
const grow = range.filter(byContent);
|
|
3938
|
+
if (sizes[k] > have && grow.length > 0) {
|
|
3939
|
+
const extra = (sizes[k] - have) / grow.length;
|
|
3940
|
+
for (const i of grow) content[i] += extra;
|
|
3941
|
+
}
|
|
3942
|
+
});
|
|
3943
|
+
return content;
|
|
3944
|
+
}
|
|
3945
|
+
function trackRanges(start, sizes, gap) {
|
|
3946
|
+
let x = start;
|
|
3947
|
+
return sizes.map((size) => {
|
|
3948
|
+
const r = [x, x + size];
|
|
3949
|
+
x += size + gap;
|
|
3950
|
+
return r;
|
|
3951
|
+
});
|
|
3952
|
+
}
|
|
3953
|
+
function gridGeometryOf(s, frame) {
|
|
3954
|
+
const f = s.boxes.get(frame);
|
|
3955
|
+
const al = f && getAutoLayout(f.node);
|
|
3956
|
+
if (!f || !al || al.mode !== "grid") return void 0;
|
|
3957
|
+
const [pt, pr, pb, pl] = resolvePadding(al.padding);
|
|
3958
|
+
const kids = flowChildren(s, frame);
|
|
3959
|
+
const { cells, rows } = gridPlace(s, al, kids);
|
|
3960
|
+
const colSpec = trackList(al.grid?.columns, 2);
|
|
3961
|
+
const rowSpec = trackList(al.grid?.rows, 1);
|
|
3962
|
+
const cols = colSpec.count;
|
|
3963
|
+
const gx = Math.max(finite(al.gap), 0);
|
|
3964
|
+
const gy = Math.max(al.rowGap !== void 0 ? finite(al.rowGap) : gx, 0);
|
|
3965
|
+
const hugW = getLayoutSizing(f.node, "width") === "hug";
|
|
3966
|
+
const hugH = getLayoutSizing(f.node, "height") === "hug";
|
|
3967
|
+
const ws = [];
|
|
3968
|
+
const hs = [];
|
|
3969
|
+
for (const c of cells) {
|
|
3970
|
+
const b = s.boxes.get(c.id);
|
|
3971
|
+
const lim2 = limitsOf(b.node);
|
|
3972
|
+
ws.push(getLayoutSizing(b.node, "width") === "fill" && !hugW ? lim2.minW ?? 0 : b.w);
|
|
3973
|
+
hs.push(getLayoutSizing(b.node, "height") === "fill" && !hugH ? lim2.minH ?? 0 : b.h);
|
|
3974
|
+
}
|
|
3975
|
+
const colContent = trackContent(cells, ws, colSpec.tracks, cols, gx, true, hugW);
|
|
3976
|
+
const rowContent = trackContent(cells, hs, rowSpec.tracks, rows, gy, false, hugH);
|
|
3977
|
+
const gapsW = gx * Math.max(cols - 1, 0);
|
|
3978
|
+
const gapsH = gy * Math.max(rows - 1, 0);
|
|
3979
|
+
const colW = resolveTracks(colSpec.tracks, colContent, hugW ? void 0 : finite(f.w) - pl - pr - gapsW);
|
|
3980
|
+
const rowH = resolveTracks(rowSpec.tracks, rowContent, hugH ? void 0 : finite(f.h) - pt - pb - gapsH);
|
|
3981
|
+
const lim = limitsOf(f.node);
|
|
3982
|
+
const width = hugW ? colW.reduce((a, b) => a + b, 0) + gapsW + pl + pr : finite(f.w);
|
|
3983
|
+
const height = hugH ? rowH.reduce((a, b) => a + b, 0) + gapsH + pt + pb : finite(f.h);
|
|
3984
|
+
return {
|
|
3985
|
+
columns: trackRanges(pl, colW, gx),
|
|
3986
|
+
rows: trackRanges(pt, rowH, gy),
|
|
3987
|
+
cells,
|
|
3988
|
+
width: Math.max(clampLayoutSize(width, lim.minW, lim.maxW), pl + pr),
|
|
3989
|
+
height: Math.max(clampLayoutSize(height, lim.minH, lim.maxH), pt + pb)
|
|
3990
|
+
};
|
|
3991
|
+
}
|
|
3992
|
+
function layoutGrid(s, frame, al) {
|
|
3993
|
+
const f = s.boxes.get(frame);
|
|
3994
|
+
const fw = f.w;
|
|
3995
|
+
const fh = f.h;
|
|
3996
|
+
const hugW = getLayoutSizing(f.node, "width") === "hug";
|
|
3997
|
+
const hugH = getLayoutSizing(f.node, "height") === "hug";
|
|
3998
|
+
const lim = limitsOf(f.node);
|
|
3999
|
+
const [pt, pr, pb, pl] = resolvePadding(al.padding);
|
|
4000
|
+
setSize(
|
|
4001
|
+
s,
|
|
4002
|
+
frame,
|
|
4003
|
+
hugW ? fw : Math.max(clampLayoutSize(fw, lim.minW, lim.maxW), pl + pr),
|
|
4004
|
+
hugH ? fh : Math.max(clampLayoutSize(fh, lim.minH, lim.maxH), pt + pb)
|
|
4005
|
+
);
|
|
4006
|
+
let g = gridGeometryOf(s, frame);
|
|
4007
|
+
if (!g) return;
|
|
4008
|
+
let widened = false;
|
|
4009
|
+
for (const c of g.cells) {
|
|
4010
|
+
const b = s.boxes.get(c.id);
|
|
4011
|
+
if (getLayoutSizing(b.node, "width") === "fill" && !hugW) {
|
|
4012
|
+
const l = limitsOf(b.node);
|
|
4013
|
+
resizeChild(s, c.id, clampLayoutSize(cellRect(g, c).width, l.minW, l.maxW), b.h);
|
|
4014
|
+
widened = true;
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
if (widened) g = gridGeometryOf(s, frame) ?? g;
|
|
4018
|
+
setSize(s, frame, g.width, g.height);
|
|
4019
|
+
constrain(s, frame, fw, fh);
|
|
4020
|
+
const frameX = al.alignMain === "center" ? "center" : al.alignMain === "end" ? "end" : "start";
|
|
4021
|
+
const frameY = al.alignCross === "center" ? "center" : al.alignCross === "end" ? "end" : "start";
|
|
4022
|
+
const offset = (a, free) => a === "center" ? free / 2 : a === "end" ? free : 0;
|
|
4023
|
+
for (const c of g.cells) {
|
|
4024
|
+
const cell = cellRect(g, c);
|
|
4025
|
+
const b = s.boxes.get(c.id);
|
|
4026
|
+
const l = limitsOf(b.node);
|
|
4027
|
+
const area = getChildLayout(b.node).gridArea ?? {};
|
|
4028
|
+
const fillW = getLayoutSizing(b.node, "width") === "fill" && !hugW;
|
|
4029
|
+
const fillH = getLayoutSizing(b.node, "height") === "fill" && !hugH;
|
|
4030
|
+
if (fillW || fillH) {
|
|
4031
|
+
resizeChild(
|
|
4032
|
+
s,
|
|
4033
|
+
c.id,
|
|
4034
|
+
fillW ? clampLayoutSize(cell.width, l.minW, l.maxW) : b.w,
|
|
4035
|
+
fillH ? clampLayoutSize(cell.height, l.minH, l.maxH) : b.h
|
|
4036
|
+
);
|
|
4037
|
+
}
|
|
4038
|
+
const ox = offset(area.alignX ?? frameX, cell.width - b.w);
|
|
4039
|
+
const oy = offset(area.alignY ?? frameY, cell.height - b.h);
|
|
4040
|
+
place(s, c.id, finite(cell.x + ox), finite(cell.y + oy));
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
4043
|
+
function constrain(s, id, ow, oh) {
|
|
4044
|
+
const f = s.boxes.get(id);
|
|
4045
|
+
if (!f) return;
|
|
4046
|
+
const nw = f.w;
|
|
4047
|
+
const nh = f.h;
|
|
4048
|
+
if (Math.abs(nw - ow) < 1e-9 && Math.abs(nh - oh) < 1e-9) return;
|
|
4049
|
+
const absoluteOnly = !!getAutoLayout(f.node);
|
|
4050
|
+
const sx = ow > 1e-9 ? nw / ow : 1;
|
|
4051
|
+
const sy = oh > 1e-9 ? nh / oh : 1;
|
|
4052
|
+
s.guard(`constrain:${id}`, () => {
|
|
4053
|
+
for (const k of f.kids) {
|
|
4054
|
+
const c = s.boxes.get(k);
|
|
4055
|
+
const child = getChildLayout(c.node);
|
|
4056
|
+
if (absoluteOnly && !child.absolute) continue;
|
|
4057
|
+
let x0 = c.x;
|
|
4058
|
+
let x1 = c.x + c.w;
|
|
4059
|
+
let y0 = c.y;
|
|
4060
|
+
let y1 = c.y + c.h;
|
|
4061
|
+
const dx = nw - ow;
|
|
4062
|
+
const dy = nh - oh;
|
|
4063
|
+
switch (child.constraints?.horizontal ?? "left") {
|
|
4064
|
+
case "right":
|
|
4065
|
+
x0 += dx;
|
|
4066
|
+
x1 += dx;
|
|
4067
|
+
break;
|
|
4068
|
+
case "leftRight":
|
|
4069
|
+
x1 += dx;
|
|
4070
|
+
break;
|
|
4071
|
+
case "center":
|
|
4072
|
+
x0 += dx / 2;
|
|
4073
|
+
x1 += dx / 2;
|
|
4074
|
+
break;
|
|
4075
|
+
case "scale":
|
|
4076
|
+
x0 *= sx;
|
|
4077
|
+
x1 *= sx;
|
|
4078
|
+
break;
|
|
4079
|
+
}
|
|
4080
|
+
switch (child.constraints?.vertical ?? "top") {
|
|
4081
|
+
case "bottom":
|
|
4082
|
+
y0 += dy;
|
|
4083
|
+
y1 += dy;
|
|
4084
|
+
break;
|
|
4085
|
+
case "topBottom":
|
|
4086
|
+
y1 += dy;
|
|
4087
|
+
break;
|
|
4088
|
+
case "center":
|
|
4089
|
+
y0 += dy / 2;
|
|
4090
|
+
y1 += dy / 2;
|
|
4091
|
+
break;
|
|
4092
|
+
case "scale":
|
|
4093
|
+
y0 *= sy;
|
|
4094
|
+
y1 *= sy;
|
|
4095
|
+
break;
|
|
4096
|
+
}
|
|
4097
|
+
const cw = c.w;
|
|
4098
|
+
const ch = c.h;
|
|
4099
|
+
const resized = Math.abs(x1 - x0 - cw) > 1e-9 || Math.abs(y1 - y0 - ch) > 1e-9;
|
|
4100
|
+
place(s, k, finite(x0), finite(y0));
|
|
4101
|
+
if (resized) {
|
|
4102
|
+
setSize(s, k, x1 - x0, y1 - y0);
|
|
4103
|
+
if (c.kids.length > 0) constrain(s, k, cw, ch);
|
|
4104
|
+
if (getAutoLayout(c.node)) layout(s, k);
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
});
|
|
4108
|
+
}
|
|
4109
|
+
function layoutFrame(nodes, frameId, options = {}) {
|
|
4110
|
+
const s = new LayoutState(nodes, options);
|
|
4111
|
+
layout(s, frameId);
|
|
4112
|
+
return s.updates();
|
|
4113
|
+
}
|
|
4114
|
+
function postOrder(s, nodes) {
|
|
4115
|
+
const out = [];
|
|
4116
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4117
|
+
const visit = (id) => {
|
|
4118
|
+
if (seen.has(id)) return;
|
|
4119
|
+
seen.add(id);
|
|
4120
|
+
for (const k of s.boxes.get(id)?.kids ?? []) visit(k);
|
|
4121
|
+
out.push(id);
|
|
4122
|
+
};
|
|
4123
|
+
const roots = nodes.filter((n) => !n.parentId || !s.boxes.has(n.parentId));
|
|
4124
|
+
for (const r of roots) visit(r.id);
|
|
4125
|
+
for (const n of nodes) visit(n.id);
|
|
4126
|
+
return out;
|
|
4127
|
+
}
|
|
4128
|
+
function layoutAll(nodes, options = {}) {
|
|
4129
|
+
const s = new LayoutState(nodes, options);
|
|
4130
|
+
for (const id of postOrder(s, nodes)) if (getAutoLayout(s.boxes.get(id).node)) layout(s, id);
|
|
4131
|
+
return s.updates();
|
|
4132
|
+
}
|
|
4133
|
+
function layoutUp(nodes, changedId, options = {}) {
|
|
4134
|
+
return layoutUpMany(nodes, [changedId], options);
|
|
4135
|
+
}
|
|
4136
|
+
function layoutUpMany(nodes, changedIds, options = {}) {
|
|
4137
|
+
const s = new LayoutState(nodes, options);
|
|
4138
|
+
const chains = [...new Set(changedIds)].filter((id) => s.boxes.has(id)).map((id) => [id, ...s.ancestors(id)]);
|
|
4139
|
+
const depth = /* @__PURE__ */ new Map();
|
|
4140
|
+
for (const chain of chains) chain.forEach((id, i) => depth.set(id, Math.max(depth.get(id) ?? 0, chain.length - 1 - i)));
|
|
4141
|
+
const order = [...depth.keys()].sort((a, b) => depth.get(b) - depth.get(a));
|
|
4142
|
+
for (const id of order) if (getAutoLayout(s.boxes.get(id).node)) layout(s, id);
|
|
4143
|
+
return s.updates();
|
|
4144
|
+
}
|
|
4145
|
+
function applyConstraints(nodes, parentId, previousSize, options = {}) {
|
|
4146
|
+
const s = new LayoutState(nodes, options);
|
|
4147
|
+
constrain(s, parentId, previousSize.width, previousSize.height);
|
|
4148
|
+
return s.updates();
|
|
4149
|
+
}
|
|
4150
|
+
function getAutoLayoutGrid(nodes, frameId, options = {}) {
|
|
4151
|
+
return gridGeometryOf(new LayoutState(nodes, options), frameId);
|
|
4152
|
+
}
|
|
4153
|
+
function getFlowChildren(nodes, frameId) {
|
|
4154
|
+
return nodes.filter((n) => n.parentId === frameId && n.id !== frameId && n.hidden !== true && !getChildLayout(n).absolute).map((n) => n.id);
|
|
4155
|
+
}
|
|
4156
|
+
function getLayoutParent(nodes, id) {
|
|
4157
|
+
const lookup = createNodeLookup(nodes);
|
|
4158
|
+
const node = lookup.get(id);
|
|
4159
|
+
if (!node?.parentId || getChildLayout(node).absolute) return void 0;
|
|
4160
|
+
const parent = lookup.get(node.parentId);
|
|
4161
|
+
return isAutoLayoutFrame(parent) ? parent : void 0;
|
|
4162
|
+
}
|
|
4163
|
+
function makeSizingCoherent(nodes, id, options = {}) {
|
|
4164
|
+
const lookup = createNodeLookup(nodes);
|
|
4165
|
+
const targets = /* @__PURE__ */ new Set([id, ...nodes.filter((n) => n.parentId === id).map((n) => n.id)]);
|
|
4166
|
+
if (!lookup.has(id)) return nodes;
|
|
4167
|
+
let changed = false;
|
|
4168
|
+
const next = nodes.map((node) => {
|
|
4169
|
+
if (!targets.has(node.id)) return node;
|
|
4170
|
+
const parent = node.parentId ? lookup.get(node.parentId) : void 0;
|
|
4171
|
+
const flowParent = parent && isAutoLayoutFrame(parent) && !getChildLayout(node).absolute ? parent : void 0;
|
|
4172
|
+
const canHug = isAutoLayoutFrame(node) || options.measure?.textSize?.(node) !== void 0;
|
|
4173
|
+
const coherent = (axis) => {
|
|
4174
|
+
const sizing = getLayoutSizing(node, axis);
|
|
4175
|
+
if (sizing === "fill" && (!flowParent || getLayoutSizing(flowParent, axis) === "hug")) return "fixed";
|
|
4176
|
+
if (sizing === "hug" && !canHug) return "fixed";
|
|
4177
|
+
return sizing;
|
|
4178
|
+
};
|
|
4179
|
+
const width = coherent("width");
|
|
4180
|
+
const height = coherent("height");
|
|
4181
|
+
if (width === getLayoutSizing(node, "width") && height === getLayoutSizing(node, "height")) return node;
|
|
4182
|
+
changed = true;
|
|
4183
|
+
const child = getChildLayout(node);
|
|
4184
|
+
return {
|
|
4185
|
+
...node,
|
|
4186
|
+
data: { ...node.data, [CHILD_LAYOUT_DATA_KEY]: { ...child, sizing: { ...child.sizing, width, height } } }
|
|
4187
|
+
};
|
|
4188
|
+
});
|
|
4189
|
+
return changed ? next : nodes;
|
|
4190
|
+
}
|
|
4191
|
+
function getAutoLayoutInsertTarget(nodes, frameId, point, options = {}) {
|
|
4192
|
+
const lookup = createNodeLookup(nodes);
|
|
4193
|
+
const frame = lookup.get(frameId);
|
|
4194
|
+
const al = getAutoLayout(frame);
|
|
4195
|
+
if (!frame || !al) return void 0;
|
|
4196
|
+
const s = new LayoutState(nodes, options);
|
|
4197
|
+
const origin = getAbsolutePosition(frame, lookup);
|
|
4198
|
+
const px = point.x - origin.x;
|
|
4199
|
+
const py = point.y - origin.y;
|
|
4200
|
+
const siblings = flowChildren(s, frameId).filter((id) => id !== options.excludeId).map((id) => s.boxes.get(id));
|
|
4201
|
+
const horizontal = al.mode !== "vertical";
|
|
4202
|
+
const main = (b) => horizontal ? b.x : b.y;
|
|
4203
|
+
const mainSize = (b) => horizontal ? b.w : b.h;
|
|
4204
|
+
const cross = (b) => horizontal ? b.y : b.x;
|
|
4205
|
+
const crossSize = (b) => horizontal ? b.h : b.w;
|
|
4206
|
+
const p = { x: px, y: py };
|
|
4207
|
+
const multiLine = al.mode === "grid" || !!al.wrap;
|
|
4208
|
+
let index = 0;
|
|
4209
|
+
for (const b of siblings) {
|
|
4210
|
+
const before = multiLine ? cross(b) + crossSize(b) <= cross(p) || cross(b) <= cross(p) && main(b) + mainSize(b) / 2 < main(p) : main(b) + mainSize(b) / 2 < main(p);
|
|
4211
|
+
if (before) index += 1;
|
|
4212
|
+
}
|
|
4213
|
+
const [pt, pr, pb, pl] = resolvePadding(al.padding);
|
|
4214
|
+
const prev = siblings[index - 1];
|
|
4215
|
+
const next = siblings[index];
|
|
4216
|
+
const f = s.boxes.get(frameId);
|
|
4217
|
+
let guide;
|
|
4218
|
+
if (horizontal) {
|
|
4219
|
+
const x = prev && next && Math.abs(cross(prev) - cross(next)) < 1e-6 ? (prev.x + prev.w + next.x) / 2 : prev ? prev.x + prev.w : next ? next.x : pl;
|
|
4220
|
+
const ref = next ?? prev;
|
|
4221
|
+
const y1 = ref ? ref.y : pt;
|
|
4222
|
+
const y2 = ref ? ref.y + ref.h : f.h - pb;
|
|
4223
|
+
guide = { orientation: "vertical", kind: "edge", x1: origin.x + x, y1: origin.y + y1, x2: origin.x + x, y2: origin.y + y2 };
|
|
4224
|
+
} else {
|
|
4225
|
+
const y = prev && next && Math.abs(cross(prev) - cross(next)) < 1e-6 ? (prev.y + prev.h + next.y) / 2 : prev ? prev.y + prev.h : next ? next.y : pt;
|
|
4226
|
+
const ref = next ?? prev;
|
|
4227
|
+
const x1 = ref ? ref.x : pl;
|
|
4228
|
+
const x2 = ref ? ref.x + ref.w : f.w - pr;
|
|
4229
|
+
guide = { orientation: "horizontal", kind: "edge", x1: origin.x + x1, y1: origin.y + y, x2: origin.x + x2, y2: origin.y + y };
|
|
4230
|
+
}
|
|
4231
|
+
return { frameId, index, guide };
|
|
4232
|
+
}
|
|
4233
|
+
function moveLayoutChild(nodes, childId, index) {
|
|
4234
|
+
const child = nodes.find((n) => n.id === childId);
|
|
4235
|
+
if (!child?.parentId) return nodes;
|
|
4236
|
+
const siblings = nodes.filter((n) => n.parentId === child.parentId && n.id !== child.parentId);
|
|
4237
|
+
const flow = siblings.filter((n) => n.hidden !== true && !getChildLayout(n).absolute && n.id !== childId);
|
|
4238
|
+
const clamped = Math.min(Math.max(Math.floor(Number.isFinite(index) ? index : 0), 0), flow.length);
|
|
4239
|
+
const order = siblings.filter((n) => n.id !== childId);
|
|
4240
|
+
const anchor = flow[clamped];
|
|
4241
|
+
const at = anchor ? order.indexOf(anchor) : flow.length > 0 ? order.indexOf(flow[flow.length - 1]) + 1 : order.length;
|
|
4242
|
+
order.splice(at, 0, child);
|
|
4243
|
+
if (order.every((n, i) => n === siblings[i])) return nodes;
|
|
4244
|
+
let k = 0;
|
|
4245
|
+
const parentId = child.parentId;
|
|
4246
|
+
const placed = nodes.map((n) => n.parentId === parentId && n.id !== parentId ? order[k++] : n);
|
|
4247
|
+
return parentsFirst(placed);
|
|
4248
|
+
}
|
|
4249
|
+
function parentsFirst(nodes) {
|
|
4250
|
+
const ids = new Set(nodes.map((n) => n.id));
|
|
4251
|
+
const pending = /* @__PURE__ */ new Map();
|
|
4252
|
+
const done = /* @__PURE__ */ new Set();
|
|
4253
|
+
const out = [];
|
|
4254
|
+
const emit = (n) => {
|
|
4255
|
+
out.push(n);
|
|
4256
|
+
done.add(n.id);
|
|
4257
|
+
const waiting = pending.get(n.id);
|
|
4258
|
+
if (waiting) {
|
|
4259
|
+
pending.delete(n.id);
|
|
4260
|
+
for (const w of waiting) emit(w);
|
|
4261
|
+
}
|
|
4262
|
+
};
|
|
4263
|
+
for (const n of nodes) {
|
|
4264
|
+
if (n.parentId && ids.has(n.parentId) && !done.has(n.parentId) && n.parentId !== n.id) {
|
|
4265
|
+
if (!pending.has(n.parentId)) pending.set(n.parentId, []);
|
|
4266
|
+
pending.get(n.parentId).push(n);
|
|
4267
|
+
} else emit(n);
|
|
4268
|
+
}
|
|
4269
|
+
for (const waiting of pending.values()) for (const n of waiting) if (!done.has(n.id)) emit(n);
|
|
4270
|
+
return out;
|
|
4271
|
+
}
|
|
4272
|
+
|
|
3391
4273
|
// src/canvas/arrangeController.ts
|
|
3392
4274
|
function createCanvasArrangeController(options) {
|
|
3393
4275
|
let guides = [];
|
|
@@ -3406,6 +4288,16 @@ function createCanvasArrangeController(options) {
|
|
|
3406
4288
|
};
|
|
3407
4289
|
function apply(name, updates) {
|
|
3408
4290
|
if (updates.length === 0) return updates;
|
|
4291
|
+
if (options.autoLayout) {
|
|
4292
|
+
const layoutOptions = options.autoLayout === true ? { rectOptions: options.rectOptions } : options.autoLayout;
|
|
4293
|
+
const moved = applyNodeUpdates(options.getNodes(), updates);
|
|
4294
|
+
const layout2 = layoutUpMany(moved, updates.map((u) => u.id), layoutOptions);
|
|
4295
|
+
if (layout2.length > 0) {
|
|
4296
|
+
const byId = /* @__PURE__ */ new Map();
|
|
4297
|
+
for (const u of [...updates, ...layout2]) byId.set(u.id, { ...byId.get(u.id), ...u });
|
|
4298
|
+
updates = [...byId.values()];
|
|
4299
|
+
}
|
|
4300
|
+
}
|
|
3409
4301
|
const inverse = invertNodeUpdates(options.getNodes(), updates);
|
|
3410
4302
|
const run = (u) => options.setNodes(applyNodeUpdates(options.getNodes(), u));
|
|
3411
4303
|
if (options.history) {
|
|
@@ -3784,7 +4676,7 @@ function createCanvasArrangeController(options) {
|
|
|
3784
4676
|
}
|
|
3785
4677
|
|
|
3786
4678
|
// src/canvas/measure.ts
|
|
3787
|
-
var
|
|
4679
|
+
var EPS2 = 1e-6;
|
|
3788
4680
|
function measureLabel(distance) {
|
|
3789
4681
|
const v = Math.round(Math.abs(distance) * 100) / 100;
|
|
3790
4682
|
return Object.is(v, -0) ? "0" : String(v);
|
|
@@ -3796,13 +4688,13 @@ function line(kind, x1, y1, x2, y2) {
|
|
|
3796
4688
|
}
|
|
3797
4689
|
function measured(out, x1, y1, x2, y2) {
|
|
3798
4690
|
const d = Math.hypot(x2 - x1, y2 - y1);
|
|
3799
|
-
if (d >
|
|
4691
|
+
if (d > EPS2 && Number.isFinite(d)) out.push({ ...line("measure", x1, y1, x2, y2), label: measureLabel(d) });
|
|
3800
4692
|
}
|
|
3801
4693
|
function extension(out, x1, y1, x2, y2) {
|
|
3802
|
-
if (Math.hypot(x2 - x1, y2 - y1) >
|
|
4694
|
+
if (Math.hypot(x2 - x1, y2 - y1) > EPS2) out.push(line("extension", x1, y1, x2, y2));
|
|
3803
4695
|
}
|
|
3804
4696
|
function contains(outer, inner) {
|
|
3805
|
-
return outer.x0 <= inner.x0 +
|
|
4697
|
+
return outer.x0 <= inner.x0 + EPS2 && outer.y0 <= inner.y0 + EPS2 && outer.x1 >= inner.x1 - EPS2 && outer.y1 >= inner.y1 - EPS2;
|
|
3806
4698
|
}
|
|
3807
4699
|
function overlapMid(a0, a1, b0, b1) {
|
|
3808
4700
|
const lo = Math.max(a0, b0);
|
|
@@ -3899,7 +4791,288 @@ function isMeasureModifierHeld(event) {
|
|
|
3899
4791
|
if (event.type === "keyup" && event.key === "Alt") return false;
|
|
3900
4792
|
return event.altKey === true || event.type === "keydown" && event.key === "Alt";
|
|
3901
4793
|
}
|
|
4794
|
+
|
|
4795
|
+
// src/canvas/autoLayoutController.ts
|
|
4796
|
+
function mergeNodeUpdates(...lists) {
|
|
4797
|
+
const byId = /* @__PURE__ */ new Map();
|
|
4798
|
+
for (const list of lists) for (const u of list) byId.set(u.id, { ...byId.get(u.id), ...u });
|
|
4799
|
+
return [...byId.values()];
|
|
4800
|
+
}
|
|
4801
|
+
function relayoutUpdates(nodes, ids, options = {}) {
|
|
4802
|
+
return layoutUpMany(nodes, ids, options);
|
|
4803
|
+
}
|
|
4804
|
+
function createCanvasAutoLayoutController(options) {
|
|
4805
|
+
const layoutOptions = () => ({ measure: options.measure, rectOptions: options.rectOptions });
|
|
4806
|
+
const enabled = () => options.enabled !== false;
|
|
4807
|
+
const pendingIds = /* @__PURE__ */ new Set();
|
|
4808
|
+
const pendingResizes = /* @__PURE__ */ new Map();
|
|
4809
|
+
const resizeStarts = /* @__PURE__ */ new Map();
|
|
4810
|
+
let pendingAll = false;
|
|
4811
|
+
const dragStarts = /* @__PURE__ */ new Map();
|
|
4812
|
+
const pendingDrops = /* @__PURE__ */ new Set();
|
|
4813
|
+
let guides = [];
|
|
4814
|
+
const setGuides = (next) => {
|
|
4815
|
+
if (next.length === 0 && guides.length === 0) return;
|
|
4816
|
+
guides = next;
|
|
4817
|
+
options.onGuidesChange?.(guides);
|
|
4818
|
+
};
|
|
4819
|
+
function run(name, forward, backward, ids, extra = [], restore) {
|
|
4820
|
+
const before = options.getNodes();
|
|
4821
|
+
const structural = forward(before);
|
|
4822
|
+
const withExtra = applyNodeUpdates(structural, extra);
|
|
4823
|
+
const layout2 = enabled() || name === "Auto Layout" ? relayoutUpdates(withExtra, ids(withExtra), layoutOptions()) : [];
|
|
4824
|
+
const updates = mergeNodeUpdates(extra, layout2);
|
|
4825
|
+
if (structural === before && updates.length === 0) return updates;
|
|
4826
|
+
let inverse = invertNodeUpdates(structural, updates);
|
|
4827
|
+
if (restore) {
|
|
4828
|
+
inverse = mergeNodeUpdates(inverse, [{ id: restore.id, position: { ...restore.position } }]);
|
|
4829
|
+
}
|
|
4830
|
+
const execute = () => options.setNodes(applyNodeUpdates(forward(options.getNodes()), updates));
|
|
4831
|
+
const undo = () => options.setNodes(backward(applyNodeUpdates(options.getNodes(), inverse)));
|
|
4832
|
+
if (options.history) options.history.execute({ name, execute, undo });
|
|
4833
|
+
else execute();
|
|
4834
|
+
return updates;
|
|
4835
|
+
}
|
|
4836
|
+
const identity = (nodes) => nodes;
|
|
4837
|
+
const controller = {
|
|
4838
|
+
/** Drop marker of the active reorder drag (flow coordinates); empty otherwise. */
|
|
4839
|
+
get guides() {
|
|
4840
|
+
return guides;
|
|
4841
|
+
},
|
|
4842
|
+
/**
|
|
4843
|
+
* Lays out frame `frameId` and its auto layout ancestors (default: every frame) as one
|
|
4844
|
+
* (optionally undoable) step. Returns the updates.
|
|
4845
|
+
*/
|
|
4846
|
+
applyAutoLayout(frameId) {
|
|
4847
|
+
if (frameId === void 0) {
|
|
4848
|
+
const updates = layoutAll(options.getNodes(), layoutOptions());
|
|
4849
|
+
return run("Auto Layout", identity, identity, () => [], updates);
|
|
4850
|
+
}
|
|
4851
|
+
return run("Auto Layout", identity, identity, () => [frameId]);
|
|
4852
|
+
},
|
|
4853
|
+
/** Updates that relayout around `ids` on the current nodes, without applying them. */
|
|
4854
|
+
layoutUpdates(ids) {
|
|
4855
|
+
return relayoutUpdates(options.getNodes(), ids, layoutOptions());
|
|
4856
|
+
},
|
|
4857
|
+
/**
|
|
4858
|
+
* Applies the relayout around `ids` (frames, or nodes inside frames) directly, not
|
|
4859
|
+
* recorded in history: auto layout is derived state, re-run after any change.
|
|
4860
|
+
*/
|
|
4861
|
+
relayout(ids) {
|
|
4862
|
+
const updates = relayoutUpdates(options.getNodes(), ids, layoutOptions());
|
|
4863
|
+
if (updates.length > 0) options.setNodes(applyNodeUpdates(options.getNodes(), updates));
|
|
4864
|
+
return updates;
|
|
4865
|
+
},
|
|
4866
|
+
/**
|
|
4867
|
+
* Adds `node` (into the frame named by its `parentId`, at flow `index` when given) and
|
|
4868
|
+
* lays out its frame, as one step.
|
|
4869
|
+
*/
|
|
4870
|
+
addNode(node, addOptions = {}) {
|
|
4871
|
+
const forward = (nodes) => {
|
|
4872
|
+
if (nodes.some((n) => n.id === node.id)) return nodes;
|
|
4873
|
+
let next = [...nodes, node];
|
|
4874
|
+
if (addOptions.index !== void 0 && node.parentId) next = moveLayoutChild(next, node.id, addOptions.index);
|
|
4875
|
+
return next;
|
|
4876
|
+
};
|
|
4877
|
+
const backward = (nodes) => nodes.filter((n) => n.id !== node.id);
|
|
4878
|
+
return run("Add Node", forward, backward, () => [node.id]);
|
|
4879
|
+
},
|
|
4880
|
+
/** Removes nodes (and their descendants) and lays out the frames they leave, as one step. */
|
|
4881
|
+
removeNodes(ids) {
|
|
4882
|
+
const before = options.getNodes();
|
|
4883
|
+
const remove = new Set(ids);
|
|
4884
|
+
let grew = true;
|
|
4885
|
+
while (grew) {
|
|
4886
|
+
grew = false;
|
|
4887
|
+
for (const n of before) {
|
|
4888
|
+
if (n.parentId && remove.has(n.parentId) && !remove.has(n.id)) {
|
|
4889
|
+
remove.add(n.id);
|
|
4890
|
+
grew = true;
|
|
4891
|
+
}
|
|
4892
|
+
}
|
|
4893
|
+
}
|
|
4894
|
+
const removed = before.map((n, i) => [i, n]).filter(([, n]) => remove.has(n.id));
|
|
4895
|
+
if (removed.length === 0) return [];
|
|
4896
|
+
const parents = [...new Set(removed.map(([, n]) => n.parentId).filter((p) => !!p && !remove.has(p)))];
|
|
4897
|
+
const forward = (nodes) => nodes.filter((n) => !remove.has(n.id));
|
|
4898
|
+
const backward = (nodes) => {
|
|
4899
|
+
const next = [...nodes];
|
|
4900
|
+
for (const [i, n] of removed) next.splice(Math.min(i, next.length), 0, n);
|
|
4901
|
+
return next;
|
|
4902
|
+
};
|
|
4903
|
+
return run("Delete", forward, backward, () => parents);
|
|
4904
|
+
},
|
|
4905
|
+
/**
|
|
4906
|
+
* Resizes node `id` (its children follow their constraints) and lays out around it,
|
|
4907
|
+
* as one step.
|
|
4908
|
+
*/
|
|
4909
|
+
resizeNode(id, size) {
|
|
4910
|
+
const nodes = options.getNodes();
|
|
4911
|
+
const node = nodes.find((n) => n.id === id);
|
|
4912
|
+
if (!node) return [];
|
|
4913
|
+
const old = getNodeSize(node, options.rectOptions);
|
|
4914
|
+
const update = { id };
|
|
4915
|
+
if (size.width !== void 0) update.width = size.width;
|
|
4916
|
+
if (size.height !== void 0) update.height = size.height;
|
|
4917
|
+
const resized = applyNodeUpdates(nodes, [update]);
|
|
4918
|
+
const constrained = mergeNodeUpdates([update], applyConstraints(resized, id, old, layoutOptions()));
|
|
4919
|
+
return run("Resize", identity, identity, () => [id], constrained);
|
|
4920
|
+
},
|
|
4921
|
+
/** Moves flow child `childId` to flow index `index` in its frame and lays it out, as one step. */
|
|
4922
|
+
moveChild(childId, index) {
|
|
4923
|
+
const before = options.getNodes();
|
|
4924
|
+
const order = before.map((n) => n.id);
|
|
4925
|
+
const forward = (nodes) => moveLayoutChild(nodes, childId, index);
|
|
4926
|
+
const backward = (nodes) => restoreOrder(nodes, order);
|
|
4927
|
+
if (forward(before) === before) return [];
|
|
4928
|
+
return run("Reorder", forward, backward, () => [childId]);
|
|
4929
|
+
},
|
|
4930
|
+
/** Where flow child `id` would drop if released at `point` (default: its centre). */
|
|
4931
|
+
getInsertTarget(id, point) {
|
|
4932
|
+
const nodes = options.getNodes();
|
|
4933
|
+
const frame = getLayoutParent(nodes, id);
|
|
4934
|
+
if (!frame) return void 0;
|
|
4935
|
+
const lookup = createNodeLookup(nodes);
|
|
4936
|
+
const rect = getNodeRect(lookup.get(id), lookup, options.rectOptions);
|
|
4937
|
+
const at = point ?? { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };
|
|
4938
|
+
return getAutoLayoutInsertTarget(nodes, frame.id, at, { ...layoutOptions(), excludeId: id });
|
|
4939
|
+
},
|
|
4940
|
+
/** Records the start position of a reorder drag. Optional: `dragReorder` records it lazily. */
|
|
4941
|
+
beginReorderDrag(id) {
|
|
4942
|
+
const node = options.getNodes().find((n) => n.id === id);
|
|
4943
|
+
if (node && getLayoutParent(options.getNodes(), id)) dragStarts.set(id, { ...node.position });
|
|
4944
|
+
},
|
|
4945
|
+
/**
|
|
4946
|
+
* While flow child `id` is dragged (as currently positioned in `getNodes()`): updates the
|
|
4947
|
+
* drop marker. Returns the insert target.
|
|
4948
|
+
*/
|
|
4949
|
+
dragReorder(id, point) {
|
|
4950
|
+
if (options.dragReorder === false) return void 0;
|
|
4951
|
+
if (!dragStarts.has(id)) controller.beginReorderDrag(id);
|
|
4952
|
+
const target = controller.getInsertTarget(id, point);
|
|
4953
|
+
setGuides(target ? [target.guide] : []);
|
|
4954
|
+
return target;
|
|
4955
|
+
},
|
|
4956
|
+
/**
|
|
4957
|
+
* Ends a reorder drag: moves `id` to the slot under `point` (default: its centre) and lays
|
|
4958
|
+
* the frame out, as one undoable step whose undo puts the node back where the drag began.
|
|
4959
|
+
*/
|
|
4960
|
+
endReorderDrag(id, point) {
|
|
4961
|
+
setGuides([]);
|
|
4962
|
+
const start = dragStarts.get(id);
|
|
4963
|
+
dragStarts.delete(id);
|
|
4964
|
+
if (options.dragReorder === false || !getLayoutParent(options.getNodes(), id)) return [];
|
|
4965
|
+
const target = controller.getInsertTarget(id, point);
|
|
4966
|
+
if (!target) return [];
|
|
4967
|
+
const before = options.getNodes();
|
|
4968
|
+
const order = before.map((n) => n.id);
|
|
4969
|
+
const forward = (nodes) => moveLayoutChild(nodes, id, target.index);
|
|
4970
|
+
const backward = (nodes) => restoreOrder(nodes, order);
|
|
4971
|
+
return run("Reorder", forward, backward, () => [id], [], start && { id, position: start });
|
|
4972
|
+
},
|
|
4973
|
+
/**
|
|
4974
|
+
* Notes a batch of React Flow / SvelteFlow style node changes (before or after they are
|
|
4975
|
+
* applied) so `flush` can relayout: dimension changes (measured sizes, resize ends),
|
|
4976
|
+
* added and removed nodes, and position changes of flow children (reorder drags).
|
|
4977
|
+
* Returns the changes unchanged.
|
|
4978
|
+
*/
|
|
4979
|
+
noteChanges(changes) {
|
|
4980
|
+
const nodes = options.getNodes();
|
|
4981
|
+
const lookup = createNodeLookup(nodes);
|
|
4982
|
+
for (const c of changes) {
|
|
4983
|
+
const id = c.id ?? c.item?.id;
|
|
4984
|
+
if (c.type === "add" && c.item) {
|
|
4985
|
+
pendingIds.add(c.item.id);
|
|
4986
|
+
} else if (c.type === "remove" && id) {
|
|
4987
|
+
const parent = lookup.get(id)?.parentId;
|
|
4988
|
+
if (parent) pendingIds.add(parent);
|
|
4989
|
+
else pendingAll = true;
|
|
4990
|
+
} else if (c.type === "replace" && id) {
|
|
4991
|
+
pendingIds.add(id);
|
|
4992
|
+
} else if (c.type === "dimensions" && id) {
|
|
4993
|
+
const node = lookup.get(id);
|
|
4994
|
+
if (c.resizing === true) {
|
|
4995
|
+
if (node && !resizeStarts.has(id)) resizeStarts.set(id, getNodeSize(node, options.rectOptions));
|
|
4996
|
+
continue;
|
|
4997
|
+
}
|
|
4998
|
+
const start = resizeStarts.get(id);
|
|
4999
|
+
resizeStarts.delete(id);
|
|
5000
|
+
if (start) pendingResizes.set(id, start);
|
|
5001
|
+
pendingIds.add(id);
|
|
5002
|
+
} else if (c.type === "position" && id && options.dragReorder !== false) {
|
|
5003
|
+
if (!getLayoutParent(nodes, id)) continue;
|
|
5004
|
+
if (c.dragging === true) {
|
|
5005
|
+
if (!dragStarts.has(id)) {
|
|
5006
|
+
const node = lookup.get(id);
|
|
5007
|
+
if (node) dragStarts.set(id, { ...node.position });
|
|
5008
|
+
}
|
|
5009
|
+
} else if (c.dragging === false || dragStarts.has(id)) {
|
|
5010
|
+
pendingDrops.add(id);
|
|
5011
|
+
}
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
5014
|
+
return changes;
|
|
5015
|
+
},
|
|
5016
|
+
/**
|
|
5017
|
+
* Notes nodes that were already removed (e.g. SvelteFlow's `ondelete`), so `flush`
|
|
5018
|
+
* relayouts the frames they left. The nodes must still carry their `parentId`.
|
|
5019
|
+
*/
|
|
5020
|
+
noteRemoved(removed) {
|
|
5021
|
+
const gone = /* @__PURE__ */ new Set();
|
|
5022
|
+
const list = [...removed];
|
|
5023
|
+
for (const n of list) gone.add(n.id);
|
|
5024
|
+
for (const n of list) if (n.parentId && !gone.has(n.parentId)) pendingIds.add(n.parentId);
|
|
5025
|
+
},
|
|
5026
|
+
/** Whether `noteChanges` left work for `flush`. */
|
|
5027
|
+
get hasPending() {
|
|
5028
|
+
return pendingAll || pendingIds.size > 0 || pendingResizes.size > 0 || pendingDrops.size > 0 || dragStarts.size > 0;
|
|
5029
|
+
},
|
|
5030
|
+
/**
|
|
5031
|
+
* Applies the work noted by `noteChanges` to the current nodes: drop markers while
|
|
5032
|
+
* dragging, committed reorders on drop (undoable), and a relayout (not recorded) for
|
|
5033
|
+
* size, add and remove changes. Call it once the changes are applied.
|
|
5034
|
+
*/
|
|
5035
|
+
flush() {
|
|
5036
|
+
let applied = [];
|
|
5037
|
+
for (const id of pendingDrops) applied = mergeNodeUpdates(applied, controller.endReorderDrag(id));
|
|
5038
|
+
pendingDrops.clear();
|
|
5039
|
+
for (const id of dragStarts.keys()) controller.dragReorder(id);
|
|
5040
|
+
if (!enabled()) {
|
|
5041
|
+
pendingIds.clear();
|
|
5042
|
+
pendingResizes.clear();
|
|
5043
|
+
pendingAll = false;
|
|
5044
|
+
return applied;
|
|
5045
|
+
}
|
|
5046
|
+
let nodes = options.getNodes();
|
|
5047
|
+
let updates = [];
|
|
5048
|
+
for (const [id, previous] of pendingResizes) {
|
|
5049
|
+
if (!nodes.some((n) => n.id === id)) continue;
|
|
5050
|
+
const constrained = applyConstraints(nodes, id, previous, layoutOptions());
|
|
5051
|
+
nodes = applyNodeUpdates(nodes, constrained);
|
|
5052
|
+
updates = mergeNodeUpdates(updates, constrained);
|
|
5053
|
+
}
|
|
5054
|
+
const layout2 = pendingAll ? layoutAll(nodes, layoutOptions()) : relayoutUpdates(nodes, [...pendingIds].filter((id) => nodes.some((n) => n.id === id)), layoutOptions());
|
|
5055
|
+
updates = mergeNodeUpdates(updates, layout2);
|
|
5056
|
+
pendingIds.clear();
|
|
5057
|
+
pendingResizes.clear();
|
|
5058
|
+
pendingAll = false;
|
|
5059
|
+
if (updates.length > 0) options.setNodes(applyNodeUpdates(options.getNodes(), updates));
|
|
5060
|
+
return mergeNodeUpdates(applied, updates);
|
|
5061
|
+
},
|
|
5062
|
+
/** Whether `id` is an auto layout frame. */
|
|
5063
|
+
isFrame: (id) => isAutoLayoutFrame(options.getNodes().find((n) => n.id === id))
|
|
5064
|
+
};
|
|
5065
|
+
return controller;
|
|
5066
|
+
}
|
|
5067
|
+
function restoreOrder(nodes, order) {
|
|
5068
|
+
const rank = new Map(order.map((id, i) => [id, i]));
|
|
5069
|
+
const indexed = nodes.map((n, i) => ({ n, r: rank.get(n.id) ?? order.length + i }));
|
|
5070
|
+
indexed.sort((a, b) => a.r - b.r);
|
|
5071
|
+
return indexed.every((e, i) => e.n === nodes[i]) ? nodes : indexed.map((e) => e.n);
|
|
5072
|
+
}
|
|
3902
5073
|
export {
|
|
5074
|
+
AUTO_LAYOUT_DATA_KEY,
|
|
5075
|
+
CHILD_LAYOUT_DATA_KEY,
|
|
3903
5076
|
CONNECTION_LINE_TYPES,
|
|
3904
5077
|
CanvasScenesStore,
|
|
3905
5078
|
DEFAULT_ARRANGE_SHORTCUTS,
|
|
@@ -3916,6 +5089,7 @@ export {
|
|
|
3916
5089
|
SHAPE_OPERATIONS,
|
|
3917
5090
|
StreamingLayoutManager,
|
|
3918
5091
|
alignNodes,
|
|
5092
|
+
applyConstraints,
|
|
3919
5093
|
applyNodeUpdates,
|
|
3920
5094
|
applyShapeCombination,
|
|
3921
5095
|
blendLayout,
|
|
@@ -3926,6 +5100,7 @@ export {
|
|
|
3926
5100
|
canvasHeight,
|
|
3927
5101
|
centerNodes,
|
|
3928
5102
|
centre,
|
|
5103
|
+
clampLayoutSize,
|
|
3929
5104
|
collectDescendantIds,
|
|
3930
5105
|
combineShapeNodes,
|
|
3931
5106
|
computeNodesBoundingBox,
|
|
@@ -3933,6 +5108,7 @@ export {
|
|
|
3933
5108
|
connectedOnly,
|
|
3934
5109
|
createBezierTrajectory,
|
|
3935
5110
|
createCanvasArrangeController,
|
|
5111
|
+
createCanvasAutoLayoutController,
|
|
3936
5112
|
createCanvasScenesStore,
|
|
3937
5113
|
createFanOutTrajectory,
|
|
3938
5114
|
createGuideIndex,
|
|
@@ -3957,7 +5133,14 @@ export {
|
|
|
3957
5133
|
flowSide,
|
|
3958
5134
|
formatNumber2 as formatNumber,
|
|
3959
5135
|
getAbsolutePosition,
|
|
5136
|
+
getAutoLayout,
|
|
5137
|
+
getAutoLayoutGrid,
|
|
5138
|
+
getAutoLayoutInsertTarget,
|
|
3960
5139
|
getCenteredNodePosition,
|
|
5140
|
+
getChildLayout,
|
|
5141
|
+
getFlowChildren,
|
|
5142
|
+
getLayoutParent,
|
|
5143
|
+
getLayoutSizing,
|
|
3961
5144
|
getLayoutedNodes,
|
|
3962
5145
|
getNodeRect,
|
|
3963
5146
|
getNodeShape,
|
|
@@ -3969,6 +5152,7 @@ export {
|
|
|
3969
5152
|
inferResizeHandle,
|
|
3970
5153
|
intersectPolygons,
|
|
3971
5154
|
invertNodeUpdates,
|
|
5155
|
+
isAutoLayoutFrame,
|
|
3972
5156
|
isEventFromTextInput,
|
|
3973
5157
|
isLocked,
|
|
3974
5158
|
isMeasureModifierHeld,
|
|
@@ -3979,16 +5163,23 @@ export {
|
|
|
3979
5163
|
isValidCanvasNode,
|
|
3980
5164
|
isValidCanvasScene,
|
|
3981
5165
|
isValidUrl,
|
|
5166
|
+
layoutAll,
|
|
3982
5167
|
layoutBounds,
|
|
5168
|
+
layoutFrame,
|
|
5169
|
+
layoutUp,
|
|
5170
|
+
layoutUpMany,
|
|
3983
5171
|
linearPositionTrajectory,
|
|
3984
5172
|
linearTrajectory,
|
|
3985
5173
|
lockNodes,
|
|
5174
|
+
makeSizingCoherent,
|
|
3986
5175
|
matchArrangeShortcut,
|
|
3987
5176
|
matchSize,
|
|
3988
5177
|
measureBetween,
|
|
3989
5178
|
measureLabel,
|
|
3990
5179
|
measureSelection,
|
|
3991
5180
|
measureToLine,
|
|
5181
|
+
mergeNodeUpdates,
|
|
5182
|
+
moveLayoutChild,
|
|
3992
5183
|
multiPolygonArea,
|
|
3993
5184
|
multiPolygonBounds,
|
|
3994
5185
|
nearestHandlePositions,
|
|
@@ -4007,10 +5198,12 @@ export {
|
|
|
4007
5198
|
positionToSide,
|
|
4008
5199
|
readStyleSize,
|
|
4009
5200
|
realClock,
|
|
5201
|
+
relayoutUpdates,
|
|
4010
5202
|
remapPastedNodes,
|
|
4011
5203
|
reorderNodes,
|
|
4012
5204
|
repositionNodesTo,
|
|
4013
5205
|
resizeHandleAxes,
|
|
5206
|
+
resolvePadding,
|
|
4014
5207
|
revertShapeCombination,
|
|
4015
5208
|
ringSignedArea,
|
|
4016
5209
|
runMultiNodeTransition,
|