]> BookStack Code Mirror - bookstack/commitdiff
Lexical: Merged custom table node code
authorDan Brown <redacted>
Tue, 3 Dec 2024 20:08:33 +0000 (20:08 +0000)
committerDan Brown <redacted>
Tue, 3 Dec 2024 20:08:33 +0000 (20:08 +0000)
17 files changed:
resources/js/wysiwyg/lexical/table/LexicalTableCellNode.ts
resources/js/wysiwyg/lexical/table/LexicalTableNode.ts
resources/js/wysiwyg/lexical/table/LexicalTableRowNode.ts
resources/js/wysiwyg/lexical/table/LexicalTableSelectionHelpers.ts
resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableRowNode.test.ts
resources/js/wysiwyg/nodes/custom-table-cell.ts [deleted file]
resources/js/wysiwyg/nodes/custom-table-row.ts [deleted file]
resources/js/wysiwyg/nodes/custom-table.ts [deleted file]
resources/js/wysiwyg/nodes/index.ts
resources/js/wysiwyg/ui/defaults/buttons/tables.ts
resources/js/wysiwyg/ui/defaults/forms/tables.ts
resources/js/wysiwyg/ui/framework/blocks/table-creator.ts
resources/js/wysiwyg/ui/framework/helpers/table-resizer.ts
resources/js/wysiwyg/ui/framework/helpers/table-selection-handler.ts
resources/js/wysiwyg/utils/table-copy-paste.ts
resources/js/wysiwyg/utils/table-map.ts
resources/js/wysiwyg/utils/tables.ts

index 455d39bf6c9c3fae7d3a2e93238202a60d03045f..72676b9bacbea5a94262ed709869902f58904828 100644 (file)
@@ -28,7 +28,8 @@ import {
   ElementNode,
 } from 'lexical';
 
-import {COLUMN_WIDTH, PIXEL_VALUE_REG_EXP} from './constants';
+import {extractStyleMapFromElement, StyleMap} from "../../utils/dom";
+import {CommonBlockAlignment, extractAlignmentFromElement} from "../../nodes/_common";
 
 export const TableCellHeaderStates = {
   BOTH: 3,
@@ -47,6 +48,8 @@ export type SerializedTableCellNode = Spread<
     headerState: TableCellHeaderState;
     width?: number;
     backgroundColor?: null | string;
+    styles: Record<string, string>;
+    alignment: CommonBlockAlignment;
   },
   SerializedElementNode
 >;
@@ -63,6 +66,10 @@ export class TableCellNode extends ElementNode {
   __width?: number;
   /** @internal */
   __backgroundColor: null | string;
+  /** @internal */
+  __styles: StyleMap = new Map;
+  /** @internal */
+  __alignment: CommonBlockAlignment = '';
 
   static getType(): string {
     return 'tablecell';
@@ -77,6 +84,8 @@ export class TableCellNode extends ElementNode {
     );
     cellNode.__rowSpan = node.__rowSpan;
     cellNode.__backgroundColor = node.__backgroundColor;
+    cellNode.__styles = new Map(node.__styles);
+    cellNode.__alignment = node.__alignment;
     return cellNode;
   }
 
@@ -94,16 +103,20 @@ export class TableCellNode extends ElementNode {
   }
 
   static importJSON(serializedNode: SerializedTableCellNode): TableCellNode {
-    const colSpan = serializedNode.colSpan || 1;
-    const rowSpan = serializedNode.rowSpan || 1;
-    const cellNode = $createTableCellNode(
-      serializedNode.headerState,
-      colSpan,
-      serializedNode.width || undefined,
+    const node = $createTableCellNode(
+        serializedNode.headerState,
+        serializedNode.colSpan,
+        serializedNode.width,
     );
-    cellNode.__rowSpan = rowSpan;
-    cellNode.__backgroundColor = serializedNode.backgroundColor || null;
-    return cellNode;
+
+    if (serializedNode.rowSpan) {
+        node.setRowSpan(serializedNode.rowSpan);
+    }
+
+    node.setStyles(new Map(Object.entries(serializedNode.styles)));
+    node.setAlignment(serializedNode.alignment);
+
+    return node;
   }
 
   constructor(
@@ -144,34 +157,19 @@ export class TableCellNode extends ElementNode {
       this.hasHeader() && config.theme.tableCellHeader,
     );
 
+    for (const [name, value] of this.__styles.entries()) {
+      element.style.setProperty(name, value);
+    }
+
+    if (this.__alignment) {
+      element.classList.add('align-' + this.__alignment);
+    }
+
     return element;
   }
 
   exportDOM(editor: LexicalEditor): DOMExportOutput {
     const {element} = super.exportDOM(editor);
-
-    if (element) {
-      const element_ = element as HTMLTableCellElement;
-      element_.style.border = '1px solid black';
-      if (this.__colSpan > 1) {
-        element_.colSpan = this.__colSpan;
-      }
-      if (this.__rowSpan > 1) {
-        element_.rowSpan = this.__rowSpan;
-      }
-      element_.style.width = `${this.getWidth() || COLUMN_WIDTH}px`;
-
-      element_.style.verticalAlign = 'top';
-      element_.style.textAlign = 'start';
-
-      const backgroundColor = this.getBackgroundColor();
-      if (backgroundColor !== null) {
-        element_.style.backgroundColor = backgroundColor;
-      } else if (this.hasHeader()) {
-        element_.style.backgroundColor = '#f2f3f5';
-      }
-    }
-
     return {
       element,
     };
@@ -186,6 +184,8 @@ export class TableCellNode extends ElementNode {
       rowSpan: this.__rowSpan,
       type: 'tablecell',
       width: this.getWidth(),
+      styles: Object.fromEntries(this.__styles),
+      alignment: this.__alignment,
     };
   }
 
@@ -231,6 +231,38 @@ export class TableCellNode extends ElementNode {
     return this.getLatest().__width;
   }
 
+  clearWidth(): void {
+    const self = this.getWritable();
+    self.__width = undefined;
+  }
+
+  getStyles(): StyleMap {
+    const self = this.getLatest();
+    return new Map(self.__styles);
+  }
+
+  setStyles(styles: StyleMap): void {
+    const self = this.getWritable();
+    self.__styles = new Map(styles);
+  }
+
+  setAlignment(alignment: CommonBlockAlignment) {
+    const self = this.getWritable();
+    self.__alignment = alignment;
+  }
+
+  getAlignment(): CommonBlockAlignment {
+    const self = this.getLatest();
+    return self.__alignment;
+  }
+
+  updateTag(tag: string): void {
+    const isHeader = tag.toLowerCase() === 'th';
+    const state = isHeader ? TableCellHeaderStates.ROW : TableCellHeaderStates.NO_STATUS;
+    const self = this.getWritable();
+    self.__headerState = state;
+  }
+
   getBackgroundColor(): null | string {
     return this.getLatest().__backgroundColor;
   }
@@ -265,7 +297,9 @@ export class TableCellNode extends ElementNode {
       prevNode.__width !== this.__width ||
       prevNode.__colSpan !== this.__colSpan ||
       prevNode.__rowSpan !== this.__rowSpan ||
-      prevNode.__backgroundColor !== this.__backgroundColor
+      prevNode.__backgroundColor !== this.__backgroundColor ||
+      prevNode.__styles !== this.__styles ||
+      prevNode.__alignment !== this.__alignment
     );
   }
 
@@ -287,38 +321,42 @@ export class TableCellNode extends ElementNode {
 }
 
 export function $convertTableCellNodeElement(
-  domNode: Node,
+    domNode: Node,
 ): DOMConversionOutput {
   const domNode_ = domNode as HTMLTableCellElement;
   const nodeName = domNode.nodeName.toLowerCase();
 
   let width: number | undefined = undefined;
 
+
+  const PIXEL_VALUE_REG_EXP = /^(\d+(?:\.\d+)?)px$/;
   if (PIXEL_VALUE_REG_EXP.test(domNode_.style.width)) {
     width = parseFloat(domNode_.style.width);
   }
 
   const tableCellNode = $createTableCellNode(
-    nodeName === 'th'
-      ? TableCellHeaderStates.ROW
-      : TableCellHeaderStates.NO_STATUS,
-    domNode_.colSpan,
-    width,
+      nodeName === 'th'
+          ? TableCellHeaderStates.ROW
+          : TableCellHeaderStates.NO_STATUS,
+      domNode_.colSpan,
+      width,
   );
 
   tableCellNode.__rowSpan = domNode_.rowSpan;
-  const backgroundColor = domNode_.style.backgroundColor;
-  if (backgroundColor !== '') {
-    tableCellNode.__backgroundColor = backgroundColor;
-  }
 
   const style = domNode_.style;
   const textDecoration = style.textDecoration.split(' ');
   const hasBoldFontWeight =
-    style.fontWeight === '700' || style.fontWeight === 'bold';
+      style.fontWeight === '700' || style.fontWeight === 'bold';
   const hasLinethroughTextDecoration = textDecoration.includes('line-through');
   const hasItalicFontStyle = style.fontStyle === 'italic';
   const hasUnderlineTextDecoration = textDecoration.includes('underline');
+
+  if (domNode instanceof HTMLElement) {
+    tableCellNode.setStyles(extractStyleMapFromElement(domNode));
+    tableCellNode.setAlignment(extractAlignmentFromElement(domNode));
+  }
+
   return {
     after: (childLexicalNodes) => {
       if (childLexicalNodes.length === 0) {
@@ -330,8 +368,8 @@ export function $convertTableCellNodeElement(
       if ($isTableCellNode(parentLexicalNode) && !$isElementNode(lexicalNode)) {
         const paragraphNode = $createParagraphNode();
         if (
-          $isLineBreakNode(lexicalNode) &&
-          lexicalNode.getTextContent() === '\n'
+            $isLineBreakNode(lexicalNode) &&
+            lexicalNode.getTextContent() === '\n'
         ) {
           return null;
         }
@@ -360,7 +398,7 @@ export function $convertTableCellNodeElement(
 }
 
 export function $createTableCellNode(
-  headerState: TableCellHeaderState,
+  headerState: TableCellHeaderState = TableCellHeaderStates.NO_STATUS,
   colSpan = 1,
   width?: number,
 ): TableCellNode {
index 357ba3e738bd6771caea89989bc9825b94b53e8f..ab163005370a4f246701511e5d21c8f646870f64 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 import type {TableCellNode} from './LexicalTableCellNode';
-import type {
+import {
   DOMConversionMap,
   DOMConversionOutput,
   DOMExportOutput,
@@ -15,7 +15,7 @@ import type {
   LexicalEditor,
   LexicalNode,
   NodeKey,
-  SerializedElementNode,
+  SerializedElementNode, Spread,
 } from 'lexical';
 
 import {addClassNamesToElement, isHTMLElement} from '@lexical/utils';
@@ -27,19 +27,36 @@ import {
 
 import {$isTableCellNode} from './LexicalTableCellNode';
 import {TableDOMCell, TableDOMTable} from './LexicalTableObserver';
-import {$isTableRowNode, TableRowNode} from './LexicalTableRowNode';
 import {getTable} from './LexicalTableSelectionHelpers';
-
-export type SerializedTableNode = SerializedElementNode;
+import {CommonBlockNode, copyCommonBlockProperties} from "lexical/nodes/CommonBlockNode";
+import {
+  commonPropertiesDifferent, deserializeCommonBlockNode,
+  SerializedCommonBlockNode, setCommonBlockPropsFromElement,
+  updateElementWithCommonBlockProps
+} from "../../nodes/_common";
+import {el, extractStyleMapFromElement, StyleMap} from "../../utils/dom";
+import {getTableColumnWidths} from "../../utils/tables";
+
+export type SerializedTableNode = Spread<{
+  colWidths: string[];
+  styles: Record<string, string>,
+}, SerializedCommonBlockNode>
 
 /** @noInheritDoc */
-export class TableNode extends ElementNode {
+export class TableNode extends CommonBlockNode {
+  __colWidths: string[] = [];
+  __styles: StyleMap = new Map;
+
   static getType(): string {
     return 'table';
   }
 
   static clone(node: TableNode): TableNode {
-    return new TableNode(node.__key);
+    const newNode = new TableNode(node.__key);
+    copyCommonBlockProperties(node, newNode);
+    newNode.__colWidths = node.__colWidths;
+    newNode.__styles = new Map(node.__styles);
+    return newNode;
   }
 
   static importDOM(): DOMConversionMap | null {
@@ -52,18 +69,24 @@ export class TableNode extends ElementNode {
   }
 
   static importJSON(_serializedNode: SerializedTableNode): TableNode {
-    return $createTableNode();
+    const node = $createTableNode();
+    deserializeCommonBlockNode(_serializedNode, node);
+    node.setColWidths(_serializedNode.colWidths);
+    node.setStyles(new Map(Object.entries(_serializedNode.styles)));
+    return node;
   }
 
   constructor(key?: NodeKey) {
     super(key);
   }
 
-  exportJSON(): SerializedElementNode {
+  exportJSON(): SerializedTableNode {
     return {
       ...super.exportJSON(),
       type: 'table',
       version: 1,
+      colWidths: this.__colWidths,
+      styles: Object.fromEntries(this.__styles),
     };
   }
 
@@ -72,11 +95,33 @@ export class TableNode extends ElementNode {
 
     addClassNamesToElement(tableElement, config.theme.table);
 
+    updateElementWithCommonBlockProps(tableElement, this);
+
+    const colWidths = this.getColWidths();
+    if (colWidths.length > 0) {
+      const colgroup = el('colgroup');
+      for (const width of colWidths) {
+        const col = el('col');
+        if (width) {
+          col.style.width = width;
+        }
+        colgroup.append(col);
+      }
+      tableElement.append(colgroup);
+    }
+
+    for (const [name, value] of this.__styles.entries()) {
+      tableElement.style.setProperty(name, value);
+    }
+
     return tableElement;
   }
 
-  updateDOM(): boolean {
-    return false;
+  updateDOM(_prevNode: TableNode): boolean {
+    return commonPropertiesDifferent(_prevNode, this)
+      || this.__colWidths.join(':') !== _prevNode.__colWidths.join(':')
+      || this.__styles.size !== _prevNode.__styles.size
+      || (Array.from(this.__styles.values()).join(':') !== (Array.from(_prevNode.__styles.values()).join(':')));
   }
 
   exportDOM(editor: LexicalEditor): DOMExportOutput {
@@ -115,6 +160,26 @@ export class TableNode extends ElementNode {
     return true;
   }
 
+  setColWidths(widths: string[]) {
+    const self = this.getWritable();
+    self.__colWidths = widths;
+  }
+
+  getColWidths(): string[] {
+    const self = this.getLatest();
+    return self.__colWidths;
+  }
+
+  getStyles(): StyleMap {
+    const self = this.getLatest();
+    return new Map(self.__styles);
+  }
+
+  setStyles(styles: StyleMap): void {
+    const self = this.getWritable();
+    self.__styles = new Map(styles);
+  }
+
   getCordsFromCellNode(
     tableCellNode: TableCellNode,
     table: TableDOMTable,
@@ -239,8 +304,15 @@ export function $getElementForTableNode(
   return getTable(tableElement);
 }
 
-export function $convertTableElement(_domNode: Node): DOMConversionOutput {
-  return {node: $createTableNode()};
+export function $convertTableElement(element: HTMLElement): DOMConversionOutput {
+  const node = $createTableNode();
+  setCommonBlockPropsFromElement(element, node);
+
+  const colWidths = getTableColumnWidths(element as HTMLTableElement);
+  node.setColWidths(colWidths);
+  node.setStyles(extractStyleMapFromElement(element));
+
+  return {node};
 }
 
 export function $createTableNode(): TableNode {
index eddea69a27eb056b6d708f101eb9b0a222453264..07db2b65dc0daaf73ed72acb200c08c08e4edadd 100644 (file)
@@ -20,11 +20,12 @@ import {
   SerializedElementNode,
 } from 'lexical';
 
-import {PIXEL_VALUE_REG_EXP} from './constants';
+import {extractStyleMapFromElement, sizeToPixels, StyleMap} from "../../utils/dom";
 
 export type SerializedTableRowNode = Spread<
   {
-    height?: number;
+    styles: Record<string, string>,
+    height?: number,
   },
   SerializedElementNode
 >;
@@ -33,13 +34,17 @@ export type SerializedTableRowNode = Spread<
 export class TableRowNode extends ElementNode {
   /** @internal */
   __height?: number;
+  /** @internal */
+  __styles: StyleMap = new Map();
 
   static getType(): string {
     return 'tablerow';
   }
 
   static clone(node: TableRowNode): TableRowNode {
-    return new TableRowNode(node.__height, node.__key);
+    const newNode = new TableRowNode(node.__key);
+    newNode.__styles = new Map(node.__styles);
+    return newNode;
   }
 
   static importDOM(): DOMConversionMap | null {
@@ -52,20 +57,24 @@ export class TableRowNode extends ElementNode {
   }
 
   static importJSON(serializedNode: SerializedTableRowNode): TableRowNode {
-    return $createTableRowNode(serializedNode.height);
+    const node = $createTableRowNode();
+
+    node.setStyles(new Map(Object.entries(serializedNode.styles)));
+
+    return node;
   }
 
-  constructor(height?: number, key?: NodeKey) {
+  constructor(key?: NodeKey) {
     super(key);
-    this.__height = height;
   }
 
   exportJSON(): SerializedTableRowNode {
     return {
       ...super.exportJSON(),
-      ...(this.getHeight() && {height: this.getHeight()}),
       type: 'tablerow',
       version: 1,
+      styles: Object.fromEntries(this.__styles),
+      height: this.__height || 0,
     };
   }
 
@@ -76,6 +85,10 @@ export class TableRowNode extends ElementNode {
       element.style.height = `${this.__height}px`;
     }
 
+    for (const [name, value] of this.__styles.entries()) {
+      element.style.setProperty(name, value);
+    }
+
     addClassNamesToElement(element, config.theme.tableRow);
 
     return element;
@@ -85,6 +98,16 @@ export class TableRowNode extends ElementNode {
     return true;
   }
 
+  getStyles(): StyleMap {
+    const self = this.getLatest();
+    return new Map(self.__styles);
+  }
+
+  setStyles(styles: StyleMap): void {
+    const self = this.getWritable();
+    self.__styles = new Map(styles);
+  }
+
   setHeight(height: number): number | null | undefined {
     const self = this.getWritable();
     self.__height = height;
@@ -96,7 +119,8 @@ export class TableRowNode extends ElementNode {
   }
 
   updateDOM(prevNode: TableRowNode): boolean {
-    return prevNode.__height !== this.__height;
+    return prevNode.__height !== this.__height
+        || prevNode.__styles !== this.__styles;
   }
 
   canBeEmpty(): false {
@@ -109,18 +133,21 @@ export class TableRowNode extends ElementNode {
 }
 
 export function $convertTableRowElement(domNode: Node): DOMConversionOutput {
-  const domNode_ = domNode as HTMLTableCellElement;
-  let height: number | undefined = undefined;
+  const rowNode = $createTableRowNode();
+  const domNode_ = domNode as HTMLElement;
+
+  const height = sizeToPixels(domNode_.style.height);
+  rowNode.setHeight(height);
 
-  if (PIXEL_VALUE_REG_EXP.test(domNode_.style.height)) {
-    height = parseFloat(domNode_.style.height);
+  if (domNode instanceof HTMLElement) {
+    rowNode.setStyles(extractStyleMapFromElement(domNode));
   }
 
-  return {node: $createTableRowNode(height)};
+  return {node: rowNode};
 }
 
-export function $createTableRowNode(height?: number): TableRowNode {
-  return $applyNodeReplacement(new TableRowNode(height));
+export function $createTableRowNode(): TableRowNode {
+  return $applyNodeReplacement(new TableRowNode());
 }
 
 export function $isTableRowNode(
index 812cccc0d251550134ff1b2256a22bad8c2be6a6..6c3317c5dfaff54878b9c3bd72e751fb4fd0f695 100644 (file)
@@ -438,59 +438,6 @@ export function applyTableHandlers(
     ),
   );
 
-  tableObserver.listenersToRemove.add(
-    editor.registerCommand<ElementFormatType>(
-      FORMAT_ELEMENT_COMMAND,
-      (formatType) => {
-        const selection = $getSelection();
-        if (
-          !$isTableSelection(selection) ||
-          !$isSelectionInTable(selection, tableNode)
-        ) {
-          return false;
-        }
-
-        const anchorNode = selection.anchor.getNode();
-        const focusNode = selection.focus.getNode();
-        if (!$isTableCellNode(anchorNode) || !$isTableCellNode(focusNode)) {
-          return false;
-        }
-
-        const [tableMap, anchorCell, focusCell] = $computeTableMap(
-          tableNode,
-          anchorNode,
-          focusNode,
-        );
-        const maxRow = Math.max(anchorCell.startRow, focusCell.startRow);
-        const maxColumn = Math.max(
-          anchorCell.startColumn,
-          focusCell.startColumn,
-        );
-        const minRow = Math.min(anchorCell.startRow, focusCell.startRow);
-        const minColumn = Math.min(
-          anchorCell.startColumn,
-          focusCell.startColumn,
-        );
-        for (let i = minRow; i <= maxRow; i++) {
-          for (let j = minColumn; j <= maxColumn; j++) {
-            const cell = tableMap[i][j].cell;
-            cell.setFormat(formatType);
-
-            const cellChildren = cell.getChildren();
-            for (let k = 0; k < cellChildren.length; k++) {
-              const child = cellChildren[k];
-              if ($isElementNode(child) && !child.isInline()) {
-                child.setFormat(formatType);
-              }
-            }
-          }
-        }
-        return true;
-      },
-      COMMAND_PRIORITY_CRITICAL,
-    ),
-  );
-
   tableObserver.listenersToRemove.add(
     editor.registerCommand(
       CONTROLLED_TEXT_INSERTION_COMMAND,
index 285d587bf5f204128903edc168ac9de9d6c90d88..5dbf03d9e9c7d82c6bf55fe7230f511659382da8 100644 (file)
@@ -39,10 +39,9 @@ describe('LexicalTableRowNode tests', () => {
           `<tr class="${editorConfig.theme.tableRow}"></tr>`,
         );
 
-        const rowHeight = 36;
-        const rowWithCustomHeightNode = $createTableRowNode(36);
+        const rowWithCustomHeightNode = $createTableRowNode();
         expect(rowWithCustomHeightNode.createDOM(editorConfig).outerHTML).toBe(
-          `<tr style="height: ${rowHeight}px;" class="${editorConfig.theme.tableRow}"></tr>`,
+          `<tr class="${editorConfig.theme.tableRow}"></tr>`,
         );
       });
     });
diff --git a/resources/js/wysiwyg/nodes/custom-table-cell.ts b/resources/js/wysiwyg/nodes/custom-table-cell.ts
deleted file mode 100644 (file)
index 793302c..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-import {
-    $createParagraphNode,
-    $isElementNode,
-    $isLineBreakNode,
-    $isTextNode,
-    DOMConversionMap,
-    DOMConversionOutput,
-    DOMExportOutput,
-    EditorConfig,
-    LexicalEditor,
-    LexicalNode,
-    Spread
-} from "lexical";
-
-import {
-    $createTableCellNode,
-    $isTableCellNode,
-    SerializedTableCellNode,
-    TableCellHeaderStates,
-    TableCellNode
-} from "@lexical/table";
-import {TableCellHeaderState} from "@lexical/table/LexicalTableCellNode";
-import {extractStyleMapFromElement, StyleMap} from "../utils/dom";
-import {CommonBlockAlignment, extractAlignmentFromElement} from "./_common";
-
-export type SerializedCustomTableCellNode = Spread<{
-    styles: Record<string, string>;
-    alignment: CommonBlockAlignment;
-}, SerializedTableCellNode>
-
-export class CustomTableCellNode extends TableCellNode {
-    __styles: StyleMap = new Map;
-    __alignment: CommonBlockAlignment = '';
-
-    static getType(): string {
-        return 'custom-table-cell';
-    }
-
-    static clone(node: CustomTableCellNode): CustomTableCellNode {
-        const cellNode = new CustomTableCellNode(
-            node.__headerState,
-            node.__colSpan,
-            node.__width,
-            node.__key,
-        );
-        cellNode.__rowSpan = node.__rowSpan;
-        cellNode.__styles = new Map(node.__styles);
-        cellNode.__alignment = node.__alignment;
-        return cellNode;
-    }
-
-    clearWidth(): void {
-        const self = this.getWritable();
-        self.__width = undefined;
-    }
-
-    getStyles(): StyleMap {
-        const self = this.getLatest();
-        return new Map(self.__styles);
-    }
-
-    setStyles(styles: StyleMap): void {
-        const self = this.getWritable();
-        self.__styles = new Map(styles);
-    }
-
-    setAlignment(alignment: CommonBlockAlignment) {
-        const self = this.getWritable();
-        self.__alignment = alignment;
-    }
-
-    getAlignment(): CommonBlockAlignment {
-        const self = this.getLatest();
-        return self.__alignment;
-    }
-
-    updateTag(tag: string): void {
-        const isHeader = tag.toLowerCase() === 'th';
-        const state = isHeader ? TableCellHeaderStates.ROW : TableCellHeaderStates.NO_STATUS;
-        const self = this.getWritable();
-        self.__headerState = state;
-    }
-
-    createDOM(config: EditorConfig): HTMLElement {
-        const element = super.createDOM(config);
-
-        for (const [name, value] of this.__styles.entries()) {
-            element.style.setProperty(name, value);
-        }
-
-        if (this.__alignment) {
-            element.classList.add('align-' + this.__alignment);
-        }
-
-        return element;
-    }
-
-    updateDOM(prevNode: CustomTableCellNode): boolean {
-        return super.updateDOM(prevNode)
-            || this.__styles !== prevNode.__styles
-            || this.__alignment !== prevNode.__alignment;
-    }
-
-    static importDOM(): DOMConversionMap | null {
-        return {
-            td: (node: Node) => ({
-                conversion: $convertCustomTableCellNodeElement,
-                priority: 0,
-            }),
-            th: (node: Node) => ({
-                conversion: $convertCustomTableCellNodeElement,
-                priority: 0,
-            }),
-        };
-    }
-
-    exportDOM(editor: LexicalEditor): DOMExportOutput {
-        const element = this.createDOM(editor._config);
-        return {
-            element
-        };
-    }
-
-    static importJSON(serializedNode: SerializedCustomTableCellNode): CustomTableCellNode {
-        const node = $createCustomTableCellNode(
-            serializedNode.headerState,
-            serializedNode.colSpan,
-            serializedNode.width,
-        );
-
-        node.setStyles(new Map(Object.entries(serializedNode.styles)));
-        node.setAlignment(serializedNode.alignment);
-
-        return node;
-    }
-
-    exportJSON(): SerializedCustomTableCellNode {
-        return {
-            ...super.exportJSON(),
-            type: 'custom-table-cell',
-            styles: Object.fromEntries(this.__styles),
-            alignment: this.__alignment,
-        };
-    }
-}
-
-function $convertCustomTableCellNodeElement(domNode: Node): DOMConversionOutput {
-    const output =  $convertTableCellNodeElement(domNode);
-
-    if (domNode instanceof HTMLElement && output.node instanceof CustomTableCellNode) {
-        output.node.setStyles(extractStyleMapFromElement(domNode));
-        output.node.setAlignment(extractAlignmentFromElement(domNode));
-    }
-
-    return output;
-}
-
-/**
- * Function taken from:
- * https://github.com/facebook/lexical/blob/e1881a6e409e1541c10dd0b5378f3a38c9dc8c9e/packages/lexical-table/src/LexicalTableCellNode.ts#L289
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- * MIT LICENSE
- * Modified since copy.
- */
-export function $convertTableCellNodeElement(
-    domNode: Node,
-): DOMConversionOutput {
-    const domNode_ = domNode as HTMLTableCellElement;
-    const nodeName = domNode.nodeName.toLowerCase();
-
-    let width: number | undefined = undefined;
-
-
-    const PIXEL_VALUE_REG_EXP = /^(\d+(?:\.\d+)?)px$/;
-    if (PIXEL_VALUE_REG_EXP.test(domNode_.style.width)) {
-        width = parseFloat(domNode_.style.width);
-    }
-
-    const tableCellNode = $createTableCellNode(
-        nodeName === 'th'
-            ? TableCellHeaderStates.ROW
-            : TableCellHeaderStates.NO_STATUS,
-        domNode_.colSpan,
-        width,
-    );
-
-    tableCellNode.__rowSpan = domNode_.rowSpan;
-
-    const style = domNode_.style;
-    const textDecoration = style.textDecoration.split(' ');
-    const hasBoldFontWeight =
-        style.fontWeight === '700' || style.fontWeight === 'bold';
-    const hasLinethroughTextDecoration = textDecoration.includes('line-through');
-    const hasItalicFontStyle = style.fontStyle === 'italic';
-    const hasUnderlineTextDecoration = textDecoration.includes('underline');
-    return {
-        after: (childLexicalNodes) => {
-            if (childLexicalNodes.length === 0) {
-                childLexicalNodes.push($createParagraphNode());
-            }
-            return childLexicalNodes;
-        },
-        forChild: (lexicalNode, parentLexicalNode) => {
-            if ($isTableCellNode(parentLexicalNode) && !$isElementNode(lexicalNode)) {
-                const paragraphNode = $createParagraphNode();
-                if (
-                    $isLineBreakNode(lexicalNode) &&
-                    lexicalNode.getTextContent() === '\n'
-                ) {
-                    return null;
-                }
-                if ($isTextNode(lexicalNode)) {
-                    if (hasBoldFontWeight) {
-                        lexicalNode.toggleFormat('bold');
-                    }
-                    if (hasLinethroughTextDecoration) {
-                        lexicalNode.toggleFormat('strikethrough');
-                    }
-                    if (hasItalicFontStyle) {
-                        lexicalNode.toggleFormat('italic');
-                    }
-                    if (hasUnderlineTextDecoration) {
-                        lexicalNode.toggleFormat('underline');
-                    }
-                }
-                paragraphNode.append(lexicalNode);
-                return paragraphNode;
-            }
-
-            return lexicalNode;
-        },
-        node: tableCellNode,
-    };
-}
-
-
-export function $createCustomTableCellNode(
-    headerState: TableCellHeaderState = TableCellHeaderStates.NO_STATUS,
-    colSpan = 1,
-    width?: number,
-): CustomTableCellNode {
-    return new CustomTableCellNode(headerState, colSpan, width);
-}
-
-export function $isCustomTableCellNode(node: LexicalNode | null | undefined): node is CustomTableCellNode {
-    return node instanceof CustomTableCellNode;
-}
\ No newline at end of file
diff --git a/resources/js/wysiwyg/nodes/custom-table-row.ts b/resources/js/wysiwyg/nodes/custom-table-row.ts
deleted file mode 100644 (file)
index f4702f3..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-import {
-    DOMConversionMap,
-    DOMConversionOutput,
-    EditorConfig,
-    LexicalNode,
-    Spread
-} from "lexical";
-
-import {
-    SerializedTableRowNode,
-    TableRowNode
-} from "@lexical/table";
-import {NodeKey} from "lexical/LexicalNode";
-import {extractStyleMapFromElement, StyleMap} from "../utils/dom";
-
-export type SerializedCustomTableRowNode = Spread<{
-    styles: Record<string, string>,
-}, SerializedTableRowNode>
-
-export class CustomTableRowNode extends TableRowNode {
-    __styles: StyleMap = new Map();
-
-    constructor(key?: NodeKey) {
-        super(0, key);
-    }
-
-    static getType(): string {
-        return 'custom-table-row';
-    }
-
-    static clone(node: CustomTableRowNode): CustomTableRowNode {
-        const cellNode = new CustomTableRowNode(node.__key);
-
-        cellNode.__styles = new Map(node.__styles);
-        return cellNode;
-    }
-
-    getStyles(): StyleMap {
-        const self = this.getLatest();
-        return new Map(self.__styles);
-    }
-
-    setStyles(styles: StyleMap): void {
-        const self = this.getWritable();
-        self.__styles = new Map(styles);
-    }
-
-    createDOM(config: EditorConfig): HTMLElement {
-        const element = super.createDOM(config);
-
-        for (const [name, value] of this.__styles.entries()) {
-            element.style.setProperty(name, value);
-        }
-
-        return element;
-    }
-
-    updateDOM(prevNode: CustomTableRowNode): boolean {
-        return super.updateDOM(prevNode)
-            || this.__styles !== prevNode.__styles;
-    }
-
-    static importDOM(): DOMConversionMap | null {
-        return {
-            tr: (node: Node) => ({
-                conversion: $convertTableRowElement,
-                priority: 0,
-            }),
-        };
-    }
-
-    static importJSON(serializedNode: SerializedCustomTableRowNode): CustomTableRowNode {
-        const node = $createCustomTableRowNode();
-
-        node.setStyles(new Map(Object.entries(serializedNode.styles)));
-
-        return node;
-    }
-
-    exportJSON(): SerializedCustomTableRowNode {
-        return {
-            ...super.exportJSON(),
-            height: 0,
-            type: 'custom-table-row',
-            styles: Object.fromEntries(this.__styles),
-        };
-    }
-}
-
-export function $convertTableRowElement(domNode: Node): DOMConversionOutput {
-    const rowNode = $createCustomTableRowNode();
-
-    if (domNode instanceof HTMLElement) {
-        rowNode.setStyles(extractStyleMapFromElement(domNode));
-    }
-
-    return {node: rowNode};
-}
-
-export function $createCustomTableRowNode(): CustomTableRowNode {
-    return new CustomTableRowNode();
-}
-
-export function $isCustomTableRowNode(node: LexicalNode | null | undefined): node is CustomTableRowNode {
-    return node instanceof CustomTableRowNode;
-}
\ No newline at end of file
diff --git a/resources/js/wysiwyg/nodes/custom-table.ts b/resources/js/wysiwyg/nodes/custom-table.ts
deleted file mode 100644 (file)
index c25c06c..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-import {SerializedTableNode, TableNode} from "@lexical/table";
-import {DOMConversion, DOMConversionMap, DOMConversionOutput, LexicalNode, Spread} from "lexical";
-import {EditorConfig} from "lexical/LexicalEditor";
-
-import {el, extractStyleMapFromElement, StyleMap} from "../utils/dom";
-import {getTableColumnWidths} from "../utils/tables";
-import {
-    CommonBlockAlignment, deserializeCommonBlockNode,
-    SerializedCommonBlockNode,
-    setCommonBlockPropsFromElement,
-    updateElementWithCommonBlockProps
-} from "./_common";
-
-export type SerializedCustomTableNode = Spread<Spread<{
-    colWidths: string[];
-    styles: Record<string, string>,
-}, SerializedTableNode>, SerializedCommonBlockNode>
-
-export class CustomTableNode extends TableNode {
-    __id: string = '';
-    __colWidths: string[] = [];
-    __styles: StyleMap = new Map;
-    __alignment: CommonBlockAlignment = '';
-    __inset: number = 0;
-
-    static getType() {
-        return 'custom-table';
-    }
-
-    setId(id: string) {
-        const self = this.getWritable();
-        self.__id = id;
-    }
-
-    getId(): string {
-        const self = this.getLatest();
-        return self.__id;
-    }
-
-    setAlignment(alignment: CommonBlockAlignment) {
-        const self = this.getWritable();
-        self.__alignment = alignment;
-    }
-
-    getAlignment(): CommonBlockAlignment {
-        const self = this.getLatest();
-        return self.__alignment;
-    }
-
-    setInset(size: number) {
-        const self = this.getWritable();
-        self.__inset = size;
-    }
-
-    getInset(): number {
-        const self = this.getLatest();
-        return self.__inset;
-    }
-
-    setColWidths(widths: string[]) {
-        const self = this.getWritable();
-        self.__colWidths = widths;
-    }
-
-    getColWidths(): string[] {
-        const self = this.getLatest();
-        return self.__colWidths;
-    }
-
-    getStyles(): StyleMap {
-        const self = this.getLatest();
-        return new Map(self.__styles);
-    }
-
-    setStyles(styles: StyleMap): void {
-        const self = this.getWritable();
-        self.__styles = new Map(styles);
-    }
-
-    static clone(node: CustomTableNode) {
-        const newNode = new CustomTableNode(node.__key);
-        newNode.__id = node.__id;
-        newNode.__colWidths = node.__colWidths;
-        newNode.__styles = new Map(node.__styles);
-        newNode.__alignment = node.__alignment;
-        newNode.__inset = node.__inset;
-        return newNode;
-    }
-
-    createDOM(config: EditorConfig): HTMLElement {
-        const dom = super.createDOM(config);
-        updateElementWithCommonBlockProps(dom, this);
-
-        const colWidths = this.getColWidths();
-        if (colWidths.length > 0) {
-            const colgroup = el('colgroup');
-            for (const width of colWidths) {
-                const col = el('col');
-                if (width) {
-                    col.style.width = width;
-                }
-                colgroup.append(col);
-            }
-            dom.append(colgroup);
-        }
-
-        for (const [name, value] of this.__styles.entries()) {
-            dom.style.setProperty(name, value);
-        }
-
-        return dom;
-    }
-
-    updateDOM(): boolean {
-        return true;
-    }
-
-    exportJSON(): SerializedCustomTableNode {
-        return {
-            ...super.exportJSON(),
-            type: 'custom-table',
-            version: 1,
-            id: this.__id,
-            colWidths: this.__colWidths,
-            styles: Object.fromEntries(this.__styles),
-            alignment: this.__alignment,
-            inset: this.__inset,
-        };
-    }
-
-    static importJSON(serializedNode: SerializedCustomTableNode): CustomTableNode {
-        const node = $createCustomTableNode();
-        deserializeCommonBlockNode(serializedNode, node);
-        node.setColWidths(serializedNode.colWidths);
-        node.setStyles(new Map(Object.entries(serializedNode.styles)));
-        return node;
-    }
-
-    static importDOM(): DOMConversionMap|null {
-        return {
-            table(node: HTMLElement): DOMConversion|null {
-                return {
-                    conversion: (element: HTMLElement): DOMConversionOutput|null => {
-                        const node = $createCustomTableNode();
-                        setCommonBlockPropsFromElement(element, node);
-
-                        const colWidths = getTableColumnWidths(element as HTMLTableElement);
-                        node.setColWidths(colWidths);
-                        node.setStyles(extractStyleMapFromElement(element));
-
-                        return {node};
-                    },
-                    priority: 1,
-                };
-            },
-        };
-    }
-}
-
-export function $createCustomTableNode(): CustomTableNode {
-    return new CustomTableNode();
-}
-
-export function $isCustomTableNode(node: LexicalNode | null | undefined): node is CustomTableNode {
-    return node instanceof CustomTableNode;
-}
index 7e0ce9daf2bf437fe44019a8f335077825b7350d..03213e2629ab5bcd1991a4f1e76f83f75867ab04 100644 (file)
@@ -11,14 +11,11 @@ import {ImageNode} from "./image";
 import {DetailsNode, SummaryNode} from "./details";
 import {ListItemNode, ListNode} from "@lexical/list";
 import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
-import {CustomTableNode} from "./custom-table";
 import {HorizontalRuleNode} from "./horizontal-rule";
 import {CodeBlockNode} from "./code-block";
 import {DiagramNode} from "./diagram";
 import {EditorUiContext} from "../ui/framework/core";
 import {MediaNode} from "./media";
-import {CustomTableCellNode} from "./custom-table-cell";
-import {CustomTableRowNode} from "./custom-table-row";
 import {HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
 import {QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
 
@@ -32,9 +29,9 @@ export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> |
         QuoteNode,
         ListNode,
         ListItemNode,
-        CustomTableNode,
-        CustomTableRowNode,
-        CustomTableCellNode,
+        TableNode,
+        TableRowNode,
+        TableCellNode,
         ImageNode, // TODO - Alignment
         HorizontalRuleNode,
         DetailsNode, SummaryNode,
@@ -43,30 +40,6 @@ export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> |
         MediaNode, // TODO - Alignment
         ParagraphNode,
         LinkNode,
-        {
-            replace: TableNode,
-            with(node: TableNode) {
-                return new CustomTableNode();
-            }
-        },
-        {
-            replace: TableRowNode,
-            with(node: TableRowNode) {
-                return new CustomTableRowNode();
-            }
-        },
-        {
-            replace: TableCellNode,
-            with: (node: TableCellNode) => {
-                const cell = new CustomTableCellNode(
-                    node.__headerState,
-                    node.__colSpan,
-                    node.__width,
-                );
-                cell.__rowSpan = node.__rowSpan;
-                return cell;
-            }
-        },
     ];
 }
 
index fc4196f0a0888e9ab8ac4d5e41491049567c0a7c..2e4883d88e6806ae2d30c80b81ac15118c805a2d 100644 (file)
@@ -9,17 +9,15 @@ import insertRowAboveIcon from "@icons/editor/table-insert-row-above.svg";
 import insertRowBelowIcon from "@icons/editor/table-insert-row-below.svg";
 import {EditorUiContext} from "../../framework/core";
 import {$getSelection, BaseSelection} from "lexical";
-import {$isCustomTableNode} from "../../../nodes/custom-table";
 import {
     $deleteTableColumn__EXPERIMENTAL,
     $deleteTableRow__EXPERIMENTAL,
     $insertTableColumn__EXPERIMENTAL,
-    $insertTableRow__EXPERIMENTAL,
-    $isTableNode, $isTableSelection, $unmergeCell, TableCellNode,
+    $insertTableRow__EXPERIMENTAL, $isTableCellNode,
+    $isTableNode, $isTableRowNode, $isTableSelection, $unmergeCell, TableCellNode,
 } from "@lexical/table";
 import {$getNodeFromSelection, $selectionContainsNodeType} from "../../../utils/selection";
 import {$getParentOfType} from "../../../utils/nodes";
-import {$isCustomTableCellNode} from "../../../nodes/custom-table-cell";
 import {$showCellPropertiesForm, $showRowPropertiesForm, $showTablePropertiesForm} from "../forms/tables";
 import {
     $clearTableFormatting,
@@ -27,7 +25,6 @@ import {
     $getTableRowsFromSelection,
     $mergeTableCellsInSelection
 } from "../../../utils/tables";
-import {$isCustomTableRowNode} from "../../../nodes/custom-table-row";
 import {
     $copySelectedColumnsToClipboard,
     $copySelectedRowsToClipboard,
@@ -41,7 +38,7 @@ import {
 } from "../../../utils/table-copy-paste";
 
 const neverActive = (): boolean => false;
-const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isCustomTableCellNode);
+const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isTableCellNode);
 
 export const table: EditorBasicButtonDefinition = {
     label: 'Table',
@@ -54,7 +51,7 @@ export const tableProperties: EditorButtonDefinition = {
     action(context: EditorUiContext) {
         context.editor.getEditorState().read(() => {
             const table = $getTableFromSelection($getSelection());
-            if ($isCustomTableNode(table)) {
+            if ($isTableNode(table)) {
                 $showTablePropertiesForm(table, context);
             }
         });
@@ -68,13 +65,13 @@ export const clearTableFormatting: EditorButtonDefinition = {
     format: 'long',
     action(context: EditorUiContext) {
         context.editor.update(() => {
-            const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
-            if (!$isCustomTableCellNode(cell)) {
+            const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
+            if (!$isTableCellNode(cell)) {
                 return;
             }
 
             const table = $getParentOfType(cell, $isTableNode);
-            if ($isCustomTableNode(table)) {
+            if ($isTableNode(table)) {
                 $clearTableFormatting(table);
             }
         });
@@ -88,13 +85,13 @@ export const resizeTableToContents: EditorButtonDefinition = {
     format: 'long',
     action(context: EditorUiContext) {
         context.editor.update(() => {
-            const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
-            if (!$isCustomTableCellNode(cell)) {
+            const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
+            if (!$isTableCellNode(cell)) {
                 return;
             }
 
-            const table = $getParentOfType(cell, $isCustomTableNode);
-            if ($isCustomTableNode(table)) {
+            const table = $getParentOfType(cell, $isTableNode);
+            if ($isTableNode(table)) {
                 $clearTableSizes(table);
             }
         });
@@ -108,7 +105,7 @@ export const deleteTable: EditorButtonDefinition = {
     icon: deleteIcon,
     action(context: EditorUiContext) {
         context.editor.update(() => {
-            const table = $getNodeFromSelection($getSelection(), $isCustomTableNode);
+            const table = $getNodeFromSelection($getSelection(), $isTableNode);
             if (table) {
                 table.remove();
             }
@@ -169,7 +166,7 @@ export const rowProperties: EditorButtonDefinition = {
     action(context: EditorUiContext) {
         context.editor.getEditorState().read(() => {
             const rows = $getTableRowsFromSelection($getSelection());
-            if ($isCustomTableRowNode(rows[0])) {
+            if ($isTableRowNode(rows[0])) {
                 $showRowPropertiesForm(rows[0], context);
             }
         });
@@ -350,8 +347,8 @@ export const cellProperties: EditorButtonDefinition = {
     format: 'long',
     action(context: EditorUiContext) {
         context.editor.getEditorState().read(() => {
-            const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
-            if ($isCustomTableCellNode(cell)) {
+            const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
+            if ($isTableCellNode(cell)) {
                 $showCellPropertiesForm(cell, context);
             }
         });
@@ -387,7 +384,7 @@ export const splitCell: EditorButtonDefinition = {
     },
     isActive: neverActive,
     isDisabled(selection) {
-        const cell = $getNodeFromSelection(selection, $isCustomTableCellNode) as TableCellNode|null;
+        const cell = $getNodeFromSelection(selection, $isTableCellNode) as TableCellNode|null;
         if (cell) {
             const merged = cell.getRowSpan() > 1 || cell.getColSpan() > 1;
             return !merged;
index 5a41c85b3dabbb8d7b479b43b9d96a568d8f3a1b..3cfe9592ccb9e16e034fbe8ec7473a3136e1b513 100644 (file)
@@ -5,7 +5,6 @@ import {
     EditorSelectFormFieldDefinition
 } from "../../framework/forms";
 import {EditorUiContext} from "../../framework/core";
-import {CustomTableCellNode} from "../../../nodes/custom-table-cell";
 import {EditorFormModal} from "../../framework/modals";
 import {$getSelection, ElementFormatType} from "lexical";
 import {
@@ -16,8 +15,8 @@ import {
     $setTableCellColumnWidth
 } from "../../../utils/tables";
 import {formatSizeValue} from "../../../utils/dom";
-import {CustomTableRowNode} from "../../../nodes/custom-table-row";
-import {CustomTableNode} from "../../../nodes/custom-table";
+import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
+import {CommonBlockAlignment} from "../../../nodes/_common";
 
 const borderStyleInput: EditorSelectFormFieldDefinition = {
     label: 'Border style',
@@ -62,14 +61,14 @@ const alignmentInput: EditorSelectFormFieldDefinition = {
     }
 };
 
-export function $showCellPropertiesForm(cell: CustomTableCellNode, context: EditorUiContext): EditorFormModal {
+export function $showCellPropertiesForm(cell: TableCellNode, context: EditorUiContext): EditorFormModal {
     const styles = cell.getStyles();
     const modalForm = context.manager.createModal('cell_properties');
     modalForm.show({
         width: $getTableCellColumnWidth(context.editor, cell),
         height: styles.get('height') || '',
         type: cell.getTag(),
-        h_align: cell.getFormatType(),
+        h_align: cell.getAlignment(),
         v_align: styles.get('vertical-align') || '',
         border_width: styles.get('border-width') || '',
         border_style: styles.get('border-style') || '',
@@ -89,7 +88,7 @@ export const cellProperties: EditorFormDefinition = {
 
                 $setTableCellColumnWidth(cell, width);
                 cell.updateTag(formData.get('type')?.toString() || '');
-                cell.setFormat((formData.get('h_align')?.toString() || '') as ElementFormatType);
+                cell.setAlignment((formData.get('h_align')?.toString() || '') as CommonBlockAlignment);
 
                 const styles = cell.getStyles();
                 styles.set('height', formatSizeValue(formData.get('height')?.toString() || ''));
@@ -172,7 +171,7 @@ export const cellProperties: EditorFormDefinition = {
     ],
 };
 
-export function $showRowPropertiesForm(row: CustomTableRowNode, context: EditorUiContext): EditorFormModal {
+export function $showRowPropertiesForm(row: TableRowNode, context: EditorUiContext): EditorFormModal {
     const styles = row.getStyles();
     const modalForm = context.manager.createModal('row_properties');
     modalForm.show({
@@ -216,7 +215,7 @@ export const rowProperties: EditorFormDefinition = {
     ],
 };
 
-export function $showTablePropertiesForm(table: CustomTableNode, context: EditorUiContext): EditorFormModal {
+export function $showTablePropertiesForm(table: TableNode, context: EditorUiContext): EditorFormModal {
     const styles = table.getStyles();
     const modalForm = context.manager.createModal('table_properties');
     modalForm.show({
@@ -229,7 +228,7 @@ export function $showTablePropertiesForm(table: CustomTableNode, context: Editor
         border_color: styles.get('border-color') || '',
         background_color: styles.get('background-color') || '',
         // caption: '', TODO
-        align: table.getFormatType(),
+        align: table.getAlignment(),
     });
     return modalForm;
 }
@@ -253,12 +252,12 @@ export const tableProperties: EditorFormDefinition = {
             styles.set('background-color', formData.get('background_color')?.toString() || '');
             table.setStyles(styles);
 
-            table.setFormat(formData.get('align') as ElementFormatType);
+            table.setAlignment(formData.get('align') as CommonBlockAlignment);
 
             const cellPadding = (formData.get('cell_padding')?.toString() || '');
             if (cellPadding) {
                 const cellPaddingFormatted = formatSizeValue(cellPadding);
-                $forEachTableCell(table, (cell: CustomTableCellNode) => {
+                $forEachTableCell(table, (cell: TableCellNode) => {
                     const styles = cell.getStyles();
                     styles.set('padding', cellPaddingFormatted);
                     cell.setStyles(styles);
index 30ff3abc56caa1df99535934fdbcad0e341dbc25..6f026ca1895daf2f713204d1aab637ef0916798d 100644 (file)
@@ -1,6 +1,5 @@
 import {EditorUiElement} from "../core";
 import {$createTableNodeWithDimensions} from "@lexical/table";
-import {CustomTableNode} from "../../../nodes/custom-table";
 import {$insertNewBlockNodeAtSelection} from "../../../utils/selection";
 import {el} from "../../../utils/dom";
 
@@ -78,7 +77,7 @@ export class EditorTableCreator extends EditorUiElement {
         const colWidths = Array(columns).fill(targetColWidth + 'px');
 
         this.getContext().editor.update(() => {
-            const table = $createTableNodeWithDimensions(rows, columns, false) as CustomTableNode;
+            const table = $createTableNodeWithDimensions(rows, columns, false);
             table.setColWidths(colWidths);
             $insertNewBlockNodeAtSelection(table);
         });
index 37f1b6f01ee8ea2feb3b7fc4da47b3bbcdf17786..4256fdafc65a98fecac926d48ef061c51fece98c 100644 (file)
@@ -1,7 +1,6 @@
 import {$getNearestNodeFromDOMNode, LexicalEditor} from "lexical";
 import {MouseDragTracker, MouseDragTrackerDistance} from "./mouse-drag-tracker";
-import {CustomTableNode} from "../../../nodes/custom-table";
-import {TableRowNode} from "@lexical/table";
+import {TableNode, TableRowNode} from "@lexical/table";
 import {el} from "../../../utils/dom";
 import {$getTableColumnWidth, $setTableColumnWidth} from "../../../utils/tables";
 
@@ -148,7 +147,7 @@ class TableResizer {
 
                     _this.editor.update(() => {
                         const table = $getNearestNodeFromDOMNode(parentTable);
-                        if (table instanceof CustomTableNode) {
+                        if (table instanceof TableNode) {
                             const originalWidth = $getTableColumnWidth(_this.editor, table, cellIndex);
                             const newWidth = Math.max(originalWidth + change, 10);
                             $setTableColumnWidth(table, cellIndex, newWidth);
index f631fb804a550d82a67fe49c23b5722c9834e001..d3d8925505f8a71074b4138c35caec38c51b611e 100644 (file)
@@ -1,12 +1,12 @@
 import {$getNodeByKey, LexicalEditor} from "lexical";
 import {NodeKey} from "lexical/LexicalNode";
 import {
+    $isTableNode,
     applyTableHandlers,
     HTMLTableElementWithWithTableSelectionState,
     TableNode,
     TableObserver
 } from "@lexical/table";
-import {$isCustomTableNode, CustomTableNode} from "../../../nodes/custom-table";
 
 // File adapted from logic in:
 // https://github.com/facebook/lexical/blob/f373759a7849f473d34960a6bf4e34b2a011e762/packages/lexical-react/src/LexicalTablePlugin.ts#L49
@@ -25,12 +25,12 @@ class TableSelectionHandler {
     }
 
     protected init() {
-        this.unregisterMutationListener = this.editor.registerMutationListener(CustomTableNode, (mutations) => {
+        this.unregisterMutationListener = this.editor.registerMutationListener(TableNode, (mutations) => {
             for (const [nodeKey, mutation] of mutations) {
                 if (mutation === 'created') {
                     this.editor.getEditorState().read(() => {
-                        const tableNode = $getNodeByKey<CustomTableNode>(nodeKey);
-                        if ($isCustomTableNode(tableNode)) {
+                        const tableNode = $getNodeByKey<TableNode>(nodeKey);
+                        if ($isTableNode(tableNode)) {
                             this.initializeTableNode(tableNode);
                         }
                     });
index 12c19b0fb8075b1e6fb359e394cd9f39b56bb96c..1e024e4c7581199932c03ab108f168e3b44f9292 100644 (file)
@@ -1,24 +1,28 @@
 import {NodeClipboard} from "./node-clipboard";
-import {CustomTableRowNode} from "../nodes/custom-table-row";
 import {$getTableCellsFromSelection, $getTableFromSelection, $getTableRowsFromSelection} from "./tables";
 import {$getSelection, BaseSelection, LexicalEditor} from "lexical";
-import {$createCustomTableCellNode, $isCustomTableCellNode, CustomTableCellNode} from "../nodes/custom-table-cell";
-import {CustomTableNode} from "../nodes/custom-table";
 import {TableMap} from "./table-map";
-import {$isTableSelection} from "@lexical/table";
+import {
+    $createTableCellNode,
+    $isTableCellNode,
+    $isTableSelection,
+    TableCellNode,
+    TableNode,
+    TableRowNode
+} from "@lexical/table";
 import {$getNodeFromSelection} from "./selection";
 
-const rowClipboard: NodeClipboard<CustomTableRowNode> = new NodeClipboard<CustomTableRowNode>();
+const rowClipboard: NodeClipboard<TableRowNode> = new NodeClipboard<TableRowNode>();
 
 export function isRowClipboardEmpty(): boolean {
     return rowClipboard.size() === 0;
 }
 
-export function validateRowsToCopy(rows: CustomTableRowNode[]): void {
+export function validateRowsToCopy(rows: TableRowNode[]): void {
     let commonRowSize: number|null = null;
 
     for (const row of rows) {
-        const cells = row.getChildren().filter(n => $isCustomTableCellNode(n));
+        const cells = row.getChildren().filter(n => $isTableCellNode(n));
         let rowSize = 0;
         for (const cell of cells) {
             rowSize += cell.getColSpan() || 1;
@@ -35,10 +39,10 @@ export function validateRowsToCopy(rows: CustomTableRowNode[]): void {
     }
 }
 
-export function validateRowsToPaste(rows: CustomTableRowNode[], targetTable: CustomTableNode): void {
+export function validateRowsToPaste(rows: TableRowNode[], targetTable: TableNode): void {
     const tableColCount = (new TableMap(targetTable)).columnCount;
     for (const row of rows) {
-        const cells = row.getChildren().filter(n => $isCustomTableCellNode(n));
+        const cells = row.getChildren().filter(n => $isTableCellNode(n));
         let rowSize = 0;
         for (const cell of cells) {
             rowSize += cell.getColSpan() || 1;
@@ -49,7 +53,7 @@ export function validateRowsToPaste(rows: CustomTableRowNode[], targetTable: Cus
         }
 
         while (rowSize < tableColCount) {
-            row.append($createCustomTableCellNode());
+            row.append($createTableCellNode());
             rowSize++;
         }
     }
@@ -98,11 +102,11 @@ export function $pasteClipboardRowsAfter(editor: LexicalEditor): void {
     }
 }
 
-const columnClipboard: NodeClipboard<CustomTableCellNode>[] = [];
+const columnClipboard: NodeClipboard<TableCellNode>[] = [];
 
-function setColumnClipboard(columns: CustomTableCellNode[][]): void {
+function setColumnClipboard(columns: TableCellNode[][]): void {
     const newClipboards = columns.map(cells => {
-        const clipboard = new NodeClipboard<CustomTableCellNode>();
+        const clipboard = new NodeClipboard<TableCellNode>();
         clipboard.set(...cells);
         return clipboard;
     });
@@ -122,9 +126,9 @@ function $getSelectionColumnRange(selection: BaseSelection|null): TableRange|nul
         return {from: shape.fromX, to: shape.toX};
     }
 
-    const cell = $getNodeFromSelection(selection, $isCustomTableCellNode);
+    const cell = $getNodeFromSelection(selection, $isTableCellNode);
     const table = $getTableFromSelection(selection);
-    if (!$isCustomTableCellNode(cell) || !table) {
+    if (!$isTableCellNode(cell) || !table) {
         return null;
     }
 
@@ -137,7 +141,7 @@ function $getSelectionColumnRange(selection: BaseSelection|null): TableRange|nul
     return {from: range.fromX, to: range.toX};
 }
 
-function $getTableColumnCellsFromSelection(range: TableRange, table: CustomTableNode): CustomTableCellNode[][] {
+function $getTableColumnCellsFromSelection(range: TableRange, table: TableNode): TableCellNode[][] {
     const map = new TableMap(table);
     const columns = [];
     for (let x = range.from; x <= range.to; x++) {
@@ -148,7 +152,7 @@ function $getTableColumnCellsFromSelection(range: TableRange, table: CustomTable
     return columns;
 }
 
-function validateColumnsToCopy(columns: CustomTableCellNode[][]): void {
+function validateColumnsToCopy(columns: TableCellNode[][]): void {
     let commonColSize: number|null = null;
 
     for (const cells of columns) {
@@ -203,7 +207,7 @@ export function $copySelectedColumnsToClipboard(): void {
     setColumnClipboard(columns);
 }
 
-function validateColumnsToPaste(columns: CustomTableCellNode[][], targetTable: CustomTableNode) {
+function validateColumnsToPaste(columns: TableCellNode[][], targetTable: TableNode) {
     const tableRowCount = (new TableMap(targetTable)).rowCount;
     for (const cells of columns) {
         let colSize = 0;
@@ -216,7 +220,7 @@ function validateColumnsToPaste(columns: CustomTableCellNode[][], targetTable: C
         }
 
         while (colSize < tableRowCount) {
-            cells.push($createCustomTableCellNode());
+            cells.push($createTableCellNode());
             colSize++;
         }
     }
index 607deffe1ca681afc2f0369d3c93b1f3df206a4f..dfe21b936f67b7da027a280a5d4d726ba742ccc5 100644 (file)
@@ -1,6 +1,4 @@
-import {CustomTableNode} from "../nodes/custom-table";
-import {$isCustomTableCellNode, CustomTableCellNode} from "../nodes/custom-table-cell";
-import {$isTableRowNode} from "@lexical/table";
+import {$isTableCellNode, $isTableRowNode, TableCellNode, TableNode} from "@lexical/table";
 
 export type CellRange = {
     fromX: number;
@@ -16,15 +14,15 @@ export class TableMap {
 
     // Represents an array (rows*columns in length) of cell nodes from top-left to
     // bottom right. Cells may repeat where merged and covering multiple spaces.
-    cells: CustomTableCellNode[] = [];
+    cells: TableCellNode[] = [];
 
-    constructor(table: CustomTableNode) {
+    constructor(table: TableNode) {
         this.buildCellMap(table);
     }
 
-    protected buildCellMap(table: CustomTableNode) {
-        const rowsAndCells: CustomTableCellNode[][] = [];
-        const setCell = (x: number, y: number, cell: CustomTableCellNode) => {
+    protected buildCellMap(table: TableNode) {
+        const rowsAndCells: TableCellNode[][] = [];
+        const setCell = (x: number, y: number, cell: TableCellNode) => {
             if (typeof rowsAndCells[y] === 'undefined') {
                 rowsAndCells[y] = [];
             }
@@ -36,7 +34,7 @@ export class TableMap {
         const rowNodes = table.getChildren().filter(r => $isTableRowNode(r));
         for (let rowIndex = 0; rowIndex < rowNodes.length; rowIndex++) {
             const rowNode = rowNodes[rowIndex];
-            const cellNodes = rowNode.getChildren().filter(c => $isCustomTableCellNode(c));
+            const cellNodes = rowNode.getChildren().filter(c => $isTableCellNode(c));
             let targetColIndex: number = 0;
             for (let cellIndex = 0; cellIndex < cellNodes.length; cellIndex++) {
                 const cellNode = cellNodes[cellIndex];
@@ -60,7 +58,7 @@ export class TableMap {
         this.columnCount = Math.max(...rowsAndCells.map(r => r.length));
 
         const cells = [];
-        let lastCell: CustomTableCellNode = rowsAndCells[0][0];
+        let lastCell: TableCellNode = rowsAndCells[0][0];
         for (let y = 0; y < this.rowCount; y++) {
             for (let x = 0; x < this.columnCount; x++) {
                 if (!rowsAndCells[y] || !rowsAndCells[y][x]) {
@@ -75,7 +73,7 @@ export class TableMap {
         this.cells = cells;
     }
 
-    public getCellAtPosition(x: number, y: number): CustomTableCellNode {
+    public getCellAtPosition(x: number, y: number): TableCellNode {
         const position = (y * this.columnCount) + x;
         if (position >= this.cells.length) {
             throw new Error(`TableMap Error: Attempted to get cell ${position+1} of ${this.cells.length}`);
@@ -84,13 +82,13 @@ export class TableMap {
         return this.cells[position];
     }
 
-    public getCellsInRange(range: CellRange): CustomTableCellNode[] {
+    public getCellsInRange(range: CellRange): TableCellNode[] {
         const minX = Math.max(Math.min(range.fromX, range.toX), 0);
         const maxX = Math.min(Math.max(range.fromX, range.toX), this.columnCount - 1);
         const minY = Math.max(Math.min(range.fromY, range.toY), 0);
         const maxY = Math.min(Math.max(range.fromY, range.toY), this.rowCount - 1);
 
-        const cells = new Set<CustomTableCellNode>();
+        const cells = new Set<TableCellNode>();
 
         for (let y = minY; y <= maxY; y++) {
             for (let x = minX; x <= maxX; x++) {
@@ -101,7 +99,7 @@ export class TableMap {
         return [...cells.values()];
     }
 
-    public getCellsInColumn(columnIndex: number): CustomTableCellNode[] {
+    public getCellsInColumn(columnIndex: number): TableCellNode[] {
         return this.getCellsInRange({
             fromX: columnIndex,
             toX: columnIndex,
@@ -110,7 +108,7 @@ export class TableMap {
         });
     }
 
-    public getRangeForCell(cell: CustomTableCellNode): CellRange|null {
+    public getRangeForCell(cell: TableCellNode): CellRange|null {
         let range: CellRange|null = null;
         const cellKey = cell.getKey();
 
index aa8ec89ba7770e18a7f655d1378ba8043d0a1c79..ed947ddcdcbce26fa1e4454a805e1a721f1d7816 100644 (file)
@@ -1,15 +1,19 @@
 import {BaseSelection, LexicalEditor} from "lexical";
-import {$isTableRowNode, $isTableSelection, TableRowNode, TableSelection, TableSelectionShape} from "@lexical/table";
-import {$isCustomTableNode, CustomTableNode} from "../nodes/custom-table";
-import {$isCustomTableCellNode, CustomTableCellNode} from "../nodes/custom-table-cell";
+import {
+    $isTableCellNode,
+    $isTableNode,
+    $isTableRowNode,
+    $isTableSelection, TableCellNode, TableNode,
+    TableRowNode,
+    TableSelection,
+} from "@lexical/table";
 import {$getParentOfType} from "./nodes";
 import {$getNodeFromSelection} from "./selection";
 import {formatSizeValue} from "./dom";
 import {TableMap} from "./table-map";
-import {$isCustomTableRowNode, CustomTableRowNode} from "../nodes/custom-table-row";
 
-function $getTableFromCell(cell: CustomTableCellNode): CustomTableNode|null {
-    return $getParentOfType(cell, $isCustomTableNode) as CustomTableNode|null;
+function $getTableFromCell(cell: TableCellNode): TableNode|null {
+    return $getParentOfType(cell, $isTableNode) as TableNode|null;
 }
 
 export function getTableColumnWidths(table: HTMLTableElement): string[] {
@@ -55,7 +59,7 @@ function extractWidthFromElement(element: HTMLElement): string {
     return width || '';
 }
 
-export function $setTableColumnWidth(node: CustomTableNode, columnIndex: number, width: number|string): void {
+export function $setTableColumnWidth(node: TableNode, columnIndex: number, width: number|string): void {
     const rows = node.getChildren() as TableRowNode[];
     let maxCols = 0;
     for (const row of rows) {
@@ -78,7 +82,7 @@ export function $setTableColumnWidth(node: CustomTableNode, columnIndex: number,
     node.setColWidths(colWidths);
 }
 
-export function $getTableColumnWidth(editor: LexicalEditor, node: CustomTableNode, columnIndex: number): number {
+export function $getTableColumnWidth(editor: LexicalEditor, node: TableNode, columnIndex: number): number {
     const colWidths = node.getColWidths();
     if (colWidths.length > columnIndex && colWidths[columnIndex].endsWith('px')) {
         return Number(colWidths[columnIndex].replace('px', ''));
@@ -97,14 +101,14 @@ export function $getTableColumnWidth(editor: LexicalEditor, node: CustomTableNod
     return 0;
 }
 
-function $getCellColumnIndex(node: CustomTableCellNode): number {
+function $getCellColumnIndex(node: TableCellNode): number {
     const row = node.getParent();
     if (!$isTableRowNode(row)) {
         return -1;
     }
 
     let index = 0;
-    const cells = row.getChildren<CustomTableCellNode>();
+    const cells = row.getChildren<TableCellNode>();
     for (const cell of cells) {
         let colSpan = cell.getColSpan() || 1;
         index += colSpan;
@@ -116,7 +120,7 @@ function $getCellColumnIndex(node: CustomTableCellNode): number {
     return index - 1;
 }
 
-export function $setTableCellColumnWidth(cell: CustomTableCellNode, width: string): void {
+export function $setTableCellColumnWidth(cell: TableCellNode, width: string): void {
     const table = $getTableFromCell(cell)
     const index = $getCellColumnIndex(cell);
 
@@ -125,7 +129,7 @@ export function $setTableCellColumnWidth(cell: CustomTableCellNode, width: strin
     }
 }
 
-export function $getTableCellColumnWidth(editor: LexicalEditor, cell: CustomTableCellNode): string {
+export function $getTableCellColumnWidth(editor: LexicalEditor, cell: TableCellNode): string {
     const table = $getTableFromCell(cell)
     const index = $getCellColumnIndex(cell);
     if (!table) {
@@ -136,13 +140,13 @@ export function $getTableCellColumnWidth(editor: LexicalEditor, cell: CustomTabl
     return (widths.length > index) ? widths[index] : '';
 }
 
-export function $getTableCellsFromSelection(selection: BaseSelection|null): CustomTableCellNode[]  {
+export function $getTableCellsFromSelection(selection: BaseSelection|null): TableCellNode[]  {
     if ($isTableSelection(selection)) {
         const nodes = selection.getNodes();
-        return nodes.filter(n => $isCustomTableCellNode(n));
+        return nodes.filter(n => $isTableCellNode(n));
     }
 
-    const cell = $getNodeFromSelection(selection, $isCustomTableCellNode) as CustomTableCellNode;
+    const cell = $getNodeFromSelection(selection, $isTableCellNode) as TableCellNode;
     return cell ? [cell] : [];
 }
 
@@ -193,12 +197,12 @@ export function $mergeTableCellsInSelection(selection: TableSelection): void {
     firstCell.setRowSpan(newHeight);
 }
 
-export function $getTableRowsFromSelection(selection: BaseSelection|null): CustomTableRowNode[] {
+export function $getTableRowsFromSelection(selection: BaseSelection|null): TableRowNode[] {
     const cells = $getTableCellsFromSelection(selection);
-    const rowsByKey: Record<string, CustomTableRowNode> = {};
+    const rowsByKey: Record<string, TableRowNode> = {};
     for (const cell of cells) {
         const row = cell.getParent();
-        if ($isCustomTableRowNode(row)) {
+        if ($isTableRowNode(row)) {
             rowsByKey[row.getKey()] = row;
         }
     }
@@ -206,28 +210,28 @@ export function $getTableRowsFromSelection(selection: BaseSelection|null): Custo
     return Object.values(rowsByKey);
 }
 
-export function $getTableFromSelection(selection: BaseSelection|null): CustomTableNode|null {
+export function $getTableFromSelection(selection: BaseSelection|null): TableNode|null {
     const cells = $getTableCellsFromSelection(selection);
     if (cells.length === 0) {
         return null;
     }
 
-    const table = $getParentOfType(cells[0], $isCustomTableNode);
-    if ($isCustomTableNode(table)) {
+    const table = $getParentOfType(cells[0], $isTableNode);
+    if ($isTableNode(table)) {
         return table;
     }
 
     return null;
 }
 
-export function $clearTableSizes(table: CustomTableNode): void {
+export function $clearTableSizes(table: TableNode): void {
     table.setColWidths([]);
 
     // TODO - Extra form things once table properties and extra things
     //   are supported
 
     for (const row of table.getChildren()) {
-        if (!$isCustomTableRowNode(row)) {
+        if (!$isTableRowNode(row)) {
             continue;
         }
 
@@ -236,7 +240,7 @@ export function $clearTableSizes(table: CustomTableNode): void {
         rowStyles.delete('width');
         row.setStyles(rowStyles);
 
-        const cells = row.getChildren().filter(c => $isCustomTableCellNode(c));
+        const cells = row.getChildren().filter(c => $isTableCellNode(c));
         for (const cell of cells) {
             const cellStyles = cell.getStyles();
             cellStyles.delete('height');
@@ -247,23 +251,21 @@ export function $clearTableSizes(table: CustomTableNode): void {
     }
 }
 
-export function $clearTableFormatting(table: CustomTableNode): void {
+export function $clearTableFormatting(table: TableNode): void {
     table.setColWidths([]);
     table.setStyles(new Map);
 
     for (const row of table.getChildren()) {
-        if (!$isCustomTableRowNode(row)) {
+        if (!$isTableRowNode(row)) {
             continue;
         }
 
         row.setStyles(new Map);
-        row.setFormat('');
 
-        const cells = row.getChildren().filter(c => $isCustomTableCellNode(c));
+        const cells = row.getChildren().filter(c => $isTableCellNode(c));
         for (const cell of cells) {
             cell.setStyles(new Map);
             cell.clearWidth();
-            cell.setFormat('');
         }
     }
 }
@@ -272,14 +274,14 @@ export function $clearTableFormatting(table: CustomTableNode): void {
  * Perform the given callback for each cell in the given table.
  * Returning false from the callback stops the function early.
  */
-export function $forEachTableCell(table: CustomTableNode, callback: (c: CustomTableCellNode) => void|false): void {
+export function $forEachTableCell(table: TableNode, callback: (c: TableCellNode) => void|false): void {
     outer: for (const row of table.getChildren()) {
-        if (!$isCustomTableRowNode(row)) {
+        if (!$isTableRowNode(row)) {
             continue;
         }
         const cells = row.getChildren();
         for (const cell of cells) {
-            if (!$isCustomTableCellNode(cell)) {
+            if (!$isTableCellNode(cell)) {
                 return;
             }
             const result = callback(cell);
@@ -290,10 +292,10 @@ export function $forEachTableCell(table: CustomTableNode, callback: (c: CustomTa
     }
 }
 
-export function $getCellPaddingForTable(table: CustomTableNode): string {
+export function $getCellPaddingForTable(table: TableNode): string {
     let padding: string|null = null;
 
-    $forEachTableCell(table, (cell: CustomTableCellNode) => {
+    $forEachTableCell(table, (cell: TableCellNode) => {
         const cellPadding = cell.getStyles().get('padding') || ''
         if (padding === null) {
             padding = cellPadding;