> = createCommand(
'DRAG_DROP_PASTE_FILE',
);
-export type SerializedQuoteNode = SerializedElementNode;
-/** @noInheritDoc */
-export class QuoteNode extends ElementNode {
- static getType(): string {
- return 'quote';
- }
-
- static clone(node: QuoteNode): QuoteNode {
- return new QuoteNode(node.__key);
- }
-
- constructor(key?: NodeKey) {
- super(key);
- }
-
- // View
-
- createDOM(config: EditorConfig): HTMLElement {
- const element = document.createElement('blockquote');
- addClassNamesToElement(element, config.theme.quote);
- return element;
- }
- updateDOM(prevNode: QuoteNode, dom: HTMLElement): boolean {
- return false;
- }
-
- static importDOM(): DOMConversionMap | null {
- return {
- blockquote: (node: Node) => ({
- conversion: $convertBlockquoteElement,
- priority: 0,
- }),
- };
- }
-
- exportDOM(editor: LexicalEditor): DOMExportOutput {
- const {element} = super.exportDOM(editor);
-
- if (element && isHTMLElement(element)) {
- if (this.isEmpty()) {
- element.append(document.createElement('br'));
- }
-
- const formatType = this.getFormatType();
- element.style.textAlign = formatType;
- }
-
- return {
- element,
- };
- }
-
- static importJSON(serializedNode: SerializedQuoteNode): QuoteNode {
- const node = $createQuoteNode();
- node.setFormat(serializedNode.format);
- node.setIndent(serializedNode.indent);
- return node;
- }
-
- exportJSON(): SerializedElementNode {
- return {
- ...super.exportJSON(),
- type: 'quote',
- };
- }
-
- // Mutation
-
- insertNewAfter(_: RangeSelection, restoreSelection?: boolean): ParagraphNode {
- const newBlock = $createParagraphNode();
- const direction = this.getDirection();
- newBlock.setDirection(direction);
- this.insertAfter(newBlock, restoreSelection);
- return newBlock;
- }
-
- collapseAtStart(): true {
- const paragraph = $createParagraphNode();
- const children = this.getChildren();
- children.forEach((child) => paragraph.append(child));
- this.replace(paragraph);
- return true;
- }
-
- canMergeWhenEmpty(): true {
- return true;
- }
-}
-
-export function $createQuoteNode(): QuoteNode {
- return $applyNodeReplacement(new QuoteNode());
-}
-
-export function $isQuoteNode(
- node: LexicalNode | null | undefined,
-): node is QuoteNode {
- return node instanceof QuoteNode;
-}
-
-export type HeadingTagType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
-
-/** @noInheritDoc */
-export class HeadingNode extends ElementNode {
- /** @internal */
- __tag: HeadingTagType;
-
- static getType(): string {
- return 'heading';
- }
-
- static clone(node: HeadingNode): HeadingNode {
- return new HeadingNode(node.__tag, node.__key);
- }
-
- constructor(tag: HeadingTagType, key?: NodeKey) {
- super(key);
- this.__tag = tag;
- }
-
- getTag(): HeadingTagType {
- return this.__tag;
- }
-
- // View
-
- createDOM(config: EditorConfig): HTMLElement {
- const tag = this.__tag;
- const element = document.createElement(tag);
- const theme = config.theme;
- const classNames = theme.heading;
- if (classNames !== undefined) {
- const className = classNames[tag];
- addClassNamesToElement(element, className);
- }
- return element;
- }
-
- updateDOM(prevNode: HeadingNode, dom: HTMLElement): boolean {
- return false;
- }
-
- static importDOM(): DOMConversionMap | null {
- return {
- h1: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h2: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h3: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h4: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h5: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h6: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- p: (node: Node) => {
- // domNode is a since we matched it by nodeName
- const paragraph = node as HTMLParagraphElement;
- const firstChild = paragraph.firstChild;
- if (firstChild !== null && isGoogleDocsTitle(firstChild)) {
- return {
- conversion: () => ({node: null}),
- priority: 3,
- };
- }
- return null;
- },
- span: (node: Node) => {
- if (isGoogleDocsTitle(node)) {
- return {
- conversion: (domNode: Node) => {
- return {
- node: $createHeadingNode('h1'),
- };
- },
- priority: 3,
- };
- }
- return null;
- },
- };
- }
-
- exportDOM(editor: LexicalEditor): DOMExportOutput {
- const {element} = super.exportDOM(editor);
-
- if (element && isHTMLElement(element)) {
- if (this.isEmpty()) {
- element.append(document.createElement('br'));
- }
-
- const formatType = this.getFormatType();
- element.style.textAlign = formatType;
- }
-
- return {
- element,
- };
- }
-
- static importJSON(serializedNode: SerializedHeadingNode): HeadingNode {
- const node = $createHeadingNode(serializedNode.tag);
- node.setFormat(serializedNode.format);
- node.setIndent(serializedNode.indent);
- return node;
- }
-
- exportJSON(): SerializedHeadingNode {
- return {
- ...super.exportJSON(),
- tag: this.getTag(),
- type: 'heading',
- version: 1,
- };
- }
-
- // Mutation
- insertNewAfter(
- selection?: RangeSelection,
- restoreSelection = true,
- ): ParagraphNode | HeadingNode {
- const anchorOffet = selection ? selection.anchor.offset : 0;
- const lastDesc = this.getLastDescendant();
- const isAtEnd =
- !lastDesc ||
- (selection &&
- selection.anchor.key === lastDesc.getKey() &&
- anchorOffet === lastDesc.getTextContentSize());
- const newElement =
- isAtEnd || !selection
- ? $createParagraphNode()
- : $createHeadingNode(this.getTag());
- const direction = this.getDirection();
- newElement.setDirection(direction);
- this.insertAfter(newElement, restoreSelection);
- if (anchorOffet === 0 && !this.isEmpty() && selection) {
- const paragraph = $createParagraphNode();
- paragraph.select();
- this.replace(paragraph, true);
- }
- return newElement;
- }
-
- collapseAtStart(): true {
- const newElement = !this.isEmpty()
- ? $createHeadingNode(this.getTag())
- : $createParagraphNode();
- const children = this.getChildren();
- children.forEach((child) => newElement.append(child));
- this.replace(newElement);
- return true;
- }
-
- extractWithChild(): boolean {
- return true;
- }
-}
-
-function isGoogleDocsTitle(domNode: Node): boolean {
- if (domNode.nodeName.toLowerCase() === 'span') {
- return (domNode as HTMLSpanElement).style.fontSize === '26pt';
- }
- return false;
-}
-
-function $convertHeadingElement(element: HTMLElement): DOMConversionOutput {
- const nodeName = element.nodeName.toLowerCase();
- let node = null;
- if (
- nodeName === 'h1' ||
- nodeName === 'h2' ||
- nodeName === 'h3' ||
- nodeName === 'h4' ||
- nodeName === 'h5' ||
- nodeName === 'h6'
- ) {
- node = $createHeadingNode(nodeName);
- if (element.style !== null) {
- node.setFormat(element.style.textAlign as ElementFormatType);
- }
- }
- return {node};
-}
-
-function $convertBlockquoteElement(element: HTMLElement): DOMConversionOutput {
- const node = $createQuoteNode();
- if (element.style !== null) {
- node.setFormat(element.style.textAlign as ElementFormatType);
- }
- return {node};
-}
-
-export function $createHeadingNode(headingTag: HeadingTagType): HeadingNode {
- return $applyNodeReplacement(new HeadingNode(headingTag));
-}
-
-export function $isHeadingNode(
- node: LexicalNode | null | undefined,
-): node is HeadingNode {
- return node instanceof HeadingNode;
-}
function onPasteForRichText(
event: CommandPayloadType,
@@ -651,9 +299,6 @@ export function registerRichText(editor: LexicalEditor): () => void {
(parentNode): parentNode is ElementNode =>
$isElementNode(parentNode) && !parentNode.isInline(),
);
- if (element !== null) {
- element.setFormat(format);
- }
}
return true;
},
@@ -691,28 +336,6 @@ export function registerRichText(editor: LexicalEditor): () => void {
},
COMMAND_PRIORITY_EDITOR,
),
- editor.registerCommand(
- INDENT_CONTENT_COMMAND,
- () => {
- return $handleIndentAndOutdent((block) => {
- const indent = block.getIndent();
- block.setIndent(indent + 1);
- });
- },
- COMMAND_PRIORITY_EDITOR,
- ),
- editor.registerCommand(
- OUTDENT_CONTENT_COMMAND,
- () => {
- return $handleIndentAndOutdent((block) => {
- const indent = block.getIndent();
- if (indent > 0) {
- block.setIndent(indent - 1);
- }
- });
- },
- COMMAND_PRIORITY_EDITOR,
- ),
editor.registerCommand(
KEY_ARROW_UP_COMMAND,
(event) => {
@@ -846,19 +469,7 @@ export function registerRichText(editor: LexicalEditor): () => void {
return false;
}
event.preventDefault();
- const {anchor} = selection;
- const anchorNode = anchor.getNode();
- if (
- selection.isCollapsed() &&
- anchor.offset === 0 &&
- !$isRootNode(anchorNode)
- ) {
- const element = $getNearestBlockElementAncestorOrThrow(anchorNode);
- if (element.getIndent() > 0) {
- return editor.dispatchCommand(OUTDENT_CONTENT_COMMAND, undefined);
- }
- }
return editor.dispatchCommand(DELETE_CHARACTER_COMMAND, true);
},
COMMAND_PRIORITY_EDITOR,
diff --git a/resources/js/wysiwyg/lexical/selection/__tests__/unit/LexicalSelection.test.ts b/resources/js/wysiwyg/lexical/selection/__tests__/unit/LexicalSelection.test.ts
index 5f2d9dcc0..cc09d1735 100644
--- a/resources/js/wysiwyg/lexical/selection/__tests__/unit/LexicalSelection.test.ts
+++ b/resources/js/wysiwyg/lexical/selection/__tests__/unit/LexicalSelection.test.ts
@@ -8,7 +8,7 @@
import {$createLinkNode} from '@lexical/link';
import {$createListItemNode, $createListNode} from '@lexical/list';
-import {$createHeadingNode, registerRichText} from '@lexical/rich-text';
+import {registerRichText} from '@lexical/rich-text';
import {
$addNodeStyle,
$getSelectionStyleValueForProperty,
@@ -74,6 +74,7 @@ import {
} from '../utils';
import {createEmptyHistoryState, registerHistory} from "@lexical/history";
import {mergeRegister} from "@lexical/utils";
+import {$createHeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
interface ExpectedSelection {
anchorPath: number[];
@@ -2604,7 +2605,7 @@ describe('LexicalSelection tests', () => {
return $createHeadingNode('h1');
});
expect(JSON.stringify(testEditor._pendingEditorState?.toJSON())).toBe(
- '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"children":[{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":3,"rowSpan":1},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":1,"rowSpan":1}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1}],"direction":null,"format":"","indent":0,"type":"table","version":1},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"}],"direction":null,"format":"","indent":0,"type":"root","version":1}}',
+ '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"type":"heading","version":1,"id":"","alignment":"","inset":0,"tag":"h1"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"type":"heading","version":1,"id":"","alignment":"","inset":0,"tag":"h1"},{"children":[{"children":[{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"type":"heading","version":1,"id":"","alignment":"","inset":0,"tag":"h1"},{"children":[],"direction":null,"type":"heading","version":1,"id":"","alignment":"","inset":0,"tag":"h1"},{"children":[],"direction":null,"type":"heading","version":1,"id":"","alignment":"","inset":0,"tag":"h1"}],"direction":null,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":3,"rowSpan":1,"styles":{},"alignment":""},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"type":"heading","version":1,"id":"","alignment":"","inset":0,"tag":"h1"},{"children":[],"direction":null,"type":"heading","version":1,"id":"","alignment":"","inset":0,"tag":"h1"},{"children":[],"direction":null,"type":"heading","version":1,"id":"","alignment":"","inset":0,"tag":"h1"}],"direction":null,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":1,"rowSpan":1,"styles":{},"alignment":""}],"direction":null,"type":"tablerow","version":1,"styles":{},"height":0}],"direction":null,"type":"table","version":1,"id":"","alignment":"","inset":0,"colWidths":[],"styles":{}},{"children":[],"direction":null,"type":"heading","version":1,"id":"","alignment":"","inset":0,"tag":"h1"}],"direction":null,"type":"root","version":1}}',
);
});
});
@@ -2694,7 +2695,7 @@ describe('LexicalSelection tests', () => {
});
});
expect(element.innerHTML).toStrictEqual(
- `1
1.1
`,
+ `1
`,
);
});
@@ -2733,7 +2734,7 @@ describe('LexicalSelection tests', () => {
});
});
expect(element.innerHTML).toStrictEqual(
- `1.1
`,
+ ``,
);
});
});
diff --git a/resources/js/wysiwyg/lexical/selection/__tests__/unit/LexicalSelectionHelpers.test.ts b/resources/js/wysiwyg/lexical/selection/__tests__/unit/LexicalSelectionHelpers.test.ts
index 4d88bde0e..0523b7f71 100644
--- a/resources/js/wysiwyg/lexical/selection/__tests__/unit/LexicalSelectionHelpers.test.ts
+++ b/resources/js/wysiwyg/lexical/selection/__tests__/unit/LexicalSelectionHelpers.test.ts
@@ -7,7 +7,6 @@
*/
import {$createLinkNode} from '@lexical/link';
-import {$createHeadingNode, $isHeadingNode} from '@lexical/rich-text';
import {
$getSelectionStyleValueForProperty,
$patchStyleText,
@@ -44,6 +43,7 @@ import {
} from 'lexical/__tests__/utils';
import {$setAnchorPoint, $setFocusPoint} from '../utils';
+import {$createHeadingNode, $isHeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
Range.prototype.getBoundingClientRect = function (): DOMRect {
const rect = {
diff --git a/resources/js/wysiwyg/lexical/selection/range-selection.ts b/resources/js/wysiwyg/lexical/selection/range-selection.ts
index dbadaf346..542eae4db 100644
--- a/resources/js/wysiwyg/lexical/selection/range-selection.ts
+++ b/resources/js/wysiwyg/lexical/selection/range-selection.ts
@@ -81,8 +81,6 @@ export function $setBlocksType(
invariant($isElementNode(node), 'Expected block node to be an ElementNode');
const targetElement = createElement();
- targetElement.setFormat(node.getFormatType());
- targetElement.setIndent(node.getIndent());
node.replace(targetElement, true);
}
}
@@ -136,8 +134,6 @@ export function $wrapNodes(
: anchor.getNode();
const children = target.getChildren();
let element = createElement();
- element.setFormat(target.getFormatType());
- element.setIndent(target.getIndent());
children.forEach((child) => element.append(child));
if (wrappingElement) {
@@ -277,8 +273,6 @@ export function $wrapNodesImpl(
if (elementMapping.get(parentKey) === undefined) {
const targetElement = createElement();
- targetElement.setFormat(parent.getFormatType());
- targetElement.setIndent(parent.getIndent());
elements.push(targetElement);
elementMapping.set(parentKey, targetElement);
// Move node and its siblings to the new
@@ -299,8 +293,6 @@ export function $wrapNodesImpl(
'Expected node in emptyElements to be an ElementNode',
);
const targetElement = createElement();
- targetElement.setFormat(node.getFormatType());
- targetElement.setIndent(node.getIndent());
elements.push(targetElement);
node.remove(true);
}
diff --git a/resources/js/wysiwyg/lexical/table/LexicalTableCellNode.ts b/resources/js/wysiwyg/lexical/table/LexicalTableCellNode.ts
index 455d39bf6..1fc6b42bb 100644
--- a/resources/js/wysiwyg/lexical/table/LexicalTableCellNode.ts
+++ b/resources/js/wysiwyg/lexical/table/LexicalTableCellNode.ts
@@ -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 "lexical/nodes/common";
export const TableCellHeaderStates = {
BOTH: 3,
@@ -47,6 +48,8 @@ export type SerializedTableCellNode = Spread<
headerState: TableCellHeaderState;
width?: number;
backgroundColor?: null | string;
+ styles: Record;
+ 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 {
diff --git a/resources/js/wysiwyg/lexical/table/LexicalTableNode.ts b/resources/js/wysiwyg/lexical/table/LexicalTableNode.ts
index 357ba3e73..9443747a6 100644
--- a/resources/js/wysiwyg/lexical/table/LexicalTableNode.ts
+++ b/resources/js/wysiwyg/lexical/table/LexicalTableNode.ts
@@ -7,7 +7,7 @@
*/
import type {TableCellNode} from './LexicalTableCellNode';
-import type {
+import {
DOMConversionMap,
DOMConversionOutput,
DOMExportOutput,
@@ -15,31 +15,48 @@ import type {
LexicalEditor,
LexicalNode,
NodeKey,
- SerializedElementNode,
+ Spread,
} from 'lexical';
import {addClassNamesToElement, isHTMLElement} from '@lexical/utils';
import {
$applyNodeReplacement,
$getNearestNodeFromDOMNode,
- ElementNode,
+
} from 'lexical';
import {$isTableCellNode} from './LexicalTableCellNode';
import {TableDOMCell, TableDOMTable} from './LexicalTableObserver';
-import {$isTableRowNode, TableRowNode} from './LexicalTableRowNode';
import {getTable} from './LexicalTableSelectionHelpers';
+import {CommonBlockNode, copyCommonBlockProperties, SerializedCommonBlockNode} from "lexical/nodes/CommonBlockNode";
+import {
+ commonPropertiesDifferent, deserializeCommonBlockNode,
+ setCommonBlockPropsFromElement,
+ updateElementWithCommonBlockProps
+} from "lexical/nodes/common";
+import {el, extractStyleMapFromElement, StyleMap} from "../../utils/dom";
+import {getTableColumnWidths} from "../../utils/tables";
-export type SerializedTableNode = SerializedElementNode;
+export type SerializedTableNode = Spread<{
+ colWidths: string[];
+ styles: Record,
+}, 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 {
diff --git a/resources/js/wysiwyg/lexical/table/LexicalTableRowNode.ts b/resources/js/wysiwyg/lexical/table/LexicalTableRowNode.ts
index eddea69a2..07db2b65d 100644
--- a/resources/js/wysiwyg/lexical/table/LexicalTableRowNode.ts
+++ b/resources/js/wysiwyg/lexical/table/LexicalTableRowNode.ts
@@ -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,
+ 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;
- if (PIXEL_VALUE_REG_EXP.test(domNode_.style.height)) {
- height = parseFloat(domNode_.style.height);
+ const height = sizeToPixels(domNode_.style.height);
+ rowNode.setHeight(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(
diff --git a/resources/js/wysiwyg/lexical/table/LexicalTableSelectionHelpers.ts b/resources/js/wysiwyg/lexical/table/LexicalTableSelectionHelpers.ts
index 812cccc0d..e098a21e4 100644
--- a/resources/js/wysiwyg/lexical/table/LexicalTableSelectionHelpers.ts
+++ b/resources/js/wysiwyg/lexical/table/LexicalTableSelectionHelpers.ts
@@ -16,7 +16,6 @@ import type {
} from './LexicalTableSelection';
import type {
BaseSelection,
- ElementFormatType,
LexicalCommand,
LexicalEditor,
LexicalNode,
@@ -50,7 +49,6 @@ import {
DELETE_LINE_COMMAND,
DELETE_WORD_COMMAND,
FOCUS_COMMAND,
- FORMAT_ELEMENT_COMMAND,
FORMAT_TEXT_COMMAND,
INSERT_PARAGRAPH_COMMAND,
KEY_ARROW_DOWN_COMMAND,
@@ -438,59 +436,6 @@ export function applyTableHandlers(
),
);
- tableObserver.listenersToRemove.add(
- editor.registerCommand(
- 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,
diff --git a/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableNode.test.ts b/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableNode.test.ts
index 6848e5532..2879decda 100644
--- a/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableNode.test.ts
+++ b/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableNode.test.ts
@@ -113,9 +113,8 @@ describe('LexicalTableNode tests', () => {
$insertDataTransferForRichText(dataTransfer, selection, editor);
});
// Make sure paragraph is inserted inside empty cells
- const emptyCell = '
| ';
expect(testEnv.innerHTML).toBe(
- `Hello there | General Kenobi! |
Lexical is nice | ${emptyCell}
`,
+ `Hello there | General Kenobi! |
Lexical is nice |
|
`,
);
});
@@ -136,7 +135,7 @@ describe('LexicalTableNode tests', () => {
$insertDataTransferForRichText(dataTransfer, selection, editor);
});
expect(testEnv.innerHTML).toBe(
- `Surface | MWP_WORK_LS_COMPOSER | 77349 |
Lexical | XDS_RICH_TEXT_AREA | sdvd sdfvsfs |
`,
+ `Surface | MWP_WORK_LS_COMPOSER | 77349 |
Lexical | XDS_RICH_TEXT_AREA | sdvd sdfvsfs |
`,
);
});
},
diff --git a/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableRowNode.test.ts b/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableRowNode.test.ts
index 285d587bf..5dbf03d9e 100644
--- a/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableRowNode.test.ts
+++ b/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableRowNode.test.ts
@@ -39,10 +39,9 @@ describe('LexicalTableRowNode tests', () => {
`
`,
);
- const rowHeight = 36;
- const rowWithCustomHeightNode = $createTableRowNode(36);
+ const rowWithCustomHeightNode = $createTableRowNode();
expect(rowWithCustomHeightNode.createDOM(editorConfig).outerHTML).toBe(
- `
`,
+ `
`,
);
});
});
diff --git a/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableSelection.test.ts b/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableSelection.test.ts
index d5b85ccaa..1548216cf 100644
--- a/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableSelection.test.ts
+++ b/resources/js/wysiwyg/lexical/table/__tests__/unit/LexicalTableSelection.test.ts
@@ -101,8 +101,6 @@ describe('table selection', () => {
__cachedText: null,
__dir: null,
__first: paragraphKey,
- __format: 0,
- __indent: 0,
__key: 'root',
__last: paragraphKey,
__next: null,
@@ -113,10 +111,11 @@ describe('table selection', () => {
__type: 'root',
});
expect(parsedParagraph).toEqual({
+ __alignment: "",
__dir: null,
__first: textKey,
- __format: 0,
- __indent: 0,
+ __id: '',
+ __inset: 0,
__key: paragraphKey,
__last: textKey,
__next: null,
@@ -124,7 +123,6 @@ describe('table selection', () => {
__prev: null,
__size: 1,
__style: '',
- __textFormat: 0,
__textStyle: '',
__type: 'paragraph',
});
diff --git a/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexicalEventHelpers.test.ts b/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexicalEventHelpers.test.ts
index fd7731f90..cae4f1aae 100644
--- a/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexicalEventHelpers.test.ts
+++ b/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexicalEventHelpers.test.ts
@@ -7,7 +7,7 @@
*/
import {AutoLinkNode, LinkNode} from '@lexical/link';
import {ListItemNode, ListNode} from '@lexical/list';
-import {HeadingNode, QuoteNode, registerRichText} from '@lexical/rich-text';
+import {registerRichText} from '@lexical/rich-text';
import {
applySelectionInputs,
pasteHTML,
@@ -15,6 +15,8 @@ import {
import {TableCellNode, TableNode, TableRowNode} from '@lexical/table';
import {$createParagraphNode, $insertNodes, LexicalEditor} from 'lexical';
import {createTestEditor, initializeClipboard} from 'lexical/__tests__/utils';
+import {HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
+import {QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
jest.mock('lexical/shared/environment', () => {
const originalModule = jest.requireActual('lexical/shared/environment');
@@ -174,7 +176,7 @@ describe('LexicalEventHelpers', () => {
},
{
expectedHTML:
- '- Other side
- I must have called
',
+ '- Other side
- I must have called
',
inputs: [
pasteHTML(
`- Other side
- I must have called
`,
@@ -184,7 +186,7 @@ describe('LexicalEventHelpers', () => {
},
{
expectedHTML:
- '',
+ '',
inputs: [
pasteHTML(
`- To tell you
- I’m sorry
`,
@@ -264,7 +266,7 @@ describe('LexicalEventHelpers', () => {
},
{
expectedHTML:
- '',
+ '',
inputs: [
pasteHTML(
``,
@@ -274,7 +276,7 @@ describe('LexicalEventHelpers', () => {
},
{
expectedHTML:
- '',
+ '',
inputs: [
pasteHTML(
``,
@@ -609,7 +611,7 @@ describe('LexicalEventHelpers', () => {
},
{
expectedHTML:
- '- 1
2
- 3
',
+ '- 1
2
- 3
',
inputs: [
pasteHTML('- 12
- 3
'),
],
@@ -645,7 +647,7 @@ describe('LexicalEventHelpers', () => {
},
{
expectedHTML:
- '- 1
- 3
',
+ '- 1
- 3
',
inputs: [pasteHTML('- 1
- 3
')],
name: 'only br in a li',
},
diff --git a/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexicalUtilsSplitNode.test.ts b/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexicalUtilsSplitNode.test.ts
index a70200d63..54cd8b54f 100644
--- a/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexicalUtilsSplitNode.test.ts
+++ b/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexicalUtilsSplitNode.test.ts
@@ -82,10 +82,10 @@ describe('LexicalUtils#splitNode', () => {
expectedHtml:
'' +
'- Before
' +
- '' +
+ '' +
'
' +
'' +
- '' +
+ '' +
'- After
' +
'
',
initialHtml:
diff --git a/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexlcaiUtilsInsertNodeToNearestRoot.test.ts b/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexlcaiUtilsInsertNodeToNearestRoot.test.ts
index fb04e6284..8c31496de 100644
--- a/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexlcaiUtilsInsertNodeToNearestRoot.test.ts
+++ b/resources/js/wysiwyg/lexical/utils/__tests__/unit/LexlcaiUtilsInsertNodeToNearestRoot.test.ts
@@ -56,11 +56,11 @@ describe('LexicalUtils#insertNodeToNearestRoot', () => {
expectedHtml:
'' +
'- Before
' +
- '' +
+ '' +
'
' +
'' +
'' +
- '' +
+ '' +
'- After
' +
'
',
initialHtml:
diff --git a/resources/js/wysiwyg/nodes.ts b/resources/js/wysiwyg/nodes.ts
new file mode 100644
index 000000000..eb836bdce
--- /dev/null
+++ b/resources/js/wysiwyg/nodes.ts
@@ -0,0 +1,67 @@
+import {CalloutNode} from '@lexical/rich-text/LexicalCalloutNode';
+import {
+ ElementNode,
+ KlassConstructor,
+ LexicalNode,
+ LexicalNodeReplacement, NodeMutation,
+ ParagraphNode
+} from "lexical";
+import {LinkNode} from "@lexical/link";
+import {ImageNode} from "@lexical/rich-text/LexicalImageNode";
+import {DetailsNode, SummaryNode} from "@lexical/rich-text/LexicalDetailsNode";
+import {ListItemNode, ListNode} from "@lexical/list";
+import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
+import {HorizontalRuleNode} from "@lexical/rich-text/LexicalHorizontalRuleNode";
+import {CodeBlockNode} from "@lexical/rich-text/LexicalCodeBlockNode";
+import {DiagramNode} from "@lexical/rich-text/LexicalDiagramNode";
+import {EditorUiContext} from "./ui/framework/core";
+import {MediaNode} from "@lexical/rich-text/LexicalMediaNode";
+import {HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
+import {QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
+
+/**
+ * Load the nodes for lexical.
+ */
+export function getNodesForPageEditor(): (KlassConstructor | LexicalNodeReplacement)[] {
+ return [
+ CalloutNode,
+ HeadingNode,
+ QuoteNode,
+ ListNode,
+ ListItemNode,
+ TableNode,
+ TableRowNode,
+ TableCellNode,
+ ImageNode, // TODO - Alignment
+ HorizontalRuleNode,
+ DetailsNode, SummaryNode,
+ CodeBlockNode,
+ DiagramNode,
+ MediaNode, // TODO - Alignment
+ ParagraphNode,
+ LinkNode,
+ ];
+}
+
+export function registerCommonNodeMutationListeners(context: EditorUiContext): void {
+ const decorated = [ImageNode, CodeBlockNode, DiagramNode];
+
+ const decorationDestroyListener = (mutations: Map): void => {
+ for (let [nodeKey, mutation] of mutations) {
+ if (mutation === "destroyed") {
+ const decorator = context.manager.getDecoratorByNodeKey(nodeKey);
+ if (decorator) {
+ decorator.destroy(context);
+ }
+ }
+ }
+ };
+
+ for (let decoratedNode of decorated) {
+ // Have to pass a unique function here since they are stored by lexical keyed on listener function.
+ context.editor.registerMutationListener(decoratedNode, (mutations) => decorationDestroyListener(mutations));
+ }
+}
+
+export type LexicalNodeMatcher = (node: LexicalNode|null|undefined) => boolean;
+export type LexicalElementNodeCreator = () => ElementNode;
\ No newline at end of file
diff --git a/resources/js/wysiwyg/nodes/custom-heading.ts b/resources/js/wysiwyg/nodes/custom-heading.ts
deleted file mode 100644
index 5df6245f5..000000000
--- a/resources/js/wysiwyg/nodes/custom-heading.ts
+++ /dev/null
@@ -1,146 +0,0 @@
-import {
- DOMConversionMap,
- DOMConversionOutput,
- LexicalNode,
- Spread
-} from "lexical";
-import {EditorConfig} from "lexical/LexicalEditor";
-import {HeadingNode, HeadingTagType, SerializedHeadingNode} from "@lexical/rich-text";
-import {
- CommonBlockAlignment, commonPropertiesDifferent, deserializeCommonBlockNode,
- SerializedCommonBlockNode,
- setCommonBlockPropsFromElement,
- updateElementWithCommonBlockProps
-} from "./_common";
-
-
-export type SerializedCustomHeadingNode = Spread
-
-export class CustomHeadingNode extends HeadingNode {
- __id: string = '';
- __alignment: CommonBlockAlignment = '';
- __inset: number = 0;
-
- static getType() {
- return 'custom-heading';
- }
-
- 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;
- }
-
- static clone(node: CustomHeadingNode) {
- const newNode = new CustomHeadingNode(node.__tag, node.__key);
- newNode.__alignment = node.__alignment;
- newNode.__inset = node.__inset;
- return newNode;
- }
-
- createDOM(config: EditorConfig): HTMLElement {
- const dom = super.createDOM(config);
- updateElementWithCommonBlockProps(dom, this);
- return dom;
- }
-
- updateDOM(prevNode: CustomHeadingNode, dom: HTMLElement): boolean {
- return super.updateDOM(prevNode, dom)
- || commonPropertiesDifferent(prevNode, this);
- }
-
- exportJSON(): SerializedCustomHeadingNode {
- return {
- ...super.exportJSON(),
- type: 'custom-heading',
- version: 1,
- id: this.__id,
- alignment: this.__alignment,
- inset: this.__inset,
- };
- }
-
- static importJSON(serializedNode: SerializedCustomHeadingNode): CustomHeadingNode {
- const node = $createCustomHeadingNode(serializedNode.tag);
- deserializeCommonBlockNode(serializedNode, node);
- return node;
- }
-
- static importDOM(): DOMConversionMap | null {
- return {
- h1: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h2: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h3: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h4: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h5: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h6: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- };
- }
-}
-
-function $convertHeadingElement(element: HTMLElement): DOMConversionOutput {
- const nodeName = element.nodeName.toLowerCase();
- let node = null;
- if (
- nodeName === 'h1' ||
- nodeName === 'h2' ||
- nodeName === 'h3' ||
- nodeName === 'h4' ||
- nodeName === 'h5' ||
- nodeName === 'h6'
- ) {
- node = $createCustomHeadingNode(nodeName);
- setCommonBlockPropsFromElement(element, node);
- }
- return {node};
-}
-
-export function $createCustomHeadingNode(tag: HeadingTagType) {
- return new CustomHeadingNode(tag);
-}
-
-export function $isCustomHeadingNode(node: LexicalNode | null | undefined): node is CustomHeadingNode {
- return node instanceof CustomHeadingNode;
-}
\ No newline at end of file
diff --git a/resources/js/wysiwyg/nodes/custom-list-item.ts b/resources/js/wysiwyg/nodes/custom-list-item.ts
deleted file mode 100644
index 11887b436..000000000
--- a/resources/js/wysiwyg/nodes/custom-list-item.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-import {$isListNode, ListItemNode, SerializedListItemNode} from "@lexical/list";
-import {EditorConfig} from "lexical/LexicalEditor";
-import {DOMExportOutput, LexicalEditor, LexicalNode} from "lexical";
-
-import {el} from "../utils/dom";
-import {$isCustomListNode} from "./custom-list";
-
-function updateListItemChecked(
- dom: HTMLElement,
- listItemNode: ListItemNode,
-): void {
- // Only set task list attrs for leaf list items
- const shouldBeTaskItem = !$isListNode(listItemNode.getFirstChild());
- dom.classList.toggle('task-list-item', shouldBeTaskItem);
- if (listItemNode.__checked) {
- dom.setAttribute('checked', 'checked');
- } else {
- dom.removeAttribute('checked');
- }
-}
-
-
-export class CustomListItemNode extends ListItemNode {
- static getType(): string {
- return 'custom-list-item';
- }
-
- static clone(node: CustomListItemNode): CustomListItemNode {
- return new CustomListItemNode(node.__value, node.__checked, node.__key);
- }
-
- createDOM(config: EditorConfig): HTMLElement {
- const element = document.createElement('li');
- const parent = this.getParent();
-
- if ($isListNode(parent) && parent.getListType() === 'check') {
- updateListItemChecked(element, this);
- }
-
- element.value = this.__value;
-
- if ($hasNestedListWithoutLabel(this)) {
- element.style.listStyle = 'none';
- }
-
- return element;
- }
-
- updateDOM(
- prevNode: ListItemNode,
- dom: HTMLElement,
- config: EditorConfig,
- ): boolean {
- const parent = this.getParent();
- if ($isListNode(parent) && parent.getListType() === 'check') {
- updateListItemChecked(dom, this);
- }
-
- dom.style.listStyle = $hasNestedListWithoutLabel(this) ? 'none' : '';
- // @ts-expect-error - this is always HTMLListItemElement
- dom.value = this.__value;
-
- return false;
- }
-
- exportDOM(editor: LexicalEditor): DOMExportOutput {
- const element = this.createDOM(editor._config);
- element.style.textAlign = this.getFormatType();
-
- if (element.classList.contains('task-list-item')) {
- const input = el('input', {
- type: 'checkbox',
- disabled: 'disabled',
- });
- if (element.hasAttribute('checked')) {
- input.setAttribute('checked', 'checked');
- element.removeAttribute('checked');
- }
-
- element.prepend(input);
- }
-
- return {
- element,
- };
- }
-
- exportJSON(): SerializedListItemNode {
- return {
- ...super.exportJSON(),
- type: 'custom-list-item',
- };
- }
-}
-
-function $hasNestedListWithoutLabel(node: CustomListItemNode): boolean {
- const children = node.getChildren();
- let hasLabel = false;
- let hasNestedList = false;
-
- for (const child of children) {
- if ($isCustomListNode(child)) {
- hasNestedList = true;
- } else if (child.getTextContent().trim().length > 0) {
- hasLabel = true;
- }
- }
-
- return hasNestedList && !hasLabel;
-}
-
-export function $isCustomListItemNode(
- node: LexicalNode | null | undefined,
-): node is CustomListItemNode {
- return node instanceof CustomListItemNode;
-}
-
-export function $createCustomListItemNode(): CustomListItemNode {
- return new CustomListItemNode();
-}
\ No newline at end of file
diff --git a/resources/js/wysiwyg/nodes/custom-list.ts b/resources/js/wysiwyg/nodes/custom-list.ts
deleted file mode 100644
index 4b05fa62e..000000000
--- a/resources/js/wysiwyg/nodes/custom-list.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-import {
- DOMConversionFn,
- DOMConversionMap, EditorConfig,
- LexicalNode,
- Spread
-} from "lexical";
-import {$isListItemNode, ListItemNode, ListNode, ListType, SerializedListNode} from "@lexical/list";
-import {$createCustomListItemNode} from "./custom-list-item";
-import {extractDirectionFromElement} from "./_common";
-
-
-export type SerializedCustomListNode = Spread<{
- id: string;
-}, SerializedListNode>
-
-export class CustomListNode extends ListNode {
- __id: string = '';
-
- static getType() {
- return 'custom-list';
- }
-
- setId(id: string) {
- const self = this.getWritable();
- self.__id = id;
- }
-
- getId(): string {
- const self = this.getLatest();
- return self.__id;
- }
-
- static clone(node: CustomListNode) {
- const newNode = new CustomListNode(node.__listType, node.__start, node.__key);
- newNode.__id = node.__id;
- newNode.__dir = node.__dir;
- return newNode;
- }
-
- createDOM(config: EditorConfig): HTMLElement {
- const dom = super.createDOM(config);
- if (this.__id) {
- dom.setAttribute('id', this.__id);
- }
-
- if (this.__dir) {
- dom.setAttribute('dir', this.__dir);
- }
-
- return dom;
- }
-
- updateDOM(prevNode: ListNode, dom: HTMLElement, config: EditorConfig): boolean {
- return super.updateDOM(prevNode, dom, config) ||
- prevNode.__dir !== this.__dir;
- }
-
- exportJSON(): SerializedCustomListNode {
- return {
- ...super.exportJSON(),
- type: 'custom-list',
- version: 1,
- id: this.__id,
- };
- }
-
- static importJSON(serializedNode: SerializedCustomListNode): CustomListNode {
- const node = $createCustomListNode(serializedNode.listType);
- node.setId(serializedNode.id);
- node.setDirection(serializedNode.direction);
- return node;
- }
-
- static importDOM(): DOMConversionMap | null {
- // @ts-ignore
- const converter = super.importDOM().ol().conversion as DOMConversionFn;
- const customConvertFunction = (element: HTMLElement) => {
- const baseResult = converter(element);
- if (element.id && baseResult?.node) {
- (baseResult.node as CustomListNode).setId(element.id);
- }
-
- if (element.dir && baseResult?.node) {
- (baseResult.node as CustomListNode).setDirection(extractDirectionFromElement(element));
- }
-
- if (baseResult) {
- baseResult.after = $normalizeChildren;
- }
-
- return baseResult;
- };
-
- return {
- ol: () => ({
- conversion: customConvertFunction,
- priority: 0,
- }),
- ul: () => ({
- conversion: customConvertFunction,
- priority: 0,
- }),
- };
- }
-}
-
-/*
- * This function is a custom normalization function to allow nested lists within list item elements.
- * Original taken from https://github.com/facebook/lexical/blob/6e10210fd1e113ccfafdc999b1d896733c5c5bea/packages/lexical-list/src/LexicalListNode.ts#L284-L303
- * With modifications made.
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- * MIT license
- */
-function $normalizeChildren(nodes: Array): Array {
- const normalizedListItems: Array = [];
-
- for (const node of nodes) {
- if ($isListItemNode(node)) {
- normalizedListItems.push(node);
- } else {
- normalizedListItems.push($wrapInListItem(node));
- }
- }
-
- return normalizedListItems;
-}
-
-function $wrapInListItem(node: LexicalNode): ListItemNode {
- const listItemWrapper = $createCustomListItemNode();
- return listItemWrapper.append(node);
-}
-
-export function $createCustomListNode(type: ListType): CustomListNode {
- return new CustomListNode(type, 1);
-}
-
-export function $isCustomListNode(node: LexicalNode | null | undefined): node is CustomListNode {
- return node instanceof CustomListNode;
-}
\ No newline at end of file
diff --git a/resources/js/wysiwyg/nodes/custom-paragraph.ts b/resources/js/wysiwyg/nodes/custom-paragraph.ts
deleted file mode 100644
index 3adc10d0e..000000000
--- a/resources/js/wysiwyg/nodes/custom-paragraph.ts
+++ /dev/null
@@ -1,123 +0,0 @@
-import {
- DOMConversion,
- DOMConversionMap,
- DOMConversionOutput,
- LexicalNode,
- ParagraphNode, SerializedParagraphNode, Spread,
-} from "lexical";
-import {EditorConfig} from "lexical/LexicalEditor";
-import {
- CommonBlockAlignment, commonPropertiesDifferent, deserializeCommonBlockNode,
- SerializedCommonBlockNode,
- setCommonBlockPropsFromElement,
- updateElementWithCommonBlockProps
-} from "./_common";
-
-export type SerializedCustomParagraphNode = Spread
-
-export class CustomParagraphNode extends ParagraphNode {
- __id: string = '';
- __alignment: CommonBlockAlignment = '';
- __inset: number = 0;
-
- static getType() {
- return 'custom-paragraph';
- }
-
- 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;
- }
-
- static clone(node: CustomParagraphNode): CustomParagraphNode {
- const newNode = new CustomParagraphNode(node.__key);
- newNode.__id = node.__id;
- newNode.__alignment = node.__alignment;
- newNode.__inset = node.__inset;
- return newNode;
- }
-
- createDOM(config: EditorConfig): HTMLElement {
- const dom = super.createDOM(config);
- updateElementWithCommonBlockProps(dom, this);
- return dom;
- }
-
- updateDOM(prevNode: CustomParagraphNode, dom: HTMLElement, config: EditorConfig): boolean {
- return super.updateDOM(prevNode, dom, config)
- || commonPropertiesDifferent(prevNode, this);
- }
-
- exportJSON(): SerializedCustomParagraphNode {
- return {
- ...super.exportJSON(),
- type: 'custom-paragraph',
- version: 1,
- id: this.__id,
- alignment: this.__alignment,
- inset: this.__inset,
- };
- }
-
- static importJSON(serializedNode: SerializedCustomParagraphNode): CustomParagraphNode {
- const node = $createCustomParagraphNode();
- deserializeCommonBlockNode(serializedNode, node);
- return node;
- }
-
- static importDOM(): DOMConversionMap|null {
- return {
- p(node: HTMLElement): DOMConversion|null {
- return {
- conversion: (element: HTMLElement): DOMConversionOutput|null => {
- const node = $createCustomParagraphNode();
- if (element.style.textIndent) {
- const indent = parseInt(element.style.textIndent, 10) / 20;
- if (indent > 0) {
- node.setIndent(indent);
- }
- }
-
- setCommonBlockPropsFromElement(element, node);
-
- return {node};
- },
- priority: 1,
- };
- },
- };
- }
-}
-
-export function $createCustomParagraphNode(): CustomParagraphNode {
- return new CustomParagraphNode();
-}
-
-export function $isCustomParagraphNode(node: LexicalNode | null | undefined): node is CustomParagraphNode {
- return node instanceof CustomParagraphNode;
-}
\ No newline at end of file
diff --git a/resources/js/wysiwyg/nodes/custom-quote.ts b/resources/js/wysiwyg/nodes/custom-quote.ts
deleted file mode 100644
index 39ae7bf8a..000000000
--- a/resources/js/wysiwyg/nodes/custom-quote.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-import {
- DOMConversionMap,
- DOMConversionOutput,
- LexicalNode,
- Spread
-} from "lexical";
-import {EditorConfig} from "lexical/LexicalEditor";
-import {QuoteNode, SerializedQuoteNode} from "@lexical/rich-text";
-import {
- CommonBlockAlignment, commonPropertiesDifferent, deserializeCommonBlockNode,
- SerializedCommonBlockNode,
- setCommonBlockPropsFromElement,
- updateElementWithCommonBlockProps
-} from "./_common";
-
-
-export type SerializedCustomQuoteNode = Spread
-
-export class CustomQuoteNode extends QuoteNode {
- __id: string = '';
- __alignment: CommonBlockAlignment = '';
- __inset: number = 0;
-
- static getType() {
- return 'custom-quote';
- }
-
- 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;
- }
-
- static clone(node: CustomQuoteNode) {
- const newNode = new CustomQuoteNode(node.__key);
- newNode.__id = node.__id;
- newNode.__alignment = node.__alignment;
- newNode.__inset = node.__inset;
- return newNode;
- }
-
- createDOM(config: EditorConfig): HTMLElement {
- const dom = super.createDOM(config);
- updateElementWithCommonBlockProps(dom, this);
- return dom;
- }
-
- updateDOM(prevNode: CustomQuoteNode): boolean {
- return commonPropertiesDifferent(prevNode, this);
- }
-
- exportJSON(): SerializedCustomQuoteNode {
- return {
- ...super.exportJSON(),
- type: 'custom-quote',
- version: 1,
- id: this.__id,
- alignment: this.__alignment,
- inset: this.__inset,
- };
- }
-
- static importJSON(serializedNode: SerializedCustomQuoteNode): CustomQuoteNode {
- const node = $createCustomQuoteNode();
- deserializeCommonBlockNode(serializedNode, node);
- return node;
- }
-
- static importDOM(): DOMConversionMap | null {
- return {
- blockquote: (node: Node) => ({
- conversion: $convertBlockquoteElement,
- priority: 0,
- }),
- };
- }
-}
-
-function $convertBlockquoteElement(element: HTMLElement): DOMConversionOutput {
- const node = $createCustomQuoteNode();
- setCommonBlockPropsFromElement(element, node);
- return {node};
-}
-
-export function $createCustomQuoteNode() {
- return new CustomQuoteNode();
-}
-
-export function $isCustomQuoteNode(node: LexicalNode | null | undefined): node is CustomQuoteNode {
- return node instanceof CustomQuoteNode;
-}
\ No newline at end of file
diff --git a/resources/js/wysiwyg/nodes/custom-table-cell.ts b/resources/js/wysiwyg/nodes/custom-table-cell.ts
deleted file mode 100644
index 793302cfe..000000000
--- a/resources/js/wysiwyg/nodes/custom-table-cell.ts
+++ /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;
- 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
index f4702f36d..000000000
--- a/resources/js/wysiwyg/nodes/custom-table-row.ts
+++ /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,
-}, 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
index c25c06c65..000000000
--- a/resources/js/wysiwyg/nodes/custom-table.ts
+++ /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,
-}, 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;
-}
diff --git a/resources/js/wysiwyg/nodes/index.ts b/resources/js/wysiwyg/nodes/index.ts
deleted file mode 100644
index b5483c500..000000000
--- a/resources/js/wysiwyg/nodes/index.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-import {HeadingNode, QuoteNode} from '@lexical/rich-text';
-import {CalloutNode} from './callout';
-import {
- ElementNode,
- KlassConstructor,
- LexicalNode,
- LexicalNodeReplacement, NodeMutation,
- ParagraphNode
-} from "lexical";
-import {CustomParagraphNode} from "./custom-paragraph";
-import {LinkNode} from "@lexical/link";
-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 {CustomListItemNode} from "./custom-list-item";
-import {CustomTableCellNode} from "./custom-table-cell";
-import {CustomTableRowNode} from "./custom-table-row";
-import {CustomHeadingNode} from "./custom-heading";
-import {CustomQuoteNode} from "./custom-quote";
-import {CustomListNode} from "./custom-list";
-
-/**
- * Load the nodes for lexical.
- */
-export function getNodesForPageEditor(): (KlassConstructor | LexicalNodeReplacement)[] {
- return [
- CalloutNode,
- CustomHeadingNode,
- CustomQuoteNode,
- CustomListNode,
- CustomListItemNode, // TODO - Alignment?
- CustomTableNode,
- CustomTableRowNode,
- CustomTableCellNode,
- ImageNode, // TODO - Alignment
- HorizontalRuleNode,
- DetailsNode, SummaryNode,
- CodeBlockNode,
- DiagramNode,
- MediaNode, // TODO - Alignment
- CustomParagraphNode,
- LinkNode,
- {
- replace: ParagraphNode,
- with: (node: ParagraphNode) => {
- return new CustomParagraphNode();
- }
- },
- {
- replace: HeadingNode,
- with: (node: HeadingNode) => {
- return new CustomHeadingNode(node.__tag);
- }
- },
- {
- replace: QuoteNode,
- with: (node: QuoteNode) => {
- return new CustomQuoteNode();
- }
- },
- {
- replace: ListNode,
- with: (node: ListNode) => {
- return new CustomListNode(node.getListType(), node.getStart());
- }
- },
- {
- replace: ListItemNode,
- with: (node: ListItemNode) => {
- return new CustomListItemNode(node.__value, node.__checked);
- }
- },
- {
- 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;
- }
- },
- ];
-}
-
-export function registerCommonNodeMutationListeners(context: EditorUiContext): void {
- const decorated = [ImageNode, CodeBlockNode, DiagramNode];
-
- const decorationDestroyListener = (mutations: Map): void => {
- for (let [nodeKey, mutation] of mutations) {
- if (mutation === "destroyed") {
- const decorator = context.manager.getDecoratorByNodeKey(nodeKey);
- if (decorator) {
- decorator.destroy(context);
- }
- }
- }
- };
-
- for (let decoratedNode of decorated) {
- // Have to pass a unique function here since they are stored by lexical keyed on listener function.
- context.editor.registerMutationListener(decoratedNode, (mutations) => decorationDestroyListener(mutations));
- }
-}
-
-export type LexicalNodeMatcher = (node: LexicalNode|null|undefined) => boolean;
-export type LexicalElementNodeCreator = () => ElementNode;
\ No newline at end of file
diff --git a/resources/js/wysiwyg/services/drop-paste-handling.ts b/resources/js/wysiwyg/services/drop-paste-handling.ts
index 07e35d443..2ee831d74 100644
--- a/resources/js/wysiwyg/services/drop-paste-handling.ts
+++ b/resources/js/wysiwyg/services/drop-paste-handling.ts
@@ -1,4 +1,5 @@
import {
+ $createParagraphNode,
$insertNodes,
$isDecoratorNode, COMMAND_PRIORITY_HIGH, DROP_COMMAND,
LexicalEditor,
@@ -7,8 +8,7 @@ import {
import {$insertNewBlockNodesAtSelection, $selectSingleNode} from "../utils/selection";
import {$getNearestBlockNodeForCoords, $htmlToBlockNodes} from "../utils/nodes";
import {Clipboard} from "../../services/clipboard";
-import {$createImageNode} from "../nodes/image";
-import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
+import {$createImageNode} from "@lexical/rich-text/LexicalImageNode";
import {$createLinkNode} from "@lexical/link";
import {EditorImageData, uploadImageFile} from "../utils/images";
import {EditorUiContext} from "../ui/framework/core";
@@ -67,7 +67,7 @@ function handleMediaInsert(data: DataTransfer, context: EditorUiContext): boolea
for (const imageFile of images) {
const loadingImage = window.baseUrl('/loading.gif');
const loadingNode = $createImageNode(loadingImage);
- const imageWrap = $createCustomParagraphNode();
+ const imageWrap = $createParagraphNode();
imageWrap.append(loadingNode);
$insertNodes([imageWrap]);
diff --git a/resources/js/wysiwyg/services/keyboard-handling.ts b/resources/js/wysiwyg/services/keyboard-handling.ts
index 2c7bfdbba..6a1345fac 100644
--- a/resources/js/wysiwyg/services/keyboard-handling.ts
+++ b/resources/js/wysiwyg/services/keyboard-handling.ts
@@ -1,5 +1,6 @@
import {EditorUiContext} from "../ui/framework/core";
import {
+ $createParagraphNode,
$getSelection,
$isDecoratorNode,
COMMAND_PRIORITY_LOW,
@@ -9,13 +10,12 @@ import {
LexicalEditor,
LexicalNode
} from "lexical";
-import {$isImageNode} from "../nodes/image";
-import {$isMediaNode} from "../nodes/media";
+import {$isImageNode} from "@lexical/rich-text/LexicalImageNode";
+import {$isMediaNode} from "@lexical/rich-text/LexicalMediaNode";
import {getLastSelection} from "../utils/selection";
import {$getNearestNodeBlockParent} from "../utils/nodes";
-import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
-import {$isCustomListItemNode} from "../nodes/custom-list-item";
import {$setInsetForSelection} from "../utils/lists";
+import {$isListItemNode} from "@lexical/list";
function isSingleSelectedNode(nodes: LexicalNode[]): boolean {
if (nodes.length === 1) {
@@ -45,7 +45,7 @@ function insertAfterSingleSelectedNode(editor: LexicalEditor, event: KeyboardEve
if (nearestBlock) {
requestAnimationFrame(() => {
editor.update(() => {
- const newParagraph = $createCustomParagraphNode();
+ const newParagraph = $createParagraphNode();
nearestBlock.insertAfter(newParagraph);
newParagraph.select();
});
@@ -62,7 +62,7 @@ function handleInsetOnTab(editor: LexicalEditor, event: KeyboardEvent|null): boo
const change = event?.shiftKey ? -40 : 40;
const selection = $getSelection();
const nodes = selection?.getNodes() || [];
- if (nodes.length > 1 || (nodes.length === 1 && $isCustomListItemNode(nodes[0].getParent()))) {
+ if (nodes.length > 1 || (nodes.length === 1 && $isListItemNode(nodes[0].getParent()))) {
editor.update(() => {
$setInsetForSelection(editor, change);
});
diff --git a/resources/js/wysiwyg/services/shortcuts.ts b/resources/js/wysiwyg/services/shortcuts.ts
index 05bdb5dcc..0384a3bf1 100644
--- a/resources/js/wysiwyg/services/shortcuts.ts
+++ b/resources/js/wysiwyg/services/shortcuts.ts
@@ -6,12 +6,12 @@ import {
toggleSelectionAsHeading, toggleSelectionAsList,
toggleSelectionAsParagraph
} from "../utils/formats";
-import {HeadingTagType} from "@lexical/rich-text";
import {EditorUiContext} from "../ui/framework/core";
import {$getNodeFromSelection} from "../utils/selection";
import {$isLinkNode, LinkNode} from "@lexical/link";
import {$showLinkForm} from "../ui/defaults/forms/objects";
import {showLinkSelector} from "../utils/links";
+import {HeadingTagType} from "@lexical/rich-text/LexicalHeadingNode";
function headerHandler(editor: LexicalEditor, tag: HeadingTagType): boolean {
toggleSelectionAsHeading(editor, tag);
diff --git a/resources/js/wysiwyg/todo.md b/resources/js/wysiwyg/todo.md
index a49cccd26..817a235a7 100644
--- a/resources/js/wysiwyg/todo.md
+++ b/resources/js/wysiwyg/todo.md
@@ -2,7 +2,11 @@
## In progress
-//
+Reorg
+ - Merge custom nodes into original nodes
+ - Reduce down to use CommonBlockNode where possible
+ - Remove existing formatType/ElementFormatType references (replaced with alignment).
+ - Remove existing indent references (replaced with inset).
## Main Todo
diff --git a/resources/js/wysiwyg/ui/decorators/code-block.ts b/resources/js/wysiwyg/ui/decorators/code-block.ts
index 37d3df588..daae32e19 100644
--- a/resources/js/wysiwyg/ui/decorators/code-block.ts
+++ b/resources/js/wysiwyg/ui/decorators/code-block.ts
@@ -1,7 +1,7 @@
import {EditorDecorator} from "../framework/decorator";
import {EditorUiContext} from "../framework/core";
-import {$openCodeEditorForNode, CodeBlockNode} from "../../nodes/code-block";
-import {$isDecoratorNode, BaseSelection} from "lexical";
+import {$openCodeEditorForNode, CodeBlockNode} from "@lexical/rich-text/LexicalCodeBlockNode";
+import {BaseSelection} from "lexical";
import {$selectionContainsNode, $selectSingleNode} from "../../utils/selection";
diff --git a/resources/js/wysiwyg/ui/decorators/diagram.ts b/resources/js/wysiwyg/ui/decorators/diagram.ts
index 44d332939..d53bcb482 100644
--- a/resources/js/wysiwyg/ui/decorators/diagram.ts
+++ b/resources/js/wysiwyg/ui/decorators/diagram.ts
@@ -1,7 +1,7 @@
import {EditorDecorator} from "../framework/decorator";
import {EditorUiContext} from "../framework/core";
import {BaseSelection} from "lexical";
-import {DiagramNode} from "../../nodes/diagram";
+import {DiagramNode} from "@lexical/rich-text/LexicalDiagramNode";
import {$selectionContainsNode, $selectSingleNode} from "../../utils/selection";
import {$openDrawingEditorForNode} from "../../utils/diagrams";
diff --git a/resources/js/wysiwyg/ui/defaults/buttons/alignments.ts b/resources/js/wysiwyg/ui/defaults/buttons/alignments.ts
index f0f46ddc6..98edf44b3 100644
--- a/resources/js/wysiwyg/ui/defaults/buttons/alignments.ts
+++ b/resources/js/wysiwyg/ui/defaults/buttons/alignments.ts
@@ -9,9 +9,9 @@ import ltrIcon from "@icons/editor/direction-ltr.svg";
import rtlIcon from "@icons/editor/direction-rtl.svg";
import {
$getBlockElementNodesInSelection,
- $selectionContainsAlignment, $selectionContainsDirection, $selectSingleNode, $toggleSelection, getLastSelection
+ $selectionContainsAlignment, $selectionContainsDirection, $selectSingleNode, getLastSelection
} from "../../../utils/selection";
-import {CommonBlockAlignment} from "../../../nodes/_common";
+import {CommonBlockAlignment} from "lexical/nodes/common";
import {nodeHasAlignment} from "../../../utils/nodes";
diff --git a/resources/js/wysiwyg/ui/defaults/buttons/block-formats.ts b/resources/js/wysiwyg/ui/defaults/buttons/block-formats.ts
index f86e33c31..b36fd1c4f 100644
--- a/resources/js/wysiwyg/ui/defaults/buttons/block-formats.ts
+++ b/resources/js/wysiwyg/ui/defaults/buttons/block-formats.ts
@@ -1,19 +1,15 @@
-import {$createCalloutNode, $isCalloutNodeOfCategory, CalloutCategory} from "../../../nodes/callout";
+import {$createCalloutNode, $isCalloutNodeOfCategory, CalloutCategory} from "@lexical/rich-text/LexicalCalloutNode";
import {EditorButtonDefinition} from "../../framework/buttons";
import {EditorUiContext} from "../../framework/core";
import {$isParagraphNode, BaseSelection, LexicalNode} from "lexical";
-import {
- $isHeadingNode,
- $isQuoteNode,
- HeadingNode,
- HeadingTagType
-} from "@lexical/rich-text";
import {$selectionContainsNodeType, $toggleSelectionBlockNodeType} from "../../../utils/selection";
import {
toggleSelectionAsBlockquote,
toggleSelectionAsHeading,
toggleSelectionAsParagraph
} from "../../../utils/formats";
+import {$isHeadingNode, HeadingNode, HeadingTagType} from "@lexical/rich-text/LexicalHeadingNode";
+import {$isQuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
function buildCalloutButton(category: CalloutCategory, name: string): EditorButtonDefinition {
return {
diff --git a/resources/js/wysiwyg/ui/defaults/buttons/objects.ts b/resources/js/wysiwyg/ui/defaults/buttons/objects.ts
index fd95f9f35..f9c029ff1 100644
--- a/resources/js/wysiwyg/ui/defaults/buttons/objects.ts
+++ b/resources/js/wysiwyg/ui/defaults/buttons/objects.ts
@@ -2,27 +2,26 @@ import {EditorButtonDefinition} from "../../framework/buttons";
import linkIcon from "@icons/editor/link.svg";
import {EditorUiContext} from "../../framework/core";
import {
- $createTextNode,
$getRoot,
$getSelection, $insertNodes,
BaseSelection,
- ElementNode, isCurrentlyReadOnlyMode
+ ElementNode
} from "lexical";
import {$isLinkNode, LinkNode} from "@lexical/link";
import unlinkIcon from "@icons/editor/unlink.svg";
import imageIcon from "@icons/editor/image.svg";
-import {$isImageNode, ImageNode} from "../../../nodes/image";
+import {$isImageNode, ImageNode} from "@lexical/rich-text/LexicalImageNode";
import horizontalRuleIcon from "@icons/editor/horizontal-rule.svg";
-import {$createHorizontalRuleNode, $isHorizontalRuleNode} from "../../../nodes/horizontal-rule";
+import {$createHorizontalRuleNode, $isHorizontalRuleNode} from "@lexical/rich-text/LexicalHorizontalRuleNode";
import codeBlockIcon from "@icons/editor/code-block.svg";
-import {$isCodeBlockNode} from "../../../nodes/code-block";
+import {$isCodeBlockNode} from "@lexical/rich-text/LexicalCodeBlockNode";
import editIcon from "@icons/edit.svg";
import diagramIcon from "@icons/editor/diagram.svg";
-import {$createDiagramNode, DiagramNode} from "../../../nodes/diagram";
+import {$createDiagramNode, DiagramNode} from "@lexical/rich-text/LexicalDiagramNode";
import detailsIcon from "@icons/editor/details.svg";
import mediaIcon from "@icons/editor/media.svg";
-import {$createDetailsNode, $isDetailsNode} from "../../../nodes/details";
-import {$isMediaNode, MediaNode} from "../../../nodes/media";
+import {$createDetailsNode, $isDetailsNode} from "@lexical/rich-text/LexicalDetailsNode";
+import {$isMediaNode, MediaNode} from "@lexical/rich-text/LexicalMediaNode";
import {
$getNodeFromSelection,
$insertNewBlockNodeAtSelection,
diff --git a/resources/js/wysiwyg/ui/defaults/buttons/tables.ts b/resources/js/wysiwyg/ui/defaults/buttons/tables.ts
index fc4196f0a..2e4883d88 100644
--- a/resources/js/wysiwyg/ui/defaults/buttons/tables.ts
+++ b/resources/js/wysiwyg/ui/defaults/buttons/tables.ts
@@ -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;
diff --git a/resources/js/wysiwyg/ui/defaults/forms/objects.ts b/resources/js/wysiwyg/ui/defaults/forms/objects.ts
index 228566d44..f00a08bb5 100644
--- a/resources/js/wysiwyg/ui/defaults/forms/objects.ts
+++ b/resources/js/wysiwyg/ui/defaults/forms/objects.ts
@@ -5,11 +5,10 @@ import {
EditorSelectFormFieldDefinition
} from "../../framework/forms";
import {EditorUiContext} from "../../framework/core";
-import {$createNodeSelection, $createTextNode, $getSelection, $insertNodes, $setSelection} from "lexical";
-import {$isImageNode, ImageNode} from "../../../nodes/image";
-import {$createLinkNode, $isLinkNode, LinkNode} from "@lexical/link";
-import {$createMediaNodeFromHtml, $createMediaNodeFromSrc, $isMediaNode, MediaNode} from "../../../nodes/media";
-import {$insertNodeToNearestRoot} from "@lexical/utils";
+import {$createNodeSelection, $getSelection, $insertNodes, $setSelection} from "lexical";
+import {$isImageNode, ImageNode} from "@lexical/rich-text/LexicalImageNode";
+import {LinkNode} from "@lexical/link";
+import {$createMediaNodeFromHtml, $createMediaNodeFromSrc, $isMediaNode, MediaNode} from "@lexical/rich-text/LexicalMediaNode";
import {$getNodeFromSelection, getLastSelection} from "../../../utils/selection";
import {EditorFormModal} from "../../framework/modals";
import {EditorActionField} from "../../framework/blocks/action-field";
diff --git a/resources/js/wysiwyg/ui/defaults/forms/tables.ts b/resources/js/wysiwyg/ui/defaults/forms/tables.ts
index 5a41c85b3..63fa24c80 100644
--- a/resources/js/wysiwyg/ui/defaults/forms/tables.ts
+++ b/resources/js/wysiwyg/ui/defaults/forms/tables.ts
@@ -5,9 +5,8 @@ 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 {$getSelection} from "lexical";
import {
$forEachTableCell, $getCellPaddingForTable,
$getTableCellColumnWidth,
@@ -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 "lexical/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);
diff --git a/resources/js/wysiwyg/ui/framework/blocks/link-field.ts b/resources/js/wysiwyg/ui/framework/blocks/link-field.ts
index 5a64cdc30..f88b22c3f 100644
--- a/resources/js/wysiwyg/ui/framework/blocks/link-field.ts
+++ b/resources/js/wysiwyg/ui/framework/blocks/link-field.ts
@@ -1,14 +1,13 @@
import {EditorContainerUiElement} from "../core";
import {el} from "../../../utils/dom";
import {EditorFormField} from "../forms";
-import {CustomHeadingNode} from "../../../nodes/custom-heading";
import {$getAllNodesOfType} from "../../../utils/nodes";
-import {$isHeadingNode} from "@lexical/rich-text";
import {uniqueIdSmall} from "../../../../services/util";
+import {$isHeadingNode, HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
export class LinkField extends EditorContainerUiElement {
protected input: EditorFormField;
- protected headerMap = new Map();
+ protected headerMap = new Map();
constructor(input: EditorFormField) {
super([input]);
@@ -43,7 +42,7 @@ export class LinkField extends EditorContainerUiElement {
return container;
}
- updateFormFromHeader(header: CustomHeadingNode) {
+ updateFormFromHeader(header: HeadingNode) {
this.getHeaderIdAndText(header).then(({id, text}) => {
console.log('updating form', id, text);
const modal = this.getContext().manager.getActiveModal('link');
@@ -57,7 +56,7 @@ export class LinkField extends EditorContainerUiElement {
});
}
- getHeaderIdAndText(header: CustomHeadingNode): Promise<{id: string, text: string}> {
+ getHeaderIdAndText(header: HeadingNode): Promise<{id: string, text: string}> {
return new Promise((res) => {
this.getContext().editor.update(() => {
let id = header.getId();
@@ -75,7 +74,7 @@ export class LinkField extends EditorContainerUiElement {
updateDataList(listEl: HTMLElement) {
this.getContext().editor.getEditorState().read(() => {
- const headers = $getAllNodesOfType($isHeadingNode) as CustomHeadingNode[];
+ const headers = $getAllNodesOfType($isHeadingNode) as HeadingNode[];
this.headerMap.clear();
const listEls: HTMLElement[] = [];
diff --git a/resources/js/wysiwyg/ui/framework/blocks/table-creator.ts b/resources/js/wysiwyg/ui/framework/blocks/table-creator.ts
index 30ff3abc5..6f026ca18 100644
--- a/resources/js/wysiwyg/ui/framework/blocks/table-creator.ts
+++ b/resources/js/wysiwyg/ui/framework/blocks/table-creator.ts
@@ -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);
});
diff --git a/resources/js/wysiwyg/ui/framework/helpers/node-resizer.ts b/resources/js/wysiwyg/ui/framework/helpers/node-resizer.ts
index 2e4f2939c..fa8ff48be 100644
--- a/resources/js/wysiwyg/ui/framework/helpers/node-resizer.ts
+++ b/resources/js/wysiwyg/ui/framework/helpers/node-resizer.ts
@@ -1,10 +1,10 @@
import {BaseSelection, LexicalNode,} from "lexical";
import {MouseDragTracker, MouseDragTrackerDistance} from "./mouse-drag-tracker";
import {el} from "../../../utils/dom";
-import {$isImageNode} from "../../../nodes/image";
+import {$isImageNode} from "@lexical/rich-text/LexicalImageNode";
import {EditorUiContext} from "../core";
-import {NodeHasSize} from "../../../nodes/_common";
-import {$isMediaNode} from "../../../nodes/media";
+import {NodeHasSize} from "lexical/nodes/common";
+import {$isMediaNode} from "@lexical/rich-text/LexicalMediaNode";
function isNodeWithSize(node: LexicalNode): node is NodeHasSize&LexicalNode {
return $isImageNode(node) || $isMediaNode(node);
diff --git a/resources/js/wysiwyg/ui/framework/helpers/table-resizer.ts b/resources/js/wysiwyg/ui/framework/helpers/table-resizer.ts
index 37f1b6f01..4256fdafc 100644
--- a/resources/js/wysiwyg/ui/framework/helpers/table-resizer.ts
+++ b/resources/js/wysiwyg/ui/framework/helpers/table-resizer.ts
@@ -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);
diff --git a/resources/js/wysiwyg/ui/framework/helpers/table-selection-handler.ts b/resources/js/wysiwyg/ui/framework/helpers/table-selection-handler.ts
index f631fb804..d3d892550 100644
--- a/resources/js/wysiwyg/ui/framework/helpers/table-selection-handler.ts
+++ b/resources/js/wysiwyg/ui/framework/helpers/table-selection-handler.ts
@@ -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(nodeKey);
- if ($isCustomTableNode(tableNode)) {
+ const tableNode = $getNodeByKey(nodeKey);
+ if ($isTableNode(tableNode)) {
this.initializeTableNode(tableNode);
}
});
diff --git a/resources/js/wysiwyg/ui/framework/helpers/task-list-handler.ts b/resources/js/wysiwyg/ui/framework/helpers/task-list-handler.ts
index da8c0eae3..62a784d83 100644
--- a/resources/js/wysiwyg/ui/framework/helpers/task-list-handler.ts
+++ b/resources/js/wysiwyg/ui/framework/helpers/task-list-handler.ts
@@ -1,5 +1,5 @@
import {$getNearestNodeFromDOMNode, LexicalEditor} from "lexical";
-import {$isCustomListItemNode} from "../../../nodes/custom-list-item";
+import {$isListItemNode} from "@lexical/list";
class TaskListHandler {
protected editorContainer: HTMLElement;
@@ -38,7 +38,7 @@ class TaskListHandler {
this.editor.update(() => {
const node = $getNearestNodeFromDOMNode(listItem);
- if ($isCustomListItemNode(node)) {
+ if ($isListItemNode(node)) {
node.setChecked(!node.getChecked());
}
});
diff --git a/resources/js/wysiwyg/ui/framework/manager.ts b/resources/js/wysiwyg/ui/framework/manager.ts
index 7c0975da7..185cd5dcc 100644
--- a/resources/js/wysiwyg/ui/framework/manager.ts
+++ b/resources/js/wysiwyg/ui/framework/manager.ts
@@ -1,7 +1,7 @@
import {EditorFormModal, EditorFormModalDefinition} from "./modals";
import {EditorContainerUiElement, EditorUiContext, EditorUiElement, EditorUiStateUpdate} from "./core";
import {EditorDecorator, EditorDecoratorAdapter} from "./decorator";
-import {$getSelection, BaseSelection, COMMAND_PRIORITY_LOW, LexicalEditor, SELECTION_CHANGE_COMMAND} from "lexical";
+import {BaseSelection, LexicalEditor} from "lexical";
import {DecoratorListener} from "lexical/LexicalEditor";
import type {NodeKey} from "lexical/LexicalNode";
import {EditorContextToolbar, EditorContextToolbarDefinition} from "./toolbars";
diff --git a/resources/js/wysiwyg/utils/diagrams.ts b/resources/js/wysiwyg/utils/diagrams.ts
index fb5543005..ffd8e603b 100644
--- a/resources/js/wysiwyg/utils/diagrams.ts
+++ b/resources/js/wysiwyg/utils/diagrams.ts
@@ -1,8 +1,8 @@
-import {$getSelection, $insertNodes, LexicalEditor, LexicalNode} from "lexical";
+import {$insertNodes, LexicalEditor, LexicalNode} from "lexical";
import {HttpError} from "../../services/http";
import {EditorUiContext} from "../ui/framework/core";
import * as DrawIO from "../../services/drawio";
-import {$createDiagramNode, DiagramNode} from "../nodes/diagram";
+import {$createDiagramNode, DiagramNode} from "@lexical/rich-text/LexicalDiagramNode";
import {ImageManager} from "../../components";
import {EditorImageData} from "./images";
import {$getNodeFromSelection, getLastSelection} from "./selection";
diff --git a/resources/js/wysiwyg/utils/formats.ts b/resources/js/wysiwyg/utils/formats.ts
index 0ec9220dd..a5f06f147 100644
--- a/resources/js/wysiwyg/utils/formats.ts
+++ b/resources/js/wysiwyg/utils/formats.ts
@@ -1,5 +1,12 @@
-import {$isQuoteNode, HeadingNode, HeadingTagType} from "@lexical/rich-text";
-import {$createTextNode, $getSelection, $insertNodes, LexicalEditor, LexicalNode} from "lexical";
+import {
+ $createParagraphNode,
+ $createTextNode,
+ $getSelection,
+ $insertNodes,
+ $isParagraphNode,
+ LexicalEditor,
+ LexicalNode
+} from "lexical";
import {
$getBlockElementNodesInSelection,
$getNodeFromSelection,
@@ -7,37 +14,35 @@ import {
$toggleSelectionBlockNodeType,
getLastSelection
} from "./selection";
-import {$createCustomHeadingNode, $isCustomHeadingNode} from "../nodes/custom-heading";
-import {$createCustomParagraphNode, $isCustomParagraphNode} from "../nodes/custom-paragraph";
-import {$createCustomQuoteNode} from "../nodes/custom-quote";
-import {$createCodeBlockNode, $isCodeBlockNode, $openCodeEditorForNode, CodeBlockNode} from "../nodes/code-block";
-import {$createCalloutNode, $isCalloutNode, CalloutCategory} from "../nodes/callout";
-import {insertList, ListNode, ListType, removeList} from "@lexical/list";
-import {$isCustomListNode} from "../nodes/custom-list";
+import {$createCodeBlockNode, $isCodeBlockNode, $openCodeEditorForNode, CodeBlockNode} from "@lexical/rich-text/LexicalCodeBlockNode";
+import {$createCalloutNode, $isCalloutNode, CalloutCategory} from "@lexical/rich-text/LexicalCalloutNode";
+import {$isListNode, insertList, ListNode, ListType, removeList} from "@lexical/list";
import {$createLinkNode, $isLinkNode} from "@lexical/link";
+import {$createHeadingNode, $isHeadingNode, HeadingTagType} from "@lexical/rich-text/LexicalHeadingNode";
+import {$createQuoteNode, $isQuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
const $isHeaderNodeOfTag = (node: LexicalNode | null | undefined, tag: HeadingTagType) => {
- return $isCustomHeadingNode(node) && (node as HeadingNode).getTag() === tag;
+ return $isHeadingNode(node) && node.getTag() === tag;
};
export function toggleSelectionAsHeading(editor: LexicalEditor, tag: HeadingTagType) {
editor.update(() => {
$toggleSelectionBlockNodeType(
(node) => $isHeaderNodeOfTag(node, tag),
- () => $createCustomHeadingNode(tag),
+ () => $createHeadingNode(tag),
)
});
}
export function toggleSelectionAsParagraph(editor: LexicalEditor) {
editor.update(() => {
- $toggleSelectionBlockNodeType($isCustomParagraphNode, $createCustomParagraphNode);
+ $toggleSelectionBlockNodeType($isParagraphNode, $createParagraphNode);
});
}
export function toggleSelectionAsBlockquote(editor: LexicalEditor) {
editor.update(() => {
- $toggleSelectionBlockNodeType($isQuoteNode, $createCustomQuoteNode);
+ $toggleSelectionBlockNodeType($isQuoteNode, $createQuoteNode);
});
}
@@ -45,7 +50,7 @@ export function toggleSelectionAsList(editor: LexicalEditor, type: ListType) {
editor.getEditorState().read(() => {
const selection = $getSelection();
const listSelected = $selectionContainsNodeType(selection, (node: LexicalNode | null | undefined): boolean => {
- return $isCustomListNode(node) && (node as ListNode).getListType() === type;
+ return $isListNode(node) && (node as ListNode).getListType() === type;
});
if (listSelected) {
diff --git a/resources/js/wysiwyg/utils/images.ts b/resources/js/wysiwyg/utils/images.ts
index 2c13427d9..85bae18e5 100644
--- a/resources/js/wysiwyg/utils/images.ts
+++ b/resources/js/wysiwyg/utils/images.ts
@@ -1,5 +1,5 @@
import {ImageManager} from "../../components";
-import {$createImageNode} from "../nodes/image";
+import {$createImageNode} from "@lexical/rich-text/LexicalImageNode";
import {$createLinkNode, LinkNode} from "@lexical/link";
export type EditorImageData = {
diff --git a/resources/js/wysiwyg/utils/lists.ts b/resources/js/wysiwyg/utils/lists.ts
index 30a97cbc1..646f341c2 100644
--- a/resources/js/wysiwyg/utils/lists.ts
+++ b/resources/js/wysiwyg/utils/lists.ts
@@ -1,22 +1,21 @@
-import {$createCustomListItemNode, $isCustomListItemNode, CustomListItemNode} from "../nodes/custom-list-item";
-import {$createCustomListNode, $isCustomListNode} from "../nodes/custom-list";
import {$getSelection, BaseSelection, LexicalEditor} from "lexical";
import {$getBlockElementNodesInSelection, $selectNodes, $toggleSelection} from "./selection";
import {nodeHasInset} from "./nodes";
+import {$createListItemNode, $createListNode, $isListItemNode, $isListNode, ListItemNode} from "@lexical/list";
-export function $nestListItem(node: CustomListItemNode): CustomListItemNode {
+export function $nestListItem(node: ListItemNode): ListItemNode {
const list = node.getParent();
- if (!$isCustomListNode(list)) {
+ if (!$isListNode(list)) {
return node;
}
- const listItems = list.getChildren() as CustomListItemNode[];
+ const listItems = list.getChildren() as ListItemNode[];
const nodeIndex = listItems.findIndex((n) => n.getKey() === node.getKey());
const isFirst = nodeIndex === 0;
- const newListItem = $createCustomListItemNode();
- const newList = $createCustomListNode(list.getListType());
+ const newListItem = $createListItemNode();
+ const newList = $createListNode(list.getListType());
newList.append(newListItem);
newListItem.append(...node.getChildren());
@@ -31,11 +30,11 @@ export function $nestListItem(node: CustomListItemNode): CustomListItemNode {
return newListItem;
}
-export function $unnestListItem(node: CustomListItemNode): CustomListItemNode {
+export function $unnestListItem(node: ListItemNode): ListItemNode {
const list = node.getParent();
const parentListItem = list?.getParent();
const outerList = parentListItem?.getParent();
- if (!$isCustomListNode(list) || !$isCustomListNode(outerList) || !$isCustomListItemNode(parentListItem)) {
+ if (!$isListNode(list) || !$isListNode(outerList) || !$isListItemNode(parentListItem)) {
return node;
}
@@ -51,19 +50,19 @@ export function $unnestListItem(node: CustomListItemNode): CustomListItemNode {
return node;
}
-function getListItemsForSelection(selection: BaseSelection|null): (CustomListItemNode|null)[] {
+function getListItemsForSelection(selection: BaseSelection|null): (ListItemNode|null)[] {
const nodes = selection?.getNodes() || [];
const listItemNodes = [];
outer: for (const node of nodes) {
- if ($isCustomListItemNode(node)) {
+ if ($isListItemNode(node)) {
listItemNodes.push(node);
continue;
}
const parents = node.getParents();
for (const parent of parents) {
- if ($isCustomListItemNode(parent)) {
+ if ($isListItemNode(parent)) {
listItemNodes.push(parent);
continue outer;
}
@@ -75,8 +74,8 @@ function getListItemsForSelection(selection: BaseSelection|null): (CustomListIte
return listItemNodes;
}
-function $reduceDedupeListItems(listItems: (CustomListItemNode|null)[]): CustomListItemNode[] {
- const listItemMap: Record = {};
+function $reduceDedupeListItems(listItems: (ListItemNode|null)[]): ListItemNode[] {
+ const listItemMap: Record = {};
for (const item of listItems) {
if (item === null) {
diff --git a/resources/js/wysiwyg/utils/nodes.ts b/resources/js/wysiwyg/utils/nodes.ts
index 2dd99d369..b5cc78955 100644
--- a/resources/js/wysiwyg/utils/nodes.ts
+++ b/resources/js/wysiwyg/utils/nodes.ts
@@ -1,4 +1,5 @@
import {
+ $createParagraphNode,
$getRoot,
$isDecoratorNode,
$isElementNode, $isRootNode,
@@ -8,16 +9,15 @@ import {
LexicalNode
} from "lexical";
import {LexicalNodeMatcher} from "../nodes";
-import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
import {$generateNodesFromDOM} from "@lexical/html";
import {htmlToDom} from "./dom";
-import {NodeHasAlignment, NodeHasInset} from "../nodes/_common";
+import {NodeHasAlignment, NodeHasInset} from "lexical/nodes/common";
import {$findMatchingParent} from "@lexical/utils";
function wrapTextNodes(nodes: LexicalNode[]): LexicalNode[] {
return nodes.map(node => {
if ($isTextNode(node)) {
- const paragraph = $createCustomParagraphNode();
+ const paragraph = $createParagraphNode();
paragraph.append(node);
return paragraph;
}
diff --git a/resources/js/wysiwyg/utils/selection.ts b/resources/js/wysiwyg/utils/selection.ts
index 67c2d91b2..28e729e92 100644
--- a/resources/js/wysiwyg/utils/selection.ts
+++ b/resources/js/wysiwyg/utils/selection.ts
@@ -7,18 +7,16 @@ import {
$isTextNode,
$setSelection,
BaseSelection, DecoratorNode,
- ElementFormatType,
ElementNode, LexicalEditor,
LexicalNode,
TextFormatType, TextNode
} from "lexical";
-import {$findMatchingParent, $getNearestBlockElementAncestorOrThrow} from "@lexical/utils";
+import {$getNearestBlockElementAncestorOrThrow} from "@lexical/utils";
import {LexicalElementNodeCreator, LexicalNodeMatcher} from "../nodes";
import {$setBlocksType} from "@lexical/selection";
import {$getNearestNodeBlockParent, $getParentOfType, nodeHasAlignment} from "./nodes";
-import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
-import {CommonBlockAlignment} from "../nodes/_common";
+import {CommonBlockAlignment} from "lexical/nodes/common";
const lastSelectionByEditor = new WeakMap;
@@ -71,7 +69,7 @@ export function $toggleSelectionBlockNodeType(matcher: LexicalNodeMatcher, creat
const selection = $getSelection();
const blockElement = selection ? $getNearestBlockElementAncestorOrThrow(selection.getNodes()[0]) : null;
if (selection && matcher(blockElement)) {
- $setBlocksType(selection, $createCustomParagraphNode);
+ $setBlocksType(selection, $createParagraphNode);
} else {
$setBlocksType(selection, creator);
}
diff --git a/resources/js/wysiwyg/utils/table-copy-paste.ts b/resources/js/wysiwyg/utils/table-copy-paste.ts
index 12c19b0fb..1e024e4c7 100644
--- a/resources/js/wysiwyg/utils/table-copy-paste.ts
+++ b/resources/js/wysiwyg/utils/table-copy-paste.ts
@@ -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 = new NodeClipboard();
+const rowClipboard: NodeClipboard = new NodeClipboard();
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[] = [];
+const columnClipboard: NodeClipboard[] = [];
-function setColumnClipboard(columns: CustomTableCellNode[][]): void {
+function setColumnClipboard(columns: TableCellNode[][]): void {
const newClipboards = columns.map(cells => {
- const clipboard = new NodeClipboard();
+ const clipboard = new NodeClipboard();
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++;
}
}
diff --git a/resources/js/wysiwyg/utils/table-map.ts b/resources/js/wysiwyg/utils/table-map.ts
index 607deffe1..dfe21b936 100644
--- a/resources/js/wysiwyg/utils/table-map.ts
+++ b/resources/js/wysiwyg/utils/table-map.ts
@@ -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();
+ const cells = new Set();
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();
diff --git a/resources/js/wysiwyg/utils/tables.ts b/resources/js/wysiwyg/utils/tables.ts
index aa8ec89ba..ed947ddcd 100644
--- a/resources/js/wysiwyg/utils/tables.ts
+++ b/resources/js/wysiwyg/utils/tables.ts
@@ -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();
+ const cells = row.getChildren();
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 = {};
+ const rowsByKey: Record = {};
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;