@pixerate/editor 0.244.0 → 0.246.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 +34 -32
- package/dist/agent/index.js +6 -4
- package/dist/animation-editor/index.cjs +61 -61
- package/dist/animation-editor/index.js +4 -4
- package/dist/{brushstrokeRender-4542T5HP.js → brushstrokeRender-AKUI3SEJ.js} +2 -2
- package/dist/{brushstrokeRender-QA5WVIDT.cjs → brushstrokeRender-ZDHMXJAE.cjs} +5 -5
- package/dist/canvas/changeFeed.d.cts +71 -0
- package/dist/canvas/changeFeed.d.ts +71 -0
- package/dist/canvas/index.cjs +490 -34
- package/dist/canvas/index.d.cts +3 -0
- package/dist/canvas/index.d.ts +3 -0
- package/dist/canvas/index.js +483 -27
- package/dist/canvas/proposal-tools.d.cts +21 -0
- package/dist/canvas/proposal-tools.d.ts +21 -0
- package/dist/canvas/proposals.d.cts +112 -0
- package/dist/canvas/proposals.d.ts +112 -0
- package/dist/chart/index.cjs +21 -21
- package/dist/chart/index.js +2 -2
- package/dist/{chunk-7YQNKSQ7.js → chunk-4PMCMWQS.js} +1 -1
- package/dist/{chunk-4I76OCVD.cjs → chunk-5DLCOQOQ.cjs} +16 -1
- package/dist/{chunk-HZ547SGQ.cjs → chunk-5MFDD7SP.cjs} +1 -1
- package/dist/{chunk-WGN7AUKB.js → chunk-7YW7T5TJ.js} +1 -1
- package/dist/{chunk-5RFENYO5.js → chunk-A23PSOBB.js} +1 -1
- package/dist/{chunk-X3ZINLIP.js → chunk-AU6MWQKZ.js} +1 -1
- package/dist/{chunk-AIS56JOO.js → chunk-BVRRIW7F.js} +1 -1
- package/dist/{chunk-BDIH4DYR.cjs → chunk-CEPKXLBS.cjs} +23 -23
- package/dist/{chunk-OSTKS3YN.js → chunk-DQWPMGH2.js} +1 -1
- package/dist/{chunk-IZL5V5RK.cjs → chunk-FK5LTDOO.cjs} +2 -2
- package/dist/{chunk-L5PB7EG3.js → chunk-LDPLEZ5T.js} +1 -1
- package/dist/{chunk-4EQY4TZJ.js → chunk-N6WUB3Y5.js} +1 -1
- package/dist/{chunk-RNSANXPT.js → chunk-NS62CQ2B.js} +112 -14
- package/dist/{chunk-UZU6DIZA.cjs → chunk-NUTMINJZ.cjs} +45 -45
- package/dist/{chunk-4T47Z4J3.cjs → chunk-Q2UYUWAZ.cjs} +10 -0
- package/dist/{chunk-7V7QMFTI.cjs → chunk-QOBCBGGI.cjs} +2 -2
- package/dist/{chunk-FQVVO5YA.js → chunk-SGPIVHJB.js} +1 -1
- package/dist/{chunk-QTMQ5TGA.js → chunk-UCYW4M66.js} +16 -1
- package/dist/{chunk-SD23XMVJ.cjs → chunk-UVPD55UZ.cjs} +35 -35
- package/dist/{chunk-TBJEMELS.js → chunk-VDAWA546.js} +10 -0
- package/dist/{chunk-W7GRGGBH.cjs → chunk-W7L4HUT2.cjs} +8 -8
- package/dist/{chunk-FJ2MSI43.cjs → chunk-WKPXOGZZ.cjs} +124 -26
- package/dist/{chunk-M6JORA5Z.cjs → chunk-XTWXBQD4.cjs} +86 -86
- package/dist/{chunk-D2SGV525.cjs → chunk-XZNU4DUX.cjs} +2 -2
- package/dist/diagram/index.cjs +2 -2
- package/dist/diagram/index.js +1 -1
- package/dist/effects/index.cjs +4 -4
- package/dist/effects/index.js +2 -2
- package/dist/extensions/index.cjs +5 -5
- package/dist/extensions/index.js +4 -4
- package/dist/gradient/index.cjs +2 -2
- package/dist/gradient/index.js +1 -1
- package/dist/history/HistoryManager.d.cts +20 -1
- package/dist/history/HistoryManager.d.ts +20 -1
- package/dist/history/index.cjs +8 -2
- package/dist/history/index.js +8 -2
- package/dist/history/types.d.cts +31 -0
- package/dist/history/types.d.ts +31 -0
- package/dist/image-editor/index.cjs +775 -775
- package/dist/image-editor/index.js +4 -4
- package/dist/index.cjs +16 -10
- package/dist/index.js +11 -5
- package/dist/paint-editor/index.cjs +136 -136
- package/dist/paint-editor/index.js +4 -4
- package/dist/parameters/index.cjs +2 -2
- package/dist/parameters/index.js +1 -1
- package/dist/tools/index.cjs +4 -2
- package/dist/tools/index.d.cts +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +3 -1
- package/dist/tools/origin.d.cts +22 -0
- package/dist/tools/origin.d.ts +22 -0
- package/dist/vector/index.cjs +964 -964
- package/dist/vector/index.js +5 -5
- package/dist/video-editor/index.cjs +4 -4
- package/dist/video-editor/index.js +2 -2
- package/package.json +1 -1
- package/skills/pixerate-canvas/SKILL.md +25 -0
- package/skills/pixerate-paint-editor/references/light-paint.md +7 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var _chunkFK5LTDOOcjs = require('./chunk-FK5LTDOO.cjs');
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
var _chunkGF2RBSDMcjs = require('./chunk-GF2RBSDM.cjs');
|
|
@@ -1361,12 +1361,12 @@ var unit = (x, y) => {
|
|
|
1361
1361
|
return l > 1e-12 && Number.isFinite(l) ? [x / l, y / l] : null;
|
|
1362
1362
|
};
|
|
1363
1363
|
function cubicOf(sp, i) {
|
|
1364
|
-
const s =
|
|
1364
|
+
const s = _chunkFK5LTDOOcjs.subpathSegment.call(void 0, sp, i);
|
|
1365
1365
|
if (s.length === 4) return s;
|
|
1366
1366
|
const [a, b] = s;
|
|
1367
1367
|
return [a, [a[0] + (b[0] - a[0]) / 3, a[1] + (b[1] - a[1]) / 3], [a[0] + 2 * (b[0] - a[0]) / 3, a[1] + 2 * (b[1] - a[1]) / 3], b];
|
|
1368
1368
|
}
|
|
1369
|
-
var isLine = (sp, i) =>
|
|
1369
|
+
var isLine = (sp, i) => _chunkFK5LTDOOcjs.subpathSegment.call(void 0, sp, i).length === 2;
|
|
1370
1370
|
function startTangent(c) {
|
|
1371
1371
|
for (let k = 1; k < 4; k++) {
|
|
1372
1372
|
const u = unit(c[k][0] - c[0][0], c[k][1] - c[0][1]);
|
|
@@ -1386,10 +1386,10 @@ function sample(c, n, out, withStart) {
|
|
|
1386
1386
|
}
|
|
1387
1387
|
var onAnchor = (a, h) => !h || Math.abs(h.x - a.x) < EPS && Math.abs(h.y - a.y) < EPS;
|
|
1388
1388
|
function tidy(a, keepType = true) {
|
|
1389
|
-
const next =
|
|
1389
|
+
const next = _chunkFK5LTDOOcjs.cloneAnchor.call(void 0, a);
|
|
1390
1390
|
if (onAnchor(next, next.in)) delete next.in;
|
|
1391
1391
|
if (onAnchor(next, next.out)) delete next.out;
|
|
1392
|
-
const shown =
|
|
1392
|
+
const shown = _chunkFK5LTDOOcjs.inferAnchorType.call(void 0, next);
|
|
1393
1393
|
const type = keepType && a.type ? a.type === "symmetric" && shown !== "symmetric" ? shown === "corner" ? "corner" : "smooth" : a.type === "smooth" && shown === "corner" ? "corner" : a.type : shown;
|
|
1394
1394
|
if (type === "corner") delete next.type;
|
|
1395
1395
|
else next.type = type;
|
|
@@ -1433,7 +1433,7 @@ function fitAcross(pts, N, t0, t1) {
|
|
|
1433
1433
|
return goldenMin(fit, 0, 1);
|
|
1434
1434
|
}
|
|
1435
1435
|
function removeAnchorKeepingShape(sp, index) {
|
|
1436
|
-
const anchors = sp.anchors.map(
|
|
1436
|
+
const anchors = sp.anchors.map(_chunkFK5LTDOOcjs.cloneAnchor);
|
|
1437
1437
|
const n = anchors.length;
|
|
1438
1438
|
if (index < 0 || index >= n) return { anchors, closed: sp.closed };
|
|
1439
1439
|
if ((sp.closed || index > 0 && index < n - 1) && n >= 3) {
|
|
@@ -1467,12 +1467,12 @@ function removeAnchorKeepingShape(sp, index) {
|
|
|
1467
1467
|
}
|
|
1468
1468
|
function removeAnchorsKeepingShape(sp, indices) {
|
|
1469
1469
|
const order = [...new Set(indices)].filter((i) => i >= 0 && i < sp.anchors.length).sort((a, b) => b - a);
|
|
1470
|
-
return order.reduce((acc, i) => removeAnchorKeepingShape(acc, i), { anchors: sp.anchors.map(
|
|
1470
|
+
return order.reduce((acc, i) => removeAnchorKeepingShape(acc, i), { anchors: sp.anchors.map(_chunkFK5LTDOOcjs.cloneAnchor), closed: sp.closed });
|
|
1471
1471
|
}
|
|
1472
1472
|
function bendSegment(sp, segment, t, p) {
|
|
1473
|
-
const anchors = sp.anchors.map(
|
|
1473
|
+
const anchors = sp.anchors.map(_chunkFK5LTDOOcjs.cloneAnchor);
|
|
1474
1474
|
const n = anchors.length;
|
|
1475
|
-
if (segment < 0 || segment >=
|
|
1475
|
+
if (segment < 0 || segment >= _chunkFK5LTDOOcjs.subpathSegmentCount.call(void 0, sp) || !Number.isFinite(t) || !Number.isFinite(p.x) || !Number.isFinite(p.y)) return { anchors, closed: sp.closed };
|
|
1476
1476
|
const tc = Math.min(0.95, Math.max(0.05, t));
|
|
1477
1477
|
const ia = segment;
|
|
1478
1478
|
const ib = (segment + 1) % n;
|
|
@@ -1483,16 +1483,16 @@ function bendSegment(sp, segment, t, p) {
|
|
|
1483
1483
|
const oy = (p.y - (a.y + (b.y - a.y) * tc)) / k;
|
|
1484
1484
|
const c1 = { x: a.x + (b.x - a.x) / 3 + ox, y: a.y + (b.y - a.y) / 3 + oy };
|
|
1485
1485
|
const c2 = { x: b.x + (a.x - b.x) / 3 + ox, y: b.y + (a.y - b.y) / 3 + oy };
|
|
1486
|
-
anchors[ia] =
|
|
1487
|
-
anchors[ib] =
|
|
1486
|
+
anchors[ia] = _chunkFK5LTDOOcjs.moveAnchorHandle.call(void 0, a, "out", c1);
|
|
1487
|
+
anchors[ib] = _chunkFK5LTDOOcjs.moveAnchorHandle.call(void 0, b, "in", c2);
|
|
1488
1488
|
return { anchors, closed: sp.closed };
|
|
1489
1489
|
}
|
|
1490
1490
|
function subpathPointAt(sp, segment, t) {
|
|
1491
|
-
const [x, y] = _chunkGF2RBSDMcjs.segmentPoint.call(void 0,
|
|
1491
|
+
const [x, y] = _chunkGF2RBSDMcjs.segmentPoint.call(void 0, _chunkFK5LTDOOcjs.subpathSegment.call(void 0, sp, segment), t);
|
|
1492
1492
|
return { x, y };
|
|
1493
1493
|
}
|
|
1494
1494
|
function curvatureMoveAnchor(sp, index, q) {
|
|
1495
|
-
const anchors = sp.anchors.map(
|
|
1495
|
+
const anchors = sp.anchors.map(_chunkFK5LTDOOcjs.cloneAnchor);
|
|
1496
1496
|
const a = sp.anchors[index];
|
|
1497
1497
|
if (!a) return { anchors, closed: sp.closed };
|
|
1498
1498
|
const own = [
|
|
@@ -1538,7 +1538,7 @@ function curvatureMoveAnchor(sp, index, q) {
|
|
|
1538
1538
|
function cutSubpathAt(sp, at) {
|
|
1539
1539
|
const n = sp.anchors.length;
|
|
1540
1540
|
const cuts = [...new Set(at)].filter((i) => Number.isInteger(i) && i >= 0 && i < n && (sp.closed || i > 0 && i < n - 1)).sort((a, b) => a - b);
|
|
1541
|
-
if (!cuts.length || n < 2) return [{ anchors: sp.anchors.map(
|
|
1541
|
+
if (!cuts.length || n < 2) return [{ anchors: sp.anchors.map(_chunkFK5LTDOOcjs.cloneAnchor), closed: sp.closed }];
|
|
1542
1542
|
const first = cuts[0];
|
|
1543
1543
|
const run = sp.closed ? Array.from({ length: n + 1 }, (_, i) => sp.anchors[(first + i) % n]) : sp.anchors;
|
|
1544
1544
|
const cutSet = new Set(sp.closed ? [...cuts.map((c) => (c - first + n) % n), n] : cuts);
|
|
@@ -1546,7 +1546,7 @@ function cutSubpathAt(sp, at) {
|
|
|
1546
1546
|
let cur = [];
|
|
1547
1547
|
run.forEach((a, i) => {
|
|
1548
1548
|
if (!cutSet.has(i)) {
|
|
1549
|
-
cur.push(
|
|
1549
|
+
cur.push(_chunkFK5LTDOOcjs.cloneAnchor.call(void 0, a));
|
|
1550
1550
|
return;
|
|
1551
1551
|
}
|
|
1552
1552
|
if (cur.length) {
|
|
@@ -1561,10 +1561,10 @@ function cutSubpathAt(sp, at) {
|
|
|
1561
1561
|
}
|
|
1562
1562
|
function splitSubpathAt(sp, segment, t, endTolerance = 1e-6) {
|
|
1563
1563
|
const n = sp.anchors.length;
|
|
1564
|
-
if (segment < 0 || segment >=
|
|
1564
|
+
if (segment < 0 || segment >= _chunkFK5LTDOOcjs.subpathSegmentCount.call(void 0, sp)) return [{ anchors: sp.anchors.map(_chunkFK5LTDOOcjs.cloneAnchor), closed: sp.closed }];
|
|
1565
1565
|
if (t <= endTolerance) return cutSubpathAt(sp, [segment]);
|
|
1566
1566
|
if (t >= 1 - endTolerance) return cutSubpathAt(sp, [(segment + 1) % n]);
|
|
1567
|
-
const { subpath, index } =
|
|
1567
|
+
const { subpath, index } = _chunkFK5LTDOOcjs.insertAnchor.call(void 0, sp, segment, t);
|
|
1568
1568
|
return cutSubpathAt(subpath, [index]);
|
|
1569
1569
|
}
|
|
1570
1570
|
var endOf = (sp, last) => sp.anchors[last ? sp.anchors.length - 1 : 0];
|
|
@@ -1587,7 +1587,7 @@ function joinSubpaths(subpaths, tolerance) {
|
|
|
1587
1587
|
const closed = [];
|
|
1588
1588
|
let open = [];
|
|
1589
1589
|
for (const sp of subpaths) {
|
|
1590
|
-
const copy = { anchors: sp.anchors.map(
|
|
1590
|
+
const copy = { anchors: sp.anchors.map(_chunkFK5LTDOOcjs.cloneAnchor), closed: sp.closed };
|
|
1591
1591
|
if (sp.closed || sp.anchors.length < 2) {
|
|
1592
1592
|
if (sp.anchors.length) closed.push(copy);
|
|
1593
1593
|
} else open.push(copy);
|
|
@@ -1642,7 +1642,7 @@ function smoothSubpath(sp, amount = 1, only) {
|
|
|
1642
1642
|
const t = Math.min(1, Math.max(0, amount));
|
|
1643
1643
|
const orig = sp.anchors;
|
|
1644
1644
|
const n = orig.length;
|
|
1645
|
-
const anchors = orig.map(
|
|
1645
|
+
const anchors = orig.map(_chunkFK5LTDOOcjs.cloneAnchor);
|
|
1646
1646
|
if (n < 3 || t === 0) return { anchors, closed: sp.closed };
|
|
1647
1647
|
for (let i = 0; i < n; i++) {
|
|
1648
1648
|
if (!sp.closed && (i === 0 || i === n - 1)) continue;
|
|
@@ -1671,8 +1671,8 @@ function smoothSubpath(sp, amount = 1, only) {
|
|
|
1671
1671
|
}
|
|
1672
1672
|
function segsOf(sp) {
|
|
1673
1673
|
const out = [];
|
|
1674
|
-
for (let i = 0; i <
|
|
1675
|
-
const s =
|
|
1674
|
+
for (let i = 0; i < _chunkFK5LTDOOcjs.subpathSegmentCount.call(void 0, sp); i++) {
|
|
1675
|
+
const s = _chunkFK5LTDOOcjs.subpathSegment.call(void 0, sp, i);
|
|
1676
1676
|
out.push(s.length === 2 ? { c: s, line: true } : { c: s, line: false });
|
|
1677
1677
|
}
|
|
1678
1678
|
return out;
|
|
@@ -1729,7 +1729,7 @@ function removeRedundantPoints(sp, tolerance) {
|
|
|
1729
1729
|
const tol = Math.max(tolerance, 1e-9);
|
|
1730
1730
|
const types = new Map(sp.anchors.filter((a) => a.type).map((a) => [`${a.x},${a.y}`, a.type]));
|
|
1731
1731
|
const segs = segsOf(sp).filter((s) => !isZeroSeg(s));
|
|
1732
|
-
if (!segs.length) return { anchors: sp.anchors.map(
|
|
1732
|
+
if (!segs.length) return { anchors: sp.anchors.map(_chunkFK5LTDOOcjs.cloneAnchor), closed: sp.closed };
|
|
1733
1733
|
const minSegs = sp.closed ? 2 : 1;
|
|
1734
1734
|
let changed = true;
|
|
1735
1735
|
while (changed && segs.length > minSegs) {
|
|
@@ -1747,7 +1747,7 @@ function removeRedundantPoints(sp, tolerance) {
|
|
|
1747
1747
|
break;
|
|
1748
1748
|
}
|
|
1749
1749
|
}
|
|
1750
|
-
return _nullishCoalesce(segsToSubpath(segs, sp.closed, types), () => ( { anchors: sp.anchors.map(
|
|
1750
|
+
return _nullishCoalesce(segsToSubpath(segs, sp.closed, types), () => ( { anchors: sp.anchors.map(_chunkFK5LTDOOcjs.cloneAnchor), closed: sp.closed }));
|
|
1751
1751
|
}
|
|
1752
1752
|
|
|
1753
1753
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkQ2UYUWAZcjs = require('./chunk-Q2UYUWAZ.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var _chunkCVFAAZXEcjs = require('./chunk-CVFAAZXE.cjs');
|
|
@@ -2527,7 +2527,7 @@ function vectorExtrudeFaces(path, params) {
|
|
|
2527
2527
|
// src/vector/brushstroke.ts
|
|
2528
2528
|
var VECTOR_BRUSHSTROKE_SCALE = 2;
|
|
2529
2529
|
function vectorBrushstrokeBrushes() {
|
|
2530
|
-
return
|
|
2530
|
+
return _chunkQ2UYUWAZcjs.BUILTIN_BRUSHES.filter((b) => _chunkPQ3H2AANcjs.isBrushstrokeBrush.call(void 0, b));
|
|
2531
2531
|
}
|
|
2532
2532
|
function vectorBrushstrokeBrush(id) {
|
|
2533
2533
|
return _nullishCoalesce(vectorBrushstrokeBrushes().find((b) => b.id === id), () => ( null));
|
|
@@ -74,7 +74,7 @@ function profileAlongPolyline(points, values, count = 32) {
|
|
|
74
74
|
var round3 = (v) => Math.round(v * 1e3) / 1e3;
|
|
75
75
|
var loading = null;
|
|
76
76
|
function loadCanvasBrushstrokeRenderer() {
|
|
77
|
-
loading ??= import("./brushstrokeRender-
|
|
77
|
+
loading ??= import("./brushstrokeRender-AKUI3SEJ.js").catch((error) => {
|
|
78
78
|
loading = null;
|
|
79
79
|
throw error;
|
|
80
80
|
});
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// src/history/types.ts
|
|
2
|
+
var USER_ORIGIN = "user";
|
|
3
|
+
function agentOrigin(agentId) {
|
|
4
|
+
return `agent:${agentId}`;
|
|
5
|
+
}
|
|
6
|
+
function originAgentId(origin) {
|
|
7
|
+
return origin?.startsWith("agent:") ? origin.slice("agent:".length) || null : null;
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
// src/history/HistoryManager.ts
|
|
2
11
|
var sumBytes = (parts) => parts.reduce((n, p) => n + p.bytes, 0);
|
|
3
12
|
function undoParts(parts) {
|
|
@@ -16,6 +25,9 @@ var HistoryManager = class {
|
|
|
16
25
|
batchDepth = 0;
|
|
17
26
|
currentBatch = null;
|
|
18
27
|
listeners = /* @__PURE__ */ new Set();
|
|
28
|
+
commitListeners = /* @__PURE__ */ new Set();
|
|
29
|
+
/** Origins set by `withOrigin`, innermost last. */
|
|
30
|
+
origins = [];
|
|
19
31
|
onStateChange;
|
|
20
32
|
cachedState;
|
|
21
33
|
cachedEntries = null;
|
|
@@ -94,7 +106,8 @@ var HistoryManager = class {
|
|
|
94
106
|
tag: command.tag,
|
|
95
107
|
timestamp,
|
|
96
108
|
parts: [part],
|
|
97
|
-
bytes: part.bytes
|
|
109
|
+
bytes: part.bytes,
|
|
110
|
+
origin: command.origin ?? this.getOrigin()
|
|
98
111
|
};
|
|
99
112
|
}
|
|
100
113
|
/** Pushes a step, clears redo and applies the depth and byte limits. */
|
|
@@ -143,14 +156,17 @@ var HistoryManager = class {
|
|
|
143
156
|
command.execute();
|
|
144
157
|
this.currentBatch.push({
|
|
145
158
|
...command,
|
|
146
|
-
timestamp: command.timestamp ?? Date.now()
|
|
159
|
+
timestamp: command.timestamp ?? Date.now(),
|
|
160
|
+
origin: command.origin ?? this.getOrigin()
|
|
147
161
|
});
|
|
148
162
|
return;
|
|
149
163
|
}
|
|
150
164
|
command.execute();
|
|
151
|
-
this.
|
|
165
|
+
const entry = this.makeEntry(command, command.timestamp ?? Date.now());
|
|
166
|
+
this.record(entry);
|
|
152
167
|
this.resetGesture();
|
|
153
168
|
this.notify();
|
|
169
|
+
this.emit("execute", entry.id, entry.origin);
|
|
154
170
|
}
|
|
155
171
|
/**
|
|
156
172
|
* Executes a command as part of a continuous interaction (slider scrub, node drag).
|
|
@@ -165,13 +181,15 @@ var HistoryManager = class {
|
|
|
165
181
|
executeMerged(command, options = {}) {
|
|
166
182
|
const now = Date.now();
|
|
167
183
|
const key = this.heldKey ?? options.key;
|
|
184
|
+
const origin = command.origin ?? this.getOrigin();
|
|
185
|
+
command = { ...command, origin };
|
|
168
186
|
if (key !== void 0) {
|
|
169
187
|
if (this.isApplying || this.batchDepth > 0) {
|
|
170
188
|
this.execute({ ...command, timestamp: now });
|
|
171
189
|
return;
|
|
172
190
|
}
|
|
173
191
|
const top = this.undoStack[this.undoStack.length - 1];
|
|
174
|
-
if (top && this.gestureKey === key && this.gestureEntryId === top.id) {
|
|
192
|
+
if (top && this.gestureKey === key && this.gestureEntryId === top.id && top.origin === origin) {
|
|
175
193
|
command.execute();
|
|
176
194
|
const redo = command.redo ?? command.execute;
|
|
177
195
|
const bytes = this.measure(command);
|
|
@@ -186,6 +204,7 @@ var HistoryManager = class {
|
|
|
186
204
|
this.redoStack = [];
|
|
187
205
|
this.trim();
|
|
188
206
|
this.notify();
|
|
207
|
+
this.emit("merge", top.id, origin);
|
|
189
208
|
return;
|
|
190
209
|
}
|
|
191
210
|
this.execute({ ...command, timestamp: now });
|
|
@@ -200,7 +219,7 @@ var HistoryManager = class {
|
|
|
200
219
|
if (command.tag && this.undoStack.length > 0 && this.batchDepth === 0 && !this.isApplying) {
|
|
201
220
|
const top = this.undoStack[this.undoStack.length - 1];
|
|
202
221
|
const elapsed = top.timestamp ? now - top.timestamp : Infinity;
|
|
203
|
-
if (top.tag === command.tag && elapsed <= windowMs) {
|
|
222
|
+
if (top.tag === command.tag && elapsed <= windowMs && top.origin === origin) {
|
|
204
223
|
command.execute();
|
|
205
224
|
const initialParts = top.parts;
|
|
206
225
|
const bytes = this.measure(command);
|
|
@@ -217,12 +236,14 @@ var HistoryManager = class {
|
|
|
217
236
|
bytes
|
|
218
237
|
}
|
|
219
238
|
],
|
|
220
|
-
bytes
|
|
239
|
+
bytes,
|
|
240
|
+
origin
|
|
221
241
|
};
|
|
222
242
|
this.redoStack = [];
|
|
223
243
|
this.resetGesture();
|
|
224
244
|
this.trim();
|
|
225
245
|
this.notify();
|
|
246
|
+
this.emit("merge", top.id, origin);
|
|
226
247
|
return;
|
|
227
248
|
}
|
|
228
249
|
}
|
|
@@ -281,8 +302,11 @@ var HistoryManager = class {
|
|
|
281
302
|
}
|
|
282
303
|
};
|
|
283
304
|
const bytes = batchCommands.reduce((n, c) => n + this.measure(c), 0);
|
|
305
|
+
const id = this.nextId++;
|
|
306
|
+
const origin = batchCommands[0].origin ?? this.getOrigin();
|
|
284
307
|
this.record({
|
|
285
|
-
id
|
|
308
|
+
id,
|
|
309
|
+
origin,
|
|
286
310
|
name,
|
|
287
311
|
timestamp: Date.now(),
|
|
288
312
|
parts: [
|
|
@@ -300,6 +324,7 @@ var HistoryManager = class {
|
|
|
300
324
|
});
|
|
301
325
|
this.resetGesture();
|
|
302
326
|
this.notify();
|
|
327
|
+
this.emit("execute", id, origin);
|
|
303
328
|
}
|
|
304
329
|
}
|
|
305
330
|
/**
|
|
@@ -330,12 +355,14 @@ var HistoryManager = class {
|
|
|
330
355
|
undoParts(entry.parts);
|
|
331
356
|
this.undoStack.pop();
|
|
332
357
|
this.redoStack.push(entry);
|
|
358
|
+
return entry.id;
|
|
333
359
|
}
|
|
334
360
|
redoOne() {
|
|
335
361
|
const entry = this.redoStack[this.redoStack.length - 1];
|
|
336
362
|
redoParts(entry.parts);
|
|
337
363
|
this.redoStack.pop();
|
|
338
364
|
this.undoStack.push(entry);
|
|
365
|
+
return entry.id;
|
|
339
366
|
}
|
|
340
367
|
/**
|
|
341
368
|
* Reverts the most recent command on the undo stack.
|
|
@@ -347,12 +374,14 @@ var HistoryManager = class {
|
|
|
347
374
|
}
|
|
348
375
|
this.isApplying = true;
|
|
349
376
|
this.resetGesture();
|
|
377
|
+
let id = null;
|
|
350
378
|
try {
|
|
351
|
-
this.undoOne();
|
|
379
|
+
id = this.undoOne();
|
|
352
380
|
return true;
|
|
353
381
|
} finally {
|
|
354
382
|
this.isApplying = false;
|
|
355
383
|
this.notify();
|
|
384
|
+
if (id !== null) this.emit("undo", id);
|
|
356
385
|
}
|
|
357
386
|
}
|
|
358
387
|
/**
|
|
@@ -365,12 +394,14 @@ var HistoryManager = class {
|
|
|
365
394
|
}
|
|
366
395
|
this.isApplying = true;
|
|
367
396
|
this.resetGesture();
|
|
397
|
+
let id = null;
|
|
368
398
|
try {
|
|
369
|
-
this.redoOne();
|
|
399
|
+
id = this.redoOne();
|
|
370
400
|
return true;
|
|
371
401
|
} finally {
|
|
372
402
|
this.isApplying = false;
|
|
373
403
|
this.notify();
|
|
404
|
+
if (id !== null) this.emit("redo", id);
|
|
374
405
|
}
|
|
375
406
|
}
|
|
376
407
|
/**
|
|
@@ -417,7 +448,10 @@ var HistoryManager = class {
|
|
|
417
448
|
} finally {
|
|
418
449
|
this.isApplying = false;
|
|
419
450
|
this.redoStack = n > 0 ? [] : this.redoStack.filter((e) => e.id < mark.nextId);
|
|
420
|
-
if (n > 0 || this.redoStack.length !== redoBefore)
|
|
451
|
+
if (n > 0 || this.redoStack.length !== redoBefore) {
|
|
452
|
+
this.notify();
|
|
453
|
+
this.emit("revert");
|
|
454
|
+
}
|
|
421
455
|
}
|
|
422
456
|
return n;
|
|
423
457
|
}
|
|
@@ -433,7 +467,8 @@ var HistoryManager = class {
|
|
|
433
467
|
label: e.name,
|
|
434
468
|
index,
|
|
435
469
|
current: index === u - 1,
|
|
436
|
-
undone: false
|
|
470
|
+
undone: false,
|
|
471
|
+
origin: e.origin
|
|
437
472
|
}));
|
|
438
473
|
for (let i = this.redoStack.length - 1; i >= 0; i--) {
|
|
439
474
|
const e = this.redoStack[i];
|
|
@@ -442,7 +477,8 @@ var HistoryManager = class {
|
|
|
442
477
|
label: e.name,
|
|
443
478
|
index: entries.length,
|
|
444
479
|
current: false,
|
|
445
|
-
undone: true
|
|
480
|
+
undone: true,
|
|
481
|
+
origin: e.origin
|
|
446
482
|
});
|
|
447
483
|
}
|
|
448
484
|
this.cachedEntries = entries;
|
|
@@ -458,20 +494,22 @@ var HistoryManager = class {
|
|
|
458
494
|
const target = Math.max(0, Math.min(total, Math.floor(index) + 1));
|
|
459
495
|
if (target === this.undoStack.length) return 0;
|
|
460
496
|
let n = 0;
|
|
497
|
+
const steps = [];
|
|
461
498
|
this.isApplying = true;
|
|
462
499
|
this.resetGesture();
|
|
463
500
|
try {
|
|
464
501
|
while (this.undoStack.length > target) {
|
|
465
|
-
this.undoOne();
|
|
502
|
+
steps.push(["undo", this.undoOne()]);
|
|
466
503
|
n++;
|
|
467
504
|
}
|
|
468
505
|
while (this.undoStack.length < target) {
|
|
469
|
-
this.redoOne();
|
|
506
|
+
steps.push(["redo", this.redoOne()]);
|
|
470
507
|
n++;
|
|
471
508
|
}
|
|
472
509
|
} finally {
|
|
473
510
|
this.isApplying = false;
|
|
474
511
|
this.notify();
|
|
512
|
+
for (const [kind, id] of steps) this.emit(kind, id);
|
|
475
513
|
}
|
|
476
514
|
return n;
|
|
477
515
|
}
|
|
@@ -484,6 +522,7 @@ var HistoryManager = class {
|
|
|
484
522
|
this.epoch++;
|
|
485
523
|
this.resetGesture();
|
|
486
524
|
this.notify();
|
|
525
|
+
this.emit("clear");
|
|
487
526
|
}
|
|
488
527
|
/**
|
|
489
528
|
* Subscribes to history state changes.
|
|
@@ -497,6 +536,62 @@ var HistoryManager = class {
|
|
|
497
536
|
this.listeners.delete(listener);
|
|
498
537
|
};
|
|
499
538
|
}
|
|
539
|
+
/**
|
|
540
|
+
* Listens to each change as it lands: what happened (`execute`, `merge`, `undo`, `redo`,
|
|
541
|
+
* `revert`, `clear`), the step and who made it. Unlike `subscribe`, it is not called at once
|
|
542
|
+
* and it hears every step of a `goTo`. Returns an unsubscribe function.
|
|
543
|
+
*/
|
|
544
|
+
onCommit(listener) {
|
|
545
|
+
this.commitListeners.add(listener);
|
|
546
|
+
return () => {
|
|
547
|
+
this.commitListeners.delete(listener);
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
emit(kind, entryId, origin) {
|
|
551
|
+
if (this.commitListeners.size === 0) return;
|
|
552
|
+
const entry = entryId === void 0 ? void 0 : this.getEntries().find((e) => e.id === entryId);
|
|
553
|
+
const event = {
|
|
554
|
+
kind,
|
|
555
|
+
...entry ? { entry } : {},
|
|
556
|
+
origin: origin ?? this.getOrigin(),
|
|
557
|
+
revision: this.revision
|
|
558
|
+
};
|
|
559
|
+
this.commitListeners.forEach((listener) => {
|
|
560
|
+
try {
|
|
561
|
+
listener(event);
|
|
562
|
+
} catch (err) {
|
|
563
|
+
console.error("[HistoryManager] Error in commit listener:", err);
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
/** The origin a change is recorded with when its command names none (see `withOrigin`). */
|
|
568
|
+
getOrigin() {
|
|
569
|
+
return this.origins[this.origins.length - 1] ?? USER_ORIGIN;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Records the changes `fn` makes as made by `origin` (`agent:<id>` for an agent), unless a
|
|
573
|
+
* command names its own. When `fn` returns a promise, the origin holds until it settles, so
|
|
574
|
+
* anything else recorded on this history meanwhile (the user's own edits) is stamped with it
|
|
575
|
+
* too: give those commands an explicit `origin`, or keep agent work synchronous.
|
|
576
|
+
*/
|
|
577
|
+
withOrigin(origin, fn) {
|
|
578
|
+
this.origins.push(origin);
|
|
579
|
+
let pending = false;
|
|
580
|
+
const pop = () => {
|
|
581
|
+
const i = this.origins.lastIndexOf(origin);
|
|
582
|
+
if (i >= 0) this.origins.splice(i, 1);
|
|
583
|
+
};
|
|
584
|
+
try {
|
|
585
|
+
const result = fn();
|
|
586
|
+
if (result && typeof result.then === "function") {
|
|
587
|
+
pending = true;
|
|
588
|
+
return Promise.resolve(result).finally(pop);
|
|
589
|
+
}
|
|
590
|
+
return result;
|
|
591
|
+
} finally {
|
|
592
|
+
if (!pending) pop();
|
|
593
|
+
}
|
|
594
|
+
}
|
|
500
595
|
/**
|
|
501
596
|
* Utility helper to create a Command from before/after state snapshots.
|
|
502
597
|
*/
|
|
@@ -515,6 +610,9 @@ function createHistoryManager(options = {}) {
|
|
|
515
610
|
}
|
|
516
611
|
|
|
517
612
|
export {
|
|
613
|
+
USER_ORIGIN,
|
|
614
|
+
agentOrigin,
|
|
615
|
+
originAgentId,
|
|
518
616
|
HistoryManager,
|
|
519
617
|
createHistoryManager
|
|
520
618
|
};
|