js-draw 1.3.1 → 1.4.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 (158) hide show
  1. package/README.md +1 -1
  2. package/dist/Editor.css +55 -13
  3. package/dist/bundle.js +2 -2
  4. package/dist/bundledStyles.js +1 -1
  5. package/dist/cjs/Editor.d.ts +36 -3
  6. package/dist/cjs/Editor.js +63 -26
  7. package/dist/cjs/commands/Erase.js +1 -1
  8. package/dist/cjs/commands/UnresolvedCommand.d.ts +1 -1
  9. package/dist/cjs/components/AbstractComponent.d.ts +1 -1
  10. package/dist/cjs/components/AbstractComponent.js +1 -1
  11. package/dist/cjs/components/BackgroundComponent.d.ts +1 -1
  12. package/dist/cjs/components/BackgroundComponent.js +1 -1
  13. package/dist/cjs/{EditorImage.d.ts → image/EditorImage.d.ts} +30 -8
  14. package/dist/cjs/{EditorImage.js → image/EditorImage.js} +51 -7
  15. package/dist/cjs/image/export/editorImageToSVG.d.ts +8 -0
  16. package/dist/cjs/image/export/editorImageToSVG.js +49 -0
  17. package/dist/cjs/image/export/setExportedSVGSize.d.ts +6 -0
  18. package/dist/cjs/image/export/setExportedSVGSize.js +25 -0
  19. package/dist/cjs/image/lib.d.ts +1 -0
  20. package/dist/cjs/image/lib.js +8 -0
  21. package/dist/cjs/lib.d.ts +1 -1
  22. package/dist/cjs/lib.js +2 -3
  23. package/dist/cjs/localizations/comments.d.ts +6 -0
  24. package/dist/cjs/localizations/comments.js +10 -0
  25. package/dist/cjs/localizations/es.js +68 -48
  26. package/dist/cjs/rendering/caching/RenderingCache.d.ts +1 -1
  27. package/dist/cjs/rendering/caching/RenderingCacheNode.d.ts +1 -1
  28. package/dist/cjs/rendering/caching/RenderingCacheNode.js +4 -3
  29. package/dist/cjs/toolbar/AbstractToolbar.d.ts +11 -3
  30. package/dist/cjs/toolbar/AbstractToolbar.js +20 -6
  31. package/dist/cjs/toolbar/EdgeToolbar.js +5 -6
  32. package/dist/cjs/toolbar/IconProvider.d.ts +1 -0
  33. package/dist/cjs/toolbar/IconProvider.js +43 -0
  34. package/dist/cjs/toolbar/widgets/ActionButtonWidget.d.ts +3 -1
  35. package/dist/cjs/toolbar/widgets/ActionButtonWidget.js +19 -1
  36. package/dist/cjs/toolbar/widgets/BaseToolWidget.d.ts +1 -0
  37. package/dist/cjs/toolbar/widgets/BaseToolWidget.js +3 -0
  38. package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +5 -0
  39. package/dist/cjs/toolbar/widgets/BaseWidget.js +30 -2
  40. package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +1 -1
  41. package/dist/cjs/toolbar/widgets/HandToolWidget.d.ts +1 -0
  42. package/dist/cjs/toolbar/widgets/HandToolWidget.js +6 -0
  43. package/dist/cjs/toolbar/widgets/InsertImageWidget.js +1 -1
  44. package/dist/cjs/toolbar/widgets/OverflowWidget.d.ts +1 -0
  45. package/dist/cjs/toolbar/widgets/OverflowWidget.js +3 -0
  46. package/dist/cjs/toolbar/widgets/SaveActionWidget.d.ts +1 -0
  47. package/dist/cjs/toolbar/widgets/SaveActionWidget.js +3 -0
  48. package/dist/cjs/tools/BaseTool.d.ts +3 -0
  49. package/dist/cjs/tools/BaseTool.js +13 -2
  50. package/dist/cjs/tools/FindTool.d.ts +1 -0
  51. package/dist/cjs/tools/FindTool.js +4 -1
  52. package/dist/cjs/tools/PanZoom.d.ts +1 -0
  53. package/dist/cjs/tools/PanZoom.js +4 -0
  54. package/dist/cjs/tools/Pen.d.ts +0 -1
  55. package/dist/cjs/tools/Pen.js +1 -4
  56. package/dist/cjs/tools/PipetteTool.d.ts +1 -0
  57. package/dist/cjs/tools/PipetteTool.js +3 -0
  58. package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +1 -0
  59. package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.js +3 -0
  60. package/dist/cjs/tools/SelectionTool/Selection.d.ts +2 -0
  61. package/dist/cjs/tools/SelectionTool/Selection.js +44 -8
  62. package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +14 -6
  63. package/dist/cjs/tools/SelectionTool/SelectionHandle.js +26 -8
  64. package/dist/cjs/tools/SelectionTool/SelectionTool.js +5 -0
  65. package/dist/cjs/tools/SoundUITool.d.ts +1 -0
  66. package/dist/cjs/tools/SoundUITool.js +4 -1
  67. package/dist/cjs/tools/TextTool.js +2 -2
  68. package/dist/cjs/tools/ToolController.d.ts +2 -0
  69. package/dist/cjs/tools/ToolController.js +13 -2
  70. package/dist/cjs/tools/ToolSwitcherShortcut.d.ts +1 -0
  71. package/dist/cjs/tools/ToolSwitcherShortcut.js +3 -0
  72. package/dist/cjs/types.d.ts +9 -4
  73. package/dist/cjs/types.js +4 -3
  74. package/dist/cjs/util/ReactiveValue.d.ts +1 -1
  75. package/dist/cjs/util/ReactiveValue.js +2 -2
  76. package/dist/cjs/version.js +1 -1
  77. package/dist/mjs/Editor.d.ts +36 -3
  78. package/dist/mjs/Editor.mjs +64 -27
  79. package/dist/mjs/Editor.toSVGAsync.test.d.ts +1 -0
  80. package/dist/mjs/commands/Erase.mjs +1 -1
  81. package/dist/mjs/commands/UnresolvedCommand.d.ts +1 -1
  82. package/dist/mjs/components/AbstractComponent.d.ts +1 -1
  83. package/dist/mjs/components/AbstractComponent.mjs +1 -1
  84. package/dist/mjs/components/BackgroundComponent.d.ts +1 -1
  85. package/dist/mjs/components/BackgroundComponent.mjs +1 -1
  86. package/dist/mjs/{EditorImage.d.ts → image/EditorImage.d.ts} +30 -8
  87. package/dist/mjs/{EditorImage.mjs → image/EditorImage.mjs} +51 -7
  88. package/dist/mjs/image/EditorImage.test.d.ts +1 -0
  89. package/dist/mjs/image/export/editorImageToSVG.d.ts +8 -0
  90. package/dist/mjs/image/export/editorImageToSVG.mjs +41 -0
  91. package/dist/mjs/image/export/setExportedSVGSize.d.ts +6 -0
  92. package/dist/mjs/image/export/setExportedSVGSize.mjs +23 -0
  93. package/dist/mjs/image/lib.d.ts +1 -0
  94. package/dist/mjs/image/lib.mjs +1 -0
  95. package/dist/mjs/lib.d.ts +1 -1
  96. package/dist/mjs/lib.mjs +1 -1
  97. package/dist/mjs/localizations/comments.d.ts +6 -0
  98. package/dist/mjs/localizations/comments.mjs +8 -0
  99. package/dist/mjs/localizations/es.mjs +68 -48
  100. package/dist/mjs/rendering/caching/RenderingCache.d.ts +1 -1
  101. package/dist/mjs/rendering/caching/RenderingCacheNode.d.ts +1 -1
  102. package/dist/mjs/rendering/caching/RenderingCacheNode.mjs +4 -3
  103. package/dist/mjs/toolbar/AbstractToolbar.d.ts +11 -3
  104. package/dist/mjs/toolbar/AbstractToolbar.mjs +20 -6
  105. package/dist/mjs/toolbar/EdgeToolbar.mjs +5 -6
  106. package/dist/mjs/toolbar/IconProvider.d.ts +1 -0
  107. package/dist/mjs/toolbar/IconProvider.mjs +43 -0
  108. package/dist/mjs/toolbar/widgets/ActionButtonWidget.d.ts +3 -1
  109. package/dist/mjs/toolbar/widgets/ActionButtonWidget.mjs +21 -2
  110. package/dist/mjs/toolbar/widgets/BaseToolWidget.d.ts +1 -0
  111. package/dist/mjs/toolbar/widgets/BaseToolWidget.mjs +3 -0
  112. package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +5 -0
  113. package/dist/mjs/toolbar/widgets/BaseWidget.mjs +30 -2
  114. package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +1 -1
  115. package/dist/mjs/toolbar/widgets/HandToolWidget.d.ts +1 -0
  116. package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +6 -0
  117. package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +1 -1
  118. package/dist/mjs/toolbar/widgets/OverflowWidget.d.ts +1 -0
  119. package/dist/mjs/toolbar/widgets/OverflowWidget.mjs +3 -0
  120. package/dist/mjs/toolbar/widgets/SaveActionWidget.d.ts +1 -0
  121. package/dist/mjs/toolbar/widgets/SaveActionWidget.mjs +3 -0
  122. package/dist/mjs/tools/BaseTool.d.ts +3 -0
  123. package/dist/mjs/tools/BaseTool.mjs +13 -2
  124. package/dist/mjs/tools/FindTool.d.ts +1 -0
  125. package/dist/mjs/tools/FindTool.mjs +4 -1
  126. package/dist/mjs/tools/PanZoom.d.ts +1 -0
  127. package/dist/mjs/tools/PanZoom.mjs +4 -0
  128. package/dist/mjs/tools/Pen.d.ts +0 -1
  129. package/dist/mjs/tools/Pen.mjs +1 -4
  130. package/dist/mjs/tools/PipetteTool.d.ts +1 -0
  131. package/dist/mjs/tools/PipetteTool.mjs +3 -0
  132. package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +1 -0
  133. package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.mjs +3 -0
  134. package/dist/mjs/tools/SelectionTool/Selection.d.ts +2 -0
  135. package/dist/mjs/tools/SelectionTool/Selection.mjs +45 -9
  136. package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +14 -6
  137. package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +25 -7
  138. package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +5 -0
  139. package/dist/mjs/tools/SoundUITool.d.ts +1 -0
  140. package/dist/mjs/tools/SoundUITool.mjs +4 -1
  141. package/dist/mjs/tools/TextTool.mjs +2 -2
  142. package/dist/mjs/tools/ToolController.d.ts +2 -0
  143. package/dist/mjs/tools/ToolController.mjs +13 -2
  144. package/dist/mjs/tools/ToolSwitcherShortcut.d.ts +1 -0
  145. package/dist/mjs/tools/ToolSwitcherShortcut.mjs +3 -0
  146. package/dist/mjs/types.d.ts +9 -4
  147. package/dist/mjs/types.mjs +4 -3
  148. package/dist/mjs/util/ReactiveValue.d.ts +1 -1
  149. package/dist/mjs/util/ReactiveValue.mjs +2 -2
  150. package/dist/mjs/version.mjs +1 -1
  151. package/package.json +5 -5
  152. package/src/Editor.scss +6 -0
  153. package/src/toolbar/EdgeToolbar.scss +19 -2
  154. package/src/tools/SelectionTool/SelectionTool.scss +74 -0
  155. package/src/tools/tools.scss +1 -1
  156. package/src/tools/SelectionTool/SelectionTool.css +0 -35
  157. /package/dist/cjs/{EditorImage.test.d.ts → Editor.toSVGAsync.test.d.ts} +0 -0
  158. /package/dist/{mjs → cjs/image}/EditorImage.test.d.ts +0 -0
@@ -1,16 +1,33 @@
1
1
  "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
2
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
15
  };
16
+ var _ActionButtonWidget_autoDisableInReadOnlyEditors;
5
17
  Object.defineProperty(exports, "__esModule", { value: true });
6
18
  const BaseWidget_1 = __importDefault(require("./BaseWidget"));
7
19
  class ActionButtonWidget extends BaseWidget_1.default {
8
- constructor(editor, id, makeIcon, title, clickAction, localizationTable, mustBeToplevel = false) {
20
+ constructor(editor, id, makeIcon, title, clickAction, localizationTable, mustBeToplevel = false, autoDisableInReadOnlyEditors = true) {
9
21
  super(editor, id, localizationTable);
10
22
  this.makeIcon = makeIcon;
11
23
  this.title = title;
12
24
  this.clickAction = clickAction;
13
25
  this.mustBeToplevel = mustBeToplevel;
26
+ _ActionButtonWidget_autoDisableInReadOnlyEditors.set(this, void 0);
27
+ __classPrivateFieldSet(this, _ActionButtonWidget_autoDisableInReadOnlyEditors, autoDisableInReadOnlyEditors, "f");
28
+ }
29
+ shouldAutoDisableInReadOnlyEditor() {
30
+ return __classPrivateFieldGet(this, _ActionButtonWidget_autoDisableInReadOnlyEditors, "f");
14
31
  }
15
32
  handleClick() {
16
33
  this.clickAction();
@@ -28,4 +45,5 @@ class ActionButtonWidget extends BaseWidget_1.default {
28
45
  return this.mustBeToplevel;
29
46
  }
30
47
  }
48
+ _ActionButtonWidget_autoDisableInReadOnlyEditors = new WeakMap();
31
49
  exports.default = ActionButtonWidget;
@@ -6,6 +6,7 @@ import BaseWidget from './BaseWidget';
6
6
  export default abstract class BaseToolWidget extends BaseWidget {
7
7
  protected targetTool: BaseTool;
8
8
  constructor(editor: Editor, targetTool: BaseTool, id: string, localizationTable?: ToolbarLocalization);
9
+ protected shouldAutoDisableInReadOnlyEditor(): boolean;
9
10
  protected handleClick(): void;
10
11
  protected onKeyPress(event: KeyPressEvent): boolean;
11
12
  addTo(parent: HTMLElement): HTMLElement;
@@ -39,6 +39,9 @@ class BaseToolWidget extends BaseWidget_1.default {
39
39
  }
40
40
  });
41
41
  }
42
+ shouldAutoDisableInReadOnlyEditor() {
43
+ return !this.targetTool.canReceiveInputInReadOnlyEditor();
44
+ }
42
45
  handleClick() {
43
46
  if (this.hasDropdown) {
44
47
  if (!this.targetTool.isEnabled()) {
@@ -29,6 +29,11 @@ export default abstract class BaseWidget {
29
29
  private toplevel;
30
30
  protected readonly localizationTable: ToolbarLocalization;
31
31
  constructor(editor: Editor, id: string, localizationTable?: ToolbarLocalization);
32
+ /**
33
+ * Should return a constant true or false value. If true (the default),
34
+ * this widget must be automatically disabled when its editor is read-only.
35
+ */
36
+ protected shouldAutoDisableInReadOnlyEditor(): boolean;
32
37
  getId(): string;
33
38
  /**
34
39
  * Note: Tags should be set *before* a tool widget is added to a toolbar.
@@ -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_tags;
16
+ var _BaseWidget_hasDropdown, _BaseWidget_disabledDueToReadOnlyEditor, _BaseWidget_tags, _BaseWidget_readOnlyListener;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.ToolbarWidgetTag = void 0;
19
19
  const ToolbarShortcutHandler_1 = __importDefault(require("../../tools/ToolbarShortcutHandler"));
@@ -36,11 +36,16 @@ class BaseWidget {
36
36
  this.id = id;
37
37
  this.dropdown = null;
38
38
  _BaseWidget_hasDropdown.set(this, void 0);
39
+ // True iff this widget is disabled.
39
40
  this.disabled = false;
41
+ // True iff this widget is currently disabled because the editor is read only
42
+ _BaseWidget_disabledDueToReadOnlyEditor.set(this, false);
40
43
  _BaseWidget_tags.set(this, []);
41
44
  // Maps subWidget IDs to subWidgets.
42
45
  this.subWidgets = {};
43
46
  this.toplevel = true;
47
+ // Listens for changes in whether the editor is read-only
48
+ _BaseWidget_readOnlyListener.set(this, null);
44
49
  this.localizationTable = localizationTable ?? editor.localization;
45
50
  // Default layout manager
46
51
  const defaultLayoutManager = new DropdownLayoutManager_1.default((text) => this.editor.announceForAccessibility(text), this.localizationTable);
@@ -68,6 +73,13 @@ class BaseWidget {
68
73
  toolbarShortcutHandlers[0].registerListener(event => this.onKeyPress(event));
69
74
  }
70
75
  }
76
+ /**
77
+ * Should return a constant true or false value. If true (the default),
78
+ * this widget must be automatically disabled when its editor is read-only.
79
+ */
80
+ shouldAutoDisableInReadOnlyEditor() {
81
+ return true;
82
+ }
71
83
  getId() {
72
84
  return this.id;
73
85
  }
@@ -262,6 +274,19 @@ class BaseWidget {
262
274
  if (this.container.parentElement) {
263
275
  this.container.remove();
264
276
  }
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");
265
290
  parent.appendChild(this.container);
266
291
  return this.container;
267
292
  }
@@ -279,6 +304,8 @@ class BaseWidget {
279
304
  }
280
305
  remove() {
281
306
  this.container.remove();
307
+ __classPrivateFieldGet(this, _BaseWidget_readOnlyListener, "f")?.remove();
308
+ __classPrivateFieldSet(this, _BaseWidget_readOnlyListener, null, "f");
282
309
  }
283
310
  updateIcon() {
284
311
  let newIcon = this.createIcon();
@@ -295,6 +322,7 @@ class BaseWidget {
295
322
  }
296
323
  setDisabled(disabled) {
297
324
  this.disabled = disabled;
325
+ __classPrivateFieldSet(this, _BaseWidget_disabledDueToReadOnlyEditor, false, "f");
298
326
  if (this.disabled) {
299
327
  this.button.classList.add('disabled');
300
328
  this.button.setAttribute('aria-disabled', 'true');
@@ -415,5 +443,5 @@ class BaseWidget {
415
443
  }
416
444
  }
417
445
  }
418
- _BaseWidget_hasDropdown = new WeakMap(), _BaseWidget_tags = new WeakMap();
446
+ _BaseWidget_hasDropdown = new WeakMap(), _BaseWidget_disabledDueToReadOnlyEditor = new WeakMap(), _BaseWidget_tags = new WeakMap(), _BaseWidget_readOnlyListener = new WeakMap();
419
447
  exports.default = BaseWidget;
@@ -29,7 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const Erase_1 = __importDefault(require("../../commands/Erase"));
30
30
  const uniteCommands_1 = __importDefault(require("../../commands/uniteCommands"));
31
31
  const BackgroundComponent_1 = __importStar(require("../../components/BackgroundComponent"));
32
- const EditorImage_1 = require("../../EditorImage");
32
+ const EditorImage_1 = require("../../image/EditorImage");
33
33
  const math_1 = require("@js-draw/math");
34
34
  const types_1 = require("../../types");
35
35
  const constants_1 = require("../constants");
@@ -7,6 +7,7 @@ export default class HandToolWidget extends BaseToolWidget {
7
7
  protected overridePanZoomTool: PanZoom;
8
8
  private allowTogglingBaseTool;
9
9
  constructor(editor: Editor, overridePanZoomTool: PanZoom, localizationTable: ToolbarLocalization);
10
+ protected shouldAutoDisableInReadOnlyEditor(): boolean;
10
11
  private static getPrimaryHandTool;
11
12
  protected getTitle(): string;
12
13
  protected createIcon(): Element;
@@ -103,6 +103,9 @@ class HandModeWidget extends BaseWidget_1.default {
103
103
  });
104
104
  this.setSelected(false);
105
105
  }
106
+ shouldAutoDisableInReadOnlyEditor() {
107
+ return false;
108
+ }
106
109
  setModeFlag(enabled) {
107
110
  this.tool.setModeEnabled(this.flag, enabled);
108
111
  }
@@ -141,6 +144,9 @@ class HandToolWidget extends BaseToolWidget_1.default {
141
144
  this.addSubWidget(touchPanningWidget);
142
145
  this.addSubWidget(rotationLockWidget);
143
146
  }
147
+ shouldAutoDisableInReadOnlyEditor() {
148
+ return false;
149
+ }
144
150
  static getPrimaryHandTool(toolController) {
145
151
  const primaryPanZoomToolList = toolController.getPrimaryTools().filter(tool => tool instanceof PanZoom_1.default);
146
152
  const primaryPanZoomTool = primaryPanZoomToolList[0];
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const ImageComponent_1 = __importDefault(require("../../components/ImageComponent"));
7
7
  const Erase_1 = __importDefault(require("../../commands/Erase"));
8
- const EditorImage_1 = __importDefault(require("../../EditorImage"));
8
+ const EditorImage_1 = __importDefault(require("../../image/EditorImage"));
9
9
  const uniteCommands_1 = __importDefault(require("../../commands/uniteCommands"));
10
10
  const SelectionTool_1 = __importDefault(require("../../tools/SelectionTool/SelectionTool"));
11
11
  const math_1 = require("@js-draw/math");
@@ -5,6 +5,7 @@ export default class OverflowWidget extends BaseWidget {
5
5
  private overflowChildren;
6
6
  private overflowContainer;
7
7
  constructor(editor: Editor, localizationTable?: ToolbarLocalization);
8
+ protected shouldAutoDisableInReadOnlyEditor(): boolean;
8
9
  protected getTitle(): string;
9
10
  protected createIcon(): Element | null;
10
11
  protected handleClick(): void;
@@ -13,6 +13,9 @@ class OverflowWidget extends BaseWidget_1.default {
13
13
  this.container.classList.add('dropdownShowable');
14
14
  this.overflowContainer ??= document.createElement('div');
15
15
  }
16
+ shouldAutoDisableInReadOnlyEditor() {
17
+ return false;
18
+ }
16
19
  getTitle() {
17
20
  return this.localizationTable.toggleOverflow;
18
21
  }
@@ -4,6 +4,7 @@ import { ToolbarLocalization } from '../localization';
4
4
  import ActionButtonWidget from './ActionButtonWidget';
5
5
  declare class SaveActionWidget extends ActionButtonWidget {
6
6
  constructor(editor: Editor, localization: ToolbarLocalization, saveCallback: () => void);
7
+ protected shouldAutoDisableInReadOnlyEditor(): boolean;
7
8
  protected onKeyPress(event: KeyPressEvent): boolean;
8
9
  mustBeInToplevelMenu(): boolean;
9
10
  }
@@ -11,6 +11,9 @@ class SaveActionWidget extends ActionButtonWidget_1.default {
11
11
  super(editor, 'save-button', editor.icons.makeSaveIcon, localization.save, saveCallback);
12
12
  this.setTags([BaseWidget_1.ToolbarWidgetTag.Save]);
13
13
  }
14
+ shouldAutoDisableInReadOnlyEditor() {
15
+ return false;
16
+ }
14
17
  onKeyPress(event) {
15
18
  if (this.editor.shortcuts.matchesShortcut(keybindings_1.saveKeyboardShortcut, event)) {
16
19
  this.clickAction();
@@ -8,6 +8,8 @@ export default abstract class BaseTool implements InputEventListener {
8
8
  private notifier;
9
9
  readonly description: string;
10
10
  protected constructor(notifier: EditorNotifier, description: string);
11
+ /** Override this to allow this tool to be enabled in a read-only editor */
12
+ canReceiveInputInReadOnlyEditor(): boolean;
11
13
  setInputMapper(mapper: InputMapper | null): void;
12
14
  getInputMapper(): InputMapper | null;
13
15
  private dispatchEventToCallback;
@@ -54,4 +56,5 @@ export default abstract class BaseTool implements InputEventListener {
54
56
  enabledValue(): ReactiveValue<boolean>;
55
57
  setToolGroup(group: ToolEnabledGroup): void;
56
58
  getToolGroup(): ToolEnabledGroup | null;
59
+ onDestroy(): void;
57
60
  }
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _BaseTool_enabled, _BaseTool_group, _BaseTool_inputMapper;
13
+ var _BaseTool_enabled, _BaseTool_group, _BaseTool_inputMapper, _BaseTool_readOnlyEditorChangeListener;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const types_1 = require("../types");
16
16
  const inputEvents_1 = require("../inputEvents");
@@ -22,6 +22,7 @@ class BaseTool {
22
22
  _BaseTool_enabled.set(this, void 0);
23
23
  _BaseTool_group.set(this, null);
24
24
  _BaseTool_inputMapper.set(this, null);
25
+ _BaseTool_readOnlyEditorChangeListener.set(this, null);
25
26
  __classPrivateFieldSet(this, _BaseTool_enabled, ReactiveValue_1.ReactiveValue.fromInitialValue(true), "f");
26
27
  __classPrivateFieldGet(this, _BaseTool_enabled, "f").onUpdate(enabled => {
27
28
  // Ensure that at most one tool in the group is enabled.
@@ -40,6 +41,10 @@ class BaseTool {
40
41
  }
41
42
  });
42
43
  }
44
+ /** Override this to allow this tool to be enabled in a read-only editor */
45
+ canReceiveInputInReadOnlyEditor() {
46
+ return false;
47
+ }
43
48
  setInputMapper(mapper) {
44
49
  __classPrivateFieldSet(this, _BaseTool_inputMapper, mapper, "f");
45
50
  if (mapper) {
@@ -157,6 +162,12 @@ class BaseTool {
157
162
  }
158
163
  return null;
159
164
  }
165
+ // Called when the tool is removed/when the editor is destroyed.
166
+ // Subclasses that override this method **must call super.onDestroy()**.
167
+ onDestroy() {
168
+ __classPrivateFieldGet(this, _BaseTool_readOnlyEditorChangeListener, "f")?.remove();
169
+ __classPrivateFieldSet(this, _BaseTool_readOnlyEditorChangeListener, null, "f");
170
+ }
160
171
  }
161
- _BaseTool_enabled = new WeakMap(), _BaseTool_group = new WeakMap(), _BaseTool_inputMapper = new WeakMap();
172
+ _BaseTool_enabled = new WeakMap(), _BaseTool_group = new WeakMap(), _BaseTool_inputMapper = new WeakMap(), _BaseTool_readOnlyEditorChangeListener = new WeakMap();
162
173
  exports.default = BaseTool;
@@ -7,6 +7,7 @@ export default class FindTool extends BaseTool {
7
7
  private searchInput;
8
8
  private currentMatchIdx;
9
9
  constructor(editor: Editor);
10
+ canReceiveInputInReadOnlyEditor(): boolean;
10
11
  private getMatches;
11
12
  private focusCurrentMatch;
12
13
  private toNextMatch;
@@ -21,6 +21,9 @@ class FindTool extends BaseTool_1.default {
21
21
  this.overlay.style.display = 'none';
22
22
  this.overlay.classList.add(`${cssPrefix}-overlay`);
23
23
  }
24
+ canReceiveInputInReadOnlyEditor() {
25
+ return true;
26
+ }
24
27
  getMatches(searchFor) {
25
28
  searchFor = searchFor.toLocaleLowerCase();
26
29
  const allTextComponents = this.editor.image.getAllElements()
@@ -113,7 +116,7 @@ class FindTool extends BaseTool_1.default {
113
116
  }
114
117
  setEnabled(enabled) {
115
118
  super.setEnabled(enabled);
116
- if (enabled) {
119
+ if (this.isEnabled()) {
117
120
  this.setVisible(false);
118
121
  }
119
122
  }
@@ -32,6 +32,7 @@ export default class PanZoom extends BaseTool {
32
32
  private inertialScroller;
33
33
  private velocity;
34
34
  constructor(editor: Editor, mode: PanZoomMode, description: string);
35
+ canReceiveInputInReadOnlyEditor(): boolean;
35
36
  computePinchData(p1: Pointer, p2: Pointer): PinchData;
36
37
  private allPointersAreOfType;
37
38
  onPointerDown({ allPointers: pointers, current: currentPointer }: PointerEvt): boolean;
@@ -80,6 +80,10 @@ class PanZoom extends BaseTool_1.default {
80
80
  this.inertialScroller = null;
81
81
  this.velocity = null;
82
82
  }
83
+ // The pan/zoom tool can be used in a read-only editor.
84
+ canReceiveInputInReadOnlyEditor() {
85
+ return true;
86
+ }
83
87
  // Returns information about the pointers in a gesture
84
88
  computePinchData(p1, p2) {
85
89
  // Swap the pointers to ensure consistent ordering.
@@ -40,6 +40,5 @@ export default class Pen extends BaseTool {
40
40
  getColor(): Color4;
41
41
  getStrokeFactory(): ComponentBuilderFactory;
42
42
  getStyleValue(): MutableReactiveValue<PenStyle>;
43
- setEnabled(enabled: boolean): void;
44
43
  onKeyPress(event: KeyPressEvent): boolean;
45
44
  }
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const math_1 = require("@js-draw/math");
7
- const EditorImage_1 = __importDefault(require("../EditorImage"));
7
+ const EditorImage_1 = __importDefault(require("../image/EditorImage"));
8
8
  const Pointer_1 = require("../Pointer");
9
9
  const FreehandLineBuilder_1 = require("../components/builders/FreehandLineBuilder");
10
10
  const types_1 = require("../types");
@@ -205,9 +205,6 @@ class Pen extends BaseTool_1.default {
205
205
  getColor() { return this.style.color; }
206
206
  getStrokeFactory() { return this.style.factory; }
207
207
  getStyleValue() { return this.styleValue; }
208
- setEnabled(enabled) {
209
- super.setEnabled(enabled);
210
- }
211
208
  onKeyPress(event) {
212
209
  const shortcuts = this.editor.shortcuts;
213
210
  // Ctrl+Z: End the stroke so that it can be undone/redone.
@@ -16,6 +16,7 @@ export default class PipetteTool extends BaseTool {
16
16
  private colorPreviewListener;
17
17
  private colorSelectListener;
18
18
  constructor(editor: Editor, description: string);
19
+ canReceiveInputInReadOnlyEditor(): boolean;
19
20
  private updateSelectingStatus;
20
21
  setColorListener(colorPreviewListener: ColorListener, colorSelectListener: ColorListener): void;
21
22
  clearColorListener(): void;
@@ -23,6 +23,9 @@ class PipetteTool extends BaseTool_1.default {
23
23
  this.updateSelectingStatus();
24
24
  });
25
25
  }
26
+ canReceiveInputInReadOnlyEditor() {
27
+ return true;
28
+ }
26
29
  // Ensures that the root editor element correctly reflects whether color selection
27
30
  // is in progress.
28
31
  updateSelectingStatus() {
@@ -4,5 +4,6 @@ import BaseTool from '../BaseTool';
4
4
  export default class SelectAllShortcutHandler extends BaseTool {
5
5
  private editor;
6
6
  constructor(editor: Editor);
7
+ canReceiveInputInReadOnlyEditor(): boolean;
7
8
  onKeyPress(event: KeyPressEvent): boolean;
8
9
  }
@@ -12,6 +12,9 @@ class SelectAllShortcutHandler extends BaseTool_1.default {
12
12
  super(editor.notifier, editor.localization.selectAllTool);
13
13
  this.editor = editor;
14
14
  }
15
+ canReceiveInputInReadOnlyEditor() {
16
+ return true;
17
+ }
15
18
  // @internal
16
19
  onKeyPress(event) {
17
20
  if (this.editor.shortcuts.matchesShortcut(keybindings_1.selectAllKeyboardShortcut, event)) {
@@ -11,6 +11,7 @@ export default class Selection {
11
11
  private editor;
12
12
  private handles;
13
13
  private originalRegion;
14
+ private selectionTightBoundingBox;
14
15
  private transformers;
15
16
  private transform;
16
17
  private selectedElems;
@@ -39,6 +40,7 @@ export default class Selection {
39
40
  private previewTransformCmds;
40
41
  resolveToObjects(): boolean;
41
42
  recomputeRegion(): boolean;
43
+ padRegion(): void;
42
44
  getMinCanvasSize(): number;
43
45
  getSelectedItemCount(): number;
44
46
  updateUI(): void;
@@ -40,13 +40,16 @@ const Erase_1 = __importDefault(require("../../commands/Erase"));
40
40
  const Duplicate_1 = __importDefault(require("../../commands/Duplicate"));
41
41
  const TransformMode_1 = require("./TransformMode");
42
42
  const types_1 = require("./types");
43
- const EditorImage_1 = __importDefault(require("../../EditorImage"));
43
+ const EditorImage_1 = __importDefault(require("../../image/EditorImage"));
44
44
  const updateChunkSize = 100;
45
45
  const maxPreviewElemCount = 500;
46
46
  // @internal
47
47
  class Selection {
48
48
  constructor(startPoint, editor) {
49
49
  this.editor = editor;
50
+ // The last-computed bounding box of selected content
51
+ // @see getTightBoundingBox
52
+ this.selectionTightBoundingBox = null;
50
53
  this.transform = math_1.Mat33.identity;
51
54
  this.selectedElems = [];
52
55
  this.hasParent = true;
@@ -65,10 +68,23 @@ class Selection {
65
68
  this.backgroundElem = document.createElement('div');
66
69
  this.backgroundElem.classList.add(`${SelectionTool_1.cssPrefix}selection-background`);
67
70
  this.container.appendChild(this.backgroundElem);
68
- const resizeHorizontalHandle = new SelectionHandle_1.default(SelectionHandle_1.HandleShape.Square, math_1.Vec2.of(1, 0.5), this, this.editor.viewport, (startPoint) => this.transformers.resize.onDragStart(startPoint, types_1.ResizeMode.HorizontalOnly), (currentPoint) => this.transformers.resize.onDragUpdate(currentPoint), () => this.transformers.resize.onDragEnd());
69
- const resizeVerticalHandle = new SelectionHandle_1.default(SelectionHandle_1.HandleShape.Square, math_1.Vec2.of(0.5, 1), this, this.editor.viewport, (startPoint) => this.transformers.resize.onDragStart(startPoint, types_1.ResizeMode.VerticalOnly), (currentPoint) => this.transformers.resize.onDragUpdate(currentPoint), () => this.transformers.resize.onDragEnd());
70
- const resizeBothHandle = new SelectionHandle_1.default(SelectionHandle_1.HandleShape.Square, math_1.Vec2.of(1, 1), this, this.editor.viewport, (startPoint) => this.transformers.resize.onDragStart(startPoint, types_1.ResizeMode.Both), (currentPoint) => this.transformers.resize.onDragUpdate(currentPoint), () => this.transformers.resize.onDragEnd());
71
- const rotationHandle = new SelectionHandle_1.default(SelectionHandle_1.HandleShape.Circle, math_1.Vec2.of(0.5, 0), this, this.editor.viewport, (startPoint) => this.transformers.rotate.onDragStart(startPoint), (currentPoint) => this.transformers.rotate.onDragUpdate(currentPoint), () => this.transformers.rotate.onDragEnd());
71
+ const resizeHorizontalHandle = new SelectionHandle_1.default({
72
+ action: SelectionHandle_1.HandleAction.ResizeX,
73
+ side: math_1.Vec2.of(1, 0.5),
74
+ }, this, this.editor.viewport, (startPoint) => this.transformers.resize.onDragStart(startPoint, types_1.ResizeMode.HorizontalOnly), (currentPoint) => this.transformers.resize.onDragUpdate(currentPoint), () => this.transformers.resize.onDragEnd());
75
+ const resizeVerticalHandle = new SelectionHandle_1.default({
76
+ action: SelectionHandle_1.HandleAction.ResizeY,
77
+ side: math_1.Vec2.of(0.5, 1),
78
+ }, this, this.editor.viewport, (startPoint) => this.transformers.resize.onDragStart(startPoint, types_1.ResizeMode.VerticalOnly), (currentPoint) => this.transformers.resize.onDragUpdate(currentPoint), () => this.transformers.resize.onDragEnd());
79
+ const resizeBothHandle = new SelectionHandle_1.default({
80
+ action: SelectionHandle_1.HandleAction.ResizeXY,
81
+ side: math_1.Vec2.of(1, 1),
82
+ }, this, this.editor.viewport, (startPoint) => this.transformers.resize.onDragStart(startPoint, types_1.ResizeMode.Both), (currentPoint) => this.transformers.resize.onDragUpdate(currentPoint), () => this.transformers.resize.onDragEnd());
83
+ const rotationHandle = new SelectionHandle_1.default({
84
+ action: SelectionHandle_1.HandleAction.Rotate,
85
+ side: math_1.Vec2.of(0.5, 0),
86
+ icon: this.editor.icons.makeRotateIcon(),
87
+ }, this, this.editor.viewport, (startPoint) => this.transformers.rotate.onDragStart(startPoint), (currentPoint) => this.transformers.rotate.onDragUpdate(currentPoint), () => this.transformers.rotate.onDragEnd());
72
88
  this.handles = [
73
89
  resizeBothHandle,
74
90
  resizeHorizontalHandle,
@@ -195,18 +211,26 @@ class Selection {
195
211
  // Returns false if the selection is empty.
196
212
  recomputeRegion() {
197
213
  const newRegion = this.computeTightBoundingBox();
214
+ this.selectionTightBoundingBox = newRegion;
198
215
  if (!newRegion) {
199
216
  this.cancelSelection();
200
217
  return false;
201
218
  }
202
219
  this.originalRegion = newRegion;
220
+ this.padRegion();
221
+ return true;
222
+ }
223
+ // Applies padding to the current region if it is too small.
224
+ // @internal
225
+ padRegion() {
226
+ const sourceRegion = this.selectionTightBoundingBox ?? this.originalRegion;
203
227
  const minSize = this.getMinCanvasSize();
204
- if (this.originalRegion.w < minSize || this.originalRegion.h < minSize) {
228
+ if (sourceRegion.w < minSize || sourceRegion.h < minSize) {
205
229
  // Add padding
206
230
  const padding = minSize / 2;
207
- this.originalRegion = math_1.Rect2.bboxOf(this.originalRegion.corners, padding);
231
+ this.originalRegion = math_1.Rect2.bboxOf(sourceRegion.corners, padding);
232
+ this.updateUI();
208
233
  }
209
- return true;
210
234
  }
211
235
  getMinCanvasSize() {
212
236
  const canvasHandleSize = SelectionHandle_1.handleSize / this.editor.viewport.getScaleFactor();
@@ -230,6 +254,14 @@ class Selection {
230
254
  const rotationDeg = this.screenRegionRotation * 180 / Math.PI;
231
255
  this.backgroundElem.style.transform = `rotate(${rotationDeg}deg)`;
232
256
  this.backgroundElem.style.transformOrigin = 'center';
257
+ // If closer to perpendicular, apply different CSS
258
+ const perpendicularClassName = `${SelectionTool_1.cssPrefix}rotated-near-perpendicular`;
259
+ if (Math.abs(Math.sin(this.screenRegionRotation)) > 0.5) {
260
+ this.container.classList.add(perpendicularClassName);
261
+ }
262
+ else {
263
+ this.container.classList.remove(perpendicularClassName);
264
+ }
233
265
  for (const handle of this.handles) {
234
266
  handle.updatePosition();
235
267
  }
@@ -401,6 +433,7 @@ class Selection {
401
433
  }
402
434
  setToPoint(point) {
403
435
  this.originalRegion = this.originalRegion.grownToPoint(point);
436
+ this.selectionTightBoundingBox = null;
404
437
  this.updateUI();
405
438
  }
406
439
  cancelSelection() {
@@ -408,12 +441,15 @@ class Selection {
408
441
  this.container.remove();
409
442
  }
410
443
  this.originalRegion = math_1.Rect2.empty;
444
+ this.selectionTightBoundingBox = null;
411
445
  this.hasParent = false;
412
446
  }
413
447
  setSelectedObjects(objects, bbox) {
414
448
  this.addRemoveSelectionFromImage(true);
415
449
  this.originalRegion = bbox;
450
+ this.selectionTightBoundingBox = bbox;
416
451
  this.selectedElems = objects.filter(object => object.isSelectable());
452
+ this.padRegion();
417
453
  this.updateUI();
418
454
  }
419
455
  getSelectedObjects() {
@@ -2,17 +2,23 @@ import { Point2, Vec2 } from '@js-draw/math';
2
2
  import Selection from './Selection';
3
3
  import Pointer from '../../Pointer';
4
4
  import Viewport from '../../Viewport';
5
- export declare enum HandleShape {
6
- Circle = 0,
7
- Square = 1
5
+ export declare enum HandleAction {
6
+ ResizeXY = "resize-xy",
7
+ Rotate = "rotate",
8
+ ResizeX = "resize-x",
9
+ ResizeY = "resize-y"
10
+ }
11
+ export interface HandlePresentation {
12
+ side: Vec2;
13
+ icon?: Element;
14
+ action: HandleAction;
8
15
  }
9
16
  export declare const handleSize = 30;
10
17
  export type DragStartCallback = (startPoint: Point2) => void;
11
18
  export type DragUpdateCallback = (canvasPoint: Point2) => void;
12
19
  export type DragEndCallback = () => void;
13
20
  export default class SelectionHandle {
14
- readonly shape: HandleShape;
15
- private readonly parentSide;
21
+ readonly presentation: HandlePresentation;
16
22
  private readonly parent;
17
23
  private readonly viewport;
18
24
  private readonly onDragStart;
@@ -20,7 +26,9 @@ export default class SelectionHandle {
20
26
  private readonly onDragEnd;
21
27
  private element;
22
28
  private snapToGrid;
23
- constructor(shape: HandleShape, parentSide: Vec2, parent: Selection, viewport: Viewport, onDragStart: DragStartCallback, onDragUpdate: DragUpdateCallback, onDragEnd: DragEndCallback);
29
+ private shape;
30
+ private parentSide;
31
+ constructor(presentation: HandlePresentation, parent: Selection, viewport: Viewport, onDragStart: DragStartCallback, onDragUpdate: DragUpdateCallback, onDragEnd: DragEndCallback);
24
32
  /**
25
33
  * Adds this to `container`, where `conatiner` should be the background/selection
26
34
  * element visible on the screen.