@tsdraw/core 0.5.1 → 0.6.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/index.cjs +146 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +146 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1310,10 +1310,26 @@ function recordsToDocumentSnapshot(records) {
|
|
|
1310
1310
|
// src/editor/Editor.ts
|
|
1311
1311
|
var shapeIdCounter = 0;
|
|
1312
1312
|
var shapeIdRuntimeSeed = Math.random().toString(36).slice(2, 8);
|
|
1313
|
+
var MAX_HISTORY_ENTRIES = 100;
|
|
1313
1314
|
function createShapeId() {
|
|
1314
1315
|
shapeIdCounter += 1;
|
|
1315
1316
|
return `shape:${Date.now().toString(36)}-${shapeIdRuntimeSeed}-${shapeIdCounter.toString(36)}`;
|
|
1316
1317
|
}
|
|
1318
|
+
function cloneDocumentSnapshot(snapshot) {
|
|
1319
|
+
if (typeof structuredClone === "function") {
|
|
1320
|
+
return structuredClone(snapshot);
|
|
1321
|
+
}
|
|
1322
|
+
return JSON.parse(JSON.stringify(snapshot));
|
|
1323
|
+
}
|
|
1324
|
+
function areDocumentSnapshotsEqual(left, right) {
|
|
1325
|
+
if (left.records.length !== right.records.length) return false;
|
|
1326
|
+
for (let i = 0; i < left.records.length; i += 1) {
|
|
1327
|
+
if (JSON.stringify(left.records[i]) !== JSON.stringify(right.records[i])) {
|
|
1328
|
+
return false;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return true;
|
|
1332
|
+
}
|
|
1317
1333
|
var Editor = class {
|
|
1318
1334
|
store = new DocumentStore();
|
|
1319
1335
|
input = new InputManager();
|
|
@@ -1329,10 +1345,22 @@ var Editor = class {
|
|
|
1329
1345
|
};
|
|
1330
1346
|
toolStateContext;
|
|
1331
1347
|
listeners = /* @__PURE__ */ new Set();
|
|
1348
|
+
historyListeners = /* @__PURE__ */ new Set();
|
|
1349
|
+
undoStack = [];
|
|
1350
|
+
redoStack = [];
|
|
1351
|
+
lastDocumentSnapshot;
|
|
1352
|
+
suppressHistoryCapture = false;
|
|
1353
|
+
historyBatchDepth = 0;
|
|
1354
|
+
historyBatchStartSnapshot = null;
|
|
1355
|
+
historyBatchChanged = false;
|
|
1332
1356
|
// Creates a new editor instance with the given options (with defaults if not provided)
|
|
1333
1357
|
constructor(opts = {}) {
|
|
1334
1358
|
this.options = { dragDistanceSquared: opts.dragDistanceSquared ?? DRAG_DISTANCE_SQUARED };
|
|
1335
|
-
this.
|
|
1359
|
+
this.lastDocumentSnapshot = this.getDocumentSnapshot();
|
|
1360
|
+
this.store.listen(() => {
|
|
1361
|
+
this.captureDocumentHistory();
|
|
1362
|
+
this.emitChange();
|
|
1363
|
+
});
|
|
1336
1364
|
this.toolStateContext = {
|
|
1337
1365
|
transition: (id, info) => this.tools.transition(id, info)
|
|
1338
1366
|
};
|
|
@@ -1343,6 +1371,25 @@ var Editor = class {
|
|
|
1343
1371
|
this.registerToolDefinition(customTool);
|
|
1344
1372
|
}
|
|
1345
1373
|
this.setCurrentTool(opts.initialToolId ?? "pen");
|
|
1374
|
+
this.lastDocumentSnapshot = this.getDocumentSnapshot();
|
|
1375
|
+
}
|
|
1376
|
+
captureDocumentHistory() {
|
|
1377
|
+
const nextSnapshot = this.getDocumentSnapshot();
|
|
1378
|
+
const previousSnapshot = this.lastDocumentSnapshot;
|
|
1379
|
+
this.lastDocumentSnapshot = nextSnapshot;
|
|
1380
|
+
if (this.suppressHistoryCapture || areDocumentSnapshotsEqual(previousSnapshot, nextSnapshot)) {
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
if (this.historyBatchDepth > 0) {
|
|
1384
|
+
this.historyBatchChanged = true;
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
this.undoStack.push(cloneDocumentSnapshot(previousSnapshot));
|
|
1388
|
+
if (this.undoStack.length > MAX_HISTORY_ENTRIES) {
|
|
1389
|
+
this.undoStack.splice(0, this.undoStack.length - MAX_HISTORY_ENTRIES);
|
|
1390
|
+
}
|
|
1391
|
+
this.redoStack = [];
|
|
1392
|
+
this.emitHistoryChange();
|
|
1346
1393
|
}
|
|
1347
1394
|
registerToolDefinition(toolDefinition) {
|
|
1348
1395
|
for (const stateConstructor of toolDefinition.stateConstructors) {
|
|
@@ -1437,7 +1484,9 @@ var Editor = class {
|
|
|
1437
1484
|
loadDocumentSnapshot(snapshot) {
|
|
1438
1485
|
const documentSnapshot = recordsToDocumentSnapshot(snapshot.records);
|
|
1439
1486
|
if (!documentSnapshot) return;
|
|
1440
|
-
this.
|
|
1487
|
+
this.runWithoutHistoryCapture(() => {
|
|
1488
|
+
this.store.loadSnapshot(documentSnapshot);
|
|
1489
|
+
});
|
|
1441
1490
|
}
|
|
1442
1491
|
getSessionStateSnapshot(args) {
|
|
1443
1492
|
return {
|
|
@@ -1475,12 +1524,92 @@ var Editor = class {
|
|
|
1475
1524
|
}
|
|
1476
1525
|
return [];
|
|
1477
1526
|
}
|
|
1527
|
+
getHistorySnapshot() {
|
|
1528
|
+
return {
|
|
1529
|
+
version: 1,
|
|
1530
|
+
undoStack: this.undoStack.map(cloneDocumentSnapshot),
|
|
1531
|
+
redoStack: this.redoStack.map(cloneDocumentSnapshot)
|
|
1532
|
+
};
|
|
1533
|
+
}
|
|
1534
|
+
loadHistorySnapshot(snapshot) {
|
|
1535
|
+
if (!snapshot || snapshot.version !== 1) return;
|
|
1536
|
+
this.undoStack = snapshot.undoStack.map(cloneDocumentSnapshot).slice(-MAX_HISTORY_ENTRIES);
|
|
1537
|
+
this.redoStack = snapshot.redoStack.map(cloneDocumentSnapshot).slice(-MAX_HISTORY_ENTRIES);
|
|
1538
|
+
this.emitHistoryChange();
|
|
1539
|
+
}
|
|
1540
|
+
clearRedoHistory() {
|
|
1541
|
+
if (this.redoStack.length === 0) return;
|
|
1542
|
+
this.redoStack = [];
|
|
1543
|
+
this.emitHistoryChange();
|
|
1544
|
+
}
|
|
1545
|
+
beginHistoryEntry() {
|
|
1546
|
+
if (this.historyBatchDepth === 0) {
|
|
1547
|
+
this.historyBatchStartSnapshot = cloneDocumentSnapshot(this.lastDocumentSnapshot);
|
|
1548
|
+
this.historyBatchChanged = false;
|
|
1549
|
+
}
|
|
1550
|
+
this.historyBatchDepth += 1;
|
|
1551
|
+
}
|
|
1552
|
+
endHistoryEntry() {
|
|
1553
|
+
if (this.historyBatchDepth === 0) return;
|
|
1554
|
+
this.historyBatchDepth -= 1;
|
|
1555
|
+
if (this.historyBatchDepth > 0) return;
|
|
1556
|
+
const startSnapshot = this.historyBatchStartSnapshot;
|
|
1557
|
+
this.historyBatchStartSnapshot = null;
|
|
1558
|
+
if (!startSnapshot) return;
|
|
1559
|
+
const endSnapshot = this.getDocumentSnapshot();
|
|
1560
|
+
this.lastDocumentSnapshot = endSnapshot;
|
|
1561
|
+
const didDocumentChange = this.historyBatchChanged || !areDocumentSnapshotsEqual(startSnapshot, endSnapshot);
|
|
1562
|
+
this.historyBatchChanged = false;
|
|
1563
|
+
if (!didDocumentChange) return;
|
|
1564
|
+
this.undoStack.push(cloneDocumentSnapshot(startSnapshot));
|
|
1565
|
+
if (this.undoStack.length > MAX_HISTORY_ENTRIES) {
|
|
1566
|
+
this.undoStack.splice(0, this.undoStack.length - MAX_HISTORY_ENTRIES);
|
|
1567
|
+
}
|
|
1568
|
+
this.redoStack = [];
|
|
1569
|
+
this.emitHistoryChange();
|
|
1570
|
+
}
|
|
1571
|
+
canUndo() {
|
|
1572
|
+
return this.undoStack.length > 0;
|
|
1573
|
+
}
|
|
1574
|
+
canRedo() {
|
|
1575
|
+
return this.redoStack.length > 0;
|
|
1576
|
+
}
|
|
1577
|
+
undo() {
|
|
1578
|
+
const previousSnapshot = this.undoStack.pop();
|
|
1579
|
+
if (!previousSnapshot) return false;
|
|
1580
|
+
const currentSnapshot = this.getDocumentSnapshot();
|
|
1581
|
+
this.redoStack.push(cloneDocumentSnapshot(currentSnapshot));
|
|
1582
|
+
if (this.redoStack.length > MAX_HISTORY_ENTRIES) {
|
|
1583
|
+
this.redoStack.splice(0, this.redoStack.length - MAX_HISTORY_ENTRIES);
|
|
1584
|
+
}
|
|
1585
|
+
this.loadDocumentSnapshot(previousSnapshot);
|
|
1586
|
+
this.emitHistoryChange();
|
|
1587
|
+
return true;
|
|
1588
|
+
}
|
|
1589
|
+
redo() {
|
|
1590
|
+
const nextSnapshot = this.redoStack.pop();
|
|
1591
|
+
if (!nextSnapshot) return false;
|
|
1592
|
+
const currentSnapshot = this.getDocumentSnapshot();
|
|
1593
|
+
this.undoStack.push(cloneDocumentSnapshot(currentSnapshot));
|
|
1594
|
+
if (this.undoStack.length > MAX_HISTORY_ENTRIES) {
|
|
1595
|
+
this.undoStack.splice(0, this.undoStack.length - MAX_HISTORY_ENTRIES);
|
|
1596
|
+
}
|
|
1597
|
+
this.loadDocumentSnapshot(nextSnapshot);
|
|
1598
|
+
this.emitHistoryChange();
|
|
1599
|
+
return true;
|
|
1600
|
+
}
|
|
1478
1601
|
listen(listener) {
|
|
1479
1602
|
this.listeners.add(listener);
|
|
1480
1603
|
return () => {
|
|
1481
1604
|
this.listeners.delete(listener);
|
|
1482
1605
|
};
|
|
1483
1606
|
}
|
|
1607
|
+
listenHistory(listener) {
|
|
1608
|
+
this.historyListeners.add(listener);
|
|
1609
|
+
return () => {
|
|
1610
|
+
this.historyListeners.delete(listener);
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1484
1613
|
// Convert screen coords to page coords
|
|
1485
1614
|
screenToPage(screenX, screenY) {
|
|
1486
1615
|
return screenToPage(this.viewport, screenX, screenY);
|
|
@@ -1497,6 +1626,21 @@ var Editor = class {
|
|
|
1497
1626
|
listener();
|
|
1498
1627
|
}
|
|
1499
1628
|
}
|
|
1629
|
+
emitHistoryChange() {
|
|
1630
|
+
for (const listener of this.historyListeners) {
|
|
1631
|
+
listener();
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
runWithoutHistoryCapture(fn) {
|
|
1635
|
+
const previousValue = this.suppressHistoryCapture;
|
|
1636
|
+
this.suppressHistoryCapture = true;
|
|
1637
|
+
try {
|
|
1638
|
+
fn();
|
|
1639
|
+
} finally {
|
|
1640
|
+
this.suppressHistoryCapture = previousValue;
|
|
1641
|
+
this.lastDocumentSnapshot = this.getDocumentSnapshot();
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1500
1644
|
};
|
|
1501
1645
|
|
|
1502
1646
|
// src/tools/select/selectHelpers.ts
|