import {EditorFormModal, EditorFormModalDefinition} from "./modals";
-import {EditorUiContext, EditorUiElement} from "./core";
-import {EditorDecorator} from "./decorator";
+import {EditorContainerUiElement, EditorUiContext, EditorUiElement, EditorUiStateUpdate} from "./core";
+import {EditorDecorator, EditorDecoratorAdapter} from "./decorator";
+import {$getSelection, COMMAND_PRIORITY_LOW, LexicalEditor, SELECTION_CHANGE_COMMAND} from "lexical";
+import {DecoratorListener} from "lexical/LexicalEditor";
+import type {NodeKey} from "lexical/LexicalNode";
export class EditorUIManager {
protected decoratorConstructorsByType: Record<string, typeof EditorDecorator> = {};
protected decoratorInstancesByNodeKey: Record<string, EditorDecorator> = {};
protected context: EditorUiContext|null = null;
+ protected toolbar: EditorContainerUiElement|null = null;
setContext(context: EditorUiContext) {
this.context = context;
+ this.setupEditor(context.editor);
}
getContext(): EditorUiContext {
return this.context;
}
- triggerStateUpdate(element: EditorUiElement) {
+ triggerStateUpdateForElement(element: EditorUiElement) {
element.updateState({
selection: null,
editor: this.getContext().editor
this.decoratorConstructorsByType[type] = decorator;
}
- getDecorator(decoratorType: string, nodeKey: string): EditorDecorator {
+ protected getDecorator(decoratorType: string, nodeKey: string): EditorDecorator {
if (this.decoratorInstancesByNodeKey[nodeKey]) {
return this.decoratorInstancesByNodeKey[nodeKey];
}
this.decoratorInstancesByNodeKey[nodeKey] = decorator;
return decorator;
}
+
+ setToolbar(toolbar: EditorContainerUiElement) {
+ if (this.toolbar) {
+ this.toolbar.getDOMElement().remove();
+ }
+
+ this.toolbar = toolbar;
+ toolbar.setContext(this.getContext());
+ this.getContext().editorDOM.before(toolbar.getDOMElement());
+ }
+
+ protected triggerStateUpdate(state: EditorUiStateUpdate): void {
+ const context = this.getContext();
+ context.lastSelection = state.selection;
+ this.toolbar?.updateState(state);
+ }
+
+ protected setupEditor(editor: LexicalEditor) {
+ // Update button states on editor selection change
+ editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
+ this.triggerStateUpdate({
+ editor: editor,
+ selection: $getSelection(),
+ });
+ return false;
+ }, COMMAND_PRIORITY_LOW);
+
+ // Register our DOM decorate listener with the editor
+ const domDecorateListener: DecoratorListener<EditorDecoratorAdapter> = (decorators: Record<NodeKey, EditorDecoratorAdapter>) => {
+ const keys = Object.keys(decorators);
+ for (const key of keys) {
+ const decoratedEl = editor.getElementByKey(key);
+ const adapter = decorators[key];
+ const decorator = this.getDecorator(adapter.type, key);
+ decorator.setNode(adapter.getNode());
+ const decoratorEl = decorator.render(this.getContext());
+ if (decoratedEl) {
+ decoratedEl.append(decoratorEl);
+ }
+ }
+ }
+ editor.registerDecoratorListener(domDecorateListener);
+ }
}
\ No newline at end of file
-import {
- $getSelection,
- COMMAND_PRIORITY_LOW,
- LexicalEditor,
- SELECTION_CHANGE_COMMAND
-} from "lexical";
+import {LexicalEditor} from "lexical";
import {getMainEditorFullToolbar} from "./toolbars";
import {EditorUIManager} from "./framework/manager";
import {image as imageFormDefinition, link as linkFormDefinition, source as sourceFormDefinition} from "./defaults/form-definitions";
-import {DecoratorListener} from "lexical/LexicalEditor";
-import type {NodeKey} from "lexical/LexicalNode";
-import {EditorDecoratorAdapter} from "./framework/decorator";
import {ImageDecorator} from "./decorators/image";
import {EditorUiContext} from "./framework/core";
const manager = new EditorUIManager();
const context: EditorUiContext = {
editor,
+ editorDOM: element,
manager,
translate: (text: string): string => text,
lastSelection: null,
manager.setContext(context);
// Create primary toolbar
- const toolbar = getMainEditorFullToolbar();
- toolbar.setContext(context);
- element.before(toolbar.getDOMElement());
+ manager.setToolbar(getMainEditorFullToolbar());
// Register modals
manager.registerModal('link', {
form: sourceFormDefinition,
});
- // Register decorator listener
- // Maybe move to manager?
+ // Register image decorator listener
manager.registerDecoratorType('image', ImageDecorator);
- const domDecorateListener: DecoratorListener<EditorDecoratorAdapter> = (decorators: Record<NodeKey, EditorDecoratorAdapter>) => {
- const keys = Object.keys(decorators);
- for (const key of keys) {
- const decoratedEl = editor.getElementByKey(key);
- const adapter = decorators[key];
- const decorator = manager.getDecorator(adapter.type, key);
- decorator.setNode(adapter.getNode());
- const decoratorEl = decorator.render(context);
- if (decoratedEl) {
- decoratedEl.append(decoratorEl);
- }
- }
- }
- editor.registerDecoratorListener(domDecorateListener);
-
- // Update button states on editor selection change
- editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
- const selection = $getSelection();
- toolbar.updateState({editor, selection});
- context.lastSelection = selection;
- return false;
- }, COMMAND_PRIORITY_LOW);
}
\ No newline at end of file