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.
Files changed (51) hide show
  1. package/README.md +10 -1
  2. package/dist/Editor.css +2 -2
  3. package/dist/bundle.js +2 -2
  4. package/dist/bundledStyles.js +1 -1
  5. package/dist/cjs/Editor.d.ts +8 -0
  6. package/dist/cjs/Editor.js +32 -9
  7. package/dist/cjs/SVGLoader.d.ts +6 -0
  8. package/dist/cjs/SVGLoader.js +100 -56
  9. package/dist/cjs/commands/Erase.d.ts +7 -1
  10. package/dist/cjs/commands/Erase.js +13 -4
  11. package/dist/cjs/commands/invertCommand.js +1 -1
  12. package/dist/cjs/components/Stroke.d.ts +1 -1
  13. package/dist/cjs/components/Stroke.js +1 -1
  14. package/dist/cjs/image/EditorImage.js +1 -1
  15. package/dist/cjs/toolbar/AbstractToolbar.d.ts +4 -1
  16. package/dist/cjs/toolbar/AbstractToolbar.js +7 -1
  17. package/dist/cjs/toolbar/widgets/BaseToolWidget.js +4 -13
  18. package/dist/cjs/toolbar/widgets/BaseToolWidget.test.d.ts +1 -0
  19. package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +5 -1
  20. package/dist/cjs/toolbar/widgets/BaseWidget.js +45 -28
  21. package/dist/cjs/toolbar/widgets/BaseWidget.test.d.ts +1 -0
  22. package/dist/cjs/tools/BaseTool.js +1 -0
  23. package/dist/cjs/tools/ToolController.d.ts +23 -0
  24. package/dist/cjs/tools/ToolController.js +65 -4
  25. package/dist/cjs/tools/ToolController.test.d.ts +1 -0
  26. package/dist/cjs/version.js +1 -1
  27. package/dist/mjs/Editor.d.ts +8 -0
  28. package/dist/mjs/Editor.mjs +32 -9
  29. package/dist/mjs/SVGLoader.d.ts +6 -0
  30. package/dist/mjs/SVGLoader.mjs +99 -55
  31. package/dist/mjs/commands/Erase.d.ts +7 -1
  32. package/dist/mjs/commands/Erase.mjs +13 -4
  33. package/dist/mjs/commands/invertCommand.mjs +1 -1
  34. package/dist/mjs/components/Stroke.d.ts +1 -1
  35. package/dist/mjs/components/Stroke.mjs +1 -1
  36. package/dist/mjs/image/EditorImage.mjs +1 -1
  37. package/dist/mjs/toolbar/AbstractToolbar.d.ts +4 -1
  38. package/dist/mjs/toolbar/AbstractToolbar.mjs +7 -1
  39. package/dist/mjs/toolbar/widgets/BaseToolWidget.mjs +4 -13
  40. package/dist/mjs/toolbar/widgets/BaseToolWidget.test.d.ts +1 -0
  41. package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +5 -1
  42. package/dist/mjs/toolbar/widgets/BaseWidget.mjs +45 -28
  43. package/dist/mjs/toolbar/widgets/BaseWidget.test.d.ts +1 -0
  44. package/dist/mjs/tools/BaseTool.mjs +1 -0
  45. package/dist/mjs/tools/ToolController.d.ts +23 -0
  46. package/dist/mjs/tools/ToolController.mjs +65 -4
  47. package/dist/mjs/tools/ToolController.test.d.ts +1 -0
  48. package/dist/mjs/version.mjs +1 -1
  49. package/docs/img/readme-images/logo.svg +1 -0
  50. package/package.json +3 -3
  51. package/src/Editor.scss +4 -2
@@ -37,7 +37,7 @@ class Stroke extends AbstractComponent_1.default {
37
37
  *
38
38
  * const stroke = new Stroke([
39
39
  * // Fill with red
40
- * path.toRenderable({ fill: Color4.red })
40
+ * pathToRenderable({ fill: Color4.red })
41
41
  * ]);
42
42
  * ```
43
43
  */
@@ -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
- /** Remove this toolbar from its container and clean up listeners. */
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
- /** Remove this toolbar from its container and clean up listeners. */
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
- editor.notifier.on(types_1.EditorEventType.ToolEnabled, toolEvt => {
18
- if (toolEvt.kind !== types_1.EditorEventType.ToolEnabled) {
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.key === ' ' && this.hasDropdown) {
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, _BaseWidget_readOnlyListener;
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
- // Listens for changes in whether the editor is read-only
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
- __classPrivateFieldSet(this, _BaseWidget_readOnlyListener, this.editor.isReadOnlyReactiveValue().onUpdateAndNow(readOnly => {
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(), _BaseWidget_readOnlyListener = 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
- // Add a tool that acts like one of the primary tools (only one primary tool can be enabled at a time).
119
- // This should be called before creating the app's toolbar.
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.addTool(tool);
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
- this.tools.push(tool);
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 {};
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = {
4
- number: '1.5.0',
4
+ number: '1.6.0',
5
5
  };
@@ -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.
@@ -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('blur', () => {
648
- for (const event of keysDown) {
649
- this.toolController.dispatchInputEvent({
650
- ...event,
651
- kind: InputEvtType.KeyUpEvent,
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: 'js-draw',
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',
@@ -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;