js-draw 1.0.1 → 1.1.0

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 (197) hide show
  1. package/LICENSE +21 -0
  2. package/dist/Editor.css +1 -0
  3. package/dist/bundle.js +1 -1
  4. package/dist/bundledStyles.js +1 -1
  5. package/dist/cjs/toolbar/AbstractToolbar.d.ts +9 -13
  6. package/dist/cjs/toolbar/AbstractToolbar.js +14 -19
  7. package/dist/cjs/toolbar/widgets/SaveActionWidget.d.ts +10 -0
  8. package/dist/cjs/toolbar/widgets/SaveActionWidget.js +26 -0
  9. package/dist/cjs/toolbar/widgets/keybindings.d.ts +1 -0
  10. package/dist/cjs/toolbar/widgets/keybindings.js +4 -1
  11. package/dist/cjs/version.js +1 -1
  12. package/dist/mjs/toolbar/AbstractToolbar.d.ts +9 -13
  13. package/dist/mjs/toolbar/AbstractToolbar.mjs +14 -19
  14. package/dist/mjs/toolbar/widgets/SaveActionWidget.d.ts +10 -0
  15. package/dist/mjs/toolbar/widgets/SaveActionWidget.mjs +21 -0
  16. package/dist/mjs/toolbar/widgets/keybindings.d.ts +1 -0
  17. package/dist/mjs/toolbar/widgets/keybindings.mjs +3 -0
  18. package/dist/mjs/version.mjs +1 -1
  19. package/docs/img/readme-images/js-draw.jpg +0 -0
  20. package/docs/img/readme-images/unsupported-elements--in-editor.png +0 -0
  21. package/package.json +5 -4
  22. package/src/toolbar/EdgeToolbar.scss +1 -0
  23. package/dist-test/test_imports/package-lock.json +0 -13
  24. package/dist-test/test_imports/package.json +0 -12
  25. package/dist-test/test_imports/test-imports.js +0 -11
  26. package/dist-test/test_imports/test-require.cjs +0 -14
  27. package/src/Editor.loadFrom.test.ts +0 -24
  28. package/src/Editor.test.ts +0 -107
  29. package/src/Editor.toSVG.test.ts +0 -294
  30. package/src/Editor.ts +0 -1443
  31. package/src/EditorImage.test.ts +0 -117
  32. package/src/EditorImage.ts +0 -609
  33. package/src/EventDispatcher.test.ts +0 -123
  34. package/src/EventDispatcher.ts +0 -72
  35. package/src/Pointer.ts +0 -183
  36. package/src/SVGLoader.test.ts +0 -114
  37. package/src/SVGLoader.ts +0 -672
  38. package/src/UndoRedoHistory.test.ts +0 -34
  39. package/src/UndoRedoHistory.ts +0 -102
  40. package/src/Viewport.ts +0 -322
  41. package/src/bundle/bundled.ts +0 -7
  42. package/src/commands/Command.ts +0 -45
  43. package/src/commands/Duplicate.ts +0 -75
  44. package/src/commands/Erase.ts +0 -95
  45. package/src/commands/SerializableCommand.ts +0 -49
  46. package/src/commands/UnresolvedCommand.ts +0 -37
  47. package/src/commands/invertCommand.ts +0 -58
  48. package/src/commands/lib.ts +0 -16
  49. package/src/commands/localization.ts +0 -47
  50. package/src/commands/uniteCommands.test.ts +0 -23
  51. package/src/commands/uniteCommands.ts +0 -140
  52. package/src/components/AbstractComponent.transformBy.test.ts +0 -23
  53. package/src/components/AbstractComponent.ts +0 -383
  54. package/src/components/BackgroundComponent.test.ts +0 -44
  55. package/src/components/BackgroundComponent.ts +0 -348
  56. package/src/components/ImageComponent.ts +0 -176
  57. package/src/components/RestylableComponent.ts +0 -161
  58. package/src/components/SVGGlobalAttributesObject.ts +0 -79
  59. package/src/components/Stroke.test.ts +0 -137
  60. package/src/components/Stroke.ts +0 -294
  61. package/src/components/TextComponent.test.ts +0 -202
  62. package/src/components/TextComponent.ts +0 -429
  63. package/src/components/UnknownSVGObject.test.ts +0 -10
  64. package/src/components/UnknownSVGObject.ts +0 -60
  65. package/src/components/builders/ArrowBuilder.ts +0 -106
  66. package/src/components/builders/CircleBuilder.ts +0 -100
  67. package/src/components/builders/FreehandLineBuilder.test.ts +0 -24
  68. package/src/components/builders/FreehandLineBuilder.ts +0 -210
  69. package/src/components/builders/LineBuilder.ts +0 -77
  70. package/src/components/builders/PressureSensitiveFreehandLineBuilder.ts +0 -453
  71. package/src/components/builders/RectangleBuilder.ts +0 -73
  72. package/src/components/builders/types.ts +0 -15
  73. package/src/components/lib.ts +0 -31
  74. package/src/components/localization.ts +0 -24
  75. package/src/components/util/StrokeSmoother.ts +0 -302
  76. package/src/components/util/describeComponentList.ts +0 -18
  77. package/src/dialogs/makeAboutDialog.ts +0 -82
  78. package/src/inputEvents.ts +0 -143
  79. package/src/lib.ts +0 -91
  80. package/src/localization.ts +0 -34
  81. package/src/localizations/de.ts +0 -146
  82. package/src/localizations/en.ts +0 -8
  83. package/src/localizations/es.ts +0 -74
  84. package/src/localizations/getLocalizationTable.test.ts +0 -27
  85. package/src/localizations/getLocalizationTable.ts +0 -74
  86. package/src/rendering/Display.ts +0 -247
  87. package/src/rendering/RenderablePathSpec.ts +0 -88
  88. package/src/rendering/RenderingStyle.test.ts +0 -68
  89. package/src/rendering/RenderingStyle.ts +0 -55
  90. package/src/rendering/TextRenderingStyle.ts +0 -55
  91. package/src/rendering/caching/CacheRecord.test.ts +0 -48
  92. package/src/rendering/caching/CacheRecord.ts +0 -76
  93. package/src/rendering/caching/CacheRecordManager.ts +0 -71
  94. package/src/rendering/caching/RenderingCache.test.ts +0 -43
  95. package/src/rendering/caching/RenderingCache.ts +0 -66
  96. package/src/rendering/caching/RenderingCacheNode.ts +0 -404
  97. package/src/rendering/caching/testUtils.ts +0 -35
  98. package/src/rendering/caching/types.ts +0 -34
  99. package/src/rendering/lib.ts +0 -8
  100. package/src/rendering/localization.ts +0 -20
  101. package/src/rendering/renderers/AbstractRenderer.ts +0 -232
  102. package/src/rendering/renderers/CanvasRenderer.ts +0 -312
  103. package/src/rendering/renderers/DummyRenderer.test.ts +0 -41
  104. package/src/rendering/renderers/DummyRenderer.ts +0 -142
  105. package/src/rendering/renderers/SVGRenderer.ts +0 -434
  106. package/src/rendering/renderers/TextOnlyRenderer.test.ts +0 -34
  107. package/src/rendering/renderers/TextOnlyRenderer.ts +0 -68
  108. package/src/shortcuts/KeyBinding.test.ts +0 -61
  109. package/src/shortcuts/KeyBinding.ts +0 -257
  110. package/src/shortcuts/KeyboardShortcutManager.test.ts +0 -95
  111. package/src/shortcuts/KeyboardShortcutManager.ts +0 -163
  112. package/src/shortcuts/lib.ts +0 -3
  113. package/src/testing/createEditor.ts +0 -11
  114. package/src/testing/getUniquePointerId.ts +0 -18
  115. package/src/testing/lib.ts +0 -3
  116. package/src/testing/sendPenEvent.ts +0 -36
  117. package/src/testing/sendTouchEvent.ts +0 -71
  118. package/src/toolbar/AbstractToolbar.ts +0 -542
  119. package/src/toolbar/DropdownToolbar.ts +0 -220
  120. package/src/toolbar/EdgeToolbar.test.ts +0 -54
  121. package/src/toolbar/EdgeToolbar.ts +0 -543
  122. package/src/toolbar/IconProvider.ts +0 -861
  123. package/src/toolbar/constants.ts +0 -1
  124. package/src/toolbar/lib.ts +0 -6
  125. package/src/toolbar/localization.ts +0 -136
  126. package/src/toolbar/types.ts +0 -13
  127. package/src/toolbar/widgets/ActionButtonWidget.ts +0 -39
  128. package/src/toolbar/widgets/BaseToolWidget.ts +0 -81
  129. package/src/toolbar/widgets/BaseWidget.ts +0 -495
  130. package/src/toolbar/widgets/DocumentPropertiesWidget.ts +0 -250
  131. package/src/toolbar/widgets/EraserToolWidget.ts +0 -84
  132. package/src/toolbar/widgets/HandToolWidget.ts +0 -239
  133. package/src/toolbar/widgets/InsertImageWidget.ts +0 -248
  134. package/src/toolbar/widgets/OverflowWidget.ts +0 -92
  135. package/src/toolbar/widgets/PenToolWidget.ts +0 -369
  136. package/src/toolbar/widgets/SelectionToolWidget.ts +0 -195
  137. package/src/toolbar/widgets/TextToolWidget.ts +0 -149
  138. package/src/toolbar/widgets/components/makeColorInput.ts +0 -184
  139. package/src/toolbar/widgets/components/makeFileInput.ts +0 -128
  140. package/src/toolbar/widgets/components/makeGridSelector.ts +0 -179
  141. package/src/toolbar/widgets/components/makeSeparator.ts +0 -17
  142. package/src/toolbar/widgets/components/makeThicknessSlider.ts +0 -62
  143. package/src/toolbar/widgets/keybindings.ts +0 -19
  144. package/src/toolbar/widgets/layout/DropdownLayoutManager.ts +0 -262
  145. package/src/toolbar/widgets/layout/EdgeToolbarLayoutManager.ts +0 -71
  146. package/src/toolbar/widgets/layout/types.ts +0 -74
  147. package/src/toolbar/widgets/lib.ts +0 -13
  148. package/src/tools/BaseTool.ts +0 -169
  149. package/src/tools/Eraser.test.ts +0 -103
  150. package/src/tools/Eraser.ts +0 -173
  151. package/src/tools/FindTool.test.ts +0 -67
  152. package/src/tools/FindTool.ts +0 -153
  153. package/src/tools/InputFilter/FunctionMapper.ts +0 -17
  154. package/src/tools/InputFilter/InputMapper.ts +0 -41
  155. package/src/tools/InputFilter/InputPipeline.test.ts +0 -41
  156. package/src/tools/InputFilter/InputPipeline.ts +0 -34
  157. package/src/tools/InputFilter/InputStabilizer.ts +0 -254
  158. package/src/tools/InputFilter/StrokeKeyboardControl.ts +0 -104
  159. package/src/tools/PanZoom.test.ts +0 -339
  160. package/src/tools/PanZoom.ts +0 -525
  161. package/src/tools/PasteHandler.ts +0 -94
  162. package/src/tools/Pen.test.ts +0 -260
  163. package/src/tools/Pen.ts +0 -284
  164. package/src/tools/PipetteTool.ts +0 -84
  165. package/src/tools/SelectionTool/SelectAllShortcutHandler.ts +0 -29
  166. package/src/tools/SelectionTool/Selection.ts +0 -647
  167. package/src/tools/SelectionTool/SelectionHandle.ts +0 -142
  168. package/src/tools/SelectionTool/SelectionTool.test.ts +0 -370
  169. package/src/tools/SelectionTool/SelectionTool.ts +0 -510
  170. package/src/tools/SelectionTool/TransformMode.ts +0 -112
  171. package/src/tools/SelectionTool/types.ts +0 -11
  172. package/src/tools/SoundUITool.ts +0 -221
  173. package/src/tools/TextTool.ts +0 -339
  174. package/src/tools/ToolController.ts +0 -224
  175. package/src/tools/ToolEnabledGroup.ts +0 -14
  176. package/src/tools/ToolSwitcherShortcut.ts +0 -39
  177. package/src/tools/ToolbarShortcutHandler.ts +0 -39
  178. package/src/tools/UndoRedoShortcut.test.ts +0 -62
  179. package/src/tools/UndoRedoShortcut.ts +0 -24
  180. package/src/tools/keybindings.ts +0 -85
  181. package/src/tools/lib.ts +0 -22
  182. package/src/tools/localization.ts +0 -76
  183. package/src/types.ts +0 -151
  184. package/src/util/ReactiveValue.test.ts +0 -168
  185. package/src/util/ReactiveValue.ts +0 -241
  186. package/src/util/assertions.ts +0 -55
  187. package/src/util/fileToBase64.ts +0 -18
  188. package/src/util/guessKeyCodeFromKey.ts +0 -36
  189. package/src/util/listPrefixMatch.ts +0 -19
  190. package/src/util/stopPropagationOfScrollingWheelEvents.ts +0 -20
  191. package/src/util/untilNextAnimationFrame.ts +0 -9
  192. package/src/util/waitForAll.ts +0 -18
  193. package/src/util/waitForTimeout.ts +0 -9
  194. package/src/version.test.ts +0 -12
  195. package/src/version.ts +0 -3
  196. package/tools/allLocales.js +0 -4
  197. package/tools/copyREADME.ts +0 -62
@@ -1,61 +0,0 @@
1
- import KeyBinding from './KeyBinding';
2
-
3
- describe('KeyBinding', () => {
4
- it('toString should produce keybinds that can be interpreted by fromString', () => {
5
- const testStrings = [
6
- 'c',
7
- 'Shift+c',
8
- 'Ctrl+Shift+a',
9
- 'Ctrl+c',
10
- 'control',
11
- 'shift',
12
- 'meta',
13
- 'Ctrl+Alt+delete',
14
- 'leftarrow',
15
- 'CtrlOrMeta+z',
16
- 'á',
17
- '-',
18
- '+',
19
- ];
20
-
21
- for (const str of testStrings) {
22
- expect(KeyBinding.fromString(str).toString()).toBe(str);
23
- }
24
- });
25
-
26
- it('ctrlOrMeta should match events with either ctrl or meta (or both) modifiers', () => {
27
- const ctrlOrMetaA = KeyBinding.fromString('CtrlOrMeta-a');
28
- const ctrlA = KeyBinding.fromString('ctrl-a');
29
- const metaA = KeyBinding.fromString('meta-a');
30
- const ctrlOrMetaShiftB = KeyBinding.fromString('CtrlOrMeta-Shift-b');
31
- const shiftB = KeyBinding.fromString('Shift-b');
32
-
33
- expect(ctrlOrMetaA.matchesEvent(ctrlA)).toBe(true);
34
- expect(ctrlOrMetaA.matchesEvent(metaA)).toBe(true);
35
- expect(ctrlOrMetaA.matchesEvent(ctrlOrMetaShiftB)).toBe(false);
36
- expect(
37
- ctrlOrMetaShiftB.matchesEvent({
38
- key: 'b', shiftKey: true, metaKey: true
39
- }),
40
- ).toBe(true);
41
- expect(ctrlOrMetaShiftB.matchesEvent(shiftB)).toBe(false);
42
- });
43
-
44
- it('ctrl-1 should match ctrl + the number 1', () => {
45
- const ctrl1 = KeyBinding.fromString('ctrl-1');
46
-
47
- expect(ctrl1.matchesEvent({ key: '1', shiftKey: false, ctrlKey: true })).toBe(true);
48
- expect(ctrl1.matchesEvent({ key: '1', shiftKey: true, ctrlKey: true })).toBe(true);
49
- expect(ctrl1.matchesEvent({ key: '1', shiftKey: true, ctrlKey: false })).toBe(false);
50
- });
51
-
52
- it('ctrl-KeyA should match ctrl + event with code KeyA', () => {
53
- const ctrlA = KeyBinding.fromString('ctrl-KeyA');
54
-
55
- expect(ctrlA.matchesEvent({ code: 'KeyA', shiftKey: false, ctrlKey: true })).toBe(true);
56
- expect(ctrlA.matchesEvent({ key: 'a', code: 'KeyA', shiftKey: false, ctrlKey: true })).toBe(true);
57
- expect(ctrlA.matchesEvent({ key: 'a', code: 'KeyA', shiftKey: false, ctrlKey: false })).toBe(false);
58
- expect(ctrlA.matchesEvent({ code: 'KeyB', shiftKey: false, ctrlKey: true })).toBe(false);
59
- expect(ctrlA.matchesEvent({ code: 'KeyA', shiftKey: true, ctrlKey: true })).toBe(false);
60
- });
61
- });
@@ -1,257 +0,0 @@
1
-
2
- export interface KeyCombination {
3
- /** A key (e.g. `a`, `b`, `control`). */
4
- readonly key: string;
5
-
6
- /**
7
- * The layout-independent name of the key being pressed. For example,
8
- * KeyA for the `a` key.
9
- */
10
- readonly code?: string;
11
-
12
- /**
13
- * Whether the shift key must be pressed to trigger the shortcut.
14
- */
15
- readonly shiftKey: boolean|undefined;
16
-
17
- /** Whether the control key must be pressed to trigger the shortcut */
18
- readonly ctrlKey: boolean;
19
-
20
- /** Whether the alt key must be pressed to trigger the shortcut */
21
- readonly altKey: boolean;
22
-
23
- /** Whether the meta key must be pressed to trigger the shortcut */
24
- readonly metaKey: boolean;
25
-
26
- /** True if this shortcut/key combination applies for either control or meta. */
27
- readonly controlOrMeta: boolean;
28
- }
29
-
30
- const isUppercaseLetter = (text: string) => {
31
- return text.toUpperCase() === text
32
- && text.toLowerCase() !== text
33
- && text.length === 1;
34
- };
35
-
36
- const isLowercaseLetter = (text: string) => {
37
- return text.toLowerCase() === text
38
- && text.toUpperCase() !== text
39
- && text.length === 1;
40
- };
41
-
42
- /** Represents a key combination that can trigger a keyboard shortcut. */
43
- export default class KeyBinding implements KeyCombination {
44
- /** @inheritdoc */
45
- public readonly key: string;
46
-
47
- /**
48
- * If undefined, the state of the shift key is ignored.
49
- */
50
- public readonly shiftKey: boolean|undefined;
51
-
52
- /** @inheritdoc */
53
- public readonly ctrlKey: boolean;
54
-
55
- /** @inheritdoc */
56
- public readonly altKey: boolean;
57
-
58
- /** @inheritdoc */
59
- public readonly metaKey: boolean;
60
-
61
- /** @inheritdoc */
62
- public readonly controlOrMeta: boolean;
63
-
64
- public constructor(trigger: KeyCombination) {
65
- this.key = trigger.key;
66
- this.shiftKey = trigger.shiftKey;
67
- this.ctrlKey = trigger.ctrlKey;
68
- this.altKey = trigger.altKey;
69
- this.metaKey = trigger.metaKey;
70
- this.controlOrMeta = trigger.controlOrMeta;
71
- }
72
-
73
- /** Returns true if and only if `keyEvent` should trigger this shortcut. */
74
- public matchesEvent(keyEvent: Partial<KeyCombination>) {
75
- const lowercaseKey = keyEvent.key?.toLowerCase();
76
-
77
- // Determine whether the input is an upper case letter or not.
78
- const isUpperCaseKey = isUppercaseLetter(keyEvent.key ?? '');
79
- const isLowercaseKey = isLowercaseLetter(keyEvent.key ?? '');
80
-
81
- const ctrlKey = (keyEvent.ctrlKey ?? false) || lowercaseKey === 'control';
82
- const altKey = (keyEvent.altKey ?? false) || lowercaseKey === 'alt';
83
- const metaKey = (keyEvent.metaKey ?? false) || lowercaseKey === 'meta';
84
- const shiftKey =
85
- (keyEvent.shiftKey ?? isUpperCaseKey) || lowercaseKey === 'shift';
86
- const keyEventHasCtrlOrMeta =
87
- keyEvent.controlOrMeta || keyEvent.ctrlKey || keyEvent.metaKey || false;
88
-
89
- // If we're not working with key codes,
90
- if (this.key !== keyEvent.code) {
91
- // Different keys entirely? They don't match.
92
- if (this.key.toLowerCase() !== lowercaseKey) {
93
- return false;
94
- }
95
-
96
- // If a case where the ASCII case of the given key might matter,
97
- // compare.
98
- if ((isUpperCaseKey || isLowercaseKey) && this.key !== keyEvent.key) {
99
- // this.shiftKey may be interpreted as allowing this shortcut to be uppercased.
100
- // If so, try making this.key uppercase and matching the shortcut.
101
- const uppercaseKeyMatches = this.shiftKey === true && this.key.toUpperCase() === keyEvent.key;
102
- if (!uppercaseKeyMatches) {
103
- return false;
104
- }
105
- }
106
- }
107
-
108
- const shortcutControlOrMeta = this.controlOrMeta;
109
- // Match ctrl/meta if the shortcut doesn't have controlOrMeta specified
110
- // (controlOrMeta should match either).
111
- const ctrlAndMetaMatches =
112
- ctrlKey === this.ctrlKey
113
- && metaKey === this.metaKey
114
- && !shortcutControlOrMeta;
115
-
116
- const matches =
117
- (ctrlAndMetaMatches || (shortcutControlOrMeta && keyEventHasCtrlOrMeta))
118
- && altKey === this.altKey
119
- && (shiftKey === this.shiftKey || this.shiftKey === undefined);
120
- return matches;
121
- }
122
-
123
- /**
124
- * Returns a string representation of this shortcut in the same format accepted by
125
- * {@link fromString}.
126
- */
127
- public toString() {
128
- const result = [];
129
-
130
- if (this.ctrlKey && this.key !== 'control') {
131
- result.push('Ctrl');
132
- }
133
- if (this.controlOrMeta) {
134
- result.push('CtrlOrMeta');
135
- }
136
- if (this.altKey && this.key !== 'alt') {
137
- result.push('Alt');
138
- }
139
- if (this.metaKey && this.key !== 'meta') {
140
- result.push('Meta');
141
- }
142
- if (this.shiftKey && this.key !== 'shift') {
143
- result.push('Shift');
144
- }
145
- result.push(this.key);
146
-
147
- return result.join('+');
148
- }
149
-
150
- /**
151
- * Accepts a string in the form `modifier1+modifier2+...+key` (e.g. `Ctrl+Shift+a`)
152
- * and returns the corresponding `KeyboardShortcut`.
153
- */
154
- public static fromString(shortcutStr: string): KeyBinding {
155
- const getDefaultModifiers = (key: string) => {
156
- // Unless a letter, as long as the given key matches, it shouldn't matter whether
157
- // the shift key is pressed.
158
- let shiftKey: boolean|undefined = undefined;
159
-
160
- if (isUppercaseLetter(key)) {
161
- shiftKey = true;
162
- }
163
- else if (isLowercaseLetter(key)) {
164
- shiftKey = false;
165
- }
166
- // If not just a single character (e.g. a key code like KeyA), shift must
167
- // be specified manually.
168
- else if (key.length > 1) {
169
- shiftKey = false;
170
- }
171
-
172
- const lowercaseKey = key.toLowerCase();
173
-
174
- // shiftKey should always be true if the key is 'shift'
175
- if (lowercaseKey === 'shift') {
176
- shiftKey = true;
177
- }
178
-
179
- return {
180
- shiftKey,
181
- ctrlKey: lowercaseKey === 'control' || lowercaseKey === 'ctrl',
182
- altKey: lowercaseKey === 'alt',
183
- metaKey: lowercaseKey === 'meta',
184
- controlOrMeta: lowercaseKey === 'control or meta' || lowercaseKey === 'ctrlormeta',
185
- };
186
- };
187
-
188
- const hasNoModifiers = shortcutStr.search(/[-+]/) === -1 || shortcutStr.length === 1;
189
- if (hasNoModifiers) {
190
- const modifiers = getDefaultModifiers(shortcutStr);
191
-
192
- return new KeyBinding({
193
- key: shortcutStr,
194
- ...modifiers,
195
- });
196
- }
197
-
198
- const keyModifiersExp = /^(.*[-+])?(.+)$/g;
199
- const match = keyModifiersExp.exec(shortcutStr);
200
-
201
- if (!match) {
202
- throw new Error(`Invalid shortcut expression, ${shortcutStr}!`);
203
- }
204
-
205
- const key = match[2];
206
- const defaultModifiers = getDefaultModifiers(key);
207
- const modifierStrings = (match[1] ?? '').split(/[-+]/);
208
-
209
- let shiftKey = defaultModifiers.shiftKey;
210
- let ctrlKey = defaultModifiers.ctrlKey;
211
- let altKey = defaultModifiers.altKey;
212
- let metaKey = defaultModifiers.metaKey;
213
- let controlOrMeta = defaultModifiers.controlOrMeta;
214
-
215
- for (const modifier of modifierStrings) {
216
- if (modifier === '') {
217
- continue;
218
- }
219
-
220
- switch (modifier.toLowerCase()) {
221
- case 'shift':
222
- shiftKey = true;
223
- break;
224
- case 'anyshift':
225
- shiftKey = undefined;
226
- break;
227
- case 'ctrl':
228
- case 'control':
229
- ctrlKey = true;
230
- break;
231
- case 'meta':
232
- metaKey = true;
233
- break;
234
- case 'ctrlormeta':
235
- case 'ctrl or meta':
236
- case 'controlormeta':
237
- controlOrMeta = true;
238
- break;
239
- case 'alt':
240
- altKey = true;
241
- break;
242
- default:
243
- throw new Error(`Unknown modifier: "${modifier}" in shortcut ${shortcutStr}.`);
244
- }
245
- }
246
-
247
- const shortcut = new KeyBinding({
248
- key,
249
- shiftKey,
250
- ctrlKey,
251
- altKey,
252
- metaKey,
253
- controlOrMeta,
254
- });
255
- return shortcut;
256
- }
257
- }
@@ -1,95 +0,0 @@
1
- import { undoKeyboardShortcutId } from '../tools/keybindings';
2
- import KeyBinding from './KeyBinding';
3
- import KeyboardShortcutManager from './KeyboardShortcutManager';
4
-
5
- describe('KeyboardShortcutManager', () => {
6
- it('should contain default shortcuts for undo', () => {
7
- const defaultUndoShortcutKeybinds =
8
- KeyboardShortcutManager.getShortcutDefaultKeybindings(undoKeyboardShortcutId);
9
- expect(defaultUndoShortcutKeybinds.length).toBeGreaterThanOrEqual(1);
10
- expect(defaultUndoShortcutKeybinds.some(shortcut => {
11
- return shortcut.key === 'KeyZ' && shortcut.controlOrMeta;
12
- })).toBe(true);
13
- });
14
-
15
- it('should be possible to override keyboard shortcuts', () => {
16
- const testNewId = 'someIdThatDoesNowExist';
17
- KeyboardShortcutManager.registerDefaultKeyboardShortcut(
18
- testNewId,
19
- [ KeyBinding.fromString('ctrl-1'), KeyBinding.fromString('-') ],
20
- 'Some description'
21
- );
22
-
23
- const shortcutManager = new KeyboardShortcutManager({
24
- someIdThatDoesNotExist: [
25
- KeyBinding.fromString('ctrl-shift-a'),
26
- KeyBinding.fromString('ctrl-a'),
27
- ],
28
- });
29
-
30
- // Should work before overriding
31
- expect(
32
- shortcutManager.matchesShortcut(testNewId, KeyBinding.fromString('ctrl-1'))
33
- ).toBe(true);
34
- expect(
35
- shortcutManager.matchesShortcut(testNewId, KeyBinding.fromString('-'))
36
- ).toBe(true);
37
- expect(
38
- shortcutManager.matchesShortcut(testNewId, KeyBinding.fromString('ctrl-b'))
39
- ).toBe(false);
40
- expect(
41
- shortcutManager.matchesShortcut(testNewId, KeyBinding.fromString('ctrl-0'))
42
- ).toBe(false);
43
- expect(
44
- shortcutManager.matchesShortcut(testNewId, KeyBinding.fromString('1'))
45
- ).toBe(false);
46
-
47
- shortcutManager.overrideShortcut(testNewId, [
48
- KeyBinding.fromString('ctrl-b'),
49
- ]);
50
-
51
-
52
- // Should work after overriding
53
- expect(
54
- shortcutManager.matchesShortcut(testNewId, KeyBinding.fromString('ctrl-1'))
55
- ).toBe(false);
56
- expect(
57
- shortcutManager.matchesShortcut(testNewId, KeyBinding.fromString('-'))
58
- ).toBe(false);
59
- expect(
60
- shortcutManager.matchesShortcut(testNewId, KeyBinding.fromString('ctrl-b'))
61
- ).toBe(true);
62
- expect(
63
- shortcutManager.matchesShortcut(testNewId, KeyBinding.fromString('ctrl-0'))
64
- ).toBe(false);
65
- expect(
66
- shortcutManager.matchesShortcut(testNewId, KeyBinding.fromString('1'))
67
- ).toBe(false);
68
- });
69
-
70
- it('should provide localized descriptions of keyboard shortcuts', () => {
71
- const testNewId = 'someIdThatDoesNowExist--testingLocalization';
72
- const defaultDescription = 'Some description 1';
73
- KeyboardShortcutManager.registerDefaultKeyboardShortcut(
74
- testNewId,
75
- [ KeyBinding.fromString('ctrl-1'), KeyBinding.fromString('-') ],
76
- defaultDescription
77
- );
78
-
79
- expect(KeyboardShortcutManager.getShortcutDescription(testNewId)).toBe(defaultDescription);
80
- expect(
81
- KeyboardShortcutManager.getShortcutDescription(testNewId, ['fakeLocale'])
82
- ).toBe(defaultDescription);
83
-
84
- const spanishDescription = 'Alguna descripción';
85
- KeyboardShortcutManager.provideShortcutDescription(
86
- testNewId,
87
- 'es',
88
- spanishDescription
89
- );
90
-
91
- expect(
92
- KeyboardShortcutManager.getShortcutDescription(testNewId, ['es', 'en'])
93
- ).toBe(spanishDescription);
94
- });
95
- });
@@ -1,163 +0,0 @@
1
- import { matchingLocalizationTable } from '../localizations/getLocalizationTable';
2
- import KeyBinding, { KeyCombination } from './KeyBinding';
3
-
4
- type ShortcutDictionary = Record<string, KeyBinding[]>;
5
-
6
- // Maps from shortcut IDs to a description of each.
7
- type ShortcutDescriptionDictionary = Record<string, string>;
8
-
9
- /**
10
- * Allows adding/changing keyboard shortcuts. This class provides static methods for registering
11
- * default shortcuts. An instance of this class must be used to access or change keyboard shortcuts.
12
- */
13
- export default class KeyboardShortcutManager {
14
- private static shortcuts: ShortcutDictionary = Object.create(null);
15
- private static shortcutDefaultDescriptions: ShortcutDescriptionDictionary
16
- = Object.create(null);
17
- private static shortcutLocalizedDescriptions: Record<string, ShortcutDescriptionDictionary>
18
- = Object.create(null);
19
-
20
- private shortcutOverrides: ShortcutDictionary = Object.create(null);
21
-
22
- /**
23
- * Creates a new `ShortcutManager` with an initial set of shortcut overrides.
24
- *
25
- * @internal
26
- */
27
- public constructor(initialOverrides: ShortcutDictionary) {
28
- for (const id in initialOverrides) {
29
- this.overrideShortcut(id, initialOverrides[id]);
30
- }
31
- }
32
-
33
- /**
34
- * Override an existing shortcut with a custom set of triggers.
35
- * @internal
36
- */
37
- public overrideShortcut(shortcutId: string, overrideWith: KeyBinding[]) {
38
- this.shortcutOverrides[shortcutId] = [ ...overrideWith ];
39
- }
40
-
41
- /** Returns true if `keyEvent` matches the shortcut with `shortcutId`. @internal */
42
- public matchesShortcut(shortcutId: string, keyEvent: Partial<KeyCombination>) {
43
- // Get all shortcucts associated with `shortcutId`.
44
- let shortcutList = this.shortcutOverrides[shortcutId];
45
-
46
- if (!shortcutList) {
47
- if (shortcutId in KeyboardShortcutManager.shortcuts) {
48
- shortcutList = KeyboardShortcutManager.shortcuts[shortcutId];
49
- } else {
50
- throw new Error(`No shortcut with ID ${shortcutId} exists!`);
51
- }
52
- }
53
-
54
- // return true if keyEvent matches *any* shortcuts in shortcutList
55
- for (const shortcut of shortcutList) {
56
- if (shortcut.matchesEvent(keyEvent)) {
57
- return true;
58
- }
59
- }
60
-
61
- return false;
62
- }
63
-
64
- /**
65
- * Registers a default keyboard shortcut that can be overridden by individual instances
66
- * of `ShortcutManager`. Note that `id` should be a globally unique identifier.
67
- *
68
- * Only the first call to this method for a given `id` has an effect.
69
- *
70
- * @example
71
- * ```ts
72
- * const shortcutId = 'io.github.personalizedrefrigerator.js-draw.select-all';
73
- *
74
- * // Associate two shortcuts with the same ID
75
- * const shortcut1 = KeyboardShortcutManager.keyboardShortcutFromString('ctrlOrMeta+a');
76
- * const shortcut2 = KeyboardShortcutManager.keyboardShortcutFromString('ctrlOrMeta+shift+a');
77
- * KeyboardShortcutManager.registerDefaultKeyboardShortcut(
78
- * shortcutId,
79
- * [ shortcut1, shortcut2 ],
80
- * "Select All",
81
- * );
82
- *
83
- * // Provide a localized description
84
- * KeyboardShortcutManager.provideShortcutDescription(
85
- * shotcutId,
86
- * 'es',
87
- * 'Seleccionar todo',
88
- * );
89
- * ```
90
- *
91
- * @internal
92
- */
93
- public static registerDefaultKeyboardShortcut(
94
- id: string,
95
- shortcuts: (KeyBinding|string)[],
96
- defaultDescription: string,
97
- ): boolean {
98
- if (id in KeyboardShortcutManager.shortcuts) {
99
- return false;
100
- }
101
-
102
- // Convert the strings to shortcut maps.
103
- const shortcutsAsShortcuts = shortcuts.map(shortcut => {
104
- if (typeof (shortcut) === 'string') {
105
- return KeyBinding.fromString(shortcut);
106
- }
107
- return shortcut;
108
- });
109
-
110
- KeyboardShortcutManager.shortcuts[id] = [ ...shortcutsAsShortcuts ];
111
- KeyboardShortcutManager.shortcutDefaultDescriptions[id] = defaultDescription;
112
- return true;
113
- }
114
-
115
- /** Provides a localized description of a keyboard shortcut. @internal */
116
- public static provideShortcutDescription(id: string, locale: string, description: string) {
117
- if (!(locale in KeyboardShortcutManager.shortcutLocalizedDescriptions)) {
118
- KeyboardShortcutManager.shortcutLocalizedDescriptions[locale] = Object.create(null);
119
- }
120
-
121
- KeyboardShortcutManager.shortcutLocalizedDescriptions[locale][id] = description;
122
- }
123
-
124
- /**
125
- * Gets all registered keyboard shortcut IDs.
126
- *
127
- * @see {@link getShortcutDescription}
128
- */
129
- public static getAllShortcutIds() {
130
- const ids = [];
131
- for (const id in this.shortcuts) {
132
- ids.push(id);
133
- }
134
- return ids;
135
- }
136
-
137
- /**
138
- * Get the default keybindings associated with a keyboard shortcut.
139
- *
140
- * Any keybinding in the resultant list, by default, can trigger the function associated
141
- * with the shortcut.
142
- */
143
- public static getShortcutDefaultKeybindings(shortcutId: string): KeyBinding[] {
144
- if (!(shortcutId in KeyboardShortcutManager.shortcuts)) {
145
- throw new Error(`No shortcut with ID ${shortcutId} exists!`);
146
- }
147
-
148
- return KeyboardShortcutManager.shortcuts[shortcutId];
149
- }
150
-
151
- /**
152
- * Get a description of a keyboard shortcut.
153
- *
154
- * `localeList`, if given, attempts to
155
- */
156
- public static getShortcutDescription(id: string, localeList?: readonly string[]): string|null {
157
- const localizationTable = matchingLocalizationTable(
158
- localeList ?? [], this.shortcutLocalizedDescriptions, this.shortcutDefaultDescriptions
159
- );
160
-
161
- return localizationTable[id] ?? this.shortcutDefaultDescriptions[id] ?? null;
162
- }
163
- }
@@ -1,3 +0,0 @@
1
-
2
- export { default as KeyboardShortcutManager } from './KeyboardShortcutManager';
3
- export { default as KeyBinding } from './KeyBinding';
@@ -1,11 +0,0 @@
1
- import { RenderingMode } from '../rendering/Display';
2
- import Editor from '../Editor';
3
-
4
- /** Creates an editor. Should only be used in test files. */
5
- export default () => {
6
- if (jest === undefined) {
7
- throw new Error('Files in the testing/ folder should only be used in tests!');
8
- }
9
-
10
- return new Editor(document.body, { renderingMode: RenderingMode.DummyRenderer });
11
- };
@@ -1,18 +0,0 @@
1
- import Pointer from '../Pointer';
2
-
3
- /** Returns the smallest ID not used by the pointers in the given list. */
4
- const getUniquePointerId = (pointers: Pointer[]) => {
5
- let ptrId = 0;
6
-
7
- const pointerIds = pointers.map(ptr => ptr.id);
8
- pointerIds.sort();
9
- for (const pointerId of pointerIds) {
10
- if (ptrId === pointerId) {
11
- ptrId = pointerId + 1;
12
- }
13
- }
14
-
15
- return ptrId;
16
- };
17
-
18
- export default getUniquePointerId;
@@ -1,3 +0,0 @@
1
-
2
- export { default as sendPenEvent } from './sendPenEvent';
3
- export { default as sendTouchEvent } from './sendTouchEvent';
@@ -1,36 +0,0 @@
1
- import Editor from '../Editor';
2
- import { Point2 } from '@js-draw/math';
3
- import Pointer from '../Pointer';
4
- import { InputEvtType } from '../inputEvents';
5
- import getUniquePointerId from './getUniquePointerId';
6
-
7
- /**
8
- * Dispatch a pen event to the currently selected tool.
9
- * Intended for unit tests.
10
- *
11
- * @see {@link sendTouchEvent}
12
- */
13
- const sendPenEvent = (
14
- editor: Editor,
15
- eventType: InputEvtType.PointerDownEvt|InputEvtType.PointerMoveEvt|InputEvtType.PointerUpEvt,
16
- point: Point2,
17
-
18
- allPointers?: Pointer[]
19
- ) => {
20
- const id = getUniquePointerId(allPointers ?? []);
21
-
22
- const mainPointer = Pointer.ofCanvasPoint(
23
- point, eventType !== InputEvtType.PointerUpEvt, editor.viewport, id
24
- );
25
-
26
- editor.toolController.dispatchInputEvent({
27
- kind: eventType,
28
- allPointers: allPointers ?? [
29
- mainPointer,
30
- ],
31
- current: mainPointer,
32
- });
33
-
34
- return mainPointer;
35
- };
36
- export default sendPenEvent;