]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/framework/containers.ts
Lexical: Added format previews to format buttons
[bookstack] / resources / js / wysiwyg / ui / framework / containers.ts
1 import {EditorUiContext, EditorUiElement, EditorUiStateUpdate} from "./base-elements";
2 import {el} from "../../helpers";
3
4 export class EditorContainerUiElement extends EditorUiElement {
5     protected children : EditorUiElement[];
6
7     constructor(children: EditorUiElement[]) {
8         super();
9         this.children = children;
10     }
11
12     protected buildDOM(): HTMLElement {
13         return el('div', {}, this.getChildren().map(child => child.getDOMElement()));
14     }
15
16     getChildren(): EditorUiElement[] {
17         return this.children;
18     }
19
20     updateState(state: EditorUiStateUpdate): void {
21         for (const child of this.children) {
22             child.updateState(state);
23         }
24     }
25
26     setContext(context: EditorUiContext) {
27         for (const child of this.getChildren()) {
28             child.setContext(context);
29         }
30     }
31 }
32
33 export class EditorSimpleClassContainer extends EditorContainerUiElement {
34     protected className;
35
36     constructor(className: string, children: EditorUiElement[]) {
37         super(children);
38         this.className = className;
39     }
40
41     protected buildDOM(): HTMLElement {
42         return el('div', {
43             class: this.className,
44         }, this.getChildren().map(child => child.getDOMElement()));
45     }
46 }
47
48 export class EditorFormatMenu extends EditorContainerUiElement {
49     buildDOM(): HTMLElement {
50         const childElements: HTMLElement[] = this.getChildren().map(child => child.getDOMElement());
51         const menu = el('div', {
52             class: 'editor-format-menu-dropdown editor-dropdown-menu editor-menu-list',
53             hidden: 'true',
54         }, childElements);
55
56         const toggle = el('button', {
57             class: 'editor-format-menu-toggle',
58             type: 'button',
59         }, ['Formats']);
60
61         const wrapper = el('div', {
62             class: 'editor-format-menu editor-dropdown-menu-container',
63         }, [toggle, menu]);
64
65         let clickListener: Function|null = null;
66
67         const hide = () => {
68             menu.hidden = true;
69             if (clickListener) {
70                 window.removeEventListener('click', clickListener as EventListener);
71             }
72         };
73
74         const show = () => {
75             menu.hidden = false
76             clickListener = (event: MouseEvent) => {
77                 if (!wrapper.contains(event.target as HTMLElement)) {
78                     hide();
79                 }
80             }
81             window.addEventListener('click', clickListener as EventListener);
82         };
83
84         toggle.addEventListener('click', event => {
85             menu.hasAttribute('hidden') ? show() : hide();
86         });
87         menu.addEventListener('mouseleave', hide);
88
89         return wrapper;
90     }
91 }