]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/nodes/index.ts
Lexical: Started linking up cell properties form
[bookstack] / resources / js / wysiwyg / nodes / index.ts
1 import {HeadingNode, QuoteNode} from '@lexical/rich-text';
2 import {CalloutNode} from './callout';
3 import {
4     ElementNode,
5     KlassConstructor,
6     LexicalNode,
7     LexicalNodeReplacement, NodeMutation,
8     ParagraphNode
9 } from "lexical";
10 import {CustomParagraphNode} from "./custom-paragraph";
11 import {LinkNode} from "@lexical/link";
12 import {ImageNode} from "./image";
13 import {DetailsNode, SummaryNode} from "./details";
14 import {ListItemNode, ListNode} from "@lexical/list";
15 import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
16 import {CustomTableNode} from "./custom-table";
17 import {HorizontalRuleNode} from "./horizontal-rule";
18 import {CodeBlockNode} from "./code-block";
19 import {DiagramNode} from "./diagram";
20 import {EditorUiContext} from "../ui/framework/core";
21 import {MediaNode} from "./media";
22 import {CustomListItemNode} from "./custom-list-item";
23 import {CustomTableCellNode} from "./custom-table-cell-node";
24
25 /**
26  * Load the nodes for lexical.
27  */
28 export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> | LexicalNodeReplacement)[] {
29     return [
30         CalloutNode, // Todo - Create custom
31         HeadingNode, // Todo - Create custom
32         QuoteNode, // Todo - Create custom
33         ListNode, // Todo - Create custom
34         CustomListItemNode,
35         CustomTableNode,
36         TableRowNode,
37         CustomTableCellNode,
38         ImageNode,
39         HorizontalRuleNode,
40         DetailsNode, SummaryNode,
41         CodeBlockNode,
42         DiagramNode,
43         MediaNode,
44         CustomParagraphNode,
45         LinkNode,
46         {
47             replace: ParagraphNode,
48             with: (node: ParagraphNode) => {
49                 return new CustomParagraphNode();
50             }
51         },
52         {
53             replace: TableNode,
54             with(node: TableNode) {
55                 return new CustomTableNode();
56             }
57         },
58         {
59             replace: ListItemNode,
60             with: (node: ListItemNode) => {
61                 return new CustomListItemNode(node.__value, node.__checked);
62             }
63         },
64         {
65             replace: TableCellNode,
66             with: (node: TableCellNode) => {
67                 const cell = new CustomTableCellNode(
68                     node.__headerState,
69                     node.__colSpan,
70                     node.__width,
71                 );
72                 cell.__rowSpan = node.__rowSpan;
73                 return cell;
74             }
75         },
76     ];
77 }
78
79 export function registerCommonNodeMutationListeners(context: EditorUiContext): void {
80     const decorated = [ImageNode, CodeBlockNode, DiagramNode];
81
82     const decorationDestroyListener = (mutations: Map<string, NodeMutation>): void => {
83         for (let [nodeKey, mutation] of mutations) {
84             if (mutation === "destroyed") {
85                 const decorator = context.manager.getDecoratorByNodeKey(nodeKey);
86                 if (decorator) {
87                     decorator.destroy(context);
88                 }
89             }
90         }
91     };
92
93     for (let decoratedNode of decorated) {
94         // Have to pass a unique function here since they are stored by lexical keyed on listener function.
95         context.editor.registerMutationListener(decoratedNode, (mutations) => decorationDestroyListener(mutations));
96     }
97 }
98
99 export type LexicalNodeMatcher = (node: LexicalNode|null|undefined) => boolean;
100 export type LexicalElementNodeCreator = () => ElementNode;