@tsdraw/core 0.5.1 → 0.6.2
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 +158 -6
- 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 +158 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -150,6 +150,12 @@ var DocumentStore = class {
|
|
|
150
150
|
loadSnapshot(snapshot) {
|
|
151
151
|
const pageState = cloneValue(snapshot.page);
|
|
152
152
|
const normalizedOrder = [...snapshot.order].filter((shapeId) => pageState.shapes[shapeId] != null);
|
|
153
|
+
const orderedSet = new Set(normalizedOrder);
|
|
154
|
+
for (const shapeId of Object.keys(pageState.shapes)) {
|
|
155
|
+
if (!orderedSet.has(shapeId)) {
|
|
156
|
+
normalizedOrder.push(shapeId);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
153
159
|
this.state = {
|
|
154
160
|
id: pageState.id,
|
|
155
161
|
shapes: pageState.shapes,
|
|
@@ -865,13 +871,14 @@ var PenDrawingState = class extends StateNode {
|
|
|
865
871
|
type: "straight",
|
|
866
872
|
path: encodePoints([prevEnd, { ...anchorPt, z: pressure }])
|
|
867
873
|
};
|
|
874
|
+
const withStraightSeg = [...segments, seg];
|
|
868
875
|
this.editor.updateShapes([
|
|
869
876
|
{
|
|
870
877
|
id,
|
|
871
878
|
type: "draw",
|
|
872
879
|
props: {
|
|
873
|
-
segments:
|
|
874
|
-
isClosed: this.detectClosure(
|
|
880
|
+
segments: withStraightSeg,
|
|
881
|
+
isClosed: this.detectClosure(withStraightSeg, size, scale)
|
|
875
882
|
}
|
|
876
883
|
}
|
|
877
884
|
]);
|
|
@@ -947,7 +954,7 @@ var PenDrawingState = class extends StateNode {
|
|
|
947
954
|
type: "draw",
|
|
948
955
|
props: {
|
|
949
956
|
segments: updated,
|
|
950
|
-
isClosed: this.detectClosure(
|
|
957
|
+
isClosed: this.detectClosure(updated, size, scale)
|
|
951
958
|
}
|
|
952
959
|
}
|
|
953
960
|
]);
|
|
@@ -1310,10 +1317,26 @@ function recordsToDocumentSnapshot(records) {
|
|
|
1310
1317
|
// src/editor/Editor.ts
|
|
1311
1318
|
var shapeIdCounter = 0;
|
|
1312
1319
|
var shapeIdRuntimeSeed = Math.random().toString(36).slice(2, 8);
|
|
1320
|
+
var MAX_HISTORY_ENTRIES = 100;
|
|
1313
1321
|
function createShapeId() {
|
|
1314
1322
|
shapeIdCounter += 1;
|
|
1315
1323
|
return `shape:${Date.now().toString(36)}-${shapeIdRuntimeSeed}-${shapeIdCounter.toString(36)}`;
|
|
1316
1324
|
}
|
|
1325
|
+
function cloneDocumentSnapshot(snapshot) {
|
|
1326
|
+
if (typeof structuredClone === "function") {
|
|
1327
|
+
return structuredClone(snapshot);
|
|
1328
|
+
}
|
|
1329
|
+
return JSON.parse(JSON.stringify(snapshot));
|
|
1330
|
+
}
|
|
1331
|
+
function areDocumentSnapshotsEqual(left, right) {
|
|
1332
|
+
if (left.records.length !== right.records.length) return false;
|
|
1333
|
+
for (let i = 0; i < left.records.length; i += 1) {
|
|
1334
|
+
if (JSON.stringify(left.records[i]) !== JSON.stringify(right.records[i])) {
|
|
1335
|
+
return false;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
return true;
|
|
1339
|
+
}
|
|
1317
1340
|
var Editor = class {
|
|
1318
1341
|
store = new DocumentStore();
|
|
1319
1342
|
input = new InputManager();
|
|
@@ -1329,10 +1352,22 @@ var Editor = class {
|
|
|
1329
1352
|
};
|
|
1330
1353
|
toolStateContext;
|
|
1331
1354
|
listeners = /* @__PURE__ */ new Set();
|
|
1355
|
+
historyListeners = /* @__PURE__ */ new Set();
|
|
1356
|
+
undoStack = [];
|
|
1357
|
+
redoStack = [];
|
|
1358
|
+
lastDocumentSnapshot;
|
|
1359
|
+
suppressHistoryCapture = false;
|
|
1360
|
+
historyBatchDepth = 0;
|
|
1361
|
+
historyBatchStartSnapshot = null;
|
|
1362
|
+
historyBatchChanged = false;
|
|
1332
1363
|
// Creates a new editor instance with the given options (with defaults if not provided)
|
|
1333
1364
|
constructor(opts = {}) {
|
|
1334
1365
|
this.options = { dragDistanceSquared: opts.dragDistanceSquared ?? DRAG_DISTANCE_SQUARED };
|
|
1335
|
-
this.
|
|
1366
|
+
this.lastDocumentSnapshot = this.getDocumentSnapshot();
|
|
1367
|
+
this.store.listen(() => {
|
|
1368
|
+
this.captureDocumentHistory();
|
|
1369
|
+
this.emitChange();
|
|
1370
|
+
});
|
|
1336
1371
|
this.toolStateContext = {
|
|
1337
1372
|
transition: (id, info) => this.tools.transition(id, info)
|
|
1338
1373
|
};
|
|
@@ -1343,6 +1378,25 @@ var Editor = class {
|
|
|
1343
1378
|
this.registerToolDefinition(customTool);
|
|
1344
1379
|
}
|
|
1345
1380
|
this.setCurrentTool(opts.initialToolId ?? "pen");
|
|
1381
|
+
this.lastDocumentSnapshot = this.getDocumentSnapshot();
|
|
1382
|
+
}
|
|
1383
|
+
captureDocumentHistory() {
|
|
1384
|
+
const nextSnapshot = this.getDocumentSnapshot();
|
|
1385
|
+
const previousSnapshot = this.lastDocumentSnapshot;
|
|
1386
|
+
this.lastDocumentSnapshot = nextSnapshot;
|
|
1387
|
+
if (this.suppressHistoryCapture || areDocumentSnapshotsEqual(previousSnapshot, nextSnapshot)) {
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
if (this.historyBatchDepth > 0) {
|
|
1391
|
+
this.historyBatchChanged = true;
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1394
|
+
this.undoStack.push(cloneDocumentSnapshot(previousSnapshot));
|
|
1395
|
+
if (this.undoStack.length > MAX_HISTORY_ENTRIES) {
|
|
1396
|
+
this.undoStack.splice(0, this.undoStack.length - MAX_HISTORY_ENTRIES);
|
|
1397
|
+
}
|
|
1398
|
+
this.redoStack = [];
|
|
1399
|
+
this.emitHistoryChange();
|
|
1346
1400
|
}
|
|
1347
1401
|
registerToolDefinition(toolDefinition) {
|
|
1348
1402
|
for (const stateConstructor of toolDefinition.stateConstructors) {
|
|
@@ -1416,10 +1470,11 @@ var Editor = class {
|
|
|
1416
1470
|
this.emitChange();
|
|
1417
1471
|
}
|
|
1418
1472
|
setViewport(partial) {
|
|
1473
|
+
const rawZoom = partial.zoom ?? this.viewport.zoom;
|
|
1419
1474
|
this.viewport = {
|
|
1420
1475
|
x: partial.x ?? this.viewport.x,
|
|
1421
1476
|
y: partial.y ?? this.viewport.y,
|
|
1422
|
-
zoom:
|
|
1477
|
+
zoom: Math.max(0.1, Math.min(4, rawZoom))
|
|
1423
1478
|
};
|
|
1424
1479
|
this.emitChange();
|
|
1425
1480
|
}
|
|
@@ -1437,7 +1492,9 @@ var Editor = class {
|
|
|
1437
1492
|
loadDocumentSnapshot(snapshot) {
|
|
1438
1493
|
const documentSnapshot = recordsToDocumentSnapshot(snapshot.records);
|
|
1439
1494
|
if (!documentSnapshot) return;
|
|
1440
|
-
this.
|
|
1495
|
+
this.runWithoutHistoryCapture(() => {
|
|
1496
|
+
this.store.loadSnapshot(documentSnapshot);
|
|
1497
|
+
});
|
|
1441
1498
|
}
|
|
1442
1499
|
getSessionStateSnapshot(args) {
|
|
1443
1500
|
return {
|
|
@@ -1475,12 +1532,92 @@ var Editor = class {
|
|
|
1475
1532
|
}
|
|
1476
1533
|
return [];
|
|
1477
1534
|
}
|
|
1535
|
+
getHistorySnapshot() {
|
|
1536
|
+
return {
|
|
1537
|
+
version: 1,
|
|
1538
|
+
undoStack: this.undoStack.map(cloneDocumentSnapshot),
|
|
1539
|
+
redoStack: this.redoStack.map(cloneDocumentSnapshot)
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
loadHistorySnapshot(snapshot) {
|
|
1543
|
+
if (!snapshot || snapshot.version !== 1) return;
|
|
1544
|
+
this.undoStack = snapshot.undoStack.map(cloneDocumentSnapshot).slice(-MAX_HISTORY_ENTRIES);
|
|
1545
|
+
this.redoStack = snapshot.redoStack.map(cloneDocumentSnapshot).slice(-MAX_HISTORY_ENTRIES);
|
|
1546
|
+
this.emitHistoryChange();
|
|
1547
|
+
}
|
|
1548
|
+
clearRedoHistory() {
|
|
1549
|
+
if (this.redoStack.length === 0) return;
|
|
1550
|
+
this.redoStack = [];
|
|
1551
|
+
this.emitHistoryChange();
|
|
1552
|
+
}
|
|
1553
|
+
beginHistoryEntry() {
|
|
1554
|
+
if (this.historyBatchDepth === 0) {
|
|
1555
|
+
this.historyBatchStartSnapshot = cloneDocumentSnapshot(this.lastDocumentSnapshot);
|
|
1556
|
+
this.historyBatchChanged = false;
|
|
1557
|
+
}
|
|
1558
|
+
this.historyBatchDepth += 1;
|
|
1559
|
+
}
|
|
1560
|
+
endHistoryEntry() {
|
|
1561
|
+
if (this.historyBatchDepth === 0) return;
|
|
1562
|
+
this.historyBatchDepth -= 1;
|
|
1563
|
+
if (this.historyBatchDepth > 0) return;
|
|
1564
|
+
const startSnapshot = this.historyBatchStartSnapshot;
|
|
1565
|
+
this.historyBatchStartSnapshot = null;
|
|
1566
|
+
if (!startSnapshot) return;
|
|
1567
|
+
const endSnapshot = this.getDocumentSnapshot();
|
|
1568
|
+
this.lastDocumentSnapshot = endSnapshot;
|
|
1569
|
+
const didDocumentChange = this.historyBatchChanged || !areDocumentSnapshotsEqual(startSnapshot, endSnapshot);
|
|
1570
|
+
this.historyBatchChanged = false;
|
|
1571
|
+
if (!didDocumentChange) return;
|
|
1572
|
+
this.undoStack.push(cloneDocumentSnapshot(startSnapshot));
|
|
1573
|
+
if (this.undoStack.length > MAX_HISTORY_ENTRIES) {
|
|
1574
|
+
this.undoStack.splice(0, this.undoStack.length - MAX_HISTORY_ENTRIES);
|
|
1575
|
+
}
|
|
1576
|
+
this.redoStack = [];
|
|
1577
|
+
this.emitHistoryChange();
|
|
1578
|
+
}
|
|
1579
|
+
canUndo() {
|
|
1580
|
+
return this.undoStack.length > 0;
|
|
1581
|
+
}
|
|
1582
|
+
canRedo() {
|
|
1583
|
+
return this.redoStack.length > 0;
|
|
1584
|
+
}
|
|
1585
|
+
undo() {
|
|
1586
|
+
const previousSnapshot = this.undoStack.pop();
|
|
1587
|
+
if (!previousSnapshot) return false;
|
|
1588
|
+
const currentSnapshot = this.getDocumentSnapshot();
|
|
1589
|
+
this.redoStack.push(cloneDocumentSnapshot(currentSnapshot));
|
|
1590
|
+
if (this.redoStack.length > MAX_HISTORY_ENTRIES) {
|
|
1591
|
+
this.redoStack.splice(0, this.redoStack.length - MAX_HISTORY_ENTRIES);
|
|
1592
|
+
}
|
|
1593
|
+
this.loadDocumentSnapshot(previousSnapshot);
|
|
1594
|
+
this.emitHistoryChange();
|
|
1595
|
+
return true;
|
|
1596
|
+
}
|
|
1597
|
+
redo() {
|
|
1598
|
+
const nextSnapshot = this.redoStack.pop();
|
|
1599
|
+
if (!nextSnapshot) return false;
|
|
1600
|
+
const currentSnapshot = this.getDocumentSnapshot();
|
|
1601
|
+
this.undoStack.push(cloneDocumentSnapshot(currentSnapshot));
|
|
1602
|
+
if (this.undoStack.length > MAX_HISTORY_ENTRIES) {
|
|
1603
|
+
this.undoStack.splice(0, this.undoStack.length - MAX_HISTORY_ENTRIES);
|
|
1604
|
+
}
|
|
1605
|
+
this.loadDocumentSnapshot(nextSnapshot);
|
|
1606
|
+
this.emitHistoryChange();
|
|
1607
|
+
return true;
|
|
1608
|
+
}
|
|
1478
1609
|
listen(listener) {
|
|
1479
1610
|
this.listeners.add(listener);
|
|
1480
1611
|
return () => {
|
|
1481
1612
|
this.listeners.delete(listener);
|
|
1482
1613
|
};
|
|
1483
1614
|
}
|
|
1615
|
+
listenHistory(listener) {
|
|
1616
|
+
this.historyListeners.add(listener);
|
|
1617
|
+
return () => {
|
|
1618
|
+
this.historyListeners.delete(listener);
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1484
1621
|
// Convert screen coords to page coords
|
|
1485
1622
|
screenToPage(screenX, screenY) {
|
|
1486
1623
|
return screenToPage(this.viewport, screenX, screenY);
|
|
@@ -1497,6 +1634,21 @@ var Editor = class {
|
|
|
1497
1634
|
listener();
|
|
1498
1635
|
}
|
|
1499
1636
|
}
|
|
1637
|
+
emitHistoryChange() {
|
|
1638
|
+
for (const listener of this.historyListeners) {
|
|
1639
|
+
listener();
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
runWithoutHistoryCapture(fn) {
|
|
1643
|
+
const previousValue = this.suppressHistoryCapture;
|
|
1644
|
+
this.suppressHistoryCapture = true;
|
|
1645
|
+
try {
|
|
1646
|
+
fn();
|
|
1647
|
+
} finally {
|
|
1648
|
+
this.suppressHistoryCapture = previousValue;
|
|
1649
|
+
this.lastDocumentSnapshot = this.getDocumentSnapshot();
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1500
1652
|
};
|
|
1501
1653
|
|
|
1502
1654
|
// src/tools/select/selectHelpers.ts
|