@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/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Irakli Iremashvili
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Irakli Iremashvili
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -269,6 +269,35 @@ viewport.toolManager.onChange((toolName) => {
|
|
|
269
269
|
});
|
|
270
270
|
```
|
|
271
271
|
|
|
272
|
+
## Keyboard shortcuts
|
|
273
|
+
|
|
274
|
+
Defaults (remappable): `Delete`/`Backspace` delete · `Escape` deselect · `mod+Z` undo ·
|
|
275
|
+
`mod+Y`/`mod+Shift+Z` redo · `mod+A` select all · `mod+C/V/D` copy/paste/duplicate ·
|
|
276
|
+
`[`/`]` z-order (with `mod` = to back/front) · `Shift+1` zoom-to-fit · arrows nudge
|
|
277
|
+
(`Shift` = one grid cell) · tool keys `V` select, `H` hand, `P` pencil, `E` eraser,
|
|
278
|
+
`A` arrow, `N` note, `T` text, `S` shape, `M` measure, `G` template.
|
|
279
|
+
|
|
280
|
+
`mod` = Ctrl or Cmd. Shortcuts fire only while the canvas has focus (click it once);
|
|
281
|
+
pass `shortcuts: { scope: 'window' }` for page-wide handling.
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
const viewport = new Viewport(el, {
|
|
285
|
+
shortcuts: {
|
|
286
|
+
bindings: {
|
|
287
|
+
duplicate: 'mod+shift+d', // remap
|
|
288
|
+
'tool:pencil': ['p', 'b'], // multiple bindings
|
|
289
|
+
copy: null, // disable
|
|
290
|
+
'tool:my-custom-tool': 'f', // any registered tool works
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
viewport.shortcuts.rebind('undo', 'mod+u');
|
|
296
|
+
viewport.shortcuts.disable('select-all');
|
|
297
|
+
viewport.shortcuts.reset(); // back to defaults
|
|
298
|
+
viewport.shortcuts.getBindings(); // current table — render a settings UI
|
|
299
|
+
```
|
|
300
|
+
|
|
272
301
|
## Changing Tool Options at Runtime
|
|
273
302
|
|
|
274
303
|
All drawing tools support `setOptions()` for changing color, width, and other settings without re-creating the tool:
|
|
@@ -435,7 +464,8 @@ Works in all modern browsers supporting Pointer Events API and HTML5 Canvas.
|
|
|
435
464
|
|
|
436
465
|
`@fieldnotes/core` and `@fieldnotes/react` are versioned independently. The react
|
|
437
466
|
package's `peerDependencies` declare the compatible core range. Pre-1.0, minor
|
|
438
|
-
versions may contain breaking changes.
|
|
467
|
+
versions may contain breaking changes. The core peer range is bounded at the next major rather than per-minor; if a core minor
|
|
468
|
+
ever breaks the wrapper, a coordinated react release raises the lower bound.
|
|
439
469
|
|
|
440
470
|
## License
|
|
441
471
|
|
package/dist/index.cjs
CHANGED
|
@@ -1150,14 +1150,158 @@ var KeyboardActions = class {
|
|
|
1150
1150
|
}
|
|
1151
1151
|
};
|
|
1152
1152
|
|
|
1153
|
+
// src/canvas/shortcut-map.ts
|
|
1154
|
+
var DEFAULT_BINDINGS = [
|
|
1155
|
+
["delete", ["delete", "backspace"]],
|
|
1156
|
+
["deselect", ["escape"]],
|
|
1157
|
+
["undo", ["mod+z"]],
|
|
1158
|
+
["redo", ["mod+y", "mod+shift+z"]],
|
|
1159
|
+
["select-all", ["mod+a"]],
|
|
1160
|
+
["copy", ["mod+c"]],
|
|
1161
|
+
["paste", ["mod+v"]],
|
|
1162
|
+
["duplicate", ["mod+d"]],
|
|
1163
|
+
["z-forward", ["]"]],
|
|
1164
|
+
["z-backward", ["["]],
|
|
1165
|
+
["z-front", ["mod+]"]],
|
|
1166
|
+
["z-back", ["mod+["]],
|
|
1167
|
+
["zoom-fit", ["shift+1"]],
|
|
1168
|
+
["nudge-left", ["arrowleft"]],
|
|
1169
|
+
["nudge-right", ["arrowright"]],
|
|
1170
|
+
["nudge-up", ["arrowup"]],
|
|
1171
|
+
["nudge-down", ["arrowdown"]],
|
|
1172
|
+
["tool:select", ["v"]],
|
|
1173
|
+
["tool:hand", ["h"]],
|
|
1174
|
+
["tool:pencil", ["p"]],
|
|
1175
|
+
["tool:eraser", ["e"]],
|
|
1176
|
+
["tool:arrow", ["a"]],
|
|
1177
|
+
["tool:note", ["n"]],
|
|
1178
|
+
["tool:text", ["t"]],
|
|
1179
|
+
["tool:shape", ["s"]],
|
|
1180
|
+
["tool:measure", ["m"]],
|
|
1181
|
+
["tool:template", ["g"]]
|
|
1182
|
+
];
|
|
1183
|
+
var ALLOW_SHIFT = /* @__PURE__ */ new Set(["nudge-left", "nudge-right", "nudge-up", "nudge-down"]);
|
|
1184
|
+
var MODIFIERS = /* @__PURE__ */ new Set(["mod", "ctrl", "meta", "shift", "alt"]);
|
|
1185
|
+
function parseBinding(binding) {
|
|
1186
|
+
const parts = binding.toLowerCase().split("+");
|
|
1187
|
+
const key = parts.pop();
|
|
1188
|
+
if (key === void 0 || key.length === 0 || MODIFIERS.has(key)) {
|
|
1189
|
+
throw new Error(`Invalid shortcut binding "${binding}": missing key`);
|
|
1190
|
+
}
|
|
1191
|
+
const normalizedKey = key === "space" ? " " : key;
|
|
1192
|
+
const parsed = {
|
|
1193
|
+
mod: false,
|
|
1194
|
+
ctrl: false,
|
|
1195
|
+
meta: false,
|
|
1196
|
+
shift: false,
|
|
1197
|
+
alt: false,
|
|
1198
|
+
key: normalizedKey,
|
|
1199
|
+
digit: /^[0-9]$/.test(normalizedKey)
|
|
1200
|
+
};
|
|
1201
|
+
for (const part of parts) {
|
|
1202
|
+
switch (part) {
|
|
1203
|
+
case "mod":
|
|
1204
|
+
parsed.mod = true;
|
|
1205
|
+
break;
|
|
1206
|
+
case "ctrl":
|
|
1207
|
+
parsed.ctrl = true;
|
|
1208
|
+
break;
|
|
1209
|
+
case "meta":
|
|
1210
|
+
parsed.meta = true;
|
|
1211
|
+
break;
|
|
1212
|
+
case "shift":
|
|
1213
|
+
parsed.shift = true;
|
|
1214
|
+
break;
|
|
1215
|
+
case "alt":
|
|
1216
|
+
parsed.alt = true;
|
|
1217
|
+
break;
|
|
1218
|
+
default:
|
|
1219
|
+
throw new Error(`Invalid shortcut binding "${binding}": unknown modifier "${part}"`);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
return parsed;
|
|
1223
|
+
}
|
|
1224
|
+
function bindingMatches(p, e, allowShift) {
|
|
1225
|
+
if (p.mod) {
|
|
1226
|
+
if (!e.ctrlKey && !e.metaKey) return false;
|
|
1227
|
+
} else if (e.ctrlKey !== p.ctrl || e.metaKey !== p.meta) {
|
|
1228
|
+
return false;
|
|
1229
|
+
}
|
|
1230
|
+
if (!allowShift && e.shiftKey !== p.shift) return false;
|
|
1231
|
+
if (e.altKey !== p.alt) return false;
|
|
1232
|
+
return p.digit ? e.code === `Digit${p.key}` : e.key.toLowerCase() === p.key;
|
|
1233
|
+
}
|
|
1234
|
+
function toArray(bindings) {
|
|
1235
|
+
if (bindings === null) return [];
|
|
1236
|
+
return Array.isArray(bindings) ? [...bindings] : [bindings];
|
|
1237
|
+
}
|
|
1238
|
+
var ShortcutMap = class {
|
|
1239
|
+
raw = /* @__PURE__ */ new Map();
|
|
1240
|
+
parsed = /* @__PURE__ */ new Map();
|
|
1241
|
+
constructor(overrides) {
|
|
1242
|
+
this.applyDefaults();
|
|
1243
|
+
if (overrides) {
|
|
1244
|
+
for (const [action, bindings] of Object.entries(overrides)) {
|
|
1245
|
+
this.rebind(action, bindings);
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
/** First matching action in registration order wins when bindings conflict. */
|
|
1250
|
+
match(e) {
|
|
1251
|
+
for (const [action, parsedList] of this.parsed) {
|
|
1252
|
+
const allowShift = ALLOW_SHIFT.has(action);
|
|
1253
|
+
for (const p of parsedList) {
|
|
1254
|
+
if (bindingMatches(p, e, allowShift)) return action;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
return null;
|
|
1258
|
+
}
|
|
1259
|
+
rebind(action, bindings) {
|
|
1260
|
+
const list = toArray(bindings);
|
|
1261
|
+
const parsedList = list.map(parseBinding);
|
|
1262
|
+
this.raw.set(action, list);
|
|
1263
|
+
this.parsed.set(action, parsedList);
|
|
1264
|
+
}
|
|
1265
|
+
disable(action) {
|
|
1266
|
+
this.rebind(action, null);
|
|
1267
|
+
}
|
|
1268
|
+
reset(action) {
|
|
1269
|
+
if (action === void 0) {
|
|
1270
|
+
this.raw.clear();
|
|
1271
|
+
this.parsed.clear();
|
|
1272
|
+
this.applyDefaults();
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
const def = DEFAULT_BINDINGS.find(([name]) => name === action);
|
|
1276
|
+
if (def) {
|
|
1277
|
+
this.rebind(action, [...def[1]]);
|
|
1278
|
+
} else if (this.raw.has(action)) {
|
|
1279
|
+
this.raw.delete(action);
|
|
1280
|
+
this.parsed.delete(action);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
getBindings() {
|
|
1284
|
+
const out = {};
|
|
1285
|
+
for (const [action, list] of this.raw) {
|
|
1286
|
+
out[action] = [...list];
|
|
1287
|
+
}
|
|
1288
|
+
return out;
|
|
1289
|
+
}
|
|
1290
|
+
applyDefaults() {
|
|
1291
|
+
for (const [action, bindings] of DEFAULT_BINDINGS) {
|
|
1292
|
+
this.rebind(action, [...bindings]);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
};
|
|
1296
|
+
|
|
1153
1297
|
// src/canvas/input-handler.ts
|
|
1154
1298
|
var ZOOM_SENSITIVITY = 1e-3;
|
|
1155
1299
|
var MIDDLE_BUTTON = 1;
|
|
1156
|
-
var
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1300
|
+
var NUDGE_DELTAS = {
|
|
1301
|
+
"nudge-left": [-1, 0],
|
|
1302
|
+
"nudge-right": [1, 0],
|
|
1303
|
+
"nudge-up": [0, -1],
|
|
1304
|
+
"nudge-down": [0, 1]
|
|
1161
1305
|
};
|
|
1162
1306
|
var InputHandler = class {
|
|
1163
1307
|
constructor(element, camera, options = {}) {
|
|
@@ -1175,7 +1319,13 @@ var InputHandler = class {
|
|
|
1175
1319
|
isToolActive: () => this.isToolActive,
|
|
1176
1320
|
fitToContent: options.fitToContent
|
|
1177
1321
|
});
|
|
1322
|
+
this.shortcutMap = new ShortcutMap(options.shortcuts?.bindings);
|
|
1323
|
+
this.scope = options.shortcuts?.scope ?? "focus";
|
|
1178
1324
|
this.element.style.touchAction = "none";
|
|
1325
|
+
if (this.scope === "focus") {
|
|
1326
|
+
this.element.tabIndex = 0;
|
|
1327
|
+
this.element.style.outline = "none";
|
|
1328
|
+
}
|
|
1179
1329
|
this.bind();
|
|
1180
1330
|
}
|
|
1181
1331
|
isPanning = false;
|
|
@@ -1194,6 +1344,8 @@ var InputHandler = class {
|
|
|
1194
1344
|
deferredDown = null;
|
|
1195
1345
|
abortController = new AbortController();
|
|
1196
1346
|
actions;
|
|
1347
|
+
shortcutMap;
|
|
1348
|
+
scope;
|
|
1197
1349
|
setToolManager(toolManager, toolContext) {
|
|
1198
1350
|
this.toolManager = toolManager;
|
|
1199
1351
|
this.toolContext = toolContext;
|
|
@@ -1201,6 +1353,9 @@ var InputHandler = class {
|
|
|
1201
1353
|
flushPendingHistory() {
|
|
1202
1354
|
this.actions.flushPendingNudge();
|
|
1203
1355
|
}
|
|
1356
|
+
get shortcuts() {
|
|
1357
|
+
return this.shortcutMap;
|
|
1358
|
+
}
|
|
1204
1359
|
destroy() {
|
|
1205
1360
|
this.actions.dispose();
|
|
1206
1361
|
this.abortController.abort();
|
|
@@ -1230,6 +1385,7 @@ var InputHandler = class {
|
|
|
1230
1385
|
});
|
|
1231
1386
|
};
|
|
1232
1387
|
onPointerDown = (e) => {
|
|
1388
|
+
this.focusSelf();
|
|
1233
1389
|
this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
1234
1390
|
this.element.setPointerCapture?.(e.pointerId);
|
|
1235
1391
|
if (this.activePointers.size === 2) {
|
|
@@ -1312,57 +1468,13 @@ var InputHandler = class {
|
|
|
1312
1468
|
if (target?.isContentEditable) return;
|
|
1313
1469
|
const tag = target?.tagName;
|
|
1314
1470
|
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
|
|
1471
|
+
if (!this.isInScope()) return;
|
|
1315
1472
|
if (e.key === " ") {
|
|
1316
1473
|
this.spaceHeld = true;
|
|
1317
1474
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
if (e.key === "Escape") {
|
|
1322
|
-
this.actions.deselect();
|
|
1323
|
-
}
|
|
1324
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "z" && !e.shiftKey) {
|
|
1325
|
-
e.preventDefault();
|
|
1326
|
-
this.actions.undo();
|
|
1327
|
-
}
|
|
1328
|
-
if ((e.ctrlKey || e.metaKey) && (e.key === "y" || e.key === "z" && e.shiftKey)) {
|
|
1329
|
-
e.preventDefault();
|
|
1330
|
-
this.actions.redo();
|
|
1331
|
-
}
|
|
1332
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "a") {
|
|
1333
|
-
e.preventDefault();
|
|
1334
|
-
this.actions.selectAll();
|
|
1335
|
-
}
|
|
1336
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "c") {
|
|
1337
|
-
e.preventDefault();
|
|
1338
|
-
this.actions.copy();
|
|
1339
|
-
}
|
|
1340
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "v") {
|
|
1341
|
-
e.preventDefault();
|
|
1342
|
-
this.actions.paste();
|
|
1343
|
-
}
|
|
1344
|
-
if ((e.ctrlKey || e.metaKey) && e.key === "d") {
|
|
1345
|
-
e.preventDefault();
|
|
1346
|
-
this.actions.duplicate();
|
|
1347
|
-
}
|
|
1348
|
-
if (e.key === "]") {
|
|
1349
|
-
e.preventDefault();
|
|
1350
|
-
this.actions.zOrder(e.ctrlKey || e.metaKey ? "front" : "forward");
|
|
1351
|
-
}
|
|
1352
|
-
if (e.key === "[") {
|
|
1353
|
-
e.preventDefault();
|
|
1354
|
-
this.actions.zOrder(e.ctrlKey || e.metaKey ? "back" : "backward");
|
|
1355
|
-
}
|
|
1356
|
-
if (e.shiftKey && e.code === "Digit1" && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
1357
|
-
e.preventDefault();
|
|
1358
|
-
this.actions.zoomToFit();
|
|
1359
|
-
}
|
|
1360
|
-
const nudgeDelta = NUDGE_KEYS[e.key];
|
|
1361
|
-
if (nudgeDelta) {
|
|
1362
|
-
const [dx, dy] = nudgeDelta;
|
|
1363
|
-
if (this.actions.nudge(dx, dy, e.shiftKey)) {
|
|
1364
|
-
e.preventDefault();
|
|
1365
|
-
}
|
|
1475
|
+
const action = this.shortcutMap.match(e);
|
|
1476
|
+
if (action !== null) {
|
|
1477
|
+
this.runAction(action, e);
|
|
1366
1478
|
}
|
|
1367
1479
|
};
|
|
1368
1480
|
onKeyUp = (e) => {
|
|
@@ -1377,6 +1489,79 @@ var InputHandler = class {
|
|
|
1377
1489
|
}
|
|
1378
1490
|
}
|
|
1379
1491
|
};
|
|
1492
|
+
runAction(action, e) {
|
|
1493
|
+
switch (action) {
|
|
1494
|
+
case "delete":
|
|
1495
|
+
e.preventDefault();
|
|
1496
|
+
this.actions.deleteSelected();
|
|
1497
|
+
return;
|
|
1498
|
+
case "deselect":
|
|
1499
|
+
this.actions.deselect();
|
|
1500
|
+
return;
|
|
1501
|
+
case "undo":
|
|
1502
|
+
e.preventDefault();
|
|
1503
|
+
this.actions.undo();
|
|
1504
|
+
return;
|
|
1505
|
+
case "redo":
|
|
1506
|
+
e.preventDefault();
|
|
1507
|
+
this.actions.redo();
|
|
1508
|
+
return;
|
|
1509
|
+
case "select-all":
|
|
1510
|
+
e.preventDefault();
|
|
1511
|
+
this.actions.selectAll();
|
|
1512
|
+
return;
|
|
1513
|
+
case "copy":
|
|
1514
|
+
e.preventDefault();
|
|
1515
|
+
this.actions.copy();
|
|
1516
|
+
return;
|
|
1517
|
+
case "paste":
|
|
1518
|
+
e.preventDefault();
|
|
1519
|
+
this.actions.paste();
|
|
1520
|
+
return;
|
|
1521
|
+
case "duplicate":
|
|
1522
|
+
e.preventDefault();
|
|
1523
|
+
this.actions.duplicate();
|
|
1524
|
+
return;
|
|
1525
|
+
case "z-forward":
|
|
1526
|
+
e.preventDefault();
|
|
1527
|
+
this.actions.zOrder("forward");
|
|
1528
|
+
return;
|
|
1529
|
+
case "z-backward":
|
|
1530
|
+
e.preventDefault();
|
|
1531
|
+
this.actions.zOrder("backward");
|
|
1532
|
+
return;
|
|
1533
|
+
case "z-front":
|
|
1534
|
+
e.preventDefault();
|
|
1535
|
+
this.actions.zOrder("front");
|
|
1536
|
+
return;
|
|
1537
|
+
case "z-back":
|
|
1538
|
+
e.preventDefault();
|
|
1539
|
+
this.actions.zOrder("back");
|
|
1540
|
+
return;
|
|
1541
|
+
case "zoom-fit":
|
|
1542
|
+
e.preventDefault();
|
|
1543
|
+
this.actions.zoomToFit();
|
|
1544
|
+
return;
|
|
1545
|
+
case "nudge-left":
|
|
1546
|
+
case "nudge-right":
|
|
1547
|
+
case "nudge-up":
|
|
1548
|
+
case "nudge-down": {
|
|
1549
|
+
const delta = NUDGE_DELTAS[action];
|
|
1550
|
+
if (delta && this.actions.nudge(delta[0], delta[1], e.shiftKey)) {
|
|
1551
|
+
e.preventDefault();
|
|
1552
|
+
}
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
default:
|
|
1556
|
+
if (action.startsWith("tool:")) {
|
|
1557
|
+
if (this.isToolActive) return;
|
|
1558
|
+
e.preventDefault();
|
|
1559
|
+
this.toolContext?.switchTool?.(action.slice("tool:".length));
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
console.warn(`[fieldnotes] unknown shortcut action "${action}"`);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1380
1565
|
startPinch() {
|
|
1381
1566
|
this.inputFilter.reset();
|
|
1382
1567
|
this.deferredDown = null;
|
|
@@ -1447,6 +1632,15 @@ var InputHandler = class {
|
|
|
1447
1632
|
this.toolManager.handlePointerUp(this.toPointerState(e), this.toolContext);
|
|
1448
1633
|
this.historyRecorder?.commit();
|
|
1449
1634
|
}
|
|
1635
|
+
isInScope() {
|
|
1636
|
+
if (this.scope === "window") return true;
|
|
1637
|
+
const active = document.activeElement;
|
|
1638
|
+
return active === this.element || this.element.contains(active);
|
|
1639
|
+
}
|
|
1640
|
+
focusSelf() {
|
|
1641
|
+
if (this.scope !== "focus" || this.isInScope()) return;
|
|
1642
|
+
this.element.focus({ preventScroll: true });
|
|
1643
|
+
}
|
|
1450
1644
|
cancelToolIfActive(e) {
|
|
1451
1645
|
if (this.isToolActive) {
|
|
1452
1646
|
this.dispatchToolUp(e);
|
|
@@ -4841,7 +5035,8 @@ var Viewport = class {
|
|
|
4841
5035
|
toolContext: this.toolContext,
|
|
4842
5036
|
historyRecorder: this.historyRecorder,
|
|
4843
5037
|
historyStack: this.history,
|
|
4844
|
-
fitToContent: () => this.fitToContent()
|
|
5038
|
+
fitToContent: () => this.fitToContent(),
|
|
5039
|
+
shortcuts: options.shortcuts
|
|
4845
5040
|
});
|
|
4846
5041
|
this.domNodeManager = new DomNodeManager({
|
|
4847
5042
|
domLayer: this.domLayer,
|
|
@@ -5015,6 +5210,9 @@ var Viewport = class {
|
|
|
5015
5210
|
setTool(name) {
|
|
5016
5211
|
this.toolManager.setTool(name, this.toolContext);
|
|
5017
5212
|
}
|
|
5213
|
+
get shortcuts() {
|
|
5214
|
+
return this.inputHandler.shortcuts;
|
|
5215
|
+
}
|
|
5018
5216
|
undo() {
|
|
5019
5217
|
this.inputHandler.flushPendingHistory();
|
|
5020
5218
|
this.historyRecorder.pause();
|
|
@@ -7053,7 +7251,7 @@ var TemplateTool = class {
|
|
|
7053
7251
|
};
|
|
7054
7252
|
|
|
7055
7253
|
// src/index.ts
|
|
7056
|
-
var VERSION = "0.
|
|
7254
|
+
var VERSION = "0.19.0";
|
|
7057
7255
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7058
7256
|
0 && (module.exports = {
|
|
7059
7257
|
AddElementCommand,
|