]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/framework/blocks/dropdown-button.ts
Lexical: Added mobile toolbar support
[bookstack] / resources / js / wysiwyg / ui / framework / blocks / dropdown-button.ts
1 import {handleDropdown} from "../helpers/dropdowns";
2 import {EditorContainerUiElement, EditorUiElement} from "../core";
3 import {EditorBasicButtonDefinition, EditorButton} from "../buttons";
4 import {el} from "../../../utils/dom";
5 import {EditorMenuButton} from "./menu-button";
6
7 export type EditorDropdownButtonOptions = {
8     showOnHover?: boolean;
9     direction?: 'vertical'|'horizontal';
10     showAside?: boolean;
11     button: EditorBasicButtonDefinition|EditorButton;
12 };
13
14 const defaultOptions: EditorDropdownButtonOptions = {
15     showOnHover: false,
16     direction: 'horizontal',
17     showAside: undefined,
18     button: {label: 'Menu'},
19 }
20
21 export class EditorDropdownButton extends EditorContainerUiElement {
22     protected button: EditorButton;
23     protected childItems: EditorUiElement[];
24     protected open: boolean = false;
25     protected options: EditorDropdownButtonOptions;
26
27     constructor(options: EditorDropdownButtonOptions, children: EditorUiElement[]) {
28         super(children);
29         this.childItems = children;
30         this.options = Object.assign({}, defaultOptions, options);
31
32         if (options.button instanceof EditorButton) {
33             this.button = options.button;
34         } else {
35             const type = options.button.format === 'long' ? EditorMenuButton : EditorButton;
36             this.button = new type({
37                 ...options.button,
38                 action() {
39                     return false;
40                 },
41                 isActive: () => {
42                     return this.open;
43                 }
44             });
45         }
46
47         this.addChildren(this.button);
48     }
49
50     insertItems(...items: EditorUiElement[]) {
51         this.addChildren(...items);
52         this.childItems.push(...items);
53     }
54
55     protected buildDOM(): HTMLElement {
56         const button = this.button.getDOMElement();
57
58         const childElements: HTMLElement[] = this.childItems.map(child => child.getDOMElement());
59         const menu = el('div', {
60             class: `editor-dropdown-menu editor-dropdown-menu-${this.options.direction}`,
61             hidden: 'true',
62         }, childElements);
63
64         const wrapper = el('div', {
65             class: 'editor-dropdown-menu-container',
66         }, [button, menu]);
67
68         handleDropdown({toggle: button, menu : menu,
69             showOnHover: this.options.showOnHover,
70             showAside: typeof this.options.showAside === 'boolean' ? this.options.showAside : (this.options.direction === 'vertical'),
71             onOpen : () => {
72             this.open = true;
73             this.getContext().manager.triggerStateUpdateForElement(this.button);
74         }, onClose : () => {
75             this.open = false;
76             this.getContext().manager.triggerStateUpdateForElement(this.button);
77         }});
78
79         return wrapper;
80     }
81 }