js-draw 1.10.0 → 1.11.1
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/Editor.css +6 -2
- package/dist/bundle.js +3 -3
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +7 -0
- package/dist/cjs/Editor.js +18 -4
- package/dist/cjs/commands/invertCommand.js +5 -0
- package/dist/cjs/components/AbstractComponent.d.ts +8 -0
- package/dist/cjs/components/AbstractComponent.js +28 -8
- package/dist/cjs/components/BackgroundComponent.d.ts +1 -1
- package/dist/cjs/components/ImageComponent.d.ts +1 -1
- package/dist/cjs/components/SVGGlobalAttributesObject.d.ts +1 -1
- package/dist/cjs/components/Stroke.d.ts +1 -1
- package/dist/cjs/components/builders/types.d.ts +11 -0
- package/dist/cjs/rendering/Display.js +3 -1
- package/dist/cjs/rendering/renderers/DummyRenderer.d.ts +1 -0
- package/dist/cjs/rendering/renderers/DummyRenderer.js +3 -0
- package/dist/cjs/toolbar/AbstractToolbar.d.ts +18 -2
- package/dist/cjs/toolbar/AbstractToolbar.js +46 -30
- package/dist/cjs/toolbar/widgets/BaseWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/ExitActionWidget.d.ts +12 -0
- package/dist/cjs/toolbar/widgets/ExitActionWidget.js +32 -0
- package/dist/cjs/toolbar/widgets/HandToolWidget.d.ts +4 -3
- package/dist/cjs/toolbar/widgets/HandToolWidget.js +24 -13
- package/dist/cjs/toolbar/widgets/InsertImageWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/keybindings.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/keybindings.js +4 -1
- package/dist/cjs/toolbar/widgets/layout/types.d.ts +1 -1
- package/dist/cjs/tools/FindTool.js +1 -1
- package/dist/cjs/tools/Pen.js +13 -2
- package/dist/cjs/tools/SelectionTool/Selection.d.ts +4 -0
- package/dist/cjs/tools/SelectionTool/Selection.js +56 -12
- package/dist/cjs/tools/SelectionTool/SelectionTool.d.ts +1 -0
- package/dist/cjs/tools/SelectionTool/SelectionTool.js +35 -3
- package/dist/cjs/tools/ToolSwitcherShortcut.d.ts +0 -1
- package/dist/cjs/tools/ToolSwitcherShortcut.js +0 -1
- package/dist/cjs/tools/keybindings.d.ts +1 -0
- package/dist/cjs/tools/keybindings.js +3 -1
- package/dist/cjs/tools/localization.d.ts +2 -0
- package/dist/cjs/tools/localization.js +2 -0
- package/dist/cjs/util/listenForKeyboardEventsFrom.d.ts +5 -0
- package/dist/cjs/util/listenForKeyboardEventsFrom.js +5 -1
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +7 -0
- package/dist/mjs/Editor.mjs +18 -4
- package/dist/mjs/commands/invertCommand.mjs +5 -0
- package/dist/mjs/components/AbstractComponent.d.ts +8 -0
- package/dist/mjs/components/AbstractComponent.mjs +28 -8
- package/dist/mjs/components/BackgroundComponent.d.ts +1 -1
- package/dist/mjs/components/ImageComponent.d.ts +1 -1
- package/dist/mjs/components/SVGGlobalAttributesObject.d.ts +1 -1
- package/dist/mjs/components/Stroke.d.ts +1 -1
- package/dist/mjs/components/builders/types.d.ts +11 -0
- package/dist/mjs/rendering/Display.mjs +3 -1
- package/dist/mjs/rendering/renderers/DummyRenderer.d.ts +1 -0
- package/dist/mjs/rendering/renderers/DummyRenderer.mjs +3 -0
- package/dist/mjs/toolbar/AbstractToolbar.d.ts +18 -2
- package/dist/mjs/toolbar/AbstractToolbar.mjs +46 -30
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/ExitActionWidget.d.ts +12 -0
- package/dist/mjs/toolbar/widgets/ExitActionWidget.mjs +27 -0
- package/dist/mjs/toolbar/widgets/HandToolWidget.d.ts +4 -3
- package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +24 -13
- package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/keybindings.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/keybindings.mjs +3 -0
- package/dist/mjs/toolbar/widgets/layout/types.d.ts +1 -1
- package/dist/mjs/tools/FindTool.mjs +1 -1
- package/dist/mjs/tools/Pen.mjs +13 -2
- package/dist/mjs/tools/SelectionTool/Selection.d.ts +4 -0
- package/dist/mjs/tools/SelectionTool/Selection.mjs +56 -12
- package/dist/mjs/tools/SelectionTool/SelectionTool.d.ts +1 -0
- package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +36 -4
- package/dist/mjs/tools/ToolSwitcherShortcut.d.ts +0 -1
- package/dist/mjs/tools/ToolSwitcherShortcut.mjs +0 -1
- package/dist/mjs/tools/keybindings.d.ts +1 -0
- package/dist/mjs/tools/keybindings.mjs +2 -0
- package/dist/mjs/tools/localization.d.ts +2 -0
- package/dist/mjs/tools/localization.mjs +2 -0
- package/dist/mjs/util/listenForKeyboardEventsFrom.d.ts +5 -0
- package/dist/mjs/util/listenForKeyboardEventsFrom.mjs +5 -1
- package/dist/mjs/version.mjs +1 -1
- package/package.json +5 -5
- package/src/toolbar/AbstractToolbar.scss +3 -2
- package/src/toolbar/widgets/components/makeColorInput.scss +8 -0
@@ -15,3 +15,4 @@ export declare const zoomInKeyboardShortcutId = "jsdraw.tools.PanZoom.zoomIn";
|
|
15
15
|
export declare const zoomOutKeyboardShortcutId = "jsdraw.tools.PanZoom.zoomOut";
|
16
16
|
export declare const selectAllKeyboardShortcut = "jsdraw.tools.SelectionTool.selectAll";
|
17
17
|
export declare const duplicateSelectionShortcut = "jsdraw.tools.SelectionTool.duplicateSelection";
|
18
|
+
export declare const sendToBackSelectionShortcut = "jsdraw.tools.SelectionTool.sendToBack";
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.duplicateSelectionShortcut = exports.selectAllKeyboardShortcut = exports.zoomOutKeyboardShortcutId = exports.zoomInKeyboardShortcutId = exports.rotateCounterClockwiseKeyboardShortcutId = exports.rotateClockwiseKeyboardShortcutId = exports.moveDownKeyboardShortcutId = exports.moveUpKeyboardShortcutId = exports.moveRightKeyboardShortcutId = exports.moveLeftKeyboardShortcutId = exports.toggleFindVisibleShortcutId = exports.lineLockKeyboardShortcutId = exports.snapToGridKeyboardShortcutId = exports.decreaseSizeKeyboardShortcutId = exports.increaseSizeKeyboardShortcutId = exports.redoKeyboardShortcutId = exports.undoKeyboardShortcutId = void 0;
|
6
|
+
exports.sendToBackSelectionShortcut = exports.duplicateSelectionShortcut = exports.selectAllKeyboardShortcut = exports.zoomOutKeyboardShortcutId = exports.zoomInKeyboardShortcutId = exports.rotateCounterClockwiseKeyboardShortcutId = exports.rotateClockwiseKeyboardShortcutId = exports.moveDownKeyboardShortcutId = exports.moveUpKeyboardShortcutId = exports.moveRightKeyboardShortcutId = exports.moveLeftKeyboardShortcutId = exports.toggleFindVisibleShortcutId = exports.lineLockKeyboardShortcutId = exports.snapToGridKeyboardShortcutId = exports.decreaseSizeKeyboardShortcutId = exports.increaseSizeKeyboardShortcutId = exports.redoKeyboardShortcutId = exports.undoKeyboardShortcutId = void 0;
|
7
7
|
const KeyboardShortcutManager_1 = __importDefault(require("../shortcuts/KeyboardShortcutManager"));
|
8
8
|
// This file contains user-overridable tool-realted keybindings.
|
9
9
|
// Undo/redo
|
@@ -45,3 +45,5 @@ exports.selectAllKeyboardShortcut = 'jsdraw.tools.SelectionTool.selectAll';
|
|
45
45
|
KeyboardShortcutManager_1.default.registerDefaultKeyboardShortcut(exports.selectAllKeyboardShortcut, ['CtrlOrMeta+KeyA'], 'Select all');
|
46
46
|
exports.duplicateSelectionShortcut = 'jsdraw.tools.SelectionTool.duplicateSelection';
|
47
47
|
KeyboardShortcutManager_1.default.registerDefaultKeyboardShortcut(exports.duplicateSelectionShortcut, ['CtrlOrMeta+KeyD'], 'Duplicate selection');
|
48
|
+
exports.sendToBackSelectionShortcut = 'jsdraw.tools.SelectionTool.sendToBack';
|
49
|
+
KeyboardShortcutManager_1.default.registerDefaultKeyboardShortcut(exports.sendToBackSelectionShortcut, ['End'], 'Send to back');
|
@@ -9,6 +9,8 @@ export interface ToolLocalization {
|
|
9
9
|
undoRedoTool: string;
|
10
10
|
pipetteTool: string;
|
11
11
|
rightClickDragPanTool: string;
|
12
|
+
autocorrectedTo: (description: string) => string;
|
13
|
+
autocorrectionCanceled: string;
|
12
14
|
textTool: string;
|
13
15
|
enterTextToInsert: string;
|
14
16
|
changeTool: string;
|
@@ -12,6 +12,8 @@ exports.defaultToolLocalization = {
|
|
12
12
|
rightClickDragPanTool: 'Right-click drag',
|
13
13
|
pipetteTool: 'Pick color from screen',
|
14
14
|
keyboardPanZoom: 'Keyboard pan/zoom shortcuts',
|
15
|
+
autocorrectedTo: (strokeDescription) => `Autocorrected to ${strokeDescription}`,
|
16
|
+
autocorrectionCanceled: 'Autocorrect cancelled',
|
15
17
|
textTool: 'Text',
|
16
18
|
enterTextToInsert: 'Text to insert',
|
17
19
|
changeTool: 'Change tool',
|
@@ -2,6 +2,11 @@ interface Callbacks {
|
|
2
2
|
filter(event: KeyboardEvent): boolean;
|
3
3
|
handleKeyDown(event: KeyboardEvent): void;
|
4
4
|
handleKeyUp(event: KeyboardEvent): void;
|
5
|
+
/**
|
6
|
+
* Should return `true` iff `source` is also registered as an event listener source.
|
7
|
+
* If `false` and focus leaves the original source, keyup events are fired.
|
8
|
+
*/
|
9
|
+
getHandlesKeyEventsFrom(source: Node): boolean;
|
5
10
|
}
|
6
11
|
/**
|
7
12
|
* Calls `callbacks` when different keys are known to be pressed.
|
@@ -67,7 +67,11 @@ const listenForKeyboardEventsFrom = (elem, callbacks) => {
|
|
67
67
|
handleKeyEvent(htmlEvent);
|
68
68
|
});
|
69
69
|
elem.addEventListener('focusout', (focusEvent) => {
|
70
|
-
|
70
|
+
let stillHasFocus = false;
|
71
|
+
if (focusEvent.relatedTarget) {
|
72
|
+
const relatedTarget = focusEvent.relatedTarget;
|
73
|
+
stillHasFocus = elem.contains(relatedTarget) || callbacks.getHandlesKeyEventsFrom(relatedTarget);
|
74
|
+
}
|
71
75
|
if (!stillHasFocus) {
|
72
76
|
for (const event of keysDown) {
|
73
77
|
callbacks.handleKeyUp(new KeyboardEvent('keyup', {
|
package/dist/cjs/version.js
CHANGED
package/dist/mjs/Editor.d.ts
CHANGED
@@ -255,6 +255,13 @@ export declare class Editor {
|
|
255
255
|
private updateEditorSizeVariables;
|
256
256
|
private pointers;
|
257
257
|
private getPointerList;
|
258
|
+
/**
|
259
|
+
* A protected method that can override setPointerCapture in environments where it may fail
|
260
|
+
* (e.g. with synthetic events). @internal
|
261
|
+
*/
|
262
|
+
protected setPointerCapture(target: HTMLElement, pointerId: number): void;
|
263
|
+
/** Can be overridden in a testing environment to handle synthetic events. @internal */
|
264
|
+
protected releasePointerCapture(target: HTMLElement, pointerId: number): void;
|
258
265
|
/**
|
259
266
|
* Dispatches a `PointerEvent` to the editor. The target element for `evt` must have the same top left
|
260
267
|
* as the content of the editor.
|
package/dist/mjs/Editor.mjs
CHANGED
@@ -327,6 +327,17 @@ export class Editor {
|
|
327
327
|
}
|
328
328
|
return res;
|
329
329
|
}
|
330
|
+
/**
|
331
|
+
* A protected method that can override setPointerCapture in environments where it may fail
|
332
|
+
* (e.g. with synthetic events). @internal
|
333
|
+
*/
|
334
|
+
setPointerCapture(target, pointerId) {
|
335
|
+
target.setPointerCapture(pointerId);
|
336
|
+
}
|
337
|
+
/** Can be overridden in a testing environment to handle synthetic events. @internal */
|
338
|
+
releasePointerCapture(target, pointerId) {
|
339
|
+
target.releasePointerCapture(pointerId);
|
340
|
+
}
|
330
341
|
/**
|
331
342
|
* Dispatches a `PointerEvent` to the editor. The target element for `evt` must have the same top left
|
332
343
|
* as the content of the editor.
|
@@ -337,7 +348,7 @@ export class Editor {
|
|
337
348
|
if (eventType === 'pointerdown') {
|
338
349
|
const pointer = Pointer.ofEvent(evt, true, this.viewport, eventsRelativeTo);
|
339
350
|
this.pointers[pointer.id] = pointer;
|
340
|
-
|
351
|
+
this.setPointerCapture(eventTarget, pointer.id);
|
341
352
|
const event = {
|
342
353
|
kind: InputEvtType.PointerDownEvt,
|
343
354
|
current: pointer,
|
@@ -374,7 +385,7 @@ export class Editor {
|
|
374
385
|
return false;
|
375
386
|
}
|
376
387
|
this.pointers[pointer.id] = pointer;
|
377
|
-
|
388
|
+
this.releasePointerCapture(eventTarget, pointer.id);
|
378
389
|
if (this.toolController.dispatchInputEvent({
|
379
390
|
kind: InputEvtType.PointerUpEvt,
|
380
391
|
current: pointer,
|
@@ -563,7 +574,7 @@ export class Editor {
|
|
563
574
|
startPoint: currentPos,
|
564
575
|
};
|
565
576
|
// Capture the pointer so we receive future events even if the overlay is hidden.
|
566
|
-
|
577
|
+
this.setPointerCapture(elem, event.pointerId);
|
567
578
|
// Don't send to the editor.
|
568
579
|
sendToEditor = false;
|
569
580
|
}
|
@@ -595,7 +606,7 @@ export class Editor {
|
|
595
606
|
// pointercancel event.
|
596
607
|
else if ((eventName === 'pointerup' || eventName === 'pointercancel')
|
597
608
|
&& gestureData[pointerId] && gestureData[pointerId].eventBuffer.length > 0) {
|
598
|
-
|
609
|
+
this.releasePointerCapture(elem, event.pointerId);
|
599
610
|
// Don't send to the editor.
|
600
611
|
sendToEditor = false;
|
601
612
|
delete gestureData[pointerId];
|
@@ -643,6 +654,9 @@ export class Editor {
|
|
643
654
|
handleKeyUp: (htmlEvent) => {
|
644
655
|
this.handleHTMLKeyUpEvent(htmlEvent);
|
645
656
|
},
|
657
|
+
getHandlesKeyEventsFrom: (element) => {
|
658
|
+
return this.eventListenerTargets.includes(element);
|
659
|
+
},
|
646
660
|
});
|
647
661
|
// Allow drop.
|
648
662
|
elem.ondragover = evt => {
|
@@ -6,6 +6,11 @@ const invertCommand = (command) => {
|
|
6
6
|
if (command instanceof SerializableCommand) {
|
7
7
|
// SerializableCommand that does the inverse of [command]
|
8
8
|
return new class extends SerializableCommand {
|
9
|
+
constructor() {
|
10
|
+
super(...arguments);
|
11
|
+
// For debugging
|
12
|
+
this._command = command;
|
13
|
+
}
|
9
14
|
serializeToJSON() {
|
10
15
|
return command.serialize();
|
11
16
|
}
|
@@ -116,6 +116,14 @@ export default abstract class AbstractComponent {
|
|
116
116
|
protected abstract applyTransformation(affineTransfm: Mat33): void;
|
117
117
|
transformBy(affineTransfm: Mat33): SerializableCommand;
|
118
118
|
setZIndex(newZIndex: number): SerializableCommand;
|
119
|
+
/**
|
120
|
+
* Combines {@link transformBy} and {@link setZIndex} into a single command.
|
121
|
+
*
|
122
|
+
* @param newZIndex - The z-index this component should have after applying this command.
|
123
|
+
* @param originalZIndex - @internal The z-index the component should revert to after unapplying
|
124
|
+
* this command.
|
125
|
+
*/
|
126
|
+
setZIndexAndTransformBy(affineTransfm: Mat33, newZIndex: number, originalZIndex?: number): SerializableCommand;
|
119
127
|
isSelectable(): boolean;
|
120
128
|
isBackground(): boolean;
|
121
129
|
getProportionalRenderingTime(): number;
|
@@ -138,13 +138,25 @@ class AbstractComponent {
|
|
138
138
|
}
|
139
139
|
// Returns a command that, when applied, transforms this by [affineTransfm] and
|
140
140
|
// updates the editor.
|
141
|
-
//
|
141
|
+
//
|
142
|
+
// The transformed component is also moved to the top (use {@link setZIndexAndTransformBy} to
|
143
|
+
// avoid this behavior).
|
142
144
|
transformBy(affineTransfm) {
|
143
145
|
return new AbstractComponent.TransformElementCommand(affineTransfm, this.getId(), this);
|
144
146
|
}
|
145
147
|
// Returns a command that updates this component's z-index.
|
146
148
|
setZIndex(newZIndex) {
|
147
|
-
return new AbstractComponent.TransformElementCommand(Mat33.identity, this.getId(), this, newZIndex
|
149
|
+
return new AbstractComponent.TransformElementCommand(Mat33.identity, this.getId(), this, newZIndex);
|
150
|
+
}
|
151
|
+
/**
|
152
|
+
* Combines {@link transformBy} and {@link setZIndex} into a single command.
|
153
|
+
*
|
154
|
+
* @param newZIndex - The z-index this component should have after applying this command.
|
155
|
+
* @param originalZIndex - @internal The z-index the component should revert to after unapplying
|
156
|
+
* this command.
|
157
|
+
*/
|
158
|
+
setZIndexAndTransformBy(affineTransfm, newZIndex, originalZIndex) {
|
159
|
+
return new AbstractComponent.TransformElementCommand(affineTransfm, this.getId(), this, newZIndex, originalZIndex);
|
148
160
|
}
|
149
161
|
// @returns true iff this component can be selected (e.g. by the selection tool.)
|
150
162
|
isSelectable() {
|
@@ -215,8 +227,12 @@ class AbstractComponent {
|
|
215
227
|
throw new Error(`Element with data ${json} cannot be deserialized.`);
|
216
228
|
}
|
217
229
|
const instance = this.deserializationCallbacks[json.name](json.data);
|
218
|
-
instance.zIndex = json.zIndex;
|
219
230
|
instance.id = json.id;
|
231
|
+
if (isFinite(json.zIndex)) {
|
232
|
+
instance.zIndex = json.zIndex;
|
233
|
+
// Ensure that new components will be added on top.
|
234
|
+
AbstractComponent.zIndexCounter = Math.max(AbstractComponent.zIndexCounter, instance.zIndex + 1);
|
235
|
+
}
|
220
236
|
// TODO: What should we do with json.loadSaveData?
|
221
237
|
// If we attach it to [instance], we create a potential security risk — loadSaveData
|
222
238
|
// is often used to store unrecognised attributes so they can be preserved on output.
|
@@ -225,6 +241,7 @@ class AbstractComponent {
|
|
225
241
|
}
|
226
242
|
}
|
227
243
|
// Topmost z-index
|
244
|
+
// TODO: Should be a property of the EditorImage.
|
228
245
|
AbstractComponent.zIndexCounter = 0;
|
229
246
|
AbstractComponent.deserializationCallbacks = {};
|
230
247
|
AbstractComponent.transformElementCommandId = 'transform-element';
|
@@ -252,7 +269,7 @@ AbstractComponent.TransformElementCommand = (_a = class extends UnresolvedSerial
|
|
252
269
|
super.resolveComponent(image);
|
253
270
|
this.origZIndex ??= this.component.getZIndex();
|
254
271
|
}
|
255
|
-
updateTransform(editor, newTransfm) {
|
272
|
+
updateTransform(editor, newTransfm, targetZIndex) {
|
256
273
|
if (!this.component) {
|
257
274
|
throw new Error('this.component is undefined or null!');
|
258
275
|
}
|
@@ -264,7 +281,12 @@ AbstractComponent.TransformElementCommand = (_a = class extends UnresolvedSerial
|
|
264
281
|
hadParent = true;
|
265
282
|
}
|
266
283
|
this.component.applyTransformation(newTransfm);
|
284
|
+
this.component.zIndex = targetZIndex;
|
267
285
|
this.component.lastChangedTime = (new Date()).getTime();
|
286
|
+
// Ensure that new components are automatically drawn above the current component.
|
287
|
+
if (targetZIndex >= AbstractComponent.zIndexCounter) {
|
288
|
+
AbstractComponent.zIndexCounter = targetZIndex + 1;
|
289
|
+
}
|
268
290
|
// Add the element back to the document.
|
269
291
|
if (hadParent) {
|
270
292
|
EditorImage.addElement(this.component).apply(editor);
|
@@ -272,14 +294,12 @@ AbstractComponent.TransformElementCommand = (_a = class extends UnresolvedSerial
|
|
272
294
|
}
|
273
295
|
apply(editor) {
|
274
296
|
this.resolveComponent(editor.image);
|
275
|
-
this.
|
276
|
-
this.updateTransform(editor, this.affineTransfm);
|
297
|
+
this.updateTransform(editor, this.affineTransfm, this.targetZIndex);
|
277
298
|
editor.queueRerender();
|
278
299
|
}
|
279
300
|
unapply(editor) {
|
280
301
|
this.resolveComponent(editor.image);
|
281
|
-
this.
|
282
|
-
this.updateTransform(editor, this.affineTransfm.inverse());
|
302
|
+
this.updateTransform(editor, this.affineTransfm.inverse(), this.origZIndex);
|
283
303
|
editor.queueRerender();
|
284
304
|
}
|
285
305
|
description(_editor, localizationTable) {
|
@@ -64,5 +64,5 @@ export default class BackgroundComponent extends AbstractComponent implements Re
|
|
64
64
|
protected applyTransformation(_affineTransfm: Mat33): void;
|
65
65
|
description(localizationTable: ImageComponentLocalization): string;
|
66
66
|
protected createClone(): AbstractComponent;
|
67
|
-
static deserializeFromJSON(json: any): BackgroundComponent;
|
67
|
+
static deserializeFromJSON(this: void, json: any): BackgroundComponent;
|
68
68
|
}
|
@@ -15,6 +15,6 @@ export default class SVGGlobalAttributesObject extends AbstractComponent {
|
|
15
15
|
protected createClone(): SVGGlobalAttributesObject;
|
16
16
|
description(localization: ImageComponentLocalization): string;
|
17
17
|
protected serializeToJSON(): string | null;
|
18
|
-
static deserializeFromString(_data: string): AbstractComponent;
|
18
|
+
static deserializeFromString(this: void, _data: string): AbstractComponent;
|
19
19
|
}
|
20
20
|
export {};
|
@@ -7,6 +7,17 @@ export interface ComponentBuilder {
|
|
7
7
|
getBBox(): Rect2;
|
8
8
|
build(): AbstractComponent;
|
9
9
|
preview(renderer: AbstractRenderer): void;
|
10
|
+
/**
|
11
|
+
* Called when the pen is stationary (or the user otherwise
|
12
|
+
* activates autocomplete). This might attempt to fit the user's
|
13
|
+
* drawing to a particular shape.
|
14
|
+
*
|
15
|
+
* The shape returned by this function may be ignored if it has
|
16
|
+
* an empty bounding box.
|
17
|
+
*
|
18
|
+
* Although this returns a Promise, it should return *as fast as
|
19
|
+
* possible*.
|
20
|
+
*/
|
10
21
|
autocorrectShape?: () => Promise<AbstractComponent | null>;
|
11
22
|
addPoint(point: StrokeDataPoint): void;
|
12
23
|
}
|
@@ -70,7 +70,9 @@ export default class Display {
|
|
70
70
|
},
|
71
71
|
blockResolution: cacheBlockResolution,
|
72
72
|
cacheSize: 600 * 600 * 4 * 90,
|
73
|
-
|
73
|
+
// On higher resolution displays, don't scale cache blocks as much to decrease blurriness.
|
74
|
+
// TODO: Decrease the minimum cache scale as well.
|
75
|
+
maxScale: Math.max(1, 1.3 / window.devicePixelRatio),
|
74
76
|
// Require about 20 strokes with 4 parts each to cache an image in one of the
|
75
77
|
// parts of the cache grid.
|
76
78
|
minProportionalRenderTimePerCache: 20 * 4,
|
@@ -29,4 +29,5 @@ export default class DummyRenderer extends AbstractRenderer {
|
|
29
29
|
isTooSmallToRender(_rect: Rect2): boolean;
|
30
30
|
canRenderFromWithoutDataLoss(other: AbstractRenderer): boolean;
|
31
31
|
renderFromOtherOfSameType(transform: Mat33, other: AbstractRenderer): void;
|
32
|
+
toString(): string;
|
32
33
|
}
|
@@ -3,6 +3,7 @@ import { ToolbarLocalization } from './localization';
|
|
3
3
|
import { ActionButtonIcon } from './types';
|
4
4
|
import BaseWidget, { ToolbarWidgetTag } from './widgets/BaseWidget';
|
5
5
|
import { DispatcherEventListener } from '../EventDispatcher';
|
6
|
+
import { BaseTool } from '../lib';
|
6
7
|
export interface SpacerOptions {
|
7
8
|
grow: number;
|
8
9
|
minSize: string;
|
@@ -131,7 +132,7 @@ export default abstract class AbstractToolbar {
|
|
131
132
|
/**
|
132
133
|
* Adds an "Exit" button that, when clicked, calls `exitCallback`.
|
133
134
|
*
|
134
|
-
* **Note**: This is roughly equivalent to
|
135
|
+
* **Note**: This is *roughly* equivalent to
|
135
136
|
* ```ts
|
136
137
|
* toolbar.addTaggedActionButton([ ToolbarWidgetTag.Exit ], {
|
137
138
|
* label: this.editor.localization.exit,
|
@@ -154,9 +155,24 @@ export default abstract class AbstractToolbar {
|
|
154
155
|
*/
|
155
156
|
addUndoRedoButtons(undoFirst?: boolean): void;
|
156
157
|
/**
|
157
|
-
* Adds
|
158
|
+
* Adds widgets for pen/eraser/selection/text/pan-zoom primary tools.
|
159
|
+
*
|
160
|
+
* If `filter` returns `false` for a tool, no widget is added for that tool.
|
161
|
+
* See {@link addDefaultToolWidgets}
|
162
|
+
*/
|
163
|
+
addWidgetsForPrimaryTools(filter?: (tool: BaseTool) => boolean): void;
|
164
|
+
/**
|
165
|
+
* Adds toolbar widgets based on the enabled tools, and additional tool-like
|
166
|
+
* buttons (e.g. {@link DocumentPropertiesWidget} and {@link InsertImageWidget}).
|
158
167
|
*/
|
159
168
|
addDefaultToolWidgets(): void;
|
169
|
+
/**
|
170
|
+
* Adds widgets that don't correspond to tools, but do allow the user to control
|
171
|
+
* the editor in some way.
|
172
|
+
*
|
173
|
+
* By default, this includes {@link DocumentPropertiesWidget} and {@link InsertImageWidget}.
|
174
|
+
*/
|
175
|
+
addDefaultEditorControlWidgets(): void;
|
160
176
|
addDefaultActionButtons(): void;
|
161
177
|
/**
|
162
178
|
* Adds both the default tool widgets and action buttons.
|
@@ -30,6 +30,7 @@ import DocumentPropertiesWidget from './widgets/DocumentPropertiesWidget.mjs';
|
|
30
30
|
import { Color4 } from '@js-draw/math';
|
31
31
|
import { toolbarCSSPrefix } from './constants.mjs';
|
32
32
|
import SaveActionWidget from './widgets/SaveActionWidget.mjs';
|
33
|
+
import ExitActionWidget from './widgets/ExitActionWidget.mjs';
|
33
34
|
class AbstractToolbar {
|
34
35
|
/** @internal */
|
35
36
|
constructor(editor, localizationTable = defaultToolbarLocalization) {
|
@@ -292,14 +293,13 @@ class AbstractToolbar {
|
|
292
293
|
*/
|
293
294
|
addSaveButton(saveCallback, labelOverride = {}) {
|
294
295
|
const widget = new SaveActionWidget(this.editor, this.localizationTable, saveCallback, labelOverride);
|
295
|
-
widget.setTags([ToolbarWidgetTag.Save]);
|
296
296
|
this.addWidget(widget);
|
297
297
|
return widget;
|
298
298
|
}
|
299
299
|
/**
|
300
300
|
* Adds an "Exit" button that, when clicked, calls `exitCallback`.
|
301
301
|
*
|
302
|
-
* **Note**: This is roughly equivalent to
|
302
|
+
* **Note**: This is *roughly* equivalent to
|
303
303
|
* ```ts
|
304
304
|
* toolbar.addTaggedActionButton([ ToolbarWidgetTag.Exit ], {
|
305
305
|
* label: this.editor.localization.exit,
|
@@ -316,15 +316,9 @@ class AbstractToolbar {
|
|
316
316
|
* @final
|
317
317
|
*/
|
318
318
|
addExitButton(exitCallback, labelOverride = {}) {
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
...labelOverride,
|
323
|
-
}, () => {
|
324
|
-
exitCallback();
|
325
|
-
}, {
|
326
|
-
autoDisableInReadOnlyEditors: false,
|
327
|
-
});
|
319
|
+
const widget = new ExitActionWidget(this.editor, this.localizationTable, exitCallback, labelOverride);
|
320
|
+
this.addWidget(widget);
|
321
|
+
return widget;
|
328
322
|
}
|
329
323
|
/**
|
330
324
|
* Adds undo and redo buttons that trigger the editor's built-in undo and redo
|
@@ -372,27 +366,49 @@ class AbstractToolbar {
|
|
372
366
|
});
|
373
367
|
}
|
374
368
|
/**
|
375
|
-
* Adds
|
369
|
+
* Adds widgets for pen/eraser/selection/text/pan-zoom primary tools.
|
370
|
+
*
|
371
|
+
* If `filter` returns `false` for a tool, no widget is added for that tool.
|
372
|
+
* See {@link addDefaultToolWidgets}
|
376
373
|
*/
|
377
|
-
|
378
|
-
const
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
374
|
+
addWidgetsForPrimaryTools(filter) {
|
375
|
+
for (const tool of this.editor.toolController.getPrimaryTools()) {
|
376
|
+
if (filter && !filter?.(tool)) {
|
377
|
+
continue;
|
378
|
+
}
|
379
|
+
if (tool instanceof PenTool) {
|
380
|
+
const widget = new PenToolWidget(this.editor, tool, this.localizationTable);
|
381
|
+
this.addWidget(widget);
|
382
|
+
}
|
383
|
+
else if (tool instanceof EraserTool) {
|
384
|
+
this.addWidget(new EraserWidget(this.editor, tool, this.localizationTable));
|
385
|
+
}
|
386
|
+
else if (tool instanceof SelectionTool) {
|
387
|
+
this.addWidget(new SelectionToolWidget(this.editor, tool, this.localizationTable));
|
388
|
+
}
|
389
|
+
else if (tool instanceof TextTool) {
|
390
|
+
this.addWidget(new TextToolWidget(this.editor, tool, this.localizationTable));
|
391
|
+
}
|
392
|
+
else if (tool instanceof PanZoomTool) {
|
393
|
+
this.addWidget(new HandToolWidget(this.editor, tool, this.localizationTable));
|
394
|
+
}
|
395
395
|
}
|
396
|
+
}
|
397
|
+
/**
|
398
|
+
* Adds toolbar widgets based on the enabled tools, and additional tool-like
|
399
|
+
* buttons (e.g. {@link DocumentPropertiesWidget} and {@link InsertImageWidget}).
|
400
|
+
*/
|
401
|
+
addDefaultToolWidgets() {
|
402
|
+
this.addWidgetsForPrimaryTools();
|
403
|
+
this.addDefaultEditorControlWidgets();
|
404
|
+
}
|
405
|
+
/**
|
406
|
+
* Adds widgets that don't correspond to tools, but do allow the user to control
|
407
|
+
* the editor in some way.
|
408
|
+
*
|
409
|
+
* By default, this includes {@link DocumentPropertiesWidget} and {@link InsertImageWidget}.
|
410
|
+
*/
|
411
|
+
addDefaultEditorControlWidgets() {
|
396
412
|
this.addWidget(new DocumentPropertiesWidget(this.editor, this.localizationTable));
|
397
413
|
this.addWidget(new InsertImageWidget(this.editor, this.localizationTable));
|
398
414
|
}
|
@@ -47,7 +47,7 @@ class BaseWidget {
|
|
47
47
|
this.layoutManager = defaultLayoutManager;
|
48
48
|
this.icon = null;
|
49
49
|
this.container = document.createElement('div');
|
50
|
-
this.container.classList.add(`${toolbarCSSPrefix}toolContainer`, `${toolbarCSSPrefix}toolButtonContainer`);
|
50
|
+
this.container.classList.add(`${toolbarCSSPrefix}toolContainer`, `${toolbarCSSPrefix}toolButtonContainer`, `${toolbarCSSPrefix}internalWidgetId--${id.replace(/[^a-zA-Z0-9_]/g, '-')}`);
|
51
51
|
this.dropdownContent = document.createElement('div');
|
52
52
|
__classPrivateFieldSet(this, _BaseWidget_hasDropdown, false, "f");
|
53
53
|
this.button = document.createElement('div');
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { KeyPressEvent } from '../../inputEvents';
|
2
|
+
import Editor from '../../Editor';
|
3
|
+
import { ToolbarLocalization } from '../localization';
|
4
|
+
import ActionButtonWidget from './ActionButtonWidget';
|
5
|
+
import { ActionButtonIcon } from '../types';
|
6
|
+
declare class ExitActionWidget extends ActionButtonWidget {
|
7
|
+
constructor(editor: Editor, localization: ToolbarLocalization, saveCallback: () => void, labelOverride?: Partial<ActionButtonIcon>);
|
8
|
+
protected shouldAutoDisableInReadOnlyEditor(): boolean;
|
9
|
+
protected onKeyPress(event: KeyPressEvent): boolean;
|
10
|
+
mustBeInToplevelMenu(): boolean;
|
11
|
+
}
|
12
|
+
export default ExitActionWidget;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import ActionButtonWidget from './ActionButtonWidget.mjs';
|
2
|
+
import { ToolbarWidgetTag } from './BaseWidget.mjs';
|
3
|
+
import { exitKeyboardShortcut } from './keybindings.mjs';
|
4
|
+
class ExitActionWidget extends ActionButtonWidget {
|
5
|
+
constructor(editor, localization, saveCallback, labelOverride = {}) {
|
6
|
+
super(editor, 'exit-button',
|
7
|
+
// Creates an icon
|
8
|
+
() => {
|
9
|
+
return labelOverride.icon ?? editor.icons.makeCloseIcon();
|
10
|
+
}, labelOverride.label ?? localization.exit, saveCallback);
|
11
|
+
this.setTags([ToolbarWidgetTag.Exit]);
|
12
|
+
}
|
13
|
+
shouldAutoDisableInReadOnlyEditor() {
|
14
|
+
return false;
|
15
|
+
}
|
16
|
+
onKeyPress(event) {
|
17
|
+
if (this.editor.shortcuts.matchesShortcut(exitKeyboardShortcut, event)) {
|
18
|
+
this.clickAction();
|
19
|
+
return true;
|
20
|
+
}
|
21
|
+
return super.onKeyPress(event);
|
22
|
+
}
|
23
|
+
mustBeInToplevelMenu() {
|
24
|
+
return true;
|
25
|
+
}
|
26
|
+
}
|
27
|
+
export default ExitActionWidget;
|
@@ -4,11 +4,12 @@ import { ToolbarLocalization } from '../localization';
|
|
4
4
|
import BaseToolWidget from './BaseToolWidget';
|
5
5
|
import { SavedToolbuttonState } from './BaseWidget';
|
6
6
|
export default class HandToolWidget extends BaseToolWidget {
|
7
|
-
protected overridePanZoomTool: PanZoom;
|
8
7
|
private allowTogglingBaseTool;
|
9
|
-
|
10
|
-
|
8
|
+
protected overridePanZoomTool: PanZoom;
|
9
|
+
constructor(editor: Editor, tool: PanZoom, localizationTable: ToolbarLocalization);
|
11
10
|
private static getPrimaryHandTool;
|
11
|
+
private static getOverrideHandTool;
|
12
|
+
protected shouldAutoDisableInReadOnlyEditor(): boolean;
|
12
13
|
protected getTitle(): string;
|
13
14
|
protected createIcon(): Element;
|
14
15
|
protected handleClick(): void;
|
@@ -96,34 +96,45 @@ class HandModeWidget extends BaseWidget {
|
|
96
96
|
}
|
97
97
|
export default class HandToolWidget extends BaseToolWidget {
|
98
98
|
constructor(editor,
|
99
|
-
//
|
100
|
-
//
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
99
|
+
// Can either be the primary pan/zoom tool (in the primary tools list) or
|
100
|
+
// the override pan/zoom tool.
|
101
|
+
// If the override pan/zoom tool, the primary will be gotten from the editor's
|
102
|
+
// tool controller.
|
103
|
+
// If the primary, the override will be gotten from the editor's tool controller.
|
104
|
+
tool, localizationTable) {
|
105
|
+
const isGivenToolPrimary = editor.toolController.getPrimaryTools().includes(tool);
|
106
|
+
const primaryTool = (isGivenToolPrimary ? tool : HandToolWidget.getPrimaryHandTool(editor.toolController))
|
107
|
+
?? tool;
|
108
|
+
super(editor, primaryTool, 'hand-tool-widget', localizationTable);
|
109
|
+
this.overridePanZoomTool =
|
110
|
+
(isGivenToolPrimary ? HandToolWidget.getOverrideHandTool(editor.toolController) : tool)
|
111
|
+
?? tool;
|
106
112
|
// Only allow toggling a hand tool if we're using the primary hand tool and not the override
|
107
113
|
// hand tool for this button.
|
108
|
-
this.allowTogglingBaseTool =
|
114
|
+
this.allowTogglingBaseTool = primaryTool !== null;
|
109
115
|
// Allow showing/hiding the dropdown, even if `overridePanZoomTool` isn't enabled.
|
110
116
|
if (!this.allowTogglingBaseTool) {
|
111
117
|
this.container.classList.add('dropdownShowable');
|
112
118
|
}
|
113
119
|
// Controls for the overriding hand tool.
|
114
|
-
const touchPanningWidget = new HandModeWidget(editor, overridePanZoomTool, PanZoomMode.OneFingerTouchGestures, () => this.editor.icons.makeTouchPanningIcon(), localizationTable.touchPanning, localizationTable);
|
115
|
-
const rotationLockWidget = new HandModeWidget(editor, overridePanZoomTool, PanZoomMode.RotationLocked, () => this.editor.icons.makeRotationLockIcon(), localizationTable.lockRotation, localizationTable);
|
120
|
+
const touchPanningWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoomMode.OneFingerTouchGestures, () => this.editor.icons.makeTouchPanningIcon(), localizationTable.touchPanning, localizationTable);
|
121
|
+
const rotationLockWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoomMode.RotationLocked, () => this.editor.icons.makeRotationLockIcon(), localizationTable.lockRotation, localizationTable);
|
116
122
|
this.addSubWidget(touchPanningWidget);
|
117
123
|
this.addSubWidget(rotationLockWidget);
|
118
124
|
}
|
119
|
-
shouldAutoDisableInReadOnlyEditor() {
|
120
|
-
return false;
|
121
|
-
}
|
122
125
|
static getPrimaryHandTool(toolController) {
|
123
126
|
const primaryPanZoomToolList = toolController.getPrimaryTools().filter(tool => tool instanceof PanZoom);
|
124
127
|
const primaryPanZoomTool = primaryPanZoomToolList[0];
|
125
128
|
return primaryPanZoomTool;
|
126
129
|
}
|
130
|
+
static getOverrideHandTool(toolController) {
|
131
|
+
const panZoomToolList = toolController.getMatchingTools(PanZoom);
|
132
|
+
const panZoomTool = panZoomToolList[0];
|
133
|
+
return panZoomTool;
|
134
|
+
}
|
135
|
+
shouldAutoDisableInReadOnlyEditor() {
|
136
|
+
return false;
|
137
|
+
}
|
127
138
|
getTitle() {
|
128
139
|
return this.localizationTable.handTool;
|
129
140
|
}
|