@fieldnotes/core 0.11.0 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +113 -5
- package/dist/index.d.cts +27 -2
- package/dist/index.d.ts +27 -2
- package/dist/index.js +112 -5
- package/package.json +12 -7
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,
|
|
@@ -398,7 +399,13 @@ function exportState(elements, camera, layers = []) {
|
|
|
398
399
|
position: { ...camera.position },
|
|
399
400
|
zoom: camera.zoom
|
|
400
401
|
},
|
|
401
|
-
elements: elements.map((el) =>
|
|
402
|
+
elements: elements.map((el) => {
|
|
403
|
+
const clone = structuredClone(el);
|
|
404
|
+
if (clone.type === "arrow") {
|
|
405
|
+
delete clone.cachedControlPoint;
|
|
406
|
+
}
|
|
407
|
+
return clone;
|
|
408
|
+
}),
|
|
402
409
|
layers: layers.map((l) => ({ ...l }))
|
|
403
410
|
};
|
|
404
411
|
}
|
|
@@ -836,6 +843,61 @@ var Background = class {
|
|
|
836
843
|
}
|
|
837
844
|
};
|
|
838
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
|
+
|
|
839
901
|
// src/canvas/input-handler.ts
|
|
840
902
|
var ZOOM_SENSITIVITY = 1e-3;
|
|
841
903
|
var MIDDLE_BUTTON = 1;
|
|
@@ -861,6 +923,9 @@ var InputHandler = class {
|
|
|
861
923
|
historyRecorder;
|
|
862
924
|
historyStack;
|
|
863
925
|
isToolActive = false;
|
|
926
|
+
lastPointerEvent = null;
|
|
927
|
+
inputFilter = new InputFilter();
|
|
928
|
+
deferredDown = null;
|
|
864
929
|
abortController = new AbortController();
|
|
865
930
|
setToolManager(toolManager, toolContext) {
|
|
866
931
|
this.toolManager = toolManager;
|
|
@@ -868,6 +933,9 @@ var InputHandler = class {
|
|
|
868
933
|
}
|
|
869
934
|
destroy() {
|
|
870
935
|
this.abortController.abort();
|
|
936
|
+
this.inputFilter.reset();
|
|
937
|
+
this.deferredDown = null;
|
|
938
|
+
this.lastPointerEvent = null;
|
|
871
939
|
}
|
|
872
940
|
bind() {
|
|
873
941
|
const opts = { signal: this.abortController.signal };
|
|
@@ -903,11 +971,18 @@ var InputHandler = class {
|
|
|
903
971
|
this.lastPointer = { x: e.clientX, y: e.clientY };
|
|
904
972
|
return;
|
|
905
973
|
}
|
|
906
|
-
if (this.activePointers.size === 1 && e.button === 0) {
|
|
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
|
+
}
|
|
907
981
|
this.dispatchToolDown(e);
|
|
908
982
|
}
|
|
909
983
|
};
|
|
910
984
|
onPointerMove = (e) => {
|
|
985
|
+
this.lastPointerEvent = e;
|
|
911
986
|
if (this.activePointers.has(e.pointerId)) {
|
|
912
987
|
this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
913
988
|
}
|
|
@@ -924,11 +999,22 @@ var InputHandler = class {
|
|
|
924
999
|
}
|
|
925
1000
|
if (this.isToolActive) {
|
|
926
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
|
+
}
|
|
927
1009
|
} else if (this.activePointers.size === 0) {
|
|
928
1010
|
this.dispatchToolHover(e);
|
|
929
1011
|
}
|
|
930
1012
|
};
|
|
931
1013
|
onPointerUp = (e) => {
|
|
1014
|
+
try {
|
|
1015
|
+
this.element.releasePointerCapture(e.pointerId);
|
|
1016
|
+
} catch {
|
|
1017
|
+
}
|
|
932
1018
|
this.activePointers.delete(e.pointerId);
|
|
933
1019
|
if (this.activePointers.size < 2) {
|
|
934
1020
|
this.lastPinchDistance = 0;
|
|
@@ -936,9 +1022,16 @@ var InputHandler = class {
|
|
|
936
1022
|
if (this.isPanning && this.activePointers.size === 0) {
|
|
937
1023
|
this.isPanning = false;
|
|
938
1024
|
}
|
|
1025
|
+
const upResult = this.inputFilter.filterUp(e);
|
|
939
1026
|
if (this.isToolActive) {
|
|
940
1027
|
this.dispatchToolUp(e);
|
|
941
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;
|
|
942
1035
|
}
|
|
943
1036
|
};
|
|
944
1037
|
onKeyDown = (e) => {
|
|
@@ -961,9 +1054,18 @@ var InputHandler = class {
|
|
|
961
1054
|
onKeyUp = (e) => {
|
|
962
1055
|
if (e.key === " ") {
|
|
963
1056
|
this.spaceHeld = false;
|
|
1057
|
+
if (this.activePointers.size === 0) {
|
|
1058
|
+
if (this.lastPointerEvent) {
|
|
1059
|
+
this.dispatchToolHover(this.lastPointerEvent);
|
|
1060
|
+
} else {
|
|
1061
|
+
this.toolContext?.setCursor?.("default");
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
964
1064
|
}
|
|
965
1065
|
};
|
|
966
1066
|
startPinch() {
|
|
1067
|
+
this.inputFilter.reset();
|
|
1068
|
+
this.deferredDown = null;
|
|
967
1069
|
this.isPanning = true;
|
|
968
1070
|
const [a, b] = this.getPinchPoints();
|
|
969
1071
|
this.lastPinchDistance = this.distance(a, b);
|
|
@@ -1003,7 +1105,8 @@ var InputHandler = class {
|
|
|
1003
1105
|
return {
|
|
1004
1106
|
x: e.clientX - rect.left,
|
|
1005
1107
|
y: e.clientY - rect.top,
|
|
1006
|
-
pressure: e.pressure
|
|
1108
|
+
pressure: e.pressure,
|
|
1109
|
+
pointerType: e.pointerType === "touch" || e.pointerType === "pen" ? e.pointerType : "mouse"
|
|
1007
1110
|
};
|
|
1008
1111
|
}
|
|
1009
1112
|
dispatchToolDown(e) {
|
|
@@ -1061,6 +1164,7 @@ var InputHandler = class {
|
|
|
1061
1164
|
this.dispatchToolUp(e);
|
|
1062
1165
|
this.isToolActive = false;
|
|
1063
1166
|
}
|
|
1167
|
+
this.deferredDown = null;
|
|
1064
1168
|
}
|
|
1065
1169
|
};
|
|
1066
1170
|
|
|
@@ -4561,7 +4665,10 @@ var Viewport = class {
|
|
|
4561
4665
|
position: "relative",
|
|
4562
4666
|
width: "100%",
|
|
4563
4667
|
height: "100%",
|
|
4564
|
-
overflow: "hidden"
|
|
4668
|
+
overflow: "hidden",
|
|
4669
|
+
overscrollBehavior: "none",
|
|
4670
|
+
userSelect: "none",
|
|
4671
|
+
webkitUserSelect: "none"
|
|
4565
4672
|
});
|
|
4566
4673
|
return el;
|
|
4567
4674
|
}
|
|
@@ -6307,7 +6414,7 @@ var UpdateLayerCommand = class {
|
|
|
6307
6414
|
};
|
|
6308
6415
|
|
|
6309
6416
|
// src/index.ts
|
|
6310
|
-
var VERSION = "0.11.
|
|
6417
|
+
var VERSION = "0.11.2";
|
|
6311
6418
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6312
6419
|
0 && (module.exports = {
|
|
6313
6420
|
AddElementCommand,
|
|
@@ -6327,6 +6434,7 @@ var VERSION = "0.11.0";
|
|
|
6327
6434
|
HistoryRecorder,
|
|
6328
6435
|
HistoryStack,
|
|
6329
6436
|
ImageTool,
|
|
6437
|
+
InputFilter,
|
|
6330
6438
|
InputHandler,
|
|
6331
6439
|
LayerManager,
|
|
6332
6440
|
MeasureTool,
|
package/dist/index.d.cts
CHANGED
|
@@ -238,6 +238,7 @@ interface PointerState {
|
|
|
238
238
|
x: number;
|
|
239
239
|
y: number;
|
|
240
240
|
pressure: number;
|
|
241
|
+
pointerType: 'mouse' | 'touch' | 'pen';
|
|
241
242
|
}
|
|
242
243
|
interface Tool {
|
|
243
244
|
readonly name: string;
|
|
@@ -423,6 +424,9 @@ declare class InputHandler {
|
|
|
423
424
|
private historyRecorder;
|
|
424
425
|
private historyStack;
|
|
425
426
|
private isToolActive;
|
|
427
|
+
private lastPointerEvent;
|
|
428
|
+
private readonly inputFilter;
|
|
429
|
+
private deferredDown;
|
|
426
430
|
private readonly abortController;
|
|
427
431
|
constructor(element: HTMLElement, camera: Camera, options?: InputHandlerOptions);
|
|
428
432
|
setToolManager(toolManager: ToolManager, toolContext: ToolContext): void;
|
|
@@ -450,6 +454,27 @@ declare class InputHandler {
|
|
|
450
454
|
private cancelToolIfActive;
|
|
451
455
|
}
|
|
452
456
|
|
|
457
|
+
type FilterAction = 'dispatch' | 'suppress' | 'defer';
|
|
458
|
+
interface FilteredEvent {
|
|
459
|
+
event: PointerEvent;
|
|
460
|
+
action: FilterAction;
|
|
461
|
+
}
|
|
462
|
+
interface FilteredUpEvent extends FilteredEvent {
|
|
463
|
+
pendingTap?: {
|
|
464
|
+
x: number;
|
|
465
|
+
y: number;
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
declare class InputFilter {
|
|
469
|
+
private activePenId;
|
|
470
|
+
private pendingTap;
|
|
471
|
+
static readonly MIN_MOVE_DISTANCE = 3;
|
|
472
|
+
filterDown(e: PointerEvent): FilteredEvent;
|
|
473
|
+
filterMove(e: PointerEvent): FilteredEvent;
|
|
474
|
+
filterUp(e: PointerEvent): FilteredUpEvent;
|
|
475
|
+
reset(): void;
|
|
476
|
+
}
|
|
477
|
+
|
|
453
478
|
interface FontSizePreset {
|
|
454
479
|
label: string;
|
|
455
480
|
size: number;
|
|
@@ -1119,6 +1144,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1119
1144
|
undo(_store: ElementStore): void;
|
|
1120
1145
|
}
|
|
1121
1146
|
|
|
1122
|
-
declare const VERSION = "0.11.
|
|
1147
|
+
declare const VERSION = "0.11.2";
|
|
1123
1148
|
|
|
1124
|
-
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 };
|
|
1149
|
+
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
|
@@ -238,6 +238,7 @@ interface PointerState {
|
|
|
238
238
|
x: number;
|
|
239
239
|
y: number;
|
|
240
240
|
pressure: number;
|
|
241
|
+
pointerType: 'mouse' | 'touch' | 'pen';
|
|
241
242
|
}
|
|
242
243
|
interface Tool {
|
|
243
244
|
readonly name: string;
|
|
@@ -423,6 +424,9 @@ declare class InputHandler {
|
|
|
423
424
|
private historyRecorder;
|
|
424
425
|
private historyStack;
|
|
425
426
|
private isToolActive;
|
|
427
|
+
private lastPointerEvent;
|
|
428
|
+
private readonly inputFilter;
|
|
429
|
+
private deferredDown;
|
|
426
430
|
private readonly abortController;
|
|
427
431
|
constructor(element: HTMLElement, camera: Camera, options?: InputHandlerOptions);
|
|
428
432
|
setToolManager(toolManager: ToolManager, toolContext: ToolContext): void;
|
|
@@ -450,6 +454,27 @@ declare class InputHandler {
|
|
|
450
454
|
private cancelToolIfActive;
|
|
451
455
|
}
|
|
452
456
|
|
|
457
|
+
type FilterAction = 'dispatch' | 'suppress' | 'defer';
|
|
458
|
+
interface FilteredEvent {
|
|
459
|
+
event: PointerEvent;
|
|
460
|
+
action: FilterAction;
|
|
461
|
+
}
|
|
462
|
+
interface FilteredUpEvent extends FilteredEvent {
|
|
463
|
+
pendingTap?: {
|
|
464
|
+
x: number;
|
|
465
|
+
y: number;
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
declare class InputFilter {
|
|
469
|
+
private activePenId;
|
|
470
|
+
private pendingTap;
|
|
471
|
+
static readonly MIN_MOVE_DISTANCE = 3;
|
|
472
|
+
filterDown(e: PointerEvent): FilteredEvent;
|
|
473
|
+
filterMove(e: PointerEvent): FilteredEvent;
|
|
474
|
+
filterUp(e: PointerEvent): FilteredUpEvent;
|
|
475
|
+
reset(): void;
|
|
476
|
+
}
|
|
477
|
+
|
|
453
478
|
interface FontSizePreset {
|
|
454
479
|
label: string;
|
|
455
480
|
size: number;
|
|
@@ -1119,6 +1144,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1119
1144
|
undo(_store: ElementStore): void;
|
|
1120
1145
|
}
|
|
1121
1146
|
|
|
1122
|
-
declare const VERSION = "0.11.
|
|
1147
|
+
declare const VERSION = "0.11.2";
|
|
1123
1148
|
|
|
1124
|
-
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 };
|
|
1149
|
+
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
|
@@ -292,7 +292,13 @@ function exportState(elements, camera, layers = []) {
|
|
|
292
292
|
position: { ...camera.position },
|
|
293
293
|
zoom: camera.zoom
|
|
294
294
|
},
|
|
295
|
-
elements: elements.map((el) =>
|
|
295
|
+
elements: elements.map((el) => {
|
|
296
|
+
const clone = structuredClone(el);
|
|
297
|
+
if (clone.type === "arrow") {
|
|
298
|
+
delete clone.cachedControlPoint;
|
|
299
|
+
}
|
|
300
|
+
return clone;
|
|
301
|
+
}),
|
|
296
302
|
layers: layers.map((l) => ({ ...l }))
|
|
297
303
|
};
|
|
298
304
|
}
|
|
@@ -730,6 +736,61 @@ var Background = class {
|
|
|
730
736
|
}
|
|
731
737
|
};
|
|
732
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
|
+
|
|
733
794
|
// src/canvas/input-handler.ts
|
|
734
795
|
var ZOOM_SENSITIVITY = 1e-3;
|
|
735
796
|
var MIDDLE_BUTTON = 1;
|
|
@@ -755,6 +816,9 @@ var InputHandler = class {
|
|
|
755
816
|
historyRecorder;
|
|
756
817
|
historyStack;
|
|
757
818
|
isToolActive = false;
|
|
819
|
+
lastPointerEvent = null;
|
|
820
|
+
inputFilter = new InputFilter();
|
|
821
|
+
deferredDown = null;
|
|
758
822
|
abortController = new AbortController();
|
|
759
823
|
setToolManager(toolManager, toolContext) {
|
|
760
824
|
this.toolManager = toolManager;
|
|
@@ -762,6 +826,9 @@ var InputHandler = class {
|
|
|
762
826
|
}
|
|
763
827
|
destroy() {
|
|
764
828
|
this.abortController.abort();
|
|
829
|
+
this.inputFilter.reset();
|
|
830
|
+
this.deferredDown = null;
|
|
831
|
+
this.lastPointerEvent = null;
|
|
765
832
|
}
|
|
766
833
|
bind() {
|
|
767
834
|
const opts = { signal: this.abortController.signal };
|
|
@@ -797,11 +864,18 @@ var InputHandler = class {
|
|
|
797
864
|
this.lastPointer = { x: e.clientX, y: e.clientY };
|
|
798
865
|
return;
|
|
799
866
|
}
|
|
800
|
-
if (this.activePointers.size === 1 && e.button === 0) {
|
|
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
|
+
}
|
|
801
874
|
this.dispatchToolDown(e);
|
|
802
875
|
}
|
|
803
876
|
};
|
|
804
877
|
onPointerMove = (e) => {
|
|
878
|
+
this.lastPointerEvent = e;
|
|
805
879
|
if (this.activePointers.has(e.pointerId)) {
|
|
806
880
|
this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
807
881
|
}
|
|
@@ -818,11 +892,22 @@ var InputHandler = class {
|
|
|
818
892
|
}
|
|
819
893
|
if (this.isToolActive) {
|
|
820
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
|
+
}
|
|
821
902
|
} else if (this.activePointers.size === 0) {
|
|
822
903
|
this.dispatchToolHover(e);
|
|
823
904
|
}
|
|
824
905
|
};
|
|
825
906
|
onPointerUp = (e) => {
|
|
907
|
+
try {
|
|
908
|
+
this.element.releasePointerCapture(e.pointerId);
|
|
909
|
+
} catch {
|
|
910
|
+
}
|
|
826
911
|
this.activePointers.delete(e.pointerId);
|
|
827
912
|
if (this.activePointers.size < 2) {
|
|
828
913
|
this.lastPinchDistance = 0;
|
|
@@ -830,9 +915,16 @@ var InputHandler = class {
|
|
|
830
915
|
if (this.isPanning && this.activePointers.size === 0) {
|
|
831
916
|
this.isPanning = false;
|
|
832
917
|
}
|
|
918
|
+
const upResult = this.inputFilter.filterUp(e);
|
|
833
919
|
if (this.isToolActive) {
|
|
834
920
|
this.dispatchToolUp(e);
|
|
835
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;
|
|
836
928
|
}
|
|
837
929
|
};
|
|
838
930
|
onKeyDown = (e) => {
|
|
@@ -855,9 +947,18 @@ var InputHandler = class {
|
|
|
855
947
|
onKeyUp = (e) => {
|
|
856
948
|
if (e.key === " ") {
|
|
857
949
|
this.spaceHeld = false;
|
|
950
|
+
if (this.activePointers.size === 0) {
|
|
951
|
+
if (this.lastPointerEvent) {
|
|
952
|
+
this.dispatchToolHover(this.lastPointerEvent);
|
|
953
|
+
} else {
|
|
954
|
+
this.toolContext?.setCursor?.("default");
|
|
955
|
+
}
|
|
956
|
+
}
|
|
858
957
|
}
|
|
859
958
|
};
|
|
860
959
|
startPinch() {
|
|
960
|
+
this.inputFilter.reset();
|
|
961
|
+
this.deferredDown = null;
|
|
861
962
|
this.isPanning = true;
|
|
862
963
|
const [a, b] = this.getPinchPoints();
|
|
863
964
|
this.lastPinchDistance = this.distance(a, b);
|
|
@@ -897,7 +998,8 @@ var InputHandler = class {
|
|
|
897
998
|
return {
|
|
898
999
|
x: e.clientX - rect.left,
|
|
899
1000
|
y: e.clientY - rect.top,
|
|
900
|
-
pressure: e.pressure
|
|
1001
|
+
pressure: e.pressure,
|
|
1002
|
+
pointerType: e.pointerType === "touch" || e.pointerType === "pen" ? e.pointerType : "mouse"
|
|
901
1003
|
};
|
|
902
1004
|
}
|
|
903
1005
|
dispatchToolDown(e) {
|
|
@@ -955,6 +1057,7 @@ var InputHandler = class {
|
|
|
955
1057
|
this.dispatchToolUp(e);
|
|
956
1058
|
this.isToolActive = false;
|
|
957
1059
|
}
|
|
1060
|
+
this.deferredDown = null;
|
|
958
1061
|
}
|
|
959
1062
|
};
|
|
960
1063
|
|
|
@@ -4455,7 +4558,10 @@ var Viewport = class {
|
|
|
4455
4558
|
position: "relative",
|
|
4456
4559
|
width: "100%",
|
|
4457
4560
|
height: "100%",
|
|
4458
|
-
overflow: "hidden"
|
|
4561
|
+
overflow: "hidden",
|
|
4562
|
+
overscrollBehavior: "none",
|
|
4563
|
+
userSelect: "none",
|
|
4564
|
+
webkitUserSelect: "none"
|
|
4459
4565
|
});
|
|
4460
4566
|
return el;
|
|
4461
4567
|
}
|
|
@@ -6201,7 +6307,7 @@ var UpdateLayerCommand = class {
|
|
|
6201
6307
|
};
|
|
6202
6308
|
|
|
6203
6309
|
// src/index.ts
|
|
6204
|
-
var VERSION = "0.11.
|
|
6310
|
+
var VERSION = "0.11.2";
|
|
6205
6311
|
export {
|
|
6206
6312
|
AddElementCommand,
|
|
6207
6313
|
ArrowTool,
|
|
@@ -6220,6 +6326,7 @@ export {
|
|
|
6220
6326
|
HistoryRecorder,
|
|
6221
6327
|
HistoryStack,
|
|
6222
6328
|
ImageTool,
|
|
6329
|
+
InputFilter,
|
|
6223
6330
|
InputHandler,
|
|
6224
6331
|
LayerManager,
|
|
6225
6332
|
MeasureTool,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fieldnotes/core",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"description": "Vanilla TypeScript infinite canvas engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -21,11 +21,6 @@
|
|
|
21
21
|
"files": [
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
|
-
"scripts": {
|
|
25
|
-
"build": "tsup",
|
|
26
|
-
"test": "vitest run",
|
|
27
|
-
"test:watch": "vitest"
|
|
28
|
-
},
|
|
29
24
|
"license": "MIT",
|
|
30
25
|
"repository": {
|
|
31
26
|
"type": "git",
|
|
@@ -45,9 +40,19 @@
|
|
|
45
40
|
"sdk"
|
|
46
41
|
],
|
|
47
42
|
"devDependencies": {
|
|
43
|
+
"@playwright/test": "^1.60.0",
|
|
48
44
|
"@vitest/coverage-v8": "^4.1.0",
|
|
49
45
|
"jsdom": "^29.0.0",
|
|
50
46
|
"tsup": "^8.5.1",
|
|
51
47
|
"vitest": "^4.1.0"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:watch": "vitest",
|
|
53
|
+
"test:coverage": "vitest run --coverage",
|
|
54
|
+
"test:all": "vitest run --coverage",
|
|
55
|
+
"e2e": "playwright test --config e2e/playwright.config.ts",
|
|
56
|
+
"e2e:update": "playwright test --config e2e/playwright.config.ts --update-snapshots"
|
|
52
57
|
}
|
|
53
|
-
}
|
|
58
|
+
}
|