js-draw 1.0.2 → 1.2.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 (41) hide show
  1. package/dist/Editor.css +7 -4
  2. package/dist/bundle.js +1 -1
  3. package/dist/bundledStyles.js +1 -1
  4. package/dist/cjs/Editor.d.ts +4 -3
  5. package/dist/cjs/lib.d.ts +15 -8
  6. package/dist/cjs/lib.js +13 -6
  7. package/dist/cjs/toolbar/AbstractToolbar.d.ts +9 -13
  8. package/dist/cjs/toolbar/AbstractToolbar.js +14 -19
  9. package/dist/cjs/toolbar/DropdownToolbar.d.ts +24 -0
  10. package/dist/cjs/toolbar/DropdownToolbar.js +24 -0
  11. package/dist/cjs/toolbar/EdgeToolbar.d.ts +28 -0
  12. package/dist/cjs/toolbar/EdgeToolbar.js +30 -2
  13. package/dist/cjs/toolbar/widgets/SaveActionWidget.d.ts +10 -0
  14. package/dist/cjs/toolbar/widgets/SaveActionWidget.js +26 -0
  15. package/dist/cjs/toolbar/widgets/keybindings.d.ts +1 -0
  16. package/dist/cjs/toolbar/widgets/keybindings.js +4 -1
  17. package/dist/cjs/util/adjustEditorThemeForContrast.d.ts +53 -0
  18. package/dist/cjs/util/adjustEditorThemeForContrast.js +100 -0
  19. package/dist/cjs/util/lib.d.ts +1 -0
  20. package/dist/cjs/util/lib.js +8 -0
  21. package/dist/cjs/version.js +1 -1
  22. package/dist/mjs/Editor.d.ts +4 -3
  23. package/dist/mjs/lib.d.ts +15 -8
  24. package/dist/mjs/lib.mjs +15 -8
  25. package/dist/mjs/toolbar/AbstractToolbar.d.ts +9 -13
  26. package/dist/mjs/toolbar/AbstractToolbar.mjs +14 -19
  27. package/dist/mjs/toolbar/DropdownToolbar.d.ts +24 -0
  28. package/dist/mjs/toolbar/DropdownToolbar.mjs +24 -0
  29. package/dist/mjs/toolbar/EdgeToolbar.d.ts +28 -0
  30. package/dist/mjs/toolbar/EdgeToolbar.mjs +30 -2
  31. package/dist/mjs/toolbar/widgets/SaveActionWidget.d.ts +10 -0
  32. package/dist/mjs/toolbar/widgets/SaveActionWidget.mjs +21 -0
  33. package/dist/mjs/toolbar/widgets/keybindings.d.ts +1 -0
  34. package/dist/mjs/toolbar/widgets/keybindings.mjs +3 -0
  35. package/dist/mjs/util/adjustEditorThemeForContrast.d.ts +53 -0
  36. package/dist/mjs/util/adjustEditorThemeForContrast.mjs +98 -0
  37. package/dist/mjs/util/lib.d.ts +1 -0
  38. package/dist/mjs/util/lib.mjs +1 -0
  39. package/dist/mjs/version.mjs +1 -1
  40. package/package.json +3 -3
  41. package/src/toolbar/EdgeToolbar.scss +7 -4
@@ -0,0 +1,53 @@
1
+ import Editor from '../Editor';
2
+ /**
3
+ * Adjusts the current editor theme such that colors have appropriate contrast.
4
+ *
5
+ * As this method overrides CSS variables using the `.style` property,
6
+ * **assumes** all original theme variables are set using CSS and not the `.style` property.
7
+ *
8
+ * If the editor changes theme in response to the system theme, this method should be
9
+ * called whenever the system theme changes (e.g. by using [the `matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
10
+ * method).
11
+ *
12
+ * @example
13
+ * ```ts,runnable
14
+ * import { Editor, adjustEditorThemeForContrast } from 'js-draw';
15
+ *
16
+ * const editor = new Editor(document.body);
17
+ * editor.addToolbar();
18
+ *
19
+ * const css = `
20
+ * :root .imageEditorContainer {
21
+ * --background-color-1: #ffff77;
22
+ * --foreground-color-1: #fff;
23
+ * --background-color-2: #ffff99;
24
+ * --foreground-color-2: #ffff88;
25
+ * --background-color-3: #ddffff;
26
+ * --foreground-color-3: #eeffff;
27
+ * --selection-background-color: #9f7;
28
+ * --selection-foreground-color: #98f;
29
+ * }
30
+ *
31
+ * @media screen and (prefers-color-scheme: dark) {
32
+ * :root .imageEditorContainer {
33
+ * --background-color-1: black;
34
+ * }
35
+ * }
36
+ * `;
37
+ * editor.addStyleSheet(css);
38
+ *
39
+ * adjustEditorThemeForContrast(editor);
40
+ *
41
+ * // Because adjustEditorThemeForContrast overrides the current theme, it should be called again
42
+ * // to allow the editor to switch between light/dark themes.
43
+ * window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
44
+ * adjustEditorThemeForContrast(editor);
45
+ * });
46
+ *
47
+ * window.matchMedia('print').addEventListener('change', () => {
48
+ * adjustEditorThemeForContrast(editor);
49
+ * });
50
+ * ```
51
+ */
52
+ declare const adjustEditorThemeForContrast: (editor: Editor) => void;
53
+ export default adjustEditorThemeForContrast;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const math_1 = require("@js-draw/math");
4
+ /**
5
+ * Adjusts the current editor theme such that colors have appropriate contrast.
6
+ *
7
+ * As this method overrides CSS variables using the `.style` property,
8
+ * **assumes** all original theme variables are set using CSS and not the `.style` property.
9
+ *
10
+ * If the editor changes theme in response to the system theme, this method should be
11
+ * called whenever the system theme changes (e.g. by using [the `matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
12
+ * method).
13
+ *
14
+ * @example
15
+ * ```ts,runnable
16
+ * import { Editor, adjustEditorThemeForContrast } from 'js-draw';
17
+ *
18
+ * const editor = new Editor(document.body);
19
+ * editor.addToolbar();
20
+ *
21
+ * const css = `
22
+ * :root .imageEditorContainer {
23
+ * --background-color-1: #ffff77;
24
+ * --foreground-color-1: #fff;
25
+ * --background-color-2: #ffff99;
26
+ * --foreground-color-2: #ffff88;
27
+ * --background-color-3: #ddffff;
28
+ * --foreground-color-3: #eeffff;
29
+ * --selection-background-color: #9f7;
30
+ * --selection-foreground-color: #98f;
31
+ * }
32
+ *
33
+ * @media screen and (prefers-color-scheme: dark) {
34
+ * :root .imageEditorContainer {
35
+ * --background-color-1: black;
36
+ * }
37
+ * }
38
+ * `;
39
+ * editor.addStyleSheet(css);
40
+ *
41
+ * adjustEditorThemeForContrast(editor);
42
+ *
43
+ * // Because adjustEditorThemeForContrast overrides the current theme, it should be called again
44
+ * // to allow the editor to switch between light/dark themes.
45
+ * window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
46
+ * adjustEditorThemeForContrast(editor);
47
+ * });
48
+ *
49
+ * window.matchMedia('print').addEventListener('change', () => {
50
+ * adjustEditorThemeForContrast(editor);
51
+ * });
52
+ * ```
53
+ */
54
+ const adjustEditorThemeForContrast = (editor) => {
55
+ const editorElem = editor.getRootElement();
56
+ // Each set of entries in colorPairs should resolve to colors with sufficient
57
+ // contrast.
58
+ const colorPairs = [
59
+ ['--background-color-1', '--foreground-color-1'],
60
+ ['--background-color-2', '--foreground-color-2'],
61
+ ['--background-color-3', '--foreground-color-3'],
62
+ ['--selection-background-color', '--selection-foreground-color'],
63
+ ];
64
+ // Clear any overrides
65
+ for (const [backgroundVar, foregroundVar] of colorPairs) {
66
+ editorElem.style.setProperty(backgroundVar, null);
67
+ editorElem.style.setProperty(foregroundVar, null);
68
+ }
69
+ const styles = getComputedStyle(editorElem);
70
+ const minContrast = 3;
71
+ for (const [backgroundVar, foregroundVar] of colorPairs) {
72
+ let color1 = math_1.Color4.fromString(styles.getPropertyValue(backgroundVar));
73
+ let color2 = math_1.Color4.fromString(styles.getPropertyValue(foregroundVar));
74
+ let swappedColors = false;
75
+ // Ensure that color1 has the lesser luminance
76
+ if (color1.relativeLuminance() < color2.relativeLuminance()) {
77
+ const tmp = color1;
78
+ color1 = color2;
79
+ color2 = tmp;
80
+ swappedColors = true;
81
+ }
82
+ let colorsUpdated = false;
83
+ let currentContrast = math_1.Color4.contrastRatio(color1, color2);
84
+ const iterations = 0;
85
+ while (currentContrast < minContrast && iterations < 5) {
86
+ const step = math_1.Vec3.of(0.1, 0.1, 0.1);
87
+ color1 = math_1.Color4.fromRGBVector(color1.rgb.plus(step));
88
+ color2 = math_1.Color4.fromRGBVector(color2.rgb.minus(step));
89
+ currentContrast = math_1.Color4.contrastRatio(color1, color2);
90
+ colorsUpdated = true;
91
+ }
92
+ if (colorsUpdated) {
93
+ const newBackground = swappedColors ? color2 : color1;
94
+ const newForeground = swappedColors ? color1 : color2;
95
+ editorElem.style.setProperty(foregroundVar, newForeground.toHexString());
96
+ editorElem.style.setProperty(backgroundVar, newBackground.toHexString());
97
+ }
98
+ }
99
+ };
100
+ exports.default = adjustEditorThemeForContrast;
@@ -0,0 +1 @@
1
+ export { default as adjustEditorThemeForContrast } from './adjustEditorThemeForContrast';
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.adjustEditorThemeForContrast = void 0;
7
+ var adjustEditorThemeForContrast_1 = require("./adjustEditorThemeForContrast");
8
+ Object.defineProperty(exports, "adjustEditorThemeForContrast", { enumerable: true, get: function () { return __importDefault(adjustEditorThemeForContrast_1).default; } });
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = {
4
- number: '1.0.2',
4
+ number: '1.2.0',
5
5
  };
@@ -16,6 +16,7 @@ import KeyBinding from './shortcuts/KeyBinding';
16
16
  import AbstractToolbar from './toolbar/AbstractToolbar';
17
17
  import RenderablePathSpec from './rendering/RenderablePathSpec';
18
18
  import { AboutDialogEntry } from './dialogs/makeAboutDialog';
19
+ /** Provides settings to an instance of an editor. See the Editor {@link Editor.constructor}. */
19
20
  export interface EditorSettings {
20
21
  /** Defaults to `RenderingMode.CanvasRenderer` */
21
22
  renderingMode: RenderingMode;
@@ -27,9 +28,9 @@ export interface EditorSettings {
27
28
  * Defaults to true.
28
29
  */
29
30
  wheelEventsEnabled: boolean | 'only-if-focused';
30
- /** Minimum zoom fraction (e.g. 0.5 → 50% zoom). */
31
+ /** Minimum zoom fraction (e.g. 0.5 → 50% zoom). Defaults to $2 \cdot 10^{-10}$. */
31
32
  minZoom: number;
32
- /** Maximum zoom fraction (e.g. 2 → 200% zoom). */
33
+ /** Maximum zoom fraction (e.g. 2 → 200% zoom). Defaults to $1 \cdot 10^{12}$. */
33
34
  maxZoom: number;
34
35
  /**
35
36
  * Overrides for keyboard shortcuts. For example,
@@ -48,7 +49,7 @@ export interface EditorSettings {
48
49
  * See, for example, the `@js-draw/material-icons` package.
49
50
  *
50
51
  * @example
51
- * ```ts
52
+ * ```ts,runnable
52
53
  * import * as jsdraw from 'js-draw';
53
54
  * import MaterialIconProvider from '@js-draw/material-icons';
54
55
  * import 'js-draw/styles';
package/dist/mjs/lib.d.ts CHANGED
@@ -6,13 +6,18 @@
6
6
  * ```ts,runnable
7
7
  * import { Editor, Vec3, Mat33, ToolbarWidgetTag } from 'js-draw';
8
8
  *
9
+ * // Use the Material Icon pack.
10
+ * import { MaterialIconProvider } from '@js-draw/material-icons';
11
+ *
9
12
  * // Apply js-draw CSS
10
13
  * import 'js-draw/styles';
11
14
  * // If your bundler doesn't support the above, try
12
15
  * // import 'js-draw/bundledStyles';
13
16
  *
14
17
  * (async () => {
15
- * const editor = new Editor(document.body);
18
+ * const editor = new Editor(document.body, {
19
+ * iconProvider: new MaterialIconProvider(),
20
+ * });
16
21
  * const toolbar = editor.addToolbar();
17
22
  *
18
23
  * // Increases the minimum height of the editor
@@ -22,8 +27,8 @@
22
27
  * await editor.loadFromSVG(`
23
28
  * <svg viewBox="0 0 500 500" width="500" height="500" version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
24
29
  * <style id="js-draw-style-sheet">path{stroke-linecap:round;stroke-linejoin:round;}text{white-space:pre;}</style>
25
- * <path d="M500,500L500,0L0,0L0,500L500,500" fill="#423131bf" class="js-draw-image-background"></path>
26
- * <text style="transform: matrix(1, 0, 0, 1, 57, 192); font-family: serif; font-size: 32px; fill: rgb(204, 102, 51);">Testing...</text>
30
+ * <path d="M500,500L500,0L0,0L0,500L500,500" fill="#aaa" class="js-draw-image-background"></path>
31
+ * <text style="transform: matrix(1, 0, 0, 1, 57, 192); font-family: serif; font-size: 32px; fill: #111;">Testing...</text>
27
32
  * </svg>
28
33
  * `);
29
34
  *
@@ -45,9 +50,10 @@
45
50
  * ```
46
51
  *
47
52
  * @see
48
- * {@link Editor}
49
- * {@link Editor.loadFromSVG}
50
- * {@link AbstractToolbar.addActionButton }
53
+ * - {@link Editor}
54
+ * - {@link Editor.loadFromSVG}
55
+ * - {@link AbstractToolbar.addActionButton }
56
+ * - {@link EditorSettings}
51
57
  *
52
58
  * @packageDocumentation
53
59
  */
@@ -70,13 +76,14 @@ export * from './shortcuts/lib';
70
76
  export { default as EventDispatcher } from './EventDispatcher';
71
77
  export { default as Pointer, PointerDevice } from './Pointer';
72
78
  export { default as UndoRedoHistory } from './UndoRedoHistory';
79
+ export * from './util/lib';
73
80
  export { default as __js_draw__version } from './version';
74
81
  import AbstractToolbar from './toolbar/AbstractToolbar';
75
- export { Editor, EditorSettings, AbstractToolbar,
82
+ export { Editor, EditorSettings, AbstractToolbar, };
76
83
  /**
77
84
  * Using the HTMLToolbar alias is deprecated. Use
78
85
  * `AbstractToolbar` instead.
79
86
  * @deprecated
80
87
  */
81
- AbstractToolbar as HTMLToolbar, };
88
+ export { AbstractToolbar as HTMLToolbar };
82
89
  export default Editor;
package/dist/mjs/lib.mjs CHANGED
@@ -6,13 +6,18 @@
6
6
  * ```ts,runnable
7
7
  * import { Editor, Vec3, Mat33, ToolbarWidgetTag } from 'js-draw';
8
8
  *
9
+ * // Use the Material Icon pack.
10
+ * import { MaterialIconProvider } from '@js-draw/material-icons';
11
+ *
9
12
  * // Apply js-draw CSS
10
13
  * import 'js-draw/styles';
11
14
  * // If your bundler doesn't support the above, try
12
15
  * // import 'js-draw/bundledStyles';
13
16
  *
14
17
  * (async () => {
15
- * const editor = new Editor(document.body);
18
+ * const editor = new Editor(document.body, {
19
+ * iconProvider: new MaterialIconProvider(),
20
+ * });
16
21
  * const toolbar = editor.addToolbar();
17
22
  *
18
23
  * // Increases the minimum height of the editor
@@ -22,8 +27,8 @@
22
27
  * await editor.loadFromSVG(`
23
28
  * <svg viewBox="0 0 500 500" width="500" height="500" version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
24
29
  * <style id="js-draw-style-sheet">path{stroke-linecap:round;stroke-linejoin:round;}text{white-space:pre;}</style>
25
- * <path d="M500,500L500,0L0,0L0,500L500,500" fill="#423131bf" class="js-draw-image-background"></path>
26
- * <text style="transform: matrix(1, 0, 0, 1, 57, 192); font-family: serif; font-size: 32px; fill: rgb(204, 102, 51);">Testing...</text>
30
+ * <path d="M500,500L500,0L0,0L0,500L500,500" fill="#aaa" class="js-draw-image-background"></path>
31
+ * <text style="transform: matrix(1, 0, 0, 1, 57, 192); font-family: serif; font-size: 32px; fill: #111;">Testing...</text>
27
32
  * </svg>
28
33
  * `);
29
34
  *
@@ -45,9 +50,10 @@
45
50
  * ```
46
51
  *
47
52
  * @see
48
- * {@link Editor}
49
- * {@link Editor.loadFromSVG}
50
- * {@link AbstractToolbar.addActionButton }
53
+ * - {@link Editor}
54
+ * - {@link Editor.loadFromSVG}
55
+ * - {@link AbstractToolbar.addActionButton }
56
+ * - {@link EditorSettings}
51
57
  *
52
58
  * @packageDocumentation
53
59
  */
@@ -70,14 +76,15 @@ export * from './shortcuts/lib.mjs';
70
76
  export { default as EventDispatcher } from './EventDispatcher.mjs';
71
77
  export { default as Pointer, PointerDevice } from './Pointer.mjs';
72
78
  export { default as UndoRedoHistory } from './UndoRedoHistory.mjs';
79
+ export * from './util/lib.mjs';
73
80
  // @internal
74
81
  export { default as __js_draw__version } from './version.mjs';
75
82
  import AbstractToolbar from './toolbar/AbstractToolbar.mjs';
76
- export { Editor, AbstractToolbar,
83
+ export { Editor, AbstractToolbar, };
77
84
  /**
78
85
  * Using the HTMLToolbar alias is deprecated. Use
79
86
  * `AbstractToolbar` instead.
80
87
  * @deprecated
81
88
  */
82
- AbstractToolbar as HTMLToolbar, };
89
+ export { AbstractToolbar as HTMLToolbar };
83
90
  export default Editor;
@@ -106,20 +106,16 @@ export default abstract class AbstractToolbar {
106
106
  /**
107
107
  * Adds a save button that, when clicked, calls `saveCallback`.
108
108
  *
109
- * **Note**: This is equivalent to
110
- * ```ts
111
- * const tags = [
112
- * ToolbarWidgetTag.Save,
113
- * ];
114
- * toolbar.addTaggedActionButton(tags, {
115
- * label: editor.localization.save,
116
- * icon: editor.icons.makeSaveIcon(),
117
- * }, () => {
118
- * saveCallback();
119
- * });
120
- * ```
109
+ * @example
110
+ * ```ts,runnable
111
+ * import { Editor, makeDropdownToolbar } from 'js-draw';
121
112
  *
122
- * @final
113
+ * const editor = new Editor(document.body);
114
+ * const toolbar = makeDropdownToolbar(editor);
115
+ *
116
+ * toolbar.addDefaults();
117
+ * toolbar.addSaveButton(() => alert('save clicked!'));
118
+ * ```
123
119
  */
124
120
  addSaveButton(saveCallback: () => void): BaseWidget;
125
121
  /**
@@ -29,6 +29,7 @@ import InsertImageWidget from './widgets/InsertImageWidget.mjs';
29
29
  import DocumentPropertiesWidget from './widgets/DocumentPropertiesWidget.mjs';
30
30
  import { Color4 } from '@js-draw/math';
31
31
  import { toolbarCSSPrefix } from './constants.mjs';
32
+ import SaveActionWidget from './widgets/SaveActionWidget.mjs';
32
33
  class AbstractToolbar {
33
34
  /** @internal */
34
35
  constructor(editor, localizationTable = defaultToolbarLocalization) {
@@ -264,28 +265,22 @@ class AbstractToolbar {
264
265
  /**
265
266
  * Adds a save button that, when clicked, calls `saveCallback`.
266
267
  *
267
- * **Note**: This is equivalent to
268
- * ```ts
269
- * const tags = [
270
- * ToolbarWidgetTag.Save,
271
- * ];
272
- * toolbar.addTaggedActionButton(tags, {
273
- * label: editor.localization.save,
274
- * icon: editor.icons.makeSaveIcon(),
275
- * }, () => {
276
- * saveCallback();
277
- * });
278
- * ```
268
+ * @example
269
+ * ```ts,runnable
270
+ * import { Editor, makeDropdownToolbar } from 'js-draw';
279
271
  *
280
- * @final
272
+ * const editor = new Editor(document.body);
273
+ * const toolbar = makeDropdownToolbar(editor);
274
+ *
275
+ * toolbar.addDefaults();
276
+ * toolbar.addSaveButton(() => alert('save clicked!'));
277
+ * ```
281
278
  */
282
279
  addSaveButton(saveCallback) {
283
- return this.addTaggedActionButton([ToolbarWidgetTag.Save], {
284
- label: this.editor.localization.save,
285
- icon: this.editor.icons.makeSaveIcon(),
286
- }, () => {
287
- saveCallback();
288
- });
280
+ const widget = new SaveActionWidget(this.editor, this.localizationTable, saveCallback);
281
+ widget.setTags([ToolbarWidgetTag.Save]);
282
+ this.addWidget(widget);
283
+ return widget;
289
284
  }
290
285
  /**
291
286
  * Adds an "Exit" button that, when clicked, calls `exitCallback`.
@@ -2,6 +2,30 @@ import Editor from '../Editor';
2
2
  import { ToolbarLocalization } from './localization';
3
3
  import BaseWidget from './widgets/BaseWidget';
4
4
  import AbstractToolbar, { SpacerOptions } from './AbstractToolbar';
5
+ /**
6
+ * @example
7
+ *
8
+ * ```ts,runnable
9
+ * import { makeDropdownToolbar, Editor } from 'js-draw';
10
+ *
11
+ * const editor = new Editor(document.body);
12
+ * const toolbar = makeDropdownToolbar(editor);
13
+ * toolbar.addDefaults();
14
+ *
15
+ * toolbar.addExitButton(editor => {
16
+ * // TODO
17
+ * });
18
+ *
19
+ * toolbar.addSaveButton(editor => {
20
+ * // TODO
21
+ * });
22
+ * ```
23
+ *
24
+ * @see
25
+ * - {@link makeEdgeToolbar}
26
+ * - {@link AbstractToolbar.addSaveButton}
27
+ * - {@link AbstractToolbar.addExitButton}
28
+ */
5
29
  export declare const makeDropdownToolbar: (editor: Editor) => AbstractToolbar;
6
30
  export default class DropdownToolbar extends AbstractToolbar {
7
31
  protected container: HTMLElement;
@@ -2,6 +2,30 @@ import { defaultToolbarLocalization } from './localization.mjs';
2
2
  import OverflowWidget from './widgets/OverflowWidget.mjs';
3
3
  import AbstractToolbar from './AbstractToolbar.mjs';
4
4
  import { toolbarCSSPrefix } from './constants.mjs';
5
+ /**
6
+ * @example
7
+ *
8
+ * ```ts,runnable
9
+ * import { makeDropdownToolbar, Editor } from 'js-draw';
10
+ *
11
+ * const editor = new Editor(document.body);
12
+ * const toolbar = makeDropdownToolbar(editor);
13
+ * toolbar.addDefaults();
14
+ *
15
+ * toolbar.addExitButton(editor => {
16
+ * // TODO
17
+ * });
18
+ *
19
+ * toolbar.addSaveButton(editor => {
20
+ * // TODO
21
+ * });
22
+ * ```
23
+ *
24
+ * @see
25
+ * - {@link makeEdgeToolbar}
26
+ * - {@link AbstractToolbar.addSaveButton}
27
+ * - {@link AbstractToolbar.addExitButton}
28
+ */
5
29
  export const makeDropdownToolbar = (editor) => {
6
30
  return new DropdownToolbar(editor, editor.getRootElement());
7
31
  };
@@ -2,6 +2,34 @@ import Editor from '../Editor';
2
2
  import { ToolbarLocalization } from './localization';
3
3
  import BaseWidget from './widgets/BaseWidget';
4
4
  import AbstractToolbar, { SpacerOptions } from './AbstractToolbar';
5
+ /**
6
+ * Creates an `EdgeToolbar`.
7
+ *
8
+ * [Credit for the original design of this UI](https://www.figma.com/file/NA5F2AMWO3wUuaoDfUaAb8/Material-3-wireframes?type=design&node-id=54490%3A1103&mode=design&t=Ee0UwnPnQ2bNC2uM-1).
9
+ *
10
+ * @example
11
+ *
12
+ * ```ts,runnable
13
+ * import { makeEdgeToolbar, Editor } from 'js-draw';
14
+ *
15
+ * const editor = new Editor(document.body);
16
+ * const toolbar = makeEdgeToolbar(editor);
17
+ * toolbar.addDefaults();
18
+ *
19
+ * toolbar.addSaveButton(editor => {
20
+ * // TODO
21
+ * });
22
+ *
23
+ * toolbar.addExitButton(editor => {
24
+ * // TODO
25
+ * });
26
+ * ```
27
+ *
28
+ * @see
29
+ * - {@link makeDropdownToolbar}
30
+ * - {@link AbstractToolbar.addSaveButton}
31
+ * - {@link AbstractToolbar.addExitButton}
32
+ */
5
33
  export declare const makeEdgeToolbar: (editor: Editor) => AbstractToolbar;
6
34
  export default class EdgeToolbar extends AbstractToolbar {
7
35
  private toolbarContainer;
@@ -4,6 +4,34 @@ import EdgeToolbarLayoutManager from './widgets/layout/EdgeToolbarLayoutManage
4
4
  import { MutableReactiveValue, ReactiveValue } from '../util/ReactiveValue.mjs';
5
5
  import AbstractToolbar from './AbstractToolbar.mjs';
6
6
  import stopPropagationOfScrollingWheelEvents from '../util/stopPropagationOfScrollingWheelEvents.mjs';
7
+ /**
8
+ * Creates an `EdgeToolbar`.
9
+ *
10
+ * [Credit for the original design of this UI](https://www.figma.com/file/NA5F2AMWO3wUuaoDfUaAb8/Material-3-wireframes?type=design&node-id=54490%3A1103&mode=design&t=Ee0UwnPnQ2bNC2uM-1).
11
+ *
12
+ * @example
13
+ *
14
+ * ```ts,runnable
15
+ * import { makeEdgeToolbar, Editor } from 'js-draw';
16
+ *
17
+ * const editor = new Editor(document.body);
18
+ * const toolbar = makeEdgeToolbar(editor);
19
+ * toolbar.addDefaults();
20
+ *
21
+ * toolbar.addSaveButton(editor => {
22
+ * // TODO
23
+ * });
24
+ *
25
+ * toolbar.addExitButton(editor => {
26
+ * // TODO
27
+ * });
28
+ * ```
29
+ *
30
+ * @see
31
+ * - {@link makeDropdownToolbar}
32
+ * - {@link AbstractToolbar.addSaveButton}
33
+ * - {@link AbstractToolbar.addExitButton}
34
+ */
7
35
  export const makeEdgeToolbar = (editor) => {
8
36
  return new EdgeToolbar(editor, editor.getRootElement(), editor.localization);
9
37
  };
@@ -45,12 +73,12 @@ export default class EdgeToolbar extends AbstractToolbar {
45
73
  this.sidebarY.onUpdateAndNow(y => {
46
74
  const belowEdgeClassName = 'dropdown-below-edge';
47
75
  if (y > 0) {
48
- this.sidebarContainer.style.translate = `0 ${y}px`;
76
+ this.sidebarContainer.style.transform = `translate(0, ${y}px)`;
49
77
  this.sidebarContainer.style.paddingBottom = '';
50
78
  this.menuContainer.classList.add(belowEdgeClassName);
51
79
  }
52
80
  else {
53
- this.sidebarContainer.style.translate = '';
81
+ this.sidebarContainer.style.transform = '';
54
82
  this.sidebarContainer.style.paddingBottom = `${-y}px`;
55
83
  this.menuContainer.classList.remove(belowEdgeClassName);
56
84
  }
@@ -0,0 +1,10 @@
1
+ import { KeyPressEvent } from '../../inputEvents';
2
+ import Editor from '../../Editor';
3
+ import { ToolbarLocalization } from '../localization';
4
+ import ActionButtonWidget from './ActionButtonWidget';
5
+ declare class SaveActionWidget extends ActionButtonWidget {
6
+ constructor(editor: Editor, localization: ToolbarLocalization, saveCallback: () => void);
7
+ protected onKeyPress(event: KeyPressEvent): boolean;
8
+ mustBeInToplevelMenu(): boolean;
9
+ }
10
+ export default SaveActionWidget;
@@ -0,0 +1,21 @@
1
+ import ActionButtonWidget from './ActionButtonWidget.mjs';
2
+ import { ToolbarWidgetTag } from './BaseWidget.mjs';
3
+ import { saveKeyboardShortcut } from './keybindings.mjs';
4
+ class SaveActionWidget extends ActionButtonWidget {
5
+ constructor(editor, localization, saveCallback) {
6
+ super(editor, 'save-button', editor.icons.makeSaveIcon, localization.save, saveCallback);
7
+ this.setTags([ToolbarWidgetTag.Save]);
8
+ }
9
+ onKeyPress(event) {
10
+ if (this.editor.shortcuts.matchesShortcut(saveKeyboardShortcut, event)) {
11
+ this.clickAction();
12
+ return true;
13
+ }
14
+ // Run any default actions registered by the parent class.
15
+ return super.onKeyPress(event);
16
+ }
17
+ mustBeInToplevelMenu() {
18
+ return true;
19
+ }
20
+ }
21
+ export default SaveActionWidget;
@@ -1,2 +1,3 @@
1
1
  export declare const resizeImageToSelectionKeyboardShortcut = "jsdraw.toolbar.SelectionTool.resizeImageToSelection";
2
2
  export declare const selectStrokeTypeKeyboardShortcutIds: string[];
3
+ export declare const saveKeyboardShortcut = "jsdraw.toolbar.SaveActionWidget.save";
@@ -8,3 +8,6 @@ for (let i = 0; i < selectStrokeTypeKeyboardShortcutIds.length; i++) {
8
8
  const id = selectStrokeTypeKeyboardShortcutIds[i];
9
9
  KeyboardShortcutManager.registerDefaultKeyboardShortcut(id, [`CtrlOrMeta+Digit${(i + 1)}`], 'Select pen style ' + (i + 1));
10
10
  }
11
+ // Save
12
+ export const saveKeyboardShortcut = 'jsdraw.toolbar.SaveActionWidget.save';
13
+ KeyboardShortcutManager.registerDefaultKeyboardShortcut(saveKeyboardShortcut, ['ctrlOrMeta+KeyS'], 'Save');
@@ -0,0 +1,53 @@
1
+ import Editor from '../Editor';
2
+ /**
3
+ * Adjusts the current editor theme such that colors have appropriate contrast.
4
+ *
5
+ * As this method overrides CSS variables using the `.style` property,
6
+ * **assumes** all original theme variables are set using CSS and not the `.style` property.
7
+ *
8
+ * If the editor changes theme in response to the system theme, this method should be
9
+ * called whenever the system theme changes (e.g. by using [the `matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
10
+ * method).
11
+ *
12
+ * @example
13
+ * ```ts,runnable
14
+ * import { Editor, adjustEditorThemeForContrast } from 'js-draw';
15
+ *
16
+ * const editor = new Editor(document.body);
17
+ * editor.addToolbar();
18
+ *
19
+ * const css = `
20
+ * :root .imageEditorContainer {
21
+ * --background-color-1: #ffff77;
22
+ * --foreground-color-1: #fff;
23
+ * --background-color-2: #ffff99;
24
+ * --foreground-color-2: #ffff88;
25
+ * --background-color-3: #ddffff;
26
+ * --foreground-color-3: #eeffff;
27
+ * --selection-background-color: #9f7;
28
+ * --selection-foreground-color: #98f;
29
+ * }
30
+ *
31
+ * @media screen and (prefers-color-scheme: dark) {
32
+ * :root .imageEditorContainer {
33
+ * --background-color-1: black;
34
+ * }
35
+ * }
36
+ * `;
37
+ * editor.addStyleSheet(css);
38
+ *
39
+ * adjustEditorThemeForContrast(editor);
40
+ *
41
+ * // Because adjustEditorThemeForContrast overrides the current theme, it should be called again
42
+ * // to allow the editor to switch between light/dark themes.
43
+ * window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
44
+ * adjustEditorThemeForContrast(editor);
45
+ * });
46
+ *
47
+ * window.matchMedia('print').addEventListener('change', () => {
48
+ * adjustEditorThemeForContrast(editor);
49
+ * });
50
+ * ```
51
+ */
52
+ declare const adjustEditorThemeForContrast: (editor: Editor) => void;
53
+ export default adjustEditorThemeForContrast;