js-draw 1.14.0 → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. package/dist/Editor.css +288 -1
  2. package/dist/bundle.js +2 -2
  3. package/dist/bundledStyles.js +1 -1
  4. package/dist/cjs/Editor.js +5 -0
  5. package/dist/cjs/components/util/StrokeSmoother.js +11 -4
  6. package/dist/cjs/rendering/caching/CacheRecordManager.js +1 -1
  7. package/dist/cjs/rendering/renderers/CanvasRenderer.js +1 -1
  8. package/dist/cjs/testing/sendHtmlSwipe.d.ts +4 -0
  9. package/dist/cjs/testing/sendHtmlSwipe.js +14 -0
  10. package/dist/cjs/toolbar/EdgeToolbar.d.ts +1 -0
  11. package/dist/cjs/toolbar/EdgeToolbar.js +30 -110
  12. package/dist/cjs/toolbar/IconProvider.d.ts +1 -0
  13. package/dist/cjs/toolbar/IconProvider.js +27 -0
  14. package/dist/cjs/toolbar/localization.d.ts +28 -1
  15. package/dist/cjs/toolbar/localization.js +30 -1
  16. package/dist/cjs/toolbar/utils/HelpDisplay.d.ts +37 -0
  17. package/dist/cjs/toolbar/utils/HelpDisplay.js +442 -0
  18. package/dist/cjs/toolbar/utils/HelpDisplay.test.d.ts +1 -0
  19. package/dist/cjs/toolbar/utils/localization.d.ts +9 -0
  20. package/dist/cjs/toolbar/utils/localization.js +11 -0
  21. package/dist/cjs/toolbar/utils/makeDraggable.d.ts +16 -0
  22. package/dist/cjs/toolbar/utils/makeDraggable.js +130 -0
  23. package/dist/cjs/toolbar/widgets/ActionButtonWidget.d.ts +7 -0
  24. package/dist/cjs/toolbar/widgets/ActionButtonWidget.js +14 -2
  25. package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +8 -1
  26. package/dist/cjs/toolbar/widgets/BaseWidget.js +25 -3
  27. package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.d.ts +3 -1
  28. package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +19 -4
  29. package/dist/cjs/toolbar/widgets/HandToolWidget.d.ts +3 -1
  30. package/dist/cjs/toolbar/widgets/HandToolWidget.js +19 -7
  31. package/dist/cjs/toolbar/widgets/InsertImageWidget.js +1 -0
  32. package/dist/cjs/toolbar/widgets/PenToolWidget.d.ts +4 -2
  33. package/dist/cjs/toolbar/widgets/PenToolWidget.js +27 -8
  34. package/dist/cjs/toolbar/widgets/SelectionToolWidget.d.ts +3 -1
  35. package/dist/cjs/toolbar/widgets/SelectionToolWidget.js +19 -5
  36. package/dist/cjs/toolbar/widgets/components/makeColorInput.d.ts +2 -0
  37. package/dist/cjs/toolbar/widgets/components/makeColorInput.js +17 -7
  38. package/dist/cjs/toolbar/widgets/components/makeGridSelector.d.ts +6 -0
  39. package/dist/cjs/toolbar/widgets/components/makeGridSelector.js +3 -0
  40. package/dist/cjs/tools/FindTool.js +18 -5
  41. package/dist/cjs/tools/PanZoom.d.ts +8 -2
  42. package/dist/cjs/tools/PanZoom.js +29 -10
  43. package/dist/cjs/tools/SelectionTool/Selection.js +16 -2
  44. package/dist/cjs/util/addLongPressOrHoverCssClasses.d.ts +3 -1
  45. package/dist/cjs/util/addLongPressOrHoverCssClasses.js +2 -1
  46. package/dist/cjs/util/cloneElementWithStyles.d.ts +6 -0
  47. package/dist/cjs/util/cloneElementWithStyles.js +32 -0
  48. package/dist/cjs/version.js +1 -1
  49. package/dist/mjs/Editor.mjs +5 -0
  50. package/dist/mjs/components/util/StrokeSmoother.mjs +11 -4
  51. package/dist/mjs/rendering/caching/CacheRecordManager.mjs +1 -1
  52. package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +1 -1
  53. package/dist/mjs/testing/sendHtmlSwipe.d.ts +4 -0
  54. package/dist/mjs/testing/sendHtmlSwipe.mjs +12 -0
  55. package/dist/mjs/toolbar/EdgeToolbar.d.ts +1 -0
  56. package/dist/mjs/toolbar/EdgeToolbar.mjs +30 -110
  57. package/dist/mjs/toolbar/IconProvider.d.ts +1 -0
  58. package/dist/mjs/toolbar/IconProvider.mjs +27 -0
  59. package/dist/mjs/toolbar/localization.d.ts +28 -1
  60. package/dist/mjs/toolbar/localization.mjs +30 -1
  61. package/dist/mjs/toolbar/utils/HelpDisplay.d.ts +37 -0
  62. package/dist/mjs/toolbar/utils/HelpDisplay.mjs +437 -0
  63. package/dist/mjs/toolbar/utils/HelpDisplay.test.d.ts +1 -0
  64. package/dist/mjs/toolbar/utils/localization.d.ts +9 -0
  65. package/dist/mjs/toolbar/utils/localization.mjs +8 -0
  66. package/dist/mjs/toolbar/utils/makeDraggable.d.ts +16 -0
  67. package/dist/mjs/toolbar/utils/makeDraggable.mjs +128 -0
  68. package/dist/mjs/toolbar/widgets/ActionButtonWidget.d.ts +7 -0
  69. package/dist/mjs/toolbar/widgets/ActionButtonWidget.mjs +14 -2
  70. package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +8 -1
  71. package/dist/mjs/toolbar/widgets/BaseWidget.mjs +25 -3
  72. package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.d.ts +3 -1
  73. package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +19 -4
  74. package/dist/mjs/toolbar/widgets/HandToolWidget.d.ts +3 -1
  75. package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +19 -7
  76. package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +1 -0
  77. package/dist/mjs/toolbar/widgets/PenToolWidget.d.ts +4 -2
  78. package/dist/mjs/toolbar/widgets/PenToolWidget.mjs +27 -8
  79. package/dist/mjs/toolbar/widgets/SelectionToolWidget.d.ts +3 -1
  80. package/dist/mjs/toolbar/widgets/SelectionToolWidget.mjs +19 -5
  81. package/dist/mjs/toolbar/widgets/components/makeColorInput.d.ts +2 -0
  82. package/dist/mjs/toolbar/widgets/components/makeColorInput.mjs +17 -7
  83. package/dist/mjs/toolbar/widgets/components/makeGridSelector.d.ts +6 -0
  84. package/dist/mjs/toolbar/widgets/components/makeGridSelector.mjs +3 -0
  85. package/dist/mjs/tools/FindTool.mjs +18 -5
  86. package/dist/mjs/tools/PanZoom.d.ts +8 -2
  87. package/dist/mjs/tools/PanZoom.mjs +29 -10
  88. package/dist/mjs/tools/SelectionTool/Selection.mjs +16 -2
  89. package/dist/mjs/util/addLongPressOrHoverCssClasses.d.ts +3 -1
  90. package/dist/mjs/util/addLongPressOrHoverCssClasses.mjs +2 -1
  91. package/dist/mjs/util/cloneElementWithStyles.d.ts +6 -0
  92. package/dist/mjs/util/cloneElementWithStyles.mjs +30 -0
  93. package/dist/mjs/version.mjs +1 -1
  94. package/package.json +3 -3
  95. package/src/toolbar/EdgeToolbar.scss +23 -2
  96. package/src/toolbar/toolbar.scss +2 -0
  97. package/src/toolbar/utils/HelpDisplay.scss +315 -0
  98. package/src/toolbar/widgets/components/makeColorInput.scss +7 -0
  99. package/src/tools/SelectionTool/SelectionTool.scss +4 -0
@@ -71,9 +71,11 @@ export default class PanZoom extends BaseTool {
71
71
  this.initialRotationSnapAngle = 0.22; // radians
72
72
  this.afterRotationStartSnapAngle = 0.07; // radians
73
73
  this.pinchZoomStartThreshold = 1.08; // scale factor
74
+ // Last timestamp at which a pointerdown event was received
74
75
  this.lastPointerDownTimestamp = 0;
75
76
  this.initialTouchAngle = 0;
76
77
  this.initialViewportRotation = 0;
78
+ this.initialViewportScale = 0;
77
79
  // Set to `true` only when scaling has started (if two fingers are down and have moved
78
80
  // far enough).
79
81
  this.isScaling = false;
@@ -113,11 +115,12 @@ export default class PanZoom extends BaseTool {
113
115
  const isRightClick = this.allPointersAreOfType(pointers, PointerDevice.RightButtonMouse);
114
116
  if (allAreTouch && pointers.length === 2 && this.mode & PanZoomMode.TwoFingerTouchGestures) {
115
117
  const { screenCenter, angle, dist } = this.computePinchData(pointers[0], pointers[1]);
116
- this.lastDist = dist;
117
- this.startDist = dist;
118
+ this.lastTouchDist = dist;
119
+ this.startTouchDist = dist;
118
120
  this.lastScreenCenter = screenCenter;
119
121
  this.initialTouchAngle = angle;
120
122
  this.initialViewportRotation = this.editor.viewport.getRotationAngle();
123
+ this.initialViewportScale = this.editor.viewport.getScaleFactor();
121
124
  this.isScaling = false;
122
125
  // We're initially rotated if `initialViewportRotation` isn't near a multiple of pi/2.
123
126
  // In other words, if sin(2 initialViewportRotation) is near zero.
@@ -193,6 +196,22 @@ export default class PanZoom extends BaseTool {
193
196
  }
194
197
  return fullRotation - this.editor.viewport.getRotationAngle();
195
198
  }
199
+ /**
200
+ * Given a scale update, `scaleFactor`, returns a new scale factor snapped
201
+ * to a power of two (if within some tolerance of that scale).
202
+ */
203
+ toSnappedScaleFactor(touchDist) {
204
+ // scaleFactor is applied to the current transformation of the viewport.
205
+ const newScale = this.initialViewportScale * touchDist / this.startTouchDist;
206
+ const currentScale = this.editor.viewport.getScaleFactor();
207
+ const logNewScale = Math.log(newScale) / Math.log(10);
208
+ const roundedLogNewScale = Math.round(logNewScale);
209
+ const logTolerance = 0.04;
210
+ if (Math.abs(roundedLogNewScale - logNewScale) < logTolerance) {
211
+ return Math.pow(10, roundedLogNewScale) / currentScale;
212
+ }
213
+ return touchDist / this.lastTouchDist;
214
+ }
196
215
  handleTwoFingerMove(allPointers) {
197
216
  const { screenCenter, canvasCenter, angle, dist } = this.computePinchData(allPointers[0], allPointers[1]);
198
217
  const delta = this.getCenterDelta(screenCenter);
@@ -209,25 +228,25 @@ export default class PanZoom extends BaseTool {
209
228
  this.isRotating = true;
210
229
  }
211
230
  this.updateVelocity(screenCenter);
212
- let scaleFactor = 1;
213
- if (this.isScaling) {
214
- scaleFactor = dist / this.lastDist;
215
- }
216
- else {
217
- const initialScaleFactor = dist / this.startDist;
231
+ if (!this.isScaling) {
232
+ const initialScaleFactor = dist / this.startTouchDist;
218
233
  // Only start scaling if scaling done so far exceeds some threshold.
219
234
  const upperBound = this.pinchZoomStartThreshold;
220
235
  const lowerBound = 1 / this.pinchZoomStartThreshold;
221
236
  if (initialScaleFactor > upperBound || initialScaleFactor < lowerBound) {
222
- scaleFactor = initialScaleFactor;
223
237
  this.isScaling = true;
224
238
  }
225
239
  }
240
+ let scaleFactor = 1;
241
+ if (this.isScaling) {
242
+ scaleFactor = this.toSnappedScaleFactor(dist);
243
+ // Don't set lastDist until we start scaling --
244
+ this.lastTouchDist = dist;
245
+ }
226
246
  const transformUpdate = Mat33.translation(delta)
227
247
  .rightMul(Mat33.scaling2D(scaleFactor, canvasCenter))
228
248
  .rightMul(Mat33.zRotation(deltaRotation, canvasCenter));
229
249
  this.lastScreenCenter = screenCenter;
230
- this.lastDist = dist;
231
250
  this.transform = Viewport.transformBy(this.transform.transform.rightMul(transformUpdate));
232
251
  return transformUpdate;
233
252
  }
@@ -80,6 +80,7 @@ class Selection {
80
80
  for (const handle of this.handles) {
81
81
  handle.addTo(this.backgroundElem);
82
82
  }
83
+ this.updateUI();
83
84
  }
84
85
  // @internal Intended for unit tests
85
86
  getBackgroundElem() {
@@ -285,6 +286,13 @@ class Selection {
285
286
  else {
286
287
  this.innerContainer.classList.remove(perpendicularClassName);
287
288
  }
289
+ // Hide handles when empty
290
+ if (screenRegion.width === 0 && screenRegion.height === 0) {
291
+ this.innerContainer.classList.add('-empty');
292
+ }
293
+ else {
294
+ this.innerContainer.classList.remove('-empty');
295
+ }
288
296
  for (const handle of this.handles) {
289
297
  handle.updatePosition();
290
298
  }
@@ -533,7 +541,11 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
533
541
  this.transformCommands = this.selectedElemIds.map(id => {
534
542
  const elem = editor.image.lookupElement(id);
535
543
  if (!elem) {
536
- throw new Error(`Unable to find element with ID, ${id}.`);
544
+ // There may be valid reasons for an element lookup to fail:
545
+ // For example, if the element was deleted remotely and the remote deletion
546
+ // hasn't been undone.
547
+ console.warn(`Unable to find element with ID, ${id}.`);
548
+ return null;
537
549
  }
538
550
  let originalZIndex = elem.getZIndex();
539
551
  let targetZIndex = elem.getZIndex() + this.deltaZIndex;
@@ -544,7 +556,9 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
544
556
  originalZIndex = elem.getZIndex() - this.deltaZIndex;
545
557
  }
546
558
  return elem.setZIndexAndTransformBy(this.fullTransform, targetZIndex, originalZIndex);
547
- });
559
+ }).filter(// Remove all null commands
560
+ // Remove all null commands
561
+ command => command !== null);
548
562
  }
549
563
  async apply(editor) {
550
564
  this.resolveToElems(editor, false);
@@ -4,7 +4,9 @@
4
4
  *
5
5
  * When no pointers are inside `element`, adds the CSS class `no-long-press-or-hover`.
6
6
  */
7
- declare const addLongPressOrHoverCssClasses: (element: HTMLElement) => {
7
+ declare const addLongPressOrHoverCssClasses: (element: HTMLElement, options?: {
8
+ timeout: number;
9
+ }) => {
8
10
  removeEventListeners: () => void;
9
11
  };
10
12
  export default addLongPressOrHoverCssClasses;
@@ -5,7 +5,7 @@ import listenForLongPressOrHover from './listenForLongPressOrHover.mjs';
5
5
  *
6
6
  * When no pointers are inside `element`, adds the CSS class `no-long-press-or-hover`.
7
7
  */
8
- const addLongPressOrHoverCssClasses = (element) => {
8
+ const addLongPressOrHoverCssClasses = (element, options) => {
9
9
  const hasLongPressClass = 'has-long-press-or-hover';
10
10
  const noLongPressClass = 'no-long-press-or-hover';
11
11
  element.classList.add('no-long-press-or-hover');
@@ -18,6 +18,7 @@ const addLongPressOrHoverCssClasses = (element) => {
18
18
  element.classList.add(noLongPressClass);
19
19
  element.classList.remove(hasLongPressClass);
20
20
  },
21
+ longPressTimeout: options?.timeout,
21
22
  });
22
23
  return {
23
24
  removeEventListeners: () => {
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Makes a clone of `element` and recursively applies styles from the original to the
3
+ * clone's children.
4
+ */
5
+ declare const cloneElementWithStyles: (element: HTMLElement) => HTMLElement;
6
+ export default cloneElementWithStyles;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Makes a clone of `element` and recursively applies styles from the original to the
3
+ * clone's children.
4
+ */
5
+ const cloneElementWithStyles = (element) => {
6
+ const restyle = (originalElement, clonedElement) => {
7
+ const originalComputedStyle = getComputedStyle(originalElement);
8
+ // jsdom doesn't support iterators in CSSStyleDeclarations. Iterate with
9
+ // an index.
10
+ for (let index = 0; index < originalComputedStyle.length; index++) {
11
+ const propertyName = originalComputedStyle.item(index);
12
+ const propertyValue = originalComputedStyle.getPropertyValue(propertyName);
13
+ clonedElement.style.setProperty(propertyName, propertyValue);
14
+ }
15
+ for (let i = 0; i < originalElement.children.length; i++) {
16
+ const originalChild = originalElement.children.item(i);
17
+ const clonedChild = clonedElement.children.item(i);
18
+ if (originalChild && clonedChild) {
19
+ restyle(originalChild, clonedChild);
20
+ }
21
+ else {
22
+ console.warn('CloneElement: Missing child');
23
+ }
24
+ }
25
+ };
26
+ const elementClone = element.cloneNode(true);
27
+ restyle(element, elementClone);
28
+ return elementClone;
29
+ };
30
+ export default cloneElementWithStyles;
@@ -1,3 +1,3 @@
1
1
  export default {
2
- number: '1.14.0',
2
+ number: '1.16.0',
3
3
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "1.14.0",
3
+ "version": "1.16.0",
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,7 +64,7 @@
64
64
  "postpack": "ts-node tools/copyREADME.ts revert"
65
65
  },
66
66
  "dependencies": {
67
- "@js-draw/math": "^1.11.1",
67
+ "@js-draw/math": "^1.16.0",
68
68
  "@melloware/coloris": "0.22.0"
69
69
  },
70
70
  "devDependencies": {
@@ -86,5 +86,5 @@
86
86
  "freehand",
87
87
  "svg"
88
88
  ],
89
- "gitHead": "6870036bd8c8160dcb00ded1a4e13b3d9b75071a"
89
+ "gitHead": "b0b6d7165d76582e1c197d0f56a10bfe6b46e2bc"
90
90
  }
@@ -5,12 +5,22 @@
5
5
  to { transform: translate(0, 0); }
6
6
  }
7
7
 
8
+ @keyframes toolbar--edgemenu-transition-in-reduce-motion {
9
+ from { opacity: 0; }
10
+ to { opacity: 1; }
11
+ }
12
+
8
13
  @keyframes toolbar--edgemenu-transition-out {
9
14
  // Don't include `from { translate: 0 }` because initially,
10
15
  // the translation might not be zero (e.g. during a drag).
11
16
  to { transform: translate(0, 100%); }
12
17
  }
13
18
 
19
+ @keyframes toolbar--edgemenu-transition-out-reduce-motion {
20
+ from { opacity: 1; }
21
+ to { opacity: 0; }
22
+ }
23
+
14
24
  @keyframes toolbar--edgemenu-container-transition-in {
15
25
  // Include overflow-y: hidden so that the bottom of the menu doesn't go below
16
26
  // the editor.
@@ -269,9 +279,11 @@
269
279
  .toolbar-edgemenu-container {
270
280
  background-color: var(--background-color-transparent);
271
281
 
272
- transition: 0.15s ease-in-out height, 0.15s ease-in-out background-color, 0.2s ease-in-out opacity;
282
+ $motion-transition: 0.15s ease-in-out height;
283
+ $non-motion-transition: 0.15s ease-in-out background-color, 0.2s ease-in-out opacity;
284
+ transition: $motion-transition, $non-motion-transition;
273
285
  @media (prefers-reduced-motion: reduce) {
274
- transition: none;
286
+ transition: $non-motion-transition;
275
287
  }
276
288
 
277
289
  position: absolute;
@@ -312,6 +324,10 @@
312
324
  --button-label-hover-offset-y: var(--button-size);
313
325
  @include labelVisibleOnHover.label-visible-on-hover('label > .button-label-text');
314
326
  }
327
+
328
+ .toolbar-help-overlay-button {
329
+ align-items: last baseline;
330
+ }
315
331
  }
316
332
 
317
333
  .toolbar-edgemenu-container .toolbar-edgemenu {
@@ -432,6 +448,11 @@
432
448
  margin-top: 5px;
433
449
  min-height: 35px;
434
450
 
451
+ // No extra space above the first
452
+ &:first-child {
453
+ margin-top: 0;
454
+ }
455
+
435
456
  // Align inputs (assumes labels come first)
436
457
  & > label {
437
458
  padding-right: 35px;
@@ -9,3 +9,5 @@
9
9
  @use "./AbstractToolbar.scss";
10
10
  @use "./EdgeToolbar.scss";
11
11
  @use "./DropdownToolbar.scss";
12
+
13
+ @use "./utils/HelpDisplay.scss";
@@ -0,0 +1,315 @@
1
+
2
+ .toolbar-help-overlay {
3
+ width: 100%;
4
+ height: 100%;
5
+ max-width: none;
6
+ max-height: none;
7
+ border: none;
8
+ margin: 0;
9
+ padding: 0;
10
+ z-index: 5;
11
+ touch-action: none;
12
+ overflow: hidden;
13
+
14
+ // TODO: Use theme colors
15
+ $help-overlay-foreground: white;
16
+ $help-overlay-background: rgba(0, 0, 0, 0.8);
17
+
18
+ color: $help-overlay-foreground;
19
+ --icon-color: #{$help-overlay-foreground};
20
+
21
+ // We use ::backdrop for background styling
22
+ background-color: transparent;
23
+
24
+ &::backdrop {
25
+ background-color: $help-overlay-background;
26
+
27
+ backdrop-filter: blur(1px);
28
+ -webkit-backdrop-filter: blur(1px);
29
+ }
30
+
31
+ display: flex;
32
+ flex-direction: column;
33
+
34
+ // Show/hide animations
35
+ &, &::backdrop {
36
+ @keyframes transition-in {
37
+ 0% { opacity: 0; }
38
+ 100% { opacity: 1; }
39
+ }
40
+ animation: 0.25s ease transition-in;
41
+ }
42
+
43
+ &.-hiding {
44
+ @keyframes transition-out {
45
+ 0% { opacity: 1; }
46
+ 100% { opacity: 0; }
47
+ }
48
+
49
+ &, &::backdrop {
50
+ animation: 0.25s ease transition-out;
51
+ opacity: 0;
52
+ }
53
+ }
54
+
55
+
56
+ // For drag transitions
57
+ transition: 0.3s ease transform;
58
+ &.-dragging {
59
+ transition: none;
60
+ }
61
+
62
+ @media (prefers-reduced-motion: reduce) {
63
+ transition: none;
64
+ }
65
+
66
+
67
+ @media screen and (min-width: 800px) {
68
+ // Move the navigation buttons to the bottom of the screen
69
+ > .navigation-buttons {
70
+ order: 1;
71
+ margin-top: auto;
72
+ }
73
+ }
74
+
75
+ // -- sub-components --
76
+
77
+ .with-text-shadow {
78
+ text-shadow: 0 0 3px rgba(20, 20, 20, 0.9);
79
+ filter: drop-shadow(0px 0px 2px rgba(0, 0, 0, 0.5));
80
+ }
81
+
82
+ button:not(:disabled) {
83
+ cursor: pointer;
84
+ }
85
+
86
+ button {
87
+ @extend .with-text-shadow;
88
+
89
+ background: transparent;
90
+ border: none;
91
+ color: var(--help-overlay-foreground);
92
+
93
+ border-radius: 15px;
94
+ }
95
+
96
+ .close-button {
97
+ align-self: flex-start;
98
+ width: 48px;
99
+ height: 48px;
100
+ z-index: 1;
101
+
102
+ > svg {
103
+ width: 100%;
104
+ }
105
+ }
106
+
107
+ .navigation-content {
108
+ flex-grow: 1;
109
+ display: flex;
110
+ }
111
+
112
+ .help-page-container {
113
+ display: flex;
114
+ align-items: center;
115
+ flex-grow: 1;
116
+ touch-action: none;
117
+
118
+ > .label {
119
+ @extend .with-text-shadow;
120
+
121
+ flex-grow: 1;
122
+ text-align: center;
123
+ font-size: 18.5pt;
124
+ margin-left: 15px;
125
+ margin-right: 15px;
126
+ margin-top: 0px;
127
+
128
+ z-index: 1;
129
+
130
+ &.-large-space-below {
131
+ margin-top: 0;
132
+ margin-bottom: auto;
133
+ }
134
+
135
+ &.-small-space-above {
136
+ margin-top: 40px;
137
+ margin-bottom: auto;
138
+ }
139
+
140
+ &.-large-space-above {
141
+ margin-top: auto;
142
+ margin-bottom: 10px;
143
+ }
144
+
145
+ transition: 0.5s ease margin-top;
146
+
147
+ @media (prefers-reduced-motion: reduce) {
148
+ transition: none;
149
+ }
150
+ }
151
+
152
+ > .cloned-element-container {
153
+ position: absolute;
154
+ z-index: 0;
155
+
156
+ // Prevent selecton on long-press
157
+ user-select: none;
158
+ -webkit-user-select: none;
159
+
160
+ border-radius: 10px;
161
+
162
+ * {
163
+ pointer-events: none !important;
164
+ }
165
+
166
+ > * {
167
+ margin: 0;
168
+ opacity: 0.01 !important;
169
+ transition: 0.3s ease opacity !important;
170
+ }
171
+
172
+ &:not(.-clickable) * {
173
+ cursor: unset !important;
174
+ }
175
+
176
+ &.-clickable, &.-background {
177
+ z-index: 1;
178
+ touch-action: none;
179
+ }
180
+
181
+ &.-clickable {
182
+ cursor: pointer;
183
+
184
+ z-index: 2;
185
+
186
+ &.has-long-press-or-hover {
187
+ opacity: 0.5 !important;
188
+ }
189
+ }
190
+
191
+ &.-clickable.has-long-press-or-hover, &.-active {
192
+ background-color: var(--background-color-1);
193
+ }
194
+
195
+ opacity: 0.01;
196
+ background-color: rgba(100, 100, 100, 0.01);
197
+ box-shadow: none;
198
+
199
+ &.-active {
200
+ opacity: 1;
201
+ background-color: var(--background-color-1);
202
+ box-shadow: 0 0 3px rgba(100, 100, 100, 0.5);
203
+
204
+ > * {
205
+ opacity: 1 !important;
206
+ }
207
+ }
208
+
209
+ transition: 0.5s ease opacity, 0.5s ease background-color;
210
+ }
211
+ }
212
+
213
+ .navigation-buttons {
214
+ display: flex;
215
+ flex-direction: row;
216
+ justify-content: space-between;
217
+
218
+ // Enforce left-to-right (enforces consistency with drag)
219
+ direction: ltr;
220
+
221
+ > button:disabled {
222
+ opacity: 0.5;
223
+ }
224
+
225
+ > .next, > .previous {
226
+ font-size: 1em;
227
+ padding: 10px;
228
+ transition: 0.2s ease font-size;
229
+ z-index: 3;
230
+
231
+ @media (prefers-reduced-motion: reduce) {
232
+ transition: none;
233
+ }
234
+ }
235
+
236
+ &:not(.-has-previous) > .next:not(:disabled) {
237
+ @keyframes highlight-button {
238
+ 0% { transform: scale(1); }
239
+ 50% { transform: scale(1.2); }
240
+ 55% { transform: scale(1.2) rotate(2deg); }
241
+ 65% { transform: scale(1.2) rotate(-2deg); }
242
+ 100% { transform: scale(1); }
243
+ }
244
+ animation: 0.5s ease highlight-button 0.5s;
245
+
246
+ @media (prefers-reduced-motion: reduce) {
247
+ animation: none;
248
+ }
249
+ }
250
+
251
+ > .next::after {
252
+ content: "❯";
253
+ margin-left: 3px;
254
+ }
255
+
256
+ > .previous::before {
257
+ content: "❮";
258
+ margin-right: 3px;
259
+ }
260
+
261
+ &.-has-next > .next {
262
+ font-size: 1.4em;
263
+ }
264
+
265
+ &.-has-previous > .previous {
266
+ font-size: 1.4em;
267
+ }
268
+
269
+ &.-highlight-next > .next, &.-highlight-previous > .previous {
270
+ font-weight: bold;
271
+ background-color: rgba(200, 200, 200, 0.1);
272
+ font-size: 1.4em;
273
+ }
274
+ }
275
+
276
+ .navigation-help {
277
+ margin-top: 1em;
278
+ font-size: 0.7em;
279
+ }
280
+ }
281
+
282
+
283
+ .toolbar-element .toolbar-help-overlay-button {
284
+ height: 0;
285
+ position: relative;
286
+
287
+ // Use flex so that items reverse in RTL
288
+ display: flex;
289
+ justify-content: end;
290
+
291
+ > .button {
292
+ margin: 0;
293
+ padding: 5px;
294
+ padding-top: 0;
295
+ padding-bottom: 0;
296
+
297
+ box-shadow: none;
298
+
299
+ text-align: center;
300
+ opacity: 0.5;
301
+
302
+ > .icon {
303
+ width: 1.18em;
304
+ height: 1.18em;
305
+
306
+ transition: 0.2s ease filter;
307
+ }
308
+
309
+ &:focus-visible, &:hover {
310
+ > .icon {
311
+ filter: drop-shadow(0px 0px 1px var(--shadow-color));
312
+ }
313
+ }
314
+ }
315
+ }
@@ -53,6 +53,13 @@ $pipette-button-size: 30px;
53
53
  display: inline-flex;
54
54
  }
55
55
 
56
+ .color-input-container {
57
+ > .color-input-wrapper {
58
+ display: flex;
59
+ justify-content: stretch;
60
+ }
61
+ }
62
+
56
63
  .color-input-container .pipetteButton > svg {
57
64
  width: 100%;
58
65
  }
@@ -117,6 +117,10 @@
117
117
  // handles.
118
118
  pointer-events: all;
119
119
  }
120
+
121
+ &.-empty {
122
+ opacity: 0;
123
+ }
120
124
  }
121
125
  }
122
126