js-draw 1.11.0 → 1.11.1

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 (40) hide show
  1. package/dist/Editor.css +6 -2
  2. package/dist/bundle.js +3 -3
  3. package/dist/bundledStyles.js +1 -1
  4. package/dist/cjs/Editor.d.ts +7 -0
  5. package/dist/cjs/Editor.js +18 -4
  6. package/dist/cjs/components/BackgroundComponent.d.ts +1 -1
  7. package/dist/cjs/components/ImageComponent.d.ts +1 -1
  8. package/dist/cjs/components/SVGGlobalAttributesObject.d.ts +1 -1
  9. package/dist/cjs/components/Stroke.d.ts +1 -1
  10. package/dist/cjs/rendering/Display.js +3 -1
  11. package/dist/cjs/rendering/renderers/DummyRenderer.d.ts +1 -0
  12. package/dist/cjs/rendering/renderers/DummyRenderer.js +3 -0
  13. package/dist/cjs/tools/FindTool.js +1 -1
  14. package/dist/cjs/tools/Pen.js +8 -2
  15. package/dist/cjs/tools/SelectionTool/SelectionTool.js +16 -2
  16. package/dist/cjs/tools/localization.d.ts +2 -0
  17. package/dist/cjs/tools/localization.js +2 -0
  18. package/dist/cjs/util/listenForKeyboardEventsFrom.d.ts +5 -0
  19. package/dist/cjs/util/listenForKeyboardEventsFrom.js +5 -1
  20. package/dist/cjs/version.js +1 -1
  21. package/dist/mjs/Editor.d.ts +7 -0
  22. package/dist/mjs/Editor.mjs +18 -4
  23. package/dist/mjs/components/BackgroundComponent.d.ts +1 -1
  24. package/dist/mjs/components/ImageComponent.d.ts +1 -1
  25. package/dist/mjs/components/SVGGlobalAttributesObject.d.ts +1 -1
  26. package/dist/mjs/components/Stroke.d.ts +1 -1
  27. package/dist/mjs/rendering/Display.mjs +3 -1
  28. package/dist/mjs/rendering/renderers/DummyRenderer.d.ts +1 -0
  29. package/dist/mjs/rendering/renderers/DummyRenderer.mjs +3 -0
  30. package/dist/mjs/tools/FindTool.mjs +1 -1
  31. package/dist/mjs/tools/Pen.mjs +8 -2
  32. package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +16 -2
  33. package/dist/mjs/tools/localization.d.ts +2 -0
  34. package/dist/mjs/tools/localization.mjs +2 -0
  35. package/dist/mjs/util/listenForKeyboardEventsFrom.d.ts +5 -0
  36. package/dist/mjs/util/listenForKeyboardEventsFrom.mjs +5 -1
  37. package/dist/mjs/version.mjs +1 -1
  38. package/package.json +5 -5
  39. package/src/toolbar/AbstractToolbar.scss +3 -2
  40. package/src/toolbar/widgets/components/makeColorInput.scss +8 -0
@@ -70,7 +70,9 @@ export default class Display {
70
70
  },
71
71
  blockResolution: cacheBlockResolution,
72
72
  cacheSize: 600 * 600 * 4 * 90,
73
- maxScale: 1.3,
73
+ // On higher resolution displays, don't scale cache blocks as much to decrease blurriness.
74
+ // TODO: Decrease the minimum cache scale as well.
75
+ maxScale: Math.max(1, 1.3 / window.devicePixelRatio),
74
76
  // Require about 20 strokes with 4 parts each to cache an image in one of the
75
77
  // parts of the cache grid.
76
78
  minProportionalRenderTimePerCache: 20 * 4,
@@ -29,4 +29,5 @@ export default class DummyRenderer extends AbstractRenderer {
29
29
  isTooSmallToRender(_rect: Rect2): boolean;
30
30
  canRenderFromWithoutDataLoss(other: AbstractRenderer): boolean;
31
31
  renderFromOtherOfSameType(transform: Mat33, other: AbstractRenderer): void;
32
+ toString(): string;
32
33
  }
@@ -103,4 +103,7 @@ export default class DummyRenderer extends AbstractRenderer {
103
103
  return transform.transformVec2(point);
104
104
  }));
105
105
  }
106
+ toString() {
107
+ return '[DummyRenderer]';
108
+ }
106
109
  }
@@ -34,7 +34,7 @@ export default class FindTool extends BaseTool {
34
34
  }
35
35
  if (matchIdx < matches.length) {
36
36
  const undoable = false;
37
- this.editor.dispatch(this.editor.viewport.zoomTo(matches[matchIdx], true, true), undoable);
37
+ void this.editor.dispatch(this.editor.viewport.zoomTo(matches[matchIdx], true, true), undoable);
38
38
  this.editor.announceForAccessibility(this.editor.localization.focusedFoundText(matchIdx + 1, matches.length));
39
39
  }
40
40
  }
@@ -97,8 +97,8 @@ export default class Pen extends BaseTool {
97
97
  this.currentDeviceType = current.device;
98
98
  if (this.shapeAutocompletionEnabled) {
99
99
  const stationaryDetectionConfig = {
100
- maxSpeed: 5,
101
- maxRadius: 10,
100
+ maxSpeed: 8.5,
101
+ maxRadius: 11,
102
102
  minTimeSeconds: 0.5, // s
103
103
  };
104
104
  this.stationaryDetector = new StationaryPenDetector(current, stationaryDetectionConfig, pointer => this.autocorrectShape(pointer));
@@ -141,6 +141,7 @@ export default class Pen extends BaseTool {
141
141
  if (this.autocorrectedShape) {
142
142
  this.removedAutocorrectedShapeTime = performance.now();
143
143
  this.autocorrectedShape = null;
144
+ this.editor.announceForAccessibility(this.editor.localization.autocorrectionCanceled);
144
145
  }
145
146
  }
146
147
  }
@@ -192,6 +193,8 @@ export default class Pen extends BaseTool {
192
193
  if (bboxArea === 0 || !isFinite(bboxArea)) {
193
194
  return;
194
195
  }
196
+ const shapeDescription = correctedShape.description(this.editor.localization);
197
+ this.editor.announceForAccessibility(this.editor.localization.autocorrectedTo(shapeDescription));
195
198
  this.autocorrectedShape = correctedShape;
196
199
  this.lastAutocorrectedShape = correctedShape;
197
200
  this.previewStroke();
@@ -206,6 +209,9 @@ export default class Pen extends BaseTool {
206
209
  const stroke = this.autocorrectedShape ?? this.builder.build();
207
210
  this.previewStroke();
208
211
  if (stroke.getBBox().area > 0) {
212
+ if (stroke === this.autocorrectedShape) {
213
+ this.editor.announceForAccessibility(this.editor.localization.autocorrectedTo(stroke.description(this.editor.localization)));
214
+ }
209
215
  const canFlatten = true;
210
216
  const action = EditorImage.addElement(stroke, canFlatten);
211
217
  this.editor.dispatch(action);
@@ -231,9 +231,11 @@ class SelectionTool extends BaseTool {
231
231
  // Pass it to another tool, if apliccable.
232
232
  return false;
233
233
  }
234
- else if (event.key === 'Shift') {
234
+ else if (event.shiftKey || event.key === 'Shift') {
235
235
  this.shiftKeyPressed = true;
236
- return true;
236
+ if (event.key === 'Shift') {
237
+ return true;
238
+ }
237
239
  }
238
240
  let rotationSteps = 0;
239
241
  let xTranslateSteps = 0;
@@ -335,6 +337,14 @@ class SelectionTool extends BaseTool {
335
337
  }
336
338
  return true;
337
339
  }
340
+ // Here, we check if shiftKey === false because, as of this writing,
341
+ // evt.shiftKey is an optional property. Being falsey could just mean
342
+ // that it wasn't set.
343
+ if (evt.shiftKey === false) {
344
+ this.shiftKeyPressed = false;
345
+ // Don't return immediately -- event may be otherwise handled
346
+ }
347
+ // Also check for key === 'Shift' (for the case where shiftKey is undefined)
338
348
  if (evt.key === 'Shift') {
339
349
  this.shiftKeyPressed = false;
340
350
  return true;
@@ -379,7 +389,11 @@ class SelectionTool extends BaseTool {
379
389
  return true;
380
390
  }
381
391
  setEnabled(enabled) {
392
+ const wasEnabled = this.isEnabled();
382
393
  super.setEnabled(enabled);
394
+ if (wasEnabled === enabled) {
395
+ return;
396
+ }
383
397
  // Clear the selection
384
398
  this.selectionBox?.cancelSelection();
385
399
  this.onSelectionUpdated();
@@ -9,6 +9,8 @@ export interface ToolLocalization {
9
9
  undoRedoTool: string;
10
10
  pipetteTool: string;
11
11
  rightClickDragPanTool: string;
12
+ autocorrectedTo: (description: string) => string;
13
+ autocorrectionCanceled: string;
12
14
  textTool: string;
13
15
  enterTextToInsert: string;
14
16
  changeTool: string;
@@ -9,6 +9,8 @@ export const defaultToolLocalization = {
9
9
  rightClickDragPanTool: 'Right-click drag',
10
10
  pipetteTool: 'Pick color from screen',
11
11
  keyboardPanZoom: 'Keyboard pan/zoom shortcuts',
12
+ autocorrectedTo: (strokeDescription) => `Autocorrected to ${strokeDescription}`,
13
+ autocorrectionCanceled: 'Autocorrect cancelled',
12
14
  textTool: 'Text',
13
15
  enterTextToInsert: 'Text to insert',
14
16
  changeTool: 'Change tool',
@@ -2,6 +2,11 @@ interface Callbacks {
2
2
  filter(event: KeyboardEvent): boolean;
3
3
  handleKeyDown(event: KeyboardEvent): void;
4
4
  handleKeyUp(event: KeyboardEvent): void;
5
+ /**
6
+ * Should return `true` iff `source` is also registered as an event listener source.
7
+ * If `false` and focus leaves the original source, keyup events are fired.
8
+ */
9
+ getHandlesKeyEventsFrom(source: Node): boolean;
5
10
  }
6
11
  /**
7
12
  * Calls `callbacks` when different keys are known to be pressed.
@@ -65,7 +65,11 @@ const listenForKeyboardEventsFrom = (elem, callbacks) => {
65
65
  handleKeyEvent(htmlEvent);
66
66
  });
67
67
  elem.addEventListener('focusout', (focusEvent) => {
68
- const stillHasFocus = focusEvent.relatedTarget && elem.contains(focusEvent.relatedTarget);
68
+ let stillHasFocus = false;
69
+ if (focusEvent.relatedTarget) {
70
+ const relatedTarget = focusEvent.relatedTarget;
71
+ stillHasFocus = elem.contains(relatedTarget) || callbacks.getHandlesKeyEventsFrom(relatedTarget);
72
+ }
69
73
  if (!stillHasFocus) {
70
74
  for (const event of keysDown) {
71
75
  callbacks.handleKeyUp(new KeyboardEvent('keyup', {
@@ -1,3 +1,3 @@
1
1
  export default {
2
- number: '1.11.0',
2
+ number: '1.11.1',
3
3
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
5
5
  "types": "./dist/mjs/lib.d.ts",
6
6
  "main": "./dist/cjs/lib.js",
@@ -64,11 +64,11 @@
64
64
  "postpack": "ts-node tools/copyREADME.ts revert"
65
65
  },
66
66
  "dependencies": {
67
- "@js-draw/math": "^1.10.0",
68
- "@melloware/coloris": "0.21.0"
67
+ "@js-draw/math": "^1.11.1",
68
+ "@melloware/coloris": "0.22.0"
69
69
  },
70
70
  "devDependencies": {
71
- "@js-draw/build-tool": "^1.7.0",
71
+ "@js-draw/build-tool": "^1.11.1",
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": "01fc3dc7bdbc9f456705bf08d9c30b4549122d97"
89
+ "gitHead": "695cfe01116839842668233a14fa858ad4ae0bac"
90
90
  }
@@ -45,7 +45,8 @@
45
45
  }
46
46
 
47
47
  .toolbar-button.disabled {
48
- filter: opacity(0.5) sepia(0.2);
48
+ filter: sepia(0.2);
49
+ opacity: 0.45;
49
50
  cursor: unset;
50
51
  }
51
52
 
@@ -103,7 +104,7 @@
103
104
 
104
105
  .toolbar-root button:disabled {
105
106
  cursor: inherit;
106
- filter: opacity(0.5);
107
+ opacity: 0.5;
107
108
  }
108
109
 
109
110
  .toolbar-root .toolbar-icon {
@@ -29,6 +29,14 @@
29
29
  display: inline-flex;
30
30
  flex-direction: row;
31
31
 
32
+ .coloris_input {
33
+ // Ensure that the region that can be clicked to open the input is roughly
34
+ // the full height of the container.
35
+ // Because the color picker is always shown below or above the input, 5px is
36
+ // subtracted to make the picker better align with the input's container.
37
+ height: calc(100% - 6px);
38
+ }
39
+
32
40
  &.picker-open .clr-field {
33
41
  // Work around what seems to be a Coloris bug -- clicking on the input button
34
42
  // keeps the color picker open (while clicking anywhere else closes the picker).