js-draw 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bundle.js +1 -1
  3. package/dist/cjs/version.js +1 -1
  4. package/dist/mjs/version.mjs +1 -1
  5. package/docs/img/readme-images/js-draw.jpg +0 -0
  6. package/docs/img/readme-images/unsupported-elements--in-editor.png +0 -0
  7. package/package.json +5 -4
  8. package/dist-test/test_imports/package-lock.json +0 -13
  9. package/dist-test/test_imports/package.json +0 -12
  10. package/dist-test/test_imports/test-imports.js +0 -11
  11. package/dist-test/test_imports/test-require.cjs +0 -14
  12. package/src/Editor.loadFrom.test.ts +0 -24
  13. package/src/Editor.test.ts +0 -107
  14. package/src/Editor.toSVG.test.ts +0 -294
  15. package/src/Editor.ts +0 -1443
  16. package/src/EditorImage.test.ts +0 -117
  17. package/src/EditorImage.ts +0 -609
  18. package/src/EventDispatcher.test.ts +0 -123
  19. package/src/EventDispatcher.ts +0 -72
  20. package/src/Pointer.ts +0 -183
  21. package/src/SVGLoader.test.ts +0 -114
  22. package/src/SVGLoader.ts +0 -672
  23. package/src/UndoRedoHistory.test.ts +0 -34
  24. package/src/UndoRedoHistory.ts +0 -102
  25. package/src/Viewport.ts +0 -322
  26. package/src/bundle/bundled.ts +0 -7
  27. package/src/commands/Command.ts +0 -45
  28. package/src/commands/Duplicate.ts +0 -75
  29. package/src/commands/Erase.ts +0 -95
  30. package/src/commands/SerializableCommand.ts +0 -49
  31. package/src/commands/UnresolvedCommand.ts +0 -37
  32. package/src/commands/invertCommand.ts +0 -58
  33. package/src/commands/lib.ts +0 -16
  34. package/src/commands/localization.ts +0 -47
  35. package/src/commands/uniteCommands.test.ts +0 -23
  36. package/src/commands/uniteCommands.ts +0 -140
  37. package/src/components/AbstractComponent.transformBy.test.ts +0 -23
  38. package/src/components/AbstractComponent.ts +0 -383
  39. package/src/components/BackgroundComponent.test.ts +0 -44
  40. package/src/components/BackgroundComponent.ts +0 -348
  41. package/src/components/ImageComponent.ts +0 -176
  42. package/src/components/RestylableComponent.ts +0 -161
  43. package/src/components/SVGGlobalAttributesObject.ts +0 -79
  44. package/src/components/Stroke.test.ts +0 -137
  45. package/src/components/Stroke.ts +0 -294
  46. package/src/components/TextComponent.test.ts +0 -202
  47. package/src/components/TextComponent.ts +0 -429
  48. package/src/components/UnknownSVGObject.test.ts +0 -10
  49. package/src/components/UnknownSVGObject.ts +0 -60
  50. package/src/components/builders/ArrowBuilder.ts +0 -106
  51. package/src/components/builders/CircleBuilder.ts +0 -100
  52. package/src/components/builders/FreehandLineBuilder.test.ts +0 -24
  53. package/src/components/builders/FreehandLineBuilder.ts +0 -210
  54. package/src/components/builders/LineBuilder.ts +0 -77
  55. package/src/components/builders/PressureSensitiveFreehandLineBuilder.ts +0 -453
  56. package/src/components/builders/RectangleBuilder.ts +0 -73
  57. package/src/components/builders/types.ts +0 -15
  58. package/src/components/lib.ts +0 -31
  59. package/src/components/localization.ts +0 -24
  60. package/src/components/util/StrokeSmoother.ts +0 -302
  61. package/src/components/util/describeComponentList.ts +0 -18
  62. package/src/dialogs/makeAboutDialog.ts +0 -82
  63. package/src/inputEvents.ts +0 -143
  64. package/src/lib.ts +0 -91
  65. package/src/localization.ts +0 -34
  66. package/src/localizations/de.ts +0 -146
  67. package/src/localizations/en.ts +0 -8
  68. package/src/localizations/es.ts +0 -74
  69. package/src/localizations/getLocalizationTable.test.ts +0 -27
  70. package/src/localizations/getLocalizationTable.ts +0 -74
  71. package/src/rendering/Display.ts +0 -247
  72. package/src/rendering/RenderablePathSpec.ts +0 -88
  73. package/src/rendering/RenderingStyle.test.ts +0 -68
  74. package/src/rendering/RenderingStyle.ts +0 -55
  75. package/src/rendering/TextRenderingStyle.ts +0 -55
  76. package/src/rendering/caching/CacheRecord.test.ts +0 -48
  77. package/src/rendering/caching/CacheRecord.ts +0 -76
  78. package/src/rendering/caching/CacheRecordManager.ts +0 -71
  79. package/src/rendering/caching/RenderingCache.test.ts +0 -43
  80. package/src/rendering/caching/RenderingCache.ts +0 -66
  81. package/src/rendering/caching/RenderingCacheNode.ts +0 -404
  82. package/src/rendering/caching/testUtils.ts +0 -35
  83. package/src/rendering/caching/types.ts +0 -34
  84. package/src/rendering/lib.ts +0 -8
  85. package/src/rendering/localization.ts +0 -20
  86. package/src/rendering/renderers/AbstractRenderer.ts +0 -232
  87. package/src/rendering/renderers/CanvasRenderer.ts +0 -312
  88. package/src/rendering/renderers/DummyRenderer.test.ts +0 -41
  89. package/src/rendering/renderers/DummyRenderer.ts +0 -142
  90. package/src/rendering/renderers/SVGRenderer.ts +0 -434
  91. package/src/rendering/renderers/TextOnlyRenderer.test.ts +0 -34
  92. package/src/rendering/renderers/TextOnlyRenderer.ts +0 -68
  93. package/src/shortcuts/KeyBinding.test.ts +0 -61
  94. package/src/shortcuts/KeyBinding.ts +0 -257
  95. package/src/shortcuts/KeyboardShortcutManager.test.ts +0 -95
  96. package/src/shortcuts/KeyboardShortcutManager.ts +0 -163
  97. package/src/shortcuts/lib.ts +0 -3
  98. package/src/testing/createEditor.ts +0 -11
  99. package/src/testing/getUniquePointerId.ts +0 -18
  100. package/src/testing/lib.ts +0 -3
  101. package/src/testing/sendPenEvent.ts +0 -36
  102. package/src/testing/sendTouchEvent.ts +0 -71
  103. package/src/toolbar/AbstractToolbar.ts +0 -542
  104. package/src/toolbar/DropdownToolbar.ts +0 -220
  105. package/src/toolbar/EdgeToolbar.test.ts +0 -54
  106. package/src/toolbar/EdgeToolbar.ts +0 -543
  107. package/src/toolbar/IconProvider.ts +0 -861
  108. package/src/toolbar/constants.ts +0 -1
  109. package/src/toolbar/lib.ts +0 -6
  110. package/src/toolbar/localization.ts +0 -136
  111. package/src/toolbar/types.ts +0 -13
  112. package/src/toolbar/widgets/ActionButtonWidget.ts +0 -39
  113. package/src/toolbar/widgets/BaseToolWidget.ts +0 -81
  114. package/src/toolbar/widgets/BaseWidget.ts +0 -495
  115. package/src/toolbar/widgets/DocumentPropertiesWidget.ts +0 -250
  116. package/src/toolbar/widgets/EraserToolWidget.ts +0 -84
  117. package/src/toolbar/widgets/HandToolWidget.ts +0 -239
  118. package/src/toolbar/widgets/InsertImageWidget.ts +0 -248
  119. package/src/toolbar/widgets/OverflowWidget.ts +0 -92
  120. package/src/toolbar/widgets/PenToolWidget.ts +0 -369
  121. package/src/toolbar/widgets/SelectionToolWidget.ts +0 -195
  122. package/src/toolbar/widgets/TextToolWidget.ts +0 -149
  123. package/src/toolbar/widgets/components/makeColorInput.ts +0 -184
  124. package/src/toolbar/widgets/components/makeFileInput.ts +0 -128
  125. package/src/toolbar/widgets/components/makeGridSelector.ts +0 -179
  126. package/src/toolbar/widgets/components/makeSeparator.ts +0 -17
  127. package/src/toolbar/widgets/components/makeThicknessSlider.ts +0 -62
  128. package/src/toolbar/widgets/keybindings.ts +0 -19
  129. package/src/toolbar/widgets/layout/DropdownLayoutManager.ts +0 -262
  130. package/src/toolbar/widgets/layout/EdgeToolbarLayoutManager.ts +0 -71
  131. package/src/toolbar/widgets/layout/types.ts +0 -74
  132. package/src/toolbar/widgets/lib.ts +0 -13
  133. package/src/tools/BaseTool.ts +0 -169
  134. package/src/tools/Eraser.test.ts +0 -103
  135. package/src/tools/Eraser.ts +0 -173
  136. package/src/tools/FindTool.test.ts +0 -67
  137. package/src/tools/FindTool.ts +0 -153
  138. package/src/tools/InputFilter/FunctionMapper.ts +0 -17
  139. package/src/tools/InputFilter/InputMapper.ts +0 -41
  140. package/src/tools/InputFilter/InputPipeline.test.ts +0 -41
  141. package/src/tools/InputFilter/InputPipeline.ts +0 -34
  142. package/src/tools/InputFilter/InputStabilizer.ts +0 -254
  143. package/src/tools/InputFilter/StrokeKeyboardControl.ts +0 -104
  144. package/src/tools/PanZoom.test.ts +0 -339
  145. package/src/tools/PanZoom.ts +0 -525
  146. package/src/tools/PasteHandler.ts +0 -94
  147. package/src/tools/Pen.test.ts +0 -260
  148. package/src/tools/Pen.ts +0 -284
  149. package/src/tools/PipetteTool.ts +0 -84
  150. package/src/tools/SelectionTool/SelectAllShortcutHandler.ts +0 -29
  151. package/src/tools/SelectionTool/Selection.ts +0 -647
  152. package/src/tools/SelectionTool/SelectionHandle.ts +0 -142
  153. package/src/tools/SelectionTool/SelectionTool.test.ts +0 -370
  154. package/src/tools/SelectionTool/SelectionTool.ts +0 -510
  155. package/src/tools/SelectionTool/TransformMode.ts +0 -112
  156. package/src/tools/SelectionTool/types.ts +0 -11
  157. package/src/tools/SoundUITool.ts +0 -221
  158. package/src/tools/TextTool.ts +0 -339
  159. package/src/tools/ToolController.ts +0 -224
  160. package/src/tools/ToolEnabledGroup.ts +0 -14
  161. package/src/tools/ToolSwitcherShortcut.ts +0 -39
  162. package/src/tools/ToolbarShortcutHandler.ts +0 -39
  163. package/src/tools/UndoRedoShortcut.test.ts +0 -62
  164. package/src/tools/UndoRedoShortcut.ts +0 -24
  165. package/src/tools/keybindings.ts +0 -85
  166. package/src/tools/lib.ts +0 -22
  167. package/src/tools/localization.ts +0 -76
  168. package/src/types.ts +0 -151
  169. package/src/util/ReactiveValue.test.ts +0 -168
  170. package/src/util/ReactiveValue.ts +0 -241
  171. package/src/util/assertions.ts +0 -55
  172. package/src/util/fileToBase64.ts +0 -18
  173. package/src/util/guessKeyCodeFromKey.ts +0 -36
  174. package/src/util/listPrefixMatch.ts +0 -19
  175. package/src/util/stopPropagationOfScrollingWheelEvents.ts +0 -20
  176. package/src/util/untilNextAnimationFrame.ts +0 -9
  177. package/src/util/waitForAll.ts +0 -18
  178. package/src/util/waitForTimeout.ts +0 -9
  179. package/src/version.test.ts +0 -12
  180. package/src/version.ts +0 -3
  181. package/tools/allLocales.js +0 -4
  182. package/tools/copyREADME.ts +0 -62
@@ -1,195 +0,0 @@
1
- import { Color4 } from '@js-draw/math';
2
- import { isRestylableComponent } from '../../components/RestylableComponent';
3
- import Editor from '../../Editor';
4
- import uniteCommands from '../../commands/uniteCommands';
5
- import SelectionTool from '../../tools/SelectionTool/SelectionTool';
6
- import { EditorEventType } from '../../types';
7
- import { KeyPressEvent } from '../../inputEvents';
8
- import { ToolbarLocalization } from '../localization';
9
- import makeColorInput from './components/makeColorInput';
10
- import ActionButtonWidget from './ActionButtonWidget';
11
- import BaseToolWidget from './BaseToolWidget';
12
- import { resizeImageToSelectionKeyboardShortcut } from './keybindings';
13
- import makeSeparator from './components/makeSeparator';
14
- import { toolbarCSSPrefix } from '../constants';
15
-
16
- const makeFormatMenu = (editor: Editor, selectionTool: SelectionTool, localizationTable: ToolbarLocalization) => {
17
- const container = document.createElement('div');
18
- container.classList.add(
19
- 'selection-format-menu', `${toolbarCSSPrefix}spacedList`, `${toolbarCSSPrefix}indentedList`
20
- );
21
-
22
- const colorRow = document.createElement('div');
23
- const colorLabel = document.createElement('label');
24
- const {
25
- input: colorInput, container: colorInputContainer, setValue: setColorInputValue
26
- } = makeColorInput(editor, color => {
27
- const selection = selectionTool.getSelection();
28
-
29
- if (selection) {
30
- const updateStyleCommands = [];
31
-
32
- for (const elem of selection.getSelectedObjects()) {
33
- if (isRestylableComponent(elem)) {
34
- updateStyleCommands.push(elem.updateStyle({ color }));
35
- }
36
- }
37
-
38
- const unitedCommand = uniteCommands(updateStyleCommands);
39
- editor.dispatch(unitedCommand);
40
- }
41
- });
42
-
43
- colorLabel.innerText = localizationTable.colorLabel;
44
-
45
- const update = () => {
46
- const selection = selectionTool.getSelection();
47
- if (selection && selection.getSelectedItemCount() > 0) {
48
- colorInput.disabled = false;
49
- container.classList.remove('disabled');
50
-
51
- const colors = [];
52
- for (const elem of selection.getSelectedObjects()) {
53
- if (isRestylableComponent(elem)) {
54
- const color = elem.getStyle().color;
55
- if (color) {
56
- colors.push(color);
57
- }
58
- }
59
- }
60
- setColorInputValue(Color4.average(colors));
61
- } else {
62
- colorInput.disabled = true;
63
- container.classList.add('disabled');
64
- setColorInputValue(Color4.transparent);
65
- }
66
- };
67
-
68
- colorRow.replaceChildren(colorLabel, colorInputContainer);
69
- container.replaceChildren(colorRow);
70
-
71
- return {
72
- addTo: (parent: HTMLElement) => {
73
- parent.appendChild(container);
74
- },
75
- update,
76
- };
77
- };
78
-
79
- export default class SelectionToolWidget extends BaseToolWidget {
80
- private updateFormatMenu: ()=>void = () => {};
81
-
82
- public constructor(
83
- editor: Editor, private tool: SelectionTool, localization?: ToolbarLocalization
84
- ) {
85
- super(editor, tool, 'selection-tool-widget', localization);
86
-
87
- const resizeButton = new ActionButtonWidget(
88
- editor, 'resize-btn',
89
- () => editor.icons.makeResizeImageToSelectionIcon(),
90
- this.localizationTable.resizeImageToSelection,
91
- () => {
92
- this.resizeImageToSelection();
93
- },
94
- localization,
95
- );
96
- const deleteButton = new ActionButtonWidget(
97
- editor, 'delete-btn',
98
- () => editor.icons.makeDeleteSelectionIcon(),
99
- this.localizationTable.deleteSelection,
100
- () => {
101
- const selection = this.tool.getSelection();
102
- this.editor.dispatch(selection!.deleteSelectedObjects());
103
- this.tool.clearSelection();
104
- },
105
- localization,
106
- );
107
- const duplicateButton = new ActionButtonWidget(
108
- editor, 'duplicate-btn',
109
- () => editor.icons.makeDuplicateSelectionIcon(),
110
- this.localizationTable.duplicateSelection,
111
- async () => {
112
- const selection = this.tool.getSelection();
113
- this.editor.dispatch(await selection!.duplicateSelectedObjects());
114
- this.setDropdownVisible(false);
115
- },
116
- localization,
117
- );
118
-
119
- this.addSubWidget(resizeButton);
120
- this.addSubWidget(deleteButton);
121
- this.addSubWidget(duplicateButton);
122
-
123
- const updateDisabled = (disabled: boolean) => {
124
- resizeButton.setDisabled(disabled);
125
- deleteButton.setDisabled(disabled);
126
- duplicateButton.setDisabled(disabled);
127
- };
128
- updateDisabled(true);
129
-
130
- // Enable/disable actions based on whether items are selected
131
- this.editor.notifier.on(EditorEventType.ToolUpdated, toolEvt => {
132
- if (toolEvt.kind !== EditorEventType.ToolUpdated) {
133
- throw new Error('Invalid event type!');
134
- }
135
-
136
- if (toolEvt.tool === this.tool) {
137
- const selection = this.tool.getSelection();
138
- const hasSelection = selection && selection.getSelectedItemCount() > 0;
139
-
140
- updateDisabled(!hasSelection);
141
- this.updateFormatMenu();
142
- }
143
- });
144
- }
145
-
146
- private resizeImageToSelection() {
147
- const selection = this.tool.getSelection();
148
- if (selection) {
149
- this.editor.dispatch(this.editor.setImportExportRect(selection.region));
150
- }
151
- }
152
-
153
- protected override onKeyPress(event: KeyPressEvent): boolean {
154
- const shortcuts = this.editor.shortcuts;
155
-
156
- // Resize image to selection:
157
- // Other keys are handled directly by the selection tool.
158
- if (shortcuts.matchesShortcut(resizeImageToSelectionKeyboardShortcut, event)) {
159
- this.resizeImageToSelection();
160
- return true;
161
- }
162
-
163
- // If we didn't handle the event, allow the superclass to handle it.
164
- if (super.onKeyPress(event)) {
165
- return true;
166
- }
167
- return false;
168
- }
169
-
170
- protected getTitle(): string {
171
- return this.localizationTable.select;
172
- }
173
-
174
- protected createIcon(): Element {
175
- return this.editor.icons.makeSelectionIcon();
176
- }
177
-
178
- protected override fillDropdown(dropdown: HTMLElement): boolean {
179
- super.fillDropdown(dropdown);
180
-
181
- const controlsContainer = document.createElement('div');
182
- controlsContainer.classList.add(`${toolbarCSSPrefix}nonbutton-controls-main-list`);
183
- dropdown.appendChild(controlsContainer);
184
-
185
- makeSeparator(this.localizationTable.reformatSelection).addTo(controlsContainer);
186
-
187
- const formatMenu = makeFormatMenu(this.editor, this.tool, this.localizationTable);
188
- formatMenu.addTo(controlsContainer);
189
- this.updateFormatMenu = () => formatMenu.update();
190
-
191
- formatMenu.update();
192
-
193
- return true;
194
- }
195
- }
@@ -1,149 +0,0 @@
1
- import { Color4 } from '@js-draw/math';
2
- import Editor from '../../Editor';
3
- import TextTool from '../../tools/TextTool';
4
- import { EditorEventType } from '../../types';
5
- import { toolbarCSSPrefix } from '../constants';
6
- import { ToolbarLocalization } from '../localization';
7
- import makeColorInput from './components/makeColorInput';
8
- import BaseToolWidget from './BaseToolWidget';
9
- import { SavedToolbuttonState } from './BaseWidget';
10
-
11
- export default class TextToolWidget extends BaseToolWidget {
12
- private updateDropdownInputs: (()=>void)|null = null;
13
- public constructor(editor: Editor, private tool: TextTool, localization?: ToolbarLocalization) {
14
- super(editor, tool, 'text-tool-widget', localization);
15
-
16
- editor.notifier.on(EditorEventType.ToolUpdated, evt => {
17
- if (evt.kind === EditorEventType.ToolUpdated && evt.tool === tool) {
18
- this.updateIcon();
19
- this.updateDropdownInputs?.();
20
- }
21
- });
22
- }
23
-
24
- protected getTitle(): string {
25
- return this.targetTool.description;
26
- }
27
-
28
- protected createIcon(): Element {
29
- const textStyle = this.tool.getTextStyle();
30
- return this.editor.icons.makeTextIcon(textStyle);
31
- }
32
-
33
- private static idCounter: number = 0;
34
- protected override fillDropdown(dropdown: HTMLElement): boolean {
35
- const container = document.createElement('div');
36
- container.classList.add(
37
- `${toolbarCSSPrefix}spacedList`, `${toolbarCSSPrefix}nonbutton-controls-main-list`
38
- );
39
- const fontRow = document.createElement('div');
40
- const colorRow = document.createElement('div');
41
- const sizeRow = document.createElement('div');
42
-
43
- const fontInput = document.createElement('select');
44
- const fontLabel = document.createElement('label');
45
-
46
- const sizeInput = document.createElement('input');
47
- const sizeLabel = document.createElement('label');
48
-
49
- const {
50
- input: colorInput, container: colorInputContainer, setValue: setColorInputValue
51
- } = makeColorInput(this.editor, color => {
52
- this.tool.setColor(color);
53
- });
54
- const colorLabel = document.createElement('label');
55
-
56
- const fontsInInput = new Set();
57
- const addFontToInput = (fontName: string) => {
58
- const option = document.createElement('option');
59
- option.value = fontName;
60
- option.textContent = fontName;
61
- fontInput.appendChild(option);
62
- fontsInInput.add(fontName);
63
- };
64
-
65
- sizeInput.setAttribute('type', 'number');
66
- sizeInput.min = '1';
67
- sizeInput.max = '128';
68
-
69
- fontLabel.innerText = this.localizationTable.fontLabel;
70
- colorLabel.innerText = this.localizationTable.colorLabel;
71
- sizeLabel.innerText = this.localizationTable.textSize;
72
-
73
- colorInput.id = `${toolbarCSSPrefix}-text-color-input-${TextToolWidget.idCounter++}`;
74
- colorLabel.setAttribute('for', colorInput.id);
75
-
76
- sizeInput.id = `${toolbarCSSPrefix}-text-size-input-${TextToolWidget.idCounter++}`;
77
- sizeLabel.setAttribute('for', sizeInput.id);
78
-
79
- addFontToInput('monospace');
80
- addFontToInput('serif');
81
- addFontToInput('sans-serif');
82
- fontInput.id = `${toolbarCSSPrefix}-text-font-input-${TextToolWidget.idCounter++}`;
83
- fontLabel.setAttribute('for', fontInput.id);
84
-
85
- fontInput.onchange = () => {
86
- this.tool.setFontFamily(fontInput.value);
87
- };
88
-
89
- sizeInput.onchange = () => {
90
- const size = parseInt(sizeInput.value);
91
- if (!isNaN(size) && size > 0) {
92
- this.tool.setFontSize(size);
93
- }
94
- };
95
-
96
- colorRow.appendChild(colorLabel);
97
- colorRow.appendChild(colorInputContainer);
98
-
99
- fontRow.appendChild(fontLabel);
100
- fontRow.appendChild(fontInput);
101
-
102
- sizeRow.appendChild(sizeLabel);
103
- sizeRow.appendChild(sizeInput);
104
-
105
- this.updateDropdownInputs = () => {
106
- const style = this.tool.getTextStyle();
107
- setColorInputValue(style.renderingStyle.fill);
108
-
109
- if (!fontsInInput.has(style.fontFamily)) {
110
- addFontToInput(style.fontFamily);
111
- }
112
- fontInput.value = style.fontFamily;
113
- sizeInput.value = `${style.size}`;
114
- };
115
- this.updateDropdownInputs();
116
-
117
- container.replaceChildren(colorRow, sizeRow, fontRow);
118
- dropdown.appendChild(container);
119
- return true;
120
- }
121
-
122
- public override serializeState(): SavedToolbuttonState {
123
- const textStyle = this.tool.getTextStyle();
124
-
125
- return {
126
- ...super.serializeState(),
127
-
128
- fontFamily: textStyle.fontFamily,
129
- textSize: textStyle.size,
130
- color: textStyle.renderingStyle.fill.toHexString(),
131
- };
132
- }
133
-
134
- public override deserializeFrom(state: SavedToolbuttonState) {
135
- if (state.fontFamily && typeof(state.fontFamily) === 'string') {
136
- this.tool.setFontFamily(state.fontFamily);
137
- }
138
-
139
- if (state.color && typeof(state.color) === 'string') {
140
- this.tool.setColor(Color4.fromHex(state.color));
141
- }
142
-
143
- if (state.textSize && typeof(state.textSize) === 'number') {
144
- this.tool.setFontSize(state.textSize);
145
- }
146
-
147
- super.deserializeFrom(state);
148
- }
149
- }
@@ -1,184 +0,0 @@
1
- import { Color4 } from '@js-draw/math';
2
- import Editor from '../../../Editor';
3
- import PipetteTool from '../../../tools/PipetteTool';
4
- import { EditorEventType } from '../../../types';
5
-
6
- type OnColorChangeListener = (color: Color4)=>void;
7
-
8
- // Returns [ color input, input container, callback to change the color value ].
9
- export const makeColorInput = (
10
- editor: Editor, onColorChange: OnColorChangeListener
11
- ) => {
12
-
13
- const colorInputContainer = document.createElement('span');
14
- const colorInput = document.createElement('input');
15
-
16
- colorInput.type = 'button';
17
- colorInput.classList.add('coloris_input');
18
- colorInputContainer.classList.add('color-input-container');
19
-
20
- colorInputContainer.appendChild(colorInput);
21
- const pipetteController = addPipetteTool(editor, colorInputContainer, (color: Color4) => {
22
- colorInput.value = color.toHexString();
23
- onInputEnd();
24
-
25
- // Update the color preview, if it exists (may be managed by Coloris).
26
- const parentElem = colorInput.parentElement;
27
- if (parentElem && parentElem.classList.contains('clr-field')) {
28
- parentElem.style.color = colorInput.value;
29
- }
30
- });
31
-
32
- let currentColor: Color4|undefined;
33
- const handleColorInput = () => {
34
- currentColor = Color4.fromHex(colorInput.value);
35
- };
36
-
37
- // Only change the pen color when we finish sending input (this limits the number of
38
- // editor events triggered and accessibility announcements).
39
- const onInputEnd = () => {
40
- handleColorInput();
41
-
42
- if (currentColor) {
43
- editor.announceForAccessibility(
44
- editor.localization.colorChangedAnnouncement(currentColor.toHexString())
45
- );
46
- onColorChange(currentColor);
47
- editor.notifier.dispatch(EditorEventType.ColorPickerColorSelected, {
48
- kind: EditorEventType.ColorPickerColorSelected,
49
- color: currentColor,
50
- });
51
- }
52
- };
53
-
54
- colorInput.oninput = handleColorInput;
55
- let isOpen = false;
56
- colorInput.addEventListener('open', () => {
57
- isOpen = true;
58
- editor.notifier.dispatch(EditorEventType.ColorPickerToggled, {
59
- kind: EditorEventType.ColorPickerToggled,
60
- open: true,
61
- });
62
- pipetteController.cancel();
63
- colorInputContainer.classList.add('picker-open');
64
-
65
- // Focus the Coloris color picker, if it exists.
66
- // Don't focus the text input within the color picker, however,
67
- // as this displays a keyboard on mobile devices.
68
- const colorPickerElem: HTMLElement|null = document.querySelector('#clr-picker #clr-hue-slider');
69
- colorPickerElem?.focus();
70
- });
71
-
72
- const onClose = () => {
73
- isOpen = false;
74
- editor.notifier.dispatch(EditorEventType.ColorPickerToggled, {
75
- kind: EditorEventType.ColorPickerToggled,
76
- open: false,
77
- });
78
- onInputEnd();
79
-
80
- // Restore focus to the input that opened the color picker
81
- colorInput.focus();
82
-
83
- colorInputContainer.classList.remove('picker-open');
84
- };
85
- colorInput.addEventListener('close', () => {
86
- onClose();
87
- });
88
-
89
- const setColorInputValue = (color: Color4|string) => {
90
- if (typeof color === 'object') {
91
- color = color.toHexString();
92
- }
93
-
94
- colorInput.value = color;
95
-
96
- // Fire all color event listeners. See
97
- // https://github.com/mdbassit/Coloris#manually-updating-the-thumbnail
98
- colorInput.dispatchEvent(new Event('input', { bubbles: true }));
99
- };
100
-
101
- return {
102
- input: colorInput,
103
- container: colorInputContainer,
104
- setValue: setColorInputValue,
105
- closePicker: () => {
106
- if (isOpen) {
107
- onInputEnd();
108
- }
109
- },
110
- };
111
- };
112
-
113
- const addPipetteTool = (editor: Editor, container: HTMLElement, onColorChange: OnColorChangeListener) => {
114
- const pipetteButton = document.createElement('button');
115
- pipetteButton.classList.add('pipetteButton');
116
- pipetteButton.title = editor.localization.pickColorFromScreen;
117
- pipetteButton.setAttribute('alt', pipetteButton.title);
118
-
119
- const pickColorLabel = document.createElement('span');
120
- pickColorLabel.classList.add('pickColorInstructions');
121
- pickColorLabel.innerText = editor.localization.clickToPickColorAnnouncement;
122
-
123
- const updatePipetteButtonContent = (color?: Color4) => {
124
- pipetteButton.replaceChildren(
125
- editor.icons.makePipetteIcon(color), pickColorLabel
126
- );
127
- };
128
- updatePipetteButtonContent();
129
-
130
- const pipetteTool: PipetteTool|undefined = editor.toolController.getMatchingTools(PipetteTool)[0];
131
-
132
- const endColorSelectMode = () => {
133
- pipetteTool?.clearColorListener();
134
- updatePipetteButtonContent();
135
- pipetteButton.classList.remove('active');
136
- };
137
-
138
- const pipetteColorSelect = (color: Color4|null) => {
139
- endColorSelectMode();
140
-
141
- if (color) {
142
- onColorChange(color);
143
- }
144
- };
145
-
146
- const pipetteColorPreview = (color: Color4|null) => {
147
- if (color) {
148
- updatePipetteButtonContent(color);
149
- } else {
150
- updatePipetteButtonContent();
151
- }
152
- };
153
-
154
- pipetteButton.onclick = () => {
155
- // If already picking, cancel it.
156
- if (pipetteButton.classList.contains('active')) {
157
- endColorSelectMode();
158
- editor.announceForAccessibility(editor.localization.colorSelectionCanceledAnnouncement);
159
- return;
160
- }
161
-
162
- pipetteTool?.setColorListener(
163
- pipetteColorPreview,
164
- pipetteColorSelect,
165
- );
166
-
167
- if (pipetteTool) {
168
- pipetteButton.classList.add('active');
169
-
170
- editor.announceForAccessibility(editor.localization.clickToPickColorAnnouncement);
171
- }
172
- };
173
-
174
- container.appendChild(pipetteButton);
175
-
176
- return {
177
- // Cancel a pipette color selection if one is in progress.
178
- cancel: () => {
179
- endColorSelectMode();
180
- },
181
- };
182
- };
183
-
184
- export default makeColorInput;
@@ -1,128 +0,0 @@
1
- import ReactiveValue, { MutableReactiveValue } from '../../../util/ReactiveValue';
2
- import { ToolbarContext } from '../../types';
3
-
4
- let idCounter = 0;
5
-
6
- /**
7
- * Creates a stylized file input.
8
- */
9
- const makeFileInput = (labelText: string, context: ToolbarContext, accepts: string = '*') => {
10
- const container = document.createElement('div');
11
- const label = document.createElement('label');
12
- const input = document.createElement('input');
13
-
14
- const descriptionBox = document.createElement('div');
15
- descriptionBox.classList.add('toolbar--file-input-description');
16
- const descriptionText = document.createElement('span');
17
-
18
- container.classList.add('toolbar--file-input-container');
19
-
20
- label.appendChild(document.createTextNode(labelText));
21
- input.accept = accepts;
22
- input.type = 'file';
23
-
24
- // Associate the label with the input
25
- const inputId = `js-draw-file-input-${idCounter ++}`;
26
- input.setAttribute('id', inputId);
27
- label.htmlFor = inputId;
28
-
29
- const icon = context.icons.makeUploadFileIcon();
30
- icon.classList.add('icon');
31
-
32
- descriptionBox.replaceChildren(icon, descriptionText);
33
- label.appendChild(descriptionBox);
34
- container.replaceChildren(label, input);
35
-
36
- const selectedFiles: MutableReactiveValue<File[]> = ReactiveValue.fromInitialValue([]);
37
-
38
- // Support droping files
39
- label.addEventListener('dragover', event => {
40
- event.preventDefault();
41
- label.classList.add('drag-target');
42
- });
43
- label.addEventListener('dragenter', event => {
44
- event.preventDefault();
45
- label.classList.add('drag-target');
46
- });
47
- label.addEventListener('dragleave', event => {
48
- event.preventDefault();
49
-
50
- // Ensure the event wasn't targeting a child.
51
- // See https://stackoverflow.com/a/54271161 and
52
- // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/relatedTarget
53
- const enteringElement = event.relatedTarget as HTMLElement;
54
- if (!enteringElement || !label.contains(enteringElement)) {
55
- label.classList.remove('drag-target');
56
- }
57
- });
58
-
59
- // See https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop#process_the_drop
60
- label.addEventListener('drop', event => {
61
- event.preventDefault();
62
- label.classList.remove('drag-target');
63
-
64
- const fileList: File[] = [];
65
-
66
- if (event.dataTransfer) {
67
- fileList.push(...event.dataTransfer.files);
68
- }
69
-
70
- selectedFiles.set(fileList);
71
- });
72
- input.addEventListener('change', () => {
73
- const fileList = input.files ?? [];
74
- selectedFiles.set([ ...fileList ]);
75
- });
76
-
77
- selectedFiles.onUpdate(files => {
78
- if (files.length === 0 && input.files && input.files.length > 0) {
79
- input.value = '';
80
- }
81
- });
82
-
83
- // Update the status text and hide/show the icon.
84
- selectedFiles.onUpdateAndNow(files => {
85
- if (files.length > 0) {
86
- descriptionText.innerText = files.map(file => file.name).join('\n');
87
-
88
- // Only show the icon when there are files
89
- icon.style.display = 'none';
90
- } else {
91
- // Show the icon
92
- icon.style.display = '';
93
-
94
- const text = context.localization.dragAndDropHereOrBrowse;
95
-
96
- // Split into regions surrounded by {{curly braces}} and regions that are
97
- // not.
98
- // When given a regular expression, `.split` outputs an array. For example,
99
- // "a test __of__ split".split(/__(.*)__/)
100
- // results in
101
- // ['a test ', 'of', ' split'].
102
- const segments = text.split(/[{]{2}(.*)[}]{2}/g);
103
- descriptionText.replaceChildren();
104
-
105
- for (let i = 0; i < segments.length; i++) {
106
- // Inside a {{pair of curly braces}}?
107
- if (i % 2 === 1) {
108
- const boldedText = document.createElement('b');
109
- boldedText.innerText = segments[i];
110
- descriptionText.appendChild(boldedText);
111
- } else {
112
- descriptionText.appendChild(document.createTextNode(segments[i]));
113
- }
114
- }
115
- }
116
- });
117
-
118
- return {
119
- container,
120
- input,
121
- selectedFiles,
122
- addTo: (parent: HTMLElement) => {
123
- parent.appendChild(container);
124
- },
125
- };
126
- };
127
-
128
- export default makeFileInput;