js-draw 1.21.2 → 1.21.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. package/dist/bundle.js +1 -1
  2. package/dist/cjs/tools/BaseTool.d.ts +61 -0
  3. package/dist/cjs/tools/BaseTool.js +179 -0
  4. package/dist/cjs/tools/Eraser.d.ts +60 -0
  5. package/dist/cjs/tools/Eraser.js +299 -0
  6. package/dist/cjs/tools/Eraser.test.d.ts +1 -0
  7. package/dist/cjs/tools/FindTool.d.ts +21 -0
  8. package/dist/cjs/tools/FindTool.js +137 -0
  9. package/dist/cjs/tools/FindTool.test.d.ts +1 -0
  10. package/dist/cjs/tools/InputFilter/ContextMenuRecognizer.d.ts +17 -0
  11. package/dist/cjs/tools/InputFilter/ContextMenuRecognizer.js +105 -0
  12. package/dist/cjs/tools/InputFilter/ContextMenuRecognizer.test.d.ts +1 -0
  13. package/dist/cjs/tools/InputFilter/FunctionMapper.d.ts +12 -0
  14. package/dist/cjs/tools/InputFilter/FunctionMapper.js +21 -0
  15. package/dist/cjs/tools/InputFilter/InputMapper.d.ts +23 -0
  16. package/dist/cjs/tools/InputFilter/InputMapper.js +38 -0
  17. package/dist/cjs/tools/InputFilter/InputPipeline.d.ts +15 -0
  18. package/dist/cjs/tools/InputFilter/InputPipeline.js +54 -0
  19. package/dist/cjs/tools/InputFilter/InputPipeline.test.d.ts +1 -0
  20. package/dist/cjs/tools/InputFilter/InputStabilizer.d.ts +29 -0
  21. package/dist/cjs/tools/InputFilter/InputStabilizer.js +181 -0
  22. package/dist/cjs/tools/InputFilter/StrokeKeyboardControl.d.ts +21 -0
  23. package/dist/cjs/tools/InputFilter/StrokeKeyboardControl.js +84 -0
  24. package/dist/cjs/tools/PanZoom.d.ts +125 -0
  25. package/dist/cjs/tools/PanZoom.js +517 -0
  26. package/dist/cjs/tools/PanZoom.test.d.ts +1 -0
  27. package/dist/cjs/tools/PasteHandler.d.ts +23 -0
  28. package/dist/cjs/tools/PasteHandler.js +109 -0
  29. package/dist/cjs/tools/Pen.d.ts +54 -0
  30. package/dist/cjs/tools/Pen.js +335 -0
  31. package/dist/cjs/tools/Pen.test.d.ts +1 -0
  32. package/dist/cjs/tools/PipetteTool.d.ts +28 -0
  33. package/dist/cjs/tools/PipetteTool.js +69 -0
  34. package/dist/cjs/tools/ScrollbarTool.d.ts +18 -0
  35. package/dist/cjs/tools/ScrollbarTool.js +85 -0
  36. package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +9 -0
  37. package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.js +32 -0
  38. package/dist/cjs/tools/SelectionTool/Selection.d.ts +72 -0
  39. package/dist/cjs/tools/SelectionTool/Selection.js +634 -0
  40. package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +62 -0
  41. package/dist/cjs/tools/SelectionTool/SelectionHandle.js +141 -0
  42. package/dist/cjs/tools/SelectionTool/SelectionMenuShortcut.d.ts +32 -0
  43. package/dist/cjs/tools/SelectionTool/SelectionMenuShortcut.js +86 -0
  44. package/dist/cjs/tools/SelectionTool/SelectionTool.d.ts +42 -0
  45. package/dist/cjs/tools/SelectionTool/SelectionTool.js +500 -0
  46. package/dist/cjs/tools/SelectionTool/SelectionTool.selecting.test.d.ts +1 -0
  47. package/dist/cjs/tools/SelectionTool/SelectionTool.test.d.ts +1 -0
  48. package/dist/cjs/tools/SelectionTool/ToPointerAutoscroller.d.ts +23 -0
  49. package/dist/cjs/tools/SelectionTool/ToPointerAutoscroller.js +83 -0
  50. package/dist/cjs/tools/SelectionTool/TransformMode.d.ts +42 -0
  51. package/dist/cjs/tools/SelectionTool/TransformMode.js +155 -0
  52. package/dist/cjs/tools/SelectionTool/keybindings.d.ts +15 -0
  53. package/dist/cjs/tools/SelectionTool/keybindings.js +38 -0
  54. package/dist/cjs/tools/SelectionTool/types.d.ts +35 -0
  55. package/dist/cjs/tools/SelectionTool/types.js +14 -0
  56. package/dist/cjs/tools/SelectionTool/util/makeClipboardErrorHandlers.d.ts +6 -0
  57. package/dist/cjs/tools/SelectionTool/util/makeClipboardErrorHandlers.js +50 -0
  58. package/dist/cjs/tools/SelectionTool/util/showSelectionContextMenu.d.ts +5 -0
  59. package/dist/cjs/tools/SelectionTool/util/showSelectionContextMenu.js +43 -0
  60. package/dist/cjs/tools/SoundUITool.d.ts +26 -0
  61. package/dist/cjs/tools/SoundUITool.js +171 -0
  62. package/dist/cjs/tools/TextTool.d.ts +36 -0
  63. package/dist/cjs/tools/TextTool.js +285 -0
  64. package/dist/cjs/tools/TextTool.test.d.ts +1 -0
  65. package/dist/cjs/tools/ToolController.d.ts +73 -0
  66. package/dist/cjs/tools/ToolController.js +304 -0
  67. package/dist/cjs/tools/ToolController.test.d.ts +1 -0
  68. package/dist/cjs/tools/ToolEnabledGroup.d.ts +6 -0
  69. package/dist/cjs/tools/ToolEnabledGroup.js +13 -0
  70. package/dist/cjs/tools/ToolSwitcherShortcut.d.ts +16 -0
  71. package/dist/cjs/tools/ToolSwitcherShortcut.js +40 -0
  72. package/dist/cjs/tools/ToolbarShortcutHandler.d.ts +12 -0
  73. package/dist/cjs/tools/ToolbarShortcutHandler.js +34 -0
  74. package/dist/cjs/tools/UndoRedoShortcut.d.ts +8 -0
  75. package/dist/cjs/tools/UndoRedoShortcut.js +27 -0
  76. package/dist/cjs/tools/UndoRedoShortcut.test.d.ts +1 -0
  77. package/dist/cjs/tools/keybindings.d.ts +16 -0
  78. package/dist/cjs/tools/keybindings.js +58 -0
  79. package/dist/cjs/tools/lib.d.ts +14 -0
  80. package/dist/cjs/tools/lib.js +36 -0
  81. package/dist/cjs/tools/localization.d.ts +43 -0
  82. package/dist/cjs/tools/localization.js +45 -0
  83. package/dist/cjs/tools/util/StationaryPenDetector.d.ts +25 -0
  84. package/dist/cjs/tools/util/StationaryPenDetector.js +107 -0
  85. package/dist/cjs/tools/util/createMenuOverlay.d.ts +10 -0
  86. package/dist/cjs/tools/util/createMenuOverlay.js +126 -0
  87. package/dist/cjs/tools/util/createMenuOverlay.test.d.ts +1 -0
  88. package/dist/cjs/version.js +1 -1
  89. package/dist/mjs/tools/BaseTool.d.ts +61 -0
  90. package/dist/mjs/tools/BaseTool.mjs +177 -0
  91. package/dist/mjs/tools/Eraser.d.ts +60 -0
  92. package/dist/mjs/tools/Eraser.mjs +292 -0
  93. package/dist/mjs/tools/Eraser.test.d.ts +1 -0
  94. package/dist/mjs/tools/FindTool.d.ts +21 -0
  95. package/dist/mjs/tools/FindTool.mjs +131 -0
  96. package/dist/mjs/tools/FindTool.test.d.ts +1 -0
  97. package/dist/mjs/tools/InputFilter/ContextMenuRecognizer.d.ts +17 -0
  98. package/dist/mjs/tools/InputFilter/ContextMenuRecognizer.mjs +76 -0
  99. package/dist/mjs/tools/InputFilter/ContextMenuRecognizer.test.d.ts +1 -0
  100. package/dist/mjs/tools/InputFilter/FunctionMapper.d.ts +12 -0
  101. package/dist/mjs/tools/InputFilter/FunctionMapper.mjs +15 -0
  102. package/dist/mjs/tools/InputFilter/InputMapper.d.ts +23 -0
  103. package/dist/mjs/tools/InputFilter/InputMapper.mjs +36 -0
  104. package/dist/mjs/tools/InputFilter/InputPipeline.d.ts +15 -0
  105. package/dist/mjs/tools/InputFilter/InputPipeline.mjs +49 -0
  106. package/dist/mjs/tools/InputFilter/InputPipeline.test.d.ts +1 -0
  107. package/dist/mjs/tools/InputFilter/InputStabilizer.d.ts +29 -0
  108. package/dist/mjs/tools/InputFilter/InputStabilizer.mjs +175 -0
  109. package/dist/mjs/tools/InputFilter/StrokeKeyboardControl.d.ts +21 -0
  110. package/dist/mjs/tools/InputFilter/StrokeKeyboardControl.mjs +78 -0
  111. package/dist/mjs/tools/PanZoom.d.ts +125 -0
  112. package/dist/mjs/tools/PanZoom.mjs +510 -0
  113. package/dist/mjs/tools/PanZoom.test.d.ts +1 -0
  114. package/dist/mjs/tools/PasteHandler.d.ts +23 -0
  115. package/dist/mjs/tools/PasteHandler.mjs +103 -0
  116. package/dist/mjs/tools/Pen.d.ts +54 -0
  117. package/dist/mjs/tools/Pen.mjs +306 -0
  118. package/dist/mjs/tools/Pen.test.d.ts +1 -0
  119. package/dist/mjs/tools/PipetteTool.d.ts +28 -0
  120. package/dist/mjs/tools/PipetteTool.mjs +63 -0
  121. package/dist/mjs/tools/ScrollbarTool.d.ts +18 -0
  122. package/dist/mjs/tools/ScrollbarTool.mjs +79 -0
  123. package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +9 -0
  124. package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.mjs +26 -0
  125. package/dist/mjs/tools/SelectionTool/Selection.d.ts +72 -0
  126. package/dist/mjs/tools/SelectionTool/Selection.mjs +606 -0
  127. package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +62 -0
  128. package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +137 -0
  129. package/dist/mjs/tools/SelectionTool/SelectionMenuShortcut.d.ts +32 -0
  130. package/dist/mjs/tools/SelectionTool/SelectionMenuShortcut.mjs +83 -0
  131. package/dist/mjs/tools/SelectionTool/SelectionTool.d.ts +42 -0
  132. package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +493 -0
  133. package/dist/mjs/tools/SelectionTool/SelectionTool.selecting.test.d.ts +1 -0
  134. package/dist/mjs/tools/SelectionTool/SelectionTool.test.d.ts +1 -0
  135. package/dist/mjs/tools/SelectionTool/ToPointerAutoscroller.d.ts +23 -0
  136. package/dist/mjs/tools/SelectionTool/ToPointerAutoscroller.mjs +77 -0
  137. package/dist/mjs/tools/SelectionTool/TransformMode.d.ts +42 -0
  138. package/dist/mjs/tools/SelectionTool/TransformMode.mjs +146 -0
  139. package/dist/mjs/tools/SelectionTool/keybindings.d.ts +15 -0
  140. package/dist/mjs/tools/SelectionTool/keybindings.mjs +32 -0
  141. package/dist/mjs/tools/SelectionTool/types.d.ts +35 -0
  142. package/dist/mjs/tools/SelectionTool/types.mjs +11 -0
  143. package/dist/mjs/tools/SelectionTool/util/makeClipboardErrorHandlers.d.ts +6 -0
  144. package/dist/mjs/tools/SelectionTool/util/makeClipboardErrorHandlers.mjs +45 -0
  145. package/dist/mjs/tools/SelectionTool/util/showSelectionContextMenu.d.ts +5 -0
  146. package/dist/mjs/tools/SelectionTool/util/showSelectionContextMenu.mjs +38 -0
  147. package/dist/mjs/tools/SoundUITool.d.ts +26 -0
  148. package/dist/mjs/tools/SoundUITool.mjs +165 -0
  149. package/dist/mjs/tools/TextTool.d.ts +36 -0
  150. package/dist/mjs/tools/TextTool.mjs +279 -0
  151. package/dist/mjs/tools/TextTool.test.d.ts +1 -0
  152. package/dist/mjs/tools/ToolController.d.ts +73 -0
  153. package/dist/mjs/tools/ToolController.mjs +275 -0
  154. package/dist/mjs/tools/ToolController.test.d.ts +1 -0
  155. package/dist/mjs/tools/ToolEnabledGroup.d.ts +6 -0
  156. package/dist/mjs/tools/ToolEnabledGroup.mjs +10 -0
  157. package/dist/mjs/tools/ToolSwitcherShortcut.d.ts +16 -0
  158. package/dist/mjs/tools/ToolSwitcherShortcut.mjs +34 -0
  159. package/dist/mjs/tools/ToolbarShortcutHandler.d.ts +12 -0
  160. package/dist/mjs/tools/ToolbarShortcutHandler.mjs +28 -0
  161. package/dist/mjs/tools/UndoRedoShortcut.d.ts +8 -0
  162. package/dist/mjs/tools/UndoRedoShortcut.mjs +21 -0
  163. package/dist/mjs/tools/UndoRedoShortcut.test.d.ts +1 -0
  164. package/dist/mjs/tools/keybindings.d.ts +16 -0
  165. package/dist/mjs/tools/keybindings.mjs +38 -0
  166. package/dist/mjs/tools/lib.d.ts +14 -0
  167. package/dist/mjs/tools/lib.mjs +14 -0
  168. package/dist/mjs/tools/localization.d.ts +43 -0
  169. package/dist/mjs/tools/localization.mjs +42 -0
  170. package/dist/mjs/tools/util/StationaryPenDetector.d.ts +25 -0
  171. package/dist/mjs/tools/util/StationaryPenDetector.mjs +103 -0
  172. package/dist/mjs/tools/util/createMenuOverlay.d.ts +10 -0
  173. package/dist/mjs/tools/util/createMenuOverlay.mjs +121 -0
  174. package/dist/mjs/tools/util/createMenuOverlay.test.d.ts +1 -0
  175. package/dist/mjs/version.mjs +1 -1
  176. package/package.json +4 -4
  177. package/src/tools/FindTool.css +7 -0
  178. package/src/tools/ScrollbarTool.scss +57 -0
  179. package/src/tools/SelectionTool/SelectionTool.scss +165 -0
  180. package/src/tools/SelectionTool/util/makeClipboardErrorHandlers.scss +15 -0
  181. package/src/tools/SoundUITool.scss +22 -0
  182. package/src/tools/tools.scss +6 -0
  183. package/src/tools/util/createMenuOverlay.scss +67 -0
@@ -0,0 +1,34 @@
1
+ import BaseTool from './BaseTool.mjs';
2
+ /**
3
+ * Handles keyboard events used, by default, to select tools. By default,
4
+ * 1 maps to the first primary tool, 2 to the second primary tool, ... .
5
+ *
6
+ * This is in the default set of {@link ToolController} tools.
7
+ *
8
+ */
9
+ export default class ToolSwitcherShortcut extends BaseTool {
10
+ constructor(editor) {
11
+ super(editor.notifier, editor.localization.changeTool);
12
+ this.editor = editor;
13
+ }
14
+ canReceiveInputInReadOnlyEditor() {
15
+ return true;
16
+ }
17
+ // @internal
18
+ onKeyPress({ key }) {
19
+ const toolController = this.editor.toolController;
20
+ const primaryTools = toolController.getPrimaryTools();
21
+ // Map keys 0-9 to primary tools.
22
+ const keyMatch = /^[0-9]$/.exec(key);
23
+ let targetTool;
24
+ if (keyMatch) {
25
+ const targetIdx = parseInt(keyMatch[0], 10) - 1;
26
+ targetTool = primaryTools[targetIdx];
27
+ }
28
+ if (targetTool) {
29
+ targetTool.setEnabled(true);
30
+ return true;
31
+ }
32
+ return false;
33
+ }
34
+ }
@@ -0,0 +1,12 @@
1
+ import Editor from '../Editor';
2
+ import { KeyPressEvent } from '../inputEvents';
3
+ import BaseTool from './BaseTool';
4
+ type KeyPressListener = (event: KeyPressEvent) => boolean;
5
+ export default class ToolbarShortcutHandler extends BaseTool {
6
+ private listeners;
7
+ constructor(editor: Editor);
8
+ registerListener(listener: KeyPressListener): void;
9
+ removeListener(listener: KeyPressListener): void;
10
+ onKeyPress(event: KeyPressEvent): boolean;
11
+ }
12
+ export {};
@@ -0,0 +1,28 @@
1
+ // Allows the toolbar to register keyboard events.
2
+ // @packageDocumentation
3
+ import BaseTool from './BaseTool.mjs';
4
+ export default class ToolbarShortcutHandler extends BaseTool {
5
+ constructor(editor) {
6
+ super(editor.notifier, editor.localization.changeTool);
7
+ this.listeners = new Set([]);
8
+ }
9
+ registerListener(listener) {
10
+ this.listeners.add(listener);
11
+ }
12
+ removeListener(listener) {
13
+ this.listeners.delete(listener);
14
+ }
15
+ onKeyPress(event) {
16
+ // TypeScript seems to automatically convert for of loops into for(init;check;update)
17
+ // loops (even with target set to es6). Thus, we cannot iterate directly through the
18
+ // set here.
19
+ // See https://stackoverflow.com/q/48886500
20
+ const listeners = Array.from(this.listeners.values());
21
+ for (const listener of listeners) {
22
+ if (listener(event)) {
23
+ return true;
24
+ }
25
+ }
26
+ return false;
27
+ }
28
+ }
@@ -0,0 +1,8 @@
1
+ import Editor from '../Editor';
2
+ import { KeyPressEvent } from '../inputEvents';
3
+ import BaseTool from './BaseTool';
4
+ export default class UndoRedoShortcut extends BaseTool {
5
+ private editor;
6
+ constructor(editor: Editor);
7
+ onKeyPress(event: KeyPressEvent): boolean;
8
+ }
@@ -0,0 +1,21 @@
1
+ import BaseTool from './BaseTool.mjs';
2
+ import { redoKeyboardShortcutId, undoKeyboardShortcutId } from './keybindings.mjs';
3
+ // Handles ctrl+Z, ctrl+Shift+Z keyboard shortcuts.
4
+ export default class UndoRedoShortcut extends BaseTool {
5
+ constructor(editor) {
6
+ super(editor.notifier, editor.localization.undoRedoTool);
7
+ this.editor = editor;
8
+ }
9
+ // @internal
10
+ onKeyPress(event) {
11
+ if (this.editor.shortcuts.matchesShortcut(undoKeyboardShortcutId, event)) {
12
+ this.editor.history.undo();
13
+ return true;
14
+ }
15
+ else if (this.editor.shortcuts.matchesShortcut(redoKeyboardShortcutId, event)) {
16
+ this.editor.history.redo();
17
+ return true;
18
+ }
19
+ return false;
20
+ }
21
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ export declare const undoKeyboardShortcutId = "jsdraw.tools.undo";
2
+ export declare const redoKeyboardShortcutId = "jsdaw.tools.redo";
3
+ export declare const increaseSizeKeyboardShortcutId = "jsdraw.tools.increaseSize";
4
+ export declare const decreaseSizeKeyboardShortcutId = "jsdraw.tools.decreaseSize";
5
+ export declare const snapToGridKeyboardShortcutId = "jsdraw.tools.snapToGrid";
6
+ export declare const lineLockKeyboardShortcutId = "jsdraw.tools.lockToLine";
7
+ export declare const toggleFindVisibleShortcutId = "js-draw.tools.FindTool.toggleVisible";
8
+ export declare const moveLeftKeyboardShortcutId = "jsdraw.tools.PanZoom.moveLeft";
9
+ export declare const moveRightKeyboardShortcutId = "jsdraw.tools.PanZoom.moveRight";
10
+ export declare const moveUpKeyboardShortcutId = "jsdraw.tools.PanZoom.moveUp";
11
+ export declare const moveDownKeyboardShortcutId = "jsdraw.tools.PanZoom.moveDown";
12
+ export declare const rotateClockwiseKeyboardShortcutId = "jsdraw.tools.PanZoom.rotateViewClockwise";
13
+ export declare const rotateCounterClockwiseKeyboardShortcutId = "jsdraw.tools.PanZoom.rotateViewCounterClockwise";
14
+ export declare const zoomInKeyboardShortcutId = "jsdraw.tools.PanZoom.zoomIn";
15
+ export declare const zoomOutKeyboardShortcutId = "jsdraw.tools.PanZoom.zoomOut";
16
+ export * from './SelectionTool/keybindings';
@@ -0,0 +1,38 @@
1
+ import KeyboardShortcutManager from '../shortcuts/KeyboardShortcutManager.mjs';
2
+ // This file contains user-overridable tool-realted keybindings.
3
+ // Undo/redo
4
+ export const undoKeyboardShortcutId = 'jsdraw.tools.undo';
5
+ export const redoKeyboardShortcutId = 'jsdaw.tools.redo';
6
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(undoKeyboardShortcutId, ['CtrlOrMeta+KeyZ'], 'Undo');
7
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(redoKeyboardShortcutId, ['CtrlOrMeta+Shift+KeyZ', 'CtrlOrMeta+KeyY'], 'Redo');
8
+ // Pen/eraser/selection keybindings
9
+ export const increaseSizeKeyboardShortcutId = 'jsdraw.tools.increaseSize';
10
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(increaseSizeKeyboardShortcutId, ['Equal', 'Shift+Equal'], 'Increase pen/eraser size');
11
+ export const decreaseSizeKeyboardShortcutId = 'jsdraw.tools.decreaseSize';
12
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(decreaseSizeKeyboardShortcutId, ['Minus', 'Shift+Minus'], 'Decrease pen/eraser size');
13
+ export const snapToGridKeyboardShortcutId = 'jsdraw.tools.snapToGrid';
14
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(snapToGridKeyboardShortcutId, ['Control', 'Meta'], 'Snap to grid (press and hold)');
15
+ export const lineLockKeyboardShortcutId = 'jsdraw.tools.lockToLine';
16
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(lineLockKeyboardShortcutId, ['Shift'], 'Snap to XY axes (press and hold)');
17
+ // Find tool
18
+ export const toggleFindVisibleShortcutId = 'js-draw.tools.FindTool.toggleVisible';
19
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(toggleFindVisibleShortcutId, ['CtrlOrMeta+KeyF'], 'Shows/hides the find tool');
20
+ // Pan/zoom
21
+ export const moveLeftKeyboardShortcutId = 'jsdraw.tools.PanZoom.moveLeft';
22
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(moveLeftKeyboardShortcutId, ['ArrowLeft', 'KeyH', 'KeyA'], 'Pan left');
23
+ export const moveRightKeyboardShortcutId = 'jsdraw.tools.PanZoom.moveRight';
24
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(moveRightKeyboardShortcutId, ['ArrowRight', 'KeyL', 'KeyD'], 'Pan right');
25
+ export const moveUpKeyboardShortcutId = 'jsdraw.tools.PanZoom.moveUp';
26
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(moveUpKeyboardShortcutId, ['ArrowUp', 'KeyK', 'KeyQ'], 'Pan up');
27
+ export const moveDownKeyboardShortcutId = 'jsdraw.tools.PanZoom.moveDown';
28
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(moveDownKeyboardShortcutId, ['ArrowDown', 'KeyJ', 'KeyE'], 'Pan down');
29
+ export const rotateClockwiseKeyboardShortcutId = 'jsdraw.tools.PanZoom.rotateViewClockwise';
30
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(rotateClockwiseKeyboardShortcutId, ['Shift+KeyR'], 'Rotate viewport clockwise');
31
+ export const rotateCounterClockwiseKeyboardShortcutId = 'jsdraw.tools.PanZoom.rotateViewCounterClockwise';
32
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(rotateCounterClockwiseKeyboardShortcutId, ['KeyR'], 'Rotate viewport counter-clockwise');
33
+ export const zoomInKeyboardShortcutId = 'jsdraw.tools.PanZoom.zoomIn';
34
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(zoomInKeyboardShortcutId, ['KeyW'], 'Zoom in');
35
+ export const zoomOutKeyboardShortcutId = 'jsdraw.tools.PanZoom.zoomOut';
36
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(zoomOutKeyboardShortcutId, ['KeyS'], 'Zoom out');
37
+ // Selection tool
38
+ export * from './SelectionTool/keybindings.mjs';
@@ -0,0 +1,14 @@
1
+ export { default as BaseTool } from './BaseTool';
2
+ export { default as ToolController } from './ToolController';
3
+ export { default as ToolEnabledGroup } from './ToolEnabledGroup';
4
+ export { default as UndoRedoShortcut } from './UndoRedoShortcut';
5
+ export { default as ToolSwitcherShortcut } from './ToolSwitcherShortcut';
6
+ export { default as PanZoomTool, PanZoomMode } from './PanZoom';
7
+ export { default as PenTool, PenStyle } from './Pen';
8
+ export { default as TextTool } from './TextTool';
9
+ export { default as SelectionTool } from './SelectionTool/SelectionTool';
10
+ export { default as SelectAllShortcutHandler } from './SelectionTool/SelectAllShortcutHandler';
11
+ export { default as EraserTool, EraserMode } from './Eraser';
12
+ export { default as PasteHandler } from './PasteHandler';
13
+ export { default as SoundUITool } from './SoundUITool';
14
+ export { default as ToolbarShortcutHandler } from './ToolbarShortcutHandler';
@@ -0,0 +1,14 @@
1
+ export { default as BaseTool } from './BaseTool.mjs';
2
+ export { default as ToolController } from './ToolController.mjs';
3
+ export { default as ToolEnabledGroup } from './ToolEnabledGroup.mjs';
4
+ export { default as UndoRedoShortcut } from './UndoRedoShortcut.mjs';
5
+ export { default as ToolSwitcherShortcut } from './ToolSwitcherShortcut.mjs';
6
+ export { default as PanZoomTool, PanZoomMode } from './PanZoom.mjs';
7
+ export { default as PenTool } from './Pen.mjs';
8
+ export { default as TextTool } from './TextTool.mjs';
9
+ export { default as SelectionTool } from './SelectionTool/SelectionTool.mjs';
10
+ export { default as SelectAllShortcutHandler } from './SelectionTool/SelectAllShortcutHandler.mjs';
11
+ export { default as EraserTool, EraserMode } from './Eraser.mjs';
12
+ export { default as PasteHandler } from './PasteHandler.mjs';
13
+ export { default as SoundUITool } from './SoundUITool.mjs';
14
+ export { default as ToolbarShortcutHandler } from './ToolbarShortcutHandler.mjs';
@@ -0,0 +1,43 @@
1
+ export interface ToolLocalization {
2
+ keyboardPanZoom: string;
3
+ penTool: (penId: number) => string;
4
+ selectionTool: string;
5
+ selectAllTool: string;
6
+ eraserTool: string;
7
+ touchPanTool: string;
8
+ twoFingerPanZoomTool: string;
9
+ undoRedoTool: string;
10
+ pipetteTool: string;
11
+ rightClickDragPanTool: string;
12
+ autocorrectedTo: (description: string) => string;
13
+ autocorrectionCanceled: string;
14
+ textTool: string;
15
+ enterTextToInsert: string;
16
+ changeTool: string;
17
+ pasteHandler: string;
18
+ soundExplorer: string;
19
+ disableAccessibilityExploreTool: string;
20
+ enableAccessibilityExploreTool: string;
21
+ soundExplorerUsageAnnouncement: string;
22
+ findLabel: string;
23
+ toNextMatch: string;
24
+ closeDialog: string;
25
+ findDialogShown: string;
26
+ findDialogHidden: string;
27
+ focusedFoundText: (currentMatchNumber: number, totalMatches: number) => string;
28
+ anyDevicePanning: string;
29
+ selectionMenu__show: string;
30
+ selectionMenu__copyToClipboard: string;
31
+ selectionMenu__duplicate: string;
32
+ selectionMenu__delete: string;
33
+ selectionMenu__paste: string;
34
+ copied: (count: number) => string;
35
+ pasted: (count: number) => string;
36
+ copyPasteError__heading: string;
37
+ copyPasteError__description: string;
38
+ copyPasteError__pasteRetry: string;
39
+ copyPasteError__errorDetails: string;
40
+ toolEnabledAnnouncement: (toolName: string) => string;
41
+ toolDisabledAnnouncement: (toolName: string) => string;
42
+ }
43
+ export declare const defaultToolLocalization: ToolLocalization;
@@ -0,0 +1,42 @@
1
+ export const defaultToolLocalization = {
2
+ penTool: (penId) => `Pen ${penId}`,
3
+ selectionTool: 'Selection',
4
+ selectAllTool: 'Select all shortcut',
5
+ eraserTool: 'Eraser',
6
+ touchPanTool: 'Touch panning',
7
+ twoFingerPanZoomTool: 'Panning and zooming',
8
+ undoRedoTool: 'Undo/Redo',
9
+ rightClickDragPanTool: 'Right-click drag',
10
+ pipetteTool: 'Pick color from screen',
11
+ keyboardPanZoom: 'Keyboard pan/zoom shortcuts',
12
+ selectionMenu__show: 'Show selection menu',
13
+ selectionMenu__copyToClipboard: 'Copy to clipboard',
14
+ selectionMenu__duplicate: 'Duplicate',
15
+ selectionMenu__delete: 'Delete',
16
+ selectionMenu__paste: 'Paste',
17
+ copyPasteError__heading: 'Error!',
18
+ copyPasteError__description: 'Something went wrong — this tool may not have clipboard access.',
19
+ copyPasteError__errorDetails: 'Show error',
20
+ copyPasteError__pasteRetry: 'To retry, please paste into the input box below:',
21
+ autocorrectedTo: (strokeDescription) => `Autocorrected to ${strokeDescription}`,
22
+ autocorrectionCanceled: 'Autocorrect cancelled',
23
+ textTool: 'Text',
24
+ enterTextToInsert: 'Text to insert',
25
+ changeTool: 'Change tool',
26
+ pasteHandler: 'Copy paste handler',
27
+ soundExplorer: 'Sound-based image exploration',
28
+ disableAccessibilityExploreTool: 'Disable sound-based exploration',
29
+ enableAccessibilityExploreTool: 'Enable sound-based exploration',
30
+ soundExplorerUsageAnnouncement: 'Sound-based image exploration enabled: Click/drag the screen to play a sound representation of different parts of the image.',
31
+ findLabel: 'Find',
32
+ toNextMatch: 'Next',
33
+ closeDialog: 'Close',
34
+ findDialogShown: 'Find dialog shown',
35
+ findDialogHidden: 'Find dialog hidden',
36
+ focusedFoundText: (matchIdx, totalMatches) => `Viewing match ${matchIdx} of ${totalMatches}`,
37
+ anyDevicePanning: 'Any device panning',
38
+ copied: (count) => `Copied ${count} item(s)`,
39
+ pasted: (count) => `Pasted ${count} item(s)`,
40
+ toolEnabledAnnouncement: (toolName) => `${toolName} enabled`,
41
+ toolDisabledAnnouncement: (toolName) => `${toolName} disabled`,
42
+ };
@@ -0,0 +1,25 @@
1
+ import Pointer from '../../Pointer';
2
+ interface Config {
3
+ maxSpeed: number;
4
+ minTimeSeconds: number;
5
+ maxRadius: number;
6
+ }
7
+ export declare const defaultStationaryDetectionConfig: Config;
8
+ type OnStationaryCallback = (lastPointer: Pointer) => void;
9
+ export default class StationaryPenDetector {
10
+ private config;
11
+ private onStationary;
12
+ private stationaryStartPointer;
13
+ private lastPointer;
14
+ private averageVelocity;
15
+ private hasMovedOutOfRadius;
16
+ private timeout;
17
+ constructor(startPointer: Pointer, config: Config, onStationary: OnStationaryCallback);
18
+ onPointerMove(currentPointer: Pointer): boolean | undefined;
19
+ onPointerUp(pointer: Pointer): void;
20
+ destroy(): void;
21
+ getHasMovedOutOfRadius(): boolean;
22
+ private cancelStationaryTimeout;
23
+ private setStationaryTimeout;
24
+ }
25
+ export {};
@@ -0,0 +1,103 @@
1
+ import { Vec2 } from '@js-draw/math';
2
+ export const defaultStationaryDetectionConfig = {
3
+ maxSpeed: 8.5, // screenPx/s
4
+ maxRadius: 11, // screenPx
5
+ minTimeSeconds: 0.5, // s
6
+ };
7
+ export default class StationaryPenDetector {
8
+ // Only handles one pen. As such, `startPointer` should be the same device/finger
9
+ // as `updatedPointer` in `onPointerMove`.
10
+ //
11
+ // A new `StationaryPenDetector` should be created for each gesture.
12
+ constructor(startPointer, config, onStationary) {
13
+ this.config = config;
14
+ this.onStationary = onStationary;
15
+ this.timeout = null;
16
+ this.stationaryStartPointer = startPointer;
17
+ this.lastPointer = startPointer;
18
+ this.averageVelocity = Vec2.zero;
19
+ this.setStationaryTimeout(this.config.minTimeSeconds * 1000);
20
+ }
21
+ // Returns true if stationary
22
+ onPointerMove(currentPointer) {
23
+ if (!this.stationaryStartPointer) {
24
+ // Destoroyed
25
+ return;
26
+ }
27
+ if (currentPointer.id !== this.stationaryStartPointer.id) {
28
+ return false;
29
+ }
30
+ // dx: "Δx" Displacement from last.
31
+ const dxFromLast = currentPointer.screenPos.minus(this.lastPointer.screenPos);
32
+ const dxFromStationaryStart = currentPointer.screenPos.minus(this.stationaryStartPointer.screenPos);
33
+ // dt: Delta time:
34
+ // /1000: Convert to s.
35
+ let dtFromLast = (currentPointer.timeStamp - this.lastPointer.timeStamp) / 1000; // s
36
+ // Don't divide by zero
37
+ if (dtFromLast === 0) {
38
+ dtFromLast = 1;
39
+ }
40
+ const currentVelocity = dxFromLast.times(1 / dtFromLast); // px/s
41
+ // Slight smoothing of the velocity to prevent input jitter from affecting the
42
+ // velocity too significantly.
43
+ this.averageVelocity = this.averageVelocity.lerp(currentVelocity, 0.5); // px/s
44
+ const dtFromStart = currentPointer.timeStamp - this.stationaryStartPointer.timeStamp; // ms
45
+ const movedOutOfRadius = dxFromStationaryStart.length() > this.config.maxRadius;
46
+ this.hasMovedOutOfRadius ||= movedOutOfRadius;
47
+ // If not stationary
48
+ if (movedOutOfRadius
49
+ || this.averageVelocity.length() > this.config.maxSpeed
50
+ || dtFromStart < this.config.minTimeSeconds) {
51
+ this.stationaryStartPointer = currentPointer;
52
+ this.lastPointer = currentPointer;
53
+ this.setStationaryTimeout(this.config.minTimeSeconds * 1000);
54
+ return false;
55
+ }
56
+ const stationaryTimeoutMs = this.config.minTimeSeconds * 1000 - dtFromStart;
57
+ this.lastPointer = currentPointer;
58
+ return stationaryTimeoutMs <= 0;
59
+ }
60
+ onPointerUp(pointer) {
61
+ if (pointer.id !== this.stationaryStartPointer?.id) {
62
+ this.cancelStationaryTimeout();
63
+ }
64
+ }
65
+ destroy() {
66
+ this.cancelStationaryTimeout();
67
+ this.stationaryStartPointer = null;
68
+ }
69
+ getHasMovedOutOfRadius() {
70
+ return this.hasMovedOutOfRadius;
71
+ }
72
+ cancelStationaryTimeout() {
73
+ if (this.timeout !== null) {
74
+ clearTimeout(this.timeout);
75
+ this.timeout = null;
76
+ }
77
+ }
78
+ setStationaryTimeout(timeoutMs) {
79
+ if (this.timeout !== null) {
80
+ return;
81
+ }
82
+ if (timeoutMs <= 0) {
83
+ this.onStationary(this.lastPointer);
84
+ }
85
+ else {
86
+ this.timeout = setTimeout(() => {
87
+ this.timeout = null;
88
+ if (!this.stationaryStartPointer) {
89
+ // Destroyed
90
+ return;
91
+ }
92
+ const timeSinceStationaryStart = performance.now() - this.stationaryStartPointer.timeStamp;
93
+ const timeRemaining = this.config.minTimeSeconds * 1000 - timeSinceStationaryStart;
94
+ if (timeRemaining <= 0) {
95
+ this.onStationary(this.lastPointer);
96
+ }
97
+ else {
98
+ this.setStationaryTimeout(timeRemaining);
99
+ }
100
+ }, timeoutMs);
101
+ }
102
+ }
103
+ }
@@ -0,0 +1,10 @@
1
+ import Editor from '../../Editor';
2
+ import { IconElemType } from '../../toolbar/IconProvider';
3
+ import { Point2 } from '@js-draw/math';
4
+ interface MenuOption<KeyType> {
5
+ key: KeyType;
6
+ text: string;
7
+ icon: () => IconElemType;
8
+ }
9
+ declare const createMenuOverlay: <KeyType>(editor: Editor, canvasAnchor: Point2, options: MenuOption<KeyType>[]) => Promise<KeyType | null>;
10
+ export default createMenuOverlay;
@@ -0,0 +1,121 @@
1
+ import waitForTimeout from '../../util/waitForTimeout.mjs';
2
+ import { EditorEventType } from '../../types.mjs';
3
+ let idCounter = 0;
4
+ const createMenuOverlay = async (editor, canvasAnchor, options) => {
5
+ const overlay = document.createElement('div');
6
+ const { remove: removeOverlay } = editor.createHTMLOverlay(overlay);
7
+ const menuModal = document.createElement('dialog');
8
+ menuModal.classList.add('editor-popup-menu');
9
+ const hideMenuTimeout = 240;
10
+ menuModal.style.setProperty('--hide-menu-animation-timeout', `${hideMenuTimeout}ms`);
11
+ const updateMenuLocation = () => {
12
+ const overlayRect = editor.getOutputBBoxInDOM();
13
+ const anchor = editor.viewport.canvasToScreen(canvasAnchor).plus(overlayRect.topLeft);
14
+ menuModal.style.setProperty('--anchor-x', `${anchor.x}px`);
15
+ menuModal.style.setProperty('--anchor-y', `${anchor.y}px`);
16
+ };
17
+ updateMenuLocation();
18
+ const viewportChangeListener = editor.notifier.on(EditorEventType.ViewportChanged, updateMenuLocation);
19
+ overlay.appendChild(menuModal);
20
+ let dismissing = false;
21
+ const dismissMenu = async () => {
22
+ if (dismissing)
23
+ return;
24
+ dismissing = true;
25
+ viewportChangeListener.remove();
26
+ menuModal.classList.add('-hide');
27
+ await waitForTimeout(hideMenuTimeout);
28
+ menuModal.close();
29
+ };
30
+ return new Promise(resolve => {
31
+ let resolved = false;
32
+ let result = null;
33
+ const resolveWithSelectedResult = () => {
34
+ if (!resolved) {
35
+ resolve(result);
36
+ resolved = true;
37
+ }
38
+ };
39
+ menuModal.onclose = () => {
40
+ removeOverlay();
41
+ resolveWithSelectedResult();
42
+ };
43
+ const onOptionSelected = (key) => {
44
+ result = key;
45
+ void dismissMenu();
46
+ // To properly handle clipboard events, this needs to be called synchronously
47
+ // and not after a delay:
48
+ resolveWithSelectedResult();
49
+ };
50
+ editor.handlePointerEventsExceptClicksFrom(menuModal, (eventName, event) => {
51
+ if (event.target === menuModal && eventName === 'pointerdown') {
52
+ void dismissMenu();
53
+ return true;
54
+ }
55
+ else if (dismissing) {
56
+ // Send pointer events to the editor if the dialog is in the process of being
57
+ // dismissed (e.g. pointermove events just after a pointerdown outside of the
58
+ // editor).
59
+ return true;
60
+ }
61
+ return false;
62
+ }, (_eventName, event) => {
63
+ return event.target === menuModal;
64
+ });
65
+ const contentElement = document.createElement('div');
66
+ contentElement.classList.add('content');
67
+ contentElement.role = 'menu';
68
+ const optionElements = [];
69
+ // Keyboard focus handling as described in
70
+ // - https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menu_role and
71
+ // - https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/examples/disclosure-navigation/
72
+ contentElement.addEventListener('keydown', (event) => {
73
+ const focusedIndex = optionElements.findIndex(item => item === document.activeElement);
74
+ if (focusedIndex === -1)
75
+ return;
76
+ let newFocusedIndex = focusedIndex;
77
+ if (event.key === 'ArrowDown') {
78
+ newFocusedIndex++;
79
+ }
80
+ else if (event.key === 'ArrowUp') {
81
+ newFocusedIndex--;
82
+ }
83
+ else if (event.key === 'End') {
84
+ newFocusedIndex = optionElements.length - 1;
85
+ }
86
+ else if (event.key === 'Home') {
87
+ newFocusedIndex = 0;
88
+ }
89
+ if (newFocusedIndex < 0) {
90
+ newFocusedIndex += optionElements.length;
91
+ }
92
+ newFocusedIndex %= optionElements.length;
93
+ if (newFocusedIndex !== focusedIndex) {
94
+ event.preventDefault();
95
+ optionElements[newFocusedIndex].focus();
96
+ }
97
+ });
98
+ for (const option of options) {
99
+ const optionElement = document.createElement('button');
100
+ optionElement.id = `menu-overlay-option-${idCounter++}`;
101
+ optionElement.role = 'menuitem';
102
+ optionElement.classList.add('option', 'editor-popup-menu-option');
103
+ optionElement.replaceChildren(option.icon(), document.createTextNode(option.text));
104
+ optionElement.onclick = (event) => {
105
+ if (event.defaultPrevented)
106
+ return;
107
+ onOptionSelected(option.key);
108
+ };
109
+ contentElement.appendChild(optionElement);
110
+ if (optionElements.length === 0) {
111
+ optionElement.autofocus = true;
112
+ }
113
+ optionElements.push(optionElement);
114
+ }
115
+ menuModal.appendChild(contentElement);
116
+ menuModal.showModal();
117
+ // Ensures that the menu is visible even if triggered near the edge of the screen.
118
+ contentElement.scrollIntoView({ block: 'nearest' });
119
+ });
120
+ };
121
+ export default createMenuOverlay;
@@ -0,0 +1 @@
1
+ export {};
@@ -4,5 +4,5 @@
4
4
  * @internal
5
5
  */
6
6
  export default {
7
- number: '1.21.2',
7
+ number: '1.21.3',
8
8
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "1.21.2",
3
+ "version": "1.21.3",
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.21.2",
67
+ "@js-draw/math": "^1.21.3",
68
68
  "@melloware/coloris": "0.22.0"
69
69
  },
70
70
  "devDependencies": {
71
- "@js-draw/build-tool": "^1.21.2",
71
+ "@js-draw/build-tool": "^1.21.3",
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": "f29b0658121b39fab5d20599003917363290bf6f"
89
+ "gitHead": "2b11a1efafeeb3b84effb7d849343d273df371f8"
90
90
  }
@@ -0,0 +1,7 @@
1
+
2
+ .find-tool-overlay {
3
+ /* Show at the bottom of the screen. */
4
+ order: -1;
5
+
6
+ position: absolute;
7
+ }
@@ -0,0 +1,57 @@
1
+
2
+ .ScrollbarTool-overlay {
3
+ width: 0;
4
+ height: 0;
5
+ overflow: visible;
6
+
7
+ $visible-opacity: 0.2;
8
+ opacity: $visible-opacity;
9
+ pointer-events: none;
10
+
11
+ --fade-out-animation: 1s ease 0s fade-out;
12
+
13
+ @media (prefers-reduced-motion: reduce) {
14
+ --fade-out-animation: none !important;
15
+ }
16
+
17
+ @keyframes fade-out {
18
+ from { opacity: $visible-opacity; }
19
+ to { opacity: 0; }
20
+ }
21
+
22
+ &:not(.just-updated) {
23
+ animation: var(--fade-out-animation);
24
+ opacity: 0;
25
+ }
26
+
27
+ --scrollbar-size: 3px;
28
+
29
+ .vertical-scrollbar, .horizontal-scrollbar {
30
+ width: var(--scrollbar-size);
31
+ height: var(--scrollbar-size);
32
+
33
+ min-width: var(--scrollbar-size);
34
+ min-height: var(--scrollbar-size);
35
+
36
+ background-color: var(--foreground-color-1);
37
+ border-radius: var(--scrollbar-size);
38
+ position: absolute;
39
+
40
+ &.represents-no-scroll {
41
+ animation: var(--fade-out-animation);
42
+ opacity: 0;
43
+ }
44
+ }
45
+
46
+ &:not(.scrollbar-left) {
47
+ .vertical-scrollbar {
48
+ margin-left: calc(var(--editor-current-display-width-px) - var(--scrollbar-size));
49
+ }
50
+ }
51
+
52
+ &:not(.scrollbar-top) {
53
+ .horizontal-scrollbar {
54
+ margin-top: calc(var(--editor-current-display-height-px) - var(--scrollbar-size));
55
+ }
56
+ }
57
+ }