js-draw 1.5.0 → 1.6.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/README.md +10 -1
- package/dist/Editor.css +2 -2
- package/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +8 -0
- package/dist/cjs/Editor.js +32 -9
- package/dist/cjs/SVGLoader.d.ts +6 -0
- package/dist/cjs/SVGLoader.js +100 -56
- package/dist/cjs/commands/Erase.d.ts +7 -1
- package/dist/cjs/commands/Erase.js +13 -4
- package/dist/cjs/commands/invertCommand.js +1 -1
- package/dist/cjs/components/Stroke.d.ts +1 -1
- package/dist/cjs/components/Stroke.js +1 -1
- package/dist/cjs/image/EditorImage.js +1 -1
- package/dist/cjs/toolbar/AbstractToolbar.d.ts +4 -1
- package/dist/cjs/toolbar/AbstractToolbar.js +7 -1
- package/dist/cjs/toolbar/widgets/BaseToolWidget.js +4 -13
- package/dist/cjs/toolbar/widgets/BaseToolWidget.test.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +5 -1
- package/dist/cjs/toolbar/widgets/BaseWidget.js +45 -28
- package/dist/cjs/toolbar/widgets/BaseWidget.test.d.ts +1 -0
- package/dist/cjs/tools/BaseTool.js +1 -0
- package/dist/cjs/tools/ToolController.d.ts +23 -0
- package/dist/cjs/tools/ToolController.js +65 -4
- package/dist/cjs/tools/ToolController.test.d.ts +1 -0
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +8 -0
- package/dist/mjs/Editor.mjs +32 -9
- package/dist/mjs/SVGLoader.d.ts +6 -0
- package/dist/mjs/SVGLoader.mjs +99 -55
- package/dist/mjs/commands/Erase.d.ts +7 -1
- package/dist/mjs/commands/Erase.mjs +13 -4
- package/dist/mjs/commands/invertCommand.mjs +1 -1
- package/dist/mjs/components/Stroke.d.ts +1 -1
- package/dist/mjs/components/Stroke.mjs +1 -1
- package/dist/mjs/image/EditorImage.mjs +1 -1
- package/dist/mjs/toolbar/AbstractToolbar.d.ts +4 -1
- package/dist/mjs/toolbar/AbstractToolbar.mjs +7 -1
- package/dist/mjs/toolbar/widgets/BaseToolWidget.mjs +4 -13
- package/dist/mjs/toolbar/widgets/BaseToolWidget.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +5 -1
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +45 -28
- package/dist/mjs/toolbar/widgets/BaseWidget.test.d.ts +1 -0
- package/dist/mjs/tools/BaseTool.mjs +1 -0
- package/dist/mjs/tools/ToolController.d.ts +23 -0
- package/dist/mjs/tools/ToolController.mjs +65 -4
- package/dist/mjs/tools/ToolController.test.d.ts +1 -0
- package/dist/mjs/version.mjs +1 -1
- package/docs/img/readme-images/logo.svg +1 -0
- package/package.json +3 -3
- package/src/Editor.scss +4 -2
@@ -58,7 +58,7 @@ class EditorImage {
|
|
58
58
|
this.settingExportRect = false;
|
59
59
|
this.root = new RootImageNode();
|
60
60
|
this.background = new RootImageNode();
|
61
|
-
this.componentsById =
|
61
|
+
this.componentsById = Object.create(null);
|
62
62
|
this.notifier = new EventDispatcher_1.default();
|
63
63
|
this.importExportViewport = new Viewport_1.default(() => {
|
64
64
|
this.onExportViewportChanged();
|
@@ -162,7 +162,10 @@ export default abstract class AbstractToolbar {
|
|
162
162
|
* Adds both the default tool widgets and action buttons.
|
163
163
|
*/
|
164
164
|
abstract addDefaults(): void;
|
165
|
-
/**
|
165
|
+
/**
|
166
|
+
* Remove this toolbar from its container and clean up listeners.
|
167
|
+
* This should only be called **once** for a given toolbar.
|
168
|
+
*/
|
166
169
|
remove(): void;
|
167
170
|
/**
|
168
171
|
* Removes `listener` when {@link remove} is called.
|
@@ -404,7 +404,10 @@ class AbstractToolbar {
|
|
404
404
|
addDefaultActionButtons() {
|
405
405
|
this.addUndoRedoButtons();
|
406
406
|
}
|
407
|
-
/**
|
407
|
+
/**
|
408
|
+
* Remove this toolbar from its container and clean up listeners.
|
409
|
+
* This should only be called **once** for a given toolbar.
|
410
|
+
*/
|
408
411
|
remove() {
|
409
412
|
this.closeColorPickerOverlay?.remove();
|
410
413
|
for (const listener of __classPrivateFieldGet(this, _AbstractToolbar_listeners, "f")) {
|
@@ -412,6 +415,9 @@ class AbstractToolbar {
|
|
412
415
|
}
|
413
416
|
__classPrivateFieldSet(this, _AbstractToolbar_listeners, [], "f");
|
414
417
|
this.onRemove();
|
418
|
+
for (const widget of __classPrivateFieldGet(this, _AbstractToolbar_widgetList, "f")) {
|
419
|
+
widget.remove();
|
420
|
+
}
|
415
421
|
}
|
416
422
|
/**
|
417
423
|
* Removes `listener` when {@link remove} is called.
|
@@ -3,7 +3,6 @@ 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
|
-
const types_1 = require("../../types");
|
7
6
|
const BaseWidget_1 = __importDefault(require("./BaseWidget"));
|
8
7
|
const constants_1 = require("../constants");
|
9
8
|
const isToolWidgetFocused = () => {
|
@@ -14,11 +13,8 @@ class BaseToolWidget extends BaseWidget_1.default {
|
|
14
13
|
constructor(editor, targetTool, id, localizationTable) {
|
15
14
|
super(editor, id, localizationTable);
|
16
15
|
this.targetTool = targetTool;
|
17
|
-
|
18
|
-
if (
|
19
|
-
throw new Error('Incorrect event type! (Expected ToolEnabled)');
|
20
|
-
}
|
21
|
-
if (toolEvt.tool === targetTool) {
|
16
|
+
this.targetTool.enabledValue().onUpdateAndNow(enabled => {
|
17
|
+
if (enabled) {
|
22
18
|
this.setSelected(true);
|
23
19
|
// Transfer focus to the current button, only if another toolbar button is
|
24
20
|
// focused.
|
@@ -28,12 +24,7 @@ class BaseToolWidget extends BaseWidget_1.default {
|
|
28
24
|
this.focus();
|
29
25
|
}
|
30
26
|
}
|
31
|
-
|
32
|
-
editor.notifier.on(types_1.EditorEventType.ToolDisabled, toolEvt => {
|
33
|
-
if (toolEvt.kind !== types_1.EditorEventType.ToolDisabled) {
|
34
|
-
throw new Error('Incorrect event type! (Expected ToolDisabled)');
|
35
|
-
}
|
36
|
-
if (toolEvt.tool === targetTool) {
|
27
|
+
else {
|
37
28
|
this.setSelected(false);
|
38
29
|
this.setDropdownVisible(false);
|
39
30
|
}
|
@@ -57,7 +48,7 @@ class BaseToolWidget extends BaseWidget_1.default {
|
|
57
48
|
}
|
58
49
|
}
|
59
50
|
onKeyPress(event) {
|
60
|
-
if (this.isSelected() && event.
|
51
|
+
if (this.isSelected() && event.code === 'Space' && this.hasDropdown) {
|
61
52
|
this.handleClick();
|
62
53
|
return true;
|
63
54
|
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -81,13 +81,17 @@ export default abstract class BaseWidget {
|
|
81
81
|
* @internal
|
82
82
|
*/
|
83
83
|
addTo(parent: HTMLElement): HTMLElement;
|
84
|
+
/**
|
85
|
+
* Remove this. This allows the widget to be added to a toolbar again
|
86
|
+
* in the future using {@link addTo}.
|
87
|
+
*/
|
88
|
+
remove(): void;
|
84
89
|
focus(): void;
|
85
90
|
/**
|
86
91
|
* @internal
|
87
92
|
*/
|
88
93
|
addCSSClassToContainer(className: string): void;
|
89
94
|
removeCSSClassFromContainer(className: string): void;
|
90
|
-
remove(): void;
|
91
95
|
protected updateIcon(): void;
|
92
96
|
setDisabled(disabled: boolean): void;
|
93
97
|
setSelected(selected: boolean): void;
|
@@ -13,7 +13,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
13
13
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
14
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
15
15
|
};
|
16
|
-
var _BaseWidget_hasDropdown, _BaseWidget_disabledDueToReadOnlyEditor, _BaseWidget_tags,
|
16
|
+
var _BaseWidget_instances, _BaseWidget_hasDropdown, _BaseWidget_disabledDueToReadOnlyEditor, _BaseWidget_tags, _BaseWidget_removeEditorListeners, _BaseWidget_addEditorListeners;
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
18
18
|
exports.ToolbarWidgetTag = void 0;
|
19
19
|
const ToolbarShortcutHandler_1 = __importDefault(require("../../tools/ToolbarShortcutHandler"));
|
@@ -32,6 +32,7 @@ var ToolbarWidgetTag;
|
|
32
32
|
})(ToolbarWidgetTag || (exports.ToolbarWidgetTag = ToolbarWidgetTag = {}));
|
33
33
|
class BaseWidget {
|
34
34
|
constructor(editor, id, localizationTable) {
|
35
|
+
_BaseWidget_instances.add(this);
|
35
36
|
this.editor = editor;
|
36
37
|
this.id = id;
|
37
38
|
this.dropdown = null;
|
@@ -44,8 +45,7 @@ class BaseWidget {
|
|
44
45
|
// Maps subWidget IDs to subWidgets.
|
45
46
|
this.subWidgets = {};
|
46
47
|
this.toplevel = true;
|
47
|
-
|
48
|
-
_BaseWidget_readOnlyListener.set(this, null);
|
48
|
+
_BaseWidget_removeEditorListeners.set(this, null);
|
49
49
|
this.localizationTable = localizationTable ?? editor.localization;
|
50
50
|
// Default layout manager
|
51
51
|
const defaultLayoutManager = new DropdownLayoutManager_1.default((text) => this.editor.announceForAccessibility(text), this.localizationTable);
|
@@ -66,12 +66,6 @@ class BaseWidget {
|
|
66
66
|
this.button.oncontextmenu = event => {
|
67
67
|
event.preventDefault();
|
68
68
|
};
|
69
|
-
const toolbarShortcutHandlers = this.editor.toolController.getMatchingTools(ToolbarShortcutHandler_1.default);
|
70
|
-
// If the onKeyPress function has been extended and the editor is configured to send keypress events to
|
71
|
-
// toolbar widgets,
|
72
|
-
if (toolbarShortcutHandlers.length > 0 && this.onKeyPress !== BaseWidget.prototype.onKeyPress) {
|
73
|
-
toolbarShortcutHandlers[0].registerListener(event => this.onKeyPress(event));
|
74
|
-
}
|
75
69
|
}
|
76
70
|
/**
|
77
71
|
* Should return a constant true or false value. If true (the default),
|
@@ -274,22 +268,18 @@ class BaseWidget {
|
|
274
268
|
if (this.container.parentElement) {
|
275
269
|
this.container.remove();
|
276
270
|
}
|
277
|
-
|
278
|
-
if (readOnly && this.shouldAutoDisableInReadOnlyEditor() && !this.disabled) {
|
279
|
-
this.setDisabled(true);
|
280
|
-
__classPrivateFieldSet(this, _BaseWidget_disabledDueToReadOnlyEditor, true, "f");
|
281
|
-
if (__classPrivateFieldGet(this, _BaseWidget_hasDropdown, "f")) {
|
282
|
-
this.dropdown?.requestHide();
|
283
|
-
}
|
284
|
-
}
|
285
|
-
else if (!readOnly && __classPrivateFieldGet(this, _BaseWidget_disabledDueToReadOnlyEditor, "f")) {
|
286
|
-
__classPrivateFieldSet(this, _BaseWidget_disabledDueToReadOnlyEditor, false, "f");
|
287
|
-
this.setDisabled(false);
|
288
|
-
}
|
289
|
-
}), "f");
|
271
|
+
__classPrivateFieldGet(this, _BaseWidget_instances, "m", _BaseWidget_addEditorListeners).call(this);
|
290
272
|
parent.appendChild(this.container);
|
291
273
|
return this.container;
|
292
274
|
}
|
275
|
+
/**
|
276
|
+
* Remove this. This allows the widget to be added to a toolbar again
|
277
|
+
* in the future using {@link addTo}.
|
278
|
+
*/
|
279
|
+
remove() {
|
280
|
+
this.container.remove();
|
281
|
+
__classPrivateFieldGet(this, _BaseWidget_removeEditorListeners, "f")?.call(this);
|
282
|
+
}
|
293
283
|
focus() {
|
294
284
|
this.button.focus();
|
295
285
|
}
|
@@ -302,11 +292,6 @@ class BaseWidget {
|
|
302
292
|
removeCSSClassFromContainer(className) {
|
303
293
|
this.container.classList.remove(className);
|
304
294
|
}
|
305
|
-
remove() {
|
306
|
-
this.container.remove();
|
307
|
-
__classPrivateFieldGet(this, _BaseWidget_readOnlyListener, "f")?.remove();
|
308
|
-
__classPrivateFieldSet(this, _BaseWidget_readOnlyListener, null, "f");
|
309
|
-
}
|
310
295
|
updateIcon() {
|
311
296
|
let newIcon = this.createIcon();
|
312
297
|
if (!newIcon) {
|
@@ -443,5 +428,37 @@ class BaseWidget {
|
|
443
428
|
}
|
444
429
|
}
|
445
430
|
}
|
446
|
-
_BaseWidget_hasDropdown = new WeakMap(), _BaseWidget_disabledDueToReadOnlyEditor = new WeakMap(), _BaseWidget_tags = new WeakMap(),
|
431
|
+
_BaseWidget_hasDropdown = new WeakMap(), _BaseWidget_disabledDueToReadOnlyEditor = new WeakMap(), _BaseWidget_tags = new WeakMap(), _BaseWidget_removeEditorListeners = new WeakMap(), _BaseWidget_instances = new WeakSet(), _BaseWidget_addEditorListeners = function _BaseWidget_addEditorListeners() {
|
432
|
+
__classPrivateFieldGet(this, _BaseWidget_removeEditorListeners, "f")?.call(this);
|
433
|
+
const toolbarShortcutHandlers = this.editor.toolController.getMatchingTools(ToolbarShortcutHandler_1.default);
|
434
|
+
let removeKeyPressListener = null;
|
435
|
+
// If the onKeyPress function has been extended and the editor is configured to send keypress events to
|
436
|
+
// toolbar widgets,
|
437
|
+
if (toolbarShortcutHandlers.length > 0 && this.onKeyPress !== BaseWidget.prototype.onKeyPress) {
|
438
|
+
const keyPressListener = (event) => this.onKeyPress(event);
|
439
|
+
const handler = toolbarShortcutHandlers[0];
|
440
|
+
handler.registerListener(keyPressListener);
|
441
|
+
removeKeyPressListener = () => {
|
442
|
+
handler.removeListener(keyPressListener);
|
443
|
+
};
|
444
|
+
}
|
445
|
+
const readOnlyListener = this.editor.isReadOnlyReactiveValue().onUpdateAndNow(readOnly => {
|
446
|
+
if (readOnly && this.shouldAutoDisableInReadOnlyEditor() && !this.disabled) {
|
447
|
+
this.setDisabled(true);
|
448
|
+
__classPrivateFieldSet(this, _BaseWidget_disabledDueToReadOnlyEditor, true, "f");
|
449
|
+
if (__classPrivateFieldGet(this, _BaseWidget_hasDropdown, "f")) {
|
450
|
+
this.dropdown?.requestHide();
|
451
|
+
}
|
452
|
+
}
|
453
|
+
else if (!readOnly && __classPrivateFieldGet(this, _BaseWidget_disabledDueToReadOnlyEditor, "f")) {
|
454
|
+
__classPrivateFieldSet(this, _BaseWidget_disabledDueToReadOnlyEditor, false, "f");
|
455
|
+
this.setDisabled(false);
|
456
|
+
}
|
457
|
+
});
|
458
|
+
__classPrivateFieldSet(this, _BaseWidget_removeEditorListeners, () => {
|
459
|
+
readOnlyListener.remove();
|
460
|
+
removeKeyPressListener?.();
|
461
|
+
__classPrivateFieldSet(this, _BaseWidget_removeEditorListeners, null, "f");
|
462
|
+
}, "f");
|
463
|
+
};
|
447
464
|
exports.default = BaseWidget;
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -167,6 +167,7 @@ class BaseTool {
|
|
167
167
|
onDestroy() {
|
168
168
|
__classPrivateFieldGet(this, _BaseTool_readOnlyEditorChangeListener, "f")?.remove();
|
169
169
|
__classPrivateFieldSet(this, _BaseTool_readOnlyEditorChangeListener, null, "f");
|
170
|
+
__classPrivateFieldSet(this, _BaseTool_group, null, "f");
|
170
171
|
}
|
171
172
|
}
|
172
173
|
_BaseTool_enabled = new WeakMap(), _BaseTool_group = new WeakMap(), _BaseTool_inputMapper = new WeakMap(), _BaseTool_readOnlyEditorChangeListener = new WeakMap();
|
@@ -13,9 +13,32 @@ export default class ToolController implements InputEventListener {
|
|
13
13
|
/** @internal */
|
14
14
|
constructor(editor: Editor, localization: ToolLocalization);
|
15
15
|
setTools(tools: BaseTool[], primaryToolGroup?: ToolEnabledGroup): void;
|
16
|
+
/**
|
17
|
+
* Add a tool that acts like one of the primary tools (only one primary tool can be enabled at a time).
|
18
|
+
*
|
19
|
+
* If the tool is already added to this, the tool is converted to a primary tool.
|
20
|
+
*
|
21
|
+
* This should be called before creating the app's toolbar.
|
22
|
+
*/
|
16
23
|
addPrimaryTool(tool: BaseTool): void;
|
17
24
|
getPrimaryTools(): BaseTool[];
|
18
25
|
addTool(tool: BaseTool): void;
|
26
|
+
/**
|
27
|
+
* Removes **and destroys** all tools in `tools` from this.
|
28
|
+
*/
|
29
|
+
removeAndDestroyTools(tools: BaseTool[]): void;
|
30
|
+
private insertTools;
|
31
|
+
/**
|
32
|
+
* Removes a tool from this' tool list and replaces it with `replaceWith`.
|
33
|
+
*
|
34
|
+
* If any of `toolsToInsert` have already been added to this, the tools are
|
35
|
+
* moved.
|
36
|
+
*
|
37
|
+
* This should be called before creating the editor's toolbar.
|
38
|
+
*/
|
39
|
+
insertToolsAfter(insertAfter: BaseTool, toolsToInsert: BaseTool[]): void;
|
40
|
+
/** @see {@link insertToolsAfter} */
|
41
|
+
insertToolsBefore(insertBefore: BaseTool, toolsToInsert: BaseTool[]): void;
|
19
42
|
private onEventInternal;
|
20
43
|
/** Alias for {@link dispatchInputEvent}. */
|
21
44
|
onEvent(event: InputEvt): boolean;
|
@@ -115,14 +115,21 @@ class ToolController {
|
|
115
115
|
this.tools = tools;
|
116
116
|
this.primaryToolGroup = primaryToolGroup ?? new ToolEnabledGroup_1.default();
|
117
117
|
}
|
118
|
-
|
119
|
-
|
118
|
+
/**
|
119
|
+
* Add a tool that acts like one of the primary tools (only one primary tool can be enabled at a time).
|
120
|
+
*
|
121
|
+
* If the tool is already added to this, the tool is converted to a primary tool.
|
122
|
+
*
|
123
|
+
* This should be called before creating the app's toolbar.
|
124
|
+
*/
|
120
125
|
addPrimaryTool(tool) {
|
121
126
|
tool.setToolGroup(this.primaryToolGroup);
|
122
127
|
if (tool.isEnabled()) {
|
123
128
|
this.primaryToolGroup.notifyEnabled(tool);
|
124
129
|
}
|
125
|
-
this.
|
130
|
+
if (!this.tools.includes(tool)) {
|
131
|
+
this.addTool(tool);
|
132
|
+
}
|
126
133
|
}
|
127
134
|
getPrimaryTools() {
|
128
135
|
return this.tools.filter(tool => {
|
@@ -131,8 +138,62 @@ class ToolController {
|
|
131
138
|
}
|
132
139
|
// Add a tool to the end of this' tool list (the added tool receives events after tools already added to this).
|
133
140
|
// This should be called before creating the app's toolbar.
|
141
|
+
//
|
142
|
+
// A tool should only be added once.
|
134
143
|
addTool(tool) {
|
135
|
-
|
144
|
+
// Only add if not already present.
|
145
|
+
if (!this.tools.includes(tool)) {
|
146
|
+
this.tools.push(tool);
|
147
|
+
}
|
148
|
+
}
|
149
|
+
/**
|
150
|
+
* Removes **and destroys** all tools in `tools` from this.
|
151
|
+
*/
|
152
|
+
removeAndDestroyTools(tools) {
|
153
|
+
const newTools = [];
|
154
|
+
for (const tool of this.tools) {
|
155
|
+
if (tools.includes(tool)) {
|
156
|
+
if (this.activeTool === tool) {
|
157
|
+
this.activeTool = null;
|
158
|
+
}
|
159
|
+
tool.onDestroy();
|
160
|
+
}
|
161
|
+
else {
|
162
|
+
newTools.push(tool);
|
163
|
+
}
|
164
|
+
}
|
165
|
+
this.tools = newTools;
|
166
|
+
}
|
167
|
+
insertTools(insertNear, toolsToInsert, mode) {
|
168
|
+
this.tools = this.tools.filter(tool => !toolsToInsert.includes(tool));
|
169
|
+
const newTools = [];
|
170
|
+
for (const tool of this.tools) {
|
171
|
+
if (mode === 'after') {
|
172
|
+
newTools.push(tool);
|
173
|
+
}
|
174
|
+
if (tool === insertNear) {
|
175
|
+
newTools.push(...toolsToInsert);
|
176
|
+
}
|
177
|
+
if (mode === 'before') {
|
178
|
+
newTools.push(tool);
|
179
|
+
}
|
180
|
+
}
|
181
|
+
this.tools = newTools;
|
182
|
+
}
|
183
|
+
/**
|
184
|
+
* Removes a tool from this' tool list and replaces it with `replaceWith`.
|
185
|
+
*
|
186
|
+
* If any of `toolsToInsert` have already been added to this, the tools are
|
187
|
+
* moved.
|
188
|
+
*
|
189
|
+
* This should be called before creating the editor's toolbar.
|
190
|
+
*/
|
191
|
+
insertToolsAfter(insertAfter, toolsToInsert) {
|
192
|
+
this.insertTools(insertAfter, toolsToInsert, 'after');
|
193
|
+
}
|
194
|
+
/** @see {@link insertToolsAfter} */
|
195
|
+
insertToolsBefore(insertBefore, toolsToInsert) {
|
196
|
+
this.insertTools(insertBefore, toolsToInsert, 'before');
|
136
197
|
}
|
137
198
|
// @internal use `dispatchEvent` rather than calling `onEvent` directly.
|
138
199
|
onEventInternal(event) {
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
package/dist/cjs/version.js
CHANGED
package/dist/mjs/Editor.d.ts
CHANGED
@@ -64,6 +64,14 @@ export interface EditorSettings {
|
|
64
64
|
* Additional messages to show in the "about" dialog.
|
65
65
|
*/
|
66
66
|
notices: AboutDialogEntry[];
|
67
|
+
/**
|
68
|
+
* Information about the app/website js-draw is running within
|
69
|
+
* to show at the beginning of the about dialog.
|
70
|
+
*/
|
71
|
+
appInfo: {
|
72
|
+
name: string;
|
73
|
+
version?: string;
|
74
|
+
} | null;
|
67
75
|
}
|
68
76
|
/**
|
69
77
|
* The main entrypoint for the full editor.
|
package/dist/mjs/Editor.mjs
CHANGED
@@ -106,6 +106,7 @@ export class Editor {
|
|
106
106
|
keyboardShortcutOverrides: settings.keyboardShortcutOverrides ?? {},
|
107
107
|
iconProvider: settings.iconProvider ?? new IconProvider(),
|
108
108
|
notices: [],
|
109
|
+
appInfo: settings.appInfo ? { ...settings.appInfo } : null,
|
109
110
|
};
|
110
111
|
// Validate settings
|
111
112
|
if (this.settings.minZoom > this.settings.maxZoom) {
|
@@ -644,12 +645,16 @@ export class Editor {
|
|
644
645
|
htmlEvent.preventDefault();
|
645
646
|
}
|
646
647
|
});
|
647
|
-
elem.addEventListener('
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
648
|
+
elem.addEventListener('focusout', (event) => {
|
649
|
+
const stillHasFocus = event.relatedTarget && elem.contains(event.relatedTarget);
|
650
|
+
if (!stillHasFocus) {
|
651
|
+
for (const event of keysDown) {
|
652
|
+
this.toolController.dispatchInputEvent({
|
653
|
+
...event,
|
654
|
+
kind: InputEvtType.KeyUpEvent,
|
655
|
+
});
|
656
|
+
}
|
657
|
+
keysDown = [];
|
653
658
|
}
|
654
659
|
});
|
655
660
|
// Allow drop.
|
@@ -1116,16 +1121,34 @@ export class Editor {
|
|
1116
1121
|
showAboutDialog() {
|
1117
1122
|
const iconLicenseText = this.icons.licenseInfo();
|
1118
1123
|
const notices = [];
|
1124
|
+
if (this.settings.appInfo) {
|
1125
|
+
const versionLines = [];
|
1126
|
+
if (this.settings.appInfo.version) {
|
1127
|
+
versionLines.push(`v${this.settings.appInfo.version}`, '');
|
1128
|
+
}
|
1129
|
+
notices.push({
|
1130
|
+
heading: `${this.settings.appInfo.name}`,
|
1131
|
+
text: [
|
1132
|
+
...versionLines,
|
1133
|
+
`Image editor library: js-draw v${version.number}.`,
|
1134
|
+
].join('\n'),
|
1135
|
+
});
|
1136
|
+
}
|
1137
|
+
else {
|
1138
|
+
notices.push({
|
1139
|
+
heading: 'js-draw',
|
1140
|
+
text: `v${version.number}`,
|
1141
|
+
});
|
1142
|
+
}
|
1119
1143
|
notices.push({
|
1120
|
-
heading: '
|
1144
|
+
heading: 'Developer information',
|
1121
1145
|
text: [
|
1122
|
-
`v${version.number}`,
|
1123
|
-
'',
|
1124
1146
|
'Image debug information (from when this dialog was opened):',
|
1125
1147
|
` ${this.viewport.getScaleFactor()}x zoom, ${180 / Math.PI * this.viewport.getRotationAngle()} rotation`,
|
1126
1148
|
` ${this.image.estimateNumElements()} components`,
|
1127
1149
|
` ${this.getImportExportRect().w}x${this.getImportExportRect().h} size`,
|
1128
1150
|
].join('\n'),
|
1151
|
+
minimized: true,
|
1129
1152
|
});
|
1130
1153
|
notices.push({
|
1131
1154
|
heading: 'Libraries',
|
package/dist/mjs/SVGLoader.d.ts
CHANGED
@@ -11,9 +11,14 @@ export type SVGLoaderUnknownStyleAttribute = {
|
|
11
11
|
value: string;
|
12
12
|
priority?: string;
|
13
13
|
};
|
14
|
+
export declare enum SVGLoaderLoadMethod {
|
15
|
+
IFrame = "iframe",
|
16
|
+
DOMParser = "domparser"
|
17
|
+
}
|
14
18
|
export interface SVGLoaderOptions {
|
15
19
|
sanitize?: boolean;
|
16
20
|
disableUnknownObjectWarnings?: boolean;
|
21
|
+
loadMethod?: 'iframe' | 'domparser';
|
17
22
|
}
|
18
23
|
export default class SVGLoader implements ImageLoader {
|
19
24
|
private source;
|
@@ -32,6 +37,7 @@ export default class SVGLoader implements ImageLoader {
|
|
32
37
|
private attachUnrecognisedAttrs;
|
33
38
|
private addPath;
|
34
39
|
private addBackground;
|
40
|
+
private getComputedStyle;
|
35
41
|
private getTransform;
|
36
42
|
private makeText;
|
37
43
|
private addText;
|