@fieldnotes/core 0.38.2 → 0.38.3
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 +180 -156
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -14
- package/dist/index.d.ts +2 -14
- package/dist/index.js +180 -156
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -6059,9 +6059,158 @@ var GridController = class {
|
|
|
6059
6059
|
}
|
|
6060
6060
|
};
|
|
6061
6061
|
|
|
6062
|
+
// src/canvas/viewport-interactions.ts
|
|
6063
|
+
var ARROW_HIT_THRESHOLD = 10;
|
|
6064
|
+
var ViewportInteractions = class {
|
|
6065
|
+
constructor(deps) {
|
|
6066
|
+
this.deps = deps;
|
|
6067
|
+
}
|
|
6068
|
+
doubleTapDetector = new DoubleTapDetector();
|
|
6069
|
+
tapDownX = 0;
|
|
6070
|
+
tapDownY = 0;
|
|
6071
|
+
startEditingElement(id) {
|
|
6072
|
+
const element = this.deps.store.getById(id);
|
|
6073
|
+
if (!element || element.type !== "note" && element.type !== "text") return;
|
|
6074
|
+
this.deps.renderLoop.flush();
|
|
6075
|
+
const node = this.deps.domNodeManager.getNode(id);
|
|
6076
|
+
if (node) {
|
|
6077
|
+
this.deps.noteEditor.startEditing(node, id, this.deps.store);
|
|
6078
|
+
}
|
|
6079
|
+
}
|
|
6080
|
+
fitNoteHeight(elementId) {
|
|
6081
|
+
const element = this.deps.store.getById(elementId);
|
|
6082
|
+
if (!element || element.type !== "note") return;
|
|
6083
|
+
if (isNoteContentEmpty(element.text)) return;
|
|
6084
|
+
const node = this.deps.domNodeManager.getNode(elementId);
|
|
6085
|
+
if (!node) return;
|
|
6086
|
+
const measured = node.scrollHeight;
|
|
6087
|
+
if (measured > element.size.h) {
|
|
6088
|
+
this.deps.store.update(elementId, { size: { w: element.size.w, h: measured } });
|
|
6089
|
+
}
|
|
6090
|
+
}
|
|
6091
|
+
onTextEditStop(elementId) {
|
|
6092
|
+
const element = this.deps.store.getById(elementId);
|
|
6093
|
+
if (!element) return;
|
|
6094
|
+
if (element.type === "note") {
|
|
6095
|
+
if (isNoteContentEmpty(element.text)) {
|
|
6096
|
+
this.deps.store.remove(elementId);
|
|
6097
|
+
return;
|
|
6098
|
+
}
|
|
6099
|
+
this.fitNoteHeight(elementId);
|
|
6100
|
+
return;
|
|
6101
|
+
}
|
|
6102
|
+
if (element.type !== "text") return;
|
|
6103
|
+
if (!element.text || element.text.trim() === "") {
|
|
6104
|
+
this.deps.store.remove(elementId);
|
|
6105
|
+
return;
|
|
6106
|
+
}
|
|
6107
|
+
const node = this.deps.domNodeManager.getNode(elementId);
|
|
6108
|
+
if (node && "size" in element) {
|
|
6109
|
+
const measured = node.scrollHeight;
|
|
6110
|
+
if (measured !== element.size.h) {
|
|
6111
|
+
this.deps.store.update(elementId, { size: { w: element.size.w, h: measured } });
|
|
6112
|
+
}
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
|
+
onTapDown = (e) => {
|
|
6116
|
+
this.tapDownX = e.clientX;
|
|
6117
|
+
this.tapDownY = e.clientY;
|
|
6118
|
+
};
|
|
6119
|
+
onDoubleTap = (e) => {
|
|
6120
|
+
const dx = e.clientX - this.tapDownX;
|
|
6121
|
+
const dy = e.clientY - this.tapDownY;
|
|
6122
|
+
const moved = Math.sqrt(dx * dx + dy * dy);
|
|
6123
|
+
if (moved > 10) return;
|
|
6124
|
+
if (!this.doubleTapDetector.feed(e)) return;
|
|
6125
|
+
if (typeof document.elementFromPoint !== "function") return;
|
|
6126
|
+
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
6127
|
+
const nodeEl = el?.closest("[data-element-id]");
|
|
6128
|
+
if (nodeEl) {
|
|
6129
|
+
const elementId = nodeEl.dataset["elementId"];
|
|
6130
|
+
if (elementId) {
|
|
6131
|
+
const element = this.deps.store.getById(elementId);
|
|
6132
|
+
if (element?.type === "note" || element?.type === "text") {
|
|
6133
|
+
this.startEditingElement(elementId);
|
|
6134
|
+
return;
|
|
6135
|
+
}
|
|
6136
|
+
}
|
|
6137
|
+
}
|
|
6138
|
+
const rect = this.deps.wrapper.getBoundingClientRect();
|
|
6139
|
+
const screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
6140
|
+
const world = this.deps.camera.screenToWorld(screen);
|
|
6141
|
+
const hit = this.hitTestWorld(world);
|
|
6142
|
+
if (hit?.type === "html") {
|
|
6143
|
+
this.deps.interactMode.startInteracting(hit.id);
|
|
6144
|
+
return;
|
|
6145
|
+
}
|
|
6146
|
+
const arrow = this.findArrowAt(world);
|
|
6147
|
+
if (arrow) {
|
|
6148
|
+
this.startArrowLabelEdit(arrow);
|
|
6149
|
+
}
|
|
6150
|
+
};
|
|
6151
|
+
findArrowAt(world) {
|
|
6152
|
+
const candidates = this.deps.store.queryPoint(world).reverse();
|
|
6153
|
+
for (const el of candidates) {
|
|
6154
|
+
if (el.type === "arrow" && isNearBezier(world, el.from, el.to, el.bend, ARROW_HIT_THRESHOLD)) {
|
|
6155
|
+
return el;
|
|
6156
|
+
}
|
|
6157
|
+
}
|
|
6158
|
+
return void 0;
|
|
6159
|
+
}
|
|
6160
|
+
startArrowLabelEdit(arrow) {
|
|
6161
|
+
this.deps.arrowLabelEditor.startEditing({
|
|
6162
|
+
arrow,
|
|
6163
|
+
layer: this.deps.domLayer,
|
|
6164
|
+
store: this.deps.store,
|
|
6165
|
+
recorder: this.deps.recorder,
|
|
6166
|
+
onDone: () => {
|
|
6167
|
+
this.deps.renderer.setLabelEditingId(null);
|
|
6168
|
+
this.deps.requestRender();
|
|
6169
|
+
}
|
|
6170
|
+
});
|
|
6171
|
+
this.deps.renderer.setLabelEditingId(arrow.id);
|
|
6172
|
+
}
|
|
6173
|
+
hitTestWorld(world) {
|
|
6174
|
+
const candidates = this.deps.store.queryPoint(world).reverse();
|
|
6175
|
+
for (const el of candidates) {
|
|
6176
|
+
if (!("size" in el)) continue;
|
|
6177
|
+
const { x, y } = el.position;
|
|
6178
|
+
const { w, h } = el.size;
|
|
6179
|
+
if (world.x >= x && world.x <= x + w && world.y >= y && world.y <= y + h) {
|
|
6180
|
+
return el;
|
|
6181
|
+
}
|
|
6182
|
+
}
|
|
6183
|
+
return null;
|
|
6184
|
+
}
|
|
6185
|
+
onDragOver = (e) => {
|
|
6186
|
+
e.preventDefault();
|
|
6187
|
+
};
|
|
6188
|
+
onDrop = (e) => {
|
|
6189
|
+
e.preventDefault();
|
|
6190
|
+
const rect = this.deps.wrapper.getBoundingClientRect();
|
|
6191
|
+
const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
6192
|
+
const worldPos = this.deps.camera.screenToWorld(screenPos);
|
|
6193
|
+
if (this.deps.dropHandler) {
|
|
6194
|
+
this.deps.dropHandler(e, worldPos);
|
|
6195
|
+
return;
|
|
6196
|
+
}
|
|
6197
|
+
const files = e.dataTransfer?.files;
|
|
6198
|
+
if (!files) return;
|
|
6199
|
+
for (const file of files) {
|
|
6200
|
+
if (!file.type.startsWith("image/")) continue;
|
|
6201
|
+
const reader = new FileReader();
|
|
6202
|
+
reader.onload = () => {
|
|
6203
|
+
const src = reader.result;
|
|
6204
|
+
if (typeof src !== "string") return;
|
|
6205
|
+
this.deps.addImage(src, worldPos);
|
|
6206
|
+
};
|
|
6207
|
+
reader.readAsDataURL(file);
|
|
6208
|
+
}
|
|
6209
|
+
};
|
|
6210
|
+
};
|
|
6211
|
+
|
|
6062
6212
|
// src/canvas/viewport.ts
|
|
6063
6213
|
var EMPTY_IDS = [];
|
|
6064
|
-
var ARROW_HIT_THRESHOLD = 10;
|
|
6065
6214
|
function noop() {
|
|
6066
6215
|
}
|
|
6067
6216
|
var Viewport = class {
|
|
@@ -6096,7 +6245,7 @@ var Viewport = class {
|
|
|
6096
6245
|
toolbar: options.toolbar,
|
|
6097
6246
|
placeholder: options.placeholder
|
|
6098
6247
|
});
|
|
6099
|
-
this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
|
|
6248
|
+
this.noteEditor.setOnStop((id) => this.interactions.onTextEditStop(id));
|
|
6100
6249
|
this.arrowLabelEditor = new ArrowLabelEditor();
|
|
6101
6250
|
this.noteEditor.setHistoryHooks(
|
|
6102
6251
|
() => this.historyRecorder.begin(),
|
|
@@ -6123,8 +6272,8 @@ var Viewport = class {
|
|
|
6123
6272
|
store: this.store,
|
|
6124
6273
|
requestRender: () => this.requestRender(),
|
|
6125
6274
|
switchTool: (name) => this.toolManager.setTool(name, this.toolContext),
|
|
6126
|
-
editElement: (id) => this.startEditingElement(id),
|
|
6127
|
-
fitNoteHeight: (id) => this.fitNoteHeight(id),
|
|
6275
|
+
editElement: (id) => this.interactions.startEditingElement(id),
|
|
6276
|
+
fitNoteHeight: (id) => this.interactions.fitNoteHeight(id),
|
|
6128
6277
|
setCursor: (cursor) => {
|
|
6129
6278
|
this.wrapper.style.cursor = cursor;
|
|
6130
6279
|
},
|
|
@@ -6160,7 +6309,7 @@ var Viewport = class {
|
|
|
6160
6309
|
this.unsubToolChange = this.toolManager.onChange(() => this.contextMenu?.close());
|
|
6161
6310
|
this.domNodeManager = new DomNodeManager({
|
|
6162
6311
|
domLayer: this.domLayer,
|
|
6163
|
-
onEditRequest: (id) => this.startEditingElement(id),
|
|
6312
|
+
onEditRequest: (id) => this.interactions.startEditingElement(id),
|
|
6164
6313
|
isEditingElement: (id) => this.noteEditor.isEditing && this.noteEditor.editingElementId === id,
|
|
6165
6314
|
getVersion: (id) => this.store.getVersion(id)
|
|
6166
6315
|
});
|
|
@@ -6232,10 +6381,26 @@ var Viewport = class {
|
|
|
6232
6381
|
this.toolContext.activeLayerId = this.layerManager.activeLayerId;
|
|
6233
6382
|
this.requestRender();
|
|
6234
6383
|
});
|
|
6235
|
-
this.
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6384
|
+
this.interactions = new ViewportInteractions({
|
|
6385
|
+
store: this.store,
|
|
6386
|
+
camera: this.camera,
|
|
6387
|
+
wrapper: this.wrapper,
|
|
6388
|
+
domLayer: this.domLayer,
|
|
6389
|
+
renderLoop: this.renderLoop,
|
|
6390
|
+
domNodeManager: this.domNodeManager,
|
|
6391
|
+
noteEditor: this.noteEditor,
|
|
6392
|
+
arrowLabelEditor: this.arrowLabelEditor,
|
|
6393
|
+
interactMode: this.interactMode,
|
|
6394
|
+
renderer: this.renderer,
|
|
6395
|
+
recorder: this.historyRecorder,
|
|
6396
|
+
requestRender: () => this.requestRender(),
|
|
6397
|
+
addImage: (src, position) => this.addImage(src, position),
|
|
6398
|
+
dropHandler: this.dropHandler
|
|
6399
|
+
});
|
|
6400
|
+
this.wrapper.addEventListener("pointerdown", this.interactions.onTapDown);
|
|
6401
|
+
this.wrapper.addEventListener("pointerup", this.interactions.onDoubleTap);
|
|
6402
|
+
this.wrapper.addEventListener("dragover", this.interactions.onDragOver);
|
|
6403
|
+
this.wrapper.addEventListener("drop", this.interactions.onDrop);
|
|
6239
6404
|
this.observeResize();
|
|
6240
6405
|
this.syncCanvasSize();
|
|
6241
6406
|
this.renderLoop.start();
|
|
@@ -6271,9 +6436,7 @@ var Viewport = class {
|
|
|
6271
6436
|
onHtmlElementMount;
|
|
6272
6437
|
dropHandler;
|
|
6273
6438
|
gridController;
|
|
6274
|
-
|
|
6275
|
-
tapDownX = 0;
|
|
6276
|
-
tapDownY = 0;
|
|
6439
|
+
interactions;
|
|
6277
6440
|
contextMenu = null;
|
|
6278
6441
|
get ctx() {
|
|
6279
6442
|
return this.canvasEl.getContext("2d");
|
|
@@ -6534,10 +6697,10 @@ var Viewport = class {
|
|
|
6534
6697
|
this.arrowLabelEditor.cancel();
|
|
6535
6698
|
this.historyRecorder.destroy();
|
|
6536
6699
|
this.contextMenu?.dispose();
|
|
6537
|
-
this.wrapper.removeEventListener("pointerdown", this.onTapDown);
|
|
6538
|
-
this.wrapper.removeEventListener("pointerup", this.onDoubleTap);
|
|
6539
|
-
this.wrapper.removeEventListener("dragover", this.onDragOver);
|
|
6540
|
-
this.wrapper.removeEventListener("drop", this.onDrop);
|
|
6700
|
+
this.wrapper.removeEventListener("pointerdown", this.interactions.onTapDown);
|
|
6701
|
+
this.wrapper.removeEventListener("pointerup", this.interactions.onDoubleTap);
|
|
6702
|
+
this.wrapper.removeEventListener("dragover", this.interactions.onDragOver);
|
|
6703
|
+
this.wrapper.removeEventListener("drop", this.interactions.onDrop);
|
|
6541
6704
|
this.inputHandler.destroy();
|
|
6542
6705
|
this.unsubCamera();
|
|
6543
6706
|
this.unsubToolChange();
|
|
@@ -6546,148 +6709,9 @@ var Viewport = class {
|
|
|
6546
6709
|
this.resizeObserver = null;
|
|
6547
6710
|
this.wrapper.remove();
|
|
6548
6711
|
}
|
|
6549
|
-
startEditingElement(id) {
|
|
6550
|
-
const element = this.store.getById(id);
|
|
6551
|
-
if (!element || element.type !== "note" && element.type !== "text") return;
|
|
6552
|
-
this.renderLoop.flush();
|
|
6553
|
-
const node = this.domNodeManager.getNode(id);
|
|
6554
|
-
if (node) {
|
|
6555
|
-
this.noteEditor.startEditing(node, id, this.store);
|
|
6556
|
-
}
|
|
6557
|
-
}
|
|
6558
|
-
fitNoteHeight(elementId) {
|
|
6559
|
-
const element = this.store.getById(elementId);
|
|
6560
|
-
if (!element || element.type !== "note") return;
|
|
6561
|
-
if (isNoteContentEmpty(element.text)) return;
|
|
6562
|
-
const node = this.domNodeManager.getNode(elementId);
|
|
6563
|
-
if (!node) return;
|
|
6564
|
-
const measured = node.scrollHeight;
|
|
6565
|
-
if (measured > element.size.h) {
|
|
6566
|
-
this.store.update(elementId, { size: { w: element.size.w, h: measured } });
|
|
6567
|
-
}
|
|
6568
|
-
}
|
|
6569
|
-
onTextEditStop(elementId) {
|
|
6570
|
-
const element = this.store.getById(elementId);
|
|
6571
|
-
if (!element) return;
|
|
6572
|
-
if (element.type === "note") {
|
|
6573
|
-
if (isNoteContentEmpty(element.text)) {
|
|
6574
|
-
this.store.remove(elementId);
|
|
6575
|
-
return;
|
|
6576
|
-
}
|
|
6577
|
-
this.fitNoteHeight(elementId);
|
|
6578
|
-
return;
|
|
6579
|
-
}
|
|
6580
|
-
if (element.type !== "text") return;
|
|
6581
|
-
if (!element.text || element.text.trim() === "") {
|
|
6582
|
-
this.store.remove(elementId);
|
|
6583
|
-
return;
|
|
6584
|
-
}
|
|
6585
|
-
const node = this.domNodeManager.getNode(elementId);
|
|
6586
|
-
if (node && "size" in element) {
|
|
6587
|
-
const measured = node.scrollHeight;
|
|
6588
|
-
if (measured !== element.size.h) {
|
|
6589
|
-
this.store.update(elementId, { size: { w: element.size.w, h: measured } });
|
|
6590
|
-
}
|
|
6591
|
-
}
|
|
6592
|
-
}
|
|
6593
|
-
onTapDown = (e) => {
|
|
6594
|
-
this.tapDownX = e.clientX;
|
|
6595
|
-
this.tapDownY = e.clientY;
|
|
6596
|
-
};
|
|
6597
|
-
onDoubleTap = (e) => {
|
|
6598
|
-
const dx = e.clientX - this.tapDownX;
|
|
6599
|
-
const dy = e.clientY - this.tapDownY;
|
|
6600
|
-
const moved = Math.sqrt(dx * dx + dy * dy);
|
|
6601
|
-
if (moved > 10) return;
|
|
6602
|
-
if (!this.doubleTapDetector.feed(e)) return;
|
|
6603
|
-
if (typeof document.elementFromPoint !== "function") return;
|
|
6604
|
-
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
6605
|
-
const nodeEl = el?.closest("[data-element-id]");
|
|
6606
|
-
if (nodeEl) {
|
|
6607
|
-
const elementId = nodeEl.dataset["elementId"];
|
|
6608
|
-
if (elementId) {
|
|
6609
|
-
const element = this.store.getById(elementId);
|
|
6610
|
-
if (element?.type === "note" || element?.type === "text") {
|
|
6611
|
-
this.startEditingElement(elementId);
|
|
6612
|
-
return;
|
|
6613
|
-
}
|
|
6614
|
-
}
|
|
6615
|
-
}
|
|
6616
|
-
const rect = this.wrapper.getBoundingClientRect();
|
|
6617
|
-
const screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
6618
|
-
const world = this.camera.screenToWorld(screen);
|
|
6619
|
-
const hit = this.hitTestWorld(world);
|
|
6620
|
-
if (hit?.type === "html") {
|
|
6621
|
-
this.interactMode.startInteracting(hit.id);
|
|
6622
|
-
return;
|
|
6623
|
-
}
|
|
6624
|
-
const arrow = this.findArrowAt(world);
|
|
6625
|
-
if (arrow) {
|
|
6626
|
-
this.startArrowLabelEdit(arrow);
|
|
6627
|
-
}
|
|
6628
|
-
};
|
|
6629
|
-
findArrowAt(world) {
|
|
6630
|
-
const candidates = this.store.queryPoint(world).reverse();
|
|
6631
|
-
for (const el of candidates) {
|
|
6632
|
-
if (el.type === "arrow" && isNearBezier(world, el.from, el.to, el.bend, ARROW_HIT_THRESHOLD)) {
|
|
6633
|
-
return el;
|
|
6634
|
-
}
|
|
6635
|
-
}
|
|
6636
|
-
return void 0;
|
|
6637
|
-
}
|
|
6638
|
-
startArrowLabelEdit(arrow) {
|
|
6639
|
-
this.arrowLabelEditor.startEditing({
|
|
6640
|
-
arrow,
|
|
6641
|
-
layer: this.domLayer,
|
|
6642
|
-
store: this.store,
|
|
6643
|
-
recorder: this.historyRecorder,
|
|
6644
|
-
onDone: () => {
|
|
6645
|
-
this.renderer.setLabelEditingId(null);
|
|
6646
|
-
this.requestRender();
|
|
6647
|
-
}
|
|
6648
|
-
});
|
|
6649
|
-
this.renderer.setLabelEditingId(arrow.id);
|
|
6650
|
-
}
|
|
6651
|
-
hitTestWorld(world) {
|
|
6652
|
-
const candidates = this.store.queryPoint(world).reverse();
|
|
6653
|
-
for (const el of candidates) {
|
|
6654
|
-
if (!("size" in el)) continue;
|
|
6655
|
-
const { x, y } = el.position;
|
|
6656
|
-
const { w, h } = el.size;
|
|
6657
|
-
if (world.x >= x && world.x <= x + w && world.y >= y && world.y <= y + h) {
|
|
6658
|
-
return el;
|
|
6659
|
-
}
|
|
6660
|
-
}
|
|
6661
|
-
return null;
|
|
6662
|
-
}
|
|
6663
6712
|
stopInteracting() {
|
|
6664
6713
|
this.interactMode.stopInteracting();
|
|
6665
6714
|
}
|
|
6666
|
-
onDragOver = (e) => {
|
|
6667
|
-
e.preventDefault();
|
|
6668
|
-
};
|
|
6669
|
-
onDrop = (e) => {
|
|
6670
|
-
e.preventDefault();
|
|
6671
|
-
const rect = this.wrapper.getBoundingClientRect();
|
|
6672
|
-
const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
6673
|
-
const worldPos = this.camera.screenToWorld(screenPos);
|
|
6674
|
-
if (this.dropHandler) {
|
|
6675
|
-
this.dropHandler(e, worldPos);
|
|
6676
|
-
return;
|
|
6677
|
-
}
|
|
6678
|
-
const files = e.dataTransfer?.files;
|
|
6679
|
-
if (!files) return;
|
|
6680
|
-
for (const file of files) {
|
|
6681
|
-
if (!file.type.startsWith("image/")) continue;
|
|
6682
|
-
const reader = new FileReader();
|
|
6683
|
-
reader.onload = () => {
|
|
6684
|
-
const src = reader.result;
|
|
6685
|
-
if (typeof src !== "string") return;
|
|
6686
|
-
this.addImage(src, worldPos);
|
|
6687
|
-
};
|
|
6688
|
-
reader.readAsDataURL(file);
|
|
6689
|
-
}
|
|
6690
|
-
};
|
|
6691
6715
|
unbindArrowsFrom(removedElement) {
|
|
6692
6716
|
const boundArrows = findBoundArrows(removedElement.id, this.store);
|
|
6693
6717
|
const bounds = getElementBounds(removedElement);
|
|
@@ -9044,7 +9068,7 @@ var TemplateTool = class {
|
|
|
9044
9068
|
};
|
|
9045
9069
|
|
|
9046
9070
|
// src/index.ts
|
|
9047
|
-
var VERSION = "0.38.
|
|
9071
|
+
var VERSION = "0.38.3";
|
|
9048
9072
|
// Annotate the CommonJS export names for ESM import in node:
|
|
9049
9073
|
0 && (module.exports = {
|
|
9050
9074
|
ArrowTool,
|