js-draw 0.4.1 → 0.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 (86) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/bundle.js +1 -1
  3. package/dist/src/Editor.d.ts +9 -6
  4. package/dist/src/Editor.js +9 -3
  5. package/dist/src/EditorImage.d.ts +3 -0
  6. package/dist/src/EditorImage.js +7 -0
  7. package/dist/src/SVGLoader.js +5 -6
  8. package/dist/src/components/AbstractComponent.d.ts +1 -0
  9. package/dist/src/components/AbstractComponent.js +4 -0
  10. package/dist/src/components/SVGGlobalAttributesObject.d.ts +1 -0
  11. package/dist/src/components/SVGGlobalAttributesObject.js +3 -0
  12. package/dist/src/components/Text.d.ts +3 -5
  13. package/dist/src/components/Text.js +19 -10
  14. package/dist/src/components/UnknownSVGObject.d.ts +1 -0
  15. package/dist/src/components/UnknownSVGObject.js +3 -0
  16. package/dist/src/components/builders/FreehandLineBuilder.js +3 -3
  17. package/dist/src/rendering/renderers/SVGRenderer.js +1 -1
  18. package/dist/src/testing/beforeEachFile.js +4 -0
  19. package/dist/src/toolbar/HTMLToolbar.js +2 -3
  20. package/dist/src/toolbar/IconProvider.d.ts +24 -0
  21. package/dist/src/toolbar/IconProvider.js +415 -0
  22. package/dist/src/toolbar/lib.d.ts +1 -1
  23. package/dist/src/toolbar/lib.js +1 -2
  24. package/dist/src/toolbar/localization.d.ts +0 -1
  25. package/dist/src/toolbar/localization.js +0 -1
  26. package/dist/src/toolbar/makeColorInput.js +1 -2
  27. package/dist/src/toolbar/widgets/BaseWidget.d.ts +2 -0
  28. package/dist/src/toolbar/widgets/BaseWidget.js +16 -2
  29. package/dist/src/toolbar/widgets/EraserToolWidget.js +1 -2
  30. package/dist/src/toolbar/widgets/HandToolWidget.d.ts +5 -3
  31. package/dist/src/toolbar/widgets/HandToolWidget.js +35 -12
  32. package/dist/src/toolbar/widgets/PenToolWidget.d.ts +2 -0
  33. package/dist/src/toolbar/widgets/PenToolWidget.js +16 -3
  34. package/dist/src/toolbar/widgets/SelectionToolWidget.d.ts +3 -0
  35. package/dist/src/toolbar/widgets/SelectionToolWidget.js +20 -7
  36. package/dist/src/toolbar/widgets/TextToolWidget.js +1 -2
  37. package/dist/src/tools/PanZoom.d.ts +1 -1
  38. package/dist/src/tools/PanZoom.js +4 -1
  39. package/dist/src/tools/SelectionTool/SelectionTool.d.ts +3 -0
  40. package/dist/src/tools/SelectionTool/SelectionTool.js +66 -3
  41. package/dist/src/tools/ToolController.js +3 -0
  42. package/dist/src/tools/ToolbarShortcutHandler.d.ts +12 -0
  43. package/dist/src/tools/ToolbarShortcutHandler.js +23 -0
  44. package/dist/src/tools/lib.d.ts +1 -0
  45. package/dist/src/tools/lib.js +1 -0
  46. package/dist/src/tools/localization.d.ts +1 -0
  47. package/dist/src/tools/localization.js +1 -0
  48. package/dist/src/types.d.ts +4 -2
  49. package/package.json +1 -1
  50. package/src/Editor.ts +17 -7
  51. package/src/EditorImage.ts +9 -0
  52. package/src/SVGLoader.test.ts +37 -0
  53. package/src/SVGLoader.ts +5 -6
  54. package/src/components/AbstractComponent.ts +5 -0
  55. package/src/components/SVGGlobalAttributesObject.ts +4 -0
  56. package/src/components/Text.test.ts +1 -16
  57. package/src/components/Text.ts +21 -11
  58. package/src/components/UnknownSVGObject.ts +4 -0
  59. package/src/components/builders/FreehandLineBuilder.ts +3 -3
  60. package/src/rendering/renderers/SVGRenderer.ts +1 -1
  61. package/src/testing/beforeEachFile.ts +6 -1
  62. package/src/toolbar/HTMLToolbar.ts +2 -3
  63. package/src/toolbar/IconProvider.ts +476 -0
  64. package/src/toolbar/lib.ts +1 -1
  65. package/src/toolbar/localization.ts +0 -2
  66. package/src/toolbar/makeColorInput.ts +1 -2
  67. package/src/toolbar/widgets/BaseWidget.ts +20 -3
  68. package/src/toolbar/widgets/EraserToolWidget.ts +1 -2
  69. package/src/toolbar/widgets/HandToolWidget.ts +42 -20
  70. package/src/toolbar/widgets/PenToolWidget.ts +20 -4
  71. package/src/toolbar/widgets/SelectionToolWidget.ts +24 -8
  72. package/src/toolbar/widgets/TextToolWidget.ts +1 -2
  73. package/src/tools/PanZoom.ts +4 -1
  74. package/src/tools/SelectionTool/SelectionTool.css +2 -1
  75. package/src/tools/SelectionTool/SelectionTool.test.ts +40 -0
  76. package/src/tools/SelectionTool/SelectionTool.ts +73 -4
  77. package/src/tools/ToolController.ts +3 -0
  78. package/src/tools/ToolbarShortcutHandler.ts +34 -0
  79. package/src/tools/UndoRedoShortcut.test.ts +3 -0
  80. package/src/tools/lib.ts +1 -0
  81. package/src/tools/localization.ts +4 -0
  82. package/src/types.ts +13 -8
  83. package/typedoc.json +5 -1
  84. package/dist/src/toolbar/icons.d.ts +0 -20
  85. package/dist/src/toolbar/icons.js +0 -385
  86. package/src/toolbar/icons.ts +0 -443
@@ -28,6 +28,7 @@ import Display, { RenderingMode } from './rendering/Display';
28
28
  import Pointer from './Pointer';
29
29
  import Rect2 from './math/Rect2';
30
30
  import { EditorLocalization } from './localization';
31
+ import IconProvider from './toolbar/IconProvider';
31
32
  declare type HTMLPointerEventType = 'pointerdown' | 'pointermove' | 'pointerup' | 'pointercancel';
32
33
  declare type HTMLPointerEventFilter = (eventName: HTMLPointerEventType, event: PointerEvent) => boolean;
33
34
  export interface EditorSettings {
@@ -44,6 +45,7 @@ export interface EditorSettings {
44
45
  /** Minimum zoom fraction (e.g. 0.5 → 50% zoom). */
45
46
  minZoom: number;
46
47
  maxZoom: number;
48
+ iconProvider: IconProvider;
47
49
  }
48
50
  export declare class Editor {
49
51
  private container;
@@ -81,18 +83,19 @@ export declare class Editor {
81
83
  * editor.dispatch(addElementCommand);
82
84
  * ```
83
85
  */
84
- image: EditorImage;
86
+ readonly image: EditorImage;
85
87
  /** Viewport for the exported/imported image. */
86
88
  private importExportViewport;
87
89
  /** @internal */
88
- localization: EditorLocalization;
89
- viewport: Viewport;
90
- toolController: ToolController;
90
+ readonly localization: EditorLocalization;
91
+ readonly icons: IconProvider;
92
+ readonly viewport: Viewport;
93
+ readonly toolController: ToolController;
91
94
  /**
92
95
  * Global event dispatcher/subscriber.
93
96
  * @see {@link types.EditorEventType}
94
97
  */
95
- notifier: EditorNotifier;
98
+ readonly notifier: EditorNotifier;
96
99
  private loadingWarning;
97
100
  private accessibilityAnnounceArea;
98
101
  private accessibilityControlArea;
@@ -193,7 +196,7 @@ export declare class Editor {
193
196
  remove: () => void;
194
197
  };
195
198
  addStyleSheet(content: string): HTMLStyleElement;
196
- sendKeyboardEvent(eventType: InputEvtType.KeyPressEvent | InputEvtType.KeyUpEvent, key: string, ctrlKey?: boolean): void;
199
+ sendKeyboardEvent(eventType: InputEvtType.KeyPressEvent | InputEvtType.KeyUpEvent, key: string, ctrlKey?: boolean, altKey?: boolean): void;
197
200
  sendPenEvent(eventType: InputEvtType.PointerDownEvt | InputEvtType.PointerMoveEvt | InputEvtType.PointerUpEvt, point: Point2, allPointers?: Pointer[]): void;
198
201
  toSVG(): SVGElement;
199
202
  loadFrom(loader: ImageLoader): Promise<void>;
@@ -41,6 +41,7 @@ import SVGLoader from './SVGLoader';
41
41
  import Pointer from './Pointer';
42
42
  import Mat33 from './math/Mat33';
43
43
  import getLocalizationTable from './localizations/getLocalizationTable';
44
+ import IconProvider from './toolbar/IconProvider';
44
45
  // { @inheritDoc Editor! }
45
46
  export class Editor {
46
47
  /**
@@ -67,7 +68,7 @@ export class Editor {
67
68
  * ```
68
69
  */
69
70
  constructor(parent, settings = {}) {
70
- var _a, _b, _c, _d;
71
+ var _a, _b, _c, _d, _e;
71
72
  this.eventListenerTargets = [];
72
73
  this.previousAccessibilityAnnouncement = '';
73
74
  this.pointers = {};
@@ -86,7 +87,9 @@ export class Editor {
86
87
  localization: this.localization,
87
88
  minZoom: (_c = settings.minZoom) !== null && _c !== void 0 ? _c : 2e-10,
88
89
  maxZoom: (_d = settings.maxZoom) !== null && _d !== void 0 ? _d : 1e12,
90
+ iconProvider: (_e = settings.iconProvider) !== null && _e !== void 0 ? _e : new IconProvider(),
89
91
  };
92
+ this.icons = this.settings.iconProvider;
90
93
  this.container = document.createElement('div');
91
94
  this.renderingRegion = document.createElement('div');
92
95
  this.container.appendChild(this.renderingRegion);
@@ -441,6 +444,7 @@ export class Editor {
441
444
  kind: InputEvtType.KeyPressEvent,
442
445
  key: evt.key,
443
446
  ctrlKey: evt.ctrlKey,
447
+ altKey: evt.altKey,
444
448
  })) {
445
449
  evt.preventDefault();
446
450
  }
@@ -453,6 +457,7 @@ export class Editor {
453
457
  kind: InputEvtType.KeyUpEvent,
454
458
  key: evt.key,
455
459
  ctrlKey: evt.ctrlKey,
460
+ altKey: evt.altKey,
456
461
  })) {
457
462
  evt.preventDefault();
458
463
  }
@@ -598,11 +603,12 @@ export class Editor {
598
603
  }
599
604
  // Dispatch a keyboard event to the currently selected tool.
600
605
  // Intended for unit testing
601
- sendKeyboardEvent(eventType, key, ctrlKey = false) {
606
+ sendKeyboardEvent(eventType, key, ctrlKey = false, altKey = false) {
602
607
  this.toolController.dispatchInputEvent({
603
608
  kind: eventType,
604
609
  key,
605
- ctrlKey
610
+ ctrlKey,
611
+ altKey,
606
612
  });
607
613
  }
608
614
  // Dispatch a pen event to the currently selected tool.
@@ -16,6 +16,9 @@ export default class EditorImage {
16
16
  render(renderer: AbstractRenderer, viewport: Viewport): void;
17
17
  /** Renders all nodes, even ones not within the viewport. @internal */
18
18
  renderAll(renderer: AbstractRenderer): void;
19
+ /** @returns all elements in the image, sorted by z-index. This can be slow for large images. */
20
+ getAllElements(): AbstractComponent[];
21
+ /** @returns a list of `AbstractComponent`s intersecting `region`, sorted by z-index. */
19
22
  getElementsIntersectingRegion(region: Rect2): AbstractComponent[];
20
23
  /** @internal */
21
24
  onDestroyElement(elem: AbstractComponent): void;
@@ -39,6 +39,13 @@ export default class EditorImage {
39
39
  leaf.getContent().render(renderer, leaf.getBBox());
40
40
  }
41
41
  }
42
+ /** @returns all elements in the image, sorted by z-index. This can be slow for large images. */
43
+ getAllElements() {
44
+ const leaves = this.root.getLeaves();
45
+ sortLeavesByZIndex(leaves);
46
+ return leaves.map(leaf => leaf.getContent());
47
+ }
48
+ /** @returns a list of `AbstractComponent`s intersecting `region`, sorted by z-index. */
42
49
  getElementsIntersectingRegion(region) {
43
50
  const leaves = this.root.getLeavesIntersectingRegion(region);
44
51
  sortLeavesByZIndex(leaves);
@@ -99,7 +99,7 @@ export default class SVGLoader {
99
99
  }
100
100
  elem.attachLoadSaveData(svgAttributesDataKey, [attr, node.getAttribute(attr)]);
101
101
  }
102
- if (supportedStyleAttrs) {
102
+ if (supportedStyleAttrs && node.style) {
103
103
  for (const attr of node.style) {
104
104
  if (attr === '' || !attr) {
105
105
  continue;
@@ -157,9 +157,9 @@ export default class SVGLoader {
157
157
  }
158
158
  const elemX = elem.getAttribute('x');
159
159
  const elemY = elem.getAttribute('y');
160
- if (elemX && elemY) {
161
- const x = parseFloat(elemX);
162
- const y = parseFloat(elemY);
160
+ if (elemX || elemY) {
161
+ const x = parseFloat(elemX !== null && elemX !== void 0 ? elemX : '0');
162
+ const y = parseFloat(elemY !== null && elemY !== void 0 ? elemY : '0');
163
163
  if (!isNaN(x) && !isNaN(y)) {
164
164
  supportedAttrs === null || supportedAttrs === void 0 ? void 0 : supportedAttrs.push('x', 'y');
165
165
  transform = transform.rightMul(Mat33.translation(Vec2.of(x, y)));
@@ -204,7 +204,7 @@ export default class SVGLoader {
204
204
  size: fontSize,
205
205
  fontFamily: computedStyles.fontFamily || elem.style.fontFamily || 'sans-serif',
206
206
  renderingStyle: {
207
- fill: Color4.fromString(computedStyles.fill)
207
+ fill: Color4.fromString(computedStyles.fill || elem.style.fill || '#000')
208
208
  },
209
209
  };
210
210
  const supportedAttrs = [];
@@ -339,7 +339,6 @@ export default class SVGLoader {
339
339
  (_b = this.onFinish) === null || _b === void 0 ? void 0 : _b.call(this);
340
340
  });
341
341
  }
342
- // TODO: Handling unsafe data! Tripple-check that this is secure!
343
342
  // @param sanitize - if `true`, don't store unknown attributes.
344
343
  static fromString(text, sanitize = false) {
345
344
  var _a, _b;
@@ -28,6 +28,7 @@ export default abstract class AbstractComponent {
28
28
  protected abstract serializeToJSON(): any[] | Record<string, any> | number | string | null;
29
29
  protected abstract applyTransformation(affineTransfm: Mat33): void;
30
30
  transformBy(affineTransfm: Mat33): SerializableCommand;
31
+ isSelectable(): boolean;
31
32
  private static transformElementCommandId;
32
33
  private static UnresolvedTransformElementCommand;
33
34
  private static TransformElementCommand;
@@ -48,6 +48,10 @@ export default class AbstractComponent {
48
48
  transformBy(affineTransfm) {
49
49
  return new AbstractComponent.TransformElementCommand(affineTransfm, this);
50
50
  }
51
+ // @returns true iff this component can be selected (e.g. by the selection tool.)
52
+ isSelectable() {
53
+ return true;
54
+ }
51
55
  // Returns a copy of this component.
52
56
  clone() {
53
57
  const clone = this.createClone();
@@ -12,6 +12,7 @@ export default class SVGGlobalAttributesObject extends AbstractComponent {
12
12
  render(canvas: AbstractRenderer, _visibleRect?: Rect2): void;
13
13
  intersects(_lineSegment: LineSegment2): boolean;
14
14
  protected applyTransformation(_affineTransfm: Mat33): void;
15
+ isSelectable(): boolean;
15
16
  protected createClone(): SVGGlobalAttributesObject;
16
17
  description(localization: ImageComponentLocalization): string;
17
18
  protected serializeToJSON(): string | null;
@@ -29,6 +29,9 @@ export default class SVGGlobalAttributesObject extends AbstractComponent {
29
29
  }
30
30
  applyTransformation(_affineTransfm) {
31
31
  }
32
+ isSelectable() {
33
+ return false;
34
+ }
32
35
  createClone() {
33
36
  return new SVGGlobalAttributesObject(this.attrs);
34
37
  }
@@ -12,16 +12,15 @@ export interface TextStyle {
12
12
  fontVariant?: string;
13
13
  renderingStyle: RenderingStyle;
14
14
  }
15
- declare type GetTextDimensCallback = (text: string, style: TextStyle) => Rect2;
16
15
  export default class Text extends AbstractComponent {
17
16
  protected readonly textObjects: Array<string | Text>;
18
17
  private transform;
19
18
  private readonly style;
20
- private readonly getTextDimens;
21
19
  protected contentBBox: Rect2;
22
- constructor(textObjects: Array<string | Text>, transform: Mat33, style: TextStyle, getTextDimens?: GetTextDimensCallback);
20
+ constructor(textObjects: Array<string | Text>, transform: Mat33, style: TextStyle);
23
21
  static applyTextStyles(ctx: CanvasRenderingContext2D, style: TextStyle): void;
24
22
  private static textMeasuringCtx;
23
+ private static estimateTextDimens;
25
24
  private static getTextDimens;
26
25
  private computeBBoxOfPart;
27
26
  private recomputeBBox;
@@ -32,6 +31,5 @@ export default class Text extends AbstractComponent {
32
31
  getText(): string;
33
32
  description(localizationTable: ImageComponentLocalization): string;
34
33
  protected serializeToJSON(): Record<string, any>;
35
- static deserializeFromString(json: any, getTextDimens?: GetTextDimensCallback): Text;
34
+ static deserializeFromString(json: any): Text;
36
35
  }
37
- export {};
@@ -5,15 +5,11 @@ import { styleFromJSON, styleToJSON } from '../rendering/RenderingStyle';
5
5
  import AbstractComponent from './AbstractComponent';
6
6
  const componentTypeId = 'text';
7
7
  export default class Text extends AbstractComponent {
8
- constructor(textObjects, transform, style,
9
- // If not given, an HtmlCanvasElement is used to determine text boundaries.
10
- // @internal
11
- getTextDimens = Text.getTextDimens) {
8
+ constructor(textObjects, transform, style) {
12
9
  super(componentTypeId);
13
10
  this.textObjects = textObjects;
14
11
  this.transform = transform;
15
12
  this.style = style;
16
- this.getTextDimens = getTextDimens;
17
13
  this.recomputeBBox();
18
14
  }
19
15
  static applyTextStyles(ctx, style) {
@@ -28,9 +24,21 @@ export default class Text extends AbstractComponent {
28
24
  ].join(' ');
29
25
  ctx.textAlign = 'left';
30
26
  }
27
+ // Roughly estimate the bounding box of `text`. Use if no CanvasRenderingContext2D is available.
28
+ static estimateTextDimens(text, style) {
29
+ const widthEst = text.length * style.size;
30
+ const heightEst = style.size;
31
+ // Text is drawn with (0, 0) as its baseline. As such, the majority of the text's height should
32
+ // be above (0, 0).
33
+ return new Rect2(0, -heightEst * 2 / 3, widthEst, heightEst);
34
+ }
35
+ // Returns the bounding box of `text`. This is approximate if no Canvas is available.
31
36
  static getTextDimens(text, style) {
32
- var _a;
33
- (_a = Text.textMeasuringCtx) !== null && _a !== void 0 ? _a : (Text.textMeasuringCtx = document.createElement('canvas').getContext('2d'));
37
+ var _a, _b;
38
+ (_a = Text.textMeasuringCtx) !== null && _a !== void 0 ? _a : (Text.textMeasuringCtx = (_b = document.createElement('canvas').getContext('2d')) !== null && _b !== void 0 ? _b : null);
39
+ if (!Text.textMeasuringCtx) {
40
+ return this.estimateTextDimens(text, style);
41
+ }
34
42
  const ctx = Text.textMeasuringCtx;
35
43
  Text.applyTextStyles(ctx, style);
36
44
  const measure = ctx.measureText(text);
@@ -41,7 +49,7 @@ export default class Text extends AbstractComponent {
41
49
  }
42
50
  computeBBoxOfPart(part) {
43
51
  if (typeof part === 'string') {
44
- const textBBox = this.getTextDimens(part, this.style);
52
+ const textBBox = Text.getTextDimens(part, this.style);
45
53
  return textBBox.transformedBoundingBox(this.transform);
46
54
  }
47
55
  else {
@@ -138,7 +146,7 @@ export default class Text extends AbstractComponent {
138
146
  style: serializableStyle,
139
147
  };
140
148
  }
141
- static deserializeFromString(json, getTextDimens = Text.getTextDimens) {
149
+ static deserializeFromString(json) {
142
150
  const style = {
143
151
  renderingStyle: styleFromJSON(json.style.renderingStyle),
144
152
  size: json.style.size,
@@ -159,7 +167,8 @@ export default class Text extends AbstractComponent {
159
167
  }
160
168
  const transformData = json.transform;
161
169
  const transform = new Mat33(...transformData);
162
- return new Text(textObjects, transform, style, getTextDimens);
170
+ return new Text(textObjects, transform, style);
163
171
  }
164
172
  }
173
+ Text.textMeasuringCtx = null;
165
174
  AbstractComponent.registerComponent(componentTypeId, (data) => Text.deserializeFromString(data));
@@ -11,6 +11,7 @@ export default class UnknownSVGObject extends AbstractComponent {
11
11
  render(canvas: AbstractRenderer, _visibleRect?: Rect2): void;
12
12
  intersects(lineSegment: LineSegment2): boolean;
13
13
  protected applyTransformation(_affineTransfm: Mat33): void;
14
+ isSelectable(): boolean;
14
15
  protected createClone(): AbstractComponent;
15
16
  description(localization: ImageComponentLocalization): string;
16
17
  protected serializeToJSON(): string | null;
@@ -25,6 +25,9 @@ export default class UnknownSVGObject extends AbstractComponent {
25
25
  }
26
26
  applyTransformation(_affineTransfm) {
27
27
  }
28
+ isSelectable() {
29
+ return false;
30
+ }
28
31
  createClone() {
29
32
  return new UnknownSVGObject(this.svgObject.cloneNode(true));
30
33
  }
@@ -312,15 +312,15 @@ export default class FreehandLineBuilder {
312
312
  }
313
313
  let enteringVec = this.lastExitingVec;
314
314
  if (!enteringVec) {
315
- let sampleIdx = Math.ceil(this.buffer.length / 3);
316
- if (sampleIdx === 0) {
315
+ let sampleIdx = Math.ceil(this.buffer.length / 2);
316
+ if (sampleIdx === 0 || sampleIdx >= this.buffer.length) {
317
317
  sampleIdx = this.buffer.length - 1;
318
318
  }
319
319
  enteringVec = this.buffer[sampleIdx].minus(this.buffer[0]);
320
320
  }
321
321
  let exitingVec = this.computeExitingVec();
322
322
  // Find the intersection between the entering vector and the exiting vector
323
- const maxRelativeLength = 3;
323
+ const maxRelativeLength = 2;
324
324
  const segmentStart = this.buffer[0];
325
325
  const segmentEnd = newPoint.pos;
326
326
  const startEndDist = segmentEnd.minus(segmentStart).magnitude();
@@ -72,7 +72,7 @@ export default class SVGRenderer extends AbstractRenderer {
72
72
  drawPath(pathSpec) {
73
73
  var _a;
74
74
  const style = pathSpec.style;
75
- const path = Path.fromRenderable(pathSpec);
75
+ const path = Path.fromRenderable(pathSpec).transformedBy(this.getCanvasToScreenTransform());
76
76
  // Try to extend the previous path, if possible
77
77
  if (!style.fill.eq((_a = this.lastPathStyle) === null || _a === void 0 ? void 0 : _a.fill) || this.lastPathString.length === 0) {
78
78
  this.addPathToSVG();
@@ -1,3 +1,7 @@
1
1
  import loadExpectExtensions from './loadExpectExtensions';
2
2
  loadExpectExtensions();
3
3
  jest.useFakeTimers();
4
+ // jsdom doesn't support HTMLCanvasElement#getContext — it logs an error
5
+ // to the console. Make it return null so we can handle a non-existent Canvas
6
+ // at runtime (e.g. use something else, if available).
7
+ HTMLCanvasElement.prototype.getContext = () => null;
@@ -2,7 +2,6 @@ import { EditorEventType } from '../types';
2
2
  import { coloris, init as colorisInit } from '@melloware/coloris';
3
3
  import Color4 from '../Color4';
4
4
  import { defaultToolbarLocalization } from './localization';
5
- import { makeRedoIcon, makeUndoIcon } from './icons';
6
5
  import SelectionTool from '../tools/SelectionTool/SelectionTool';
7
6
  import PanZoomTool from '../tools/PanZoom';
8
7
  import TextTool from '../tools/TextTool';
@@ -123,13 +122,13 @@ export default class HTMLToolbar {
123
122
  undoRedoGroup.classList.add(`${toolbarCSSPrefix}buttonGroup`);
124
123
  const undoButton = this.addActionButton({
125
124
  label: this.localizationTable.undo,
126
- icon: makeUndoIcon()
125
+ icon: this.editor.icons.makeUndoIcon()
127
126
  }, () => {
128
127
  this.editor.history.undo();
129
128
  }, undoRedoGroup);
130
129
  const redoButton = this.addActionButton({
131
130
  label: this.localizationTable.redo,
132
- icon: makeRedoIcon(),
131
+ icon: this.editor.icons.makeRedoIcon(),
133
132
  }, () => {
134
133
  this.editor.history.redo();
135
134
  }, undoRedoGroup);
@@ -0,0 +1,24 @@
1
+ import Color4 from '../Color4';
2
+ import { ComponentBuilderFactory } from '../components/builders/types';
3
+ import { TextStyle } from '../components/Text';
4
+ import Pen from '../tools/Pen';
5
+ export default class IconProvider {
6
+ makeUndoIcon(): SVGSVGElement;
7
+ makeRedoIcon(mirror?: boolean): SVGSVGElement;
8
+ makeDropdownIcon(): SVGSVGElement;
9
+ makeEraserIcon(): SVGSVGElement;
10
+ makeSelectionIcon(): SVGSVGElement;
11
+ protected makeIconFromPath(pathData: string, fill?: string, strokeColor?: string, strokeWidth?: string): SVGSVGElement;
12
+ makeHandToolIcon(): SVGSVGElement;
13
+ makeTouchPanningIcon(): SVGSVGElement;
14
+ makeAllDevicePanningIcon(): SVGSVGElement;
15
+ makeZoomIcon: () => SVGSVGElement;
16
+ makeTextIcon(textStyle: TextStyle): SVGSVGElement;
17
+ makePenIcon(tipThickness: number, color: string | Color4): SVGSVGElement;
18
+ makeIconFromFactory(pen: Pen, factory: ComponentBuilderFactory): SVGSVGElement;
19
+ makePipetteIcon(color?: Color4): SVGSVGElement;
20
+ makeResizeViewportIcon(): SVGSVGElement;
21
+ makeDuplicateSelectionIcon(): SVGSVGElement;
22
+ makeDeleteSelectionIcon(): SVGSVGElement;
23
+ makeSaveIcon(): SVGSVGElement;
24
+ }