js-draw 1.18.0 → 1.19.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. package/dist/Editor.css +35 -3
  2. package/dist/bundle.js +2 -2
  3. package/dist/bundledStyles.js +1 -1
  4. package/dist/cjs/Editor.d.ts +20 -1
  5. package/dist/cjs/Editor.js +6 -0
  6. package/dist/cjs/{SVGLoader.d.ts → SVGLoader/index.d.ts} +1 -1
  7. package/dist/cjs/{SVGLoader.js → SVGLoader/index.js} +12 -29
  8. package/dist/cjs/SVGLoader/utils/determineFontSize.d.ts +3 -0
  9. package/dist/cjs/SVGLoader/utils/determineFontSize.js +27 -0
  10. package/dist/cjs/Viewport.d.ts +33 -1
  11. package/dist/cjs/components/TextComponent.js +3 -1
  12. package/dist/cjs/rendering/caching/RenderingCacheNode.js +20 -15
  13. package/dist/cjs/testing/findNodeWithText.d.ts +3 -0
  14. package/dist/cjs/testing/findNodeWithText.js +16 -0
  15. package/dist/cjs/testing/firstElementAncestorOfNode.d.ts +3 -0
  16. package/dist/cjs/testing/firstElementAncestorOfNode.js +13 -0
  17. package/dist/cjs/testing/sendKeyPressRelease.d.ts +3 -0
  18. package/dist/cjs/testing/sendKeyPressRelease.js +8 -0
  19. package/dist/cjs/testing/sendPenEvent.d.ts +2 -2
  20. package/dist/cjs/testing/sendPenEvent.js +26 -3
  21. package/dist/cjs/toolbar/localization.d.ts +2 -0
  22. package/dist/cjs/toolbar/localization.js +2 -0
  23. package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +1 -0
  24. package/dist/cjs/toolbar/widgets/BaseWidget.js +1 -0
  25. package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +22 -0
  26. package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.js +58 -0
  27. package/dist/cjs/toolbar/widgets/InsertImageWidget/fileToImages.d.ts +3 -0
  28. package/dist/cjs/toolbar/widgets/InsertImageWidget/fileToImages.js +21 -0
  29. package/dist/cjs/toolbar/widgets/InsertImageWidget/index.d.ts +37 -0
  30. package/dist/cjs/toolbar/widgets/InsertImageWidget/index.js +281 -0
  31. package/dist/cjs/toolbar/widgets/TextToolWidget.js +5 -3
  32. package/dist/cjs/toolbar/widgets/TextToolWidget.test.d.ts +1 -0
  33. package/dist/cjs/toolbar/widgets/components/makeFileInput.d.ts +12 -2
  34. package/dist/cjs/toolbar/widgets/components/makeFileInput.js +102 -45
  35. package/dist/cjs/toolbar/widgets/components/makeFileInput.test.d.ts +1 -0
  36. package/dist/cjs/toolbar/widgets/components/makeSnappedList.d.ts +15 -0
  37. package/dist/cjs/toolbar/widgets/components/makeSnappedList.js +103 -0
  38. package/dist/cjs/tools/Eraser.d.ts +7 -2
  39. package/dist/cjs/tools/Eraser.js +54 -1
  40. package/dist/cjs/tools/SelectionTool/Selection.d.ts +2 -2
  41. package/dist/cjs/tools/SelectionTool/Selection.js +20 -20
  42. package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +8 -2
  43. package/dist/cjs/tools/SelectionTool/SelectionHandle.js +6 -0
  44. package/dist/cjs/tools/SelectionTool/SelectionTool.js +1 -1
  45. package/dist/cjs/tools/SelectionTool/types.d.ts +19 -0
  46. package/dist/cjs/tools/TextTool.js +2 -1
  47. package/dist/cjs/tools/TextTool.test.d.ts +1 -0
  48. package/dist/cjs/tools/ToolController.d.ts +2 -0
  49. package/dist/cjs/tools/ToolController.js +10 -1
  50. package/dist/cjs/util/ReactiveValue.d.ts +2 -0
  51. package/dist/cjs/util/ReactiveValue.js +11 -0
  52. package/dist/cjs/util/bytesToSizeString.d.ts +8 -0
  53. package/dist/cjs/util/bytesToSizeString.js +26 -0
  54. package/dist/cjs/util/bytesToSizeString.test.d.ts +1 -0
  55. package/dist/cjs/util/stopPropagationOfScrollingWheelEvents.js +10 -6
  56. package/dist/cjs/util/waitForAll.d.ts +2 -0
  57. package/dist/cjs/util/waitForAll.js +2 -0
  58. package/dist/cjs/util/waitForImageLoaded.js +3 -0
  59. package/dist/cjs/util/waitForTimeout.d.ts +1 -0
  60. package/dist/cjs/util/waitForTimeout.js +1 -1
  61. package/dist/cjs/version.js +1 -1
  62. package/dist/mjs/Editor.d.ts +20 -1
  63. package/dist/mjs/Editor.mjs +6 -0
  64. package/dist/mjs/{SVGLoader.d.ts → SVGLoader/index.d.ts} +1 -1
  65. package/dist/mjs/{SVGLoader.mjs → SVGLoader/index.mjs} +12 -29
  66. package/dist/mjs/SVGLoader/index.test.d.ts +1 -0
  67. package/dist/mjs/SVGLoader/utils/determineFontSize.d.ts +3 -0
  68. package/dist/mjs/SVGLoader/utils/determineFontSize.mjs +25 -0
  69. package/dist/mjs/Viewport.d.ts +33 -1
  70. package/dist/mjs/components/TextComponent.mjs +3 -1
  71. package/dist/mjs/rendering/caching/RenderingCacheNode.mjs +20 -15
  72. package/dist/mjs/testing/findNodeWithText.d.ts +3 -0
  73. package/dist/mjs/testing/findNodeWithText.mjs +14 -0
  74. package/dist/mjs/testing/firstElementAncestorOfNode.d.ts +3 -0
  75. package/dist/mjs/testing/firstElementAncestorOfNode.mjs +11 -0
  76. package/dist/mjs/testing/sendKeyPressRelease.d.ts +3 -0
  77. package/dist/mjs/testing/sendKeyPressRelease.mjs +6 -0
  78. package/dist/mjs/testing/sendPenEvent.d.ts +2 -2
  79. package/dist/mjs/testing/sendPenEvent.mjs +3 -3
  80. package/dist/mjs/toolbar/localization.d.ts +2 -0
  81. package/dist/mjs/toolbar/localization.mjs +2 -0
  82. package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +1 -0
  83. package/dist/mjs/toolbar/widgets/BaseWidget.mjs +1 -0
  84. package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +22 -0
  85. package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.mjs +54 -0
  86. package/dist/mjs/toolbar/widgets/InsertImageWidget/fileToImages.d.ts +3 -0
  87. package/dist/mjs/toolbar/widgets/InsertImageWidget/fileToImages.mjs +16 -0
  88. package/dist/mjs/toolbar/widgets/InsertImageWidget/index.d.ts +37 -0
  89. package/dist/mjs/toolbar/widgets/InsertImageWidget/index.mjs +276 -0
  90. package/dist/mjs/toolbar/widgets/InsertImageWidget/index.test.d.ts +1 -0
  91. package/dist/mjs/toolbar/widgets/TextToolWidget.mjs +5 -3
  92. package/dist/mjs/toolbar/widgets/TextToolWidget.test.d.ts +1 -0
  93. package/dist/mjs/toolbar/widgets/components/makeFileInput.d.ts +12 -2
  94. package/dist/mjs/toolbar/widgets/components/makeFileInput.mjs +102 -45
  95. package/dist/mjs/toolbar/widgets/components/makeFileInput.test.d.ts +1 -0
  96. package/dist/mjs/toolbar/widgets/components/makeSnappedList.d.ts +15 -0
  97. package/dist/mjs/toolbar/widgets/components/makeSnappedList.mjs +98 -0
  98. package/dist/mjs/tools/Eraser.d.ts +7 -2
  99. package/dist/mjs/tools/Eraser.mjs +54 -1
  100. package/dist/mjs/tools/SelectionTool/Selection.d.ts +2 -2
  101. package/dist/mjs/tools/SelectionTool/Selection.mjs +20 -20
  102. package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +8 -2
  103. package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +6 -0
  104. package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +1 -1
  105. package/dist/mjs/tools/SelectionTool/types.d.ts +19 -0
  106. package/dist/mjs/tools/TextTool.mjs +2 -1
  107. package/dist/mjs/tools/TextTool.test.d.ts +1 -0
  108. package/dist/mjs/tools/ToolController.d.ts +2 -0
  109. package/dist/mjs/tools/ToolController.mjs +10 -1
  110. package/dist/mjs/util/ReactiveValue.d.ts +2 -0
  111. package/dist/mjs/util/ReactiveValue.mjs +11 -0
  112. package/dist/mjs/util/bytesToSizeString.d.ts +8 -0
  113. package/dist/mjs/util/bytesToSizeString.mjs +24 -0
  114. package/dist/mjs/util/bytesToSizeString.test.d.ts +1 -0
  115. package/dist/mjs/util/stopPropagationOfScrollingWheelEvents.mjs +10 -6
  116. package/dist/mjs/util/waitForAll.d.ts +2 -0
  117. package/dist/mjs/util/waitForAll.mjs +2 -0
  118. package/dist/mjs/util/waitForImageLoaded.mjs +3 -0
  119. package/dist/mjs/util/waitForTimeout.d.ts +1 -0
  120. package/dist/mjs/util/waitForTimeout.mjs +1 -1
  121. package/dist/mjs/version.mjs +1 -1
  122. package/package.json +4 -4
  123. package/src/toolbar/toolbar.scss +1 -7
  124. package/src/toolbar/widgets/{InsertImageWidget.scss → InsertImageWidget/index.scss} +3 -2
  125. package/src/toolbar/widgets/components/components.scss +2 -1
  126. package/src/toolbar/widgets/components/makeFileInput.scss +14 -1
  127. package/src/toolbar/widgets/components/makeSnappedList.scss +28 -0
  128. package/src/toolbar/widgets/widgets.scss +7 -0
  129. package/dist/cjs/toolbar/widgets/InsertImageWidget.d.ts +0 -22
  130. package/dist/cjs/toolbar/widgets/InsertImageWidget.js +0 -269
  131. package/dist/mjs/toolbar/widgets/InsertImageWidget.d.ts +0 -22
  132. package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +0 -264
  133. /package/dist/cjs/{SVGLoader.test.d.ts → SVGLoader/index.test.d.ts} +0 -0
  134. /package/dist/{mjs/SVGLoader.test.d.ts → cjs/toolbar/widgets/InsertImageWidget/index.test.d.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "1.18.0",
3
+ "version": "1.19.1",
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": "50fa44a2bb68b93d24efea433760a5e45c56293f"
90
90
  }
@@ -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,28 @@
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
+ overflow-y: auto;
6
+ scroll-snap-type: y mandatory;
7
+ height: min(200px, 50vh);
8
+ display: flex;
9
+ flex-direction: column;
10
+
11
+ > .item {
12
+ height: 100%;
13
+ width: 100%;
14
+ flex-shrink: 0;
15
+
16
+ display: flex;
17
+ justify-content: center;
18
+ align-items: center;
19
+
20
+ scroll-snap-align: start;
21
+ scroll-snap-stop: always;
22
+ box-sizing: border-box;
23
+ }
24
+
25
+ &.-empty {
26
+ display: none;
27
+ }
28
+ }
@@ -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
- }
@@ -1,269 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const ImageComponent_1 = __importDefault(require("../../components/ImageComponent"));
7
- const Erase_1 = __importDefault(require("../../commands/Erase"));
8
- const EditorImage_1 = __importDefault(require("../../image/EditorImage"));
9
- const uniteCommands_1 = __importDefault(require("../../commands/uniteCommands"));
10
- const SelectionTool_1 = __importDefault(require("../../tools/SelectionTool/SelectionTool"));
11
- const math_1 = require("@js-draw/math");
12
- const fileToBase64Url_1 = __importDefault(require("../../util/fileToBase64Url"));
13
- const BaseWidget_1 = __importDefault(require("./BaseWidget"));
14
- const types_1 = require("../../types");
15
- const constants_1 = require("../constants");
16
- const makeFileInput_1 = __importDefault(require("./components/makeFileInput"));
17
- class ImageWrapper {
18
- constructor(imageBase64Url, preview, onUrlUpdate) {
19
- this.imageBase64Url = imageBase64Url;
20
- this.preview = preview;
21
- this.onUrlUpdate = onUrlUpdate;
22
- this.originalSrc = imageBase64Url;
23
- preview.src = imageBase64Url;
24
- }
25
- updateImageData(base64DataUrl) {
26
- this.preview.src = base64DataUrl;
27
- this.imageBase64Url = base64DataUrl;
28
- this.onUrlUpdate();
29
- }
30
- decreaseSize(resizeFactor = 3 / 4) {
31
- const canvas = document.createElement('canvas');
32
- canvas.width = this.preview.naturalWidth * resizeFactor;
33
- canvas.height = this.preview.naturalHeight * resizeFactor;
34
- const ctx = canvas.getContext('2d');
35
- ctx?.drawImage(this.preview, 0, 0, canvas.width, canvas.height);
36
- // JPEG can be much smaller than PNG for the same image size. Prefer it if
37
- // the image is already a JPEG.
38
- const format = this.originalSrc?.startsWith('data:image/jpeg;') ? 'image/jpeg' : 'image/png';
39
- this.updateImageData(canvas.toDataURL(format));
40
- }
41
- reset() {
42
- this.updateImageData(this.originalSrc);
43
- }
44
- isChanged() {
45
- return this.imageBase64Url !== this.originalSrc;
46
- }
47
- getBase64Url() {
48
- return this.imageBase64Url;
49
- }
50
- static fromSrcAndPreview(initialBase64Src, preview, onUrlUpdate) {
51
- return new ImageWrapper(initialBase64Src, preview, onUrlUpdate);
52
- }
53
- }
54
- class InsertImageWidget extends BaseWidget_1.default {
55
- constructor(editor, localization) {
56
- localization ??= editor.localization;
57
- super(editor, 'insert-image-widget', localization);
58
- this.image = null;
59
- // Make the dropdown showable
60
- this.container.classList.add('dropdownShowable');
61
- editor.notifier.on(types_1.EditorEventType.SelectionUpdated, event => {
62
- if (event.kind === types_1.EditorEventType.SelectionUpdated && this.isDropdownVisible()) {
63
- this.updateInputs();
64
- }
65
- });
66
- }
67
- getTitle() {
68
- return this.localizationTable.image;
69
- }
70
- createIcon() {
71
- return this.editor.icons.makeInsertImageIcon();
72
- }
73
- setDropdownVisible(visible) {
74
- super.setDropdownVisible(visible);
75
- // Update the dropdown just before showing.
76
- if (this.isDropdownVisible()) {
77
- this.updateInputs();
78
- }
79
- }
80
- handleClick() {
81
- this.setDropdownVisible(!this.isDropdownVisible());
82
- }
83
- fillDropdown(dropdown) {
84
- const container = document.createElement('div');
85
- container.classList.add('insert-image-widget-dropdown-content', `${constants_1.toolbarCSSPrefix}spacedList`, `${constants_1.toolbarCSSPrefix}nonbutton-controls-main-list`);
86
- const { container: chooseImageRow, selectedFiles, } = (0, makeFileInput_1.default)(this.localizationTable.chooseFile, this.editor, 'image/*');
87
- const altTextRow = document.createElement('div');
88
- this.imagePreview = document.createElement('img');
89
- this.statusView = document.createElement('div');
90
- const actionButtonRow = document.createElement('div');
91
- actionButtonRow.classList.add('action-button-row');
92
- this.statusView.classList.add('insert-image-image-status-view');
93
- this.submitButton = document.createElement('button');
94
- this.selectedFiles = selectedFiles;
95
- this.imageAltTextInput = document.createElement('input');
96
- // Label the alt text input
97
- const imageAltTextLabel = document.createElement('label');
98
- const altTextInputId = `insert-image-alt-text-input-${InsertImageWidget.nextInputId++}`;
99
- this.imageAltTextInput.setAttribute('id', altTextInputId);
100
- imageAltTextLabel.htmlFor = altTextInputId;
101
- imageAltTextLabel.innerText = this.localizationTable.inputAltText;
102
- this.imageAltTextInput.type = 'text';
103
- this.imageAltTextInput.placeholder = this.localizationTable.describeTheImage;
104
- this.statusView.setAttribute('aria-live', 'polite');
105
- this.submitButton.innerText = this.localizationTable.submit;
106
- this.selectedFiles.onUpdateAndNow(async (files) => {
107
- if (files.length === 0) {
108
- this.image = null;
109
- this.onImageDataUpdate();
110
- return;
111
- }
112
- this.imagePreview.style.display = 'block';
113
- const image = files[0];
114
- let data = null;
115
- let errorMessage = null;
116
- try {
117
- data = await (0, fileToBase64Url_1.default)(image);
118
- }
119
- catch (error) {
120
- console.error('Image load error', error);
121
- errorMessage = this.localizationTable.imageLoadError(error);
122
- }
123
- if (data) {
124
- this.image = ImageWrapper.fromSrcAndPreview(data, this.imagePreview, () => this.onImageDataUpdate());
125
- }
126
- else {
127
- this.image = null;
128
- }
129
- this.onImageDataUpdate();
130
- // Show the error after image update callbacks to ensure it is
131
- // actually shown.
132
- if (errorMessage) {
133
- this.statusView.innerText = errorMessage;
134
- }
135
- });
136
- altTextRow.replaceChildren(imageAltTextLabel, this.imageAltTextInput);
137
- actionButtonRow.replaceChildren(this.submitButton);
138
- container.replaceChildren(chooseImageRow, altTextRow, this.imagePreview, this.statusView, actionButtonRow);
139
- dropdown.replaceChildren(container);
140
- return true;
141
- }
142
- onImageDataUpdate() {
143
- const base64Data = this.image?.getBase64Url();
144
- if (base64Data) {
145
- this.submitButton.disabled = false;
146
- this.submitButton.style.display = '';
147
- this.imagePreview.style.display = '';
148
- this.updateImageSizeDisplay();
149
- }
150
- else {
151
- this.submitButton.disabled = true;
152
- this.submitButton.style.display = 'none';
153
- this.statusView.innerText = '';
154
- this.imagePreview.style.display = 'none';
155
- this.submitButton.disabled = true;
156
- }
157
- }
158
- hideDialog() {
159
- this.setDropdownVisible(false);
160
- }
161
- updateImageSizeDisplay() {
162
- const imageData = this.image?.getBase64Url() ?? '';
163
- const sizeInKiB = imageData.length / 1024;
164
- const sizeInMiB = sizeInKiB / 1024;
165
- let units = 'KiB';
166
- let size = sizeInKiB;
167
- if (sizeInMiB >= 1) {
168
- size = sizeInMiB;
169
- units = 'MiB';
170
- }
171
- const sizeText = document.createElement('span');
172
- sizeText.innerText = this.localizationTable.imageSize(Math.round(size), units);
173
- // Add a button to allow decreasing the size of large images.
174
- const decreaseSizeButton = document.createElement('button');
175
- decreaseSizeButton.innerText = this.localizationTable.decreaseImageSize;
176
- decreaseSizeButton.onclick = () => {
177
- this.image?.decreaseSize();
178
- };
179
- const resetSizeButton = document.createElement('button');
180
- resetSizeButton.innerText = this.localizationTable.resetImage;
181
- resetSizeButton.onclick = () => {
182
- this.image?.reset();
183
- };
184
- this.statusView.replaceChildren(sizeText);
185
- const largeImageThreshold = 0.12; // MiB
186
- if (sizeInMiB > largeImageThreshold) {
187
- this.statusView.appendChild(decreaseSizeButton);
188
- }
189
- else if (this.image?.isChanged()) {
190
- this.statusView.appendChild(resetSizeButton);
191
- }
192
- }
193
- updateInputs() {
194
- const resetInputs = () => {
195
- this.selectedFiles?.set([]);
196
- this.imageAltTextInput.value = '';
197
- this.imagePreview.style.display = 'none';
198
- this.submitButton.disabled = true;
199
- this.statusView.innerText = '';
200
- this.submitButton.style.display = '';
201
- this.imageAltTextInput.oninput = null;
202
- };
203
- resetInputs();
204
- const selectionTools = this.editor.toolController.getMatchingTools(SelectionTool_1.default);
205
- const selectedObjects = selectionTools.map(tool => tool.getSelectedObjects()).flat();
206
- // Check: Is there a selected image that can be edited?
207
- let editingImage = null;
208
- if (selectedObjects.length === 1 && selectedObjects[0] instanceof ImageComponent_1.default) {
209
- editingImage = selectedObjects[0];
210
- this.imageAltTextInput.value = editingImage.getAltText() ?? '';
211
- this.image = ImageWrapper.fromSrcAndPreview(editingImage.getURL(), this.imagePreview, () => this.onImageDataUpdate());
212
- this.onImageDataUpdate();
213
- }
214
- else if (selectedObjects.length > 0) {
215
- // If not, clear the selection.
216
- selectionTools.forEach(tool => tool.clearSelection());
217
- }
218
- // Show the submit button only when there is data to submit.
219
- this.submitButton.style.display = 'none';
220
- this.imageAltTextInput.oninput = () => {
221
- if (this.imagePreview.src?.length > 0) {
222
- this.submitButton.style.display = '';
223
- }
224
- };
225
- this.submitButton.onclick = async () => {
226
- if (!this.image) {
227
- return;
228
- }
229
- const image = new Image();
230
- image.src = this.image.getBase64Url();
231
- image.setAttribute('alt', this.imageAltTextInput.value);
232
- let component;
233
- try {
234
- component = await ImageComponent_1.default.fromImage(image, math_1.Mat33.identity);
235
- }
236
- catch (error) {
237
- console.error('Error loading image', error);
238
- this.statusView.innerText = this.localizationTable.imageLoadError(error);
239
- return;
240
- }
241
- if (component.getBBox().area === 0) {
242
- this.statusView.innerText = this.localizationTable.errorImageHasZeroSize;
243
- return;
244
- }
245
- this.hideDialog();
246
- if (editingImage) {
247
- const eraseCommand = new Erase_1.default([editingImage]);
248
- // Try to preserve the original width
249
- const originalTransform = editingImage.getTransformation();
250
- // || 1: Prevent division by zero
251
- const originalWidth = editingImage.getBBox().width || 1;
252
- const newWidth = component.getBBox().transformedBoundingBox(originalTransform).width || 1;
253
- const widthAdjustTransform = math_1.Mat33.scaling2D(originalWidth / newWidth);
254
- await this.editor.dispatch((0, uniteCommands_1.default)([
255
- EditorImage_1.default.addElement(component),
256
- component.transformBy(originalTransform.rightMul(widthAdjustTransform)),
257
- component.setZIndex(editingImage.getZIndex()),
258
- eraseCommand,
259
- ]));
260
- selectionTools[0]?.setSelection([component]);
261
- }
262
- else {
263
- await this.editor.addAndCenterComponents([component]);
264
- }
265
- };
266
- }
267
- }
268
- InsertImageWidget.nextInputId = 0;
269
- exports.default = InsertImageWidget;
@@ -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
- }