]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/framework/buttons.ts
Lexical: Updated lexical, added undo state tracking, format styles
[bookstack] / resources / js / wysiwyg / ui / framework / buttons.ts
1 import {BaseSelection} from "lexical";
2 import {EditorUiContext, EditorUiElement, EditorUiStateUpdate} from "./core";
3 import {el} from "../../helpers";
4 import {context} from "esbuild";
5
6 export interface EditorBasicButtonDefinition {
7     label: string;
8     icon?: string|undefined;
9 }
10
11 export interface EditorButtonDefinition extends EditorBasicButtonDefinition {
12     action: (context: EditorUiContext) => void;
13     isActive: (selection: BaseSelection|null) => boolean;
14     setup?: (context: EditorUiContext, button: EditorButton) => void;
15 }
16
17 export class EditorButton extends EditorUiElement {
18     protected definition: EditorButtonDefinition;
19     protected active: boolean = false;
20     protected completedSetup: boolean = false;
21     protected disabled: boolean = false;
22
23     constructor(definition: EditorButtonDefinition) {
24         super();
25         this.definition = definition;
26     }
27
28     setContext(context: EditorUiContext) {
29         super.setContext(context);
30
31         if (this.definition.setup && !this.completedSetup) {
32             this.definition.setup(context, this);
33             this.completedSetup = true;
34         }
35     }
36
37     protected buildDOM(): HTMLButtonElement {
38
39         const label = this.getLabel();
40         let child: string|HTMLElement = label;
41         if (this.definition.icon) {
42             child = el('span', {class: 'editor-button-icon'});
43             child.innerHTML = this.definition.icon;
44         }
45
46         const button = el('button', {
47             type: 'button',
48             class: 'editor-button',
49             title: this.definition.icon ? label : null,
50             disabled: this.disabled ? 'true' : null,
51         }, [child]) as HTMLButtonElement;
52
53         button.addEventListener('click', this.onClick.bind(this));
54
55         return button;
56     }
57
58     protected onClick() {
59         this.definition.action(this.getContext());
60     }
61
62     updateActiveState(selection: BaseSelection|null) {
63         this.active = this.definition.isActive(selection);
64         this.dom?.classList.toggle('editor-button-active', this.active);
65     }
66
67     updateState(state: EditorUiStateUpdate): void {
68         this.updateActiveState(state.selection);
69     }
70
71     isActive(): boolean {
72         return this.active;
73     }
74
75     getLabel(): string {
76         return this.trans(this.definition.label);
77     }
78
79     toggleDisabled(disabled: boolean) {
80         this.disabled = disabled;
81         if (disabled) {
82             this.dom?.setAttribute('disabled', 'true');
83         } else {
84             this.dom?.removeAttribute('disabled');
85         }
86     }
87 }