js-draw 0.4.1 → 0.5.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/CHANGELOG.md +8 -0
- package/dist/bundle.js +1 -1
- package/dist/src/Editor.d.ts +1 -1
- package/dist/src/Editor.js +5 -2
- package/dist/src/components/builders/FreehandLineBuilder.js +1 -1
- package/dist/src/rendering/renderers/SVGRenderer.js +1 -1
- package/dist/src/toolbar/widgets/BaseWidget.d.ts +2 -0
- package/dist/src/toolbar/widgets/BaseWidget.js +15 -0
- package/dist/src/toolbar/widgets/PenToolWidget.d.ts +2 -0
- package/dist/src/toolbar/widgets/PenToolWidget.js +14 -0
- package/dist/src/tools/ToolController.js +2 -0
- package/dist/src/tools/ToolbarShortcutHandler.d.ts +12 -0
- package/dist/src/tools/ToolbarShortcutHandler.js +23 -0
- package/dist/src/tools/lib.d.ts +1 -0
- package/dist/src/tools/lib.js +1 -0
- package/dist/src/types.d.ts +4 -2
- package/package.json +1 -1
- package/src/Editor.ts +6 -2
- package/src/components/builders/FreehandLineBuilder.ts +1 -1
- package/src/rendering/renderers/SVGRenderer.ts +1 -1
- package/src/toolbar/widgets/BaseWidget.ts +19 -1
- package/src/toolbar/widgets/PenToolWidget.ts +18 -1
- package/src/tools/SelectionTool/SelectionTool.css +1 -1
- package/src/tools/ToolController.ts +2 -0
- package/src/tools/ToolbarShortcutHandler.ts +34 -0
- package/src/tools/UndoRedoShortcut.test.ts +3 -0
- package/src/tools/lib.ts +1 -0
- package/src/types.ts +13 -8
package/dist/src/Editor.d.ts
CHANGED
@@ -193,7 +193,7 @@ export declare class Editor {
|
|
193
193
|
remove: () => void;
|
194
194
|
};
|
195
195
|
addStyleSheet(content: string): HTMLStyleElement;
|
196
|
-
sendKeyboardEvent(eventType: InputEvtType.KeyPressEvent | InputEvtType.KeyUpEvent, key: string, ctrlKey?: boolean): void;
|
196
|
+
sendKeyboardEvent(eventType: InputEvtType.KeyPressEvent | InputEvtType.KeyUpEvent, key: string, ctrlKey?: boolean, altKey?: boolean): void;
|
197
197
|
sendPenEvent(eventType: InputEvtType.PointerDownEvt | InputEvtType.PointerMoveEvt | InputEvtType.PointerUpEvt, point: Point2, allPointers?: Pointer[]): void;
|
198
198
|
toSVG(): SVGElement;
|
199
199
|
loadFrom(loader: ImageLoader): Promise<void>;
|
package/dist/src/Editor.js
CHANGED
@@ -441,6 +441,7 @@ export class Editor {
|
|
441
441
|
kind: InputEvtType.KeyPressEvent,
|
442
442
|
key: evt.key,
|
443
443
|
ctrlKey: evt.ctrlKey,
|
444
|
+
altKey: evt.altKey,
|
444
445
|
})) {
|
445
446
|
evt.preventDefault();
|
446
447
|
}
|
@@ -453,6 +454,7 @@ export class Editor {
|
|
453
454
|
kind: InputEvtType.KeyUpEvent,
|
454
455
|
key: evt.key,
|
455
456
|
ctrlKey: evt.ctrlKey,
|
457
|
+
altKey: evt.altKey,
|
456
458
|
})) {
|
457
459
|
evt.preventDefault();
|
458
460
|
}
|
@@ -598,11 +600,12 @@ export class Editor {
|
|
598
600
|
}
|
599
601
|
// Dispatch a keyboard event to the currently selected tool.
|
600
602
|
// Intended for unit testing
|
601
|
-
sendKeyboardEvent(eventType, key, ctrlKey = false) {
|
603
|
+
sendKeyboardEvent(eventType, key, ctrlKey = false, altKey = false) {
|
602
604
|
this.toolController.dispatchInputEvent({
|
603
605
|
kind: eventType,
|
604
606
|
key,
|
605
|
-
ctrlKey
|
607
|
+
ctrlKey,
|
608
|
+
altKey,
|
606
609
|
});
|
607
610
|
}
|
608
611
|
// Dispatch a pen event to the currently selected tool.
|
@@ -320,7 +320,7 @@ export default class FreehandLineBuilder {
|
|
320
320
|
}
|
321
321
|
let exitingVec = this.computeExitingVec();
|
322
322
|
// Find the intersection between the entering vector and the exiting vector
|
323
|
-
const maxRelativeLength =
|
323
|
+
const maxRelativeLength = 2;
|
324
324
|
const segmentStart = this.buffer[0];
|
325
325
|
const segmentEnd = newPoint.pos;
|
326
326
|
const startEndDist = segmentEnd.minus(segmentStart).magnitude();
|
@@ -72,7 +72,7 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
72
72
|
drawPath(pathSpec) {
|
73
73
|
var _a;
|
74
74
|
const style = pathSpec.style;
|
75
|
-
const path = Path.fromRenderable(pathSpec);
|
75
|
+
const path = Path.fromRenderable(pathSpec).transformedBy(this.getCanvasToScreenTransform());
|
76
76
|
// Try to extend the previous path, if possible
|
77
77
|
if (!style.fill.eq((_a = this.lastPathStyle) === null || _a === void 0 ? void 0 : _a.fill) || this.lastPathString.length === 0) {
|
78
78
|
this.addPathToSVG();
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import Editor from '../../Editor';
|
2
|
+
import { KeyPressEvent } from '../../types';
|
2
3
|
import { ToolbarLocalization } from '../localization';
|
3
4
|
export default abstract class BaseWidget {
|
4
5
|
#private;
|
@@ -18,6 +19,7 @@ export default abstract class BaseWidget {
|
|
18
19
|
protected abstract createIcon(): Element;
|
19
20
|
protected fillDropdown(dropdown: HTMLElement): boolean;
|
20
21
|
protected setupActionBtnClickListener(button: HTMLElement): void;
|
22
|
+
protected onKeyPress(_event: KeyPressEvent): boolean;
|
21
23
|
protected abstract handleClick(): void;
|
22
24
|
protected get hasDropdown(): boolean;
|
23
25
|
protected addSubWidget(widget: BaseWidget): void;
|
@@ -10,6 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
11
11
|
};
|
12
12
|
var _BaseWidget_hasDropdown;
|
13
|
+
import ToolbarShortcutHandler from '../../tools/ToolbarShortcutHandler';
|
13
14
|
import { EditorEventType, InputEvtType } from '../../types';
|
14
15
|
import { toolbarCSSPrefix } from '../HTMLToolbar';
|
15
16
|
import { makeDropdownIcon } from '../icons';
|
@@ -33,6 +34,12 @@ export default class BaseWidget {
|
|
33
34
|
this.label = document.createElement('label');
|
34
35
|
this.button.setAttribute('role', 'button');
|
35
36
|
this.button.tabIndex = 0;
|
37
|
+
const toolbarShortcutHandlers = this.editor.toolController.getMatchingTools(ToolbarShortcutHandler);
|
38
|
+
// If the onKeyPress function has been extended and the editor is configured to send keypress events to
|
39
|
+
// toolbar widgets,
|
40
|
+
if (toolbarShortcutHandlers.length > 0 && this.onKeyPress !== BaseWidget.prototype.onKeyPress) {
|
41
|
+
toolbarShortcutHandlers[0].registerListener(event => this.onKeyPress(event));
|
42
|
+
}
|
36
43
|
}
|
37
44
|
// Add content to the widget's associated dropdown menu.
|
38
45
|
// Returns true if such a menu should be created, false otherwise.
|
@@ -62,6 +69,7 @@ export default class BaseWidget {
|
|
62
69
|
kind: InputEvtType.KeyPressEvent,
|
63
70
|
key: evt.key,
|
64
71
|
ctrlKey: evt.ctrlKey,
|
72
|
+
altKey: evt.altKey,
|
65
73
|
});
|
66
74
|
}
|
67
75
|
};
|
@@ -73,6 +81,7 @@ export default class BaseWidget {
|
|
73
81
|
kind: InputEvtType.KeyUpEvent,
|
74
82
|
key: evt.key,
|
75
83
|
ctrlKey: evt.ctrlKey,
|
84
|
+
altKey: evt.altKey,
|
76
85
|
});
|
77
86
|
};
|
78
87
|
button.onclick = () => {
|
@@ -81,6 +90,12 @@ export default class BaseWidget {
|
|
81
90
|
}
|
82
91
|
};
|
83
92
|
}
|
93
|
+
// Add a listener that is triggered when a key is pressed.
|
94
|
+
// Listeners will fire regardless of whether this widget is selected and require that
|
95
|
+
// {@link lib!Editor.toolController} to have an enabled {@link lib!ToolbarShortcutHandler} tool.
|
96
|
+
onKeyPress(_event) {
|
97
|
+
return false;
|
98
|
+
}
|
84
99
|
get hasDropdown() {
|
85
100
|
return __classPrivateFieldGet(this, _BaseWidget_hasDropdown, "f");
|
86
101
|
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { ComponentBuilderFactory } from '../../components/builders/types';
|
2
2
|
import Editor from '../../Editor';
|
3
3
|
import Pen from '../../tools/Pen';
|
4
|
+
import { KeyPressEvent } from '../../types';
|
4
5
|
import { ToolbarLocalization } from '../localization';
|
5
6
|
import BaseToolWidget from './BaseToolWidget';
|
6
7
|
export interface PenTypeRecord {
|
@@ -16,4 +17,5 @@ export default class PenToolWidget extends BaseToolWidget {
|
|
16
17
|
protected createIcon(): Element;
|
17
18
|
private static idCounter;
|
18
19
|
protected fillDropdown(dropdown: HTMLElement): boolean;
|
20
|
+
protected onKeyPress(event: KeyPressEvent): boolean;
|
19
21
|
}
|
@@ -127,5 +127,19 @@ export default class PenToolWidget extends BaseToolWidget {
|
|
127
127
|
dropdown.replaceChildren(container);
|
128
128
|
return true;
|
129
129
|
}
|
130
|
+
onKeyPress(event) {
|
131
|
+
if (!this.isSelected()) {
|
132
|
+
return false;
|
133
|
+
}
|
134
|
+
// Map alt+0-9 to different pen types.
|
135
|
+
if (/^[0-9]$/.exec(event.key) && event.ctrlKey) {
|
136
|
+
const penTypeIdx = parseInt(event.key) - 1;
|
137
|
+
if (penTypeIdx >= 0 && penTypeIdx < this.penTypes.length) {
|
138
|
+
this.tool.setStrokeFactory(this.penTypes[penTypeIdx].factory);
|
139
|
+
return true;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
return false;
|
143
|
+
}
|
130
144
|
}
|
131
145
|
PenToolWidget.idCounter = 0;
|
@@ -10,6 +10,7 @@ import TextTool from './TextTool';
|
|
10
10
|
import PipetteTool from './PipetteTool';
|
11
11
|
import ToolSwitcherShortcut from './ToolSwitcherShortcut';
|
12
12
|
import PasteHandler from './PasteHandler';
|
13
|
+
import ToolbarShortcutHandler from './ToolbarShortcutHandler';
|
13
14
|
export default class ToolController {
|
14
15
|
/** @internal */
|
15
16
|
constructor(editor, localization) {
|
@@ -35,6 +36,7 @@ export default class ToolController {
|
|
35
36
|
...primaryTools,
|
36
37
|
keyboardPanZoomTool,
|
37
38
|
new UndoRedoShortcut(editor),
|
39
|
+
new ToolbarShortcutHandler(editor),
|
38
40
|
new ToolSwitcherShortcut(editor),
|
39
41
|
new PasteHandler(editor),
|
40
42
|
];
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import Editor from '../Editor';
|
2
|
+
import { KeyPressEvent } from '../types';
|
3
|
+
import BaseTool from './BaseTool';
|
4
|
+
declare type KeyPressListener = (event: KeyPressEvent) => boolean;
|
5
|
+
export default class ToolbarShortcutHandler extends BaseTool {
|
6
|
+
private listeners;
|
7
|
+
constructor(editor: Editor);
|
8
|
+
registerListener(listener: KeyPressListener): void;
|
9
|
+
removeListener(listener: KeyPressListener): void;
|
10
|
+
onKeyPress(event: KeyPressEvent): boolean;
|
11
|
+
}
|
12
|
+
export {};
|
@@ -0,0 +1,23 @@
|
|
1
|
+
// Allows the toolbar to register keyboard events.
|
2
|
+
// @packageDocumentation
|
3
|
+
import BaseTool from './BaseTool';
|
4
|
+
export default class ToolbarShortcutHandler extends BaseTool {
|
5
|
+
constructor(editor) {
|
6
|
+
super(editor.notifier, editor.localization.changeTool);
|
7
|
+
this.listeners = new Set([]);
|
8
|
+
}
|
9
|
+
registerListener(listener) {
|
10
|
+
this.listeners.add(listener);
|
11
|
+
}
|
12
|
+
removeListener(listener) {
|
13
|
+
this.listeners.delete(listener);
|
14
|
+
}
|
15
|
+
onKeyPress(event) {
|
16
|
+
for (const listener of this.listeners) {
|
17
|
+
if (listener(event)) {
|
18
|
+
return true;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
return false;
|
22
|
+
}
|
23
|
+
}
|
package/dist/src/tools/lib.d.ts
CHANGED
@@ -12,3 +12,4 @@ export { default as TextTool } from './TextTool';
|
|
12
12
|
export { default as SelectionTool } from './SelectionTool/SelectionTool';
|
13
13
|
export { default as EraserTool } from './Eraser';
|
14
14
|
export { default as PasteHandler } from './PasteHandler';
|
15
|
+
export { default as ToolbarShortcutHandler } from './ToolbarShortcutHandler';
|
package/dist/src/tools/lib.js
CHANGED
@@ -12,3 +12,4 @@ export { default as TextTool } from './TextTool';
|
|
12
12
|
export { default as SelectionTool } from './SelectionTool/SelectionTool';
|
13
13
|
export { default as EraserTool } from './Eraser';
|
14
14
|
export { default as PasteHandler } from './PasteHandler';
|
15
|
+
export { default as ToolbarShortcutHandler } from './ToolbarShortcutHandler';
|
package/dist/src/types.d.ts
CHANGED
@@ -34,12 +34,14 @@ export interface WheelEvt {
|
|
34
34
|
export interface KeyPressEvent {
|
35
35
|
readonly kind: InputEvtType.KeyPressEvent;
|
36
36
|
readonly key: string;
|
37
|
-
readonly ctrlKey: boolean;
|
37
|
+
readonly ctrlKey: boolean | undefined;
|
38
|
+
readonly altKey: boolean | undefined;
|
38
39
|
}
|
39
40
|
export interface KeyUpEvent {
|
40
41
|
readonly kind: InputEvtType.KeyUpEvent;
|
41
42
|
readonly key: string;
|
42
|
-
readonly ctrlKey: boolean;
|
43
|
+
readonly ctrlKey: boolean | undefined;
|
44
|
+
readonly altKey: boolean | undefined;
|
43
45
|
}
|
44
46
|
export interface CopyEvent {
|
45
47
|
readonly kind: InputEvtType.CopyEvent;
|
package/package.json
CHANGED
package/src/Editor.ts
CHANGED
@@ -586,6 +586,7 @@ export class Editor {
|
|
586
586
|
kind: InputEvtType.KeyPressEvent,
|
587
587
|
key: evt.key,
|
588
588
|
ctrlKey: evt.ctrlKey,
|
589
|
+
altKey: evt.altKey,
|
589
590
|
})) {
|
590
591
|
evt.preventDefault();
|
591
592
|
} else if (evt.key === 'Escape') {
|
@@ -598,6 +599,7 @@ export class Editor {
|
|
598
599
|
kind: InputEvtType.KeyUpEvent,
|
599
600
|
key: evt.key,
|
600
601
|
ctrlKey: evt.ctrlKey,
|
602
|
+
altKey: evt.altKey,
|
601
603
|
})) {
|
602
604
|
evt.preventDefault();
|
603
605
|
}
|
@@ -783,12 +785,14 @@ export class Editor {
|
|
783
785
|
public sendKeyboardEvent(
|
784
786
|
eventType: InputEvtType.KeyPressEvent|InputEvtType.KeyUpEvent,
|
785
787
|
key: string,
|
786
|
-
ctrlKey: boolean = false
|
788
|
+
ctrlKey: boolean = false,
|
789
|
+
altKey: boolean = false,
|
787
790
|
) {
|
788
791
|
this.toolController.dispatchInputEvent({
|
789
792
|
kind: eventType,
|
790
793
|
key,
|
791
|
-
ctrlKey
|
794
|
+
ctrlKey,
|
795
|
+
altKey,
|
792
796
|
});
|
793
797
|
}
|
794
798
|
|
@@ -426,7 +426,7 @@ export default class FreehandLineBuilder implements ComponentBuilder {
|
|
426
426
|
let exitingVec = this.computeExitingVec();
|
427
427
|
|
428
428
|
// Find the intersection between the entering vector and the exiting vector
|
429
|
-
const maxRelativeLength =
|
429
|
+
const maxRelativeLength = 2;
|
430
430
|
const segmentStart = this.buffer[0];
|
431
431
|
const segmentEnd = newPoint.pos;
|
432
432
|
const startEndDist = segmentEnd.minus(segmentStart).magnitude();
|
@@ -88,7 +88,7 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
88
88
|
|
89
89
|
public drawPath(pathSpec: RenderablePathSpec) {
|
90
90
|
const style = pathSpec.style;
|
91
|
-
const path = Path.fromRenderable(pathSpec);
|
91
|
+
const path = Path.fromRenderable(pathSpec).transformedBy(this.getCanvasToScreenTransform());
|
92
92
|
|
93
93
|
// Try to extend the previous path, if possible
|
94
94
|
if (!style.fill.eq(this.lastPathStyle?.fill) || this.lastPathString.length === 0) {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import Editor from '../../Editor';
|
2
|
-
import
|
2
|
+
import ToolbarShortcutHandler from '../../tools/ToolbarShortcutHandler';
|
3
|
+
import { EditorEventType, InputEvtType, KeyPressEvent } from '../../types';
|
3
4
|
import { toolbarCSSPrefix } from '../HTMLToolbar';
|
4
5
|
import { makeDropdownIcon } from '../icons';
|
5
6
|
import { ToolbarLocalization } from '../localization';
|
@@ -33,6 +34,14 @@ export default abstract class BaseWidget {
|
|
33
34
|
this.label = document.createElement('label');
|
34
35
|
this.button.setAttribute('role', 'button');
|
35
36
|
this.button.tabIndex = 0;
|
37
|
+
|
38
|
+
const toolbarShortcutHandlers = this.editor.toolController.getMatchingTools(ToolbarShortcutHandler);
|
39
|
+
|
40
|
+
// If the onKeyPress function has been extended and the editor is configured to send keypress events to
|
41
|
+
// toolbar widgets,
|
42
|
+
if (toolbarShortcutHandlers.length > 0 && this.onKeyPress !== BaseWidget.prototype.onKeyPress) {
|
43
|
+
toolbarShortcutHandlers[0].registerListener(event => this.onKeyPress(event));
|
44
|
+
}
|
36
45
|
}
|
37
46
|
|
38
47
|
protected abstract getTitle(): string;
|
@@ -70,6 +79,7 @@ export default abstract class BaseWidget {
|
|
70
79
|
kind: InputEvtType.KeyPressEvent,
|
71
80
|
key: evt.key,
|
72
81
|
ctrlKey: evt.ctrlKey,
|
82
|
+
altKey: evt.altKey,
|
73
83
|
});
|
74
84
|
}
|
75
85
|
};
|
@@ -83,6 +93,7 @@ export default abstract class BaseWidget {
|
|
83
93
|
kind: InputEvtType.KeyUpEvent,
|
84
94
|
key: evt.key,
|
85
95
|
ctrlKey: evt.ctrlKey,
|
96
|
+
altKey: evt.altKey,
|
86
97
|
});
|
87
98
|
};
|
88
99
|
|
@@ -93,6 +104,13 @@ export default abstract class BaseWidget {
|
|
93
104
|
};
|
94
105
|
}
|
95
106
|
|
107
|
+
// Add a listener that is triggered when a key is pressed.
|
108
|
+
// Listeners will fire regardless of whether this widget is selected and require that
|
109
|
+
// {@link lib!Editor.toolController} to have an enabled {@link lib!ToolbarShortcutHandler} tool.
|
110
|
+
protected onKeyPress(_event: KeyPressEvent): boolean {
|
111
|
+
return false;
|
112
|
+
}
|
113
|
+
|
96
114
|
protected abstract handleClick(): void;
|
97
115
|
|
98
116
|
protected get hasDropdown() {
|
@@ -5,7 +5,7 @@ import { makeFilledRectangleBuilder, makeOutlinedRectangleBuilder } from '../../
|
|
5
5
|
import { ComponentBuilderFactory } from '../../components/builders/types';
|
6
6
|
import Editor from '../../Editor';
|
7
7
|
import Pen from '../../tools/Pen';
|
8
|
-
import { EditorEventType } from '../../types';
|
8
|
+
import { EditorEventType, KeyPressEvent } from '../../types';
|
9
9
|
import { toolbarCSSPrefix } from '../HTMLToolbar';
|
10
10
|
import { makeIconFromFactory, makePenIcon } from '../icons';
|
11
11
|
import { ToolbarLocalization } from '../localization';
|
@@ -165,4 +165,21 @@ export default class PenToolWidget extends BaseToolWidget {
|
|
165
165
|
dropdown.replaceChildren(container);
|
166
166
|
return true;
|
167
167
|
}
|
168
|
+
|
169
|
+
protected onKeyPress(event: KeyPressEvent): boolean {
|
170
|
+
if (!this.isSelected()) {
|
171
|
+
return false;
|
172
|
+
}
|
173
|
+
|
174
|
+
// Map alt+0-9 to different pen types.
|
175
|
+
if (/^[0-9]$/.exec(event.key) && event.ctrlKey) {
|
176
|
+
const penTypeIdx = parseInt(event.key) - 1;
|
177
|
+
if (penTypeIdx >= 0 && penTypeIdx < this.penTypes.length) {
|
178
|
+
this.tool.setStrokeFactory(this.penTypes[penTypeIdx].factory);
|
179
|
+
return true;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
return false;
|
184
|
+
}
|
168
185
|
}
|
@@ -13,6 +13,7 @@ import TextTool from './TextTool';
|
|
13
13
|
import PipetteTool from './PipetteTool';
|
14
14
|
import ToolSwitcherShortcut from './ToolSwitcherShortcut';
|
15
15
|
import PasteHandler from './PasteHandler';
|
16
|
+
import ToolbarShortcutHandler from './ToolbarShortcutHandler';
|
16
17
|
|
17
18
|
export default class ToolController {
|
18
19
|
private tools: BaseTool[];
|
@@ -45,6 +46,7 @@ export default class ToolController {
|
|
45
46
|
...primaryTools,
|
46
47
|
keyboardPanZoomTool,
|
47
48
|
new UndoRedoShortcut(editor),
|
49
|
+
new ToolbarShortcutHandler(editor),
|
48
50
|
new ToolSwitcherShortcut(editor),
|
49
51
|
new PasteHandler(editor),
|
50
52
|
];
|
@@ -0,0 +1,34 @@
|
|
1
|
+
// Allows the toolbar to register keyboard events.
|
2
|
+
// @packageDocumentation
|
3
|
+
|
4
|
+
import Editor from '../Editor';
|
5
|
+
import { KeyPressEvent } from '../types';
|
6
|
+
import BaseTool from './BaseTool';
|
7
|
+
|
8
|
+
// Returns true if the event was handled, false otherwise.
|
9
|
+
type KeyPressListener = (event: KeyPressEvent)=>boolean;
|
10
|
+
|
11
|
+
export default class ToolbarShortcutHandler extends BaseTool {
|
12
|
+
private listeners: Set<KeyPressListener> = new Set([]);
|
13
|
+
public constructor(editor: Editor) {
|
14
|
+
super(editor.notifier, editor.localization.changeTool);
|
15
|
+
}
|
16
|
+
|
17
|
+
public registerListener(listener: KeyPressListener) {
|
18
|
+
this.listeners.add(listener);
|
19
|
+
}
|
20
|
+
|
21
|
+
public removeListener(listener: KeyPressListener) {
|
22
|
+
this.listeners.delete(listener);
|
23
|
+
}
|
24
|
+
|
25
|
+
public onKeyPress(event: KeyPressEvent): boolean {
|
26
|
+
for (const listener of this.listeners) {
|
27
|
+
if (listener(event)) {
|
28
|
+
return true;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
return false;
|
33
|
+
}
|
34
|
+
}
|
@@ -19,6 +19,7 @@ describe('UndoRedoShortcut', () => {
|
|
19
19
|
editor.toolController.dispatchInputEvent({
|
20
20
|
kind: InputEvtType.KeyPressEvent,
|
21
21
|
ctrlKey: true,
|
22
|
+
altKey: false,
|
22
23
|
key: 'z',
|
23
24
|
});
|
24
25
|
|
@@ -35,6 +36,7 @@ describe('UndoRedoShortcut', () => {
|
|
35
36
|
editor.toolController.dispatchInputEvent({
|
36
37
|
kind: InputEvtType.KeyPressEvent,
|
37
38
|
ctrlKey: true,
|
39
|
+
altKey: false,
|
38
40
|
key: 'z',
|
39
41
|
});
|
40
42
|
|
@@ -44,6 +46,7 @@ describe('UndoRedoShortcut', () => {
|
|
44
46
|
editor.toolController.dispatchInputEvent({
|
45
47
|
kind: InputEvtType.KeyPressEvent,
|
46
48
|
ctrlKey: true,
|
49
|
+
altKey: false,
|
47
50
|
key: 'Z',
|
48
51
|
});
|
49
52
|
|
package/src/tools/lib.ts
CHANGED
@@ -17,3 +17,4 @@ export { default as SelectionTool } from './SelectionTool/SelectionTool';
|
|
17
17
|
export { default as EraserTool } from './Eraser';
|
18
18
|
export { default as PasteHandler } from './PasteHandler';
|
19
19
|
|
20
|
+
export { default as ToolbarShortcutHandler } from './ToolbarShortcutHandler';
|
package/src/types.ts
CHANGED
@@ -52,14 +52,25 @@ export interface WheelEvt {
|
|
52
52
|
|
53
53
|
export interface KeyPressEvent {
|
54
54
|
readonly kind: InputEvtType.KeyPressEvent;
|
55
|
+
|
56
|
+
// key, as given by an HTML `KeyboardEvent`
|
55
57
|
readonly key: string;
|
56
|
-
|
58
|
+
|
59
|
+
// If `ctrlKey` is undefined, that is equivalent to `ctrlKey = false`.
|
60
|
+
readonly ctrlKey: boolean|undefined;
|
61
|
+
|
62
|
+
// If falsey, the `alt` key is not pressed.
|
63
|
+
readonly altKey: boolean|undefined;
|
57
64
|
}
|
58
65
|
|
59
66
|
export interface KeyUpEvent {
|
60
67
|
readonly kind: InputEvtType.KeyUpEvent;
|
61
68
|
readonly key: string;
|
62
|
-
|
69
|
+
|
70
|
+
// As in `KeyPressEvent, if `ctrlKey` is undefined, that is equivalent to
|
71
|
+
// `ctrlKey = false`.
|
72
|
+
readonly ctrlKey: boolean|undefined;
|
73
|
+
readonly altKey: boolean|undefined;
|
63
74
|
}
|
64
75
|
|
65
76
|
export interface CopyEvent {
|
@@ -101,12 +112,6 @@ export type InputEvt = KeyPressEvent | KeyUpEvent | WheelEvt | GestureCancelEvt
|
|
101
112
|
export type EditorNotifier = EventDispatcher<EditorEventType, EditorEventDataType>;
|
102
113
|
|
103
114
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
115
|
export enum EditorEventType {
|
111
116
|
ToolEnabled,
|
112
117
|
ToolDisabled,
|