js-draw 1.18.0 → 1.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. package/README.md +51 -0
  2. package/dist/Editor.css +78 -5
  3. package/dist/bundle.js +2 -2
  4. package/dist/bundledStyles.js +1 -1
  5. package/dist/cjs/Editor.d.ts +20 -1
  6. package/dist/cjs/Editor.js +6 -0
  7. package/dist/cjs/{SVGLoader.d.ts → SVGLoader/index.d.ts} +1 -1
  8. package/dist/cjs/{SVGLoader.js → SVGLoader/index.js} +15 -30
  9. package/dist/cjs/SVGLoader/utils/determineFontSize.d.ts +3 -0
  10. package/dist/cjs/SVGLoader/utils/determineFontSize.js +27 -0
  11. package/dist/cjs/Viewport.d.ts +33 -1
  12. package/dist/cjs/components/TextComponent.js +3 -1
  13. package/dist/cjs/image/EditorImage.d.ts +2 -1
  14. package/dist/cjs/image/EditorImage.js +101 -5
  15. package/dist/cjs/rendering/caching/RenderingCacheNode.js +20 -15
  16. package/dist/cjs/rendering/renderers/CanvasRenderer.js +4 -4
  17. package/dist/cjs/testing/findNodeWithText.d.ts +3 -0
  18. package/dist/cjs/testing/findNodeWithText.js +16 -0
  19. package/dist/cjs/testing/firstElementAncestorOfNode.d.ts +3 -0
  20. package/dist/cjs/testing/firstElementAncestorOfNode.js +13 -0
  21. package/dist/cjs/testing/sendKeyPressRelease.d.ts +3 -0
  22. package/dist/cjs/testing/sendKeyPressRelease.js +8 -0
  23. package/dist/cjs/testing/sendPenEvent.d.ts +2 -2
  24. package/dist/cjs/testing/sendPenEvent.js +26 -3
  25. package/dist/cjs/toolbar/localization.d.ts +3 -0
  26. package/dist/cjs/toolbar/localization.js +3 -0
  27. package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +1 -0
  28. package/dist/cjs/toolbar/widgets/BaseWidget.js +1 -0
  29. package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +23 -0
  30. package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.js +65 -0
  31. package/dist/cjs/toolbar/widgets/InsertImageWidget/fileToImages.d.ts +3 -0
  32. package/dist/cjs/toolbar/widgets/InsertImageWidget/fileToImages.js +21 -0
  33. package/dist/cjs/toolbar/widgets/InsertImageWidget/index.d.ts +37 -0
  34. package/dist/cjs/toolbar/widgets/InsertImageWidget/index.js +289 -0
  35. package/dist/cjs/toolbar/widgets/TextToolWidget.js +5 -3
  36. package/dist/cjs/toolbar/widgets/TextToolWidget.test.d.ts +1 -0
  37. package/dist/cjs/toolbar/widgets/components/makeFileInput.d.ts +12 -2
  38. package/dist/cjs/toolbar/widgets/components/makeFileInput.js +113 -45
  39. package/dist/cjs/toolbar/widgets/components/makeFileInput.test.d.ts +1 -0
  40. package/dist/cjs/toolbar/widgets/components/makeSnappedList.d.ts +15 -0
  41. package/dist/cjs/toolbar/widgets/components/makeSnappedList.js +168 -0
  42. package/dist/cjs/tools/Eraser.d.ts +7 -2
  43. package/dist/cjs/tools/Eraser.js +76 -6
  44. package/dist/cjs/tools/PanZoom.d.ts +54 -0
  45. package/dist/cjs/tools/PanZoom.js +54 -2
  46. package/dist/cjs/tools/SelectionTool/Selection.d.ts +2 -2
  47. package/dist/cjs/tools/SelectionTool/Selection.js +20 -20
  48. package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +8 -2
  49. package/dist/cjs/tools/SelectionTool/SelectionHandle.js +6 -0
  50. package/dist/cjs/tools/SelectionTool/SelectionTool.js +1 -1
  51. package/dist/cjs/tools/SelectionTool/types.d.ts +19 -0
  52. package/dist/cjs/tools/TextTool.js +2 -1
  53. package/dist/cjs/tools/TextTool.test.d.ts +1 -0
  54. package/dist/cjs/tools/ToolController.d.ts +2 -0
  55. package/dist/cjs/tools/ToolController.js +10 -1
  56. package/dist/cjs/util/ReactiveValue.d.ts +6 -0
  57. package/dist/cjs/util/ReactiveValue.js +16 -0
  58. package/dist/cjs/util/bytesToSizeString.d.ts +8 -0
  59. package/dist/cjs/util/bytesToSizeString.js +26 -0
  60. package/dist/cjs/util/bytesToSizeString.test.d.ts +1 -0
  61. package/dist/cjs/util/stopPropagationOfScrollingWheelEvents.js +10 -6
  62. package/dist/cjs/util/waitForAll.d.ts +2 -0
  63. package/dist/cjs/util/waitForAll.js +2 -0
  64. package/dist/cjs/util/waitForImageLoaded.js +3 -0
  65. package/dist/cjs/util/waitForTimeout.d.ts +1 -0
  66. package/dist/cjs/util/waitForTimeout.js +1 -1
  67. package/dist/cjs/version.js +1 -1
  68. package/dist/mjs/Editor.d.ts +20 -1
  69. package/dist/mjs/Editor.mjs +6 -0
  70. package/dist/mjs/{SVGLoader.d.ts → SVGLoader/index.d.ts} +1 -1
  71. package/dist/mjs/{SVGLoader.mjs → SVGLoader/index.mjs} +15 -30
  72. package/dist/mjs/SVGLoader/index.test.d.ts +1 -0
  73. package/dist/mjs/SVGLoader/utils/determineFontSize.d.ts +3 -0
  74. package/dist/mjs/SVGLoader/utils/determineFontSize.mjs +25 -0
  75. package/dist/mjs/Viewport.d.ts +33 -1
  76. package/dist/mjs/components/TextComponent.mjs +3 -1
  77. package/dist/mjs/image/EditorImage.d.ts +2 -1
  78. package/dist/mjs/image/EditorImage.mjs +101 -5
  79. package/dist/mjs/rendering/caching/RenderingCacheNode.mjs +20 -15
  80. package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +4 -4
  81. package/dist/mjs/testing/findNodeWithText.d.ts +3 -0
  82. package/dist/mjs/testing/findNodeWithText.mjs +14 -0
  83. package/dist/mjs/testing/firstElementAncestorOfNode.d.ts +3 -0
  84. package/dist/mjs/testing/firstElementAncestorOfNode.mjs +11 -0
  85. package/dist/mjs/testing/sendKeyPressRelease.d.ts +3 -0
  86. package/dist/mjs/testing/sendKeyPressRelease.mjs +6 -0
  87. package/dist/mjs/testing/sendPenEvent.d.ts +2 -2
  88. package/dist/mjs/testing/sendPenEvent.mjs +3 -3
  89. package/dist/mjs/toolbar/localization.d.ts +3 -0
  90. package/dist/mjs/toolbar/localization.mjs +3 -0
  91. package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +1 -0
  92. package/dist/mjs/toolbar/widgets/BaseWidget.mjs +1 -0
  93. package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +23 -0
  94. package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.mjs +61 -0
  95. package/dist/mjs/toolbar/widgets/InsertImageWidget/fileToImages.d.ts +3 -0
  96. package/dist/mjs/toolbar/widgets/InsertImageWidget/fileToImages.mjs +16 -0
  97. package/dist/mjs/toolbar/widgets/InsertImageWidget/index.d.ts +37 -0
  98. package/dist/mjs/toolbar/widgets/InsertImageWidget/index.mjs +284 -0
  99. package/dist/mjs/toolbar/widgets/InsertImageWidget/index.test.d.ts +1 -0
  100. package/dist/mjs/toolbar/widgets/TextToolWidget.mjs +5 -3
  101. package/dist/mjs/toolbar/widgets/TextToolWidget.test.d.ts +1 -0
  102. package/dist/mjs/toolbar/widgets/components/makeFileInput.d.ts +12 -2
  103. package/dist/mjs/toolbar/widgets/components/makeFileInput.mjs +113 -45
  104. package/dist/mjs/toolbar/widgets/components/makeFileInput.test.d.ts +1 -0
  105. package/dist/mjs/toolbar/widgets/components/makeSnappedList.d.ts +15 -0
  106. package/dist/mjs/toolbar/widgets/components/makeSnappedList.mjs +163 -0
  107. package/dist/mjs/tools/Eraser.d.ts +7 -2
  108. package/dist/mjs/tools/Eraser.mjs +76 -6
  109. package/dist/mjs/tools/PanZoom.d.ts +54 -0
  110. package/dist/mjs/tools/PanZoom.mjs +54 -2
  111. package/dist/mjs/tools/SelectionTool/Selection.d.ts +2 -2
  112. package/dist/mjs/tools/SelectionTool/Selection.mjs +20 -20
  113. package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +8 -2
  114. package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +6 -0
  115. package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +1 -1
  116. package/dist/mjs/tools/SelectionTool/types.d.ts +19 -0
  117. package/dist/mjs/tools/TextTool.mjs +2 -1
  118. package/dist/mjs/tools/TextTool.test.d.ts +1 -0
  119. package/dist/mjs/tools/ToolController.d.ts +2 -0
  120. package/dist/mjs/tools/ToolController.mjs +10 -1
  121. package/dist/mjs/util/ReactiveValue.d.ts +6 -0
  122. package/dist/mjs/util/ReactiveValue.mjs +16 -0
  123. package/dist/mjs/util/bytesToSizeString.d.ts +8 -0
  124. package/dist/mjs/util/bytesToSizeString.mjs +24 -0
  125. package/dist/mjs/util/bytesToSizeString.test.d.ts +1 -0
  126. package/dist/mjs/util/stopPropagationOfScrollingWheelEvents.mjs +10 -6
  127. package/dist/mjs/util/waitForAll.d.ts +2 -0
  128. package/dist/mjs/util/waitForAll.mjs +2 -0
  129. package/dist/mjs/util/waitForImageLoaded.mjs +3 -0
  130. package/dist/mjs/util/waitForTimeout.d.ts +1 -0
  131. package/dist/mjs/util/waitForTimeout.mjs +1 -1
  132. package/dist/mjs/version.mjs +1 -1
  133. package/package.json +4 -4
  134. package/src/toolbar/EdgeToolbar.scss +8 -3
  135. package/src/toolbar/toolbar.scss +1 -7
  136. package/src/toolbar/widgets/{InsertImageWidget.scss → InsertImageWidget/index.scss} +3 -2
  137. package/src/toolbar/widgets/components/components.scss +2 -1
  138. package/src/toolbar/widgets/components/makeFileInput.scss +14 -1
  139. package/src/toolbar/widgets/components/makeSnappedList.scss +74 -0
  140. package/src/toolbar/widgets/widgets.scss +7 -0
  141. package/dist/cjs/toolbar/widgets/InsertImageWidget.d.ts +0 -22
  142. package/dist/cjs/toolbar/widgets/InsertImageWidget.js +0 -269
  143. package/dist/mjs/toolbar/widgets/InsertImageWidget.d.ts +0 -22
  144. package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +0 -264
  145. /package/dist/cjs/{SVGLoader.test.d.ts → SVGLoader/index.test.d.ts} +0 -0
  146. /package/dist/{mjs/SVGLoader.test.d.ts → cjs/toolbar/widgets/InsertImageWidget/index.test.d.ts} +0 -0
@@ -61,6 +61,11 @@ export default class SelectionHandle {
61
61
  addTo(container) {
62
62
  container.appendChild(this.element);
63
63
  }
64
+ /**
65
+ * Removes this element from its container. Should only be called
66
+ * after {@link addTo}.
67
+ */
68
+ remove() { this.element.remove(); }
64
69
  /**
65
70
  * Returns this handle's bounding box relative to the top left of the
66
71
  * selection box.
@@ -109,6 +114,7 @@ export default class SelectionHandle {
109
114
  handleDragStart(pointer) {
110
115
  this.onDragStart(pointer.canvasPos);
111
116
  this.dragLastPos = pointer.canvasPos;
117
+ return true;
112
118
  }
113
119
  handleDragUpdate(pointer) {
114
120
  if (!this.dragLastPos) {
@@ -398,7 +398,7 @@ class SelectionTool extends BaseTool {
398
398
  resolve(blob);
399
399
  }
400
400
  else {
401
- reject('Failed to convert canvas to blob.');
401
+ reject(new Error('Failed to convert canvas to blob.'));
402
402
  }
403
403
  }, 'image/png');
404
404
  }));
@@ -1,3 +1,5 @@
1
+ import type { Rect2, Point2 } from '@js-draw/math';
2
+ import Pointer from '../../Pointer';
1
3
  export declare enum ResizeMode {
2
4
  Both = 0,
3
5
  HorizontalOnly = 1,
@@ -7,3 +9,20 @@ export declare enum TransformMode {
7
9
  Snap = 0,
8
10
  NoSnap = 1
9
11
  }
12
+ /**
13
+ * Represents a child of the selection that should move with the selection
14
+ * and handle events.
15
+ *
16
+ * Although selection children should be `HTMLElement`s, the selection may be
17
+ * hidden behind an invisible element. As such, these elements should handle
18
+ * drag start/update/end events.
19
+ */
20
+ export interface SelectionBoxChild {
21
+ updatePosition(selectionScreenBBox: Rect2): void;
22
+ containsPoint(point: Point2): boolean;
23
+ addTo(container: HTMLElement): void;
24
+ remove(): void;
25
+ handleDragStart(pointer: Pointer): boolean;
26
+ handleDragUpdate(pointer: Pointer): void;
27
+ handleDragEnd(): void;
28
+ }
@@ -18,9 +18,10 @@ export default class TextTool extends BaseTool {
18
18
  this.textMeasuringCtx = null;
19
19
  this.textScale = Vec2.of(1, 1);
20
20
  this.removeExistingCommand = null;
21
+ const editorFonts = editor.getCurrentSettings().text?.fonts ?? [];
21
22
  this.textStyleValue = ReactiveValue.fromInitialValue({
22
23
  size: 32,
23
- fontFamily: 'sans-serif',
24
+ fontFamily: editorFonts.length > 0 ? editorFonts[0] : 'sans-serif',
24
25
  renderingStyle: {
25
26
  fill: Color4.purple,
26
27
  },
@@ -0,0 +1 @@
1
+ export {};
@@ -55,6 +55,8 @@ export default class ToolController implements InputEventListener {
55
55
  insertToolsAfter(insertAfter: BaseTool, toolsToInsert: BaseTool[]): void;
56
56
  /** @see {@link insertToolsAfter} */
57
57
  insertToolsBefore(insertBefore: BaseTool, toolsToInsert: BaseTool[]): void;
58
+ /** @internal */
59
+ changeActiveToolTo(tool: BaseTool): void;
58
60
  private onEventInternal;
59
61
  /** Alias for {@link dispatchInputEvent}. */
60
62
  onEvent(event: InputEvt): boolean;
@@ -34,6 +34,7 @@ export default class ToolController {
34
34
  const secondaryPenTool = new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness: 4 });
35
35
  // Stabilize the secondary pen tool.
36
36
  secondaryPenTool.setInputMapper(new InputStabilizer(editor.viewport));
37
+ const eraser = new Eraser(editor, localization.eraserTool);
37
38
  const primaryTools = [
38
39
  // Three pens
39
40
  primaryPenTool,
@@ -44,7 +45,7 @@ export default class ToolController {
44
45
  thickness: 40,
45
46
  factory: makePressureSensitiveFreehandLineBuilder
46
47
  }),
47
- new Eraser(editor, localization.eraserTool),
48
+ eraser,
48
49
  new SelectionTool(editor, localization.selectionTool),
49
50
  new TextTool(editor, localization.textTool, localization),
50
51
  new PanZoom(editor, PanZoomMode.SinglePointerGestures, localization.anyDevicePanning),
@@ -62,6 +63,7 @@ export default class ToolController {
62
63
  new UndoRedoShortcut(editor),
63
64
  new ToolbarShortcutHandler(editor),
64
65
  new ToolSwitcherShortcut(editor),
66
+ eraser.makeEraserSwitcherTool(),
65
67
  new FindTool(editor),
66
68
  new PasteHandler(editor),
67
69
  new SelectAllShortcutHandler(editor),
@@ -180,6 +182,13 @@ export default class ToolController {
180
182
  insertToolsBefore(insertBefore, toolsToInsert) {
181
183
  this.insertTools(insertBefore, toolsToInsert, 'before');
182
184
  }
185
+ /** @internal */
186
+ changeActiveToolTo(tool) {
187
+ if (!tool.isEnabled()) {
188
+ tool.setEnabled(true);
189
+ }
190
+ this.activeTool = tool;
191
+ }
183
192
  // @internal use `dispatchEvent` rather than calling `onEvent` directly.
184
193
  onEventInternal(event) {
185
194
  const isEditorReadOnly = this.isEditorReadOnly.get();
@@ -2,6 +2,9 @@ type ListenerResult = {
2
2
  remove(): void;
3
3
  };
4
4
  type UpdateCallback<T> = (value: T) => void;
5
+ type ReactiveValuesOf<T extends unknown[]> = {
6
+ [key in keyof T]: ReactiveValue<T[key]>;
7
+ };
5
8
  /**
6
9
  * A `ReactiveValue` is a value that
7
10
  * - updates periodically,
@@ -33,6 +36,8 @@ export declare abstract class ReactiveValue<T> {
33
36
  * @see {@link onUpdate}.
34
37
  */
35
38
  abstract onUpdateAndNow(callback: UpdateCallback<T>): ListenerResult;
39
+ /** Returns a promise that resolves when this value is next changed. */
40
+ waitForNextUpdate(): Promise<T>;
36
41
  /** Creates a `ReactiveValue` with an initial value, `initialValue`. */
37
42
  static fromInitialValue<T>(initialValue: T): MutableReactiveValue<T>;
38
43
  /** Returns a `ReactiveValue` that is **known** will never change. */
@@ -54,6 +59,7 @@ export declare abstract class ReactiveValue<T> {
54
59
  * Returns a reactive value derived from a single `source`.
55
60
  */
56
61
  static map<A, B>(source: ReactiveValue<A>, map: (a: A) => B, inverseMap: (b: B) => A): MutableReactiveValue<B>;
62
+ static union<Values extends [...unknown[]]>(values: ReactiveValuesOf<Values>): ReactiveValue<Values>;
57
63
  }
58
64
  export declare abstract class MutableReactiveValue<T> extends ReactiveValue<T> {
59
65
  /**
@@ -35,6 +35,15 @@ const noOpSetUpdateListener = () => {
35
35
  * Avoid extending this class from an external library, as that may not be stable.
36
36
  */
37
37
  export class ReactiveValue {
38
+ /** Returns a promise that resolves when this value is next changed. */
39
+ waitForNextUpdate() {
40
+ return new Promise(resolve => {
41
+ const listener = this.onUpdate(value => {
42
+ listener.remove();
43
+ resolve(value);
44
+ });
45
+ });
46
+ }
38
47
  /** Creates a `ReactiveValue` with an initial value, `initialValue`. */
39
48
  static fromInitialValue(initialValue) {
40
49
  return new ReactiveValueImpl(initialValue);
@@ -48,6 +57,8 @@ export class ReactiveValue {
48
57
  callback(value);
49
58
  return noOpUpdateListenerResult;
50
59
  },
60
+ // Never resolves -- immutable.
61
+ waitForNextUpdate: () => new Promise(() => { }),
51
62
  };
52
63
  }
53
64
  /**
@@ -92,6 +103,11 @@ export class ReactiveValue {
92
103
  }
93
104
  return result;
94
105
  }
106
+ static union(values) {
107
+ return ReactiveValue.fromCallback(() => {
108
+ return values.map(value => value.get());
109
+ }, values);
110
+ }
95
111
  }
96
112
  export class MutableReactiveValue extends ReactiveValue {
97
113
  static fromProperty(sourceValue, propertyName) {
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Returns a size in bytes, KiB, or MiB with units suffix.
3
+ */
4
+ declare const bytesToSizeString: (sizeBytes: number) => {
5
+ size: number;
6
+ units: string;
7
+ };
8
+ export default bytesToSizeString;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Returns a size in bytes, KiB, or MiB with units suffix.
3
+ */
4
+ const bytesToSizeString = (sizeBytes) => {
5
+ const sizeInKiB = sizeBytes / 1024;
6
+ const sizeInMiB = sizeInKiB / 1024;
7
+ const sizeInGiB = sizeInMiB / 1024;
8
+ let units = 'B';
9
+ let size = sizeBytes;
10
+ if (sizeInGiB >= 1) {
11
+ size = sizeInGiB;
12
+ units = 'GiB';
13
+ }
14
+ else if (sizeInMiB >= 1) {
15
+ size = sizeInMiB;
16
+ units = 'MiB';
17
+ }
18
+ else if (sizeInKiB >= 1) {
19
+ size = sizeInKiB;
20
+ units = 'KiB';
21
+ }
22
+ return { size, units };
23
+ };
24
+ export default bytesToSizeString;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,13 +1,17 @@
1
1
  const stopPropagationOfScrollingWheelEvents = (scrollingContainer) => {
2
+ const scrollsAxis = (delta, clientSize, scrollOffset, scrollSize) => {
3
+ const hasScroll = clientSize !== scrollSize && delta !== 0;
4
+ const eventScrollsPastStart = scrollOffset + delta <= 0;
5
+ const scrollEnd = scrollOffset + clientSize;
6
+ const eventScrollsPastEnd = scrollEnd + delta > scrollSize;
7
+ return hasScroll && !eventScrollsPastStart && !eventScrollsPastEnd;
8
+ };
2
9
  scrollingContainer.onwheel = (event) => {
3
- const hasScroll = scrollingContainer.clientWidth !== scrollingContainer.scrollWidth
4
- && event.deltaX !== 0;
5
- const eventScrollsPastLeft = scrollingContainer.scrollLeft + event.deltaX <= 0;
6
- const scrollRight = scrollingContainer.scrollLeft + scrollingContainer.clientWidth;
7
- const eventScrollsPastRight = scrollRight + event.deltaX > scrollingContainer.scrollWidth;
10
+ const scrollsX = scrollsAxis(event.deltaX, scrollingContainer.clientWidth, scrollingContainer.scrollLeft, scrollingContainer.scrollWidth);
11
+ const scrollsY = scrollsAxis(event.deltaY, scrollingContainer.clientHeight, scrollingContainer.scrollTop, scrollingContainer.scrollHeight);
8
12
  // Stop the editor from receiving the event if it will scroll the pen type selector
9
13
  // instead.
10
- if (hasScroll && !eventScrollsPastLeft && !eventScrollsPastRight) {
14
+ if (scrollsX || scrollsY) {
11
15
  event.stopPropagation();
12
16
  }
13
17
  };
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Resolves when all given promises have resolved. If no promises are given,
3
3
  * does not return a Promise.
4
+ *
5
+ * If all elements of `results` are known to be `Promise`s, use `Promise.all`.
4
6
  */
5
7
  declare const waitForAll: (results: (Promise<void> | void)[]) => Promise<void> | void;
6
8
  export default waitForAll;
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Resolves when all given promises have resolved. If no promises are given,
3
3
  * does not return a Promise.
4
+ *
5
+ * If all elements of `results` are known to be `Promise`s, use `Promise.all`.
4
6
  */
5
7
  const waitForAll = (results) => {
6
8
  // If any are Promises...
@@ -2,7 +2,10 @@ const waitForImageLoad = async (image) => {
2
2
  if (!image.complete) {
3
3
  await new Promise((resolve, reject) => {
4
4
  image.onload = event => resolve(event);
5
+ // TODO(v2): Return a `new Error(event.message)`
6
+ // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- Forwarding an error-like object.
5
7
  image.onerror = event => reject(event);
8
+ // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- Forwarding an error-like object.
6
9
  image.onabort = event => reject(event);
7
10
  });
8
11
  }
@@ -1,2 +1,3 @@
1
+ /** Returns a promise that resolves after `timeout` milliseconds. */
1
2
  declare const waitForTimeout: (timeout: number) => Promise<void>;
2
3
  export default waitForTimeout;
@@ -1,4 +1,4 @@
1
- // Returns a promise that resolves after `timeout` milliseconds.
1
+ /** Returns a promise that resolves after `timeout` milliseconds. */
2
2
  const waitForTimeout = (timeout) => {
3
3
  return new Promise(resolve => {
4
4
  setTimeout(() => resolve(), timeout);
@@ -4,5 +4,5 @@
4
4
  * @internal
5
5
  */
6
6
  export default {
7
- number: '1.18.0',
7
+ number: '1.20.0',
8
8
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "1.18.0",
3
+ "version": "1.20.0",
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.18.0",
67
+ "@js-draw/math": "^1.19.0",
68
68
  "@melloware/coloris": "0.22.0"
69
69
  },
70
70
  "devDependencies": {
71
- "@js-draw/build-tool": "^1.17.0",
71
+ "@js-draw/build-tool": "^1.19.0",
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": "73c0d802a8439b5d408ba1e60f91be029db7e402"
89
+ "gitHead": "5bf4f42d0c3367a074c9e9bbb50370421d8bf7d0"
90
90
  }
@@ -307,14 +307,19 @@
307
307
  border: none;
308
308
  padding: 10px;
309
309
 
310
- color: var(--foreground-color-1);
311
-
312
310
  transition: 0.2s ease box-shadow;
313
311
 
314
- &:hover {
312
+ &:not(:disabled):hover {
315
313
  box-shadow: 0 1px 2px var(--shadow-color);
316
314
  }
317
315
 
316
+ &:disabled {
317
+ opacity: 0.5;
318
+ font-weight: unset;
319
+ cursor: unset;
320
+ color: var(--foreground-color-1);
321
+ }
322
+
318
323
  font-weight: bold;
319
324
  color: var(--primary-action-foreground-color);
320
325
  }
@@ -1,10 +1,4 @@
1
- @use "./widgets/InsertImageWidget.scss";
2
- @use "./widgets/OverflowWidget.css";
3
- @use "./widgets/PenToolWidget.scss";
4
- @use "./widgets/HandToolWidget.scss";
5
- @use "./widgets/SelectionToolWidget.scss";
6
- @use "./widgets/DocumentPropertiesWidget.scss";
7
- @use "./widgets/components/components.scss";
1
+ @use "./widgets/widgets.scss";
8
2
 
9
3
  @use "./AbstractToolbar.scss";
10
4
  @use "./EdgeToolbar.scss";
@@ -11,8 +11,8 @@ $image-widget-selector: '.insert-image-widget-dropdown-content';
11
11
  }
12
12
 
13
13
  img {
14
- max-width: min(50vw, 75%);
15
- max-height: min(300px, 50vh);
14
+ max-width: 100%;
15
+ max-height: 100%;
16
16
 
17
17
  /* Center */
18
18
  display: block;
@@ -23,6 +23,7 @@ $image-widget-selector: '.insert-image-widget-dropdown-content';
23
23
  .insert-image-image-status-view {
24
24
  display: flex;
25
25
  justify-content: space-between;
26
+ padding-bottom: 0;
26
27
  }
27
28
 
28
29
  .action-button-row {
@@ -2,4 +2,5 @@
2
2
  @use "./makeColorInput.scss";
3
3
  @use "./makeSeparator.scss";
4
4
  @use "./makeFileInput.scss";
5
- @use "./makeGridSelector.scss";
5
+ @use "./makeGridSelector.scss";
6
+ @use "./makeSnappedList.scss";
@@ -2,7 +2,11 @@
2
2
  .toolbar-element .toolbar--file-input-container {
3
3
  display: flex;
4
4
 
5
- > input[type="file"] {
5
+ &.-loading {
6
+ opacity: 0.8;
7
+ }
8
+
9
+ > input.file-input {
6
10
  // Hide in a way such that screen readers can still access the
7
11
  // input.
8
12
  opacity: 0;
@@ -11,6 +15,11 @@
11
15
  min-width: 0 !important;
12
16
  max-width: 0;
13
17
  height: 0;
18
+
19
+ // Needed when the input is a button.
20
+ overflow: hidden;
21
+ padding: 0;
22
+ margin: 0;
14
23
  }
15
24
 
16
25
  > label {
@@ -28,6 +37,10 @@
28
37
  in srgb, var(--foreground-color-1), transparent
29
38
  );
30
39
 
40
+ > .cancel-button {
41
+ display: block;
42
+ }
43
+
31
44
  > .toolbar--file-input-description {
32
45
  background-color: var(--background-color-3);
33
46
  color: var(--foreground-color-3);
@@ -0,0 +1,74 @@
1
+
2
+ // Repeat for specificity.
3
+ // TODO(v2): Refactor everything to use RCSS.
4
+ :root .toolbar-snapped-scroll-list.toolbar-snapped-scroll-list.toolbar-snapped-scroll-list {
5
+ height: min(200px, 50vh);
6
+ position: relative;
7
+ display: flex;
8
+ align-items: center;
9
+
10
+ > .scroller {
11
+ display: flex;
12
+ flex-direction: column;
13
+ overflow-y: auto;
14
+ scroll-snap-type: y mandatory;
15
+
16
+ height: 100%;
17
+ width: 100%;
18
+ flex-grow: 1;
19
+
20
+ > .item {
21
+ height: 100%;
22
+ width: 100%;
23
+ flex-shrink: 0;
24
+
25
+ display: flex;
26
+ justify-content: center;
27
+ align-items: center;
28
+
29
+ scroll-snap-align: start;
30
+ scroll-snap-stop: always;
31
+ box-sizing: border-box;
32
+ }
33
+ }
34
+
35
+ &.-empty {
36
+ display: none;
37
+ }
38
+
39
+ > .page-markers {
40
+ overflow: hidden;
41
+
42
+ display: flex;
43
+ flex-direction: column;
44
+ align-items: center;
45
+
46
+ max-height: 100%;
47
+ min-height: 0;
48
+
49
+ &.-one-element {
50
+ visibility: hidden;
51
+ }
52
+
53
+ > .marker {
54
+ > .content {
55
+ background-color: var(--foreground-color-1);
56
+ border-radius: 2px;
57
+ padding: 2px;
58
+ }
59
+
60
+ padding: 2px;
61
+ opacity: 0.1;
62
+ cursor: pointer;
63
+
64
+ left: 0;
65
+ transition: left 0.2s ease;
66
+
67
+ &.-active {
68
+ position: relative;
69
+ left: 2px;
70
+ opacity: 0.2;
71
+ }
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,7 @@
1
+ @use "./InsertImageWidget/index.scss";
2
+ @use "./OverflowWidget.css";
3
+ @use "./PenToolWidget.scss";
4
+ @use "./HandToolWidget.scss";
5
+ @use "./SelectionToolWidget.scss";
6
+ @use "./DocumentPropertiesWidget.scss";
7
+ @use "./components/components.scss";
@@ -1,22 +0,0 @@
1
- import Editor from '../../Editor';
2
- import { ToolbarLocalization } from '../localization';
3
- import BaseWidget from './BaseWidget';
4
- export default class InsertImageWidget extends BaseWidget {
5
- private imagePreview;
6
- private image;
7
- private selectedFiles;
8
- private imageAltTextInput;
9
- private statusView;
10
- private submitButton;
11
- constructor(editor: Editor, localization?: ToolbarLocalization);
12
- protected getTitle(): string;
13
- protected createIcon(): Element | null;
14
- protected setDropdownVisible(visible: boolean): void;
15
- protected handleClick(): void;
16
- private static nextInputId;
17
- protected fillDropdown(dropdown: HTMLElement): boolean;
18
- private onImageDataUpdate;
19
- private hideDialog;
20
- private updateImageSizeDisplay;
21
- private updateInputs;
22
- }