@fieldnotes/core 0.18.0 → 0.19.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/LICENSE +21 -21
- package/README.md +31 -1
- package/dist/index.cjs +253 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.js +253 -55
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -432,12 +432,25 @@ declare class HistoryRecorder {
|
|
|
432
432
|
private flushUpdateSnapshots;
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
+
type ShortcutBindings = Record<string, string | string[] | null>;
|
|
436
|
+
interface ShortcutOptions {
|
|
437
|
+
scope?: 'focus' | 'window';
|
|
438
|
+
bindings?: ShortcutBindings;
|
|
439
|
+
}
|
|
440
|
+
interface ShortcutsApi {
|
|
441
|
+
rebind(action: string, bindings: string | string[] | null): void;
|
|
442
|
+
disable(action: string): void;
|
|
443
|
+
reset(action?: string): void;
|
|
444
|
+
getBindings(): Record<string, string[]>;
|
|
445
|
+
}
|
|
446
|
+
|
|
435
447
|
interface InputHandlerOptions {
|
|
436
448
|
toolManager?: ToolManager;
|
|
437
449
|
toolContext?: ToolContext;
|
|
438
450
|
historyRecorder?: HistoryRecorder;
|
|
439
451
|
historyStack?: HistoryStack;
|
|
440
452
|
fitToContent?: () => void;
|
|
453
|
+
shortcuts?: ShortcutOptions;
|
|
441
454
|
}
|
|
442
455
|
declare class InputHandler {
|
|
443
456
|
private readonly element;
|
|
@@ -458,9 +471,12 @@ declare class InputHandler {
|
|
|
458
471
|
private deferredDown;
|
|
459
472
|
private readonly abortController;
|
|
460
473
|
private readonly actions;
|
|
474
|
+
private readonly shortcutMap;
|
|
475
|
+
private readonly scope;
|
|
461
476
|
constructor(element: HTMLElement, camera: Camera, options?: InputHandlerOptions);
|
|
462
477
|
setToolManager(toolManager: ToolManager, toolContext: ToolContext): void;
|
|
463
478
|
flushPendingHistory(): void;
|
|
479
|
+
get shortcuts(): ShortcutsApi;
|
|
464
480
|
destroy(): void;
|
|
465
481
|
private bind;
|
|
466
482
|
private onWheel;
|
|
@@ -469,6 +485,7 @@ declare class InputHandler {
|
|
|
469
485
|
private onPointerUp;
|
|
470
486
|
private onKeyDown;
|
|
471
487
|
private onKeyUp;
|
|
488
|
+
private runAction;
|
|
472
489
|
private startPinch;
|
|
473
490
|
private handlePinchMove;
|
|
474
491
|
private getPinchPoints;
|
|
@@ -479,6 +496,8 @@ declare class InputHandler {
|
|
|
479
496
|
private dispatchToolMove;
|
|
480
497
|
private dispatchToolHover;
|
|
481
498
|
private dispatchToolUp;
|
|
499
|
+
private isInScope;
|
|
500
|
+
private focusSelf;
|
|
482
501
|
private cancelToolIfActive;
|
|
483
502
|
}
|
|
484
503
|
|
|
@@ -569,6 +588,7 @@ interface ViewportOptions {
|
|
|
569
588
|
background?: BackgroundOptions;
|
|
570
589
|
fontSizePresets?: FontSizePreset[];
|
|
571
590
|
toolbar?: boolean;
|
|
591
|
+
shortcuts?: ShortcutOptions;
|
|
572
592
|
onHtmlElementMount?: (elementId: string, domId: string | undefined, container: HTMLDivElement) => void;
|
|
573
593
|
onDrop?: (event: DragEvent, worldPosition: {
|
|
574
594
|
x: number;
|
|
@@ -617,6 +637,7 @@ declare class Viewport {
|
|
|
617
637
|
loadState(state: CanvasState): void;
|
|
618
638
|
loadJSON(json: string): void;
|
|
619
639
|
setTool(name: string): void;
|
|
640
|
+
get shortcuts(): ShortcutsApi;
|
|
620
641
|
undo(): boolean;
|
|
621
642
|
redo(): boolean;
|
|
622
643
|
addImage(src: string, position: {
|
|
@@ -1212,6 +1233,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1212
1233
|
undo(_store: ElementStore): void;
|
|
1213
1234
|
}
|
|
1214
1235
|
|
|
1215
|
-
declare const VERSION = "0.
|
|
1236
|
+
declare const VERSION = "0.19.0";
|
|
1216
1237
|
|
|
1217
|
-
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 InputHandlerOptions, 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 };
|
|
1238
|
+
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 InputHandlerOptions, 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 ShortcutBindings, type ShortcutOptions, type ShortcutsApi, 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
|
@@ -432,12 +432,25 @@ declare class HistoryRecorder {
|
|
|
432
432
|
private flushUpdateSnapshots;
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
+
type ShortcutBindings = Record<string, string | string[] | null>;
|
|
436
|
+
interface ShortcutOptions {
|
|
437
|
+
scope?: 'focus' | 'window';
|
|
438
|
+
bindings?: ShortcutBindings;
|
|
439
|
+
}
|
|
440
|
+
interface ShortcutsApi {
|
|
441
|
+
rebind(action: string, bindings: string | string[] | null): void;
|
|
442
|
+
disable(action: string): void;
|
|
443
|
+
reset(action?: string): void;
|
|
444
|
+
getBindings(): Record<string, string[]>;
|
|
445
|
+
}
|
|
446
|
+
|
|
435
447
|
interface InputHandlerOptions {
|
|
436
448
|
toolManager?: ToolManager;
|
|
437
449
|
toolContext?: ToolContext;
|
|
438
450
|
historyRecorder?: HistoryRecorder;
|
|
439
451
|
historyStack?: HistoryStack;
|
|
440
452
|
fitToContent?: () => void;
|
|
453
|
+
shortcuts?: ShortcutOptions;
|
|
441
454
|
}
|
|
442
455
|
declare class InputHandler {
|
|
443
456
|
private readonly element;
|
|
@@ -458,9 +471,12 @@ declare class InputHandler {
|
|
|
458
471
|
private deferredDown;
|
|
459
472
|
private readonly abortController;
|
|
460
473
|
private readonly actions;
|
|
474
|
+
private readonly shortcutMap;
|
|
475
|
+
private readonly scope;
|
|
461
476
|
constructor(element: HTMLElement, camera: Camera, options?: InputHandlerOptions);
|
|
462
477
|
setToolManager(toolManager: ToolManager, toolContext: ToolContext): void;
|
|
463
478
|
flushPendingHistory(): void;
|
|
479
|
+
get shortcuts(): ShortcutsApi;
|
|
464
480
|
destroy(): void;
|
|
465
481
|
private bind;
|
|
466
482
|
private onWheel;
|
|
@@ -469,6 +485,7 @@ declare class InputHandler {
|
|
|
469
485
|
private onPointerUp;
|
|
470
486
|
private onKeyDown;
|
|
471
487
|
private onKeyUp;
|
|
488
|
+
private runAction;
|
|
472
489
|
private startPinch;
|
|
473
490
|
private handlePinchMove;
|
|
474
491
|
private getPinchPoints;
|
|
@@ -479,6 +496,8 @@ declare class InputHandler {
|
|
|
479
496
|
private dispatchToolMove;
|
|
480
497
|
private dispatchToolHover;
|
|
481
498
|
private dispatchToolUp;
|
|
499
|
+
private isInScope;
|
|
500
|
+
private focusSelf;
|
|
482
501
|
private cancelToolIfActive;
|
|
483
502
|
}
|
|
484
503
|
|
|
@@ -569,6 +588,7 @@ interface ViewportOptions {
|
|
|
569
588
|
background?: BackgroundOptions;
|
|
570
589
|
fontSizePresets?: FontSizePreset[];
|
|
571
590
|
toolbar?: boolean;
|
|
591
|
+
shortcuts?: ShortcutOptions;
|
|
572
592
|
onHtmlElementMount?: (elementId: string, domId: string | undefined, container: HTMLDivElement) => void;
|
|
573
593
|
onDrop?: (event: DragEvent, worldPosition: {
|
|
574
594
|
x: number;
|
|
@@ -617,6 +637,7 @@ declare class Viewport {
|
|
|
617
637
|
loadState(state: CanvasState): void;
|
|
618
638
|
loadJSON(json: string): void;
|
|
619
639
|
setTool(name: string): void;
|
|
640
|
+
get shortcuts(): ShortcutsApi;
|
|
620
641
|
undo(): boolean;
|
|
621
642
|
redo(): boolean;
|
|
622
643
|
addImage(src: string, position: {
|
|
@@ -1212,6 +1233,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1212
1233
|
undo(_store: ElementStore): void;
|
|
1213
1234
|
}
|
|
1214
1235
|
|
|
1215
|
-
declare const VERSION = "0.
|
|
1236
|
+
declare const VERSION = "0.19.0";
|
|
1216
1237
|
|
|
1217
|
-
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 InputHandlerOptions, 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 };
|
|
1238
|
+
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 InputHandlerOptions, 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 ShortcutBindings, type ShortcutOptions, type ShortcutsApi, 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
|
@@ -1041,14 +1041,158 @@ var KeyboardActions = class {
|
|
|
1041
1041
|
}
|
|
1042
1042
|
};
|
|
1043
1043
|
|
|
1044
|
+
// src/canvas/shortcut-map.ts
|
|
1045
|
+
var DEFAULT_BINDINGS = [
|
|
1046
|
+
["delete", ["delete", "backspace"]],
|
|
1047
|
+
["deselect", ["escape"]],
|
|
1048
|
+
["undo", ["mod+z"]],
|
|
1049
|
+
["redo", ["mod+y", "mod+shift+z"]],
|
|
1050
|
+
["select-all", ["mod+a"]],
|
|
1051
|
+
["copy", ["mod+c"]],
|
|
1052
|
+
["paste", ["mod+v"]],
|
|
1053
|
+
["duplicate", ["mod+d"]],
|
|
1054
|
+
["z-forward", ["]"]],
|
|
1055
|
+
["z-backward", ["["]],
|
|
1056
|
+
["z-front", ["mod+]"]],
|
|
1057
|
+
["z-back", ["mod+["]],
|
|
1058
|
+
["zoom-fit", ["shift+1"]],
|
|
1059
|
+
["nudge-left", ["arrowleft"]],
|
|
1060
|
+
["nudge-right", ["arrowright"]],
|
|
1061
|
+
["nudge-up", ["arrowup"]],
|
|
1062
|
+
["nudge-down", ["arrowdown"]],
|
|
1063
|
+
["tool:select", ["v"]],
|
|
1064
|
+
["tool:hand", ["h"]],
|
|
1065
|
+
["tool:pencil", ["p"]],
|
|
1066
|
+
["tool:eraser", ["e"]],
|
|
1067
|
+
["tool:arrow", ["a"]],
|
|
1068
|
+
["tool:note", ["n"]],
|
|
1069
|
+
["tool:text", ["t"]],
|
|
1070
|
+
["tool:shape", ["s"]],
|
|
1071
|
+
["tool:measure", ["m"]],
|
|
1072
|
+
["tool:template", ["g"]]
|
|
1073
|
+
];
|
|
1074
|
+
var ALLOW_SHIFT = /* @__PURE__ */ new Set(["nudge-left", "nudge-right", "nudge-up", "nudge-down"]);
|
|
1075
|
+
var MODIFIERS = /* @__PURE__ */ new Set(["mod", "ctrl", "meta", "shift", "alt"]);
|
|
1076
|
+
function parseBinding(binding) {
|
|
1077
|
+
const parts = binding.toLowerCase().split("+");
|
|
1078
|
+
const key = parts.pop();
|
|
1079
|
+
if (key === void 0 || key.length === 0 || MODIFIERS.has(key)) {
|
|
1080
|
+
throw new Error(`Invalid shortcut binding "${binding}": missing key`);
|
|
1081
|
+
}
|
|
1082
|
+
const normalizedKey = key === "space" ? " " : key;
|
|
1083
|
+
const parsed = {
|
|
1084
|
+
mod: false,
|
|
1085
|
+
ctrl: false,
|
|
1086
|
+
meta: false,
|
|
1087
|
+
shift: false,
|
|
1088
|
+
alt: false,
|
|
1089
|
+
key: normalizedKey,
|
|
1090
|
+
digit: /^[0-9]$/.test(normalizedKey)
|
|
1091
|
+
};
|
|
1092
|
+
for (const part of parts) {
|
|
1093
|
+
switch (part) {
|
|
1094
|
+
case "mod":
|
|
1095
|
+
parsed.mod = true;
|
|
1096
|
+
break;
|
|
1097
|
+
case "ctrl":
|
|
1098
|
+
parsed.ctrl = true;
|
|
1099
|
+
break;
|
|
1100
|
+
case "meta":
|
|
1101
|
+
parsed.meta = true;
|
|
1102
|
+
break;
|
|
1103
|
+
case "shift":
|
|
1104
|
+
parsed.shift = true;
|
|
1105
|
+
break;
|
|
1106
|
+
case "alt":
|
|
1107
|
+
parsed.alt = true;
|
|
1108
|
+
break;
|
|
1109
|
+
default:
|
|
1110
|
+
throw new Error(`Invalid shortcut binding "${binding}": unknown modifier "${part}"`);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
return parsed;
|
|
1114
|
+
}
|
|
1115
|
+
function bindingMatches(p, e, allowShift) {
|
|
1116
|
+
if (p.mod) {
|
|
1117
|
+
if (!e.ctrlKey && !e.metaKey) return false;
|
|
1118
|
+
} else if (e.ctrlKey !== p.ctrl || e.metaKey !== p.meta) {
|
|
1119
|
+
return false;
|
|
1120
|
+
}
|
|
1121
|
+
if (!allowShift && e.shiftKey !== p.shift) return false;
|
|
1122
|
+
if (e.altKey !== p.alt) return false;
|
|
1123
|
+
return p.digit ? e.code === `Digit${p.key}` : e.key.toLowerCase() === p.key;
|
|
1124
|
+
}
|
|
1125
|
+
function toArray(bindings) {
|
|
1126
|
+
if (bindings === null) return [];
|
|
1127
|
+
return Array.isArray(bindings) ? [...bindings] : [bindings];
|
|
1128
|
+
}
|
|
1129
|
+
var ShortcutMap = class {
|
|
1130
|
+
raw = /* @__PURE__ */ new Map();
|
|
1131
|
+
parsed = /* @__PURE__ */ new Map();
|
|
1132
|
+
constructor(overrides) {
|
|
1133
|
+
this.applyDefaults();
|
|
1134
|
+
if (overrides) {
|
|
1135
|
+
for (const [action, bindings] of Object.entries(overrides)) {
|
|
1136
|
+
this.rebind(action, bindings);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
/** First matching action in registration order wins when bindings conflict. */
|
|
1141
|
+
match(e) {
|
|
1142
|
+
for (const [action, parsedList] of this.parsed) {
|
|
1143
|
+
const allowShift = ALLOW_SHIFT.has(action);
|
|
1144
|
+
for (const p of parsedList) {
|
|
1145
|
+
if (bindingMatches(p, e, allowShift)) return action;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
return null;
|
|
1149
|
+
}
|
|
1150
|
+
rebind(action, bindings) {
|
|
1151
|
+
const list = toArray(bindings);
|
|
1152
|
+
const parsedList = list.map(parseBinding);
|
|
1153
|
+
this.raw.set(action, list);
|
|
1154
|
+
this.parsed.set(action, parsedList);
|
|
1155
|
+
}
|
|
1156
|
+
disable(action) {
|
|
1157
|
+
this.rebind(action, null);
|
|
1158
|
+
}
|
|
1159
|
+
reset(action) {
|
|
1160
|
+
if (action === void 0) {
|
|
1161
|
+
this.raw.clear();
|
|
1162
|
+
this.parsed.clear();
|
|
1163
|
+
this.applyDefaults();
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
const def = DEFAULT_BINDINGS.find(([name]) => name === action);
|
|
1167
|
+
if (def) {
|
|
1168
|
+
this.rebind(action, [...def[1]]);
|
|
1169
|
+
} else if (this.raw.has(action)) {
|
|
1170
|
+
this.raw.delete(action);
|
|
1171
|
+
this.parsed.delete(action);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
getBindings() {
|
|
1175
|
+
const out = {};
|
|
1176
|
+
for (const [action, list] of this.raw) {
|
|
1177
|
+
out[action] = [...list];
|
|
1178
|
+
}
|
|
1179
|
+
return out;
|
|
1180
|
+
}
|
|
1181
|
+
applyDefaults() {
|
|
1182
|
+
for (const [action, bindings] of DEFAULT_BINDINGS) {
|
|
1183
|
+
this.rebind(action, [...bindings]);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1044
1188
|
// src/canvas/input-handler.ts
|
|
1045
1189
|
var ZOOM_SENSITIVITY = 1e-3;
|
|
1046
1190
|
var MIDDLE_BUTTON = 1;
|
|
1047
|
-
var
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1191
|
+
var NUDGE_DELTAS = {
|
|
1192
|
+
"nudge-left": [-1, 0],
|
|
1193
|
+
"nudge-right": [1, 0],
|
|
1194
|
+
"nudge-up": [0, -1],
|
|
1195
|
+
"nudge-down": [0, 1]
|
|
1052
1196
|
};
|
|
1053
1197
|
var InputHandler = class {
|
|
1054
1198
|
constructor(element, camera, options = {}) {
|
|
@@ -1066,7 +1210,13 @@ var InputHandler = class {
|
|
|
1066
1210
|
isToolActive: () => this.isToolActive,
|
|
1067
1211
|
fitToContent: options.fitToContent
|
|
1068
1212
|
});
|
|
1213
|
+
this.shortcutMap = new ShortcutMap(options.shortcuts?.bindings);
|
|
1214
|
+
this.scope = options.shortcuts?.scope ?? "focus";
|
|
1069
1215
|
this.element.style.touchAction = "none";
|
|
1216
|
+
if (this.scope === "focus") {
|
|
1217
|
+
this.element.tabIndex = 0;
|
|
1218
|
+
this.element.style.outline = "none";
|
|
1219
|
+
}
|
|
1070
1220
|
this.bind();
|
|
1071
1221
|
}
|
|
1072
1222
|
isPanning = false;
|
|
@@ -1085,6 +1235,8 @@ var InputHandler = class {
|
|
|
1085
1235
|
deferredDown = null;
|
|
1086
1236
|
abortController = new AbortController();
|
|
1087
1237
|
actions;
|
|
1238
|
+
shortcutMap;
|
|
1239
|
+
scope;
|
|
1088
1240
|
setToolManager(toolManager, toolContext) {
|
|
1089
1241
|
this.toolManager = toolManager;
|
|
1090
1242
|
this.toolContext = toolContext;
|
|
@@ -1092,6 +1244,9 @@ var InputHandler = class {
|
|
|
1092
1244
|
flushPendingHistory() {
|
|
1093
1245
|
this.actions.flushPendingNudge();
|
|
1094
1246
|
}
|
|
1247
|
+
get shortcuts() {
|
|
1248
|
+
return this.shortcutMap;
|
|
1249
|
+
}
|
|
1095
1250
|
destroy() {
|
|
1096
1251
|
this.actions.dispose();
|
|
1097
1252
|
this.abortController.abort();
|
|
@@ -1121,6 +1276,7 @@ var InputHandler = class {
|
|
|
1121
1276
|
});
|
|
1122
1277
|
};
|
|
1123
1278
|
onPointerDown = (e) => {
|
|
1279
|
+
this.focusSelf();
|
|
1124
1280
|
this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
1125
1281
|
this.element.setPointerCapture?.(e.pointerId);
|
|
1126
1282
|
if (this.activePointers.size === 2) {
|
|
@@ -1203,57 +1359,13 @@ var InputHandler = class {
|
|
|
1203
1359
|
if (target?.isContentEditable) return;
|
|
1204
1360
|
const tag = target?.tagName;
|
|
1205
1361
|
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
|
|
1362
|
+
if (!this.isInScope()) return;
|
|
1206
1363
|
if (e.key === " ") {
|
|
1207
1364
|
this.spaceHeld = true;
|
|
1208
1365
|
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
if (e.key === "Escape") {
|
|
1213
|
-
this.actions.deselect();
|
|
1214
|
-
}
|
|
1215
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "z" && !e.shiftKey) {
|
|
1216
|
-
e.preventDefault();
|
|
1217
|
-
this.actions.undo();
|
|
1218
|
-
}
|
|
1219
|
-
if ((e.ctrlKey || e.metaKey) && (e.key === "y" || e.key === "z" && e.shiftKey)) {
|
|
1220
|
-
e.preventDefault();
|
|
1221
|
-
this.actions.redo();
|
|
1222
|
-
}
|
|
1223
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "a") {
|
|
1224
|
-
e.preventDefault();
|
|
1225
|
-
this.actions.selectAll();
|
|
1226
|
-
}
|
|
1227
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "c") {
|
|
1228
|
-
e.preventDefault();
|
|
1229
|
-
this.actions.copy();
|
|
1230
|
-
}
|
|
1231
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "v") {
|
|
1232
|
-
e.preventDefault();
|
|
1233
|
-
this.actions.paste();
|
|
1234
|
-
}
|
|
1235
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "d") {
|
|
1236
|
-
e.preventDefault();
|
|
1237
|
-
this.actions.duplicate();
|
|
1238
|
-
}
|
|
1239
|
-
if (e.key === "]") {
|
|
1240
|
-
e.preventDefault();
|
|
1241
|
-
this.actions.zOrder(e.ctrlKey || e.metaKey ? "front" : "forward");
|
|
1242
|
-
}
|
|
1243
|
-
if (e.key === "[") {
|
|
1244
|
-
e.preventDefault();
|
|
1245
|
-
this.actions.zOrder(e.ctrlKey || e.metaKey ? "back" : "backward");
|
|
1246
|
-
}
|
|
1247
|
-
if (e.shiftKey && e.code === "Digit1" && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
1248
|
-
e.preventDefault();
|
|
1249
|
-
this.actions.zoomToFit();
|
|
1250
|
-
}
|
|
1251
|
-
const nudgeDelta = NUDGE_KEYS[e.key];
|
|
1252
|
-
if (nudgeDelta) {
|
|
1253
|
-
const [dx, dy] = nudgeDelta;
|
|
1254
|
-
if (this.actions.nudge(dx, dy, e.shiftKey)) {
|
|
1255
|
-
e.preventDefault();
|
|
1256
|
-
}
|
|
1366
|
+
const action = this.shortcutMap.match(e);
|
|
1367
|
+
if (action !== null) {
|
|
1368
|
+
this.runAction(action, e);
|
|
1257
1369
|
}
|
|
1258
1370
|
};
|
|
1259
1371
|
onKeyUp = (e) => {
|
|
@@ -1268,6 +1380,79 @@ var InputHandler = class {
|
|
|
1268
1380
|
}
|
|
1269
1381
|
}
|
|
1270
1382
|
};
|
|
1383
|
+
runAction(action, e) {
|
|
1384
|
+
switch (action) {
|
|
1385
|
+
case "delete":
|
|
1386
|
+
e.preventDefault();
|
|
1387
|
+
this.actions.deleteSelected();
|
|
1388
|
+
return;
|
|
1389
|
+
case "deselect":
|
|
1390
|
+
this.actions.deselect();
|
|
1391
|
+
return;
|
|
1392
|
+
case "undo":
|
|
1393
|
+
e.preventDefault();
|
|
1394
|
+
this.actions.undo();
|
|
1395
|
+
return;
|
|
1396
|
+
case "redo":
|
|
1397
|
+
e.preventDefault();
|
|
1398
|
+
this.actions.redo();
|
|
1399
|
+
return;
|
|
1400
|
+
case "select-all":
|
|
1401
|
+
e.preventDefault();
|
|
1402
|
+
this.actions.selectAll();
|
|
1403
|
+
return;
|
|
1404
|
+
case "copy":
|
|
1405
|
+
e.preventDefault();
|
|
1406
|
+
this.actions.copy();
|
|
1407
|
+
return;
|
|
1408
|
+
case "paste":
|
|
1409
|
+
e.preventDefault();
|
|
1410
|
+
this.actions.paste();
|
|
1411
|
+
return;
|
|
1412
|
+
case "duplicate":
|
|
1413
|
+
e.preventDefault();
|
|
1414
|
+
this.actions.duplicate();
|
|
1415
|
+
return;
|
|
1416
|
+
case "z-forward":
|
|
1417
|
+
e.preventDefault();
|
|
1418
|
+
this.actions.zOrder("forward");
|
|
1419
|
+
return;
|
|
1420
|
+
case "z-backward":
|
|
1421
|
+
e.preventDefault();
|
|
1422
|
+
this.actions.zOrder("backward");
|
|
1423
|
+
return;
|
|
1424
|
+
case "z-front":
|
|
1425
|
+
e.preventDefault();
|
|
1426
|
+
this.actions.zOrder("front");
|
|
1427
|
+
return;
|
|
1428
|
+
case "z-back":
|
|
1429
|
+
e.preventDefault();
|
|
1430
|
+
this.actions.zOrder("back");
|
|
1431
|
+
return;
|
|
1432
|
+
case "zoom-fit":
|
|
1433
|
+
e.preventDefault();
|
|
1434
|
+
this.actions.zoomToFit();
|
|
1435
|
+
return;
|
|
1436
|
+
case "nudge-left":
|
|
1437
|
+
case "nudge-right":
|
|
1438
|
+
case "nudge-up":
|
|
1439
|
+
case "nudge-down": {
|
|
1440
|
+
const delta = NUDGE_DELTAS[action];
|
|
1441
|
+
if (delta && this.actions.nudge(delta[0], delta[1], e.shiftKey)) {
|
|
1442
|
+
e.preventDefault();
|
|
1443
|
+
}
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
default:
|
|
1447
|
+
if (action.startsWith("tool:")) {
|
|
1448
|
+
if (this.isToolActive) return;
|
|
1449
|
+
e.preventDefault();
|
|
1450
|
+
this.toolContext?.switchTool?.(action.slice("tool:".length));
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
console.warn(`[fieldnotes] unknown shortcut action "${action}"`);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1271
1456
|
startPinch() {
|
|
1272
1457
|
this.inputFilter.reset();
|
|
1273
1458
|
this.deferredDown = null;
|
|
@@ -1338,6 +1523,15 @@ var InputHandler = class {
|
|
|
1338
1523
|
this.toolManager.handlePointerUp(this.toPointerState(e), this.toolContext);
|
|
1339
1524
|
this.historyRecorder?.commit();
|
|
1340
1525
|
}
|
|
1526
|
+
isInScope() {
|
|
1527
|
+
if (this.scope === "window") return true;
|
|
1528
|
+
const active = document.activeElement;
|
|
1529
|
+
return active === this.element || this.element.contains(active);
|
|
1530
|
+
}
|
|
1531
|
+
focusSelf() {
|
|
1532
|
+
if (this.scope !== "focus" || this.isInScope()) return;
|
|
1533
|
+
this.element.focus({ preventScroll: true });
|
|
1534
|
+
}
|
|
1341
1535
|
cancelToolIfActive(e) {
|
|
1342
1536
|
if (this.isToolActive) {
|
|
1343
1537
|
this.dispatchToolUp(e);
|
|
@@ -4732,7 +4926,8 @@ var Viewport = class {
|
|
|
4732
4926
|
toolContext: this.toolContext,
|
|
4733
4927
|
historyRecorder: this.historyRecorder,
|
|
4734
4928
|
historyStack: this.history,
|
|
4735
|
-
fitToContent: () => this.fitToContent()
|
|
4929
|
+
fitToContent: () => this.fitToContent(),
|
|
4930
|
+
shortcuts: options.shortcuts
|
|
4736
4931
|
});
|
|
4737
4932
|
this.domNodeManager = new DomNodeManager({
|
|
4738
4933
|
domLayer: this.domLayer,
|
|
@@ -4906,6 +5101,9 @@ var Viewport = class {
|
|
|
4906
5101
|
setTool(name) {
|
|
4907
5102
|
this.toolManager.setTool(name, this.toolContext);
|
|
4908
5103
|
}
|
|
5104
|
+
get shortcuts() {
|
|
5105
|
+
return this.inputHandler.shortcuts;
|
|
5106
|
+
}
|
|
4909
5107
|
undo() {
|
|
4910
5108
|
this.inputHandler.flushPendingHistory();
|
|
4911
5109
|
this.historyRecorder.pause();
|
|
@@ -6944,7 +7142,7 @@ var TemplateTool = class {
|
|
|
6944
7142
|
};
|
|
6945
7143
|
|
|
6946
7144
|
// src/index.ts
|
|
6947
|
-
var VERSION = "0.
|
|
7145
|
+
var VERSION = "0.19.0";
|
|
6948
7146
|
export {
|
|
6949
7147
|
AddElementCommand,
|
|
6950
7148
|
ArrowTool,
|