1 import {SerializedTableNode, TableNode} from "@lexical/table";
2 import {DOMConversion, DOMConversionMap, DOMConversionOutput, LexicalNode, Spread} from "lexical";
3 import {EditorConfig} from "lexical/LexicalEditor";
5 import {el, extractStyleMapFromElement, StyleMap} from "../utils/dom";
6 import {getTableColumnWidths} from "../utils/tables";
8 CommonBlockAlignment, deserializeCommonBlockNode,
9 SerializedCommonBlockNode,
10 setCommonBlockPropsFromElement,
11 updateElementWithCommonBlockProps
14 export type SerializedCustomTableNode = Spread<Spread<{
16 styles: Record<string, string>,
17 }, SerializedTableNode>, SerializedCommonBlockNode>
19 export class CustomTableNode extends TableNode {
21 __colWidths: string[] = [];
22 __styles: StyleMap = new Map;
23 __alignment: CommonBlockAlignment = '';
27 return 'custom-table';
31 const self = this.getWritable();
36 const self = this.getLatest();
40 setAlignment(alignment: CommonBlockAlignment) {
41 const self = this.getWritable();
42 self.__alignment = alignment;
45 getAlignment(): CommonBlockAlignment {
46 const self = this.getLatest();
47 return self.__alignment;
50 setInset(size: number) {
51 const self = this.getWritable();
56 const self = this.getLatest();
60 setColWidths(widths: string[]) {
61 const self = this.getWritable();
62 self.__colWidths = widths;
65 getColWidths(): string[] {
66 const self = this.getLatest();
67 return self.__colWidths;
70 getStyles(): StyleMap {
71 const self = this.getLatest();
72 return new Map(self.__styles);
75 setStyles(styles: StyleMap): void {
76 const self = this.getWritable();
77 self.__styles = new Map(styles);
80 static clone(node: CustomTableNode) {
81 const newNode = new CustomTableNode(node.__key);
82 newNode.__id = node.__id;
83 newNode.__colWidths = node.__colWidths;
84 newNode.__styles = new Map(node.__styles);
85 newNode.__alignment = node.__alignment;
86 newNode.__inset = node.__inset;
90 createDOM(config: EditorConfig): HTMLElement {
91 const dom = super.createDOM(config);
92 updateElementWithCommonBlockProps(dom, this);
94 const colWidths = this.getColWidths();
95 if (colWidths.length > 0) {
96 const colgroup = el('colgroup');
97 for (const width of colWidths) {
98 const col = el('col');
100 col.style.width = width;
102 colgroup.append(col);
104 dom.append(colgroup);
107 for (const [name, value] of this.__styles.entries()) {
108 dom.style.setProperty(name, value);
114 updateDOM(): boolean {
118 exportJSON(): SerializedCustomTableNode {
120 ...super.exportJSON(),
121 type: 'custom-table',
124 colWidths: this.__colWidths,
125 styles: Object.fromEntries(this.__styles),
126 alignment: this.__alignment,
131 static importJSON(serializedNode: SerializedCustomTableNode): CustomTableNode {
132 const node = $createCustomTableNode();
133 deserializeCommonBlockNode(serializedNode, node);
134 node.setColWidths(serializedNode.colWidths);
135 node.setStyles(new Map(Object.entries(serializedNode.styles)));
139 static importDOM(): DOMConversionMap|null {
141 table(node: HTMLElement): DOMConversion|null {
143 conversion: (element: HTMLElement): DOMConversionOutput|null => {
144 const node = $createCustomTableNode();
145 setCommonBlockPropsFromElement(element, node);
147 const colWidths = getTableColumnWidths(element as HTMLTableElement);
148 node.setColWidths(colWidths);
149 node.setStyles(extractStyleMapFromElement(element));
160 export function $createCustomTableNode(): CustomTableNode {
161 return new CustomTableNode();
164 export function $isCustomTableNode(node: LexicalNode | null | undefined): node is CustomTableNode {
165 return node instanceof CustomTableNode;