js-draw 1.20.3 → 1.21.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (243) hide show
  1. package/LICENSE +1 -1
  2. package/dist/Editor.css +134 -26
  3. package/dist/bundle.js +2 -2
  4. package/dist/bundledStyles.js +1 -1
  5. package/dist/cjs/Editor.d.ts +27 -6
  6. package/dist/cjs/Editor.js +30 -8
  7. package/dist/cjs/SVGLoader/SVGLoader.js +2 -2
  8. package/dist/cjs/Viewport.d.ts +2 -2
  9. package/dist/cjs/commands/Command.d.ts +5 -0
  10. package/dist/cjs/commands/Command.js +5 -0
  11. package/dist/cjs/commands/SerializableCommand.d.ts +7 -0
  12. package/dist/cjs/commands/SerializableCommand.js +9 -0
  13. package/dist/cjs/dialogs/makeAboutDialog.d.ts +1 -1
  14. package/dist/cjs/dialogs/makeAboutDialog.js +10 -25
  15. package/dist/cjs/dialogs/makeMessageDialog.d.ts +11 -0
  16. package/dist/cjs/dialogs/makeMessageDialog.js +56 -0
  17. package/dist/cjs/image/EditorImage.d.ts +15 -1
  18. package/dist/cjs/image/EditorImage.js +15 -5
  19. package/dist/cjs/inputEvents.d.ts +10 -2
  20. package/dist/cjs/inputEvents.js +1 -0
  21. package/dist/cjs/localizations/es.js +3 -0
  22. package/dist/cjs/rendering/Display.d.ts +1 -0
  23. package/dist/cjs/rendering/Display.js +1 -0
  24. package/dist/cjs/rendering/TextRenderingStyle.d.ts +7 -6
  25. package/dist/cjs/rendering/TextRenderingStyle.js +1 -0
  26. package/dist/cjs/rendering/renderers/CanvasRenderer.d.ts +12 -3
  27. package/dist/cjs/rendering/renderers/CanvasRenderer.js +15 -2
  28. package/dist/cjs/rendering/renderers/DummyRenderer.d.ts +1 -1
  29. package/dist/cjs/testing/firstElementAncestorOfNode.d.ts +1 -1
  30. package/dist/cjs/testing/firstElementAncestorOfNode.js +1 -1
  31. package/dist/cjs/testing/sendPenEvent.d.ts +2 -2
  32. package/dist/cjs/testing/sendTouchEvent.d.ts +2 -2
  33. package/dist/cjs/toolbar/AbstractToolbar.d.ts +6 -1
  34. package/dist/cjs/toolbar/AbstractToolbar.js +6 -1
  35. package/dist/cjs/toolbar/IconProvider.d.ts +1 -1
  36. package/dist/cjs/toolbar/IconProvider.js +6 -1
  37. package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +8 -0
  38. package/dist/cjs/toolbar/widgets/BaseWidget.js +8 -0
  39. package/dist/cjs/toolbar/widgets/HandToolWidget.d.ts +1 -0
  40. package/dist/cjs/toolbar/widgets/HandToolWidget.js +1 -0
  41. package/dist/cjs/toolbar/widgets/PenToolWidget.d.ts +6 -0
  42. package/dist/cjs/toolbar/widgets/PenToolWidget.js +5 -0
  43. package/dist/cjs/types.d.ts +5 -0
  44. package/dist/cjs/types.js +1 -0
  45. package/dist/cjs/util/ClipboardHandler.d.ts +9 -1
  46. package/dist/cjs/util/ClipboardHandler.js +82 -24
  47. package/dist/cjs/version.js +1 -1
  48. package/dist/mjs/Editor.d.ts +27 -6
  49. package/dist/mjs/Editor.mjs +31 -9
  50. package/dist/mjs/SVGLoader/SVGLoader.mjs +2 -2
  51. package/dist/mjs/Viewport.d.ts +2 -2
  52. package/dist/mjs/commands/Command.d.ts +5 -0
  53. package/dist/mjs/commands/Command.mjs +5 -0
  54. package/dist/mjs/commands/SerializableCommand.d.ts +7 -0
  55. package/dist/mjs/commands/SerializableCommand.mjs +9 -0
  56. package/dist/mjs/dialogs/makeAboutDialog.d.ts +1 -1
  57. package/dist/mjs/dialogs/makeAboutDialog.mjs +7 -25
  58. package/dist/mjs/dialogs/makeMessageDialog.d.ts +11 -0
  59. package/dist/mjs/dialogs/makeMessageDialog.mjs +51 -0
  60. package/dist/mjs/image/EditorImage.d.ts +15 -1
  61. package/dist/mjs/image/EditorImage.mjs +15 -5
  62. package/dist/mjs/inputEvents.d.ts +10 -2
  63. package/dist/mjs/inputEvents.mjs +1 -0
  64. package/dist/mjs/localizations/es.mjs +3 -0
  65. package/dist/mjs/rendering/Display.d.ts +1 -0
  66. package/dist/mjs/rendering/Display.mjs +1 -0
  67. package/dist/mjs/rendering/TextRenderingStyle.d.ts +7 -6
  68. package/dist/mjs/rendering/TextRenderingStyle.mjs +1 -0
  69. package/dist/mjs/rendering/renderers/CanvasRenderer.d.ts +12 -3
  70. package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +15 -2
  71. package/dist/mjs/rendering/renderers/DummyRenderer.d.ts +1 -1
  72. package/dist/mjs/testing/firstElementAncestorOfNode.d.ts +1 -1
  73. package/dist/mjs/testing/firstElementAncestorOfNode.mjs +1 -1
  74. package/dist/mjs/testing/sendPenEvent.d.ts +2 -2
  75. package/dist/mjs/testing/sendTouchEvent.d.ts +2 -2
  76. package/dist/mjs/toolbar/AbstractToolbar.d.ts +6 -1
  77. package/dist/mjs/toolbar/AbstractToolbar.mjs +6 -1
  78. package/dist/mjs/toolbar/IconProvider.d.ts +1 -1
  79. package/dist/mjs/toolbar/IconProvider.mjs +6 -1
  80. package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +8 -0
  81. package/dist/mjs/toolbar/widgets/BaseWidget.mjs +8 -0
  82. package/dist/mjs/toolbar/widgets/HandToolWidget.d.ts +1 -0
  83. package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +1 -0
  84. package/dist/mjs/toolbar/widgets/PenToolWidget.d.ts +6 -0
  85. package/dist/mjs/toolbar/widgets/PenToolWidget.mjs +5 -0
  86. package/dist/mjs/types.d.ts +5 -0
  87. package/dist/mjs/types.mjs +1 -0
  88. package/dist/mjs/util/ClipboardHandler.d.ts +9 -1
  89. package/dist/mjs/util/ClipboardHandler.mjs +82 -24
  90. package/dist/mjs/version.mjs +1 -1
  91. package/package.json +8 -9
  92. package/src/dialogs/dialogs.scss +9 -21
  93. package/src/dialogs/makeAboutDialog.scss +13 -33
  94. package/src/dialogs/makeMessageDialog.scss +46 -0
  95. package/dist/cjs/tools/BaseTool.d.ts +0 -60
  96. package/dist/cjs/tools/BaseTool.js +0 -174
  97. package/dist/cjs/tools/Eraser.d.ts +0 -56
  98. package/dist/cjs/tools/Eraser.js +0 -295
  99. package/dist/cjs/tools/Eraser.test.d.ts +0 -1
  100. package/dist/cjs/tools/FindTool.d.ts +0 -21
  101. package/dist/cjs/tools/FindTool.js +0 -137
  102. package/dist/cjs/tools/FindTool.test.d.ts +0 -1
  103. package/dist/cjs/tools/InputFilter/FunctionMapper.d.ts +0 -12
  104. package/dist/cjs/tools/InputFilter/FunctionMapper.js +0 -21
  105. package/dist/cjs/tools/InputFilter/InputMapper.d.ts +0 -23
  106. package/dist/cjs/tools/InputFilter/InputMapper.js +0 -38
  107. package/dist/cjs/tools/InputFilter/InputPipeline.d.ts +0 -15
  108. package/dist/cjs/tools/InputFilter/InputPipeline.js +0 -54
  109. package/dist/cjs/tools/InputFilter/InputPipeline.test.d.ts +0 -1
  110. package/dist/cjs/tools/InputFilter/InputStabilizer.d.ts +0 -29
  111. package/dist/cjs/tools/InputFilter/InputStabilizer.js +0 -181
  112. package/dist/cjs/tools/InputFilter/StrokeKeyboardControl.d.ts +0 -21
  113. package/dist/cjs/tools/InputFilter/StrokeKeyboardControl.js +0 -84
  114. package/dist/cjs/tools/PanZoom.d.ts +0 -119
  115. package/dist/cjs/tools/PanZoom.js +0 -508
  116. package/dist/cjs/tools/PanZoom.test.d.ts +0 -1
  117. package/dist/cjs/tools/PasteHandler.d.ts +0 -23
  118. package/dist/cjs/tools/PasteHandler.js +0 -109
  119. package/dist/cjs/tools/Pen.d.ts +0 -53
  120. package/dist/cjs/tools/Pen.js +0 -318
  121. package/dist/cjs/tools/Pen.test.d.ts +0 -1
  122. package/dist/cjs/tools/PipetteTool.d.ts +0 -28
  123. package/dist/cjs/tools/PipetteTool.js +0 -69
  124. package/dist/cjs/tools/ScrollbarTool.d.ts +0 -18
  125. package/dist/cjs/tools/ScrollbarTool.js +0 -85
  126. package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +0 -9
  127. package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.js +0 -32
  128. package/dist/cjs/tools/SelectionTool/Selection.d.ts +0 -71
  129. package/dist/cjs/tools/SelectionTool/Selection.js +0 -620
  130. package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +0 -62
  131. package/dist/cjs/tools/SelectionTool/SelectionHandle.js +0 -141
  132. package/dist/cjs/tools/SelectionTool/SelectionTool.d.ts +0 -40
  133. package/dist/cjs/tools/SelectionTool/SelectionTool.js +0 -494
  134. package/dist/cjs/tools/SelectionTool/SelectionTool.selecting.test.d.ts +0 -1
  135. package/dist/cjs/tools/SelectionTool/SelectionTool.test.d.ts +0 -1
  136. package/dist/cjs/tools/SelectionTool/ToPointerAutoscroller.d.ts +0 -23
  137. package/dist/cjs/tools/SelectionTool/ToPointerAutoscroller.js +0 -83
  138. package/dist/cjs/tools/SelectionTool/TransformMode.d.ts +0 -42
  139. package/dist/cjs/tools/SelectionTool/TransformMode.js +0 -155
  140. package/dist/cjs/tools/SelectionTool/types.d.ts +0 -28
  141. package/dist/cjs/tools/SelectionTool/types.js +0 -14
  142. package/dist/cjs/tools/SoundUITool.d.ts +0 -26
  143. package/dist/cjs/tools/SoundUITool.js +0 -171
  144. package/dist/cjs/tools/TextTool.d.ts +0 -36
  145. package/dist/cjs/tools/TextTool.js +0 -285
  146. package/dist/cjs/tools/TextTool.test.d.ts +0 -1
  147. package/dist/cjs/tools/ToolController.d.ts +0 -73
  148. package/dist/cjs/tools/ToolController.js +0 -304
  149. package/dist/cjs/tools/ToolController.test.d.ts +0 -1
  150. package/dist/cjs/tools/ToolEnabledGroup.d.ts +0 -6
  151. package/dist/cjs/tools/ToolEnabledGroup.js +0 -13
  152. package/dist/cjs/tools/ToolSwitcherShortcut.d.ts +0 -16
  153. package/dist/cjs/tools/ToolSwitcherShortcut.js +0 -40
  154. package/dist/cjs/tools/ToolbarShortcutHandler.d.ts +0 -12
  155. package/dist/cjs/tools/ToolbarShortcutHandler.js +0 -34
  156. package/dist/cjs/tools/UndoRedoShortcut.d.ts +0 -8
  157. package/dist/cjs/tools/UndoRedoShortcut.js +0 -27
  158. package/dist/cjs/tools/UndoRedoShortcut.test.d.ts +0 -1
  159. package/dist/cjs/tools/keybindings.d.ts +0 -18
  160. package/dist/cjs/tools/keybindings.js +0 -49
  161. package/dist/cjs/tools/lib.d.ts +0 -14
  162. package/dist/cjs/tools/lib.js +0 -36
  163. package/dist/cjs/tools/localization.d.ts +0 -34
  164. package/dist/cjs/tools/localization.js +0 -36
  165. package/dist/cjs/tools/util/StationaryPenDetector.d.ts +0 -22
  166. package/dist/cjs/tools/util/StationaryPenDetector.js +0 -95
  167. package/dist/mjs/tools/BaseTool.d.ts +0 -60
  168. package/dist/mjs/tools/BaseTool.mjs +0 -172
  169. package/dist/mjs/tools/Eraser.d.ts +0 -56
  170. package/dist/mjs/tools/Eraser.mjs +0 -288
  171. package/dist/mjs/tools/Eraser.test.d.ts +0 -1
  172. package/dist/mjs/tools/FindTool.d.ts +0 -21
  173. package/dist/mjs/tools/FindTool.mjs +0 -131
  174. package/dist/mjs/tools/FindTool.test.d.ts +0 -1
  175. package/dist/mjs/tools/InputFilter/FunctionMapper.d.ts +0 -12
  176. package/dist/mjs/tools/InputFilter/FunctionMapper.mjs +0 -15
  177. package/dist/mjs/tools/InputFilter/InputMapper.d.ts +0 -23
  178. package/dist/mjs/tools/InputFilter/InputMapper.mjs +0 -36
  179. package/dist/mjs/tools/InputFilter/InputPipeline.d.ts +0 -15
  180. package/dist/mjs/tools/InputFilter/InputPipeline.mjs +0 -49
  181. package/dist/mjs/tools/InputFilter/InputPipeline.test.d.ts +0 -1
  182. package/dist/mjs/tools/InputFilter/InputStabilizer.d.ts +0 -29
  183. package/dist/mjs/tools/InputFilter/InputStabilizer.mjs +0 -175
  184. package/dist/mjs/tools/InputFilter/StrokeKeyboardControl.d.ts +0 -21
  185. package/dist/mjs/tools/InputFilter/StrokeKeyboardControl.mjs +0 -78
  186. package/dist/mjs/tools/PanZoom.d.ts +0 -119
  187. package/dist/mjs/tools/PanZoom.mjs +0 -501
  188. package/dist/mjs/tools/PanZoom.test.d.ts +0 -1
  189. package/dist/mjs/tools/PasteHandler.d.ts +0 -23
  190. package/dist/mjs/tools/PasteHandler.mjs +0 -103
  191. package/dist/mjs/tools/Pen.d.ts +0 -53
  192. package/dist/mjs/tools/Pen.mjs +0 -312
  193. package/dist/mjs/tools/Pen.test.d.ts +0 -1
  194. package/dist/mjs/tools/PipetteTool.d.ts +0 -28
  195. package/dist/mjs/tools/PipetteTool.mjs +0 -63
  196. package/dist/mjs/tools/ScrollbarTool.d.ts +0 -18
  197. package/dist/mjs/tools/ScrollbarTool.mjs +0 -79
  198. package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +0 -9
  199. package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.mjs +0 -26
  200. package/dist/mjs/tools/SelectionTool/Selection.d.ts +0 -71
  201. package/dist/mjs/tools/SelectionTool/Selection.mjs +0 -592
  202. package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +0 -62
  203. package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +0 -137
  204. package/dist/mjs/tools/SelectionTool/SelectionTool.d.ts +0 -40
  205. package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +0 -488
  206. package/dist/mjs/tools/SelectionTool/SelectionTool.selecting.test.d.ts +0 -1
  207. package/dist/mjs/tools/SelectionTool/SelectionTool.test.d.ts +0 -1
  208. package/dist/mjs/tools/SelectionTool/ToPointerAutoscroller.d.ts +0 -23
  209. package/dist/mjs/tools/SelectionTool/ToPointerAutoscroller.mjs +0 -77
  210. package/dist/mjs/tools/SelectionTool/TransformMode.d.ts +0 -42
  211. package/dist/mjs/tools/SelectionTool/TransformMode.mjs +0 -146
  212. package/dist/mjs/tools/SelectionTool/types.d.ts +0 -28
  213. package/dist/mjs/tools/SelectionTool/types.mjs +0 -11
  214. package/dist/mjs/tools/SoundUITool.d.ts +0 -26
  215. package/dist/mjs/tools/SoundUITool.mjs +0 -165
  216. package/dist/mjs/tools/TextTool.d.ts +0 -36
  217. package/dist/mjs/tools/TextTool.mjs +0 -279
  218. package/dist/mjs/tools/TextTool.test.d.ts +0 -1
  219. package/dist/mjs/tools/ToolController.d.ts +0 -73
  220. package/dist/mjs/tools/ToolController.mjs +0 -275
  221. package/dist/mjs/tools/ToolController.test.d.ts +0 -1
  222. package/dist/mjs/tools/ToolEnabledGroup.d.ts +0 -6
  223. package/dist/mjs/tools/ToolEnabledGroup.mjs +0 -10
  224. package/dist/mjs/tools/ToolSwitcherShortcut.d.ts +0 -16
  225. package/dist/mjs/tools/ToolSwitcherShortcut.mjs +0 -34
  226. package/dist/mjs/tools/ToolbarShortcutHandler.d.ts +0 -12
  227. package/dist/mjs/tools/ToolbarShortcutHandler.mjs +0 -28
  228. package/dist/mjs/tools/UndoRedoShortcut.d.ts +0 -8
  229. package/dist/mjs/tools/UndoRedoShortcut.mjs +0 -21
  230. package/dist/mjs/tools/UndoRedoShortcut.test.d.ts +0 -1
  231. package/dist/mjs/tools/keybindings.d.ts +0 -18
  232. package/dist/mjs/tools/keybindings.mjs +0 -43
  233. package/dist/mjs/tools/lib.d.ts +0 -14
  234. package/dist/mjs/tools/lib.mjs +0 -14
  235. package/dist/mjs/tools/localization.d.ts +0 -34
  236. package/dist/mjs/tools/localization.mjs +0 -33
  237. package/dist/mjs/tools/util/StationaryPenDetector.d.ts +0 -22
  238. package/dist/mjs/tools/util/StationaryPenDetector.mjs +0 -92
  239. package/src/tools/FindTool.css +0 -7
  240. package/src/tools/ScrollbarTool.scss +0 -57
  241. package/src/tools/SelectionTool/SelectionTool.scss +0 -137
  242. package/src/tools/SoundUITool.scss +0 -22
  243. package/src/tools/tools.scss +0 -5
@@ -25,8 +25,9 @@ mime.endsWith('+xml') || mime.startsWith('text/');
25
25
  * js-draw clipboard events.
26
26
  */
27
27
  class ClipboardHandler {
28
- constructor(editor) {
28
+ constructor(editor, callbacks) {
29
29
  this.editor = editor;
30
+ this.callbacks = callbacks;
30
31
  _ClipboardHandler_preferClipboardEvents.set(this, false);
31
32
  }
32
33
  /**
@@ -37,7 +38,27 @@ class ClipboardHandler {
37
38
  * `navigator.clipboard` will be used instead.
38
39
  * @returns true if the paste event was handled by the editor.
39
40
  */
40
- async paste(event) {
41
+ paste(event) {
42
+ const onError = (error) => {
43
+ if (this.callbacks?.onPasteError) {
44
+ this.callbacks.onPasteError(error);
45
+ return Promise.resolve(false);
46
+ }
47
+ else {
48
+ throw error;
49
+ }
50
+ };
51
+ try {
52
+ // Use .catch rather than `async` to prevent future modifications from
53
+ // moving clipboard handling logic out of user event handlers.
54
+ // In the past, `await`s have caused permissions issues in some browsers.
55
+ return this.pasteInternal(event).catch(onError);
56
+ }
57
+ catch (error) {
58
+ return onError(error);
59
+ }
60
+ }
61
+ async pasteInternal(event) {
41
62
  const editor = this.editor;
42
63
  const clipboardData = event?.dataTransfer ?? event?.clipboardData ?? null;
43
64
  const hasEvent = !!clipboardData;
@@ -136,45 +157,82 @@ class ClipboardHandler {
136
157
  * images.
137
158
  */
138
159
  copy(event) {
139
- const mimeToData = Object.create(null);
160
+ const onError = (error) => {
161
+ if (this.callbacks?.onCopyError) {
162
+ this.callbacks.onCopyError(error);
163
+ return Promise.resolve();
164
+ }
165
+ else {
166
+ throw error;
167
+ }
168
+ };
169
+ try {
170
+ // As above, use `.catch` to be certain that certain copyInternal
171
+ // is run now, before returning.
172
+ return this.copyInternal(event).catch(onError);
173
+ }
174
+ catch (error) {
175
+ return onError(error);
176
+ }
177
+ }
178
+ copyInternal(event) {
179
+ const mimeToData = new Map();
140
180
  if (this.editor.toolController.dispatchInputEvent({
141
181
  kind: inputEvents_1.InputEvtType.CopyEvent,
142
182
  setData: (mime, data) => {
143
- mimeToData[mime] = data;
183
+ mimeToData.set(mime, data);
144
184
  },
145
185
  })) {
146
186
  event?.preventDefault();
147
187
  }
148
- const mimeTypes = Object.keys(mimeToData);
188
+ const mimeTypes = [...mimeToData.keys()];
149
189
  const hasNonTextMimeTypes = mimeTypes.some(mime => !isTextMimeType(mime));
150
- const copyToEvent = () => {
190
+ const copyToEvent = (reason) => {
151
191
  if (!event) {
152
- throw new Error('Unable to paste -- no event provided.');
192
+ throw new Error(`Unable to copy -- no event provided${reason ? `. Original error: ${reason}` : ''}`);
153
193
  }
154
- for (const key in mimeToData) {
155
- const value = mimeToData[key];
194
+ for (const [key, value] of mimeToData.entries()) {
156
195
  if (typeof value === 'string') {
157
196
  event.clipboardData?.setData(key, value);
158
197
  }
159
198
  }
160
199
  };
161
200
  const copyToClipboardApi = () => {
162
- const mappedMimeToData = Object.create(null);
163
- const mimeMapping = {
164
- // image/svg+xml is unsupported in Chrome.
165
- 'image/svg+xml': 'text/html',
166
- };
167
- for (const key in mimeToData) {
168
- const data = mimeToData[key];
169
- const mappedKey = mimeMapping[key] || key;
170
- if (typeof data === 'string') {
171
- mappedMimeToData[mappedKey] = new Blob([new TextEncoder().encode(data)], { type: mappedKey });
201
+ const mapInternalDataToBrowserData = (originalMimeToData) => {
202
+ const mappedMimeToData = Object.create(null);
203
+ for (const [key, data] of originalMimeToData.entries()) {
204
+ if (typeof data === 'string') {
205
+ const loadedData = new Blob([new TextEncoder().encode(data)], { type: key });
206
+ mappedMimeToData[key] = loadedData;
207
+ }
208
+ else {
209
+ mappedMimeToData[key] = data;
210
+ }
211
+ // Different platforms have varying support for different clipboard MIME types:
212
+ // - As of September 2024, image/svg+xml is unsupported on iOS
213
+ // - text/html is unsupported on Chrome/Android (and perhaps Chrome on other platforms).
214
+ // - See https://issues.chromium.org/issues/40851502
215
+ if (key === 'image/svg+xml') {
216
+ mappedMimeToData['text/html'] ??= mappedMimeToData[key];
217
+ }
172
218
  }
173
- else {
174
- mappedMimeToData[mappedKey] = data;
219
+ return mappedMimeToData;
220
+ };
221
+ const removeUnsupportedMime = (originalMimeToData) => {
222
+ const filteredMimeToData = Object.create(null);
223
+ for (const [key, data] of Object.entries(originalMimeToData)) {
224
+ // Browser support for ClipboardItem.supports is limited as of mid 2024. However, some browsers
225
+ // that do support `.supports` throw an exception when attempting to copy an unsupported MIME type
226
+ // (e.g. Firefox).
227
+ const unsupported = 'supports' in ClipboardItem && typeof ClipboardItem.supports === 'function' && !ClipboardItem.supports(key);
228
+ if (!unsupported) {
229
+ filteredMimeToData[key] = data;
230
+ }
175
231
  }
176
- }
177
- return navigator.clipboard.write([new ClipboardItem(mappedMimeToData)]);
232
+ return filteredMimeToData;
233
+ };
234
+ const browserMimeToData = removeUnsupportedMime(mapInternalDataToBrowserData(mimeToData));
235
+ return navigator.clipboard.write([new ClipboardItem(browserMimeToData)]);
178
236
  };
179
237
  const supportsClipboardApi = (typeof ClipboardItem !== 'undefined'
180
238
  && typeof navigator?.clipboard?.write !== 'undefined');
@@ -183,7 +241,7 @@ class ClipboardHandler {
183
241
  const fallBackToCopyEvent = (reason) => {
184
242
  console.warn('Unable to copy to the clipboard API. Future calls to .copy will use ClipboardEvents if possible.', reason);
185
243
  __classPrivateFieldSet(this, _ClipboardHandler_preferClipboardEvents, true, "f");
186
- copyToEvent();
244
+ copyToEvent(reason);
187
245
  };
188
246
  try {
189
247
  clipboardApiPromise = copyToClipboardApi();
@@ -6,5 +6,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  * @internal
7
7
  */
8
8
  exports.default = {
9
- number: '1.20.3',
9
+ number: '1.21.1',
10
10
  };
@@ -1,7 +1,7 @@
1
1
  import EditorImage from './image/EditorImage';
2
2
  import ToolController from './tools/ToolController';
3
3
  import { EditorNotifier, ImageLoader } from './types';
4
- import { HTMLPointerEventFilter, InputEvtType } from './inputEvents';
4
+ import { HTMLPointerEventFilter, InputEvtType, PointerEvtType } from './inputEvents';
5
5
  import Command from './commands/Command';
6
6
  import UndoRedoHistory from './UndoRedoHistory';
7
7
  import Viewport from './Viewport';
@@ -68,8 +68,8 @@ export interface EditorSettings {
68
68
  */
69
69
  notices: AboutDialogEntry[];
70
70
  /**
71
- * Information about the app/website js-draw is running within
72
- * to show at the beginning of the about dialog.
71
+ * Information about the app/website js-draw is running within. This is shown
72
+ * at the beginning of the about dialog.
73
73
  */
74
74
  appInfo: {
75
75
  name: string;
@@ -291,8 +291,18 @@ export declare class Editor {
291
291
  * ```
292
292
  */
293
293
  getRootElement(): HTMLElement;
294
- /** @param fractionLoaded - should be a number from 0 to 1, where 1 represents completely loaded. */
294
+ /**
295
+ * @returns the bounding box of the main rendering region of the editor in the HTML viewport.
296
+ *
297
+ * @internal
298
+ */
299
+ getOutputBBoxInDOM(): Rect2;
300
+ /**
301
+ * Shows a "Loading..." message.
302
+ * @param fractionLoaded - should be a number from 0 to 1, where 1 represents completely loaded.
303
+ */
295
304
  showLoadingWarning(fractionLoaded: number): void;
305
+ /** @see {@link showLoadingWarning} */
296
306
  hideLoadingWarning(): void;
297
307
  private previousAccessibilityAnnouncement;
298
308
  /**
@@ -389,7 +399,12 @@ export declare class Editor {
389
399
  setReadOnly(readOnly: boolean): void;
390
400
  isReadOnlyReactiveValue(): ReactiveValue<boolean>;
391
401
  isReadOnly(): MutableReactiveValue<boolean>;
392
- /** `apply` a command. `command` will be announced for accessibility. */
402
+ /**
403
+ * `apply` a command. `command` will be announced for accessibility.
404
+ *
405
+ * **Example**:
406
+ * [[include:doc-pages/inline-examples/adding-a-stroke.md]]
407
+ */
393
408
  dispatch(command: Command, addToHistory?: boolean): void | Promise<void>;
394
409
  /**
395
410
  * Dispatches a command without announcing it. By default, does not add to history.
@@ -414,7 +429,13 @@ export declare class Editor {
414
429
  * has been applied.
415
430
  */
416
431
  asyncApplyOrUnapplyCommands(commands: Command[], apply: boolean, updateChunkSize: number): Promise<void>;
432
+ /** @see {@link asyncApplyOrUnapplyCommands } */
417
433
  asyncApplyCommands(commands: Command[], chunkSize: number): Promise<void>;
434
+ /**
435
+ * @see {@link asyncApplyOrUnapplyCommands}
436
+ *
437
+ * If `unapplyInReverseOrder`, commands are reversed before unapplying.
438
+ */
418
439
  asyncUnapplyCommands(commands: Command[], chunkSize: number, unapplyInReverseOrder?: boolean): Promise<void>;
419
440
  private announceUndoCallback;
420
441
  private announceRedoCallback;
@@ -492,7 +513,7 @@ export declare class Editor {
492
513
  * @deprecated
493
514
  * @see {@link sendPenEvent} {@link sendTouchEvent}
494
515
  */
495
- sendPenEvent(eventType: InputEvtType.PointerDownEvt | InputEvtType.PointerMoveEvt | InputEvtType.PointerUpEvt, point: Point2, allPointers?: Pointer[]): void;
516
+ sendPenEvent(eventType: PointerEvtType, point: Point2, allPointers?: Pointer[]): void;
496
517
  /**
497
518
  * Adds all components in `components` such that they are in the center of the screen.
498
519
  * This is a convenience method that creates **and applies** a single command.
@@ -5,7 +5,7 @@ import { InputEvtType, keyUpEventFromHTMLEvent, keyPressEventFromHTMLEvent } f
5
5
  import UndoRedoHistory from './UndoRedoHistory.mjs';
6
6
  import Viewport from './Viewport.mjs';
7
7
  import EventDispatcher from './EventDispatcher.mjs';
8
- import { Vec2, Vec3, Color4, Mat33 } from '@js-draw/math';
8
+ import { Vec2, Vec3, Color4, Mat33, Rect2 } from '@js-draw/math';
9
9
  import Display, { RenderingMode } from './rendering/Display.mjs';
10
10
  import SVGLoader from './SVGLoader/SVGLoader.mjs';
11
11
  import Pointer from './Pointer.mjs';
@@ -29,6 +29,7 @@ import { 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';
32
+ import ContextMenuRecognizer from './tools/InputFilter/ContextMenuRecognizer.mjs';
32
33
  /**
33
34
  * The main entrypoint for the full editor.
34
35
  *
@@ -164,6 +165,7 @@ export class Editor {
164
165
  this.toolController = new ToolController(this, this.localization);
165
166
  // TODO: Make this pipeline configurable (e.g. allow users to add global input stabilization)
166
167
  this.toolController.addInputMapper(StrokeKeyboardControl.fromEditor(this));
168
+ this.toolController.addInputMapper(new ContextMenuRecognizer());
167
169
  parent.appendChild(this.container);
168
170
  this.viewport.updateScreenSize(Vec2.of(this.display.width, this.display.height));
169
171
  this.registerListeners();
@@ -221,12 +223,24 @@ export class Editor {
221
223
  getRootElement() {
222
224
  return this.container;
223
225
  }
224
- /** @param fractionLoaded - should be a number from 0 to 1, where 1 represents completely loaded. */
226
+ /**
227
+ * @returns the bounding box of the main rendering region of the editor in the HTML viewport.
228
+ *
229
+ * @internal
230
+ */
231
+ getOutputBBoxInDOM() {
232
+ return Rect2.of(this.renderingRegion.getBoundingClientRect());
233
+ }
234
+ /**
235
+ * Shows a "Loading..." message.
236
+ * @param fractionLoaded - should be a number from 0 to 1, where 1 represents completely loaded.
237
+ */
225
238
  showLoadingWarning(fractionLoaded) {
226
239
  const loadingPercent = Math.round(fractionLoaded * 100);
227
240
  this.loadingWarning.innerText = this.localization.loading(loadingPercent);
228
241
  this.loadingWarning.style.display = 'block';
229
242
  }
243
+ /** @see {@link showLoadingWarning} */
230
244
  hideLoadingWarning() {
231
245
  this.loadingWarning.style.display = 'none';
232
246
  this.announceForAccessibility(this.localization.doneLoading);
@@ -340,8 +354,8 @@ export class Editor {
340
354
  delta = Vec3.of(0, 0, event.deltaY);
341
355
  }
342
356
  // Ensure that `pos` is relative to `this.renderingRegion`
343
- const bbox = this.renderingRegion.getBoundingClientRect();
344
- const pos = Vec2.of(event.clientX, event.clientY).minus(Vec2.of(bbox.left, bbox.top));
357
+ const bbox = this.getOutputBBoxInDOM();
358
+ const pos = Vec2.of(event.clientX, event.clientY).minus(bbox.topLeft);
345
359
  if (this.toolController.dispatchInputEvent({
346
360
  kind: InputEvtType.WheelEvt,
347
361
  delta,
@@ -689,7 +703,12 @@ export class Editor {
689
703
  isReadOnly() {
690
704
  return this.readOnly;
691
705
  }
692
- /** `apply` a command. `command` will be announced for accessibility. */
706
+ /**
707
+ * `apply` a command. `command` will be announced for accessibility.
708
+ *
709
+ * **Example**:
710
+ * [[include:doc-pages/inline-examples/adding-a-stroke.md]]
711
+ */
693
712
  dispatch(command, addToHistory = true) {
694
713
  const dispatchResult = this.dispatchNoAnnounce(command, addToHistory);
695
714
  const commandDescription = command.description(this, this.localization);
@@ -750,12 +769,15 @@ export class Editor {
750
769
  this.display.setDraftMode(false);
751
770
  this.hideLoadingWarning();
752
771
  }
753
- // @see {@link asyncApplyOrUnapplyCommands }
772
+ /** @see {@link asyncApplyOrUnapplyCommands } */
754
773
  asyncApplyCommands(commands, chunkSize) {
755
774
  return this.asyncApplyOrUnapplyCommands(commands, true, chunkSize);
756
775
  }
757
- // If `unapplyInReverseOrder`, commands are reversed before unapplying.
758
- // @see {@link asyncApplyOrUnapplyCommands }
776
+ /**
777
+ * @see {@link asyncApplyOrUnapplyCommands}
778
+ *
779
+ * If `unapplyInReverseOrder`, commands are reversed before unapplying.
780
+ */
759
781
  asyncUnapplyCommands(commands, chunkSize, unapplyInReverseOrder = false) {
760
782
  if (unapplyInReverseOrder) {
761
783
  commands = [...commands]; // copy
@@ -1233,7 +1255,7 @@ export class Editor {
1233
1255
  '',
1234
1256
  '',
1235
1257
  '== js-draw ==',
1236
- mitLicenseAttribution('2023 Henry Heino'),
1258
+ mitLicenseAttribution('2023-2024 Henry Heino'),
1237
1259
  '',
1238
1260
  ].join('\n'),
1239
1261
  minimized: true,
@@ -54,7 +54,7 @@ export default class SVGLoader {
54
54
  try {
55
55
  fill = Color4.fromString(fillAttribute);
56
56
  }
57
- catch (e) {
57
+ catch {
58
58
  console.error('Unknown fill color,', fillAttribute);
59
59
  }
60
60
  }
@@ -241,7 +241,7 @@ export default class SVGLoader {
241
241
  supportedAttrs?.push(highpTransformAttribute);
242
242
  }
243
243
  catch (e) {
244
- console.warn(`Unable to parse raw transform data, ${rawTransformData}. Falling back to CSS data.`);
244
+ console.warn(`Unable to parse raw transform data, ${rawTransformData}. Falling back to CSS data. Error:`, e);
245
245
  }
246
246
  }
247
247
  if (!transform) {
@@ -78,14 +78,14 @@ export declare class Viewport {
78
78
  minus(v: Vec3): Vec3;
79
79
  dot(other: Vec3): number;
80
80
  cross(other: Vec3): Vec3;
81
- scale(other: number | Vec3): Vec3;
81
+ scale(other: Vec3 | number): Vec3;
82
82
  orthog(): Vec3;
83
83
  extend(distance: number, direction: Vec3): Vec3;
84
84
  lerp(target: Vec3, fractionTo: number): Vec3;
85
85
  zip(other: Vec3, zip: (componentInThis: number, componentInOther: number) => number): Vec3;
86
86
  map(fn: (component: number, index: number) => number): Vec3;
87
87
  asArray(): [number, number, number];
88
- eq(other: Vec3, fuzz?: number | undefined): boolean;
88
+ eq(other: Vec3, fuzz?: number): boolean;
89
89
  toString(): string;
90
90
  };
91
91
  /** Returns the size of one screen pixel in canvas units. */
@@ -1,5 +1,10 @@
1
1
  import Editor from '../Editor';
2
2
  import { EditorLocalization } from '../localization';
3
+ /**
4
+ * A `Command` is an action that can be done, redone, and undone. It's used to enable undo/redo.
5
+ *
6
+ * See {@link Editor.dispatch}.
7
+ */
3
8
  export declare abstract class Command {
4
9
  abstract apply(editor: Editor): Promise<void> | void;
5
10
  abstract unapply(editor: Editor): Promise<void> | void;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * A `Command` is an action that can be done, redone, and undone. It's used to enable undo/redo.
3
+ *
4
+ * See {@link Editor.dispatch}.
5
+ */
1
6
  export class Command {
2
7
  // Called when the command is being deleted
3
8
  onDrop(_editor) { }
@@ -1,8 +1,15 @@
1
1
  import Editor from '../Editor';
2
2
  import Command from './Command';
3
3
  export type DeserializationCallback = (data: Record<string, any> | any[], editor: Editor) => SerializableCommand;
4
+ /**
5
+ * A command that can be serialized to or deserialized from JSON. To allow a command to be deserialized, {@link SerializableCommand.register}
6
+ * must be called for each {@link SerializableCommand}.
7
+ *
8
+ * This is used to [allow collaborative editing](https://github.com/personalizedrefrigerator/js-draw/tree/main/docs/examples/example-collaborative).
9
+ */
4
10
  export default abstract class SerializableCommand extends Command {
5
11
  #private;
12
+ /** @param commandTypeId - A unique identifier for this command. */
6
13
  constructor(commandTypeId: string);
7
14
  protected abstract serializeToJSON(): string | Record<string, any> | any[];
8
15
  private static deserializationCallbacks;
@@ -11,7 +11,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
11
11
  };
12
12
  var _SerializableCommand_commandTypeId;
13
13
  import Command from './Command.mjs';
14
+ /**
15
+ * A command that can be serialized to or deserialized from JSON. To allow a command to be deserialized, {@link SerializableCommand.register}
16
+ * must be called for each {@link SerializableCommand}.
17
+ *
18
+ * This is used to [allow collaborative editing](https://github.com/personalizedrefrigerator/js-draw/tree/main/docs/examples/example-collaborative).
19
+ */
14
20
  class SerializableCommand extends Command {
21
+ /** @param commandTypeId - A unique identifier for this command. */
15
22
  constructor(commandTypeId) {
16
23
  super();
17
24
  _SerializableCommand_commandTypeId.set(this, void 0);
@@ -32,6 +39,8 @@ class SerializableCommand extends Command {
32
39
  }
33
40
  // Convert a `string` containing JSON data (or the output of `JSON.parse`) into a
34
41
  // `Command`.
42
+ //
43
+ // Implementations should assume that `data` is untrusted.
35
44
  static deserialize(data, editor) {
36
45
  const json = typeof data === 'string' ? JSON.parse(data) : data;
37
46
  const commandType = json.commandType;
@@ -10,6 +10,6 @@ export interface AboutDialogEntry {
10
10
  minimized?: boolean;
11
11
  }
12
12
  declare const makeAboutDialog: (editor: Editor, entries: AboutDialogEntry[]) => {
13
- close: () => void;
13
+ close: () => Promise<void>;
14
14
  };
15
15
  export default makeAboutDialog;
@@ -1,24 +1,9 @@
1
+ import makeMessageDialog from './makeMessageDialog.mjs';
1
2
  const makeAboutDialog = (editor, entries) => {
2
- const overlay = document.createElement('div');
3
- const { remove: removeOverlay } = editor.createHTMLOverlay(overlay);
4
- overlay.classList.add('dialog-container', 'about-dialog-container');
5
- const dialog = document.createElement('dialog');
6
- const heading = document.createElement('h1');
7
- heading.innerText = editor.localization.about;
8
- heading.setAttribute('autofocus', 'true');
9
- const closeButton = document.createElement('button');
10
- closeButton.innerText = editor.localization.closeDialog;
11
- closeButton.classList.add('close-button');
12
- closeButton.onclick = () => removeOverlay();
13
- overlay.onclick = event => {
14
- if (event.target === overlay) {
15
- removeOverlay();
16
- }
17
- };
18
- const licenseContainer = document.createElement('div');
19
- licenseContainer.classList.add('about-entry-container');
20
- // Allow scrolling in the license container -- don't forward wheel events.
21
- licenseContainer.onwheel = evt => evt.stopPropagation();
3
+ const dialog = makeMessageDialog(editor, {
4
+ title: editor.localization.about,
5
+ contentClassNames: ['about-dialog-content'],
6
+ });
22
7
  for (const entry of entries) {
23
8
  const container = document.createElement(entry.minimized ? 'details' : 'div');
24
9
  container.classList.add('about-entry');
@@ -38,14 +23,11 @@ const makeAboutDialog = (editor, entries) => {
38
23
  bodyText.innerText = entry.text;
39
24
  container.appendChild(bodyText);
40
25
  }
41
- licenseContainer.appendChild(container);
26
+ dialog.appendChild(container);
42
27
  }
43
- dialog.replaceChildren(heading, licenseContainer, closeButton);
44
- overlay.replaceChildren(dialog);
45
- dialog.show();
46
28
  return {
47
29
  close: () => {
48
- removeOverlay();
30
+ return dialog.close();
49
31
  },
50
32
  };
51
33
  };
@@ -0,0 +1,11 @@
1
+ import type Editor from '../Editor';
2
+ export interface MessageDialogOptions {
3
+ title: string;
4
+ classNames?: string[];
5
+ contentClassNames?: string[];
6
+ }
7
+ declare const makeAboutDialog: (editor: Editor, options: MessageDialogOptions) => {
8
+ close: () => Promise<void>;
9
+ appendChild: (child: Node) => void;
10
+ };
11
+ export default makeAboutDialog;
@@ -0,0 +1,51 @@
1
+ import waitForTimeout from '../util/waitForTimeout.mjs';
2
+ const makeAboutDialog = (editor, options) => {
3
+ const overlay = document.createElement('div');
4
+ const { remove: removeOverlay } = editor.createHTMLOverlay(overlay);
5
+ overlay.classList.add('dialog-container', 'message-dialog-container', ...(options.classNames ?? []));
6
+ const dialog = document.createElement('dialog');
7
+ const contentWrapper = document.createElement('div');
8
+ contentWrapper.classList.add('message-dialog-content', ...(options.contentClassNames ?? []));
9
+ const heading = document.createElement('h1');
10
+ heading.textContent = options.title;
11
+ heading.setAttribute('autofocus', 'true');
12
+ const closeButton = document.createElement('button');
13
+ closeButton.innerText = editor.localization.closeDialog;
14
+ closeButton.classList.add('close');
15
+ const scrollRegion = document.createElement('div');
16
+ scrollRegion.classList.add('scroll');
17
+ // Allow scrolling in the scrollable container -- don't forward wheel events.
18
+ scrollRegion.onwheel = evt => evt.stopPropagation();
19
+ contentWrapper.replaceChildren(heading, scrollRegion, closeButton);
20
+ dialog.replaceChildren(contentWrapper);
21
+ overlay.replaceChildren(dialog);
22
+ const closeTimeout = 300;
23
+ dialog.style.setProperty('--close-delay', `${closeTimeout}ms`);
24
+ const closeDialog = async () => {
25
+ dialog.classList.add('-closing');
26
+ await waitForTimeout(closeTimeout);
27
+ dialog.close();
28
+ };
29
+ const addCloseListeners = () => {
30
+ dialog.addEventListener('pointerdown', event => {
31
+ if (event.target === dialog) {
32
+ void closeDialog();
33
+ }
34
+ });
35
+ dialog.onclose = () => {
36
+ removeOverlay();
37
+ };
38
+ closeButton.onclick = () => closeDialog();
39
+ };
40
+ addCloseListeners();
41
+ dialog.showModal();
42
+ return {
43
+ close: () => {
44
+ return closeDialog();
45
+ },
46
+ appendChild: (child) => {
47
+ scrollRegion.appendChild(child);
48
+ },
49
+ };
50
+ };
51
+ export default makeAboutDialog;
@@ -21,6 +21,9 @@ export type EditorImageNotifier = EventDispatcher<EditorImageEventType, {
21
21
  * 3. stop the render process early by returning `false`.
22
22
  */
23
23
  export type PreRenderComponentCallback = (component: AbstractComponent, componentsProcessed: number, totalComponents: number) => Promise<boolean>;
24
+ /**
25
+ * Handles lookup/storage of elements in the image.
26
+ */
24
27
  export default class EditorImage {
25
28
  private root;
26
29
  private background;
@@ -88,7 +91,8 @@ export default class EditorImage {
88
91
  *
89
92
  * @see {@link Display.flatten}
90
93
  *
91
- * @example
94
+ * **Example**:
95
+ *
92
96
  * [[include:doc-pages/inline-examples/adding-a-stroke.md]]
93
97
  */
94
98
  static addElement(elem: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
@@ -199,6 +203,16 @@ export declare class ImageNode {
199
203
  getParent(): ImageNode | null;
200
204
  protected getChildrenIntersectingRegion(region: Rect2, isTooSmallFilter?: TooSmallToRenderCheck): ImageNode[];
201
205
  getChildrenOrSelfIntersectingRegion(region: Rect2): ImageNode[];
206
+ /**
207
+ * Returns a list of `ImageNode`s with content (and thus no children).
208
+ * Override getChildrenIntersectingRegion to customize how this method
209
+ * determines whether/which children are in `region`.
210
+ *
211
+ * @paran region - All resultant `ImageNode`s must intersect `region`.
212
+ * @param isTooSmall - If `isTooSmall` returns true for an image node, that node
213
+ * is excluded from the output.
214
+ *
215
+ */
202
216
  getLeavesIntersectingRegion(region: Rect2, isTooSmall?: TooSmallToRenderCheck): ImageNode[];
203
217
  getChildWithContent(target: AbstractComponent): ImageNode | null;
204
218
  getLeaves(): ImageNode[];
@@ -20,7 +20,9 @@ export var EditorImageEventType;
20
20
  EditorImageEventType[EditorImageEventType["AutoresizeModeChanged"] = 1] = "AutoresizeModeChanged";
21
21
  })(EditorImageEventType || (EditorImageEventType = {}));
22
22
  let debugMode = false;
23
- // Handles lookup/storage of elements in the image
23
+ /**
24
+ * Handles lookup/storage of elements in the image.
25
+ */
24
26
  class EditorImage {
25
27
  // @internal
26
28
  constructor() {
@@ -181,7 +183,8 @@ class EditorImage {
181
183
  *
182
184
  * @see {@link Display.flatten}
183
185
  *
184
- * @example
186
+ * **Example**:
187
+ *
185
188
  * [[include:doc-pages/inline-examples/adding-a-stroke.md]]
186
189
  */
187
190
  static addElement(elem, applyByFlattening = false) {
@@ -518,9 +521,16 @@ export class ImageNode {
518
521
  }
519
522
  return this.getChildrenIntersectingRegion(region);
520
523
  }
521
- // Returns a list of `ImageNode`s with content (and thus no children).
522
- // Override getChildrenIntersectingRegion to customize how this method
523
- // determines whether/which children are in `region`.
524
+ /**
525
+ * Returns a list of `ImageNode`s with content (and thus no children).
526
+ * Override getChildrenIntersectingRegion to customize how this method
527
+ * determines whether/which children are in `region`.
528
+ *
529
+ * @paran region - All resultant `ImageNode`s must intersect `region`.
530
+ * @param isTooSmall - If `isTooSmall` returns true for an image node, that node
531
+ * is excluded from the output.
532
+ *
533
+ */
524
534
  getLeavesIntersectingRegion(region, isTooSmall) {
525
535
  const result = [];
526
536
  const workList = [];