ElementNode,
} from 'lexical';
-import {COLUMN_WIDTH, PIXEL_VALUE_REG_EXP} from './constants';
+import {extractStyleMapFromElement, StyleMap} from "../../utils/dom";
+import {CommonBlockAlignment, extractAlignmentFromElement} from "lexical/nodes/common";
export const TableCellHeaderStates = {
BOTH: 3,
headerState: TableCellHeaderState;
width?: number;
backgroundColor?: null | string;
+ styles: Record<string, string>;
+ alignment: CommonBlockAlignment;
},
SerializedElementNode
>;
__width?: number;
/** @internal */
__backgroundColor: null | string;
+ /** @internal */
+ __styles: StyleMap = new Map;
+ /** @internal */
+ __alignment: CommonBlockAlignment = '';
static getType(): string {
return 'tablecell';
);
cellNode.__rowSpan = node.__rowSpan;
cellNode.__backgroundColor = node.__backgroundColor;
+ cellNode.__styles = new Map(node.__styles);
+ cellNode.__alignment = node.__alignment;
return cellNode;
}
}
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(
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,
};
rowSpan: this.__rowSpan,
type: 'tablecell',
width: this.getWidth(),
+ styles: Object.fromEntries(this.__styles),
+ alignment: this.__alignment,
};
}
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;
}
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
);
}
}
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) {
if ($isTableCellNode(parentLexicalNode) && !$isElementNode(lexicalNode)) {
const paragraphNode = $createParagraphNode();
if (
- $isLineBreakNode(lexicalNode) &&
- lexicalNode.getTextContent() === '\n'
+ $isLineBreakNode(lexicalNode) &&
+ lexicalNode.getTextContent() === '\n'
) {
return null;
}
}
export function $createTableCellNode(
- headerState: TableCellHeaderState,
+ headerState: TableCellHeaderState = TableCellHeaderStates.NO_STATUS,
colSpan = 1,
width?: number,
): TableCellNode {