@fieldnotes/core 0.11.1 → 0.11.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 +105 -4
- package/dist/index.d.cts +27 -2
- package/dist/index.d.ts +27 -2
- package/dist/index.js +104 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -37,6 +37,7 @@ __export(index_exports, {
|
|
|
37
37
|
HistoryRecorder: () => HistoryRecorder,
|
|
38
38
|
HistoryStack: () => HistoryStack,
|
|
39
39
|
ImageTool: () => ImageTool,
|
|
40
|
+
InputFilter: () => InputFilter,
|
|
40
41
|
InputHandler: () => InputHandler,
|
|
41
42
|
LayerManager: () => LayerManager,
|
|
42
43
|
MeasureTool: () => MeasureTool,
|
|
@@ -842,6 +843,61 @@ var Background = class {
|
|
|
842
843
|
}
|
|
843
844
|
};
|
|
844
845
|
|
|
846
|
+
// src/canvas/input-filter.ts
|
|
847
|
+
var InputFilter = class _InputFilter {
|
|
848
|
+
activePenId = null;
|
|
849
|
+
pendingTap = null;
|
|
850
|
+
static MIN_MOVE_DISTANCE = 3;
|
|
851
|
+
filterDown(e) {
|
|
852
|
+
if (e.pointerType === "pen") {
|
|
853
|
+
this.activePenId = e.pointerId;
|
|
854
|
+
return { event: e, action: "dispatch" };
|
|
855
|
+
}
|
|
856
|
+
if (e.pointerType === "touch" && this.activePenId !== null) {
|
|
857
|
+
return { event: e, action: "suppress" };
|
|
858
|
+
}
|
|
859
|
+
if (e.pointerType === "touch") {
|
|
860
|
+
this.pendingTap = { pointerId: e.pointerId, x: e.clientX, y: e.clientY };
|
|
861
|
+
return { event: e, action: "defer" };
|
|
862
|
+
}
|
|
863
|
+
return { event: e, action: "dispatch" };
|
|
864
|
+
}
|
|
865
|
+
filterMove(e) {
|
|
866
|
+
if (e.pointerType === "touch" && this.activePenId !== null) {
|
|
867
|
+
return { event: e, action: "suppress" };
|
|
868
|
+
}
|
|
869
|
+
if (this.pendingTap && e.pointerId === this.pendingTap.pointerId) {
|
|
870
|
+
const dx = e.clientX - this.pendingTap.x;
|
|
871
|
+
const dy = e.clientY - this.pendingTap.y;
|
|
872
|
+
if (dx * dx + dy * dy > _InputFilter.MIN_MOVE_DISTANCE * _InputFilter.MIN_MOVE_DISTANCE) {
|
|
873
|
+
this.pendingTap = null;
|
|
874
|
+
return { event: e, action: "dispatch" };
|
|
875
|
+
}
|
|
876
|
+
return { event: e, action: "suppress" };
|
|
877
|
+
}
|
|
878
|
+
return { event: e, action: "dispatch" };
|
|
879
|
+
}
|
|
880
|
+
filterUp(e) {
|
|
881
|
+
if (e.pointerId === this.activePenId) {
|
|
882
|
+
this.activePenId = null;
|
|
883
|
+
return { event: e, action: "dispatch" };
|
|
884
|
+
}
|
|
885
|
+
if (e.pointerType === "touch" && this.activePenId !== null) {
|
|
886
|
+
return { event: e, action: "suppress" };
|
|
887
|
+
}
|
|
888
|
+
if (this.pendingTap && e.pointerId === this.pendingTap.pointerId) {
|
|
889
|
+
const tap = { x: this.pendingTap.x, y: this.pendingTap.y };
|
|
890
|
+
this.pendingTap = null;
|
|
891
|
+
return { event: e, action: "dispatch", pendingTap: tap };
|
|
892
|
+
}
|
|
893
|
+
return { event: e, action: "dispatch" };
|
|
894
|
+
}
|
|
895
|
+
reset() {
|
|
896
|
+
this.activePenId = null;
|
|
897
|
+
this.pendingTap = null;
|
|
898
|
+
}
|
|
899
|
+
};
|
|
900
|
+
|
|
845
901
|
// src/canvas/input-handler.ts
|
|
846
902
|
var ZOOM_SENSITIVITY = 1e-3;
|
|
847
903
|
var MIDDLE_BUTTON = 1;
|
|
@@ -868,6 +924,8 @@ var InputHandler = class {
|
|
|
868
924
|
historyStack;
|
|
869
925
|
isToolActive = false;
|
|
870
926
|
lastPointerEvent = null;
|
|
927
|
+
inputFilter = new InputFilter();
|
|
928
|
+
deferredDown = null;
|
|
871
929
|
abortController = new AbortController();
|
|
872
930
|
setToolManager(toolManager, toolContext) {
|
|
873
931
|
this.toolManager = toolManager;
|
|
@@ -875,6 +933,8 @@ var InputHandler = class {
|
|
|
875
933
|
}
|
|
876
934
|
destroy() {
|
|
877
935
|
this.abortController.abort();
|
|
936
|
+
this.inputFilter.reset();
|
|
937
|
+
this.deferredDown = null;
|
|
878
938
|
this.lastPointerEvent = null;
|
|
879
939
|
}
|
|
880
940
|
bind() {
|
|
@@ -912,6 +972,12 @@ var InputHandler = class {
|
|
|
912
972
|
return;
|
|
913
973
|
}
|
|
914
974
|
if (this.activePointers.size === 1 && (e.button === 0 || e.pointerType === "touch" || e.pointerType === "pen")) {
|
|
975
|
+
const result = this.inputFilter.filterDown(e);
|
|
976
|
+
if (result.action === "suppress") return;
|
|
977
|
+
if (result.action === "defer") {
|
|
978
|
+
this.deferredDown = e;
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
915
981
|
this.dispatchToolDown(e);
|
|
916
982
|
}
|
|
917
983
|
};
|
|
@@ -933,6 +999,13 @@ var InputHandler = class {
|
|
|
933
999
|
}
|
|
934
1000
|
if (this.isToolActive) {
|
|
935
1001
|
this.dispatchToolMove(e);
|
|
1002
|
+
} else if (this.deferredDown) {
|
|
1003
|
+
const result = this.inputFilter.filterMove(e);
|
|
1004
|
+
if (result.action === "dispatch") {
|
|
1005
|
+
this.dispatchToolDown(this.deferredDown);
|
|
1006
|
+
this.deferredDown = null;
|
|
1007
|
+
this.dispatchToolMove(e);
|
|
1008
|
+
}
|
|
936
1009
|
} else if (this.activePointers.size === 0) {
|
|
937
1010
|
this.dispatchToolHover(e);
|
|
938
1011
|
}
|
|
@@ -949,9 +1022,16 @@ var InputHandler = class {
|
|
|
949
1022
|
if (this.isPanning && this.activePointers.size === 0) {
|
|
950
1023
|
this.isPanning = false;
|
|
951
1024
|
}
|
|
1025
|
+
const upResult = this.inputFilter.filterUp(e);
|
|
952
1026
|
if (this.isToolActive) {
|
|
953
1027
|
this.dispatchToolUp(e);
|
|
954
1028
|
this.isToolActive = false;
|
|
1029
|
+
} else if (this.deferredDown && upResult.pendingTap) {
|
|
1030
|
+
this.dispatchToolDown(this.deferredDown);
|
|
1031
|
+
this.dispatchToolUp(e);
|
|
1032
|
+
this.deferredDown = null;
|
|
1033
|
+
} else {
|
|
1034
|
+
this.deferredDown = null;
|
|
955
1035
|
}
|
|
956
1036
|
};
|
|
957
1037
|
onKeyDown = (e) => {
|
|
@@ -984,6 +1064,8 @@ var InputHandler = class {
|
|
|
984
1064
|
}
|
|
985
1065
|
};
|
|
986
1066
|
startPinch() {
|
|
1067
|
+
this.inputFilter.reset();
|
|
1068
|
+
this.deferredDown = null;
|
|
987
1069
|
this.isPanning = true;
|
|
988
1070
|
const [a, b] = this.getPinchPoints();
|
|
989
1071
|
this.lastPinchDistance = this.distance(a, b);
|
|
@@ -1023,7 +1105,8 @@ var InputHandler = class {
|
|
|
1023
1105
|
return {
|
|
1024
1106
|
x: e.clientX - rect.left,
|
|
1025
1107
|
y: e.clientY - rect.top,
|
|
1026
|
-
pressure: e.pressure
|
|
1108
|
+
pressure: e.pressure,
|
|
1109
|
+
pointerType: e.pointerType === "touch" || e.pointerType === "pen" ? e.pointerType : "mouse"
|
|
1027
1110
|
};
|
|
1028
1111
|
}
|
|
1029
1112
|
dispatchToolDown(e) {
|
|
@@ -1081,6 +1164,7 @@ var InputHandler = class {
|
|
|
1081
1164
|
this.dispatchToolUp(e);
|
|
1082
1165
|
this.isToolActive = false;
|
|
1083
1166
|
}
|
|
1167
|
+
this.deferredDown = null;
|
|
1084
1168
|
}
|
|
1085
1169
|
};
|
|
1086
1170
|
|
|
@@ -1328,19 +1412,23 @@ var ElementStore = class {
|
|
|
1328
1412
|
bus = new EventBus();
|
|
1329
1413
|
layerOrderMap = /* @__PURE__ */ new Map();
|
|
1330
1414
|
spatialIndex = new Quadtree({ x: -1e5, y: -1e5, w: 2e5, h: 2e5 });
|
|
1415
|
+
sortedCache = null;
|
|
1331
1416
|
get count() {
|
|
1332
1417
|
return this.elements.size;
|
|
1333
1418
|
}
|
|
1334
1419
|
setLayerOrder(order) {
|
|
1335
1420
|
this.layerOrderMap = new Map(order);
|
|
1421
|
+
this.sortedCache = null;
|
|
1336
1422
|
}
|
|
1337
1423
|
getAll() {
|
|
1338
|
-
|
|
1424
|
+
if (this.sortedCache) return this.sortedCache;
|
|
1425
|
+
this.sortedCache = [...this.elements.values()].sort((a, b) => {
|
|
1339
1426
|
const layerA = this.layerOrderMap.get(a.layerId) ?? 0;
|
|
1340
1427
|
const layerB = this.layerOrderMap.get(b.layerId) ?? 0;
|
|
1341
1428
|
if (layerA !== layerB) return layerA - layerB;
|
|
1342
1429
|
return a.zIndex - b.zIndex;
|
|
1343
1430
|
});
|
|
1431
|
+
return this.sortedCache;
|
|
1344
1432
|
}
|
|
1345
1433
|
getById(id) {
|
|
1346
1434
|
return this.elements.get(id);
|
|
@@ -1351,6 +1439,7 @@ var ElementStore = class {
|
|
|
1351
1439
|
);
|
|
1352
1440
|
}
|
|
1353
1441
|
add(element) {
|
|
1442
|
+
this.sortedCache = null;
|
|
1354
1443
|
this.elements.set(element.id, element);
|
|
1355
1444
|
const bounds = getElementBounds(element);
|
|
1356
1445
|
if (bounds) this.spatialIndex.insert(element.id, bounds);
|
|
@@ -1359,11 +1448,15 @@ var ElementStore = class {
|
|
|
1359
1448
|
update(id, partial) {
|
|
1360
1449
|
const existing = this.elements.get(id);
|
|
1361
1450
|
if (!existing) return;
|
|
1451
|
+
this.sortedCache = null;
|
|
1362
1452
|
const updated = { ...existing, ...partial, id: existing.id, type: existing.type };
|
|
1363
1453
|
if (updated.type === "arrow") {
|
|
1364
1454
|
const arrow = updated;
|
|
1365
1455
|
arrow.cachedControlPoint = getArrowControlPoint(arrow.from, arrow.to, arrow.bend);
|
|
1366
1456
|
}
|
|
1457
|
+
if (updated.type === "note" && "text" in partial) {
|
|
1458
|
+
updated.text = sanitizeNoteHtml(updated.text);
|
|
1459
|
+
}
|
|
1367
1460
|
this.elements.set(id, updated);
|
|
1368
1461
|
const newBounds = getElementBounds(updated);
|
|
1369
1462
|
if (newBounds) {
|
|
@@ -1374,11 +1467,13 @@ var ElementStore = class {
|
|
|
1374
1467
|
remove(id) {
|
|
1375
1468
|
const element = this.elements.get(id);
|
|
1376
1469
|
if (!element) return;
|
|
1470
|
+
this.sortedCache = null;
|
|
1377
1471
|
this.elements.delete(id);
|
|
1378
1472
|
this.spatialIndex.remove(id);
|
|
1379
1473
|
this.bus.emit("remove", element);
|
|
1380
1474
|
}
|
|
1381
1475
|
clear() {
|
|
1476
|
+
this.sortedCache = null;
|
|
1382
1477
|
this.elements.clear();
|
|
1383
1478
|
this.spatialIndex.clear();
|
|
1384
1479
|
this.bus.emit("clear", null);
|
|
@@ -1387,6 +1482,7 @@ var ElementStore = class {
|
|
|
1387
1482
|
return this.getAll().map((el) => ({ ...el }));
|
|
1388
1483
|
}
|
|
1389
1484
|
loadSnapshot(elements) {
|
|
1485
|
+
this.sortedCache = null;
|
|
1390
1486
|
this.elements.clear();
|
|
1391
1487
|
this.spatialIndex.clear();
|
|
1392
1488
|
for (const el of elements) {
|
|
@@ -1394,6 +1490,10 @@ var ElementStore = class {
|
|
|
1394
1490
|
const bounds = getElementBounds(el);
|
|
1395
1491
|
if (bounds) this.spatialIndex.insert(el.id, bounds);
|
|
1396
1492
|
}
|
|
1493
|
+
this.bus.emit("clear", null);
|
|
1494
|
+
for (const el of elements) {
|
|
1495
|
+
this.bus.emit("add", el);
|
|
1496
|
+
}
|
|
1397
1497
|
}
|
|
1398
1498
|
queryRect(rect) {
|
|
1399
1499
|
const ids = this.spatialIndex.query(rect);
|
|
@@ -2474,7 +2574,7 @@ function createNote(input) {
|
|
|
2474
2574
|
locked: input.locked ?? false,
|
|
2475
2575
|
layerId: input.layerId ?? "",
|
|
2476
2576
|
size: input.size ?? { w: 200, h: 100 },
|
|
2477
|
-
text: input.text ?? "",
|
|
2577
|
+
text: sanitizeNoteHtml(input.text ?? ""),
|
|
2478
2578
|
backgroundColor: input.backgroundColor ?? "#ffeb3b",
|
|
2479
2579
|
textColor: input.textColor ?? "#000000",
|
|
2480
2580
|
fontSize: input.fontSize ?? DEFAULT_NOTE_FONT_SIZE
|
|
@@ -6330,7 +6430,7 @@ var UpdateLayerCommand = class {
|
|
|
6330
6430
|
};
|
|
6331
6431
|
|
|
6332
6432
|
// src/index.ts
|
|
6333
|
-
var VERSION = "0.11.
|
|
6433
|
+
var VERSION = "0.11.3";
|
|
6334
6434
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6335
6435
|
0 && (module.exports = {
|
|
6336
6436
|
AddElementCommand,
|
|
@@ -6350,6 +6450,7 @@ var VERSION = "0.11.0";
|
|
|
6350
6450
|
HistoryRecorder,
|
|
6351
6451
|
HistoryStack,
|
|
6352
6452
|
ImageTool,
|
|
6453
|
+
InputFilter,
|
|
6353
6454
|
InputHandler,
|
|
6354
6455
|
LayerManager,
|
|
6355
6456
|
MeasureTool,
|
package/dist/index.d.cts
CHANGED
|
@@ -200,6 +200,7 @@ declare class ElementStore {
|
|
|
200
200
|
private bus;
|
|
201
201
|
private layerOrderMap;
|
|
202
202
|
private spatialIndex;
|
|
203
|
+
private sortedCache;
|
|
203
204
|
get count(): number;
|
|
204
205
|
setLayerOrder(order: Map<string, number>): void;
|
|
205
206
|
getAll(): CanvasElement[];
|
|
@@ -238,6 +239,7 @@ interface PointerState {
|
|
|
238
239
|
x: number;
|
|
239
240
|
y: number;
|
|
240
241
|
pressure: number;
|
|
242
|
+
pointerType: 'mouse' | 'touch' | 'pen';
|
|
241
243
|
}
|
|
242
244
|
interface Tool {
|
|
243
245
|
readonly name: string;
|
|
@@ -424,6 +426,8 @@ declare class InputHandler {
|
|
|
424
426
|
private historyStack;
|
|
425
427
|
private isToolActive;
|
|
426
428
|
private lastPointerEvent;
|
|
429
|
+
private readonly inputFilter;
|
|
430
|
+
private deferredDown;
|
|
427
431
|
private readonly abortController;
|
|
428
432
|
constructor(element: HTMLElement, camera: Camera, options?: InputHandlerOptions);
|
|
429
433
|
setToolManager(toolManager: ToolManager, toolContext: ToolContext): void;
|
|
@@ -451,6 +455,27 @@ declare class InputHandler {
|
|
|
451
455
|
private cancelToolIfActive;
|
|
452
456
|
}
|
|
453
457
|
|
|
458
|
+
type FilterAction = 'dispatch' | 'suppress' | 'defer';
|
|
459
|
+
interface FilteredEvent {
|
|
460
|
+
event: PointerEvent;
|
|
461
|
+
action: FilterAction;
|
|
462
|
+
}
|
|
463
|
+
interface FilteredUpEvent extends FilteredEvent {
|
|
464
|
+
pendingTap?: {
|
|
465
|
+
x: number;
|
|
466
|
+
y: number;
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
declare class InputFilter {
|
|
470
|
+
private activePenId;
|
|
471
|
+
private pendingTap;
|
|
472
|
+
static readonly MIN_MOVE_DISTANCE = 3;
|
|
473
|
+
filterDown(e: PointerEvent): FilteredEvent;
|
|
474
|
+
filterMove(e: PointerEvent): FilteredEvent;
|
|
475
|
+
filterUp(e: PointerEvent): FilteredUpEvent;
|
|
476
|
+
reset(): void;
|
|
477
|
+
}
|
|
478
|
+
|
|
454
479
|
interface FontSizePreset {
|
|
455
480
|
label: string;
|
|
456
481
|
size: number;
|
|
@@ -1120,6 +1145,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1120
1145
|
undo(_store: ElementStore): void;
|
|
1121
1146
|
}
|
|
1122
1147
|
|
|
1123
|
-
declare const VERSION = "0.11.
|
|
1148
|
+
declare const VERSION = "0.11.3";
|
|
1124
1149
|
|
|
1125
|
-
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, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, 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, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
|
|
1150
|
+
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, 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, 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
|
@@ -200,6 +200,7 @@ declare class ElementStore {
|
|
|
200
200
|
private bus;
|
|
201
201
|
private layerOrderMap;
|
|
202
202
|
private spatialIndex;
|
|
203
|
+
private sortedCache;
|
|
203
204
|
get count(): number;
|
|
204
205
|
setLayerOrder(order: Map<string, number>): void;
|
|
205
206
|
getAll(): CanvasElement[];
|
|
@@ -238,6 +239,7 @@ interface PointerState {
|
|
|
238
239
|
x: number;
|
|
239
240
|
y: number;
|
|
240
241
|
pressure: number;
|
|
242
|
+
pointerType: 'mouse' | 'touch' | 'pen';
|
|
241
243
|
}
|
|
242
244
|
interface Tool {
|
|
243
245
|
readonly name: string;
|
|
@@ -424,6 +426,8 @@ declare class InputHandler {
|
|
|
424
426
|
private historyStack;
|
|
425
427
|
private isToolActive;
|
|
426
428
|
private lastPointerEvent;
|
|
429
|
+
private readonly inputFilter;
|
|
430
|
+
private deferredDown;
|
|
427
431
|
private readonly abortController;
|
|
428
432
|
constructor(element: HTMLElement, camera: Camera, options?: InputHandlerOptions);
|
|
429
433
|
setToolManager(toolManager: ToolManager, toolContext: ToolContext): void;
|
|
@@ -451,6 +455,27 @@ declare class InputHandler {
|
|
|
451
455
|
private cancelToolIfActive;
|
|
452
456
|
}
|
|
453
457
|
|
|
458
|
+
type FilterAction = 'dispatch' | 'suppress' | 'defer';
|
|
459
|
+
interface FilteredEvent {
|
|
460
|
+
event: PointerEvent;
|
|
461
|
+
action: FilterAction;
|
|
462
|
+
}
|
|
463
|
+
interface FilteredUpEvent extends FilteredEvent {
|
|
464
|
+
pendingTap?: {
|
|
465
|
+
x: number;
|
|
466
|
+
y: number;
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
declare class InputFilter {
|
|
470
|
+
private activePenId;
|
|
471
|
+
private pendingTap;
|
|
472
|
+
static readonly MIN_MOVE_DISTANCE = 3;
|
|
473
|
+
filterDown(e: PointerEvent): FilteredEvent;
|
|
474
|
+
filterMove(e: PointerEvent): FilteredEvent;
|
|
475
|
+
filterUp(e: PointerEvent): FilteredUpEvent;
|
|
476
|
+
reset(): void;
|
|
477
|
+
}
|
|
478
|
+
|
|
454
479
|
interface FontSizePreset {
|
|
455
480
|
label: string;
|
|
456
481
|
size: number;
|
|
@@ -1120,6 +1145,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1120
1145
|
undo(_store: ElementStore): void;
|
|
1121
1146
|
}
|
|
1122
1147
|
|
|
1123
|
-
declare const VERSION = "0.11.
|
|
1148
|
+
declare const VERSION = "0.11.3";
|
|
1124
1149
|
|
|
1125
|
-
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, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, 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, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
|
|
1150
|
+
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, 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, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
|
package/dist/index.js
CHANGED
|
@@ -736,6 +736,61 @@ var Background = class {
|
|
|
736
736
|
}
|
|
737
737
|
};
|
|
738
738
|
|
|
739
|
+
// src/canvas/input-filter.ts
|
|
740
|
+
var InputFilter = class _InputFilter {
|
|
741
|
+
activePenId = null;
|
|
742
|
+
pendingTap = null;
|
|
743
|
+
static MIN_MOVE_DISTANCE = 3;
|
|
744
|
+
filterDown(e) {
|
|
745
|
+
if (e.pointerType === "pen") {
|
|
746
|
+
this.activePenId = e.pointerId;
|
|
747
|
+
return { event: e, action: "dispatch" };
|
|
748
|
+
}
|
|
749
|
+
if (e.pointerType === "touch" && this.activePenId !== null) {
|
|
750
|
+
return { event: e, action: "suppress" };
|
|
751
|
+
}
|
|
752
|
+
if (e.pointerType === "touch") {
|
|
753
|
+
this.pendingTap = { pointerId: e.pointerId, x: e.clientX, y: e.clientY };
|
|
754
|
+
return { event: e, action: "defer" };
|
|
755
|
+
}
|
|
756
|
+
return { event: e, action: "dispatch" };
|
|
757
|
+
}
|
|
758
|
+
filterMove(e) {
|
|
759
|
+
if (e.pointerType === "touch" && this.activePenId !== null) {
|
|
760
|
+
return { event: e, action: "suppress" };
|
|
761
|
+
}
|
|
762
|
+
if (this.pendingTap && e.pointerId === this.pendingTap.pointerId) {
|
|
763
|
+
const dx = e.clientX - this.pendingTap.x;
|
|
764
|
+
const dy = e.clientY - this.pendingTap.y;
|
|
765
|
+
if (dx * dx + dy * dy > _InputFilter.MIN_MOVE_DISTANCE * _InputFilter.MIN_MOVE_DISTANCE) {
|
|
766
|
+
this.pendingTap = null;
|
|
767
|
+
return { event: e, action: "dispatch" };
|
|
768
|
+
}
|
|
769
|
+
return { event: e, action: "suppress" };
|
|
770
|
+
}
|
|
771
|
+
return { event: e, action: "dispatch" };
|
|
772
|
+
}
|
|
773
|
+
filterUp(e) {
|
|
774
|
+
if (e.pointerId === this.activePenId) {
|
|
775
|
+
this.activePenId = null;
|
|
776
|
+
return { event: e, action: "dispatch" };
|
|
777
|
+
}
|
|
778
|
+
if (e.pointerType === "touch" && this.activePenId !== null) {
|
|
779
|
+
return { event: e, action: "suppress" };
|
|
780
|
+
}
|
|
781
|
+
if (this.pendingTap && e.pointerId === this.pendingTap.pointerId) {
|
|
782
|
+
const tap = { x: this.pendingTap.x, y: this.pendingTap.y };
|
|
783
|
+
this.pendingTap = null;
|
|
784
|
+
return { event: e, action: "dispatch", pendingTap: tap };
|
|
785
|
+
}
|
|
786
|
+
return { event: e, action: "dispatch" };
|
|
787
|
+
}
|
|
788
|
+
reset() {
|
|
789
|
+
this.activePenId = null;
|
|
790
|
+
this.pendingTap = null;
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
|
|
739
794
|
// src/canvas/input-handler.ts
|
|
740
795
|
var ZOOM_SENSITIVITY = 1e-3;
|
|
741
796
|
var MIDDLE_BUTTON = 1;
|
|
@@ -762,6 +817,8 @@ var InputHandler = class {
|
|
|
762
817
|
historyStack;
|
|
763
818
|
isToolActive = false;
|
|
764
819
|
lastPointerEvent = null;
|
|
820
|
+
inputFilter = new InputFilter();
|
|
821
|
+
deferredDown = null;
|
|
765
822
|
abortController = new AbortController();
|
|
766
823
|
setToolManager(toolManager, toolContext) {
|
|
767
824
|
this.toolManager = toolManager;
|
|
@@ -769,6 +826,8 @@ var InputHandler = class {
|
|
|
769
826
|
}
|
|
770
827
|
destroy() {
|
|
771
828
|
this.abortController.abort();
|
|
829
|
+
this.inputFilter.reset();
|
|
830
|
+
this.deferredDown = null;
|
|
772
831
|
this.lastPointerEvent = null;
|
|
773
832
|
}
|
|
774
833
|
bind() {
|
|
@@ -806,6 +865,12 @@ var InputHandler = class {
|
|
|
806
865
|
return;
|
|
807
866
|
}
|
|
808
867
|
if (this.activePointers.size === 1 && (e.button === 0 || e.pointerType === "touch" || e.pointerType === "pen")) {
|
|
868
|
+
const result = this.inputFilter.filterDown(e);
|
|
869
|
+
if (result.action === "suppress") return;
|
|
870
|
+
if (result.action === "defer") {
|
|
871
|
+
this.deferredDown = e;
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
809
874
|
this.dispatchToolDown(e);
|
|
810
875
|
}
|
|
811
876
|
};
|
|
@@ -827,6 +892,13 @@ var InputHandler = class {
|
|
|
827
892
|
}
|
|
828
893
|
if (this.isToolActive) {
|
|
829
894
|
this.dispatchToolMove(e);
|
|
895
|
+
} else if (this.deferredDown) {
|
|
896
|
+
const result = this.inputFilter.filterMove(e);
|
|
897
|
+
if (result.action === "dispatch") {
|
|
898
|
+
this.dispatchToolDown(this.deferredDown);
|
|
899
|
+
this.deferredDown = null;
|
|
900
|
+
this.dispatchToolMove(e);
|
|
901
|
+
}
|
|
830
902
|
} else if (this.activePointers.size === 0) {
|
|
831
903
|
this.dispatchToolHover(e);
|
|
832
904
|
}
|
|
@@ -843,9 +915,16 @@ var InputHandler = class {
|
|
|
843
915
|
if (this.isPanning && this.activePointers.size === 0) {
|
|
844
916
|
this.isPanning = false;
|
|
845
917
|
}
|
|
918
|
+
const upResult = this.inputFilter.filterUp(e);
|
|
846
919
|
if (this.isToolActive) {
|
|
847
920
|
this.dispatchToolUp(e);
|
|
848
921
|
this.isToolActive = false;
|
|
922
|
+
} else if (this.deferredDown && upResult.pendingTap) {
|
|
923
|
+
this.dispatchToolDown(this.deferredDown);
|
|
924
|
+
this.dispatchToolUp(e);
|
|
925
|
+
this.deferredDown = null;
|
|
926
|
+
} else {
|
|
927
|
+
this.deferredDown = null;
|
|
849
928
|
}
|
|
850
929
|
};
|
|
851
930
|
onKeyDown = (e) => {
|
|
@@ -878,6 +957,8 @@ var InputHandler = class {
|
|
|
878
957
|
}
|
|
879
958
|
};
|
|
880
959
|
startPinch() {
|
|
960
|
+
this.inputFilter.reset();
|
|
961
|
+
this.deferredDown = null;
|
|
881
962
|
this.isPanning = true;
|
|
882
963
|
const [a, b] = this.getPinchPoints();
|
|
883
964
|
this.lastPinchDistance = this.distance(a, b);
|
|
@@ -917,7 +998,8 @@ var InputHandler = class {
|
|
|
917
998
|
return {
|
|
918
999
|
x: e.clientX - rect.left,
|
|
919
1000
|
y: e.clientY - rect.top,
|
|
920
|
-
pressure: e.pressure
|
|
1001
|
+
pressure: e.pressure,
|
|
1002
|
+
pointerType: e.pointerType === "touch" || e.pointerType === "pen" ? e.pointerType : "mouse"
|
|
921
1003
|
};
|
|
922
1004
|
}
|
|
923
1005
|
dispatchToolDown(e) {
|
|
@@ -975,6 +1057,7 @@ var InputHandler = class {
|
|
|
975
1057
|
this.dispatchToolUp(e);
|
|
976
1058
|
this.isToolActive = false;
|
|
977
1059
|
}
|
|
1060
|
+
this.deferredDown = null;
|
|
978
1061
|
}
|
|
979
1062
|
};
|
|
980
1063
|
|
|
@@ -1222,19 +1305,23 @@ var ElementStore = class {
|
|
|
1222
1305
|
bus = new EventBus();
|
|
1223
1306
|
layerOrderMap = /* @__PURE__ */ new Map();
|
|
1224
1307
|
spatialIndex = new Quadtree({ x: -1e5, y: -1e5, w: 2e5, h: 2e5 });
|
|
1308
|
+
sortedCache = null;
|
|
1225
1309
|
get count() {
|
|
1226
1310
|
return this.elements.size;
|
|
1227
1311
|
}
|
|
1228
1312
|
setLayerOrder(order) {
|
|
1229
1313
|
this.layerOrderMap = new Map(order);
|
|
1314
|
+
this.sortedCache = null;
|
|
1230
1315
|
}
|
|
1231
1316
|
getAll() {
|
|
1232
|
-
|
|
1317
|
+
if (this.sortedCache) return this.sortedCache;
|
|
1318
|
+
this.sortedCache = [...this.elements.values()].sort((a, b) => {
|
|
1233
1319
|
const layerA = this.layerOrderMap.get(a.layerId) ?? 0;
|
|
1234
1320
|
const layerB = this.layerOrderMap.get(b.layerId) ?? 0;
|
|
1235
1321
|
if (layerA !== layerB) return layerA - layerB;
|
|
1236
1322
|
return a.zIndex - b.zIndex;
|
|
1237
1323
|
});
|
|
1324
|
+
return this.sortedCache;
|
|
1238
1325
|
}
|
|
1239
1326
|
getById(id) {
|
|
1240
1327
|
return this.elements.get(id);
|
|
@@ -1245,6 +1332,7 @@ var ElementStore = class {
|
|
|
1245
1332
|
);
|
|
1246
1333
|
}
|
|
1247
1334
|
add(element) {
|
|
1335
|
+
this.sortedCache = null;
|
|
1248
1336
|
this.elements.set(element.id, element);
|
|
1249
1337
|
const bounds = getElementBounds(element);
|
|
1250
1338
|
if (bounds) this.spatialIndex.insert(element.id, bounds);
|
|
@@ -1253,11 +1341,15 @@ var ElementStore = class {
|
|
|
1253
1341
|
update(id, partial) {
|
|
1254
1342
|
const existing = this.elements.get(id);
|
|
1255
1343
|
if (!existing) return;
|
|
1344
|
+
this.sortedCache = null;
|
|
1256
1345
|
const updated = { ...existing, ...partial, id: existing.id, type: existing.type };
|
|
1257
1346
|
if (updated.type === "arrow") {
|
|
1258
1347
|
const arrow = updated;
|
|
1259
1348
|
arrow.cachedControlPoint = getArrowControlPoint(arrow.from, arrow.to, arrow.bend);
|
|
1260
1349
|
}
|
|
1350
|
+
if (updated.type === "note" && "text" in partial) {
|
|
1351
|
+
updated.text = sanitizeNoteHtml(updated.text);
|
|
1352
|
+
}
|
|
1261
1353
|
this.elements.set(id, updated);
|
|
1262
1354
|
const newBounds = getElementBounds(updated);
|
|
1263
1355
|
if (newBounds) {
|
|
@@ -1268,11 +1360,13 @@ var ElementStore = class {
|
|
|
1268
1360
|
remove(id) {
|
|
1269
1361
|
const element = this.elements.get(id);
|
|
1270
1362
|
if (!element) return;
|
|
1363
|
+
this.sortedCache = null;
|
|
1271
1364
|
this.elements.delete(id);
|
|
1272
1365
|
this.spatialIndex.remove(id);
|
|
1273
1366
|
this.bus.emit("remove", element);
|
|
1274
1367
|
}
|
|
1275
1368
|
clear() {
|
|
1369
|
+
this.sortedCache = null;
|
|
1276
1370
|
this.elements.clear();
|
|
1277
1371
|
this.spatialIndex.clear();
|
|
1278
1372
|
this.bus.emit("clear", null);
|
|
@@ -1281,6 +1375,7 @@ var ElementStore = class {
|
|
|
1281
1375
|
return this.getAll().map((el) => ({ ...el }));
|
|
1282
1376
|
}
|
|
1283
1377
|
loadSnapshot(elements) {
|
|
1378
|
+
this.sortedCache = null;
|
|
1284
1379
|
this.elements.clear();
|
|
1285
1380
|
this.spatialIndex.clear();
|
|
1286
1381
|
for (const el of elements) {
|
|
@@ -1288,6 +1383,10 @@ var ElementStore = class {
|
|
|
1288
1383
|
const bounds = getElementBounds(el);
|
|
1289
1384
|
if (bounds) this.spatialIndex.insert(el.id, bounds);
|
|
1290
1385
|
}
|
|
1386
|
+
this.bus.emit("clear", null);
|
|
1387
|
+
for (const el of elements) {
|
|
1388
|
+
this.bus.emit("add", el);
|
|
1389
|
+
}
|
|
1291
1390
|
}
|
|
1292
1391
|
queryRect(rect) {
|
|
1293
1392
|
const ids = this.spatialIndex.query(rect);
|
|
@@ -2368,7 +2467,7 @@ function createNote(input) {
|
|
|
2368
2467
|
locked: input.locked ?? false,
|
|
2369
2468
|
layerId: input.layerId ?? "",
|
|
2370
2469
|
size: input.size ?? { w: 200, h: 100 },
|
|
2371
|
-
text: input.text ?? "",
|
|
2470
|
+
text: sanitizeNoteHtml(input.text ?? ""),
|
|
2372
2471
|
backgroundColor: input.backgroundColor ?? "#ffeb3b",
|
|
2373
2472
|
textColor: input.textColor ?? "#000000",
|
|
2374
2473
|
fontSize: input.fontSize ?? DEFAULT_NOTE_FONT_SIZE
|
|
@@ -6224,7 +6323,7 @@ var UpdateLayerCommand = class {
|
|
|
6224
6323
|
};
|
|
6225
6324
|
|
|
6226
6325
|
// src/index.ts
|
|
6227
|
-
var VERSION = "0.11.
|
|
6326
|
+
var VERSION = "0.11.3";
|
|
6228
6327
|
export {
|
|
6229
6328
|
AddElementCommand,
|
|
6230
6329
|
ArrowTool,
|
|
@@ -6243,6 +6342,7 @@ export {
|
|
|
6243
6342
|
HistoryRecorder,
|
|
6244
6343
|
HistoryStack,
|
|
6245
6344
|
ImageTool,
|
|
6345
|
+
InputFilter,
|
|
6246
6346
|
InputHandler,
|
|
6247
6347
|
LayerManager,
|
|
6248
6348
|
MeasureTool,
|