js-draw 0.16.1 → 0.17.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 +9 -0
- package/dist/bundle.js +1 -1
- package/dist/src/Editor.js +2 -1
- package/dist/src/EditorImage.js +12 -5
- package/dist/src/UndoRedoHistory.d.ts +2 -3
- package/dist/src/UndoRedoHistory.js +37 -20
- package/dist/src/components/RestylableComponent.js +2 -2
- package/dist/src/components/localization.d.ts +1 -1
- package/dist/src/components/localization.js +1 -1
- package/dist/src/lib.d.ts +1 -0
- package/dist/src/lib.js +1 -0
- package/dist/src/toolbar/widgets/OverflowWidget.js +6 -0
- package/dist/src/types.d.ts +7 -0
- package/dist/src/types.js +7 -0
- package/package.json +1 -1
- package/src/Editor.ts +3 -1
- package/src/EditorImage.ts +11 -6
- package/src/UndoRedoHistory.ts +28 -23
- package/src/components/RestylableComponent.ts +2 -2
- package/src/components/localization.ts +2 -2
- package/src/lib.ts +1 -0
- package/src/toolbar/toolbar.css +7 -1
- package/src/toolbar/widgets/OverflowWidget.css +20 -2
- package/src/toolbar/widgets/OverflowWidget.ts +9 -0
- package/src/types.ts +11 -1
package/dist/src/Editor.js
CHANGED
@@ -503,11 +503,12 @@ export class Editor {
|
|
503
503
|
* ```
|
504
504
|
*/
|
505
505
|
dispatchNoAnnounce(command, addToHistory = false) {
|
506
|
+
const result = command.apply(this);
|
506
507
|
if (addToHistory) {
|
507
508
|
const apply = false; // Don't double-apply
|
508
509
|
this.history.push(command, apply);
|
509
510
|
}
|
510
|
-
return
|
511
|
+
return result;
|
511
512
|
}
|
512
513
|
/**
|
513
514
|
* Apply a large transformation in chunks.
|
package/dist/src/EditorImage.js
CHANGED
@@ -172,9 +172,13 @@ EditorImage.AddElementCommand = (_a = class extends SerializableCommand {
|
|
172
172
|
super('add-element');
|
173
173
|
this.element = element;
|
174
174
|
this.applyByFlattening = applyByFlattening;
|
175
|
-
|
176
|
-
//
|
177
|
-
this
|
175
|
+
this.serializedElem = null;
|
176
|
+
// FIXME: The serialized version of this command may be inaccurate if this is
|
177
|
+
// serialized when this command is not on the top of the undo stack.
|
178
|
+
//
|
179
|
+
// Caching the element's serialized data leads to additional memory usage *and*
|
180
|
+
// sometimes incorrect behavior in collaborative editing.
|
181
|
+
this.serializedElem = null;
|
178
182
|
if (isNaN(element.getBBox().area)) {
|
179
183
|
throw new Error('Elements in the image cannot have NaN bounding boxes');
|
180
184
|
}
|
@@ -197,8 +201,9 @@ EditorImage.AddElementCommand = (_a = class extends SerializableCommand {
|
|
197
201
|
return localization.addElementAction(this.element.description(localization));
|
198
202
|
}
|
199
203
|
serializeToJSON() {
|
204
|
+
var _a;
|
200
205
|
return {
|
201
|
-
elemData: this.serializedElem,
|
206
|
+
elemData: (_a = this.serializedElem) !== null && _a !== void 0 ? _a : this.element.serialize(),
|
202
207
|
};
|
203
208
|
}
|
204
209
|
},
|
@@ -207,7 +212,9 @@ EditorImage.AddElementCommand = (_a = class extends SerializableCommand {
|
|
207
212
|
const id = json.elemData.id;
|
208
213
|
const foundElem = editor.image.lookupElement(id);
|
209
214
|
const elem = foundElem !== null && foundElem !== void 0 ? foundElem : AbstractComponent.deserialize(json.elemData);
|
210
|
-
|
215
|
+
const result = new EditorImage.AddElementCommand(elem);
|
216
|
+
result.serializedElem = json.elemData;
|
217
|
+
return result;
|
211
218
|
});
|
212
219
|
})(),
|
213
220
|
_a);
|
@@ -3,12 +3,11 @@ import Command from './commands/Command';
|
|
3
3
|
type AnnounceRedoCallback = (command: Command) => void;
|
4
4
|
type AnnounceUndoCallback = (command: Command) => void;
|
5
5
|
declare class UndoRedoHistory {
|
6
|
+
#private;
|
6
7
|
private readonly editor;
|
7
8
|
private announceRedoCallback;
|
8
9
|
private announceUndoCallback;
|
9
|
-
private
|
10
|
-
private redoStack;
|
11
|
-
private maxUndoRedoStackSize;
|
10
|
+
private readonly maxUndoRedoStackSize;
|
12
11
|
constructor(editor: Editor, announceRedoCallback: AnnounceRedoCallback, announceUndoCallback: AnnounceUndoCallback);
|
13
12
|
private fireUpdateEvent;
|
14
13
|
push(command: Command, apply?: boolean): void;
|
@@ -1,19 +1,35 @@
|
|
1
|
-
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
6
|
+
};
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
11
|
+
};
|
12
|
+
var _UndoRedoHistory_undoStack, _UndoRedoHistory_redoStack;
|
13
|
+
import { EditorEventType, UndoEventType } from './types';
|
2
14
|
class UndoRedoHistory {
|
3
15
|
// @internal
|
4
16
|
constructor(editor, announceRedoCallback, announceUndoCallback) {
|
5
17
|
this.editor = editor;
|
6
18
|
this.announceRedoCallback = announceRedoCallback;
|
7
19
|
this.announceUndoCallback = announceUndoCallback;
|
20
|
+
_UndoRedoHistory_undoStack.set(this, void 0);
|
21
|
+
_UndoRedoHistory_redoStack.set(this, void 0);
|
8
22
|
this.maxUndoRedoStackSize = 700;
|
9
|
-
this
|
10
|
-
this
|
23
|
+
__classPrivateFieldSet(this, _UndoRedoHistory_undoStack, [], "f");
|
24
|
+
__classPrivateFieldSet(this, _UndoRedoHistory_redoStack, [], "f");
|
11
25
|
}
|
12
|
-
fireUpdateEvent() {
|
26
|
+
fireUpdateEvent(stackUpdateType, triggeringCommand) {
|
13
27
|
this.editor.notifier.dispatch(EditorEventType.UndoRedoStackUpdated, {
|
14
28
|
kind: EditorEventType.UndoRedoStackUpdated,
|
15
|
-
undoStackSize: this.
|
16
|
-
redoStackSize: this.
|
29
|
+
undoStackSize: __classPrivateFieldGet(this, _UndoRedoHistory_undoStack, "f").length,
|
30
|
+
redoStackSize: __classPrivateFieldGet(this, _UndoRedoHistory_redoStack, "f").length,
|
31
|
+
command: triggeringCommand,
|
32
|
+
stackUpdateType,
|
17
33
|
});
|
18
34
|
}
|
19
35
|
// Adds the given command to this and applies it to the editor.
|
@@ -21,17 +37,17 @@ class UndoRedoHistory {
|
|
21
37
|
if (apply) {
|
22
38
|
command.apply(this.editor);
|
23
39
|
}
|
24
|
-
this.
|
25
|
-
for (const elem of this
|
40
|
+
__classPrivateFieldGet(this, _UndoRedoHistory_undoStack, "f").push(command);
|
41
|
+
for (const elem of __classPrivateFieldGet(this, _UndoRedoHistory_redoStack, "f")) {
|
26
42
|
elem.onDrop(this.editor);
|
27
43
|
}
|
28
|
-
this
|
29
|
-
if (this.
|
44
|
+
__classPrivateFieldSet(this, _UndoRedoHistory_redoStack, [], "f");
|
45
|
+
if (__classPrivateFieldGet(this, _UndoRedoHistory_undoStack, "f").length > this.maxUndoRedoStackSize) {
|
30
46
|
const removeAtOnceCount = 10;
|
31
|
-
const removedElements = this.
|
47
|
+
const removedElements = __classPrivateFieldGet(this, _UndoRedoHistory_undoStack, "f").splice(0, removeAtOnceCount);
|
32
48
|
removedElements.forEach(elem => elem.onDrop(this.editor));
|
33
49
|
}
|
34
|
-
this.fireUpdateEvent();
|
50
|
+
this.fireUpdateEvent(UndoEventType.CommandDone, command);
|
35
51
|
this.editor.notifier.dispatch(EditorEventType.CommandDone, {
|
36
52
|
kind: EditorEventType.CommandDone,
|
37
53
|
command,
|
@@ -39,12 +55,12 @@ class UndoRedoHistory {
|
|
39
55
|
}
|
40
56
|
// Remove the last command from this' undo stack and apply it.
|
41
57
|
undo() {
|
42
|
-
const command = this.
|
58
|
+
const command = __classPrivateFieldGet(this, _UndoRedoHistory_undoStack, "f").pop();
|
43
59
|
if (command) {
|
44
|
-
this.
|
60
|
+
__classPrivateFieldGet(this, _UndoRedoHistory_redoStack, "f").push(command);
|
45
61
|
command.unapply(this.editor);
|
46
62
|
this.announceUndoCallback(command);
|
47
|
-
this.fireUpdateEvent();
|
63
|
+
this.fireUpdateEvent(UndoEventType.CommandUndone, command);
|
48
64
|
this.editor.notifier.dispatch(EditorEventType.CommandUndone, {
|
49
65
|
kind: EditorEventType.CommandUndone,
|
50
66
|
command,
|
@@ -52,12 +68,12 @@ class UndoRedoHistory {
|
|
52
68
|
}
|
53
69
|
}
|
54
70
|
redo() {
|
55
|
-
const command = this.
|
71
|
+
const command = __classPrivateFieldGet(this, _UndoRedoHistory_redoStack, "f").pop();
|
56
72
|
if (command) {
|
57
|
-
this.
|
73
|
+
__classPrivateFieldGet(this, _UndoRedoHistory_undoStack, "f").push(command);
|
58
74
|
command.apply(this.editor);
|
59
75
|
this.announceRedoCallback(command);
|
60
|
-
this.fireUpdateEvent();
|
76
|
+
this.fireUpdateEvent(UndoEventType.CommandRedone, command);
|
61
77
|
this.editor.notifier.dispatch(EditorEventType.CommandDone, {
|
62
78
|
kind: EditorEventType.CommandDone,
|
63
79
|
command,
|
@@ -65,10 +81,11 @@ class UndoRedoHistory {
|
|
65
81
|
}
|
66
82
|
}
|
67
83
|
get undoStackSize() {
|
68
|
-
return this.
|
84
|
+
return __classPrivateFieldGet(this, _UndoRedoHistory_undoStack, "f").length;
|
69
85
|
}
|
70
86
|
get redoStackSize() {
|
71
|
-
return this.
|
87
|
+
return __classPrivateFieldGet(this, _UndoRedoHistory_redoStack, "f").length;
|
72
88
|
}
|
73
89
|
}
|
90
|
+
_UndoRedoHistory_undoStack = new WeakMap(), _UndoRedoHistory_redoStack = new WeakMap();
|
74
91
|
export default UndoRedoHistory;
|
@@ -56,8 +56,8 @@ class DefaultRestyleComponentCommand extends UnresolvedSerializableCommand {
|
|
56
56
|
unapply(editor) {
|
57
57
|
this.getComponent(editor).forceStyle(this.originalStyle, editor);
|
58
58
|
}
|
59
|
-
description(
|
60
|
-
return localizationTable.
|
59
|
+
description(editor, localizationTable) {
|
60
|
+
return localizationTable.restyledElement(this.getComponent(editor).description(localizationTable));
|
61
61
|
}
|
62
62
|
serializeToJSON() {
|
63
63
|
return {
|
@@ -6,6 +6,6 @@ export interface ImageComponentLocalization {
|
|
6
6
|
svgObject: string;
|
7
7
|
emptyBackground: string;
|
8
8
|
filledBackgroundWithColor: (color: string) => string;
|
9
|
-
|
9
|
+
restyledElement: (elementDescription: string) => string;
|
10
10
|
}
|
11
11
|
export declare const defaultComponentLocalization: ImageComponentLocalization;
|
@@ -2,9 +2,9 @@ export const defaultComponentLocalization = {
|
|
2
2
|
unlabeledImageNode: 'Unlabeled image node',
|
3
3
|
stroke: 'Stroke',
|
4
4
|
svgObject: 'SVG Object',
|
5
|
-
restyledElements: 'Restyled elements',
|
6
5
|
emptyBackground: 'Empty background',
|
7
6
|
filledBackgroundWithColor: (color) => `Filled background (${color})`,
|
8
7
|
text: (text) => `Text object: ${text}`,
|
9
8
|
imageNode: (description) => `Image: ${description}`,
|
9
|
+
restyledElement: (elementDescription) => `Restyled ${elementDescription}`,
|
10
10
|
};
|
package/dist/src/lib.d.ts
CHANGED
@@ -28,5 +28,6 @@ export * from './toolbar/lib';
|
|
28
28
|
export * from './rendering/lib';
|
29
29
|
export { default as Pointer, PointerDevice } from './Pointer';
|
30
30
|
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
|
31
|
+
export { default as UndoRedoHistory } from './UndoRedoHistory';
|
31
32
|
export { Editor, EditorSettings };
|
32
33
|
export default Editor;
|
package/dist/src/lib.js
CHANGED
@@ -28,5 +28,6 @@ export * from './toolbar/lib';
|
|
28
28
|
export * from './rendering/lib';
|
29
29
|
export { default as Pointer, PointerDevice } from './Pointer';
|
30
30
|
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
|
31
|
+
export { default as UndoRedoHistory } from './UndoRedoHistory';
|
31
32
|
export { Editor };
|
32
33
|
export default Editor;
|
@@ -4,6 +4,7 @@ export default class OverflowWidget extends BaseWidget {
|
|
4
4
|
var _a;
|
5
5
|
super(editor, 'overflow-widget', localizationTable);
|
6
6
|
this.overflowChildren = [];
|
7
|
+
this.container.classList.add('toolbar-overflow-widget');
|
7
8
|
// Make the dropdown openable
|
8
9
|
this.container.classList.add('dropdownShowable');
|
9
10
|
(_a = this.overflowContainer) !== null && _a !== void 0 ? _a : (this.overflowContainer = document.createElement('div'));
|
@@ -32,6 +33,7 @@ export default class OverflowWidget extends BaseWidget {
|
|
32
33
|
*/
|
33
34
|
clearChildren() {
|
34
35
|
this.overflowContainer.replaceChildren();
|
36
|
+
this.container.classList.remove('horizontal');
|
35
37
|
const overflowChildren = this.overflowChildren;
|
36
38
|
this.overflowChildren = [];
|
37
39
|
return overflowChildren;
|
@@ -56,6 +58,10 @@ export default class OverflowWidget extends BaseWidget {
|
|
56
58
|
this.overflowChildren.push(widget);
|
57
59
|
widget.addTo(this.overflowContainer);
|
58
60
|
widget.setIsToplevel(false);
|
61
|
+
// Switch to a horizontal layout if enough children
|
62
|
+
if (this.overflowChildren.length > 2) {
|
63
|
+
this.container.classList.add('horizontal');
|
64
|
+
}
|
59
65
|
}
|
60
66
|
// This always returns false.
|
61
67
|
// Don't try to move the overflow menu to itself.
|
package/dist/src/types.d.ts
CHANGED
@@ -85,6 +85,11 @@ export declare enum EditorEventType {
|
|
85
85
|
ColorPickerColorSelected = 10,
|
86
86
|
ToolbarDropdownShown = 11
|
87
87
|
}
|
88
|
+
export declare enum UndoEventType {
|
89
|
+
CommandDone = 0,
|
90
|
+
CommandUndone = 1,
|
91
|
+
CommandRedone = 2
|
92
|
+
}
|
88
93
|
type EditorToolEventType = EditorEventType.ToolEnabled | EditorEventType.ToolDisabled | EditorEventType.ToolUpdated;
|
89
94
|
export interface EditorToolEvent {
|
90
95
|
readonly kind: EditorToolEventType;
|
@@ -107,6 +112,8 @@ export interface EditorUndoStackUpdated {
|
|
107
112
|
readonly kind: EditorEventType.UndoRedoStackUpdated;
|
108
113
|
readonly undoStackSize: number;
|
109
114
|
readonly redoStackSize: number;
|
115
|
+
readonly command?: Command;
|
116
|
+
readonly stackUpdateType: UndoEventType;
|
110
117
|
}
|
111
118
|
export interface CommandDoneEvent {
|
112
119
|
readonly kind: EditorEventType.CommandDone;
|
package/dist/src/types.js
CHANGED
@@ -26,3 +26,10 @@ export var EditorEventType;
|
|
26
26
|
EditorEventType[EditorEventType["ColorPickerColorSelected"] = 10] = "ColorPickerColorSelected";
|
27
27
|
EditorEventType[EditorEventType["ToolbarDropdownShown"] = 11] = "ToolbarDropdownShown";
|
28
28
|
})(EditorEventType || (EditorEventType = {}));
|
29
|
+
// Types of `EditorUndoStackUpdated` events.
|
30
|
+
export var UndoEventType;
|
31
|
+
(function (UndoEventType) {
|
32
|
+
UndoEventType[UndoEventType["CommandDone"] = 0] = "CommandDone";
|
33
|
+
UndoEventType[UndoEventType["CommandUndone"] = 1] = "CommandUndone";
|
34
|
+
UndoEventType[UndoEventType["CommandRedone"] = 2] = "CommandRedone";
|
35
|
+
})(UndoEventType || (UndoEventType = {}));
|
package/package.json
CHANGED
package/src/Editor.ts
CHANGED
@@ -663,12 +663,14 @@ export class Editor {
|
|
663
663
|
* ```
|
664
664
|
*/
|
665
665
|
public dispatchNoAnnounce(command: Command, addToHistory: boolean = false) {
|
666
|
+
const result = command.apply(this);
|
667
|
+
|
666
668
|
if (addToHistory) {
|
667
669
|
const apply = false; // Don't double-apply
|
668
670
|
this.history.push(command, apply);
|
669
671
|
}
|
670
672
|
|
671
|
-
return
|
673
|
+
return result;
|
672
674
|
}
|
673
675
|
|
674
676
|
/**
|
package/src/EditorImage.ts
CHANGED
@@ -211,7 +211,7 @@ export default class EditorImage {
|
|
211
211
|
|
212
212
|
// A Command that can access private [EditorImage] functionality
|
213
213
|
private static AddElementCommand = class extends SerializableCommand {
|
214
|
-
private serializedElem: any;
|
214
|
+
private serializedElem: any|null = null;
|
215
215
|
|
216
216
|
// If [applyByFlattening], then the rendered content of this element
|
217
217
|
// is present on the display's wet ink canvas. As such, no re-render is necessary
|
@@ -222,9 +222,12 @@ export default class EditorImage {
|
|
222
222
|
) {
|
223
223
|
super('add-element');
|
224
224
|
|
225
|
-
//
|
226
|
-
//
|
227
|
-
|
225
|
+
// FIXME: The serialized version of this command may be inaccurate if this is
|
226
|
+
// serialized when this command is not on the top of the undo stack.
|
227
|
+
//
|
228
|
+
// Caching the element's serialized data leads to additional memory usage *and*
|
229
|
+
// sometimes incorrect behavior in collaborative editing.
|
230
|
+
this.serializedElem = null;
|
228
231
|
|
229
232
|
if (isNaN(element.getBBox().area)) {
|
230
233
|
throw new Error('Elements in the image cannot have NaN bounding boxes');
|
@@ -253,7 +256,7 @@ export default class EditorImage {
|
|
253
256
|
|
254
257
|
protected serializeToJSON() {
|
255
258
|
return {
|
256
|
-
elemData: this.serializedElem,
|
259
|
+
elemData: this.serializedElem ?? this.element.serialize(),
|
257
260
|
};
|
258
261
|
}
|
259
262
|
|
@@ -262,7 +265,9 @@ export default class EditorImage {
|
|
262
265
|
const id = json.elemData.id;
|
263
266
|
const foundElem = editor.image.lookupElement(id);
|
264
267
|
const elem = foundElem ?? AbstractComponent.deserialize(json.elemData);
|
265
|
-
|
268
|
+
const result = new EditorImage.AddElementCommand(elem);
|
269
|
+
result.serializedElem = json.elemData;
|
270
|
+
return result;
|
266
271
|
});
|
267
272
|
}
|
268
273
|
};
|
package/src/UndoRedoHistory.ts
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
import Editor from './Editor';
|
2
2
|
import Command from './commands/Command';
|
3
|
-
import { EditorEventType } from './types';
|
3
|
+
import { EditorEventType, UndoEventType } from './types';
|
4
4
|
|
5
5
|
type AnnounceRedoCallback = (command: Command)=>void;
|
6
6
|
type AnnounceUndoCallback = (command: Command)=>void;
|
7
7
|
|
8
8
|
class UndoRedoHistory {
|
9
|
-
|
10
|
-
|
9
|
+
#undoStack: Command[];
|
10
|
+
#redoStack: Command[];
|
11
11
|
|
12
|
-
private maxUndoRedoStackSize: number = 700;
|
12
|
+
private readonly maxUndoRedoStackSize: number = 700;
|
13
13
|
|
14
14
|
// @internal
|
15
15
|
public constructor(
|
@@ -17,15 +17,20 @@ class UndoRedoHistory {
|
|
17
17
|
private announceRedoCallback: AnnounceRedoCallback,
|
18
18
|
private announceUndoCallback: AnnounceUndoCallback,
|
19
19
|
) {
|
20
|
-
this
|
21
|
-
this
|
20
|
+
this.#undoStack = [];
|
21
|
+
this.#redoStack = [];
|
22
22
|
}
|
23
23
|
|
24
|
-
private fireUpdateEvent(
|
24
|
+
private fireUpdateEvent(
|
25
|
+
stackUpdateType: UndoEventType, triggeringCommand: Command
|
26
|
+
) {
|
25
27
|
this.editor.notifier.dispatch(EditorEventType.UndoRedoStackUpdated, {
|
26
28
|
kind: EditorEventType.UndoRedoStackUpdated,
|
27
|
-
undoStackSize: this
|
28
|
-
redoStackSize: this
|
29
|
+
undoStackSize: this.#undoStack.length,
|
30
|
+
redoStackSize: this.#redoStack.length,
|
31
|
+
|
32
|
+
command: triggeringCommand,
|
33
|
+
stackUpdateType,
|
29
34
|
});
|
30
35
|
}
|
31
36
|
|
@@ -34,20 +39,20 @@ class UndoRedoHistory {
|
|
34
39
|
if (apply) {
|
35
40
|
command.apply(this.editor);
|
36
41
|
}
|
37
|
-
this
|
42
|
+
this.#undoStack.push(command);
|
38
43
|
|
39
|
-
for (const elem of this
|
44
|
+
for (const elem of this.#redoStack) {
|
40
45
|
elem.onDrop(this.editor);
|
41
46
|
}
|
42
|
-
this
|
47
|
+
this.#redoStack = [];
|
43
48
|
|
44
|
-
if (this
|
49
|
+
if (this.#undoStack.length > this.maxUndoRedoStackSize) {
|
45
50
|
const removeAtOnceCount = 10;
|
46
|
-
const removedElements = this
|
51
|
+
const removedElements = this.#undoStack.splice(0, removeAtOnceCount);
|
47
52
|
removedElements.forEach(elem => elem.onDrop(this.editor));
|
48
53
|
}
|
49
54
|
|
50
|
-
this.fireUpdateEvent();
|
55
|
+
this.fireUpdateEvent(UndoEventType.CommandDone, command);
|
51
56
|
this.editor.notifier.dispatch(EditorEventType.CommandDone, {
|
52
57
|
kind: EditorEventType.CommandDone,
|
53
58
|
command,
|
@@ -56,13 +61,13 @@ class UndoRedoHistory {
|
|
56
61
|
|
57
62
|
// Remove the last command from this' undo stack and apply it.
|
58
63
|
public undo() {
|
59
|
-
const command = this
|
64
|
+
const command = this.#undoStack.pop();
|
60
65
|
if (command) {
|
61
|
-
this
|
66
|
+
this.#redoStack.push(command);
|
62
67
|
command.unapply(this.editor);
|
63
68
|
this.announceUndoCallback(command);
|
64
69
|
|
65
|
-
this.fireUpdateEvent();
|
70
|
+
this.fireUpdateEvent(UndoEventType.CommandUndone, command);
|
66
71
|
this.editor.notifier.dispatch(EditorEventType.CommandUndone, {
|
67
72
|
kind: EditorEventType.CommandUndone,
|
68
73
|
command,
|
@@ -71,13 +76,13 @@ class UndoRedoHistory {
|
|
71
76
|
}
|
72
77
|
|
73
78
|
public redo() {
|
74
|
-
const command = this
|
79
|
+
const command = this.#redoStack.pop();
|
75
80
|
if (command) {
|
76
|
-
this
|
81
|
+
this.#undoStack.push(command);
|
77
82
|
command.apply(this.editor);
|
78
83
|
this.announceRedoCallback(command);
|
79
84
|
|
80
|
-
this.fireUpdateEvent();
|
85
|
+
this.fireUpdateEvent(UndoEventType.CommandRedone, command);
|
81
86
|
this.editor.notifier.dispatch(EditorEventType.CommandDone, {
|
82
87
|
kind: EditorEventType.CommandDone,
|
83
88
|
command,
|
@@ -86,11 +91,11 @@ class UndoRedoHistory {
|
|
86
91
|
}
|
87
92
|
|
88
93
|
public get undoStackSize(): number {
|
89
|
-
return this
|
94
|
+
return this.#undoStack.length;
|
90
95
|
}
|
91
96
|
|
92
97
|
public get redoStackSize(): number {
|
93
|
-
return this
|
98
|
+
return this.#redoStack.length;
|
94
99
|
}
|
95
100
|
}
|
96
101
|
|
@@ -111,8 +111,8 @@ class DefaultRestyleComponentCommand extends UnresolvedSerializableCommand {
|
|
111
111
|
this.getComponent(editor).forceStyle(this.originalStyle, editor);
|
112
112
|
}
|
113
113
|
|
114
|
-
public description(
|
115
|
-
return localizationTable.
|
114
|
+
public description(editor: Editor, localizationTable: EditorLocalization): string {
|
115
|
+
return localizationTable.restyledElement(this.getComponent(editor).description(localizationTable));
|
116
116
|
}
|
117
117
|
|
118
118
|
protected serializeToJSON() {
|
@@ -7,16 +7,16 @@ export interface ImageComponentLocalization {
|
|
7
7
|
emptyBackground: string;
|
8
8
|
filledBackgroundWithColor: (color: string)=> string;
|
9
9
|
|
10
|
-
|
10
|
+
restyledElement: (elementDescription: string) => string;
|
11
11
|
}
|
12
12
|
|
13
13
|
export const defaultComponentLocalization: ImageComponentLocalization = {
|
14
14
|
unlabeledImageNode: 'Unlabeled image node',
|
15
15
|
stroke: 'Stroke',
|
16
16
|
svgObject: 'SVG Object',
|
17
|
-
restyledElements: 'Restyled elements',
|
18
17
|
emptyBackground: 'Empty background',
|
19
18
|
filledBackgroundWithColor: (color) => `Filled background (${color})`,
|
20
19
|
text: (text) => `Text object: ${text}`,
|
21
20
|
imageNode: (description: string) => `Image: ${description}`,
|
21
|
+
restyledElement: (elementDescription: string) => `Restyled ${elementDescription}`,
|
22
22
|
};
|
package/src/lib.ts
CHANGED
@@ -30,6 +30,7 @@ export * from './toolbar/lib';
|
|
30
30
|
export * from './rendering/lib';
|
31
31
|
export { default as Pointer, PointerDevice } from './Pointer';
|
32
32
|
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
|
33
|
+
export { default as UndoRedoHistory } from './UndoRedoHistory';
|
33
34
|
|
34
35
|
export { Editor, EditorSettings };
|
35
36
|
export default Editor;
|
package/src/toolbar/toolbar.css
CHANGED
@@ -18,6 +18,8 @@
|
|
18
18
|
flex-direction: row;
|
19
19
|
justify-content: center;
|
20
20
|
|
21
|
+
--toolbar-button-height: min(20vh, 60px);
|
22
|
+
|
21
23
|
/* Display above selection dialogs, etc. */
|
22
24
|
z-index: 2;
|
23
25
|
|
@@ -30,7 +32,7 @@
|
|
30
32
|
.toolbar-root > .toolbar-button {
|
31
33
|
width: min-content;
|
32
34
|
white-space: pre;
|
33
|
-
height:
|
35
|
+
height: var(--toolbar-button-height);
|
34
36
|
}
|
35
37
|
|
36
38
|
.toolbar-dropdown .toolbar-button > .toolbar-icon {
|
@@ -76,6 +78,10 @@
|
|
76
78
|
font-size: 1em;
|
77
79
|
}
|
78
80
|
|
81
|
+
.toolbar-button > label {
|
82
|
+
cursor: inherit;
|
83
|
+
}
|
84
|
+
|
79
85
|
.toolbar-dropdown > .toolbar-toolContainer > button,
|
80
86
|
.toolbar-dropdown > .toolbar-toolContainer > .toolbar-button {
|
81
87
|
width: 6em;
|
@@ -3,7 +3,25 @@
|
|
3
3
|
display: flex;
|
4
4
|
flex-direction: column;
|
5
5
|
flex-wrap: wrap;
|
6
|
+
justify-content: center;
|
7
|
+
}
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
+
.toolbar-overflow-widget-overflow-list > .toolbar-toolContainer > .toolbar-button {
|
10
|
+
height: var(--toolbar-button-height);
|
11
|
+
}
|
12
|
+
|
13
|
+
.toolbar-overflow-widget.horizontal .toolbar-overflow-widget-overflow-list {
|
14
|
+
flex-direction: row;
|
15
|
+
}
|
16
|
+
|
17
|
+
.toolbar-overflow-widget.horizontal > .toolbar-dropdown {
|
18
|
+
max-width: 100%;
|
19
|
+
left: 15px;
|
20
|
+
right: 15px;
|
21
|
+
|
22
|
+
/* Override the default transform and margin-left */
|
23
|
+
margin-left: 0 !important;
|
24
|
+
transform: none !important;
|
25
|
+
|
26
|
+
padding: 4px;
|
9
27
|
}
|
@@ -10,6 +10,9 @@ export default class OverflowWidget extends BaseWidget {
|
|
10
10
|
public constructor(editor: Editor, localizationTable?: ToolbarLocalization) {
|
11
11
|
super(editor, 'overflow-widget', localizationTable);
|
12
12
|
|
13
|
+
|
14
|
+
this.container.classList.add('toolbar-overflow-widget');
|
15
|
+
|
13
16
|
// Make the dropdown openable
|
14
17
|
this.container.classList.add('dropdownShowable');
|
15
18
|
this.overflowContainer ??= document.createElement('div');
|
@@ -44,6 +47,7 @@ export default class OverflowWidget extends BaseWidget {
|
|
44
47
|
*/
|
45
48
|
public clearChildren(): BaseWidget[] {
|
46
49
|
this.overflowContainer.replaceChildren();
|
50
|
+
this.container.classList.remove('horizontal');
|
47
51
|
|
48
52
|
const overflowChildren = this.overflowChildren;
|
49
53
|
this.overflowChildren = [];
|
@@ -73,6 +77,11 @@ export default class OverflowWidget extends BaseWidget {
|
|
73
77
|
this.overflowChildren.push(widget);
|
74
78
|
widget.addTo(this.overflowContainer);
|
75
79
|
widget.setIsToplevel(false);
|
80
|
+
|
81
|
+
// Switch to a horizontal layout if enough children
|
82
|
+
if (this.overflowChildren.length > 2) {
|
83
|
+
this.container.classList.add('horizontal');
|
84
|
+
}
|
76
85
|
}
|
77
86
|
|
78
87
|
// This always returns false.
|
package/src/types.ts
CHANGED
@@ -111,7 +111,6 @@ export type InputEvt = KeyPressEvent | KeyUpEvent | WheelEvt | GestureCancelEvt
|
|
111
111
|
|
112
112
|
export type EditorNotifier = EventDispatcher<EditorEventType, EditorEventDataType>;
|
113
113
|
|
114
|
-
|
115
114
|
export enum EditorEventType {
|
116
115
|
ToolEnabled,
|
117
116
|
ToolDisabled,
|
@@ -130,6 +129,13 @@ export enum EditorEventType {
|
|
130
129
|
ToolbarDropdownShown,
|
131
130
|
}
|
132
131
|
|
132
|
+
// Types of `EditorUndoStackUpdated` events.
|
133
|
+
export enum UndoEventType {
|
134
|
+
CommandDone,
|
135
|
+
CommandUndone,
|
136
|
+
CommandRedone,
|
137
|
+
}
|
138
|
+
|
133
139
|
type EditorToolEventType = EditorEventType.ToolEnabled
|
134
140
|
| EditorEventType.ToolDisabled
|
135
141
|
| EditorEventType.ToolUpdated;
|
@@ -159,8 +165,12 @@ export interface DisplayResizedEvent {
|
|
159
165
|
|
160
166
|
export interface EditorUndoStackUpdated {
|
161
167
|
readonly kind: EditorEventType.UndoRedoStackUpdated;
|
168
|
+
|
162
169
|
readonly undoStackSize: number;
|
163
170
|
readonly redoStackSize: number;
|
171
|
+
|
172
|
+
readonly command?: Command;
|
173
|
+
readonly stackUpdateType: UndoEventType;
|
164
174
|
}
|
165
175
|
|
166
176
|
export interface CommandDoneEvent {
|