]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/defaults/buttons/block-formats.ts
Lexical: Split helpers to utils, refactored files
[bookstack] / resources / js / wysiwyg / ui / defaults / buttons / block-formats.ts
1 import {$createCalloutNode, $isCalloutNodeOfCategory, CalloutCategory} from "../../../nodes/callout";
2 import {EditorButtonDefinition} from "../../framework/buttons";
3 import {EditorUiContext} from "../../framework/core";
4 import {$createParagraphNode, $isParagraphNode, BaseSelection, LexicalNode} from "lexical";
5 import {
6     $createHeadingNode,
7     $createQuoteNode,
8     $isHeadingNode,
9     $isQuoteNode,
10     HeadingNode,
11     HeadingTagType
12 } from "@lexical/rich-text";
13 import {$selectionContainsNodeType, $toggleSelectionBlockNodeType} from "../../../utils/selection";
14
15 function buildCalloutButton(category: CalloutCategory, name: string): EditorButtonDefinition {
16     return {
17         label: `${name} Callout`,
18         action(context: EditorUiContext) {
19             context.editor.update(() => {
20                 $toggleSelectionBlockNodeType(
21                     (node) => $isCalloutNodeOfCategory(node, category),
22                     () => $createCalloutNode(category),
23                 )
24             });
25         },
26         isActive(selection: BaseSelection|null): boolean {
27             return $selectionContainsNodeType(selection, (node) => $isCalloutNodeOfCategory(node, category));
28         }
29     };
30 }
31
32 export const infoCallout: EditorButtonDefinition = buildCalloutButton('info', 'Info');
33 export const dangerCallout: EditorButtonDefinition = buildCalloutButton('danger', 'Danger');
34 export const warningCallout: EditorButtonDefinition = buildCalloutButton('warning', 'Warning');
35 export const successCallout: EditorButtonDefinition = buildCalloutButton('success', 'Success');
36
37 const isHeaderNodeOfTag = (node: LexicalNode | null | undefined, tag: HeadingTagType) => {
38     return $isHeadingNode(node) && (node as HeadingNode).getTag() === tag;
39 };
40
41 function buildHeaderButton(tag: HeadingTagType, name: string): EditorButtonDefinition {
42     return {
43         label: name,
44         action(context: EditorUiContext) {
45             context.editor.update(() => {
46                 $toggleSelectionBlockNodeType(
47                     (node) => isHeaderNodeOfTag(node, tag),
48                     () => $createHeadingNode(tag),
49                 )
50             });
51         },
52         isActive(selection: BaseSelection|null): boolean {
53             return $selectionContainsNodeType(selection, (node) => isHeaderNodeOfTag(node, tag));
54         }
55     };
56 }
57
58 export const h2: EditorButtonDefinition = buildHeaderButton('h2', 'Large Header');
59 export const h3: EditorButtonDefinition = buildHeaderButton('h3', 'Medium Header');
60 export const h4: EditorButtonDefinition = buildHeaderButton('h4', 'Small Header');
61 export const h5: EditorButtonDefinition = buildHeaderButton('h5', 'Tiny Header');
62
63 export const blockquote: EditorButtonDefinition = {
64     label: 'Blockquote',
65     action(context: EditorUiContext) {
66         context.editor.update(() => {
67             $toggleSelectionBlockNodeType($isQuoteNode, $createQuoteNode);
68         });
69     },
70     isActive(selection: BaseSelection|null): boolean {
71         return $selectionContainsNodeType(selection, $isQuoteNode);
72     }
73 };
74
75 export const paragraph: EditorButtonDefinition = {
76     label: 'Paragraph',
77     action(context: EditorUiContext) {
78         context.editor.update(() => {
79             $toggleSelectionBlockNodeType($isParagraphNode, $createParagraphNode);
80         });
81     },
82     isActive(selection: BaseSelection|null): boolean {
83         return $selectionContainsNodeType(selection, $isParagraphNode);
84     }
85 }