@fieldnotes/core 0.14.0 → 0.16.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 +259 -50
- package/dist/index.d.cts +33 -3
- package/dist/index.d.ts +33 -3
- package/dist/index.js +259 -50
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1084,6 +1084,14 @@ var InputHandler = class {
|
|
|
1084
1084
|
e.preventDefault();
|
|
1085
1085
|
this.handlePaste();
|
|
1086
1086
|
}
|
|
1087
|
+
if (e.key === "]") {
|
|
1088
|
+
e.preventDefault();
|
|
1089
|
+
this.handleZOrder(e.ctrlKey || e.metaKey ? "front" : "forward");
|
|
1090
|
+
}
|
|
1091
|
+
if (e.key === "[") {
|
|
1092
|
+
e.preventDefault();
|
|
1093
|
+
this.handleZOrder(e.ctrlKey || e.metaKey ? "back" : "backward");
|
|
1094
|
+
}
|
|
1087
1095
|
};
|
|
1088
1096
|
onKeyUp = (e) => {
|
|
1089
1097
|
if (e.key === " ") {
|
|
@@ -1260,6 +1268,33 @@ var InputHandler = class {
|
|
|
1260
1268
|
selectTool.setSelection(newIds);
|
|
1261
1269
|
this.toolContext.requestRender();
|
|
1262
1270
|
}
|
|
1271
|
+
handleZOrder(operation) {
|
|
1272
|
+
if (!this.toolManager || !this.toolContext) return;
|
|
1273
|
+
const tool = this.toolManager.activeTool;
|
|
1274
|
+
if (tool?.name !== "select") return;
|
|
1275
|
+
const selectTool = tool;
|
|
1276
|
+
const ids = selectTool.selectedIds;
|
|
1277
|
+
if (ids.length === 0) return;
|
|
1278
|
+
this.historyRecorder?.begin();
|
|
1279
|
+
for (const id of ids) {
|
|
1280
|
+
switch (operation) {
|
|
1281
|
+
case "forward":
|
|
1282
|
+
this.toolContext.store.bringForward(id);
|
|
1283
|
+
break;
|
|
1284
|
+
case "backward":
|
|
1285
|
+
this.toolContext.store.sendBackward(id);
|
|
1286
|
+
break;
|
|
1287
|
+
case "front":
|
|
1288
|
+
this.toolContext.store.bringToFront(id);
|
|
1289
|
+
break;
|
|
1290
|
+
case "back":
|
|
1291
|
+
this.toolContext.store.sendToBack(id);
|
|
1292
|
+
break;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
this.historyRecorder?.commit();
|
|
1296
|
+
this.toolContext.requestRender();
|
|
1297
|
+
}
|
|
1263
1298
|
cancelToolIfActive(e) {
|
|
1264
1299
|
if (this.isToolActive) {
|
|
1265
1300
|
this.dispatchToolUp(e);
|
|
@@ -1556,9 +1591,13 @@ var ElementStore = class {
|
|
|
1556
1591
|
layerOrderMap = /* @__PURE__ */ new Map();
|
|
1557
1592
|
spatialIndex = new Quadtree({ x: -1e5, y: -1e5, w: 2e5, h: 2e5 });
|
|
1558
1593
|
sortedCache = null;
|
|
1594
|
+
_versions = /* @__PURE__ */ new Map();
|
|
1559
1595
|
get count() {
|
|
1560
1596
|
return this.elements.size;
|
|
1561
1597
|
}
|
|
1598
|
+
getVersion(id) {
|
|
1599
|
+
return this._versions.get(id) ?? -1;
|
|
1600
|
+
}
|
|
1562
1601
|
setLayerOrder(order) {
|
|
1563
1602
|
this.layerOrderMap = new Map(order);
|
|
1564
1603
|
this.sortedCache = null;
|
|
@@ -1583,6 +1622,7 @@ var ElementStore = class {
|
|
|
1583
1622
|
}
|
|
1584
1623
|
add(element) {
|
|
1585
1624
|
this.sortedCache = null;
|
|
1625
|
+
this._versions.set(element.id, 0);
|
|
1586
1626
|
this.elements.set(element.id, element);
|
|
1587
1627
|
const bounds = getElementBounds(element);
|
|
1588
1628
|
if (bounds) this.spatialIndex.insert(element.id, bounds);
|
|
@@ -1592,6 +1632,7 @@ var ElementStore = class {
|
|
|
1592
1632
|
const existing = this.elements.get(id);
|
|
1593
1633
|
if (!existing) return;
|
|
1594
1634
|
this.sortedCache = null;
|
|
1635
|
+
this._versions.set(id, (this._versions.get(id) ?? 0) + 1);
|
|
1595
1636
|
const updated = { ...existing, ...partial, id: existing.id, type: existing.type };
|
|
1596
1637
|
if (updated.type === "arrow") {
|
|
1597
1638
|
const arrow = updated;
|
|
@@ -1611,12 +1652,14 @@ var ElementStore = class {
|
|
|
1611
1652
|
const element = this.elements.get(id);
|
|
1612
1653
|
if (!element) return;
|
|
1613
1654
|
this.sortedCache = null;
|
|
1655
|
+
this._versions.delete(id);
|
|
1614
1656
|
this.elements.delete(id);
|
|
1615
1657
|
this.spatialIndex.remove(id);
|
|
1616
1658
|
this.bus.emit("remove", element);
|
|
1617
1659
|
}
|
|
1618
1660
|
clear() {
|
|
1619
1661
|
this.sortedCache = null;
|
|
1662
|
+
this._versions.clear();
|
|
1620
1663
|
this.elements.clear();
|
|
1621
1664
|
this.spatialIndex.clear();
|
|
1622
1665
|
this.bus.emit("clear", null);
|
|
@@ -1626,10 +1669,12 @@ var ElementStore = class {
|
|
|
1626
1669
|
}
|
|
1627
1670
|
loadSnapshot(elements) {
|
|
1628
1671
|
this.sortedCache = null;
|
|
1672
|
+
this._versions.clear();
|
|
1629
1673
|
this.elements.clear();
|
|
1630
1674
|
this.spatialIndex.clear();
|
|
1631
1675
|
for (const el of elements) {
|
|
1632
1676
|
this.elements.set(el.id, el);
|
|
1677
|
+
this._versions.set(el.id, 0);
|
|
1633
1678
|
const bounds = getElementBounds(el);
|
|
1634
1679
|
if (bounds) this.spatialIndex.insert(el.id, bounds);
|
|
1635
1680
|
}
|
|
@@ -1638,6 +1683,54 @@ var ElementStore = class {
|
|
|
1638
1683
|
this.bus.emit("add", el);
|
|
1639
1684
|
}
|
|
1640
1685
|
}
|
|
1686
|
+
bringToFront(id) {
|
|
1687
|
+
const el = this.elements.get(id);
|
|
1688
|
+
if (!el) return;
|
|
1689
|
+
const siblings = [...this.elements.values()].filter(
|
|
1690
|
+
(e) => e.layerId === el.layerId && e.id !== id
|
|
1691
|
+
);
|
|
1692
|
+
if (siblings.length === 0) return;
|
|
1693
|
+
const maxZ = Math.max(...siblings.map((e) => e.zIndex));
|
|
1694
|
+
if (el.zIndex >= maxZ) return;
|
|
1695
|
+
this.update(id, { zIndex: maxZ + 1 });
|
|
1696
|
+
}
|
|
1697
|
+
sendToBack(id) {
|
|
1698
|
+
const el = this.elements.get(id);
|
|
1699
|
+
if (!el) return;
|
|
1700
|
+
const siblings = [...this.elements.values()].filter(
|
|
1701
|
+
(e) => e.layerId === el.layerId && e.id !== id
|
|
1702
|
+
);
|
|
1703
|
+
if (siblings.length === 0) return;
|
|
1704
|
+
const minZ = Math.min(...siblings.map((e) => e.zIndex));
|
|
1705
|
+
if (el.zIndex <= minZ) return;
|
|
1706
|
+
this.update(id, { zIndex: minZ - 1 });
|
|
1707
|
+
}
|
|
1708
|
+
bringForward(id) {
|
|
1709
|
+
const el = this.elements.get(id);
|
|
1710
|
+
if (!el) return;
|
|
1711
|
+
const sorted = [...this.elements.values()].filter((e) => e.layerId === el.layerId).sort((a, b) => a.zIndex - b.zIndex);
|
|
1712
|
+
const idx = sorted.findIndex((e) => e.id === id);
|
|
1713
|
+
if (idx < 0 || idx >= sorted.length - 1) return;
|
|
1714
|
+
const next = sorted[idx + 1];
|
|
1715
|
+
if (!next) return;
|
|
1716
|
+
const myZ = el.zIndex;
|
|
1717
|
+
const nextZ = next.zIndex;
|
|
1718
|
+
this.update(id, { zIndex: nextZ });
|
|
1719
|
+
this.update(next.id, { zIndex: myZ });
|
|
1720
|
+
}
|
|
1721
|
+
sendBackward(id) {
|
|
1722
|
+
const el = this.elements.get(id);
|
|
1723
|
+
if (!el) return;
|
|
1724
|
+
const sorted = [...this.elements.values()].filter((e) => e.layerId === el.layerId).sort((a, b) => a.zIndex - b.zIndex);
|
|
1725
|
+
const idx = sorted.findIndex((e) => e.id === id);
|
|
1726
|
+
if (idx <= 0) return;
|
|
1727
|
+
const prev = sorted[idx - 1];
|
|
1728
|
+
if (!prev) return;
|
|
1729
|
+
const myZ = el.zIndex;
|
|
1730
|
+
const prevZ = prev.zIndex;
|
|
1731
|
+
this.update(id, { zIndex: prevZ });
|
|
1732
|
+
this.update(prev.id, { zIndex: myZ });
|
|
1733
|
+
}
|
|
1641
1734
|
queryRect(rect) {
|
|
1642
1735
|
const ids = this.spatialIndex.query(rect);
|
|
1643
1736
|
const elements = [];
|
|
@@ -3309,16 +3402,64 @@ var BatchCommand = class {
|
|
|
3309
3402
|
}
|
|
3310
3403
|
};
|
|
3311
3404
|
|
|
3405
|
+
// src/history/layer-commands.ts
|
|
3406
|
+
var CreateLayerCommand = class {
|
|
3407
|
+
constructor(manager, layer) {
|
|
3408
|
+
this.manager = manager;
|
|
3409
|
+
this.layer = layer;
|
|
3410
|
+
}
|
|
3411
|
+
execute(_store) {
|
|
3412
|
+
this.manager.addLayerDirect(this.layer);
|
|
3413
|
+
}
|
|
3414
|
+
undo(_store) {
|
|
3415
|
+
this.manager.removeLayerDirect(this.layer.id);
|
|
3416
|
+
}
|
|
3417
|
+
};
|
|
3418
|
+
var RemoveLayerCommand = class {
|
|
3419
|
+
constructor(manager, layer) {
|
|
3420
|
+
this.manager = manager;
|
|
3421
|
+
this.layer = layer;
|
|
3422
|
+
}
|
|
3423
|
+
execute(_store) {
|
|
3424
|
+
this.manager.removeLayerDirect(this.layer.id);
|
|
3425
|
+
}
|
|
3426
|
+
undo(_store) {
|
|
3427
|
+
this.manager.addLayerDirect(this.layer);
|
|
3428
|
+
}
|
|
3429
|
+
};
|
|
3430
|
+
var UpdateLayerCommand = class {
|
|
3431
|
+
constructor(manager, layerId, previous, current) {
|
|
3432
|
+
this.manager = manager;
|
|
3433
|
+
this.layerId = layerId;
|
|
3434
|
+
this.previous = previous;
|
|
3435
|
+
this.current = current;
|
|
3436
|
+
}
|
|
3437
|
+
execute(_store) {
|
|
3438
|
+
this.manager.updateLayerDirect(this.layerId, { ...this.current });
|
|
3439
|
+
}
|
|
3440
|
+
undo(_store) {
|
|
3441
|
+
this.manager.updateLayerDirect(this.layerId, { ...this.previous });
|
|
3442
|
+
}
|
|
3443
|
+
};
|
|
3444
|
+
|
|
3312
3445
|
// src/history/history-recorder.ts
|
|
3313
3446
|
var HistoryRecorder = class {
|
|
3314
|
-
constructor(store, stack) {
|
|
3447
|
+
constructor(store, stack, layerManager) {
|
|
3315
3448
|
this.store = store;
|
|
3316
3449
|
this.stack = stack;
|
|
3450
|
+
this.layerManager = layerManager;
|
|
3317
3451
|
this.unsubscribers = [
|
|
3318
3452
|
store.on("add", (el) => this.onAdd(el)),
|
|
3319
3453
|
store.on("remove", (el) => this.onRemove(el)),
|
|
3320
3454
|
store.on("update", ({ previous, current }) => this.onUpdate(previous, current))
|
|
3321
3455
|
];
|
|
3456
|
+
if (layerManager) {
|
|
3457
|
+
this.unsubscribers.push(
|
|
3458
|
+
layerManager.on("create", (layer) => this.onLayerCreate(layer)),
|
|
3459
|
+
layerManager.on("remove", (layer) => this.onLayerRemove(layer)),
|
|
3460
|
+
layerManager.on("update", ({ previous, current }) => this.onLayerUpdate(previous, current))
|
|
3461
|
+
);
|
|
3462
|
+
}
|
|
3322
3463
|
}
|
|
3323
3464
|
recording = true;
|
|
3324
3465
|
transaction = null;
|
|
@@ -3379,6 +3520,21 @@ var HistoryRecorder = class {
|
|
|
3379
3520
|
this.stack.push(new UpdateElementCommand(current.id, previous, current));
|
|
3380
3521
|
}
|
|
3381
3522
|
}
|
|
3523
|
+
onLayerCreate(layer) {
|
|
3524
|
+
if (!this.recording) return;
|
|
3525
|
+
if (!this.layerManager) return;
|
|
3526
|
+
this.record(new CreateLayerCommand(this.layerManager, layer));
|
|
3527
|
+
}
|
|
3528
|
+
onLayerRemove(layer) {
|
|
3529
|
+
if (!this.recording) return;
|
|
3530
|
+
if (!this.layerManager) return;
|
|
3531
|
+
this.record(new RemoveLayerCommand(this.layerManager, layer));
|
|
3532
|
+
}
|
|
3533
|
+
onLayerUpdate(previous, current) {
|
|
3534
|
+
if (!this.recording) return;
|
|
3535
|
+
if (!this.layerManager) return;
|
|
3536
|
+
this.record(new UpdateLayerCommand(this.layerManager, current.id, previous, current));
|
|
3537
|
+
}
|
|
3382
3538
|
flushUpdateSnapshots() {
|
|
3383
3539
|
const commands = [];
|
|
3384
3540
|
for (const [id, previous] of this.updateSnapshots) {
|
|
@@ -3811,18 +3967,23 @@ var LayerManager = class {
|
|
|
3811
3967
|
addLayerDirect(layer) {
|
|
3812
3968
|
this.layers.set(layer.id, { ...layer });
|
|
3813
3969
|
this.syncLayerOrder();
|
|
3970
|
+
this.bus.emit("create", { ...layer });
|
|
3814
3971
|
this.bus.emit("change", null);
|
|
3815
3972
|
}
|
|
3816
3973
|
removeLayerDirect(id) {
|
|
3974
|
+
const layer = this.layers.get(id);
|
|
3817
3975
|
this.layers.delete(id);
|
|
3818
3976
|
this.syncLayerOrder();
|
|
3977
|
+
if (layer) this.bus.emit("remove", { ...layer });
|
|
3819
3978
|
this.bus.emit("change", null);
|
|
3820
3979
|
}
|
|
3821
3980
|
updateLayerDirect(id, props) {
|
|
3822
3981
|
const layer = this.layers.get(id);
|
|
3823
3982
|
if (!layer) return;
|
|
3983
|
+
const previous = { ...layer };
|
|
3824
3984
|
Object.assign(layer, props);
|
|
3825
3985
|
if ("order" in props) this.syncLayerOrder();
|
|
3986
|
+
this.bus.emit("update", { previous, current: { ...layer } });
|
|
3826
3987
|
this.bus.emit("change", null);
|
|
3827
3988
|
}
|
|
3828
3989
|
syncLayerOrder() {
|
|
@@ -3900,10 +4061,14 @@ var DomNodeManager = class {
|
|
|
3900
4061
|
domLayer;
|
|
3901
4062
|
onEditRequest;
|
|
3902
4063
|
isEditingElement;
|
|
4064
|
+
getVersion;
|
|
4065
|
+
lastSyncedVersion = /* @__PURE__ */ new Map();
|
|
4066
|
+
lastSyncedZIndex = /* @__PURE__ */ new Map();
|
|
3903
4067
|
constructor(deps) {
|
|
3904
4068
|
this.domLayer = deps.domLayer;
|
|
3905
4069
|
this.onEditRequest = deps.onEditRequest;
|
|
3906
4070
|
this.isEditingElement = deps.isEditingElement;
|
|
4071
|
+
this.getVersion = deps.getVersion ?? null;
|
|
3907
4072
|
}
|
|
3908
4073
|
getNode(id) {
|
|
3909
4074
|
return this.domNodes.get(id);
|
|
@@ -3911,6 +4076,20 @@ var DomNodeManager = class {
|
|
|
3911
4076
|
storeHtmlContent(elementId, dom) {
|
|
3912
4077
|
this.htmlContent.set(elementId, dom);
|
|
3913
4078
|
}
|
|
4079
|
+
hasContent(elementId) {
|
|
4080
|
+
return this.htmlContent.has(elementId);
|
|
4081
|
+
}
|
|
4082
|
+
resetHtmlContent(elementId) {
|
|
4083
|
+
this.htmlContent.delete(elementId);
|
|
4084
|
+
this.lastSyncedVersion.delete(elementId);
|
|
4085
|
+
this.lastSyncedZIndex.delete(elementId);
|
|
4086
|
+
const node = this.domNodes.get(elementId);
|
|
4087
|
+
if (!node) return;
|
|
4088
|
+
while (node.firstChild) {
|
|
4089
|
+
node.removeChild(node.firstChild);
|
|
4090
|
+
}
|
|
4091
|
+
delete node.dataset["initialized"];
|
|
4092
|
+
}
|
|
3914
4093
|
syncDomNode(element, zIndex = 0) {
|
|
3915
4094
|
let node = this.domNodes.get(element.id);
|
|
3916
4095
|
if (!node) {
|
|
@@ -3922,6 +4101,17 @@ var DomNodeManager = class {
|
|
|
3922
4101
|
});
|
|
3923
4102
|
this.domLayer.appendChild(node);
|
|
3924
4103
|
this.domNodes.set(element.id, node);
|
|
4104
|
+
} else if (this.getVersion) {
|
|
4105
|
+
const currentVersion = this.getVersion(element.id);
|
|
4106
|
+
const lastVersion = this.lastSyncedVersion.get(element.id);
|
|
4107
|
+
const lastZ = this.lastSyncedZIndex.get(element.id);
|
|
4108
|
+
if (lastVersion === currentVersion && lastZ === zIndex) {
|
|
4109
|
+
return;
|
|
4110
|
+
}
|
|
4111
|
+
}
|
|
4112
|
+
if (this.getVersion) {
|
|
4113
|
+
this.lastSyncedVersion.set(element.id, this.getVersion(element.id));
|
|
4114
|
+
this.lastSyncedZIndex.set(element.id, zIndex);
|
|
3925
4115
|
}
|
|
3926
4116
|
const size = "size" in element ? element.size : null;
|
|
3927
4117
|
Object.assign(node.style, {
|
|
@@ -3940,6 +4130,8 @@ var DomNodeManager = class {
|
|
|
3940
4130
|
}
|
|
3941
4131
|
removeDomNode(id) {
|
|
3942
4132
|
this.htmlContent.delete(id);
|
|
4133
|
+
this.lastSyncedVersion.delete(id);
|
|
4134
|
+
this.lastSyncedZIndex.delete(id);
|
|
3943
4135
|
const node = this.domNodes.get(id);
|
|
3944
4136
|
if (node) {
|
|
3945
4137
|
node.remove();
|
|
@@ -3950,6 +4142,8 @@ var DomNodeManager = class {
|
|
|
3950
4142
|
this.domNodes.forEach((node) => node.remove());
|
|
3951
4143
|
this.domNodes.clear();
|
|
3952
4144
|
this.htmlContent.clear();
|
|
4145
|
+
this.lastSyncedVersion.clear();
|
|
4146
|
+
this.lastSyncedZIndex.clear();
|
|
3953
4147
|
}
|
|
3954
4148
|
reattachHtmlContent(store) {
|
|
3955
4149
|
for (const el of store.getElementsByType("html")) {
|
|
@@ -4437,8 +4631,10 @@ var Viewport = class {
|
|
|
4437
4631
|
toolbar: options.toolbar
|
|
4438
4632
|
});
|
|
4439
4633
|
this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
|
|
4634
|
+
this.onHtmlElementMount = options.onHtmlElementMount;
|
|
4635
|
+
this.dropHandler = options.onDrop;
|
|
4440
4636
|
this.history = new HistoryStack();
|
|
4441
|
-
this.historyRecorder = new HistoryRecorder(this.store, this.history);
|
|
4637
|
+
this.historyRecorder = new HistoryRecorder(this.store, this.history, this.layerManager);
|
|
4442
4638
|
this.wrapper = this.createWrapper();
|
|
4443
4639
|
this.canvasEl = this.createCanvas();
|
|
4444
4640
|
this.domLayer = this.createDomLayer();
|
|
@@ -4469,7 +4665,8 @@ var Viewport = class {
|
|
|
4469
4665
|
this.domNodeManager = new DomNodeManager({
|
|
4470
4666
|
domLayer: this.domLayer,
|
|
4471
4667
|
onEditRequest: (id) => this.startEditingElement(id),
|
|
4472
|
-
isEditingElement: (id) => this.noteEditor.isEditing && this.noteEditor.editingElementId === id
|
|
4668
|
+
isEditingElement: (id) => this.noteEditor.isEditing && this.noteEditor.editingElementId === id,
|
|
4669
|
+
getVersion: (id) => this.store.getVersion(id)
|
|
4473
4670
|
});
|
|
4474
4671
|
this.interactMode = new InteractMode({
|
|
4475
4672
|
getNode: (id) => this.domNodeManager.getNode(id)
|
|
@@ -4557,6 +4754,8 @@ var Viewport = class {
|
|
|
4557
4754
|
renderLoop;
|
|
4558
4755
|
domNodeManager;
|
|
4559
4756
|
interactMode;
|
|
4757
|
+
onHtmlElementMount;
|
|
4758
|
+
dropHandler;
|
|
4560
4759
|
gridChangeListeners = /* @__PURE__ */ new Set();
|
|
4561
4760
|
doubleTapDetector = new DoubleTapDetector();
|
|
4562
4761
|
tapDownX = 0;
|
|
@@ -4600,6 +4799,22 @@ var Viewport = class {
|
|
|
4600
4799
|
this.layerManager.setActiveLayer(state.activeLayerId);
|
|
4601
4800
|
}
|
|
4602
4801
|
this.domNodeManager.reattachHtmlContent(this.store);
|
|
4802
|
+
if (this.onHtmlElementMount) {
|
|
4803
|
+
for (const el of this.store.getElementsByType("html")) {
|
|
4804
|
+
if (!this.domNodeManager.hasContent(el.id)) {
|
|
4805
|
+
this.domNodeManager.syncDomNode(el);
|
|
4806
|
+
const node = this.domNodeManager.getNode(el.id);
|
|
4807
|
+
if (node) {
|
|
4808
|
+
this.onHtmlElementMount(el.id, el.domId, node);
|
|
4809
|
+
node.dataset["initialized"] = "true";
|
|
4810
|
+
Object.assign(node.style, {
|
|
4811
|
+
overflow: "hidden",
|
|
4812
|
+
pointerEvents: el.interactive ? "auto" : "none"
|
|
4813
|
+
});
|
|
4814
|
+
}
|
|
4815
|
+
}
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4603
4818
|
this.history.clear();
|
|
4604
4819
|
this.historyRecorder.resume();
|
|
4605
4820
|
this.camera.moveTo(state.camera.position.x, state.camera.position.y);
|
|
@@ -4645,6 +4860,19 @@ var Viewport = class {
|
|
|
4645
4860
|
this.requestRender();
|
|
4646
4861
|
return el.id;
|
|
4647
4862
|
}
|
|
4863
|
+
removeLayer(id) {
|
|
4864
|
+
this.historyRecorder.begin();
|
|
4865
|
+
this.layerManager.removeLayer(id);
|
|
4866
|
+
this.historyRecorder.commit();
|
|
4867
|
+
}
|
|
4868
|
+
updateHtmlElement(id, newContent) {
|
|
4869
|
+
const el = this.store.getById(id);
|
|
4870
|
+
if (!el) throw new Error(`Element not found: ${id}`);
|
|
4871
|
+
if (el.type !== "html") throw new Error(`Element ${id} is not an HTML element`);
|
|
4872
|
+
this.domNodeManager.resetHtmlContent(id);
|
|
4873
|
+
this.domNodeManager.storeHtmlContent(id, newContent);
|
|
4874
|
+
this.requestRender();
|
|
4875
|
+
}
|
|
4648
4876
|
addGrid(input) {
|
|
4649
4877
|
const existing = this.store.getElementsByType("grid")[0];
|
|
4650
4878
|
this.historyRecorder.begin();
|
|
@@ -4796,17 +5024,21 @@ var Viewport = class {
|
|
|
4796
5024
|
};
|
|
4797
5025
|
onDrop = (e) => {
|
|
4798
5026
|
e.preventDefault();
|
|
5027
|
+
const rect = this.wrapper.getBoundingClientRect();
|
|
5028
|
+
const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
5029
|
+
const worldPos = this.camera.screenToWorld(screenPos);
|
|
5030
|
+
if (this.dropHandler) {
|
|
5031
|
+
this.dropHandler(e, worldPos);
|
|
5032
|
+
return;
|
|
5033
|
+
}
|
|
4799
5034
|
const files = e.dataTransfer?.files;
|
|
4800
5035
|
if (!files) return;
|
|
4801
|
-
const rect = this.wrapper.getBoundingClientRect();
|
|
4802
5036
|
for (const file of files) {
|
|
4803
5037
|
if (!file.type.startsWith("image/")) continue;
|
|
4804
5038
|
const reader = new FileReader();
|
|
4805
5039
|
reader.onload = () => {
|
|
4806
5040
|
const src = reader.result;
|
|
4807
5041
|
if (typeof src !== "string") return;
|
|
4808
|
-
const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
4809
|
-
const worldPos = this.camera.screenToWorld(screenPos);
|
|
4810
5042
|
this.addImage(src, worldPos);
|
|
4811
5043
|
};
|
|
4812
5044
|
reader.readAsDataURL(file);
|
|
@@ -5292,6 +5524,7 @@ var SelectTool = class {
|
|
|
5292
5524
|
ctx = null;
|
|
5293
5525
|
pendingSingleSelectId = null;
|
|
5294
5526
|
hasDragged = false;
|
|
5527
|
+
resizeAspectRatio = 0;
|
|
5295
5528
|
get selectedIds() {
|
|
5296
5529
|
return [...this._selectedIds];
|
|
5297
5530
|
}
|
|
@@ -5337,7 +5570,8 @@ var SelectTool = class {
|
|
|
5337
5570
|
const resizeHit = this.hitTestResizeHandle(world, ctx);
|
|
5338
5571
|
if (resizeHit) {
|
|
5339
5572
|
const el = ctx.store.getById(resizeHit.elementId);
|
|
5340
|
-
if (el) {
|
|
5573
|
+
if (el && "size" in el) {
|
|
5574
|
+
this.resizeAspectRatio = el.size.h > 0 ? el.size.w / el.size.h : 0;
|
|
5341
5575
|
this.mode = {
|
|
5342
5576
|
type: "resizing",
|
|
5343
5577
|
elementId: resizeHit.elementId,
|
|
@@ -5389,7 +5623,7 @@ var SelectTool = class {
|
|
|
5389
5623
|
}
|
|
5390
5624
|
if (this.mode.type === "resizing") {
|
|
5391
5625
|
ctx.setCursor?.(HANDLE_CURSORS[this.mode.handle]);
|
|
5392
|
-
this.handleResize(world, ctx);
|
|
5626
|
+
this.handleResize(world, ctx, state.shiftKey);
|
|
5393
5627
|
return;
|
|
5394
5628
|
}
|
|
5395
5629
|
if (this.mode.type === "dragging" && this._selectedIds.length > 0) {
|
|
@@ -5513,7 +5747,7 @@ var SelectTool = class {
|
|
|
5513
5747
|
const hit = this.hitTest(world, ctx);
|
|
5514
5748
|
ctx.setCursor?.(hit ? "move" : "default");
|
|
5515
5749
|
}
|
|
5516
|
-
handleResize(world, ctx) {
|
|
5750
|
+
handleResize(world, ctx, shiftKey = false) {
|
|
5517
5751
|
if (this.mode.type !== "resizing") return;
|
|
5518
5752
|
const el = ctx.store.getById(this.mode.elementId);
|
|
5519
5753
|
if (!el || !("size" in el) || el.locked) return;
|
|
@@ -5544,6 +5778,21 @@ var SelectTool = class {
|
|
|
5544
5778
|
h -= dy;
|
|
5545
5779
|
break;
|
|
5546
5780
|
}
|
|
5781
|
+
if (shiftKey && this.resizeAspectRatio > 0) {
|
|
5782
|
+
const absDw = Math.abs(w - el.size.w);
|
|
5783
|
+
const absDh = Math.abs(h - el.size.h);
|
|
5784
|
+
if (absDw >= absDh) {
|
|
5785
|
+
h = w / this.resizeAspectRatio;
|
|
5786
|
+
} else {
|
|
5787
|
+
w = h * this.resizeAspectRatio;
|
|
5788
|
+
}
|
|
5789
|
+
if (handle === "nw" || handle === "sw") {
|
|
5790
|
+
x = el.position.x + el.size.w - w;
|
|
5791
|
+
}
|
|
5792
|
+
if (handle === "nw" || handle === "ne") {
|
|
5793
|
+
y = el.position.y + el.size.h - h;
|
|
5794
|
+
}
|
|
5795
|
+
}
|
|
5547
5796
|
if (w < MIN_ELEMENT_SIZE) {
|
|
5548
5797
|
if (handle === "nw" || handle === "sw") x = el.position.x + el.size.w - MIN_ELEMENT_SIZE;
|
|
5549
5798
|
w = MIN_ELEMENT_SIZE;
|
|
@@ -6606,48 +6855,8 @@ var TemplateTool = class {
|
|
|
6606
6855
|
}
|
|
6607
6856
|
};
|
|
6608
6857
|
|
|
6609
|
-
// src/history/layer-commands.ts
|
|
6610
|
-
var CreateLayerCommand = class {
|
|
6611
|
-
constructor(manager, layer) {
|
|
6612
|
-
this.manager = manager;
|
|
6613
|
-
this.layer = layer;
|
|
6614
|
-
}
|
|
6615
|
-
execute(_store) {
|
|
6616
|
-
this.manager.addLayerDirect(this.layer);
|
|
6617
|
-
}
|
|
6618
|
-
undo(_store) {
|
|
6619
|
-
this.manager.removeLayerDirect(this.layer.id);
|
|
6620
|
-
}
|
|
6621
|
-
};
|
|
6622
|
-
var RemoveLayerCommand = class {
|
|
6623
|
-
constructor(manager, layer) {
|
|
6624
|
-
this.manager = manager;
|
|
6625
|
-
this.layer = layer;
|
|
6626
|
-
}
|
|
6627
|
-
execute(_store) {
|
|
6628
|
-
this.manager.removeLayerDirect(this.layer.id);
|
|
6629
|
-
}
|
|
6630
|
-
undo(_store) {
|
|
6631
|
-
this.manager.addLayerDirect(this.layer);
|
|
6632
|
-
}
|
|
6633
|
-
};
|
|
6634
|
-
var UpdateLayerCommand = class {
|
|
6635
|
-
constructor(manager, layerId, previous, current) {
|
|
6636
|
-
this.manager = manager;
|
|
6637
|
-
this.layerId = layerId;
|
|
6638
|
-
this.previous = previous;
|
|
6639
|
-
this.current = current;
|
|
6640
|
-
}
|
|
6641
|
-
execute(_store) {
|
|
6642
|
-
this.manager.updateLayerDirect(this.layerId, { ...this.current });
|
|
6643
|
-
}
|
|
6644
|
-
undo(_store) {
|
|
6645
|
-
this.manager.updateLayerDirect(this.layerId, { ...this.previous });
|
|
6646
|
-
}
|
|
6647
|
-
};
|
|
6648
|
-
|
|
6649
6858
|
// src/index.ts
|
|
6650
|
-
var VERSION = "0.
|
|
6859
|
+
var VERSION = "0.16.0";
|
|
6651
6860
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6652
6861
|
0 && (module.exports = {
|
|
6653
6862
|
AddElementCommand,
|
package/dist/index.d.cts
CHANGED
|
@@ -204,7 +204,9 @@ declare class ElementStore {
|
|
|
204
204
|
private layerOrderMap;
|
|
205
205
|
private spatialIndex;
|
|
206
206
|
private sortedCache;
|
|
207
|
+
private _versions;
|
|
207
208
|
get count(): number;
|
|
209
|
+
getVersion(id: string): number;
|
|
208
210
|
setLayerOrder(order: Map<string, number>): void;
|
|
209
211
|
getAll(): CanvasElement[];
|
|
210
212
|
getById(id: string): CanvasElement | undefined;
|
|
@@ -217,6 +219,10 @@ declare class ElementStore {
|
|
|
217
219
|
clear(): void;
|
|
218
220
|
snapshot(): CanvasElement[];
|
|
219
221
|
loadSnapshot(elements: CanvasElement[]): void;
|
|
222
|
+
bringToFront(id: string): void;
|
|
223
|
+
sendToBack(id: string): void;
|
|
224
|
+
bringForward(id: string): void;
|
|
225
|
+
sendBackward(id: string): void;
|
|
220
226
|
queryRect(rect: Bounds): CanvasElement[];
|
|
221
227
|
queryPoint(point: Point): CanvasElement[];
|
|
222
228
|
on<K extends keyof ElementStoreEvents>(event: K, listener: (data: ElementStoreEvents[K]) => void): () => void;
|
|
@@ -264,6 +270,15 @@ declare function snapPoint(point: Point, gridSize: number): Point;
|
|
|
264
270
|
declare function snapToHexCenter(point: Point, cellSize: number, orientation: HexOrientation): Point;
|
|
265
271
|
declare function smartSnap(point: Point, ctx: ToolContext): Point;
|
|
266
272
|
|
|
273
|
+
interface LayerManagerEvents {
|
|
274
|
+
change: null;
|
|
275
|
+
create: Layer;
|
|
276
|
+
remove: Layer;
|
|
277
|
+
update: {
|
|
278
|
+
previous: Layer;
|
|
279
|
+
current: Layer;
|
|
280
|
+
};
|
|
281
|
+
}
|
|
267
282
|
declare class LayerManager {
|
|
268
283
|
private readonly store;
|
|
269
284
|
private layers;
|
|
@@ -287,7 +302,7 @@ declare class LayerManager {
|
|
|
287
302
|
moveElementToLayer(elementId: string, layerId: string): void;
|
|
288
303
|
snapshot(): Layer[];
|
|
289
304
|
loadSnapshot(layers: Layer[]): void;
|
|
290
|
-
on(event:
|
|
305
|
+
on<K extends keyof LayerManagerEvents>(event: K, callback: (data: LayerManagerEvents[K]) => void): () => void;
|
|
291
306
|
addLayerDirect(layer: Layer): void;
|
|
292
307
|
removeLayerDirect(id: string): void;
|
|
293
308
|
updateLayerDirect(id: string, props: Omit<Partial<Layer>, 'id'>): void;
|
|
@@ -393,11 +408,12 @@ declare class HistoryStack {
|
|
|
393
408
|
declare class HistoryRecorder {
|
|
394
409
|
private readonly store;
|
|
395
410
|
private readonly stack;
|
|
411
|
+
private readonly layerManager?;
|
|
396
412
|
private recording;
|
|
397
413
|
private transaction;
|
|
398
414
|
private updateSnapshots;
|
|
399
415
|
private unsubscribers;
|
|
400
|
-
constructor(store: ElementStore, stack: HistoryStack);
|
|
416
|
+
constructor(store: ElementStore, stack: HistoryStack, layerManager?: LayerManager | undefined);
|
|
401
417
|
pause(): void;
|
|
402
418
|
resume(): void;
|
|
403
419
|
begin(): void;
|
|
@@ -408,6 +424,9 @@ declare class HistoryRecorder {
|
|
|
408
424
|
private onAdd;
|
|
409
425
|
private onRemove;
|
|
410
426
|
private onUpdate;
|
|
427
|
+
private onLayerCreate;
|
|
428
|
+
private onLayerRemove;
|
|
429
|
+
private onLayerUpdate;
|
|
411
430
|
private flushUpdateSnapshots;
|
|
412
431
|
}
|
|
413
432
|
|
|
@@ -462,6 +481,7 @@ declare class InputHandler {
|
|
|
462
481
|
private handleRedo;
|
|
463
482
|
private handleCopy;
|
|
464
483
|
private handlePaste;
|
|
484
|
+
private handleZOrder;
|
|
465
485
|
private cancelToolIfActive;
|
|
466
486
|
}
|
|
467
487
|
|
|
@@ -552,6 +572,11 @@ interface ViewportOptions {
|
|
|
552
572
|
background?: BackgroundOptions;
|
|
553
573
|
fontSizePresets?: FontSizePreset[];
|
|
554
574
|
toolbar?: boolean;
|
|
575
|
+
onHtmlElementMount?: (elementId: string, domId: string | undefined, container: HTMLDivElement) => void;
|
|
576
|
+
onDrop?: (event: DragEvent, worldPosition: {
|
|
577
|
+
x: number;
|
|
578
|
+
y: number;
|
|
579
|
+
}) => void;
|
|
555
580
|
}
|
|
556
581
|
declare class Viewport {
|
|
557
582
|
private readonly container;
|
|
@@ -577,6 +602,8 @@ declare class Viewport {
|
|
|
577
602
|
private readonly renderLoop;
|
|
578
603
|
private readonly domNodeManager;
|
|
579
604
|
private readonly interactMode;
|
|
605
|
+
private readonly onHtmlElementMount?;
|
|
606
|
+
private readonly dropHandler?;
|
|
580
607
|
private readonly gridChangeListeners;
|
|
581
608
|
private readonly doubleTapDetector;
|
|
582
609
|
private tapDownX;
|
|
@@ -607,6 +634,8 @@ declare class Viewport {
|
|
|
607
634
|
w: number;
|
|
608
635
|
h: number;
|
|
609
636
|
}): string;
|
|
637
|
+
removeLayer(id: string): void;
|
|
638
|
+
updateHtmlElement(id: string, newContent: HTMLElement): void;
|
|
610
639
|
addGrid(input: {
|
|
611
640
|
gridType?: 'square' | 'hex';
|
|
612
641
|
hexOrientation?: 'pointy' | 'flat';
|
|
@@ -935,6 +964,7 @@ declare class SelectTool implements Tool {
|
|
|
935
964
|
private ctx;
|
|
936
965
|
private pendingSingleSelectId;
|
|
937
966
|
private hasDragged;
|
|
967
|
+
private resizeAspectRatio;
|
|
938
968
|
get selectedIds(): string[];
|
|
939
969
|
setSelection(ids: string[]): void;
|
|
940
970
|
get isMarqueeActive(): boolean;
|
|
@@ -1181,6 +1211,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1181
1211
|
undo(_store: ElementStore): void;
|
|
1182
1212
|
}
|
|
1183
1213
|
|
|
1184
|
-
declare const VERSION = "0.
|
|
1214
|
+
declare const VERSION = "0.16.0";
|
|
1185
1215
|
|
|
1186
1216
|
export { type ActiveFormats, AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, DEFAULT_FONT_SIZE_PRESETS, DEFAULT_NOTE_FONT_SIZE, DoubleTapDetector, type DoubleTapDetectorOptions, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FilterAction, type FilteredEvent, type FilteredUpEvent, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputFilter, InputHandler, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, NoteEditor, type NoteEditorOptions, type NoteElement, NoteTool, type NoteToolOptions, NoteToolbar, PencilTool, type PencilToolOptions, type Point, type PointerState, Quadtree, RemoveElementCommand, RemoveLayerCommand, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type StyledRun, type TemplateElement, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, boundsIntersect, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportState, findBindTarget, findBoundArrows, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
|
package/dist/index.d.ts
CHANGED
|
@@ -204,7 +204,9 @@ declare class ElementStore {
|
|
|
204
204
|
private layerOrderMap;
|
|
205
205
|
private spatialIndex;
|
|
206
206
|
private sortedCache;
|
|
207
|
+
private _versions;
|
|
207
208
|
get count(): number;
|
|
209
|
+
getVersion(id: string): number;
|
|
208
210
|
setLayerOrder(order: Map<string, number>): void;
|
|
209
211
|
getAll(): CanvasElement[];
|
|
210
212
|
getById(id: string): CanvasElement | undefined;
|
|
@@ -217,6 +219,10 @@ declare class ElementStore {
|
|
|
217
219
|
clear(): void;
|
|
218
220
|
snapshot(): CanvasElement[];
|
|
219
221
|
loadSnapshot(elements: CanvasElement[]): void;
|
|
222
|
+
bringToFront(id: string): void;
|
|
223
|
+
sendToBack(id: string): void;
|
|
224
|
+
bringForward(id: string): void;
|
|
225
|
+
sendBackward(id: string): void;
|
|
220
226
|
queryRect(rect: Bounds): CanvasElement[];
|
|
221
227
|
queryPoint(point: Point): CanvasElement[];
|
|
222
228
|
on<K extends keyof ElementStoreEvents>(event: K, listener: (data: ElementStoreEvents[K]) => void): () => void;
|
|
@@ -264,6 +270,15 @@ declare function snapPoint(point: Point, gridSize: number): Point;
|
|
|
264
270
|
declare function snapToHexCenter(point: Point, cellSize: number, orientation: HexOrientation): Point;
|
|
265
271
|
declare function smartSnap(point: Point, ctx: ToolContext): Point;
|
|
266
272
|
|
|
273
|
+
interface LayerManagerEvents {
|
|
274
|
+
change: null;
|
|
275
|
+
create: Layer;
|
|
276
|
+
remove: Layer;
|
|
277
|
+
update: {
|
|
278
|
+
previous: Layer;
|
|
279
|
+
current: Layer;
|
|
280
|
+
};
|
|
281
|
+
}
|
|
267
282
|
declare class LayerManager {
|
|
268
283
|
private readonly store;
|
|
269
284
|
private layers;
|
|
@@ -287,7 +302,7 @@ declare class LayerManager {
|
|
|
287
302
|
moveElementToLayer(elementId: string, layerId: string): void;
|
|
288
303
|
snapshot(): Layer[];
|
|
289
304
|
loadSnapshot(layers: Layer[]): void;
|
|
290
|
-
on(event:
|
|
305
|
+
on<K extends keyof LayerManagerEvents>(event: K, callback: (data: LayerManagerEvents[K]) => void): () => void;
|
|
291
306
|
addLayerDirect(layer: Layer): void;
|
|
292
307
|
removeLayerDirect(id: string): void;
|
|
293
308
|
updateLayerDirect(id: string, props: Omit<Partial<Layer>, 'id'>): void;
|
|
@@ -393,11 +408,12 @@ declare class HistoryStack {
|
|
|
393
408
|
declare class HistoryRecorder {
|
|
394
409
|
private readonly store;
|
|
395
410
|
private readonly stack;
|
|
411
|
+
private readonly layerManager?;
|
|
396
412
|
private recording;
|
|
397
413
|
private transaction;
|
|
398
414
|
private updateSnapshots;
|
|
399
415
|
private unsubscribers;
|
|
400
|
-
constructor(store: ElementStore, stack: HistoryStack);
|
|
416
|
+
constructor(store: ElementStore, stack: HistoryStack, layerManager?: LayerManager | undefined);
|
|
401
417
|
pause(): void;
|
|
402
418
|
resume(): void;
|
|
403
419
|
begin(): void;
|
|
@@ -408,6 +424,9 @@ declare class HistoryRecorder {
|
|
|
408
424
|
private onAdd;
|
|
409
425
|
private onRemove;
|
|
410
426
|
private onUpdate;
|
|
427
|
+
private onLayerCreate;
|
|
428
|
+
private onLayerRemove;
|
|
429
|
+
private onLayerUpdate;
|
|
411
430
|
private flushUpdateSnapshots;
|
|
412
431
|
}
|
|
413
432
|
|
|
@@ -462,6 +481,7 @@ declare class InputHandler {
|
|
|
462
481
|
private handleRedo;
|
|
463
482
|
private handleCopy;
|
|
464
483
|
private handlePaste;
|
|
484
|
+
private handleZOrder;
|
|
465
485
|
private cancelToolIfActive;
|
|
466
486
|
}
|
|
467
487
|
|
|
@@ -552,6 +572,11 @@ interface ViewportOptions {
|
|
|
552
572
|
background?: BackgroundOptions;
|
|
553
573
|
fontSizePresets?: FontSizePreset[];
|
|
554
574
|
toolbar?: boolean;
|
|
575
|
+
onHtmlElementMount?: (elementId: string, domId: string | undefined, container: HTMLDivElement) => void;
|
|
576
|
+
onDrop?: (event: DragEvent, worldPosition: {
|
|
577
|
+
x: number;
|
|
578
|
+
y: number;
|
|
579
|
+
}) => void;
|
|
555
580
|
}
|
|
556
581
|
declare class Viewport {
|
|
557
582
|
private readonly container;
|
|
@@ -577,6 +602,8 @@ declare class Viewport {
|
|
|
577
602
|
private readonly renderLoop;
|
|
578
603
|
private readonly domNodeManager;
|
|
579
604
|
private readonly interactMode;
|
|
605
|
+
private readonly onHtmlElementMount?;
|
|
606
|
+
private readonly dropHandler?;
|
|
580
607
|
private readonly gridChangeListeners;
|
|
581
608
|
private readonly doubleTapDetector;
|
|
582
609
|
private tapDownX;
|
|
@@ -607,6 +634,8 @@ declare class Viewport {
|
|
|
607
634
|
w: number;
|
|
608
635
|
h: number;
|
|
609
636
|
}): string;
|
|
637
|
+
removeLayer(id: string): void;
|
|
638
|
+
updateHtmlElement(id: string, newContent: HTMLElement): void;
|
|
610
639
|
addGrid(input: {
|
|
611
640
|
gridType?: 'square' | 'hex';
|
|
612
641
|
hexOrientation?: 'pointy' | 'flat';
|
|
@@ -935,6 +964,7 @@ declare class SelectTool implements Tool {
|
|
|
935
964
|
private ctx;
|
|
936
965
|
private pendingSingleSelectId;
|
|
937
966
|
private hasDragged;
|
|
967
|
+
private resizeAspectRatio;
|
|
938
968
|
get selectedIds(): string[];
|
|
939
969
|
setSelection(ids: string[]): void;
|
|
940
970
|
get isMarqueeActive(): boolean;
|
|
@@ -1181,6 +1211,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1181
1211
|
undo(_store: ElementStore): void;
|
|
1182
1212
|
}
|
|
1183
1213
|
|
|
1184
|
-
declare const VERSION = "0.
|
|
1214
|
+
declare const VERSION = "0.16.0";
|
|
1185
1215
|
|
|
1186
1216
|
export { type ActiveFormats, AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, DEFAULT_FONT_SIZE_PRESETS, DEFAULT_NOTE_FONT_SIZE, DoubleTapDetector, type DoubleTapDetectorOptions, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FilterAction, type FilteredEvent, type FilteredUpEvent, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputFilter, InputHandler, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, NoteEditor, type NoteEditorOptions, type NoteElement, NoteTool, type NoteToolOptions, NoteToolbar, PencilTool, type PencilToolOptions, type Point, type PointerState, Quadtree, RemoveElementCommand, RemoveLayerCommand, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type StyledRun, type TemplateElement, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, boundsIntersect, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportState, findBindTarget, findBoundArrows, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
|
package/dist/index.js
CHANGED
|
@@ -975,6 +975,14 @@ var InputHandler = class {
|
|
|
975
975
|
e.preventDefault();
|
|
976
976
|
this.handlePaste();
|
|
977
977
|
}
|
|
978
|
+
if (e.key === "]") {
|
|
979
|
+
e.preventDefault();
|
|
980
|
+
this.handleZOrder(e.ctrlKey || e.metaKey ? "front" : "forward");
|
|
981
|
+
}
|
|
982
|
+
if (e.key === "[") {
|
|
983
|
+
e.preventDefault();
|
|
984
|
+
this.handleZOrder(e.ctrlKey || e.metaKey ? "back" : "backward");
|
|
985
|
+
}
|
|
978
986
|
};
|
|
979
987
|
onKeyUp = (e) => {
|
|
980
988
|
if (e.key === " ") {
|
|
@@ -1151,6 +1159,33 @@ var InputHandler = class {
|
|
|
1151
1159
|
selectTool.setSelection(newIds);
|
|
1152
1160
|
this.toolContext.requestRender();
|
|
1153
1161
|
}
|
|
1162
|
+
handleZOrder(operation) {
|
|
1163
|
+
if (!this.toolManager || !this.toolContext) return;
|
|
1164
|
+
const tool = this.toolManager.activeTool;
|
|
1165
|
+
if (tool?.name !== "select") return;
|
|
1166
|
+
const selectTool = tool;
|
|
1167
|
+
const ids = selectTool.selectedIds;
|
|
1168
|
+
if (ids.length === 0) return;
|
|
1169
|
+
this.historyRecorder?.begin();
|
|
1170
|
+
for (const id of ids) {
|
|
1171
|
+
switch (operation) {
|
|
1172
|
+
case "forward":
|
|
1173
|
+
this.toolContext.store.bringForward(id);
|
|
1174
|
+
break;
|
|
1175
|
+
case "backward":
|
|
1176
|
+
this.toolContext.store.sendBackward(id);
|
|
1177
|
+
break;
|
|
1178
|
+
case "front":
|
|
1179
|
+
this.toolContext.store.bringToFront(id);
|
|
1180
|
+
break;
|
|
1181
|
+
case "back":
|
|
1182
|
+
this.toolContext.store.sendToBack(id);
|
|
1183
|
+
break;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
this.historyRecorder?.commit();
|
|
1187
|
+
this.toolContext.requestRender();
|
|
1188
|
+
}
|
|
1154
1189
|
cancelToolIfActive(e) {
|
|
1155
1190
|
if (this.isToolActive) {
|
|
1156
1191
|
this.dispatchToolUp(e);
|
|
@@ -1447,9 +1482,13 @@ var ElementStore = class {
|
|
|
1447
1482
|
layerOrderMap = /* @__PURE__ */ new Map();
|
|
1448
1483
|
spatialIndex = new Quadtree({ x: -1e5, y: -1e5, w: 2e5, h: 2e5 });
|
|
1449
1484
|
sortedCache = null;
|
|
1485
|
+
_versions = /* @__PURE__ */ new Map();
|
|
1450
1486
|
get count() {
|
|
1451
1487
|
return this.elements.size;
|
|
1452
1488
|
}
|
|
1489
|
+
getVersion(id) {
|
|
1490
|
+
return this._versions.get(id) ?? -1;
|
|
1491
|
+
}
|
|
1453
1492
|
setLayerOrder(order) {
|
|
1454
1493
|
this.layerOrderMap = new Map(order);
|
|
1455
1494
|
this.sortedCache = null;
|
|
@@ -1474,6 +1513,7 @@ var ElementStore = class {
|
|
|
1474
1513
|
}
|
|
1475
1514
|
add(element) {
|
|
1476
1515
|
this.sortedCache = null;
|
|
1516
|
+
this._versions.set(element.id, 0);
|
|
1477
1517
|
this.elements.set(element.id, element);
|
|
1478
1518
|
const bounds = getElementBounds(element);
|
|
1479
1519
|
if (bounds) this.spatialIndex.insert(element.id, bounds);
|
|
@@ -1483,6 +1523,7 @@ var ElementStore = class {
|
|
|
1483
1523
|
const existing = this.elements.get(id);
|
|
1484
1524
|
if (!existing) return;
|
|
1485
1525
|
this.sortedCache = null;
|
|
1526
|
+
this._versions.set(id, (this._versions.get(id) ?? 0) + 1);
|
|
1486
1527
|
const updated = { ...existing, ...partial, id: existing.id, type: existing.type };
|
|
1487
1528
|
if (updated.type === "arrow") {
|
|
1488
1529
|
const arrow = updated;
|
|
@@ -1502,12 +1543,14 @@ var ElementStore = class {
|
|
|
1502
1543
|
const element = this.elements.get(id);
|
|
1503
1544
|
if (!element) return;
|
|
1504
1545
|
this.sortedCache = null;
|
|
1546
|
+
this._versions.delete(id);
|
|
1505
1547
|
this.elements.delete(id);
|
|
1506
1548
|
this.spatialIndex.remove(id);
|
|
1507
1549
|
this.bus.emit("remove", element);
|
|
1508
1550
|
}
|
|
1509
1551
|
clear() {
|
|
1510
1552
|
this.sortedCache = null;
|
|
1553
|
+
this._versions.clear();
|
|
1511
1554
|
this.elements.clear();
|
|
1512
1555
|
this.spatialIndex.clear();
|
|
1513
1556
|
this.bus.emit("clear", null);
|
|
@@ -1517,10 +1560,12 @@ var ElementStore = class {
|
|
|
1517
1560
|
}
|
|
1518
1561
|
loadSnapshot(elements) {
|
|
1519
1562
|
this.sortedCache = null;
|
|
1563
|
+
this._versions.clear();
|
|
1520
1564
|
this.elements.clear();
|
|
1521
1565
|
this.spatialIndex.clear();
|
|
1522
1566
|
for (const el of elements) {
|
|
1523
1567
|
this.elements.set(el.id, el);
|
|
1568
|
+
this._versions.set(el.id, 0);
|
|
1524
1569
|
const bounds = getElementBounds(el);
|
|
1525
1570
|
if (bounds) this.spatialIndex.insert(el.id, bounds);
|
|
1526
1571
|
}
|
|
@@ -1529,6 +1574,54 @@ var ElementStore = class {
|
|
|
1529
1574
|
this.bus.emit("add", el);
|
|
1530
1575
|
}
|
|
1531
1576
|
}
|
|
1577
|
+
bringToFront(id) {
|
|
1578
|
+
const el = this.elements.get(id);
|
|
1579
|
+
if (!el) return;
|
|
1580
|
+
const siblings = [...this.elements.values()].filter(
|
|
1581
|
+
(e) => e.layerId === el.layerId && e.id !== id
|
|
1582
|
+
);
|
|
1583
|
+
if (siblings.length === 0) return;
|
|
1584
|
+
const maxZ = Math.max(...siblings.map((e) => e.zIndex));
|
|
1585
|
+
if (el.zIndex >= maxZ) return;
|
|
1586
|
+
this.update(id, { zIndex: maxZ + 1 });
|
|
1587
|
+
}
|
|
1588
|
+
sendToBack(id) {
|
|
1589
|
+
const el = this.elements.get(id);
|
|
1590
|
+
if (!el) return;
|
|
1591
|
+
const siblings = [...this.elements.values()].filter(
|
|
1592
|
+
(e) => e.layerId === el.layerId && e.id !== id
|
|
1593
|
+
);
|
|
1594
|
+
if (siblings.length === 0) return;
|
|
1595
|
+
const minZ = Math.min(...siblings.map((e) => e.zIndex));
|
|
1596
|
+
if (el.zIndex <= minZ) return;
|
|
1597
|
+
this.update(id, { zIndex: minZ - 1 });
|
|
1598
|
+
}
|
|
1599
|
+
bringForward(id) {
|
|
1600
|
+
const el = this.elements.get(id);
|
|
1601
|
+
if (!el) return;
|
|
1602
|
+
const sorted = [...this.elements.values()].filter((e) => e.layerId === el.layerId).sort((a, b) => a.zIndex - b.zIndex);
|
|
1603
|
+
const idx = sorted.findIndex((e) => e.id === id);
|
|
1604
|
+
if (idx < 0 || idx >= sorted.length - 1) return;
|
|
1605
|
+
const next = sorted[idx + 1];
|
|
1606
|
+
if (!next) return;
|
|
1607
|
+
const myZ = el.zIndex;
|
|
1608
|
+
const nextZ = next.zIndex;
|
|
1609
|
+
this.update(id, { zIndex: nextZ });
|
|
1610
|
+
this.update(next.id, { zIndex: myZ });
|
|
1611
|
+
}
|
|
1612
|
+
sendBackward(id) {
|
|
1613
|
+
const el = this.elements.get(id);
|
|
1614
|
+
if (!el) return;
|
|
1615
|
+
const sorted = [...this.elements.values()].filter((e) => e.layerId === el.layerId).sort((a, b) => a.zIndex - b.zIndex);
|
|
1616
|
+
const idx = sorted.findIndex((e) => e.id === id);
|
|
1617
|
+
if (idx <= 0) return;
|
|
1618
|
+
const prev = sorted[idx - 1];
|
|
1619
|
+
if (!prev) return;
|
|
1620
|
+
const myZ = el.zIndex;
|
|
1621
|
+
const prevZ = prev.zIndex;
|
|
1622
|
+
this.update(id, { zIndex: prevZ });
|
|
1623
|
+
this.update(prev.id, { zIndex: myZ });
|
|
1624
|
+
}
|
|
1532
1625
|
queryRect(rect) {
|
|
1533
1626
|
const ids = this.spatialIndex.query(rect);
|
|
1534
1627
|
const elements = [];
|
|
@@ -3200,16 +3293,64 @@ var BatchCommand = class {
|
|
|
3200
3293
|
}
|
|
3201
3294
|
};
|
|
3202
3295
|
|
|
3296
|
+
// src/history/layer-commands.ts
|
|
3297
|
+
var CreateLayerCommand = class {
|
|
3298
|
+
constructor(manager, layer) {
|
|
3299
|
+
this.manager = manager;
|
|
3300
|
+
this.layer = layer;
|
|
3301
|
+
}
|
|
3302
|
+
execute(_store) {
|
|
3303
|
+
this.manager.addLayerDirect(this.layer);
|
|
3304
|
+
}
|
|
3305
|
+
undo(_store) {
|
|
3306
|
+
this.manager.removeLayerDirect(this.layer.id);
|
|
3307
|
+
}
|
|
3308
|
+
};
|
|
3309
|
+
var RemoveLayerCommand = class {
|
|
3310
|
+
constructor(manager, layer) {
|
|
3311
|
+
this.manager = manager;
|
|
3312
|
+
this.layer = layer;
|
|
3313
|
+
}
|
|
3314
|
+
execute(_store) {
|
|
3315
|
+
this.manager.removeLayerDirect(this.layer.id);
|
|
3316
|
+
}
|
|
3317
|
+
undo(_store) {
|
|
3318
|
+
this.manager.addLayerDirect(this.layer);
|
|
3319
|
+
}
|
|
3320
|
+
};
|
|
3321
|
+
var UpdateLayerCommand = class {
|
|
3322
|
+
constructor(manager, layerId, previous, current) {
|
|
3323
|
+
this.manager = manager;
|
|
3324
|
+
this.layerId = layerId;
|
|
3325
|
+
this.previous = previous;
|
|
3326
|
+
this.current = current;
|
|
3327
|
+
}
|
|
3328
|
+
execute(_store) {
|
|
3329
|
+
this.manager.updateLayerDirect(this.layerId, { ...this.current });
|
|
3330
|
+
}
|
|
3331
|
+
undo(_store) {
|
|
3332
|
+
this.manager.updateLayerDirect(this.layerId, { ...this.previous });
|
|
3333
|
+
}
|
|
3334
|
+
};
|
|
3335
|
+
|
|
3203
3336
|
// src/history/history-recorder.ts
|
|
3204
3337
|
var HistoryRecorder = class {
|
|
3205
|
-
constructor(store, stack) {
|
|
3338
|
+
constructor(store, stack, layerManager) {
|
|
3206
3339
|
this.store = store;
|
|
3207
3340
|
this.stack = stack;
|
|
3341
|
+
this.layerManager = layerManager;
|
|
3208
3342
|
this.unsubscribers = [
|
|
3209
3343
|
store.on("add", (el) => this.onAdd(el)),
|
|
3210
3344
|
store.on("remove", (el) => this.onRemove(el)),
|
|
3211
3345
|
store.on("update", ({ previous, current }) => this.onUpdate(previous, current))
|
|
3212
3346
|
];
|
|
3347
|
+
if (layerManager) {
|
|
3348
|
+
this.unsubscribers.push(
|
|
3349
|
+
layerManager.on("create", (layer) => this.onLayerCreate(layer)),
|
|
3350
|
+
layerManager.on("remove", (layer) => this.onLayerRemove(layer)),
|
|
3351
|
+
layerManager.on("update", ({ previous, current }) => this.onLayerUpdate(previous, current))
|
|
3352
|
+
);
|
|
3353
|
+
}
|
|
3213
3354
|
}
|
|
3214
3355
|
recording = true;
|
|
3215
3356
|
transaction = null;
|
|
@@ -3270,6 +3411,21 @@ var HistoryRecorder = class {
|
|
|
3270
3411
|
this.stack.push(new UpdateElementCommand(current.id, previous, current));
|
|
3271
3412
|
}
|
|
3272
3413
|
}
|
|
3414
|
+
onLayerCreate(layer) {
|
|
3415
|
+
if (!this.recording) return;
|
|
3416
|
+
if (!this.layerManager) return;
|
|
3417
|
+
this.record(new CreateLayerCommand(this.layerManager, layer));
|
|
3418
|
+
}
|
|
3419
|
+
onLayerRemove(layer) {
|
|
3420
|
+
if (!this.recording) return;
|
|
3421
|
+
if (!this.layerManager) return;
|
|
3422
|
+
this.record(new RemoveLayerCommand(this.layerManager, layer));
|
|
3423
|
+
}
|
|
3424
|
+
onLayerUpdate(previous, current) {
|
|
3425
|
+
if (!this.recording) return;
|
|
3426
|
+
if (!this.layerManager) return;
|
|
3427
|
+
this.record(new UpdateLayerCommand(this.layerManager, current.id, previous, current));
|
|
3428
|
+
}
|
|
3273
3429
|
flushUpdateSnapshots() {
|
|
3274
3430
|
const commands = [];
|
|
3275
3431
|
for (const [id, previous] of this.updateSnapshots) {
|
|
@@ -3702,18 +3858,23 @@ var LayerManager = class {
|
|
|
3702
3858
|
addLayerDirect(layer) {
|
|
3703
3859
|
this.layers.set(layer.id, { ...layer });
|
|
3704
3860
|
this.syncLayerOrder();
|
|
3861
|
+
this.bus.emit("create", { ...layer });
|
|
3705
3862
|
this.bus.emit("change", null);
|
|
3706
3863
|
}
|
|
3707
3864
|
removeLayerDirect(id) {
|
|
3865
|
+
const layer = this.layers.get(id);
|
|
3708
3866
|
this.layers.delete(id);
|
|
3709
3867
|
this.syncLayerOrder();
|
|
3868
|
+
if (layer) this.bus.emit("remove", { ...layer });
|
|
3710
3869
|
this.bus.emit("change", null);
|
|
3711
3870
|
}
|
|
3712
3871
|
updateLayerDirect(id, props) {
|
|
3713
3872
|
const layer = this.layers.get(id);
|
|
3714
3873
|
if (!layer) return;
|
|
3874
|
+
const previous = { ...layer };
|
|
3715
3875
|
Object.assign(layer, props);
|
|
3716
3876
|
if ("order" in props) this.syncLayerOrder();
|
|
3877
|
+
this.bus.emit("update", { previous, current: { ...layer } });
|
|
3717
3878
|
this.bus.emit("change", null);
|
|
3718
3879
|
}
|
|
3719
3880
|
syncLayerOrder() {
|
|
@@ -3791,10 +3952,14 @@ var DomNodeManager = class {
|
|
|
3791
3952
|
domLayer;
|
|
3792
3953
|
onEditRequest;
|
|
3793
3954
|
isEditingElement;
|
|
3955
|
+
getVersion;
|
|
3956
|
+
lastSyncedVersion = /* @__PURE__ */ new Map();
|
|
3957
|
+
lastSyncedZIndex = /* @__PURE__ */ new Map();
|
|
3794
3958
|
constructor(deps) {
|
|
3795
3959
|
this.domLayer = deps.domLayer;
|
|
3796
3960
|
this.onEditRequest = deps.onEditRequest;
|
|
3797
3961
|
this.isEditingElement = deps.isEditingElement;
|
|
3962
|
+
this.getVersion = deps.getVersion ?? null;
|
|
3798
3963
|
}
|
|
3799
3964
|
getNode(id) {
|
|
3800
3965
|
return this.domNodes.get(id);
|
|
@@ -3802,6 +3967,20 @@ var DomNodeManager = class {
|
|
|
3802
3967
|
storeHtmlContent(elementId, dom) {
|
|
3803
3968
|
this.htmlContent.set(elementId, dom);
|
|
3804
3969
|
}
|
|
3970
|
+
hasContent(elementId) {
|
|
3971
|
+
return this.htmlContent.has(elementId);
|
|
3972
|
+
}
|
|
3973
|
+
resetHtmlContent(elementId) {
|
|
3974
|
+
this.htmlContent.delete(elementId);
|
|
3975
|
+
this.lastSyncedVersion.delete(elementId);
|
|
3976
|
+
this.lastSyncedZIndex.delete(elementId);
|
|
3977
|
+
const node = this.domNodes.get(elementId);
|
|
3978
|
+
if (!node) return;
|
|
3979
|
+
while (node.firstChild) {
|
|
3980
|
+
node.removeChild(node.firstChild);
|
|
3981
|
+
}
|
|
3982
|
+
delete node.dataset["initialized"];
|
|
3983
|
+
}
|
|
3805
3984
|
syncDomNode(element, zIndex = 0) {
|
|
3806
3985
|
let node = this.domNodes.get(element.id);
|
|
3807
3986
|
if (!node) {
|
|
@@ -3813,6 +3992,17 @@ var DomNodeManager = class {
|
|
|
3813
3992
|
});
|
|
3814
3993
|
this.domLayer.appendChild(node);
|
|
3815
3994
|
this.domNodes.set(element.id, node);
|
|
3995
|
+
} else if (this.getVersion) {
|
|
3996
|
+
const currentVersion = this.getVersion(element.id);
|
|
3997
|
+
const lastVersion = this.lastSyncedVersion.get(element.id);
|
|
3998
|
+
const lastZ = this.lastSyncedZIndex.get(element.id);
|
|
3999
|
+
if (lastVersion === currentVersion && lastZ === zIndex) {
|
|
4000
|
+
return;
|
|
4001
|
+
}
|
|
4002
|
+
}
|
|
4003
|
+
if (this.getVersion) {
|
|
4004
|
+
this.lastSyncedVersion.set(element.id, this.getVersion(element.id));
|
|
4005
|
+
this.lastSyncedZIndex.set(element.id, zIndex);
|
|
3816
4006
|
}
|
|
3817
4007
|
const size = "size" in element ? element.size : null;
|
|
3818
4008
|
Object.assign(node.style, {
|
|
@@ -3831,6 +4021,8 @@ var DomNodeManager = class {
|
|
|
3831
4021
|
}
|
|
3832
4022
|
removeDomNode(id) {
|
|
3833
4023
|
this.htmlContent.delete(id);
|
|
4024
|
+
this.lastSyncedVersion.delete(id);
|
|
4025
|
+
this.lastSyncedZIndex.delete(id);
|
|
3834
4026
|
const node = this.domNodes.get(id);
|
|
3835
4027
|
if (node) {
|
|
3836
4028
|
node.remove();
|
|
@@ -3841,6 +4033,8 @@ var DomNodeManager = class {
|
|
|
3841
4033
|
this.domNodes.forEach((node) => node.remove());
|
|
3842
4034
|
this.domNodes.clear();
|
|
3843
4035
|
this.htmlContent.clear();
|
|
4036
|
+
this.lastSyncedVersion.clear();
|
|
4037
|
+
this.lastSyncedZIndex.clear();
|
|
3844
4038
|
}
|
|
3845
4039
|
reattachHtmlContent(store) {
|
|
3846
4040
|
for (const el of store.getElementsByType("html")) {
|
|
@@ -4328,8 +4522,10 @@ var Viewport = class {
|
|
|
4328
4522
|
toolbar: options.toolbar
|
|
4329
4523
|
});
|
|
4330
4524
|
this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
|
|
4525
|
+
this.onHtmlElementMount = options.onHtmlElementMount;
|
|
4526
|
+
this.dropHandler = options.onDrop;
|
|
4331
4527
|
this.history = new HistoryStack();
|
|
4332
|
-
this.historyRecorder = new HistoryRecorder(this.store, this.history);
|
|
4528
|
+
this.historyRecorder = new HistoryRecorder(this.store, this.history, this.layerManager);
|
|
4333
4529
|
this.wrapper = this.createWrapper();
|
|
4334
4530
|
this.canvasEl = this.createCanvas();
|
|
4335
4531
|
this.domLayer = this.createDomLayer();
|
|
@@ -4360,7 +4556,8 @@ var Viewport = class {
|
|
|
4360
4556
|
this.domNodeManager = new DomNodeManager({
|
|
4361
4557
|
domLayer: this.domLayer,
|
|
4362
4558
|
onEditRequest: (id) => this.startEditingElement(id),
|
|
4363
|
-
isEditingElement: (id) => this.noteEditor.isEditing && this.noteEditor.editingElementId === id
|
|
4559
|
+
isEditingElement: (id) => this.noteEditor.isEditing && this.noteEditor.editingElementId === id,
|
|
4560
|
+
getVersion: (id) => this.store.getVersion(id)
|
|
4364
4561
|
});
|
|
4365
4562
|
this.interactMode = new InteractMode({
|
|
4366
4563
|
getNode: (id) => this.domNodeManager.getNode(id)
|
|
@@ -4448,6 +4645,8 @@ var Viewport = class {
|
|
|
4448
4645
|
renderLoop;
|
|
4449
4646
|
domNodeManager;
|
|
4450
4647
|
interactMode;
|
|
4648
|
+
onHtmlElementMount;
|
|
4649
|
+
dropHandler;
|
|
4451
4650
|
gridChangeListeners = /* @__PURE__ */ new Set();
|
|
4452
4651
|
doubleTapDetector = new DoubleTapDetector();
|
|
4453
4652
|
tapDownX = 0;
|
|
@@ -4491,6 +4690,22 @@ var Viewport = class {
|
|
|
4491
4690
|
this.layerManager.setActiveLayer(state.activeLayerId);
|
|
4492
4691
|
}
|
|
4493
4692
|
this.domNodeManager.reattachHtmlContent(this.store);
|
|
4693
|
+
if (this.onHtmlElementMount) {
|
|
4694
|
+
for (const el of this.store.getElementsByType("html")) {
|
|
4695
|
+
if (!this.domNodeManager.hasContent(el.id)) {
|
|
4696
|
+
this.domNodeManager.syncDomNode(el);
|
|
4697
|
+
const node = this.domNodeManager.getNode(el.id);
|
|
4698
|
+
if (node) {
|
|
4699
|
+
this.onHtmlElementMount(el.id, el.domId, node);
|
|
4700
|
+
node.dataset["initialized"] = "true";
|
|
4701
|
+
Object.assign(node.style, {
|
|
4702
|
+
overflow: "hidden",
|
|
4703
|
+
pointerEvents: el.interactive ? "auto" : "none"
|
|
4704
|
+
});
|
|
4705
|
+
}
|
|
4706
|
+
}
|
|
4707
|
+
}
|
|
4708
|
+
}
|
|
4494
4709
|
this.history.clear();
|
|
4495
4710
|
this.historyRecorder.resume();
|
|
4496
4711
|
this.camera.moveTo(state.camera.position.x, state.camera.position.y);
|
|
@@ -4536,6 +4751,19 @@ var Viewport = class {
|
|
|
4536
4751
|
this.requestRender();
|
|
4537
4752
|
return el.id;
|
|
4538
4753
|
}
|
|
4754
|
+
removeLayer(id) {
|
|
4755
|
+
this.historyRecorder.begin();
|
|
4756
|
+
this.layerManager.removeLayer(id);
|
|
4757
|
+
this.historyRecorder.commit();
|
|
4758
|
+
}
|
|
4759
|
+
updateHtmlElement(id, newContent) {
|
|
4760
|
+
const el = this.store.getById(id);
|
|
4761
|
+
if (!el) throw new Error(`Element not found: ${id}`);
|
|
4762
|
+
if (el.type !== "html") throw new Error(`Element ${id} is not an HTML element`);
|
|
4763
|
+
this.domNodeManager.resetHtmlContent(id);
|
|
4764
|
+
this.domNodeManager.storeHtmlContent(id, newContent);
|
|
4765
|
+
this.requestRender();
|
|
4766
|
+
}
|
|
4539
4767
|
addGrid(input) {
|
|
4540
4768
|
const existing = this.store.getElementsByType("grid")[0];
|
|
4541
4769
|
this.historyRecorder.begin();
|
|
@@ -4687,17 +4915,21 @@ var Viewport = class {
|
|
|
4687
4915
|
};
|
|
4688
4916
|
onDrop = (e) => {
|
|
4689
4917
|
e.preventDefault();
|
|
4918
|
+
const rect = this.wrapper.getBoundingClientRect();
|
|
4919
|
+
const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
4920
|
+
const worldPos = this.camera.screenToWorld(screenPos);
|
|
4921
|
+
if (this.dropHandler) {
|
|
4922
|
+
this.dropHandler(e, worldPos);
|
|
4923
|
+
return;
|
|
4924
|
+
}
|
|
4690
4925
|
const files = e.dataTransfer?.files;
|
|
4691
4926
|
if (!files) return;
|
|
4692
|
-
const rect = this.wrapper.getBoundingClientRect();
|
|
4693
4927
|
for (const file of files) {
|
|
4694
4928
|
if (!file.type.startsWith("image/")) continue;
|
|
4695
4929
|
const reader = new FileReader();
|
|
4696
4930
|
reader.onload = () => {
|
|
4697
4931
|
const src = reader.result;
|
|
4698
4932
|
if (typeof src !== "string") return;
|
|
4699
|
-
const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
4700
|
-
const worldPos = this.camera.screenToWorld(screenPos);
|
|
4701
4933
|
this.addImage(src, worldPos);
|
|
4702
4934
|
};
|
|
4703
4935
|
reader.readAsDataURL(file);
|
|
@@ -5183,6 +5415,7 @@ var SelectTool = class {
|
|
|
5183
5415
|
ctx = null;
|
|
5184
5416
|
pendingSingleSelectId = null;
|
|
5185
5417
|
hasDragged = false;
|
|
5418
|
+
resizeAspectRatio = 0;
|
|
5186
5419
|
get selectedIds() {
|
|
5187
5420
|
return [...this._selectedIds];
|
|
5188
5421
|
}
|
|
@@ -5228,7 +5461,8 @@ var SelectTool = class {
|
|
|
5228
5461
|
const resizeHit = this.hitTestResizeHandle(world, ctx);
|
|
5229
5462
|
if (resizeHit) {
|
|
5230
5463
|
const el = ctx.store.getById(resizeHit.elementId);
|
|
5231
|
-
if (el) {
|
|
5464
|
+
if (el && "size" in el) {
|
|
5465
|
+
this.resizeAspectRatio = el.size.h > 0 ? el.size.w / el.size.h : 0;
|
|
5232
5466
|
this.mode = {
|
|
5233
5467
|
type: "resizing",
|
|
5234
5468
|
elementId: resizeHit.elementId,
|
|
@@ -5280,7 +5514,7 @@ var SelectTool = class {
|
|
|
5280
5514
|
}
|
|
5281
5515
|
if (this.mode.type === "resizing") {
|
|
5282
5516
|
ctx.setCursor?.(HANDLE_CURSORS[this.mode.handle]);
|
|
5283
|
-
this.handleResize(world, ctx);
|
|
5517
|
+
this.handleResize(world, ctx, state.shiftKey);
|
|
5284
5518
|
return;
|
|
5285
5519
|
}
|
|
5286
5520
|
if (this.mode.type === "dragging" && this._selectedIds.length > 0) {
|
|
@@ -5404,7 +5638,7 @@ var SelectTool = class {
|
|
|
5404
5638
|
const hit = this.hitTest(world, ctx);
|
|
5405
5639
|
ctx.setCursor?.(hit ? "move" : "default");
|
|
5406
5640
|
}
|
|
5407
|
-
handleResize(world, ctx) {
|
|
5641
|
+
handleResize(world, ctx, shiftKey = false) {
|
|
5408
5642
|
if (this.mode.type !== "resizing") return;
|
|
5409
5643
|
const el = ctx.store.getById(this.mode.elementId);
|
|
5410
5644
|
if (!el || !("size" in el) || el.locked) return;
|
|
@@ -5435,6 +5669,21 @@ var SelectTool = class {
|
|
|
5435
5669
|
h -= dy;
|
|
5436
5670
|
break;
|
|
5437
5671
|
}
|
|
5672
|
+
if (shiftKey && this.resizeAspectRatio > 0) {
|
|
5673
|
+
const absDw = Math.abs(w - el.size.w);
|
|
5674
|
+
const absDh = Math.abs(h - el.size.h);
|
|
5675
|
+
if (absDw >= absDh) {
|
|
5676
|
+
h = w / this.resizeAspectRatio;
|
|
5677
|
+
} else {
|
|
5678
|
+
w = h * this.resizeAspectRatio;
|
|
5679
|
+
}
|
|
5680
|
+
if (handle === "nw" || handle === "sw") {
|
|
5681
|
+
x = el.position.x + el.size.w - w;
|
|
5682
|
+
}
|
|
5683
|
+
if (handle === "nw" || handle === "ne") {
|
|
5684
|
+
y = el.position.y + el.size.h - h;
|
|
5685
|
+
}
|
|
5686
|
+
}
|
|
5438
5687
|
if (w < MIN_ELEMENT_SIZE) {
|
|
5439
5688
|
if (handle === "nw" || handle === "sw") x = el.position.x + el.size.w - MIN_ELEMENT_SIZE;
|
|
5440
5689
|
w = MIN_ELEMENT_SIZE;
|
|
@@ -6497,48 +6746,8 @@ var TemplateTool = class {
|
|
|
6497
6746
|
}
|
|
6498
6747
|
};
|
|
6499
6748
|
|
|
6500
|
-
// src/history/layer-commands.ts
|
|
6501
|
-
var CreateLayerCommand = class {
|
|
6502
|
-
constructor(manager, layer) {
|
|
6503
|
-
this.manager = manager;
|
|
6504
|
-
this.layer = layer;
|
|
6505
|
-
}
|
|
6506
|
-
execute(_store) {
|
|
6507
|
-
this.manager.addLayerDirect(this.layer);
|
|
6508
|
-
}
|
|
6509
|
-
undo(_store) {
|
|
6510
|
-
this.manager.removeLayerDirect(this.layer.id);
|
|
6511
|
-
}
|
|
6512
|
-
};
|
|
6513
|
-
var RemoveLayerCommand = class {
|
|
6514
|
-
constructor(manager, layer) {
|
|
6515
|
-
this.manager = manager;
|
|
6516
|
-
this.layer = layer;
|
|
6517
|
-
}
|
|
6518
|
-
execute(_store) {
|
|
6519
|
-
this.manager.removeLayerDirect(this.layer.id);
|
|
6520
|
-
}
|
|
6521
|
-
undo(_store) {
|
|
6522
|
-
this.manager.addLayerDirect(this.layer);
|
|
6523
|
-
}
|
|
6524
|
-
};
|
|
6525
|
-
var UpdateLayerCommand = class {
|
|
6526
|
-
constructor(manager, layerId, previous, current) {
|
|
6527
|
-
this.manager = manager;
|
|
6528
|
-
this.layerId = layerId;
|
|
6529
|
-
this.previous = previous;
|
|
6530
|
-
this.current = current;
|
|
6531
|
-
}
|
|
6532
|
-
execute(_store) {
|
|
6533
|
-
this.manager.updateLayerDirect(this.layerId, { ...this.current });
|
|
6534
|
-
}
|
|
6535
|
-
undo(_store) {
|
|
6536
|
-
this.manager.updateLayerDirect(this.layerId, { ...this.previous });
|
|
6537
|
-
}
|
|
6538
|
-
};
|
|
6539
|
-
|
|
6540
6749
|
// src/index.ts
|
|
6541
|
-
var VERSION = "0.
|
|
6750
|
+
var VERSION = "0.16.0";
|
|
6542
6751
|
export {
|
|
6543
6752
|
AddElementCommand,
|
|
6544
6753
|
ArrowTool,
|