@fieldnotes/core 0.14.0 → 0.15.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 +135 -5
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +135 -5
- 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 = [];
|
|
@@ -3900,10 +3993,14 @@ var DomNodeManager = class {
|
|
|
3900
3993
|
domLayer;
|
|
3901
3994
|
onEditRequest;
|
|
3902
3995
|
isEditingElement;
|
|
3996
|
+
getVersion;
|
|
3997
|
+
lastSyncedVersion = /* @__PURE__ */ new Map();
|
|
3998
|
+
lastSyncedZIndex = /* @__PURE__ */ new Map();
|
|
3903
3999
|
constructor(deps) {
|
|
3904
4000
|
this.domLayer = deps.domLayer;
|
|
3905
4001
|
this.onEditRequest = deps.onEditRequest;
|
|
3906
4002
|
this.isEditingElement = deps.isEditingElement;
|
|
4003
|
+
this.getVersion = deps.getVersion ?? null;
|
|
3907
4004
|
}
|
|
3908
4005
|
getNode(id) {
|
|
3909
4006
|
return this.domNodes.get(id);
|
|
@@ -3922,6 +4019,17 @@ var DomNodeManager = class {
|
|
|
3922
4019
|
});
|
|
3923
4020
|
this.domLayer.appendChild(node);
|
|
3924
4021
|
this.domNodes.set(element.id, node);
|
|
4022
|
+
} else if (this.getVersion) {
|
|
4023
|
+
const currentVersion = this.getVersion(element.id);
|
|
4024
|
+
const lastVersion = this.lastSyncedVersion.get(element.id);
|
|
4025
|
+
const lastZ = this.lastSyncedZIndex.get(element.id);
|
|
4026
|
+
if (lastVersion === currentVersion && lastZ === zIndex) {
|
|
4027
|
+
return;
|
|
4028
|
+
}
|
|
4029
|
+
}
|
|
4030
|
+
if (this.getVersion) {
|
|
4031
|
+
this.lastSyncedVersion.set(element.id, this.getVersion(element.id));
|
|
4032
|
+
this.lastSyncedZIndex.set(element.id, zIndex);
|
|
3925
4033
|
}
|
|
3926
4034
|
const size = "size" in element ? element.size : null;
|
|
3927
4035
|
Object.assign(node.style, {
|
|
@@ -3940,6 +4048,8 @@ var DomNodeManager = class {
|
|
|
3940
4048
|
}
|
|
3941
4049
|
removeDomNode(id) {
|
|
3942
4050
|
this.htmlContent.delete(id);
|
|
4051
|
+
this.lastSyncedVersion.delete(id);
|
|
4052
|
+
this.lastSyncedZIndex.delete(id);
|
|
3943
4053
|
const node = this.domNodes.get(id);
|
|
3944
4054
|
if (node) {
|
|
3945
4055
|
node.remove();
|
|
@@ -3950,6 +4060,8 @@ var DomNodeManager = class {
|
|
|
3950
4060
|
this.domNodes.forEach((node) => node.remove());
|
|
3951
4061
|
this.domNodes.clear();
|
|
3952
4062
|
this.htmlContent.clear();
|
|
4063
|
+
this.lastSyncedVersion.clear();
|
|
4064
|
+
this.lastSyncedZIndex.clear();
|
|
3953
4065
|
}
|
|
3954
4066
|
reattachHtmlContent(store) {
|
|
3955
4067
|
for (const el of store.getElementsByType("html")) {
|
|
@@ -4469,7 +4581,8 @@ var Viewport = class {
|
|
|
4469
4581
|
this.domNodeManager = new DomNodeManager({
|
|
4470
4582
|
domLayer: this.domLayer,
|
|
4471
4583
|
onEditRequest: (id) => this.startEditingElement(id),
|
|
4472
|
-
isEditingElement: (id) => this.noteEditor.isEditing && this.noteEditor.editingElementId === id
|
|
4584
|
+
isEditingElement: (id) => this.noteEditor.isEditing && this.noteEditor.editingElementId === id,
|
|
4585
|
+
getVersion: (id) => this.store.getVersion(id)
|
|
4473
4586
|
});
|
|
4474
4587
|
this.interactMode = new InteractMode({
|
|
4475
4588
|
getNode: (id) => this.domNodeManager.getNode(id)
|
|
@@ -5292,6 +5405,7 @@ var SelectTool = class {
|
|
|
5292
5405
|
ctx = null;
|
|
5293
5406
|
pendingSingleSelectId = null;
|
|
5294
5407
|
hasDragged = false;
|
|
5408
|
+
resizeAspectRatio = 0;
|
|
5295
5409
|
get selectedIds() {
|
|
5296
5410
|
return [...this._selectedIds];
|
|
5297
5411
|
}
|
|
@@ -5337,7 +5451,8 @@ var SelectTool = class {
|
|
|
5337
5451
|
const resizeHit = this.hitTestResizeHandle(world, ctx);
|
|
5338
5452
|
if (resizeHit) {
|
|
5339
5453
|
const el = ctx.store.getById(resizeHit.elementId);
|
|
5340
|
-
if (el) {
|
|
5454
|
+
if (el && "size" in el) {
|
|
5455
|
+
this.resizeAspectRatio = el.size.h > 0 ? el.size.w / el.size.h : 0;
|
|
5341
5456
|
this.mode = {
|
|
5342
5457
|
type: "resizing",
|
|
5343
5458
|
elementId: resizeHit.elementId,
|
|
@@ -5389,7 +5504,7 @@ var SelectTool = class {
|
|
|
5389
5504
|
}
|
|
5390
5505
|
if (this.mode.type === "resizing") {
|
|
5391
5506
|
ctx.setCursor?.(HANDLE_CURSORS[this.mode.handle]);
|
|
5392
|
-
this.handleResize(world, ctx);
|
|
5507
|
+
this.handleResize(world, ctx, state.shiftKey);
|
|
5393
5508
|
return;
|
|
5394
5509
|
}
|
|
5395
5510
|
if (this.mode.type === "dragging" && this._selectedIds.length > 0) {
|
|
@@ -5513,7 +5628,7 @@ var SelectTool = class {
|
|
|
5513
5628
|
const hit = this.hitTest(world, ctx);
|
|
5514
5629
|
ctx.setCursor?.(hit ? "move" : "default");
|
|
5515
5630
|
}
|
|
5516
|
-
handleResize(world, ctx) {
|
|
5631
|
+
handleResize(world, ctx, shiftKey = false) {
|
|
5517
5632
|
if (this.mode.type !== "resizing") return;
|
|
5518
5633
|
const el = ctx.store.getById(this.mode.elementId);
|
|
5519
5634
|
if (!el || !("size" in el) || el.locked) return;
|
|
@@ -5544,6 +5659,21 @@ var SelectTool = class {
|
|
|
5544
5659
|
h -= dy;
|
|
5545
5660
|
break;
|
|
5546
5661
|
}
|
|
5662
|
+
if (shiftKey && this.resizeAspectRatio > 0) {
|
|
5663
|
+
const absDw = Math.abs(w - el.size.w);
|
|
5664
|
+
const absDh = Math.abs(h - el.size.h);
|
|
5665
|
+
if (absDw >= absDh) {
|
|
5666
|
+
h = w / this.resizeAspectRatio;
|
|
5667
|
+
} else {
|
|
5668
|
+
w = h * this.resizeAspectRatio;
|
|
5669
|
+
}
|
|
5670
|
+
if (handle === "nw" || handle === "sw") {
|
|
5671
|
+
x = el.position.x + el.size.w - w;
|
|
5672
|
+
}
|
|
5673
|
+
if (handle === "nw" || handle === "ne") {
|
|
5674
|
+
y = el.position.y + el.size.h - h;
|
|
5675
|
+
}
|
|
5676
|
+
}
|
|
5547
5677
|
if (w < MIN_ELEMENT_SIZE) {
|
|
5548
5678
|
if (handle === "nw" || handle === "sw") x = el.position.x + el.size.w - MIN_ELEMENT_SIZE;
|
|
5549
5679
|
w = MIN_ELEMENT_SIZE;
|
|
@@ -6647,7 +6777,7 @@ var UpdateLayerCommand = class {
|
|
|
6647
6777
|
};
|
|
6648
6778
|
|
|
6649
6779
|
// src/index.ts
|
|
6650
|
-
var VERSION = "0.
|
|
6780
|
+
var VERSION = "0.15.0";
|
|
6651
6781
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6652
6782
|
0 && (module.exports = {
|
|
6653
6783
|
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;
|
|
@@ -462,6 +468,7 @@ declare class InputHandler {
|
|
|
462
468
|
private handleRedo;
|
|
463
469
|
private handleCopy;
|
|
464
470
|
private handlePaste;
|
|
471
|
+
private handleZOrder;
|
|
465
472
|
private cancelToolIfActive;
|
|
466
473
|
}
|
|
467
474
|
|
|
@@ -935,6 +942,7 @@ declare class SelectTool implements Tool {
|
|
|
935
942
|
private ctx;
|
|
936
943
|
private pendingSingleSelectId;
|
|
937
944
|
private hasDragged;
|
|
945
|
+
private resizeAspectRatio;
|
|
938
946
|
get selectedIds(): string[];
|
|
939
947
|
setSelection(ids: string[]): void;
|
|
940
948
|
get isMarqueeActive(): boolean;
|
|
@@ -1181,6 +1189,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1181
1189
|
undo(_store: ElementStore): void;
|
|
1182
1190
|
}
|
|
1183
1191
|
|
|
1184
|
-
declare const VERSION = "0.
|
|
1192
|
+
declare const VERSION = "0.15.0";
|
|
1185
1193
|
|
|
1186
1194
|
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;
|
|
@@ -462,6 +468,7 @@ declare class InputHandler {
|
|
|
462
468
|
private handleRedo;
|
|
463
469
|
private handleCopy;
|
|
464
470
|
private handlePaste;
|
|
471
|
+
private handleZOrder;
|
|
465
472
|
private cancelToolIfActive;
|
|
466
473
|
}
|
|
467
474
|
|
|
@@ -935,6 +942,7 @@ declare class SelectTool implements Tool {
|
|
|
935
942
|
private ctx;
|
|
936
943
|
private pendingSingleSelectId;
|
|
937
944
|
private hasDragged;
|
|
945
|
+
private resizeAspectRatio;
|
|
938
946
|
get selectedIds(): string[];
|
|
939
947
|
setSelection(ids: string[]): void;
|
|
940
948
|
get isMarqueeActive(): boolean;
|
|
@@ -1181,6 +1189,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1181
1189
|
undo(_store: ElementStore): void;
|
|
1182
1190
|
}
|
|
1183
1191
|
|
|
1184
|
-
declare const VERSION = "0.
|
|
1192
|
+
declare const VERSION = "0.15.0";
|
|
1185
1193
|
|
|
1186
1194
|
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 = [];
|
|
@@ -3791,10 +3884,14 @@ var DomNodeManager = class {
|
|
|
3791
3884
|
domLayer;
|
|
3792
3885
|
onEditRequest;
|
|
3793
3886
|
isEditingElement;
|
|
3887
|
+
getVersion;
|
|
3888
|
+
lastSyncedVersion = /* @__PURE__ */ new Map();
|
|
3889
|
+
lastSyncedZIndex = /* @__PURE__ */ new Map();
|
|
3794
3890
|
constructor(deps) {
|
|
3795
3891
|
this.domLayer = deps.domLayer;
|
|
3796
3892
|
this.onEditRequest = deps.onEditRequest;
|
|
3797
3893
|
this.isEditingElement = deps.isEditingElement;
|
|
3894
|
+
this.getVersion = deps.getVersion ?? null;
|
|
3798
3895
|
}
|
|
3799
3896
|
getNode(id) {
|
|
3800
3897
|
return this.domNodes.get(id);
|
|
@@ -3813,6 +3910,17 @@ var DomNodeManager = class {
|
|
|
3813
3910
|
});
|
|
3814
3911
|
this.domLayer.appendChild(node);
|
|
3815
3912
|
this.domNodes.set(element.id, node);
|
|
3913
|
+
} else if (this.getVersion) {
|
|
3914
|
+
const currentVersion = this.getVersion(element.id);
|
|
3915
|
+
const lastVersion = this.lastSyncedVersion.get(element.id);
|
|
3916
|
+
const lastZ = this.lastSyncedZIndex.get(element.id);
|
|
3917
|
+
if (lastVersion === currentVersion && lastZ === zIndex) {
|
|
3918
|
+
return;
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
if (this.getVersion) {
|
|
3922
|
+
this.lastSyncedVersion.set(element.id, this.getVersion(element.id));
|
|
3923
|
+
this.lastSyncedZIndex.set(element.id, zIndex);
|
|
3816
3924
|
}
|
|
3817
3925
|
const size = "size" in element ? element.size : null;
|
|
3818
3926
|
Object.assign(node.style, {
|
|
@@ -3831,6 +3939,8 @@ var DomNodeManager = class {
|
|
|
3831
3939
|
}
|
|
3832
3940
|
removeDomNode(id) {
|
|
3833
3941
|
this.htmlContent.delete(id);
|
|
3942
|
+
this.lastSyncedVersion.delete(id);
|
|
3943
|
+
this.lastSyncedZIndex.delete(id);
|
|
3834
3944
|
const node = this.domNodes.get(id);
|
|
3835
3945
|
if (node) {
|
|
3836
3946
|
node.remove();
|
|
@@ -3841,6 +3951,8 @@ var DomNodeManager = class {
|
|
|
3841
3951
|
this.domNodes.forEach((node) => node.remove());
|
|
3842
3952
|
this.domNodes.clear();
|
|
3843
3953
|
this.htmlContent.clear();
|
|
3954
|
+
this.lastSyncedVersion.clear();
|
|
3955
|
+
this.lastSyncedZIndex.clear();
|
|
3844
3956
|
}
|
|
3845
3957
|
reattachHtmlContent(store) {
|
|
3846
3958
|
for (const el of store.getElementsByType("html")) {
|
|
@@ -4360,7 +4472,8 @@ var Viewport = class {
|
|
|
4360
4472
|
this.domNodeManager = new DomNodeManager({
|
|
4361
4473
|
domLayer: this.domLayer,
|
|
4362
4474
|
onEditRequest: (id) => this.startEditingElement(id),
|
|
4363
|
-
isEditingElement: (id) => this.noteEditor.isEditing && this.noteEditor.editingElementId === id
|
|
4475
|
+
isEditingElement: (id) => this.noteEditor.isEditing && this.noteEditor.editingElementId === id,
|
|
4476
|
+
getVersion: (id) => this.store.getVersion(id)
|
|
4364
4477
|
});
|
|
4365
4478
|
this.interactMode = new InteractMode({
|
|
4366
4479
|
getNode: (id) => this.domNodeManager.getNode(id)
|
|
@@ -5183,6 +5296,7 @@ var SelectTool = class {
|
|
|
5183
5296
|
ctx = null;
|
|
5184
5297
|
pendingSingleSelectId = null;
|
|
5185
5298
|
hasDragged = false;
|
|
5299
|
+
resizeAspectRatio = 0;
|
|
5186
5300
|
get selectedIds() {
|
|
5187
5301
|
return [...this._selectedIds];
|
|
5188
5302
|
}
|
|
@@ -5228,7 +5342,8 @@ var SelectTool = class {
|
|
|
5228
5342
|
const resizeHit = this.hitTestResizeHandle(world, ctx);
|
|
5229
5343
|
if (resizeHit) {
|
|
5230
5344
|
const el = ctx.store.getById(resizeHit.elementId);
|
|
5231
|
-
if (el) {
|
|
5345
|
+
if (el && "size" in el) {
|
|
5346
|
+
this.resizeAspectRatio = el.size.h > 0 ? el.size.w / el.size.h : 0;
|
|
5232
5347
|
this.mode = {
|
|
5233
5348
|
type: "resizing",
|
|
5234
5349
|
elementId: resizeHit.elementId,
|
|
@@ -5280,7 +5395,7 @@ var SelectTool = class {
|
|
|
5280
5395
|
}
|
|
5281
5396
|
if (this.mode.type === "resizing") {
|
|
5282
5397
|
ctx.setCursor?.(HANDLE_CURSORS[this.mode.handle]);
|
|
5283
|
-
this.handleResize(world, ctx);
|
|
5398
|
+
this.handleResize(world, ctx, state.shiftKey);
|
|
5284
5399
|
return;
|
|
5285
5400
|
}
|
|
5286
5401
|
if (this.mode.type === "dragging" && this._selectedIds.length > 0) {
|
|
@@ -5404,7 +5519,7 @@ var SelectTool = class {
|
|
|
5404
5519
|
const hit = this.hitTest(world, ctx);
|
|
5405
5520
|
ctx.setCursor?.(hit ? "move" : "default");
|
|
5406
5521
|
}
|
|
5407
|
-
handleResize(world, ctx) {
|
|
5522
|
+
handleResize(world, ctx, shiftKey = false) {
|
|
5408
5523
|
if (this.mode.type !== "resizing") return;
|
|
5409
5524
|
const el = ctx.store.getById(this.mode.elementId);
|
|
5410
5525
|
if (!el || !("size" in el) || el.locked) return;
|
|
@@ -5435,6 +5550,21 @@ var SelectTool = class {
|
|
|
5435
5550
|
h -= dy;
|
|
5436
5551
|
break;
|
|
5437
5552
|
}
|
|
5553
|
+
if (shiftKey && this.resizeAspectRatio > 0) {
|
|
5554
|
+
const absDw = Math.abs(w - el.size.w);
|
|
5555
|
+
const absDh = Math.abs(h - el.size.h);
|
|
5556
|
+
if (absDw >= absDh) {
|
|
5557
|
+
h = w / this.resizeAspectRatio;
|
|
5558
|
+
} else {
|
|
5559
|
+
w = h * this.resizeAspectRatio;
|
|
5560
|
+
}
|
|
5561
|
+
if (handle === "nw" || handle === "sw") {
|
|
5562
|
+
x = el.position.x + el.size.w - w;
|
|
5563
|
+
}
|
|
5564
|
+
if (handle === "nw" || handle === "ne") {
|
|
5565
|
+
y = el.position.y + el.size.h - h;
|
|
5566
|
+
}
|
|
5567
|
+
}
|
|
5438
5568
|
if (w < MIN_ELEMENT_SIZE) {
|
|
5439
5569
|
if (handle === "nw" || handle === "sw") x = el.position.x + el.size.w - MIN_ELEMENT_SIZE;
|
|
5440
5570
|
w = MIN_ELEMENT_SIZE;
|
|
@@ -6538,7 +6668,7 @@ var UpdateLayerCommand = class {
|
|
|
6538
6668
|
};
|
|
6539
6669
|
|
|
6540
6670
|
// src/index.ts
|
|
6541
|
-
var VERSION = "0.
|
|
6671
|
+
var VERSION = "0.15.0";
|
|
6542
6672
|
export {
|
|
6543
6673
|
AddElementCommand,
|
|
6544
6674
|
ArrowTool,
|