js-draw 1.16.1 → 1.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. package/dist/bundle.js +2 -2
  2. package/dist/bundledStyles.js +1 -1
  3. package/dist/cjs/Editor.d.ts +76 -6
  4. package/dist/cjs/Editor.js +89 -89
  5. package/dist/cjs/Pointer.d.ts +2 -1
  6. package/dist/cjs/Pointer.js +9 -2
  7. package/dist/cjs/commands/localization.d.ts +1 -0
  8. package/dist/cjs/commands/localization.js +1 -0
  9. package/dist/cjs/commands/uniteCommands.d.ts +5 -1
  10. package/dist/cjs/commands/uniteCommands.js +33 -7
  11. package/dist/cjs/components/TextComponent.d.ts +36 -1
  12. package/dist/cjs/components/TextComponent.js +39 -1
  13. package/dist/cjs/components/builders/ArrowBuilder.js +1 -1
  14. package/dist/cjs/components/builders/PolylineBuilder.d.ts +35 -0
  15. package/dist/cjs/components/builders/PolylineBuilder.js +115 -0
  16. package/dist/cjs/components/builders/PressureSensitiveFreehandLineBuilder.js +1 -1
  17. package/dist/cjs/components/builders/autocorrect/makeShapeFitAutocorrect.js +1 -1
  18. package/dist/cjs/components/lib.d.ts +1 -0
  19. package/dist/cjs/components/lib.js +3 -1
  20. package/dist/cjs/components/util/StrokeSmoother.js +4 -4
  21. package/dist/cjs/image/EditorImage.d.ts +4 -1
  22. package/dist/cjs/image/EditorImage.js +4 -1
  23. package/dist/cjs/inputEvents.d.ts +11 -1
  24. package/dist/cjs/localizations/comments.d.ts +3 -0
  25. package/dist/cjs/localizations/comments.js +3 -0
  26. package/dist/cjs/localizations/de.js +0 -2
  27. package/dist/cjs/localizations/es.js +2 -2
  28. package/dist/cjs/rendering/renderers/CanvasRenderer.d.ts +7 -0
  29. package/dist/cjs/rendering/renderers/CanvasRenderer.js +16 -0
  30. package/dist/cjs/rendering/renderers/SVGRenderer.js +1 -1
  31. package/dist/cjs/toolbar/IconProvider.d.ts +6 -3
  32. package/dist/cjs/toolbar/IconProvider.js +6 -4
  33. package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +24 -1
  34. package/dist/cjs/toolbar/widgets/PenToolWidget.d.ts +1 -1
  35. package/dist/cjs/toolbar/widgets/PenToolWidget.js +7 -1
  36. package/dist/cjs/tools/Eraser.js +1 -1
  37. package/dist/cjs/tools/InputFilter/InputStabilizer.js +3 -3
  38. package/dist/cjs/tools/PasteHandler.js +36 -10
  39. package/dist/cjs/tools/Pen.js +2 -2
  40. package/dist/cjs/tools/SelectionTool/SelectionTool.js +23 -4
  41. package/dist/cjs/tools/SelectionTool/ToPointerAutoscroller.js +1 -1
  42. package/dist/cjs/tools/ToolController.d.ts +17 -1
  43. package/dist/cjs/tools/ToolController.js +21 -8
  44. package/dist/cjs/tools/localization.d.ts +2 -2
  45. package/dist/cjs/tools/localization.js +2 -2
  46. package/dist/cjs/util/ClipboardHandler.d.ts +27 -0
  47. package/dist/cjs/util/ClipboardHandler.js +205 -0
  48. package/dist/cjs/util/ClipboardHandler.test.d.ts +1 -0
  49. package/dist/cjs/version.d.ts +5 -0
  50. package/dist/cjs/version.js +6 -1
  51. package/dist/mjs/Editor.d.ts +76 -6
  52. package/dist/mjs/Editor.mjs +89 -89
  53. package/dist/mjs/Pointer.d.ts +2 -1
  54. package/dist/mjs/Pointer.mjs +9 -2
  55. package/dist/mjs/commands/localization.d.ts +1 -0
  56. package/dist/mjs/commands/localization.mjs +1 -0
  57. package/dist/mjs/commands/uniteCommands.d.ts +5 -1
  58. package/dist/mjs/commands/uniteCommands.mjs +33 -7
  59. package/dist/mjs/components/TextComponent.d.ts +36 -1
  60. package/dist/mjs/components/TextComponent.mjs +40 -2
  61. package/dist/mjs/components/builders/ArrowBuilder.mjs +1 -1
  62. package/dist/mjs/components/builders/PolylineBuilder.d.ts +35 -0
  63. package/dist/mjs/components/builders/PolylineBuilder.mjs +108 -0
  64. package/dist/mjs/components/builders/PressureSensitiveFreehandLineBuilder.mjs +1 -1
  65. package/dist/mjs/components/builders/autocorrect/makeShapeFitAutocorrect.mjs +1 -1
  66. package/dist/mjs/components/lib.d.ts +1 -0
  67. package/dist/mjs/components/lib.mjs +1 -0
  68. package/dist/mjs/components/util/StrokeSmoother.mjs +4 -4
  69. package/dist/mjs/image/EditorImage.d.ts +4 -1
  70. package/dist/mjs/image/EditorImage.mjs +4 -1
  71. package/dist/mjs/inputEvents.d.ts +11 -1
  72. package/dist/mjs/localizations/comments.d.ts +3 -0
  73. package/dist/mjs/localizations/comments.mjs +3 -0
  74. package/dist/mjs/localizations/de.mjs +0 -2
  75. package/dist/mjs/localizations/es.mjs +2 -2
  76. package/dist/mjs/rendering/renderers/CanvasRenderer.d.ts +7 -0
  77. package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +16 -0
  78. package/dist/mjs/rendering/renderers/SVGRenderer.mjs +1 -1
  79. package/dist/mjs/toolbar/IconProvider.d.ts +6 -3
  80. package/dist/mjs/toolbar/IconProvider.mjs +6 -4
  81. package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +24 -1
  82. package/dist/mjs/toolbar/widgets/PenToolWidget.d.ts +1 -1
  83. package/dist/mjs/toolbar/widgets/PenToolWidget.mjs +7 -1
  84. package/dist/mjs/tools/Eraser.mjs +1 -1
  85. package/dist/mjs/tools/InputFilter/InputStabilizer.mjs +3 -3
  86. package/dist/mjs/tools/PasteHandler.mjs +36 -10
  87. package/dist/mjs/tools/Pen.mjs +2 -2
  88. package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +23 -4
  89. package/dist/mjs/tools/SelectionTool/ToPointerAutoscroller.mjs +1 -1
  90. package/dist/mjs/tools/ToolController.d.ts +17 -1
  91. package/dist/mjs/tools/ToolController.mjs +21 -8
  92. package/dist/mjs/tools/localization.d.ts +2 -2
  93. package/dist/mjs/tools/localization.mjs +2 -2
  94. package/dist/mjs/util/ClipboardHandler.d.ts +27 -0
  95. package/dist/mjs/util/ClipboardHandler.mjs +200 -0
  96. package/dist/mjs/util/ClipboardHandler.test.d.ts +1 -0
  97. package/dist/mjs/version.d.ts +5 -0
  98. package/dist/mjs/version.mjs +6 -1
  99. package/package.json +6 -6
@@ -12,6 +12,12 @@ export default class ToolController implements InputEventListener {
12
12
  private isEditorReadOnly;
13
13
  /** @internal */
14
14
  constructor(editor: Editor, localization: ToolLocalization);
15
+ /**
16
+ * Replaces the current set of tools with `tools`. This should only be done before
17
+ * the creation of the app's toolbar (if using `AbstractToolbar`).
18
+ *
19
+ * If no `primaryToolGroup` is given, an empty one will be created.
20
+ */
15
21
  setTools(tools: BaseTool[], primaryToolGroup?: ToolEnabledGroup): void;
16
22
  /**
17
23
  * Add a tool that acts like one of the primary tools (only one primary tool can be enabled at a time).
@@ -22,7 +28,17 @@ export default class ToolController implements InputEventListener {
22
28
  */
23
29
  addPrimaryTool(tool: BaseTool): void;
24
30
  getPrimaryTools(): BaseTool[];
25
- addTool(tool: BaseTool): void;
31
+ /**
32
+ * Add a tool to the end of this' tool list (the added tool receives events after tools already added to this).
33
+ * This should be called before creating the app's toolbar.
34
+ *
35
+ * If `options.addToFront`, the tool is added to the beginning of this' tool list.
36
+ *
37
+ * Does nothing if the tool is already present.
38
+ */
39
+ addTool(tool: BaseTool, options?: {
40
+ addToFront: boolean;
41
+ }): void;
26
42
  /**
27
43
  * Removes **and destroys** all tools in `tools` from this.
28
44
  */
@@ -81,8 +81,12 @@ export default class ToolController {
81
81
  });
82
82
  this.activeTool = null;
83
83
  }
84
- // Replaces the current set of tools with `tools`. This should only be done before
85
- // the creation of the app's toolbar (if using `AbstractToolbar`).
84
+ /**
85
+ * Replaces the current set of tools with `tools`. This should only be done before
86
+ * the creation of the app's toolbar (if using `AbstractToolbar`).
87
+ *
88
+ * If no `primaryToolGroup` is given, an empty one will be created.
89
+ */
86
90
  setTools(tools, primaryToolGroup) {
87
91
  this.tools = tools;
88
92
  this.primaryToolGroup = primaryToolGroup ?? new ToolEnabledGroup();
@@ -108,14 +112,23 @@ export default class ToolController {
108
112
  return tool.getToolGroup() === this.primaryToolGroup;
109
113
  });
110
114
  }
111
- // Add a tool to the end of this' tool list (the added tool receives events after tools already added to this).
112
- // This should be called before creating the app's toolbar.
113
- //
114
- // A tool should only be added once.
115
- addTool(tool) {
115
+ /**
116
+ * Add a tool to the end of this' tool list (the added tool receives events after tools already added to this).
117
+ * This should be called before creating the app's toolbar.
118
+ *
119
+ * If `options.addToFront`, the tool is added to the beginning of this' tool list.
120
+ *
121
+ * Does nothing if the tool is already present.
122
+ */
123
+ addTool(tool, options) {
116
124
  // Only add if not already present.
117
125
  if (!this.tools.includes(tool)) {
118
- this.tools.push(tool);
126
+ if (options?.addToFront) {
127
+ this.tools.splice(0, 0, tool);
128
+ }
129
+ else {
130
+ this.tools.push(tool);
131
+ }
119
132
  }
120
133
  }
121
134
  /**
@@ -26,8 +26,8 @@ export interface ToolLocalization {
26
26
  findDialogHidden: string;
27
27
  focusedFoundText: (currentMatchNumber: number, totalMatches: number) => string;
28
28
  anyDevicePanning: string;
29
- copied: (count: number, description: string) => string;
30
- pasted: (count: number, description: string) => string;
29
+ copied: (count: number) => string;
30
+ pasted: (count: number) => string;
31
31
  toolEnabledAnnouncement: (toolName: string) => string;
32
32
  toolDisabledAnnouncement: (toolName: string) => string;
33
33
  }
@@ -26,8 +26,8 @@ export const defaultToolLocalization = {
26
26
  findDialogHidden: 'Find dialog hidden',
27
27
  focusedFoundText: (matchIdx, totalMatches) => `Viewing match ${matchIdx} of ${totalMatches}`,
28
28
  anyDevicePanning: 'Any device panning',
29
- copied: (count, description) => `Copied ${count} ${description}`,
30
- pasted: (count, description) => `Pasted ${count} ${description}`,
29
+ copied: (count) => `Copied ${count} item(s)`,
30
+ pasted: (count) => `Pasted ${count} item(s)`,
31
31
  toolEnabledAnnouncement: (toolName) => `${toolName} enabled`,
32
32
  toolDisabledAnnouncement: (toolName) => `${toolName} disabled`,
33
33
  };
@@ -0,0 +1,27 @@
1
+ import { Editor } from '../Editor';
2
+ /**
3
+ * Handles conversion between the browser clipboard APIs and internal
4
+ * js-draw clipboard events.
5
+ */
6
+ export default class ClipboardHandler {
7
+ #private;
8
+ private editor;
9
+ constructor(editor: Editor);
10
+ /**
11
+ * Pastes data from the clipboard into the editor associated with
12
+ * this handler.
13
+ *
14
+ * @param event Optional -- a clipboard/drag event. If not provided,
15
+ * `navigator.clipboard` will be used instead.
16
+ * @returns true if the paste event was handled by the editor.
17
+ */
18
+ paste(event?: DragEvent | ClipboardEvent): Promise<boolean>;
19
+ /**
20
+ * Copies text from the editor associated with this.
21
+ *
22
+ * Even if `event` is provided, the `navigator.clipboard` API may be used if image data
23
+ * is to be copied. This is done because `ClipboardEvent`s seem to not support attaching
24
+ * images.
25
+ */
26
+ copy(event?: ClipboardEvent): Promise<void>;
27
+ }
@@ -0,0 +1,200 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
7
+ if (kind === "m") throw new TypeError("Private method is not writable");
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
+ };
12
+ var _ClipboardHandler_preferClipboardEvents;
13
+ import { InputEvtType } from '../inputEvents.mjs';
14
+ import fileToBase64Url from './fileToBase64Url.mjs';
15
+ const isTextMimeType = (mime) =>
16
+ // +xml: Handles image/svg+xml
17
+ mime.endsWith('+xml') || mime.startsWith('text/');
18
+ /**
19
+ * Handles conversion between the browser clipboard APIs and internal
20
+ * js-draw clipboard events.
21
+ */
22
+ class ClipboardHandler {
23
+ constructor(editor) {
24
+ this.editor = editor;
25
+ _ClipboardHandler_preferClipboardEvents.set(this, false);
26
+ }
27
+ /**
28
+ * Pastes data from the clipboard into the editor associated with
29
+ * this handler.
30
+ *
31
+ * @param event Optional -- a clipboard/drag event. If not provided,
32
+ * `navigator.clipboard` will be used instead.
33
+ * @returns true if the paste event was handled by the editor.
34
+ */
35
+ async paste(event) {
36
+ const editor = this.editor;
37
+ const clipboardData = event?.dataTransfer ?? event?.clipboardData ?? null;
38
+ const hasEvent = !!clipboardData;
39
+ const sendPasteEvent = (mime, data) => {
40
+ return data && editor.toolController.dispatchInputEvent({
41
+ kind: InputEvtType.PasteEvent,
42
+ mime,
43
+ data,
44
+ });
45
+ };
46
+ // Listed in order of precedence
47
+ const supportedMIMEs = [
48
+ 'image/svg+xml',
49
+ 'text/html',
50
+ 'image/png',
51
+ 'image/jpeg',
52
+ 'text/plain',
53
+ ];
54
+ let files = [];
55
+ const textData = new Map();
56
+ if (hasEvent) {
57
+ // NOTE: On some browsers, .getData and .files must be used before any async operations.
58
+ files = [...clipboardData.files];
59
+ for (const mime of supportedMIMEs) {
60
+ const data = clipboardData.getData(mime);
61
+ if (data) {
62
+ textData.set(mime, data);
63
+ }
64
+ }
65
+ }
66
+ else {
67
+ const clipboardData = await navigator.clipboard.read();
68
+ for (const item of clipboardData) {
69
+ for (const mime of item.types) {
70
+ if (supportedMIMEs.includes(mime)) {
71
+ files.push(await item.getType(mime));
72
+ }
73
+ }
74
+ }
75
+ }
76
+ // Returns true if handled
77
+ const handleMIME = async (mime) => {
78
+ const isTextFormat = isTextMimeType(mime);
79
+ if (isTextFormat) {
80
+ const data = textData.get(mime);
81
+ if (sendPasteEvent(mime, data)) {
82
+ event?.preventDefault();
83
+ return true;
84
+ }
85
+ }
86
+ for (const file of files) {
87
+ const fileType = file.type.toLowerCase();
88
+ if (fileType !== mime) {
89
+ continue;
90
+ }
91
+ if (isTextFormat) {
92
+ const text = await file.text();
93
+ if (sendPasteEvent(mime, text)) {
94
+ event?.preventDefault();
95
+ return true;
96
+ }
97
+ }
98
+ else {
99
+ editor.showLoadingWarning(0);
100
+ const onprogress = (evt) => {
101
+ editor.showLoadingWarning(evt.loaded / evt.total);
102
+ };
103
+ try {
104
+ const data = await fileToBase64Url(file, { onprogress });
105
+ if (sendPasteEvent(mime, data)) {
106
+ event?.preventDefault();
107
+ editor.hideLoadingWarning();
108
+ return true;
109
+ }
110
+ }
111
+ catch (e) {
112
+ console.error('Error reading image:', e);
113
+ }
114
+ editor.hideLoadingWarning();
115
+ }
116
+ }
117
+ return false;
118
+ };
119
+ for (const mime of supportedMIMEs) {
120
+ if (await handleMIME(mime)) {
121
+ return true;
122
+ }
123
+ }
124
+ return false;
125
+ }
126
+ /**
127
+ * Copies text from the editor associated with this.
128
+ *
129
+ * Even if `event` is provided, the `navigator.clipboard` API may be used if image data
130
+ * is to be copied. This is done because `ClipboardEvent`s seem to not support attaching
131
+ * images.
132
+ */
133
+ copy(event) {
134
+ const mimeToData = Object.create(null);
135
+ if (this.editor.toolController.dispatchInputEvent({
136
+ kind: InputEvtType.CopyEvent,
137
+ setData: (mime, data) => {
138
+ mimeToData[mime] = data;
139
+ },
140
+ })) {
141
+ event?.preventDefault();
142
+ }
143
+ const mimeTypes = Object.keys(mimeToData);
144
+ const hasNonTextMimeTypes = mimeTypes.some(mime => !isTextMimeType(mime));
145
+ const copyToEvent = () => {
146
+ if (!event) {
147
+ throw new Error('Unable to paste -- no event provided.');
148
+ }
149
+ for (const key in mimeToData) {
150
+ const value = mimeToData[key];
151
+ if (typeof value === 'string') {
152
+ event.clipboardData?.setData(key, value);
153
+ }
154
+ }
155
+ };
156
+ const copyToClipboardApi = () => {
157
+ const mappedMimeToData = Object.create(null);
158
+ const mimeMapping = {
159
+ // image/svg+xml is unsupported in Chrome.
160
+ 'image/svg+xml': 'text/html',
161
+ };
162
+ for (const key in mimeToData) {
163
+ const data = mimeToData[key];
164
+ const mappedKey = mimeMapping[key] || key;
165
+ if (typeof data === 'string') {
166
+ mappedMimeToData[mappedKey] = new Blob([new TextEncoder().encode(data)], { type: mappedKey });
167
+ }
168
+ else {
169
+ mappedMimeToData[mappedKey] = data;
170
+ }
171
+ }
172
+ return navigator.clipboard.write([new ClipboardItem(mappedMimeToData)]);
173
+ };
174
+ const supportsClipboardApi = (typeof ClipboardItem !== 'undefined'
175
+ && typeof navigator?.clipboard?.write !== 'undefined');
176
+ if (!__classPrivateFieldGet(this, _ClipboardHandler_preferClipboardEvents, "f") && supportsClipboardApi && (hasNonTextMimeTypes || !event)) {
177
+ let clipboardApiPromise = null;
178
+ const fallBackToCopyEvent = (reason) => {
179
+ console.warn('Unable to copy to the clipboard API. Future calls to .copy will use ClipboardEvents if possible.', reason);
180
+ __classPrivateFieldSet(this, _ClipboardHandler_preferClipboardEvents, true, "f");
181
+ copyToEvent();
182
+ };
183
+ try {
184
+ clipboardApiPromise = copyToClipboardApi();
185
+ }
186
+ catch (error) {
187
+ fallBackToCopyEvent(error);
188
+ }
189
+ if (clipboardApiPromise) {
190
+ return clipboardApiPromise.catch(fallBackToCopyEvent);
191
+ }
192
+ }
193
+ else {
194
+ copyToEvent();
195
+ }
196
+ return Promise.resolve();
197
+ }
198
+ }
199
+ _ClipboardHandler_preferClipboardEvents = new WeakMap();
200
+ export default ClipboardHandler;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Contains the current version of the library -- used
3
+ * internaly (e.g. for documentation).
4
+ * @internal
5
+ */
1
6
  declare const _default: {
2
7
  number: string;
3
8
  };
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Contains the current version of the library -- used
3
+ * internaly (e.g. for documentation).
4
+ * @internal
5
+ */
1
6
  export default {
2
- number: '1.16.1',
7
+ number: '1.17.0',
3
8
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "1.16.1",
3
+ "version": "1.17.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",
@@ -57,18 +57,18 @@
57
57
  "scripts": {
58
58
  "dist-test": "cd dist-test/test_imports && npm install && npm run test",
59
59
  "dist": "npm run build && npm run dist-test",
60
- "build": "rm -rf ./dist/* && mkdir -p dist && build-tool build",
61
- "watch": "rm -rf ./dist/* && mkdir -p dist && build-tool watch",
60
+ "build": "rm -rf ./dist/* && build-tool build",
61
+ "watch": "build-tool watch",
62
62
  "build-translation-templates": "build-tool build-translation-templates",
63
63
  "prepack": "npm run dist && cd ../../ && npm run test && cd packages/js-draw && ts-node tools/copyREADME.ts copy",
64
64
  "postpack": "ts-node tools/copyREADME.ts revert"
65
65
  },
66
66
  "dependencies": {
67
- "@js-draw/math": "^1.16.0",
67
+ "@js-draw/math": "^1.17.0",
68
68
  "@melloware/coloris": "0.22.0"
69
69
  },
70
70
  "devDependencies": {
71
- "@js-draw/build-tool": "^1.11.1",
71
+ "@js-draw/build-tool": "^1.17.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": "7a1d4ea8bae0a2549494fce672b9d43ce97a68a8"
89
+ "gitHead": "d0eff585750ab5670af3acda8ddff090e8825bd3"
90
90
  }