js-draw 1.23.1 → 1.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/Editor.css +21 -0
  2. package/dist/bundle.js +2 -2
  3. package/dist/bundledStyles.js +1 -1
  4. package/dist/cjs/Editor.d.ts +7 -1
  5. package/dist/cjs/Editor.js +71 -9
  6. package/dist/cjs/SVGLoader/SVGLoader.js +17 -7
  7. package/dist/cjs/Viewport.d.ts +2 -0
  8. package/dist/cjs/Viewport.js +0 -1
  9. package/dist/cjs/components/AbstractComponent.d.ts +1 -1
  10. package/dist/cjs/components/BackgroundComponent.js +17 -7
  11. package/dist/cjs/components/SVGGlobalAttributesObject.js +17 -7
  12. package/dist/cjs/components/UnknownSVGObject.js +17 -7
  13. package/dist/cjs/components/lib.js +17 -7
  14. package/dist/cjs/image/EditorImage.js +17 -7
  15. package/dist/cjs/testing/sendPenEvent.js +17 -7
  16. package/dist/cjs/testing/sendTouchEvent.js +17 -7
  17. package/dist/cjs/toolbar/EdgeToolbar.d.ts +1 -1
  18. package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +17 -7
  19. package/dist/cjs/toolbar/widgets/HandToolWidget.js +17 -7
  20. package/dist/cjs/tools/InputFilter/ContextMenuRecognizer.js +17 -7
  21. package/dist/cjs/tools/Pen.js +17 -7
  22. package/dist/cjs/tools/SelectionTool/Selection.js +17 -7
  23. package/dist/cjs/tools/SelectionTool/SelectionMenuShortcut.js +1 -1
  24. package/dist/cjs/tools/SelectionTool/util/makeClipboardErrorHandlers.d.ts +2 -2
  25. package/dist/cjs/tools/SelectionTool/util/makeClipboardErrorHandlers.js +1 -1
  26. package/dist/cjs/tools/SoundUITool.js +1 -1
  27. package/dist/cjs/tools/TextTool.d.ts +4 -4
  28. package/dist/cjs/tools/TextTool.js +45 -51
  29. package/dist/cjs/tools/ToolController.js +17 -7
  30. package/dist/cjs/tools/UndoRedoShortcut.js +2 -2
  31. package/dist/cjs/util/ClipboardHandler.js +1 -0
  32. package/dist/cjs/version.js +1 -1
  33. package/dist/mjs/Editor.d.ts +7 -1
  34. package/dist/mjs/Editor.mjs +54 -2
  35. package/dist/mjs/Viewport.d.ts +2 -0
  36. package/dist/mjs/Viewport.mjs +0 -1
  37. package/dist/mjs/components/AbstractComponent.d.ts +1 -1
  38. package/dist/mjs/toolbar/EdgeToolbar.d.ts +1 -1
  39. package/dist/mjs/tools/SelectionTool/SelectionMenuShortcut.mjs +1 -1
  40. package/dist/mjs/tools/SelectionTool/util/makeClipboardErrorHandlers.d.ts +2 -2
  41. package/dist/mjs/tools/SelectionTool/util/makeClipboardErrorHandlers.mjs +1 -1
  42. package/dist/mjs/tools/SoundUITool.mjs +1 -1
  43. package/dist/mjs/tools/TextTool.d.ts +4 -4
  44. package/dist/mjs/tools/TextTool.mjs +45 -51
  45. package/dist/mjs/tools/UndoRedoShortcut.mjs +2 -2
  46. package/dist/mjs/util/ClipboardHandler.mjs +1 -0
  47. package/dist/mjs/version.mjs +1 -1
  48. package/package.json +4 -4
  49. package/src/Editor.scss +31 -0
@@ -25,7 +25,7 @@ import guessKeyCodeFromKey from './util/guessKeyCodeFromKey.mjs';
25
25
  import makeAboutDialog from './dialogs/makeAboutDialog.mjs';
26
26
  import version from './version.mjs';
27
27
  import { editorImageToSVGSync, editorImageToSVGAsync } from './image/export/editorImageToSVG.mjs';
28
- import { MutableReactiveValue } from './util/ReactiveValue.mjs';
28
+ import ReactiveValue, { MutableReactiveValue } from './util/ReactiveValue.mjs';
29
29
  import listenForKeyboardEventsFrom from './util/listenForKeyboardEventsFrom.mjs';
30
30
  import mitLicenseAttribution from './util/mitLicenseAttribution.mjs';
31
31
  import ClipboardHandler from './util/ClipboardHandler.mjs';
@@ -473,7 +473,7 @@ export class Editor {
473
473
  /** @internal */
474
474
  async handleDrop(evt) {
475
475
  evt.preventDefault();
476
- this.handlePaste(evt);
476
+ await this.handlePaste(evt);
477
477
  }
478
478
  /** @internal */
479
479
  async handlePaste(evt) {
@@ -884,6 +884,58 @@ export class Editor {
884
884
  remove: () => overlay.remove(),
885
885
  };
886
886
  }
887
+ /**
888
+ * Anchors the given `element` to the canvas with a given position/transformation in canvas space.
889
+ */
890
+ anchorElementToCanvas(element, canvasTransform) {
891
+ if (canvasTransform instanceof Mat33) {
892
+ canvasTransform = ReactiveValue.fromImmutable(canvasTransform);
893
+ }
894
+ // The element hierarchy looks like this:
895
+ // overlay > contentWrapper > content
896
+ //
897
+ // Both contentWrapper and overlay are present to:
898
+ // 1. overlay: Positions the content at the top left of the viewport. The overlay
899
+ // has `height: 0` to allow other overlays to also be aligned with the viewport's
900
+ // top left.
901
+ // 2. contentWrapper: Has the same width/height as the editor's visible region and
902
+ // has `overflow: hidden`. This prevents the anchored element from being visible
903
+ // when not in the visible region of the canvas.
904
+ const overlay = document.createElement('div');
905
+ overlay.classList.add('anchored-element-overlay');
906
+ const contentWrapper = document.createElement('div');
907
+ contentWrapper.classList.add('content-wrapper');
908
+ element.classList.add('content');
909
+ // Updates CSS variables that specify the position/rotation/scale of the content.
910
+ const updateElementPositioning = () => {
911
+ const transform = canvasTransform.get();
912
+ const canvasRotation = transform.transformVec3(Vec2.unitX).angle();
913
+ const screenRotation = canvasRotation + this.viewport.getRotationAngle();
914
+ const screenTransform = this.viewport.canvasToScreenTransform.rightMul(canvasTransform.get());
915
+ overlay.style.setProperty('--full-transform', screenTransform.toCSSMatrix());
916
+ const translation = screenTransform.transformVec2(Vec2.zero);
917
+ overlay.style.setProperty('--position-x', `${translation.x}px`);
918
+ overlay.style.setProperty('--position-y', `${translation.y}px`);
919
+ overlay.style.setProperty('--rotation', `${(screenRotation * 180) / Math.PI}deg`);
920
+ overlay.style.setProperty('--scale', `${screenTransform.getScaleFactor()}`);
921
+ };
922
+ updateElementPositioning();
923
+ // The anchored element needs to be updated both when the user moves the canvas
924
+ // and when the anchored element's transform changes.
925
+ const updateListener = canvasTransform.onUpdate(updateElementPositioning);
926
+ const viewportListener = this.notifier.on(EditorEventType.ViewportChanged, updateElementPositioning);
927
+ contentWrapper.appendChild(element);
928
+ overlay.appendChild(contentWrapper);
929
+ overlay.classList.add('overlay', 'js-draw-editor-overlay');
930
+ this.renderingRegion.insertAdjacentElement('afterend', overlay);
931
+ return {
932
+ remove: () => {
933
+ overlay.remove();
934
+ updateListener.remove();
935
+ viewportListener.remove();
936
+ },
937
+ };
938
+ }
887
939
  /**
888
940
  * Creates a CSS stylesheet with `content` and applies it to the document
889
941
  * (and thus, to this editor).
@@ -9,7 +9,9 @@ type TransformChangeCallback = (oldTransform: Mat33, newTransform: Mat33) => voi
9
9
  export declare class Viewport {
10
10
  private onTransformChangeCallback;
11
11
  private static ViewportTransform;
12
+ /** Converts from canvas to screen coordinates */
12
13
  private transform;
14
+ /** Converts from screen to canvas coordinates */
13
15
  private inverseTransform;
14
16
  private screenRect;
15
17
  constructor(onTransformChangeCallback: TransformChangeCallback);
@@ -127,7 +127,6 @@ export class Viewport {
127
127
  }
128
128
  // The separate function type definition seems necessary here.
129
129
  // See https://stackoverflow.com/a/58163623/17055750.
130
- // eslint-disable-next-line no-dupe-class-members
131
130
  static roundPoint(point, tolerance) {
132
131
  const scaleFactor = 10 ** Math.floor(Math.log10(tolerance));
133
132
  const roundComponent = (component) => {
@@ -163,5 +163,5 @@ export default abstract class AbstractComponent {
163
163
  data: string | number | any[] | Record<string, any>;
164
164
  };
165
165
  private static isNotDeserializable;
166
- static deserialize(json: string | any): AbstractComponent;
166
+ static deserialize(json: any): AbstractComponent;
167
167
  }
@@ -49,7 +49,7 @@ export default class EdgeToolbar extends AbstractToolbar {
49
49
  constructor(editor: Editor, parent: HTMLElement, localizationTable: ToolbarLocalization);
50
50
  private listenForVisibilityChanges;
51
51
  private onToolbarRowResize;
52
- addSpacer(_options?: Partial<SpacerOptions> | undefined): void;
52
+ addSpacer(_options?: Partial<SpacerOptions>): void;
53
53
  addUndoRedoButtons(): void;
54
54
  addDefaults(): void;
55
55
  private updateWidgetCSSClasses;
@@ -10,7 +10,7 @@ export default class SelectionMenuShortcut {
10
10
  this.element = document.createElement('div');
11
11
  this.element.classList.add(`${cssPrefix}handle`, `${cssPrefix}selection-menu`);
12
12
  this.element.style.setProperty('--vertical-offset', `${verticalOffset}px`);
13
- this.onClick = async () => {
13
+ this.onClick = () => {
14
14
  const anchor = this.getBBoxCanvasCoords().center;
15
15
  showContextMenu(anchor);
16
16
  };
@@ -1,6 +1,6 @@
1
1
  import Editor from '../../../Editor';
2
2
  declare const makeClipboardErrorHandlers: (editor: Editor) => {
3
- onCopyError(error: Error | unknown): Promise<void>;
4
- onPasteError(error: Error | unknown): void;
3
+ onCopyError(error: unknown): void;
4
+ onPasteError(error: unknown): void;
5
5
  };
6
6
  export default makeClipboardErrorHandlers;
@@ -16,7 +16,7 @@ const makeClipboardErrorHandlers = (editor) => {
16
16
  return dialog;
17
17
  };
18
18
  return {
19
- async onCopyError(error) {
19
+ onCopyError(error) {
20
20
  const dialog = makeErrorDialog(error);
21
21
  const textboxLabel = document.createElement('label');
22
22
  textboxLabel.textContent = editor.localization.copyPasteError__copyRetry;
@@ -73,7 +73,7 @@ class SoundFeedback {
73
73
  this.boundaryGain.gain.linearRampToValueAtTime(0, this.ctx.currentTime + 0.25);
74
74
  }
75
75
  close() {
76
- this.ctx.close();
76
+ void this.ctx.close();
77
77
  this.closed = true;
78
78
  }
79
79
  }
@@ -5,23 +5,22 @@ import BaseTool from './BaseTool';
5
5
  import { ToolLocalization } from './localization';
6
6
  import TextRenderingStyle from '../rendering/TextRenderingStyle';
7
7
  import { MutableReactiveValue } from '../util/ReactiveValue';
8
+ /** A tool that allows users to enter and edit text. */
8
9
  export default class TextTool extends BaseTool {
9
10
  private editor;
10
11
  private localizationTable;
11
12
  private textStyleValue;
12
13
  private textStyle;
14
+ private anchorControl;
15
+ private contentTransform;
13
16
  private textEditOverlay;
14
17
  private textInputElem;
15
- private textTargetPosition;
16
18
  private textMeasuringCtx;
17
- private textRotation;
18
- private textScale;
19
19
  private removeExistingCommand;
20
20
  constructor(editor: Editor, description: string, localizationTable: ToolLocalization);
21
21
  private initTextMeasuringCanvas;
22
22
  private getTextAscent;
23
23
  private flushInput;
24
- private getTextScaleMatrix;
25
24
  private updateTextInput;
26
25
  private startTextInput;
27
26
  setEnabled(enabled: boolean): void;
@@ -33,4 +32,5 @@ export default class TextTool extends BaseTool {
33
32
  getTextStyle(): TextRenderingStyle;
34
33
  getStyleValue(): MutableReactiveValue<TextRenderingStyle>;
35
34
  private setTextStyle;
35
+ onDestroy(): void;
36
36
  }
@@ -8,15 +8,14 @@ import Erase from '../commands/Erase.mjs';
8
8
  import uniteCommands from '../commands/uniteCommands.mjs';
9
9
  import { ReactiveValue } from '../util/ReactiveValue.mjs';
10
10
  const overlayCSSClass = 'textEditorOverlay';
11
+ /** A tool that allows users to enter and edit text. */
11
12
  export default class TextTool extends BaseTool {
12
13
  constructor(editor, description, localizationTable) {
13
14
  super(editor.notifier, description);
14
15
  this.editor = editor;
15
16
  this.localizationTable = localizationTable;
16
17
  this.textInputElem = null;
17
- this.textTargetPosition = null;
18
18
  this.textMeasuringCtx = null;
19
- this.textScale = Vec2.of(1, 1);
20
19
  this.removeExistingCommand = null;
21
20
  const editorFonts = editor.getCurrentSettings().text?.fonts ?? [];
22
21
  this.textStyleValue = ReactiveValue.fromInitialValue({
@@ -34,18 +33,10 @@ export default class TextTool extends BaseTool {
34
33
  tool: this,
35
34
  });
36
35
  });
36
+ this.contentTransform = ReactiveValue.fromInitialValue(Mat33.identity);
37
37
  this.textEditOverlay = document.createElement('div');
38
38
  this.textEditOverlay.classList.add(overlayCSSClass);
39
39
  this.editor.addStyleSheet(`
40
- .${overlayCSSClass} {
41
- height: 0;
42
- overflow: visible;
43
-
44
- /* Allows absolutely-positioned textareas to scroll with
45
- the containing overlay. */
46
- position: relative;
47
- }
48
-
49
40
  .${overlayCSSClass} textarea {
50
41
  background-color: rgba(0, 0, 0, 0);
51
42
 
@@ -61,8 +52,7 @@ export default class TextTool extends BaseTool {
61
52
  min-height: 1.1em;
62
53
  }
63
54
  `);
64
- this.editor.createHTMLOverlay(this.textEditOverlay);
65
- this.editor.notifier.on(EditorEventType.ViewportChanged, () => this.updateTextInput());
55
+ this.anchorControl = this.editor.anchorElementToCanvas(this.textEditOverlay, this.contentTransform);
66
56
  }
67
57
  initTextMeasuringCanvas() {
68
58
  this.textMeasuringCtx ??= document.createElement('canvas').getContext('2d');
@@ -82,24 +72,32 @@ export default class TextTool extends BaseTool {
82
72
  // If [removeInput], the HTML input element is removed. Otherwise, its value
83
73
  // is cleared.
84
74
  flushInput(removeInput = true) {
85
- if (this.textInputElem && this.textTargetPosition) {
86
- const content = this.textInputElem.value.trimEnd();
87
- this.textInputElem.value = '';
88
- if (removeInput) {
89
- // In some browsers, .remove() triggers a .blur event (synchronously).
90
- // Clear this.textInputElem before removal
91
- const input = this.textInputElem;
92
- this.textInputElem = null;
93
- input.remove();
94
- }
95
- if (content === '') {
96
- return;
97
- }
98
- const textTransform = Mat33.translation(this.textTargetPosition)
99
- .rightMul(this.getTextScaleMatrix())
100
- .rightMul(Mat33.scaling2D(this.editor.viewport.getSizeOfPixelOnCanvas()))
101
- .rightMul(Mat33.zRotation(this.textRotation));
102
- const textComponent = TextComponent.fromLines(content.split('\n'), textTransform, this.textStyle);
75
+ if (!this.textInputElem)
76
+ return;
77
+ // Determine the scroll first -- removing the input (and other DOM changes)
78
+ // also change the scroll.
79
+ const scrollingRegion = this.textEditOverlay.parentElement;
80
+ const containerScroll = Vec2.of(scrollingRegion?.scrollLeft ?? 0, scrollingRegion?.scrollTop ?? 0);
81
+ const content = this.textInputElem.value.trimEnd();
82
+ this.textInputElem.value = '';
83
+ if (removeInput) {
84
+ // In some browsers, .remove() triggers a .blur event (synchronously).
85
+ // Clear this.textInputElem before removal
86
+ const input = this.textInputElem;
87
+ this.textInputElem = null;
88
+ input.remove();
89
+ }
90
+ if (content !== '') {
91
+ // When the text is long, it can cause its container to scroll so that the
92
+ // editing caret is in view.
93
+ // So that the text added to the document is in the same position as the text
94
+ // shown in the editor, account for this scroll when computing the transform:
95
+ const scrollCorrectionScreen = containerScroll.times(-1);
96
+ // Uses .transformVec3 to avoid also translating the scroll correction (treating
97
+ // it as a point):
98
+ const scrollCorrectionCanvas = this.editor.viewport.screenToCanvasTransform.transformVec3(scrollCorrectionScreen);
99
+ const scrollTransform = Mat33.translation(scrollCorrectionCanvas);
100
+ const textComponent = TextComponent.fromLines(content.split('\n'), scrollTransform.rightMul(this.contentTransform.get()), this.textStyle);
103
101
  const action = EditorImage.addElement(textComponent);
104
102
  if (this.removeExistingCommand) {
105
103
  // Unapply so that `removeExistingCommand` can be added to the undo stack.
@@ -112,16 +110,10 @@ export default class TextTool extends BaseTool {
112
110
  }
113
111
  }
114
112
  }
115
- getTextScaleMatrix() {
116
- return Mat33.scaling2D(this.textScale.times(1 / this.editor.viewport.getSizeOfPixelOnCanvas()));
117
- }
118
113
  updateTextInput() {
119
- if (!this.textInputElem || !this.textTargetPosition) {
120
- this.textInputElem?.remove();
114
+ if (!this.textInputElem) {
121
115
  return;
122
116
  }
123
- const viewport = this.editor.viewport;
124
- const textScreenPos = viewport.canvasToScreen(this.textTargetPosition);
125
117
  this.textInputElem.placeholder = this.localizationTable.enterTextToInsert;
126
118
  this.textInputElem.style.fontFamily = this.textStyle.fontFamily;
127
119
  this.textInputElem.style.fontStyle = this.textStyle.fontStyle ?? '';
@@ -129,9 +121,6 @@ export default class TextTool extends BaseTool {
129
121
  this.textInputElem.style.fontWeight = this.textStyle.fontWeight ?? '';
130
122
  this.textInputElem.style.fontSize = `${this.textStyle.size}px`;
131
123
  this.textInputElem.style.color = this.textStyle.renderingStyle.fill.toHexString();
132
- this.textInputElem.style.position = 'absolute';
133
- this.textInputElem.style.left = `${textScreenPos.x}px`;
134
- this.textInputElem.style.top = `${textScreenPos.y}px`;
135
124
  this.textInputElem.style.margin = '0';
136
125
  this.textInputElem.style.width = `${this.textInputElem.scrollWidth}px`;
137
126
  this.textInputElem.style.height = `${this.textInputElem.scrollHeight}px`;
@@ -140,9 +129,7 @@ export default class TextTool extends BaseTool {
140
129
  const tallText = 'Testing!';
141
130
  const ascent = this.getTextAscent(tallText, this.textStyle);
142
131
  const vertAdjust = ascent;
143
- const rotation = this.textRotation + viewport.getRotationAngle();
144
- const scale = this.getTextScaleMatrix();
145
- this.textInputElem.style.transform = `${scale.toCSSMatrix()} rotate(${(rotation * 180) / Math.PI}deg) translate(0, ${-vertAdjust}px)`;
132
+ this.textInputElem.style.transform = `translate(0, ${-vertAdjust}px)`;
146
133
  this.textInputElem.style.transformOrigin = 'top left';
147
134
  // Match the line height of default rendered text.
148
135
  const lineHeight = Math.floor(this.textStyle.size);
@@ -153,9 +140,14 @@ export default class TextTool extends BaseTool {
153
140
  this.textInputElem = document.createElement('textarea');
154
141
  this.textInputElem.value = initialText;
155
142
  this.textInputElem.style.display = 'inline-block';
156
- this.textTargetPosition = this.editor.viewport.roundPoint(textCanvasPos);
157
- this.textRotation = -this.editor.viewport.getRotationAngle();
158
- this.textScale = Vec2.of(1, 1).times(this.editor.viewport.getSizeOfPixelOnCanvas());
143
+ const textTargetPosition = this.editor.viewport.roundPoint(textCanvasPos);
144
+ const textRotation = -this.editor.viewport.getRotationAngle();
145
+ const textScale = Vec2.of(1, 1).times(this.editor.viewport.getSizeOfPixelOnCanvas());
146
+ this.contentTransform.set(
147
+ // Scale, then rotate, then translate:
148
+ Mat33.translation(textTargetPosition)
149
+ .rightMul(Mat33.zRotation(textRotation))
150
+ .rightMul(Mat33.scaling2D(textScale)));
159
151
  this.updateTextInput();
160
152
  // Update the input size/position/etc. after the placeHolder has had time to appear.
161
153
  setTimeout(() => this.updateTextInput(), 0);
@@ -224,10 +216,7 @@ export default class TextTool extends BaseTool {
224
216
  this.removeExistingCommand = new Erase([targetNode]);
225
217
  this.removeExistingCommand.apply(this.editor);
226
218
  this.startTextInput(targetNode.getBaselinePos(), targetNode.getText());
227
- const transform = targetNode.getTransform();
228
- this.textRotation = transform.transformVec3(Vec2.unitX).angle();
229
- const scaleFactor = transform.transformVec3(Vec2.unitX).magnitude();
230
- this.textScale = Vec2.of(1, 1).times(scaleFactor);
219
+ this.contentTransform.set(targetNode.getTransform());
231
220
  this.updateTextInput();
232
221
  }
233
222
  else {
@@ -278,4 +267,9 @@ export default class TextTool extends BaseTool {
278
267
  setTextStyle(style) {
279
268
  this.textStyleValue.set(style);
280
269
  }
270
+ // @internal
271
+ onDestroy() {
272
+ super.onDestroy();
273
+ this.anchorControl.remove();
274
+ }
281
275
  }
@@ -9,11 +9,11 @@ export default class UndoRedoShortcut extends BaseTool {
9
9
  // @internal
10
10
  onKeyPress(event) {
11
11
  if (this.editor.shortcuts.matchesShortcut(undoKeyboardShortcutId, event)) {
12
- this.editor.history.undo();
12
+ void this.editor.history.undo();
13
13
  return true;
14
14
  }
15
15
  else if (this.editor.shortcuts.matchesShortcut(redoKeyboardShortcutId, event)) {
16
- this.editor.history.redo();
16
+ void this.editor.history.redo();
17
17
  return true;
18
18
  }
19
19
  return false;
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-redundant-type-constituents -- Used for clarity */
1
2
  var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
3
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
4
  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");
@@ -4,5 +4,5 @@
4
4
  * @internal
5
5
  */
6
6
  export default {
7
- number: '1.23.1',
7
+ number: '1.24.1',
8
8
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "1.23.1",
3
+ "version": "1.24.1",
4
4
  "description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
5
5
  "types": "./dist/mjs/lib.d.ts",
6
6
  "main": "./dist/cjs/lib.js",
@@ -64,11 +64,11 @@
64
64
  "postpack": "ts-node tools/copyREADME.ts revert"
65
65
  },
66
66
  "dependencies": {
67
- "@js-draw/math": "^1.23.1",
67
+ "@js-draw/math": "^1.24.1",
68
68
  "@melloware/coloris": "0.22.0"
69
69
  },
70
70
  "devDependencies": {
71
- "@js-draw/build-tool": "^1.23.1",
71
+ "@js-draw/build-tool": "^1.24.1",
72
72
  "@types/jest": "29.5.5",
73
73
  "@types/jsdom": "21.1.3"
74
74
  },
@@ -86,5 +86,5 @@
86
86
  "freehand",
87
87
  "svg"
88
88
  ],
89
- "gitHead": "e0bb3336d5f3a94533c823906778d39a4880f4cf"
89
+ "gitHead": "ef847374748e32d6d96d993a2236a99d9109a32c"
90
90
  }
package/src/Editor.scss CHANGED
@@ -165,6 +165,37 @@
165
165
  z-index: 5;
166
166
  }
167
167
 
168
+ // See Editor.anchorElementToCanvas
169
+ .imageEditorContainer .anchored-element-overlay {
170
+ overflow: visible;
171
+ height: 0;
172
+
173
+ > .content-wrapper {
174
+ width: var(--editor-current-display-width-px);
175
+ height: var(--editor-current-display-height-px);
176
+ overflow: hidden;
177
+ // Display 'position: absolute' children relative to this.
178
+ position: relative;
179
+
180
+ // Disable pointer events: If the parent (or the container) has
181
+ // captured pointers and the container is removed, this prevents
182
+ // us from receiving the following events (e.g. in Firefox).
183
+ pointer-events: none;
184
+
185
+ > .content {
186
+ position: absolute;
187
+ left: var(--position-x);
188
+ top: var(--position-y);
189
+ transform: scale(var(--scale)) rotate(var(--rotation));
190
+ transform-origin: left top;
191
+ margin: 0;
192
+
193
+ // We *do* want pointer events for the positioned content.
194
+ pointer-events: all;
195
+ }
196
+ }
197
+ }
198
+
168
199
  // TODO: Apply this change during a future major release.
169
200
  // So as not to change the position of other overlays, all overlays should have
170
201
  // 0 height.