Skip to content

Commit 9d732d8

Browse files
committed
Lexical: Started dev API outline
1 parent 9e8088f commit 9d732d8

File tree

7 files changed

+129
-10
lines changed

7 files changed

+129
-10
lines changed

dev/docs/wysiwyg-js-api.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# WYSIWYG JavaScript API
2+
3+
TODO - Link to this from JS code doc.
4+
TODO - Create JS events and add to the js public events doc.
5+
6+
TODO - Document the JS API.
7+
8+
TODO - Add testing coverage

resources/js/wysiwyg/api/api.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import {EditorApiUiModule} from "./ui";
2+
import {EditorUiContext} from "../ui/framework/core";
3+
4+
export class EditorApi {
5+
6+
public ui: EditorApiUiModule;
7+
8+
constructor(context: EditorUiContext) {
9+
this.ui = new EditorApiUiModule(context);
10+
}
11+
}

resources/js/wysiwyg/api/ui.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import {EditorButton} from "../ui/framework/buttons";
2+
import {EditorUiContext} from "../ui/framework/core";
3+
import {EditorOverflowContainer} from "../ui/framework/blocks/overflow-container";
4+
5+
type EditorApiButtonOptions = {
6+
label?: string;
7+
icon?: string;
8+
onClick: () => void;
9+
};
10+
11+
class EditorApiButton {
12+
#button: EditorButton;
13+
#isActive: boolean = false;
14+
15+
constructor(options: EditorApiButtonOptions, context: EditorUiContext) {
16+
this.#button = new EditorButton({
17+
label: options.label || '',
18+
icon: options.icon || '',
19+
action: () => {
20+
options.onClick();
21+
},
22+
isActive: () => this.#isActive,
23+
});
24+
this.#button.setContext(context);
25+
}
26+
27+
setActive(active: boolean = true): void {
28+
this.#isActive = active;
29+
this.#button.setActiveState(active);
30+
}
31+
32+
_getOriginalModel() {
33+
return this.#button;
34+
}
35+
}
36+
37+
class EditorApiToolbarSection {
38+
#section: EditorOverflowContainer;
39+
label: string;
40+
41+
constructor(section: EditorOverflowContainer) {
42+
this.#section = section;
43+
this.label = section.getLabel();
44+
}
45+
46+
getLabel(): string {
47+
return this.#section.getLabel();
48+
}
49+
50+
addButton(button: EditorApiButton, targetIndex: number = -1): void {
51+
this.#section.addChild(button._getOriginalModel(), targetIndex);
52+
this.#section.rebuildDOM();
53+
}
54+
}
55+
56+
57+
export class EditorApiUiModule {
58+
#context: EditorUiContext;
59+
60+
constructor(context: EditorUiContext) {
61+
this.#context = context;
62+
}
63+
64+
createButton(options: EditorApiButtonOptions): EditorApiButton {
65+
return new EditorApiButton(options, this.#context);
66+
}
67+
68+
getToolbarSections(): EditorApiToolbarSection[] {
69+
const toolbar = this.#context.manager.getToolbar();
70+
if (!toolbar) {
71+
return [];
72+
}
73+
74+
const sections = toolbar.getChildren();
75+
return sections.filter(section => {
76+
return section instanceof EditorOverflowContainer;
77+
}).map(section => new EditorApiToolbarSection(section));
78+
}
79+
}

resources/js/wysiwyg/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {CodeBlockDecorator} from "./ui/decorators/code-block";
2121
import {DiagramDecorator} from "./ui/decorators/diagram";
2222
import {registerMouseHandling} from "./services/mouse-handling";
2323
import {registerSelectionHandling} from "./services/selection-handling";
24+
import {EditorApi} from "./api/api";
2425

2526
const theme = {
2627
text: {
@@ -94,6 +95,12 @@ export function createPageEditorInstance(container: HTMLElement, htmlContent: st
9495

9596
registerCommonNodeMutationListeners(context);
9697

98+
// TODO - Emit this as a public event instead
99+
// TODO - Add support to basic editor below
100+
const api = new EditorApi(context);
101+
// @ts-ignore
102+
window.editorApi = api;
103+
97104
return new SimpleWysiwygEditorInterface(context);
98105
}
99106

resources/js/wysiwyg/ui/defaults/toolbars.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
8888
return new EditorSimpleClassContainer('editor-toolbar-main', [
8989

9090
// History state
91-
new EditorOverflowContainer(2, [
91+
new EditorOverflowContainer('history', 2, [
9292
new EditorButton(undo),
9393
new EditorButton(redo),
9494
]),
@@ -110,7 +110,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
110110
]),
111111

112112
// Inline formats
113-
new EditorOverflowContainer(6, [
113+
new EditorOverflowContainer('inline_formats', 6, [
114114
new EditorButton(bold),
115115
new EditorButton(italic),
116116
new EditorButton(underline),
@@ -128,7 +128,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
128128
]),
129129

130130
// Alignment
131-
new EditorOverflowContainer(6, [
131+
new EditorOverflowContainer('alignment', 6, [
132132
new EditorButton(alignLeft),
133133
new EditorButton(alignCenter),
134134
new EditorButton(alignRight),
@@ -138,7 +138,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
138138
].filter(x => x !== null)),
139139

140140
// Lists
141-
new EditorOverflowContainer(3, [
141+
new EditorOverflowContainer('lists', 3, [
142142
new EditorButton(bulletList),
143143
new EditorButton(numberList),
144144
new EditorButton(taskList),
@@ -147,7 +147,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
147147
]),
148148

149149
// Insert types
150-
new EditorOverflowContainer(4, [
150+
new EditorOverflowContainer('inserts', 4, [
151151
new EditorButton(link),
152152

153153
new EditorDropdownButton({button: table, direction: 'vertical', showAside: false}, [
@@ -200,7 +200,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
200200
]),
201201

202202
// Meta elements
203-
new EditorOverflowContainer(3, [
203+
new EditorOverflowContainer('meta', 3, [
204204
new EditorButton(source),
205205
new EditorButton(about),
206206
new EditorButton(fullscreen),
@@ -261,16 +261,16 @@ export const contextToolbars: Record<string, EditorContextToolbarDefinition> = {
261261
selector: 'td,th',
262262
content() {
263263
return [
264-
new EditorOverflowContainer(2, [
264+
new EditorOverflowContainer('table', 2, [
265265
new EditorButton(tableProperties),
266266
new EditorButton(deleteTable),
267267
]),
268-
new EditorOverflowContainer(3, [
268+
new EditorOverflowContainer('table_row',3, [
269269
new EditorButton(insertRowAbove),
270270
new EditorButton(insertRowBelow),
271271
new EditorButton(deleteRow),
272272
]),
273-
new EditorOverflowContainer(3, [
273+
new EditorOverflowContainer('table_column', 3, [
274274
new EditorButton(insertColumnBefore),
275275
new EditorButton(insertColumnAfter),
276276
new EditorButton(deleteColumn),

resources/js/wysiwyg/ui/framework/blocks/overflow-container.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ export class EditorOverflowContainer extends EditorContainerUiElement {
99
protected size: number;
1010
protected overflowButton: EditorDropdownButton;
1111
protected content: EditorUiElement[];
12+
protected label: string;
1213

13-
constructor(size: number, children: EditorUiElement[]) {
14+
constructor(label: string, size: number, children: EditorUiElement[]) {
1415
super(children);
16+
this.label = label;
1517
this.size = size;
1618
this.content = children;
1719
this.overflowButton = new EditorDropdownButton({
@@ -24,6 +26,11 @@ export class EditorOverflowContainer extends EditorContainerUiElement {
2426
this.addChildren(this.overflowButton);
2527
}
2628

29+
addChild(child: EditorUiElement, targetIndex: number = -1): void {
30+
this.content.splice(targetIndex, 0, child);
31+
this.addChildren(child);
32+
}
33+
2734
protected buildDOM(): HTMLElement {
2835
const slicePosition = this.content.length > this.size ? this.size - 1 : this.size;
2936
const visibleChildren = this.content.slice(0, slicePosition);
@@ -41,5 +48,8 @@ export class EditorOverflowContainer extends EditorContainerUiElement {
4148
}, visibleElements);
4249
}
4350

51+
getLabel(): string {
52+
return this.label;
53+
}
4454

4555
}

resources/js/wysiwyg/ui/framework/manager.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ export class EditorUIManager {
109109
this.getContext().containerDOM.prepend(toolbar.getDOMElement());
110110
}
111111

112+
getToolbar(): EditorContainerUiElement|null {
113+
return this.toolbar;
114+
}
115+
112116
registerContextToolbar(key: string, definition: EditorContextToolbarDefinition) {
113117
this.contextToolbarDefinitionsByKey[key] = definition;
114118
}

0 commit comments

Comments
 (0)