js-draw 1.22.0 → 1.23.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 (63) hide show
  1. package/README.md +1 -1
  2. package/dist/bundle.js +1 -1
  3. package/dist/cjs/Editor.d.ts +1 -3
  4. package/dist/cjs/Editor.js +2 -4
  5. package/dist/cjs/SVGLoader/SVGLoader.js +2 -0
  6. package/dist/cjs/Viewport.d.ts +1 -1
  7. package/dist/cjs/Viewport.js +1 -1
  8. package/dist/cjs/components/AbstractComponent.d.ts +1 -1
  9. package/dist/cjs/components/AbstractComponent.js +1 -1
  10. package/dist/cjs/components/builders/ArrowBuilder.d.ts +1 -1
  11. package/dist/cjs/components/builders/ArrowBuilder.js +1 -1
  12. package/dist/cjs/image/EditorImage.d.ts +30 -7
  13. package/dist/cjs/image/EditorImage.js +30 -7
  14. package/dist/cjs/rendering/renderers/CanvasRenderer.d.ts +2 -25
  15. package/dist/cjs/rendering/renderers/CanvasRenderer.js +2 -25
  16. package/dist/cjs/rendering/renderers/SVGRenderer.js +2 -2
  17. package/dist/cjs/toolbar/AbstractToolbar.d.ts +19 -0
  18. package/dist/cjs/toolbar/AbstractToolbar.js +19 -0
  19. package/dist/cjs/toolbar/IconProvider.d.ts +5 -1
  20. package/dist/cjs/toolbar/IconProvider.js +112 -146
  21. package/dist/cjs/toolbar/localization.js +2 -2
  22. package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +1 -1
  23. package/dist/cjs/toolbar/widgets/BaseWidget.js +1 -1
  24. package/dist/cjs/tools/PanZoom.js +1 -1
  25. package/dist/cjs/tools/Pen.d.ts +13 -0
  26. package/dist/cjs/tools/Pen.js +13 -0
  27. package/dist/cjs/tools/lib.d.ts +1 -0
  28. package/dist/cjs/tools/lib.js +3 -1
  29. package/dist/cjs/util/cloneElementWithStyles.js +1 -1
  30. package/dist/cjs/util/createElement.d.ts +62 -0
  31. package/dist/cjs/util/createElement.js +53 -0
  32. package/dist/cjs/version.js +1 -1
  33. package/dist/mjs/Editor.d.ts +1 -3
  34. package/dist/mjs/Editor.mjs +2 -4
  35. package/dist/mjs/SVGLoader/SVGLoader.mjs +2 -0
  36. package/dist/mjs/Viewport.d.ts +1 -1
  37. package/dist/mjs/Viewport.mjs +1 -1
  38. package/dist/mjs/components/AbstractComponent.d.ts +1 -1
  39. package/dist/mjs/components/AbstractComponent.mjs +1 -1
  40. package/dist/mjs/components/builders/ArrowBuilder.d.ts +1 -1
  41. package/dist/mjs/components/builders/ArrowBuilder.mjs +1 -1
  42. package/dist/mjs/image/EditorImage.d.ts +30 -7
  43. package/dist/mjs/image/EditorImage.mjs +30 -7
  44. package/dist/mjs/rendering/renderers/CanvasRenderer.d.ts +2 -25
  45. package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +2 -25
  46. package/dist/mjs/rendering/renderers/SVGRenderer.mjs +2 -2
  47. package/dist/mjs/toolbar/AbstractToolbar.d.ts +19 -0
  48. package/dist/mjs/toolbar/AbstractToolbar.mjs +19 -0
  49. package/dist/mjs/toolbar/IconProvider.d.ts +5 -1
  50. package/dist/mjs/toolbar/IconProvider.mjs +112 -146
  51. package/dist/mjs/toolbar/localization.mjs +2 -2
  52. package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +1 -1
  53. package/dist/mjs/toolbar/widgets/BaseWidget.mjs +1 -1
  54. package/dist/mjs/tools/PanZoom.mjs +1 -1
  55. package/dist/mjs/tools/Pen.d.ts +13 -0
  56. package/dist/mjs/tools/Pen.mjs +13 -0
  57. package/dist/mjs/tools/lib.d.ts +1 -0
  58. package/dist/mjs/tools/lib.mjs +1 -0
  59. package/dist/mjs/util/cloneElementWithStyles.mjs +1 -1
  60. package/dist/mjs/util/createElement.d.ts +62 -0
  61. package/dist/mjs/util/createElement.mjs +47 -0
  62. package/dist/mjs/version.mjs +1 -1
  63. package/package.json +4 -4
@@ -411,9 +411,7 @@ export declare class Editor {
411
411
  * Use this to show finalized commands that don't need to have `announceForAccessibility`
412
412
  * called.
413
413
  *
414
- * Prefer `command.apply(editor)` for incomplete commands. `dispatchNoAnnounce` may allow
415
- * clients to listen for the application of commands (e.g. `SerializableCommand`s so they can
416
- * be sent across the network), while `apply` does not.
414
+ * If `addToHistory` is `false`, this is equivalent to `command.apply(editor)`.
417
415
  *
418
416
  * @example
419
417
  * ```
@@ -137,7 +137,7 @@ class Editor {
137
137
  maxZoom: settings.maxZoom ?? 1e12,
138
138
  keyboardShortcutOverrides: settings.keyboardShortcutOverrides ?? {},
139
139
  iconProvider: settings.iconProvider ?? new IconProvider_1.default(),
140
- notices: [],
140
+ notices: settings.notices ?? [],
141
141
  appInfo: settings.appInfo ? { ...settings.appInfo } : null,
142
142
  pens: {
143
143
  additionalPenTypes: settings.pens?.additionalPenTypes ?? [],
@@ -755,9 +755,7 @@ class Editor {
755
755
  * Use this to show finalized commands that don't need to have `announceForAccessibility`
756
756
  * called.
757
757
  *
758
- * Prefer `command.apply(editor)` for incomplete commands. `dispatchNoAnnounce` may allow
759
- * clients to listen for the application of commands (e.g. `SerializableCommand`s so they can
760
- * be sent across the network), while `apply` does not.
758
+ * If `addToHistory` is `false`, this is equivalent to `command.apply(editor)`.
761
759
  *
762
760
  * @example
763
761
  * ```
@@ -561,6 +561,7 @@ class SVGLoader {
561
561
  const { svgElem, cleanUp } = (() => {
562
562
  // If the user requested an iframe load (the default) try to load with an iframe.
563
563
  // There are some cases (e.g. in a sandboxed iframe) where this doesn't work.
564
+ // TODO(v2): Use domParserLoad by default.
564
565
  if (!domParserLoad) {
565
566
  try {
566
567
  const sandbox = document.createElement('iframe');
@@ -600,6 +601,7 @@ class SVGLoader {
600
601
  `);
601
602
  sandboxDoc.close();
602
603
  const svgElem = sandboxDoc.createElementNS('http://www.w3.org/2000/svg', 'svg');
604
+ // eslint-disable-next-line no-unsanitized/property -- setting innerHTML in a sandboxed document.
603
605
  svgElem.innerHTML = text;
604
606
  sandboxDoc.body.appendChild(svgElem);
605
607
  const cleanUp = () => {
@@ -53,7 +53,7 @@ export declare class Viewport {
53
53
  /**
54
54
  * Snaps `canvasPos` to the nearest grid cell corner.
55
55
  *
56
- * @see {@link getGridSize} and {@link getScaleFactorToNearestPowerOf}.
56
+ * @see {@link getGridSize}.
57
57
  */
58
58
  snapToGrid(canvasPos: Point2): {
59
59
  readonly x: number;
@@ -107,7 +107,7 @@ class Viewport {
107
107
  /**
108
108
  * Snaps `canvasPos` to the nearest grid cell corner.
109
109
  *
110
- * @see {@link getGridSize} and {@link getScaleFactorToNearestPowerOf}.
110
+ * @see {@link getGridSize}.
111
111
  */
112
112
  snapToGrid(canvasPos) {
113
113
  const scaleFactor = this.getScaleFactorToNearestPowerOf(2);
@@ -122,7 +122,7 @@ export default abstract class AbstractComponent {
122
122
  * updates the editor.
123
123
  *
124
124
  * The transformed component is also moved to the top (use
125
- * {@link AbstractComponent.setZIndexAndTransformBy} to avoid this behavior).
125
+ * {@link AbstractComponent#setZIndexAndTransformBy} to avoid this behavior).
126
126
  */
127
127
  transformBy(affineTransfm: Mat33): SerializableCommand;
128
128
  setZIndex(newZIndex: number): SerializableCommand;
@@ -162,7 +162,7 @@ class AbstractComponent {
162
162
  * updates the editor.
163
163
  *
164
164
  * The transformed component is also moved to the top (use
165
- * {@link AbstractComponent.setZIndexAndTransformBy} to avoid this behavior).
165
+ * {@link AbstractComponent#setZIndexAndTransformBy} to avoid this behavior).
166
166
  */
167
167
  transformBy(affineTransfm) {
168
168
  return new AbstractComponent.TransformElementCommand(affineTransfm, this.getId(), this);
@@ -5,7 +5,7 @@ import Viewport from '../../Viewport';
5
5
  import AbstractComponent from '../AbstractComponent';
6
6
  import { ComponentBuilder, ComponentBuilderFactory } from './types';
7
7
  /**
8
- * Creates a stroke builder that generates arrows circles.
8
+ * Creates a stroke builder that generates arrows.
9
9
  *
10
10
  * Example:
11
11
  * [[include:doc-pages/inline-examples/changing-pen-types.md]]
@@ -8,7 +8,7 @@ const math_1 = require("@js-draw/math");
8
8
  const Stroke_1 = __importDefault(require("../Stroke"));
9
9
  const makeSnapToGridAutocorrect_1 = __importDefault(require("./autocorrect/makeSnapToGridAutocorrect"));
10
10
  /**
11
- * Creates a stroke builder that generates arrows circles.
11
+ * Creates a stroke builder that generates arrows.
12
12
  *
13
13
  * Example:
14
14
  * [[include:doc-pages/inline-examples/changing-pen-types.md]]
@@ -22,7 +22,20 @@ export type EditorImageNotifier = EventDispatcher<EditorImageEventType, {
22
22
  */
23
23
  export type PreRenderComponentCallback = (component: AbstractComponent, componentsProcessed: number, totalComponents: number) => Promise<boolean>;
24
24
  /**
25
- * Handles lookup/storage of elements in the image.
25
+ * @summary Handles lookup/storage of elements in the image.
26
+ *
27
+ * `js-draw` images are made up of a collection of {@link AbstractComponent}s (which
28
+ * includes {@link Stroke}s, {@link TextComponent}s, etc.). An `EditorImage`
29
+ * is the data structure that stores these components.
30
+ *
31
+ * Here's how to do a few common operations:
32
+ * - **Get all components in a {@link @js-draw/math!Rect2 | Rect2}**:
33
+ * {@link EditorImage.getElementsIntersectingRegion}.
34
+ * - **Draw an `EditorImage` onto a canvas/SVG**: {@link EditorImage.render}.
35
+ * - **Adding a new component**: {@link EditorImage.addElement}.
36
+ *
37
+ * **Example**:
38
+ * [[include:doc-pages/inline-examples/image-add-and-lookup.md]]
26
39
  */
27
40
  export default class EditorImage {
28
41
  private root;
@@ -40,10 +53,13 @@ export default class EditorImage {
40
53
  /** @internal */
41
54
  renderWithCache(screenRenderer: AbstractRenderer, cache: RenderingCache, viewport: Viewport): void;
42
55
  /**
43
- * Renders all nodes visible from `viewport` (or all nodes if `viewport = null`).
56
+ * Renders this image to the given `renderer`.
44
57
  *
45
- * `viewport` is used to improve rendering performance. If given, it must match
46
- * the viewport used by the `renderer` (if any).
58
+ * If `viewport` is non-null, only components that can be seen from that viewport
59
+ * will be rendered. If `viewport` is `null`, **all** components are rendered.
60
+ *
61
+ * **Example**:
62
+ * [[include:doc-pages/inline-examples/canvas-renderer.md]]
47
63
  */
48
64
  render(renderer: AbstractRenderer, viewport: Viewport | null): void;
49
65
  /**
@@ -63,14 +79,21 @@ export default class EditorImage {
63
79
  */
64
80
  renderAll(renderer: AbstractRenderer): void;
65
81
  /**
66
- * @returns all elements in the image, sorted by z-index. This can be slow for large images.
82
+ * @returns all elements in the image, sorted by z-index (low to high).
67
83
  *
68
- * Does not include background elements. See {@link getBackgroundComponents}.
84
+ * This can be slow for large images. If you only need all elemenst in part of the image,
85
+ * consider using {@link getElementsIntersectingRegion} instead.
86
+ *
87
+ * **Note**: The result does not include background elements. See {@link getBackgroundComponents}.
69
88
  */
70
89
  getAllElements(): AbstractComponent[];
71
90
  /** Returns the number of elements added to this image. @internal */
72
91
  estimateNumElements(): number;
73
- /** @returns a list of `AbstractComponent`s intersecting `region`, sorted by z-index. */
92
+ /**
93
+ * @returns a list of `AbstractComponent`s intersecting `region`, sorted by increasing z-index.
94
+ *
95
+ * Components in the background layer are only included if `includeBackground` is `true`.
96
+ */
74
97
  getElementsIntersectingRegion(region: Rect2, includeBackground?: boolean): AbstractComponent[];
75
98
  /** Called whenever (just after) an element is completely removed. @internal */
76
99
  onDestroyElement(elem: AbstractComponent): void;
@@ -51,7 +51,20 @@ var EditorImageEventType;
51
51
  })(EditorImageEventType || (exports.EditorImageEventType = EditorImageEventType = {}));
52
52
  let debugMode = false;
53
53
  /**
54
- * Handles lookup/storage of elements in the image.
54
+ * @summary Handles lookup/storage of elements in the image.
55
+ *
56
+ * `js-draw` images are made up of a collection of {@link AbstractComponent}s (which
57
+ * includes {@link Stroke}s, {@link TextComponent}s, etc.). An `EditorImage`
58
+ * is the data structure that stores these components.
59
+ *
60
+ * Here's how to do a few common operations:
61
+ * - **Get all components in a {@link @js-draw/math!Rect2 | Rect2}**:
62
+ * {@link EditorImage.getElementsIntersectingRegion}.
63
+ * - **Draw an `EditorImage` onto a canvas/SVG**: {@link EditorImage.render}.
64
+ * - **Adding a new component**: {@link EditorImage.addElement}.
65
+ *
66
+ * **Example**:
67
+ * [[include:doc-pages/inline-examples/image-add-and-lookup.md]]
55
68
  */
56
69
  class EditorImage {
57
70
  // @internal
@@ -110,10 +123,13 @@ class EditorImage {
110
123
  }
111
124
  }
112
125
  /**
113
- * Renders all nodes visible from `viewport` (or all nodes if `viewport = null`).
126
+ * Renders this image to the given `renderer`.
114
127
  *
115
- * `viewport` is used to improve rendering performance. If given, it must match
116
- * the viewport used by the `renderer` (if any).
128
+ * If `viewport` is non-null, only components that can be seen from that viewport
129
+ * will be rendered. If `viewport` is `null`, **all** components are rendered.
130
+ *
131
+ * **Example**:
132
+ * [[include:doc-pages/inline-examples/canvas-renderer.md]]
117
133
  */
118
134
  render(renderer, viewport) {
119
135
  this.background.render(renderer, viewport?.visibleRect);
@@ -144,9 +160,12 @@ class EditorImage {
144
160
  this.render(renderer, null);
145
161
  }
146
162
  /**
147
- * @returns all elements in the image, sorted by z-index. This can be slow for large images.
163
+ * @returns all elements in the image, sorted by z-index (low to high).
148
164
  *
149
- * Does not include background elements. See {@link getBackgroundComponents}.
165
+ * This can be slow for large images. If you only need all elemenst in part of the image,
166
+ * consider using {@link getElementsIntersectingRegion} instead.
167
+ *
168
+ * **Note**: The result does not include background elements. See {@link getBackgroundComponents}.
150
169
  */
151
170
  getAllElements() {
152
171
  const leaves = this.root.getLeaves();
@@ -157,7 +176,11 @@ class EditorImage {
157
176
  estimateNumElements() {
158
177
  return this.componentCount;
159
178
  }
160
- /** @returns a list of `AbstractComponent`s intersecting `region`, sorted by z-index. */
179
+ /**
180
+ * @returns a list of `AbstractComponent`s intersecting `region`, sorted by increasing z-index.
181
+ *
182
+ * Components in the background layer are only included if `includeBackground` is `true`.
183
+ */
161
184
  getElementsIntersectingRegion(region, includeBackground = false) {
162
185
  let leaves = this.root.getLeavesIntersectingRegion(region);
163
186
  if (includeBackground) {
@@ -7,31 +7,8 @@ import RenderablePathSpec from '../RenderablePathSpec';
7
7
  /**
8
8
  * Renders onto a `CanvasRenderingContext2D`.
9
9
  *
10
- * @example
11
- * ```ts,runnable
12
- * import {Editor,CanvasRenderer} from 'js-draw';
13
- *
14
- * // Create an editor and load initial data -- don't add to the body (hidden editor).
15
- * const editor = new Editor(document.createElement('div'));
16
- * await editor.loadFromSVG('<svg><path d="m0,0 l100,5 l-50,60 l30,20 z" fill="green"/></svg>');
17
- * ---visible---
18
- * // Given some editor.
19
- * // Set up the canvas to be drawn onto.
20
- * const canvas = document.createElement('canvas');
21
- * const ctx = canvas.getContext('2d');
22
- *
23
- * // Ensure that the canvas can fit the entire rendering
24
- * const viewport = editor.image.getImportExportViewport();
25
- * canvas.width = viewport.getScreenRectSize().x;
26
- * canvas.height = viewport.getScreenRectSize().y;
27
- *
28
- * // Render editor.image onto the renderer
29
- * const renderer = new CanvasRenderer(ctx, viewport);
30
- * editor.image.render(renderer, viewport);
31
- *
32
- * // Add the rendered canvas to the document.
33
- * document.body.appendChild(canvas);
34
- * ```
10
+ * **Example**:
11
+ * [[include:doc-pages/inline-examples/canvas-renderer.md]]
35
12
  */
36
13
  export default class CanvasRenderer extends AbstractRenderer {
37
14
  private ctx;
@@ -10,31 +10,8 @@ const RenderablePathSpec_1 = require("../RenderablePathSpec");
10
10
  /**
11
11
  * Renders onto a `CanvasRenderingContext2D`.
12
12
  *
13
- * @example
14
- * ```ts,runnable
15
- * import {Editor,CanvasRenderer} from 'js-draw';
16
- *
17
- * // Create an editor and load initial data -- don't add to the body (hidden editor).
18
- * const editor = new Editor(document.createElement('div'));
19
- * await editor.loadFromSVG('<svg><path d="m0,0 l100,5 l-50,60 l30,20 z" fill="green"/></svg>');
20
- * ---visible---
21
- * // Given some editor.
22
- * // Set up the canvas to be drawn onto.
23
- * const canvas = document.createElement('canvas');
24
- * const ctx = canvas.getContext('2d');
25
- *
26
- * // Ensure that the canvas can fit the entire rendering
27
- * const viewport = editor.image.getImportExportViewport();
28
- * canvas.width = viewport.getScreenRectSize().x;
29
- * canvas.height = viewport.getScreenRectSize().y;
30
- *
31
- * // Render editor.image onto the renderer
32
- * const renderer = new CanvasRenderer(ctx, viewport);
33
- * editor.image.render(renderer, viewport);
34
- *
35
- * // Add the rendered canvas to the document.
36
- * document.body.appendChild(canvas);
37
- * ```
13
+ * **Example**:
14
+ * [[include:doc-pages/inline-examples/canvas-renderer.md]]
38
15
  */
39
16
  class CanvasRenderer extends AbstractRenderer_1.default {
40
17
  /**
@@ -49,7 +49,7 @@ class SVGRenderer extends AbstractRenderer_1.default {
49
49
  if (!this.elem.querySelector(`#${exports.renderedStylesheetId}`)) {
50
50
  // Default to rounded strokes.
51
51
  const styleSheet = document.createElementNS('http://www.w3.org/2000/svg', 'style');
52
- styleSheet.innerHTML = `
52
+ styleSheet.appendChild(document.createTextNode(`
53
53
  path {
54
54
  stroke-linecap: round;
55
55
  stroke-linejoin: round;
@@ -58,7 +58,7 @@ class SVGRenderer extends AbstractRenderer_1.default {
58
58
  text {
59
59
  white-space: pre;
60
60
  }
61
- `.replace(/\s+/g, '');
61
+ `.replace(/\s+/g, '')));
62
62
  styleSheet.setAttribute('id', exports.renderedStylesheetId);
63
63
  this.elem.appendChild(styleSheet);
64
64
  }
@@ -110,6 +110,25 @@ export default abstract class AbstractToolbar {
110
110
  * as being the value of `mustBeToplevel`.
111
111
  *
112
112
  * @return The added button.
113
+ *
114
+ * **Example**:
115
+ * ```ts,runnable
116
+ * import { Editor } from 'js-draw';
117
+ * const editor = new Editor(document.body);
118
+ * const toolbar = editor.addToolbar();
119
+ *
120
+ * function makeTrashIcon() {
121
+ * const container = document.createElement('div');
122
+ * container.textContent = '🗑️';
123
+ * return container;
124
+ * }
125
+ *
126
+ * toolbar.addActionButton({
127
+ * icon: makeTrashIcon(), // can be any Element not in the DOM
128
+ * label: 'Delete all',
129
+ * }, () => {
130
+ * alert('to-do!');
131
+ * });
113
132
  */
114
133
  addActionButton(title: string | ActionButtonIcon, command: () => void, options?: ToolbarActionButtonOptions | boolean): BaseWidget;
115
134
  /**
@@ -269,6 +269,25 @@ class AbstractToolbar {
269
269
  * as being the value of `mustBeToplevel`.
270
270
  *
271
271
  * @return The added button.
272
+ *
273
+ * **Example**:
274
+ * ```ts,runnable
275
+ * import { Editor } from 'js-draw';
276
+ * const editor = new Editor(document.body);
277
+ * const toolbar = editor.addToolbar();
278
+ *
279
+ * function makeTrashIcon() {
280
+ * const container = document.createElement('div');
281
+ * container.textContent = '🗑️';
282
+ * return container;
283
+ * }
284
+ *
285
+ * toolbar.addActionButton({
286
+ * icon: makeTrashIcon(), // can be any Element not in the DOM
287
+ * label: 'Delete all',
288
+ * }, () => {
289
+ * alert('to-do!');
290
+ * });
272
291
  */
273
292
  addActionButton(title, command, options = true) {
274
293
  const widget = this.makeActionButton(title, command, options);
@@ -80,9 +80,13 @@ export default class IconProvider {
80
80
  * @returns An object with both the definition of a checkerboard pattern and the syntax to
81
81
  * reference that pattern. The defs provided by this function should be wrapped within a
82
82
  * `<defs></defs>` element.
83
+ *
84
+ * **Note**: This function's return value includes both `patternDefElement` (which returns
85
+ * an Element) and a (deprecated) `patternDef` string. Avoid using the `patternDef` result.
83
86
  */
84
87
  protected makeCheckerboardPattern(): {
85
- patternDef: string;
88
+ patternDefElement: SVGElement;
89
+ readonly patternDef: string;
86
90
  patternRef: string;
87
91
  };
88
92
  /**