]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/nodes/custom-table-row.ts
Lexical: Merged list nodes
[bookstack] / resources / js / wysiwyg / nodes / custom-table-row.ts
1 import {
2     DOMConversionMap,
3     DOMConversionOutput,
4     EditorConfig,
5     LexicalNode,
6     Spread
7 } from "lexical";
8
9 import {
10     SerializedTableRowNode,
11     TableRowNode
12 } from "@lexical/table";
13 import {NodeKey} from "lexical/LexicalNode";
14 import {extractStyleMapFromElement, StyleMap} from "../utils/dom";
15
16 export type SerializedCustomTableRowNode = Spread<{
17     styles: Record<string, string>,
18 }, SerializedTableRowNode>
19
20 export class CustomTableRowNode extends TableRowNode {
21     __styles: StyleMap = new Map();
22
23     constructor(key?: NodeKey) {
24         super(0, key);
25     }
26
27     static getType(): string {
28         return 'custom-table-row';
29     }
30
31     static clone(node: CustomTableRowNode): CustomTableRowNode {
32         const cellNode = new CustomTableRowNode(node.__key);
33
34         cellNode.__styles = new Map(node.__styles);
35         return cellNode;
36     }
37
38     getStyles(): StyleMap {
39         const self = this.getLatest();
40         return new Map(self.__styles);
41     }
42
43     setStyles(styles: StyleMap): void {
44         const self = this.getWritable();
45         self.__styles = new Map(styles);
46     }
47
48     createDOM(config: EditorConfig): HTMLElement {
49         const element = super.createDOM(config);
50
51         for (const [name, value] of this.__styles.entries()) {
52             element.style.setProperty(name, value);
53         }
54
55         return element;
56     }
57
58     updateDOM(prevNode: CustomTableRowNode): boolean {
59         return super.updateDOM(prevNode)
60             || this.__styles !== prevNode.__styles;
61     }
62
63     static importDOM(): DOMConversionMap | null {
64         return {
65             tr: (node: Node) => ({
66                 conversion: $convertTableRowElement,
67                 priority: 0,
68             }),
69         };
70     }
71
72     static importJSON(serializedNode: SerializedCustomTableRowNode): CustomTableRowNode {
73         const node = $createCustomTableRowNode();
74
75         node.setStyles(new Map(Object.entries(serializedNode.styles)));
76
77         return node;
78     }
79
80     exportJSON(): SerializedCustomTableRowNode {
81         return {
82             ...super.exportJSON(),
83             height: 0,
84             type: 'custom-table-row',
85             styles: Object.fromEntries(this.__styles),
86         };
87     }
88 }
89
90 export function $convertTableRowElement(domNode: Node): DOMConversionOutput {
91     const rowNode = $createCustomTableRowNode();
92
93     if (domNode instanceof HTMLElement) {
94         rowNode.setStyles(extractStyleMapFromElement(domNode));
95     }
96
97     return {node: rowNode};
98 }
99
100 export function $createCustomTableRowNode(): CustomTableRowNode {
101     return new CustomTableRowNode();
102 }
103
104 export function $isCustomTableRowNode(node: LexicalNode | null | undefined): node is CustomTableRowNode {
105     return node instanceof CustomTableRowNode;
106 }