]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/nodes/index.ts
Lexical: Added cell width fetching, Created custom row node
[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";
24 import {CustomTableRowNode} from "./custom-table-row";
25
26 /**
27  * Load the nodes for lexical.
28  */
29 export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> | LexicalNodeReplacement)[] {
30     return [
31         CalloutNode, // Todo - Create custom
32         HeadingNode, // Todo - Create custom
33         QuoteNode, // Todo - Create custom
34         ListNode, // Todo - Create custom
35         CustomListItemNode,
36         CustomTableNode,
37         CustomTableRowNode,
38         CustomTableCellNode,
39         ImageNode,
40         HorizontalRuleNode,
41         DetailsNode, SummaryNode,
42         CodeBlockNode,
43         DiagramNode,
44         MediaNode,
45         CustomParagraphNode,
46         LinkNode,
47         {
48             replace: ParagraphNode,
49             with: (node: ParagraphNode) => {
50                 return new CustomParagraphNode();
51             }
52         },
53         {
54             replace: ListItemNode,
55             with: (node: ListItemNode) => {
56                 return new CustomListItemNode(node.__value, node.__checked);
57             }
58         },
59         {
60             replace: TableNode,
61             with(node: TableNode) {
62                 return new CustomTableNode();
63             }
64         },
65         {
66             replace: TableRowNode,
67             with(node: TableRowNode) {
68                 return new CustomTableRowNode();
69             }
70         },
71         {
72             replace: TableCellNode,
73             with: (node: TableCellNode) => {
74                 const cell = new CustomTableCellNode(
75                     node.__headerState,
76                     node.__colSpan,
77                     node.__width,
78                 );
79                 cell.__rowSpan = node.__rowSpan;
80                 return cell;
81             }
82         },
83     ];
84 }
85
86 export function registerCommonNodeMutationListeners(context: EditorUiContext): void {
87     const decorated = [ImageNode, CodeBlockNode, DiagramNode];
88
89     const decorationDestroyListener = (mutations: Map<string, NodeMutation>): void => {
90         for (let [nodeKey, mutation] of mutations) {
91             if (mutation === "destroyed") {
92                 const decorator = context.manager.getDecoratorByNodeKey(nodeKey);
93                 if (decorator) {
94                     decorator.destroy(context);
95                 }
96             }
97         }
98     };
99
100     for (let decoratedNode of decorated) {
101         // Have to pass a unique function here since they are stored by lexical keyed on listener function.
102         context.editor.registerMutationListener(decoratedNode, (mutations) => decorationDestroyListener(mutations));
103     }
104 }
105
106 export type LexicalNodeMatcher = (node: LexicalNode|null|undefined) => boolean;
107 export type LexicalElementNodeCreator = () => ElementNode;