js-draw 0.11.3 → 0.13.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.
- package/CHANGELOG.md +15 -0
- package/dist/bundle.js +1 -1
- package/dist/src/Color4.d.ts +13 -0
- package/dist/src/Color4.js +17 -0
- package/dist/src/Editor.d.ts +33 -18
- package/dist/src/Editor.js +26 -24
- package/dist/src/EditorImage.d.ts +12 -0
- package/dist/src/EditorImage.js +12 -0
- package/dist/src/Pointer.d.ts +1 -0
- package/dist/src/Pointer.js +8 -0
- package/dist/src/SVGLoader.d.ts +5 -0
- package/dist/src/SVGLoader.js +49 -36
- package/dist/src/Viewport.d.ts +30 -1
- package/dist/src/Viewport.js +39 -9
- package/dist/src/commands/invertCommand.js +1 -1
- package/dist/src/components/AbstractComponent.d.ts +20 -0
- package/dist/src/components/AbstractComponent.js +32 -2
- package/dist/src/lib.d.ts +6 -3
- package/dist/src/lib.js +4 -1
- package/dist/src/math/Mat33.d.ts +1 -1
- package/dist/src/math/Mat33.js +1 -1
- package/dist/src/rendering/Display.d.ts +9 -11
- package/dist/src/rendering/Display.js +12 -14
- package/dist/src/rendering/lib.d.ts +3 -0
- package/dist/src/rendering/lib.js +3 -0
- package/dist/src/rendering/renderers/DummyRenderer.js +2 -2
- package/dist/src/rendering/renderers/SVGRenderer.js +4 -0
- package/dist/src/toolbar/HTMLToolbar.d.ts +51 -0
- package/dist/src/toolbar/HTMLToolbar.js +63 -5
- package/dist/src/toolbar/IconProvider.d.ts +2 -2
- package/dist/src/toolbar/IconProvider.js +123 -35
- package/dist/src/toolbar/widgets/EraserToolWidget.d.ts +8 -1
- package/dist/src/toolbar/widgets/EraserToolWidget.js +45 -4
- package/dist/src/toolbar/widgets/PenToolWidget.js +2 -2
- package/dist/src/toolbar/widgets/SelectionToolWidget.js +12 -3
- package/dist/src/tools/Eraser.d.ts +10 -1
- package/dist/src/tools/Eraser.js +65 -13
- package/dist/src/tools/PanZoom.js +1 -1
- package/dist/src/tools/PasteHandler.d.ts +11 -4
- package/dist/src/tools/PasteHandler.js +12 -5
- package/dist/src/tools/Pen.d.ts +7 -2
- package/dist/src/tools/Pen.js +39 -6
- package/dist/src/tools/SelectionTool/Selection.d.ts +4 -1
- package/dist/src/tools/SelectionTool/Selection.js +64 -27
- package/dist/src/tools/SelectionTool/SelectionHandle.d.ts +3 -0
- package/dist/src/tools/SelectionTool/SelectionHandle.js +6 -0
- package/dist/src/tools/SelectionTool/SelectionTool.d.ts +3 -1
- package/dist/src/tools/SelectionTool/SelectionTool.js +56 -16
- package/dist/src/tools/TextTool.js +10 -6
- package/dist/src/tools/ToolSwitcherShortcut.d.ts +8 -0
- package/dist/src/tools/ToolSwitcherShortcut.js +9 -3
- package/dist/src/tools/UndoRedoShortcut.js +2 -4
- package/dist/src/types.d.ts +2 -2
- package/package.json +2 -2
- package/src/Color4.test.ts +11 -0
- package/src/Color4.ts +23 -0
- package/src/Editor.ts +39 -26
- package/src/EditorImage.ts +12 -0
- package/src/Pointer.ts +19 -0
- package/src/SVGLoader.ts +20 -15
- package/src/Viewport.ts +50 -11
- package/src/commands/invertCommand.ts +1 -1
- package/src/components/AbstractComponent.ts +52 -2
- package/src/lib.ts +6 -3
- package/src/math/Mat33.ts +1 -1
- package/src/rendering/Display.ts +12 -15
- package/src/rendering/RenderingStyle.ts +1 -1
- package/src/rendering/lib.ts +4 -0
- package/src/rendering/renderers/DummyRenderer.ts +2 -3
- package/src/rendering/renderers/SVGRenderer.ts +4 -0
- package/src/rendering/renderers/TextOnlyRenderer.ts +0 -1
- package/src/toolbar/HTMLToolbar.ts +81 -5
- package/src/toolbar/IconProvider.ts +132 -37
- package/src/toolbar/widgets/EraserToolWidget.ts +64 -5
- package/src/toolbar/widgets/PenToolWidget.ts +2 -2
- package/src/toolbar/widgets/SelectionToolWidget.ts +2 -2
- package/src/tools/Eraser.test.ts +79 -0
- package/src/tools/Eraser.ts +81 -17
- package/src/tools/PanZoom.ts +1 -1
- package/src/tools/PasteHandler.ts +12 -6
- package/src/tools/Pen.test.ts +44 -1
- package/src/tools/Pen.ts +53 -8
- package/src/tools/SelectionTool/Selection.ts +73 -23
- package/src/tools/SelectionTool/SelectionHandle.ts +9 -0
- package/src/tools/SelectionTool/SelectionTool.test.ts +138 -21
- package/src/tools/SelectionTool/SelectionTool.ts +70 -16
- package/src/tools/TextTool.ts +14 -8
- package/src/tools/ToolSwitcherShortcut.ts +10 -5
- package/src/tools/UndoRedoShortcut.ts +2 -5
- package/src/types.ts +2 -2
- package/typedoc.json +2 -2
package/src/Viewport.ts
CHANGED
@@ -92,26 +92,30 @@ export class Viewport {
|
|
92
92
|
this.screenRect = this.screenRect.resizedTo(screenSize);
|
93
93
|
}
|
94
94
|
|
95
|
-
|
95
|
+
/** Get the screen's visible region transformed into canvas space. */
|
96
96
|
public get visibleRect(): Rect2 {
|
97
97
|
return this.screenRect.transformedBoundingBox(this.inverseTransform);
|
98
98
|
}
|
99
99
|
|
100
|
-
|
100
|
+
/** @returns the given point, but in canvas coordinates */
|
101
101
|
public screenToCanvas(screenPoint: Point2): Point2 {
|
102
102
|
return this.inverseTransform.transformVec2(screenPoint);
|
103
103
|
}
|
104
104
|
|
105
|
+
/** @returns the given point transformed into screen coordinates. */
|
105
106
|
public canvasToScreen(canvasPoint: Point2): Point2 {
|
106
107
|
return this.transform.transformVec2(canvasPoint);
|
107
108
|
}
|
108
109
|
|
110
|
+
/** @returns a command that transforms the canvas by `transform`. */
|
109
111
|
public static transformBy(transform: Mat33): ViewportTransform {
|
110
112
|
return new Viewport.ViewportTransform(transform);
|
111
113
|
}
|
112
114
|
|
113
|
-
|
114
|
-
|
115
|
+
/**
|
116
|
+
* Updates the transformation directly. Using `transformBy` is preferred.
|
117
|
+
* @param newTransform - should map from canvas coordinates to screen coordinates.
|
118
|
+
*/
|
115
119
|
public resetTransform(newTransform: Mat33 = Mat33.identity) {
|
116
120
|
const oldTransform = this.transform;
|
117
121
|
this.transform = newTransform;
|
@@ -131,29 +135,64 @@ export class Viewport {
|
|
131
135
|
return this.transform;
|
132
136
|
}
|
133
137
|
|
134
|
-
|
138
|
+
/** @returns the size of the visible region in pixels. */
|
139
|
+
public getScreenRectSize(): Vec2 {
|
135
140
|
return this.screenRect.size;
|
136
141
|
}
|
137
142
|
|
138
|
-
|
143
|
+
/** Alias for `getScreenRectSize`. @deprecated */
|
144
|
+
public getResolution() {
|
145
|
+
return this.getScreenRectSize();
|
146
|
+
}
|
147
|
+
|
148
|
+
/** @returns the amount a vector on the canvas is scaled to become a vector on the screen. */
|
139
149
|
public getScaleFactor(): number {
|
140
150
|
// Use transformVec3 to avoid translating the vector
|
141
151
|
return this.transform.transformVec3(Vec3.unitX).magnitude();
|
142
152
|
}
|
143
153
|
|
144
|
-
|
154
|
+
/**
|
155
|
+
* @returns `getScaleFactor()` rounded to the nearest power of 10.
|
156
|
+
* For example, if `getScaleFactor()` returns 101, `getScaleFactorToNearestPowerOfTen()`
|
157
|
+
* should return `100` because `100` is the nearest power of 10 to 101.
|
158
|
+
*/
|
159
|
+
public getScaleFactorToNearestPowerOfTen() {
|
160
|
+
const scaleFactor = this.getScaleFactor();
|
161
|
+
return Math.pow(10, Math.round(Math.log10(scaleFactor)));
|
162
|
+
}
|
163
|
+
|
164
|
+
public snapToGrid(canvasPos: Point2) {
|
165
|
+
const snapCoordinate = (coordinate: number) => {
|
166
|
+
const scaleFactor = this.getScaleFactorToNearestPowerOfTen();
|
167
|
+
const roundFactor = scaleFactor / 100;
|
168
|
+
const snapped = Math.round(coordinate * roundFactor) / roundFactor;
|
169
|
+
|
170
|
+
return snapped;
|
171
|
+
};
|
172
|
+
|
173
|
+
const snappedCanvasPos = Vec2.of(
|
174
|
+
snapCoordinate(canvasPos.x), snapCoordinate(canvasPos.y)
|
175
|
+
);
|
176
|
+
return snappedCanvasPos;
|
177
|
+
}
|
178
|
+
|
179
|
+
/** Returns the size of one screen pixel in canvas units. */
|
145
180
|
public getSizeOfPixelOnCanvas(): number {
|
146
181
|
return 1/this.getScaleFactor();
|
147
182
|
}
|
148
183
|
|
149
|
-
|
150
|
-
|
184
|
+
/**
|
185
|
+
* @returns the angle of the canvas in radians.
|
186
|
+
* This is the angle by which the canvas is rotated relative to the screen.
|
187
|
+
*/
|
151
188
|
public getRotationAngle(): number {
|
152
189
|
return this.transform.transformVec3(Vec3.unitX).angle();
|
153
190
|
}
|
154
191
|
|
155
|
-
|
156
|
-
|
192
|
+
/**
|
193
|
+
* Rounds the given `point` to a multiple of 10 such that it is within `tolerance` of
|
194
|
+
* its original location. This is useful for preparing data for base-10 conversion.
|
195
|
+
*/
|
157
196
|
public static roundPoint<T extends Point2|number>(
|
158
197
|
point: T, tolerance: number,
|
159
198
|
): PointDataType<T>;
|
@@ -3,7 +3,7 @@ import { EditorLocalization } from '../localization';
|
|
3
3
|
import Command from './Command';
|
4
4
|
import SerializableCommand from './SerializableCommand';
|
5
5
|
|
6
|
-
// Returns a command
|
6
|
+
// Returns a command that does the opposite of the given command --- `result.apply()` calls
|
7
7
|
// `command.unapply()` and `result.unapply()` calls `command.apply()`.
|
8
8
|
const invertCommand = <T extends Command> (command: T): T extends SerializableCommand ? SerializableCommand : Command => {
|
9
9
|
if (command instanceof SerializableCommand) {
|
@@ -13,9 +13,20 @@ export type LoadSaveDataTable = Record<string, Array<LoadSaveData>>;
|
|
13
13
|
export type DeserializeCallback = (data: string)=>AbstractComponent;
|
14
14
|
type ComponentId = string;
|
15
15
|
|
16
|
+
/**
|
17
|
+
* A base class for everything that can be added to an {@link EditorImage}.
|
18
|
+
*/
|
16
19
|
export default abstract class AbstractComponent {
|
20
|
+
// The timestamp (milliseconds) at which the component was
|
21
|
+
// last changed (i.e. created/translated).
|
22
|
+
// @deprecated
|
17
23
|
protected lastChangedTime: number;
|
24
|
+
|
25
|
+
// The bounding box of this component.
|
26
|
+
// {@link getBBox}, by default, returns `contentBBox`.
|
27
|
+
// This must be set by components.
|
18
28
|
protected abstract contentBBox: Rect2;
|
29
|
+
|
19
30
|
private zIndex: number;
|
20
31
|
private id: string;
|
21
32
|
|
@@ -38,7 +49,7 @@ export default abstract class AbstractComponent {
|
|
38
49
|
}
|
39
50
|
|
40
51
|
// Returns a unique ID for this element.
|
41
|
-
// @see { @link EditorImage
|
52
|
+
// @see { @link lib!EditorImage.lookupElement }
|
42
53
|
public getId() {
|
43
54
|
return this.id;
|
44
55
|
}
|
@@ -55,14 +66,22 @@ export default abstract class AbstractComponent {
|
|
55
66
|
this.deserializationCallbacks[componentKind] = deserialize ?? null;
|
56
67
|
}
|
57
68
|
|
58
|
-
//
|
69
|
+
// Stores data attached by a loader.
|
59
70
|
private loadSaveData: LoadSaveDataTable = {};
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Attach data that can be used while exporting the component (e.g. to SVG).
|
74
|
+
*
|
75
|
+
* This is intended for use by a {@link ImageLoader}.
|
76
|
+
*/
|
60
77
|
public attachLoadSaveData(key: string, data: LoadSaveData) {
|
61
78
|
if (!this.loadSaveData[key]) {
|
62
79
|
this.loadSaveData[key] = [];
|
63
80
|
}
|
64
81
|
this.loadSaveData[key].push(data);
|
65
82
|
}
|
83
|
+
|
84
|
+
/** See {@link attachLoadSaveData} */
|
66
85
|
public getLoadSaveData(): LoadSaveDataTable {
|
67
86
|
return this.loadSaveData;
|
68
87
|
}
|
@@ -71,13 +90,39 @@ export default abstract class AbstractComponent {
|
|
71
90
|
return this.zIndex;
|
72
91
|
}
|
73
92
|
|
93
|
+
/** @returns the bounding box of */
|
74
94
|
public getBBox(): Rect2 {
|
75
95
|
return this.contentBBox;
|
76
96
|
}
|
77
97
|
|
78
98
|
public abstract render(canvas: AbstractRenderer, visibleRect?: Rect2): void;
|
99
|
+
|
100
|
+
/** @return true if `lineSegment` intersects this component. */
|
79
101
|
public abstract intersects(lineSegment: LineSegment2): boolean;
|
80
102
|
|
103
|
+
/**
|
104
|
+
* @returns true if this component intersects `rect` -- it is entirely contained
|
105
|
+
* within the rectangle or one of the rectangle's edges intersects this component.
|
106
|
+
*/
|
107
|
+
public intersectsRect(rect: Rect2): boolean {
|
108
|
+
// If this component intersects rect,
|
109
|
+
// it is either contained entirely within rect or intersects one of rect's edges.
|
110
|
+
|
111
|
+
// If contained within,
|
112
|
+
if (rect.containsRect(this.getBBox())) {
|
113
|
+
return true;
|
114
|
+
}
|
115
|
+
|
116
|
+
// Calculated bounding boxes can be slightly larger than their actual contents' bounding box.
|
117
|
+
// As such, test with more lines than just the rect's edges.
|
118
|
+
const testLines = [];
|
119
|
+
for (const subregion of rect.divideIntoGrid(2, 2)) {
|
120
|
+
testLines.push(...subregion.getEdges());
|
121
|
+
}
|
122
|
+
|
123
|
+
return testLines.some(edge => this.intersects(edge));
|
124
|
+
}
|
125
|
+
|
81
126
|
// Return null iff this object cannot be safely serialized/deserialized.
|
82
127
|
protected abstract serializeToJSON(): any[]|Record<string, any>|number|string|null;
|
83
128
|
|
@@ -181,6 +226,7 @@ export default abstract class AbstractComponent {
|
|
181
226
|
}
|
182
227
|
|
183
228
|
this.component.applyTransformation(newTransfm);
|
229
|
+
this.component.lastChangedTime = (new Date()).getTime();
|
184
230
|
|
185
231
|
// Add the element back to the document.
|
186
232
|
if (hadParent) {
|
@@ -231,6 +277,10 @@ export default abstract class AbstractComponent {
|
|
231
277
|
}
|
232
278
|
};
|
233
279
|
|
280
|
+
/**
|
281
|
+
* @return a description that could be read by a screen reader
|
282
|
+
* (e.g. when adding/erasing the component)
|
283
|
+
*/
|
234
284
|
public abstract description(localizationTable: ImageComponentLocalization): string;
|
235
285
|
|
236
286
|
// Component-specific implementation of {@link clone}.
|
package/src/lib.ts
CHANGED
@@ -8,25 +8,28 @@
|
|
8
8
|
* ```
|
9
9
|
*
|
10
10
|
* @see
|
11
|
-
* {@link Editor
|
11
|
+
* {@link Editor}
|
12
12
|
*
|
13
13
|
* @packageDocumentation
|
14
14
|
*/
|
15
15
|
|
16
|
-
import Editor from './Editor';
|
16
|
+
import Editor, { EditorSettings } from './Editor';
|
17
17
|
export { default as EditorImage } from './EditorImage';
|
18
18
|
export * from './types';
|
19
19
|
export { default as getLocalizationTable } from './localizations/getLocalizationTable';
|
20
20
|
export * from './localization';
|
21
21
|
|
22
22
|
export { default as Color4 } from './Color4';
|
23
|
+
export { default as SVGLoader } from './SVGLoader';
|
24
|
+
export { default as Viewport } from './Viewport';
|
23
25
|
export * from './math/lib';
|
24
26
|
export * from './components/lib';
|
25
27
|
export * from './commands/lib';
|
26
28
|
export * from './tools/lib';
|
27
29
|
export * from './toolbar/lib';
|
30
|
+
export * from './rendering/lib';
|
28
31
|
export { default as Pointer, PointerDevice } from './Pointer';
|
29
32
|
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
|
30
33
|
|
31
|
-
export { Editor };
|
34
|
+
export { Editor, EditorSettings };
|
32
35
|
export default Editor;
|
package/src/math/Mat33.ts
CHANGED
@@ -338,7 +338,7 @@ export default class Mat33 {
|
|
338
338
|
return result.rightMul(Mat33.translation(center.times(-1)));
|
339
339
|
}
|
340
340
|
|
341
|
-
/** @see {@link
|
341
|
+
/** @see {@link fromCSSMatrix} */
|
342
342
|
public toCSSMatrix(): string {
|
343
343
|
return `matrix(${this.a1},${this.b1},${this.a2},${this.b2},${this.a3},${this.b3})`;
|
344
344
|
}
|
package/src/rendering/Display.ts
CHANGED
@@ -1,18 +1,3 @@
|
|
1
|
-
/**
|
2
|
-
* Handles `HTMLCanvasElement`s (or other drawing surfaces if being used) used to display the editor's contents.
|
3
|
-
*
|
4
|
-
* @example
|
5
|
-
* ```
|
6
|
-
* const editor = new Editor(document.body);
|
7
|
-
* const w = editor.display.width;
|
8
|
-
* const h = editor.display.height;
|
9
|
-
* const center = Vec2.of(w / 2, h / 2);
|
10
|
-
* const colorAtCenter = editor.display.getColorAt(center);
|
11
|
-
* ```
|
12
|
-
*
|
13
|
-
* @packageDocumentation
|
14
|
-
*/
|
15
|
-
|
16
1
|
import AbstractRenderer from './renderers/AbstractRenderer';
|
17
2
|
import CanvasRenderer from './renderers/CanvasRenderer';
|
18
3
|
import { Editor } from '../Editor';
|
@@ -29,6 +14,18 @@ export enum RenderingMode {
|
|
29
14
|
// SVGRenderer is not supported by the main display
|
30
15
|
}
|
31
16
|
|
17
|
+
/**
|
18
|
+
* Handles `HTMLCanvasElement`s (or other drawing surfaces if being used) used to display the editor's contents.
|
19
|
+
*
|
20
|
+
* @example
|
21
|
+
* ```
|
22
|
+
* const editor = new Editor(document.body);
|
23
|
+
* const w = editor.display.width;
|
24
|
+
* const h = editor.display.height;
|
25
|
+
* const center = Vec2.of(w / 2, h / 2);
|
26
|
+
* const colorAtCenter = editor.display.getColorAt(center);
|
27
|
+
* ```
|
28
|
+
*/
|
32
29
|
export default class Display {
|
33
30
|
private dryInkRenderer: AbstractRenderer;
|
34
31
|
private wetInkRenderer: AbstractRenderer;
|
@@ -13,7 +13,7 @@ export default RenderingStyle;
|
|
13
13
|
export const stylesEqual = (a: RenderingStyle, b: RenderingStyle): boolean => {
|
14
14
|
const result = a === b || (a.fill.eq(b.fill)
|
15
15
|
&& (a.stroke == undefined) === (b.stroke == undefined)
|
16
|
-
|
16
|
+
&& (a.stroke?.color?.eq(b.stroke?.color) ?? true)
|
17
17
|
&& a.stroke?.width === b.stroke?.width);
|
18
18
|
|
19
19
|
// Map undefined/null -> false
|
@@ -1,5 +1,3 @@
|
|
1
|
-
// Renderer that outputs nothing. Useful for automated tests.
|
2
|
-
|
3
1
|
import { TextStyle } from '../../components/TextComponent';
|
4
2
|
import Mat33 from '../../math/Mat33';
|
5
3
|
import Rect2 from '../../math/Rect2';
|
@@ -9,6 +7,7 @@ import Viewport from '../../Viewport';
|
|
9
7
|
import RenderingStyle from '../RenderingStyle';
|
10
8
|
import AbstractRenderer, { RenderableImage } from './AbstractRenderer';
|
11
9
|
|
10
|
+
// Renderer that outputs almost nothing. Useful for automated tests.
|
12
11
|
export default class DummyRenderer extends AbstractRenderer {
|
13
12
|
// Variables that track the state of what's been rendered
|
14
13
|
public clearedCount: number = 0;
|
@@ -28,7 +27,7 @@ export default class DummyRenderer extends AbstractRenderer {
|
|
28
27
|
|
29
28
|
public displaySize(): Vec2 {
|
30
29
|
// Do we have a stored viewport size?
|
31
|
-
const viewportSize = this.getViewport().
|
30
|
+
const viewportSize = this.getViewport().getScreenRectSize();
|
32
31
|
|
33
32
|
// Don't use a 0x0 viewport — DummyRenderer is often used
|
34
33
|
// for tests that run without a display, so pretend we have a
|
@@ -38,6 +38,10 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
38
38
|
stroke-linecap: round;
|
39
39
|
stroke-linejoin: round;
|
40
40
|
}
|
41
|
+
|
42
|
+
text {
|
43
|
+
white-space: pre;
|
44
|
+
}
|
41
45
|
`.replace(/\s+/g, '');
|
42
46
|
styleSheet.setAttribute('id', renderedStylesheetId);
|
43
47
|
this.elem.appendChild(styleSheet);
|
@@ -9,7 +9,6 @@ import RenderingStyle from '../RenderingStyle';
|
|
9
9
|
import AbstractRenderer, { RenderableImage } from './AbstractRenderer';
|
10
10
|
|
11
11
|
// Outputs a description of what was rendered.
|
12
|
-
|
13
12
|
export default class TextOnlyRenderer extends AbstractRenderer {
|
14
13
|
private descriptionBuilder: string[] = [];
|
15
14
|
private pathCount: number = 0;
|
@@ -16,12 +16,25 @@ import SelectionToolWidget from './widgets/SelectionToolWidget';
|
|
16
16
|
import TextToolWidget from './widgets/TextToolWidget';
|
17
17
|
import HandToolWidget from './widgets/HandToolWidget';
|
18
18
|
import BaseWidget from './widgets/BaseWidget';
|
19
|
-
import
|
19
|
+
import ActionButtonWidget from './widgets/ActionButtonWidget';
|
20
|
+
import InsertImageWidget from './widgets/InsertImageWidget';
|
20
21
|
|
21
22
|
export const toolbarCSSPrefix = 'toolbar-';
|
22
23
|
|
23
24
|
type UpdateColorisCallback = ()=>void;
|
24
25
|
|
26
|
+
interface SpacerOptions {
|
27
|
+
// Defaults to 0. If a non-zero number, determines the rate at which the
|
28
|
+
// spacer should grow (like flexGrow).
|
29
|
+
grow: number;
|
30
|
+
|
31
|
+
// Minimum size (e.g. "23px")
|
32
|
+
minSize: string;
|
33
|
+
|
34
|
+
// Maximum size (e.g. "50px")
|
35
|
+
maxSize: string;
|
36
|
+
}
|
37
|
+
|
25
38
|
export default class HTMLToolbar {
|
26
39
|
private container: HTMLElement;
|
27
40
|
|
@@ -121,8 +134,17 @@ export default class HTMLToolbar {
|
|
121
134
|
});
|
122
135
|
}
|
123
136
|
|
124
|
-
|
125
|
-
|
137
|
+
/**
|
138
|
+
* Adds an `ActionButtonWidget` or `BaseToolWidget`. The widget should not have already have a parent
|
139
|
+
* (i.e. its `addTo` method should not have been called).
|
140
|
+
*
|
141
|
+
* @example
|
142
|
+
* ```ts
|
143
|
+
* const toolbar = editor.addToolbar();
|
144
|
+
* const insertImageWidget = new InsertImageWidget(editor);
|
145
|
+
* toolbar.addWidget(insertImageWidget);
|
146
|
+
* ```
|
147
|
+
*/
|
126
148
|
public addWidget(widget: BaseWidget) {
|
127
149
|
// Prevent name collisions
|
128
150
|
const id = widget.getUniqueIdIn(this.widgets);
|
@@ -135,6 +157,46 @@ export default class HTMLToolbar {
|
|
135
157
|
this.setupColorPickers();
|
136
158
|
}
|
137
159
|
|
160
|
+
/**
|
161
|
+
* Adds a spacer.
|
162
|
+
*
|
163
|
+
* @example
|
164
|
+
* Adding a save button that moves to the very right edge of the toolbar
|
165
|
+
* while keeping the other buttons centered:
|
166
|
+
* ```ts
|
167
|
+
* const toolbar = editor.addToolbar(false);
|
168
|
+
*
|
169
|
+
* toolbar.addSpacer({ grow: 1 });
|
170
|
+
* toolbar.addDefaults();
|
171
|
+
* toolbar.addSpacer({ grow: 1 });
|
172
|
+
*
|
173
|
+
* toolbar.addActionButton({
|
174
|
+
* label: 'Save',
|
175
|
+
* icon: editor.icons.makeSaveIcon(),
|
176
|
+
* }, () => {
|
177
|
+
* saveCallback();
|
178
|
+
* });
|
179
|
+
* ```
|
180
|
+
*/
|
181
|
+
public addSpacer(options: Partial<SpacerOptions> = {}) {
|
182
|
+
const spacer = document.createElement('div');
|
183
|
+
spacer.classList.add(`${toolbarCSSPrefix}spacer`);
|
184
|
+
|
185
|
+
if (options.grow) {
|
186
|
+
spacer.style.flexGrow = `${options.grow}`;
|
187
|
+
}
|
188
|
+
|
189
|
+
if (options.minSize) {
|
190
|
+
spacer.style.minWidth = options.minSize;
|
191
|
+
}
|
192
|
+
|
193
|
+
if (options.maxSize) {
|
194
|
+
spacer.style.maxWidth = options.maxSize;
|
195
|
+
}
|
196
|
+
|
197
|
+
this.container.appendChild(spacer);
|
198
|
+
}
|
199
|
+
|
138
200
|
public serializeState(): string {
|
139
201
|
const result: Record<string, any> = {};
|
140
202
|
|
@@ -145,8 +207,10 @@ export default class HTMLToolbar {
|
|
145
207
|
return JSON.stringify(result);
|
146
208
|
}
|
147
209
|
|
148
|
-
|
149
|
-
|
210
|
+
/**
|
211
|
+
* Deserialize toolbar widgets from the given state.
|
212
|
+
* Assumes that toolbar widgets are in the same order as when state was serialized.
|
213
|
+
*/
|
150
214
|
public deserializeState(state: string) {
|
151
215
|
const data = JSON.parse(state);
|
152
216
|
|
@@ -247,4 +311,16 @@ export default class HTMLToolbar {
|
|
247
311
|
public addDefaultActionButtons() {
|
248
312
|
this.addUndoRedoButtons();
|
249
313
|
}
|
314
|
+
|
315
|
+
/**
|
316
|
+
* Adds both the default tool widgets and action buttons. Equivalent to
|
317
|
+
* ```ts
|
318
|
+
* toolbar.addDefaultToolWidgets();
|
319
|
+
* toolbar.addDefaultActionButtons();
|
320
|
+
* ```
|
321
|
+
*/
|
322
|
+
public addDefaults() {
|
323
|
+
this.addDefaultToolWidgets();
|
324
|
+
this.addDefaultActionButtons();
|
325
|
+
}
|
250
326
|
}
|