Skip to content

Commit

Permalink
Add node replacement system to core (#3367)
Browse files Browse the repository at this point in the history
* Add node replacement system to core

* Add test

* Fix missing logic

* Fix prettier

* Update flow types
  • Loading branch information
trueadm committed Nov 18, 2022
1 parent 7fc77ad commit 102b01d
Show file tree
Hide file tree
Showing 27 changed files with 207 additions and 57 deletions.
15 changes: 8 additions & 7 deletions packages/lexical-code/src/CodeHighlightNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@

// eslint-disable-next-line simple-import-sort/imports
import {
$applyNodeReplacement,
$isLineBreakNode,
EditorConfig,
EditorThemeClasses,
LexicalNode,
NodeKey,
SerializedTextNode,
Spread,
type EditorConfig,
type EditorThemeClasses,
type LexicalNode,
type NodeKey,
type SerializedTextNode,
type Spread,
TextNode,
} from 'lexical';

Expand Down Expand Up @@ -203,7 +204,7 @@ export function $createCodeHighlightNode(
text: string,
highlightType?: string | null | undefined,
): CodeHighlightNode {
return new CodeHighlightNode(text, highlightType);
return $applyNodeReplacement(new CodeHighlightNode(text, highlightType));
}

export function $isCodeHighlightNode(
Expand Down
3 changes: 2 additions & 1 deletion packages/lexical-code/src/CodeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import 'prismjs/components/prism-swift';

import {addClassNamesToElement} from '@lexical/utils';
import {
$applyNodeReplacement,
$createLineBreakNode,
$createParagraphNode,
$getSelection,
Expand Down Expand Up @@ -291,7 +292,7 @@ export class CodeNode extends ElementNode {
export function $createCodeNode(
language?: string | null | undefined,
): CodeNode {
return new CodeNode(language);
return $applyNodeReplacement(new CodeNode(language));
}

export function $isCodeNode(
Expand Down
4 changes: 2 additions & 2 deletions packages/lexical-hashtag/src/LexicalHashtagNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
} from 'lexical';

import {addClassNamesToElement} from '@lexical/utils';
import {TextNode} from 'lexical';
import {$applyNodeReplacement, TextNode} from 'lexical';

/** @noInheritDoc */
export class HashtagNode extends TextNode {
Expand Down Expand Up @@ -62,7 +62,7 @@ export class HashtagNode extends TextNode {
}

export function $createHashtagNode(text = ''): HashtagNode {
return new HashtagNode(text);
return $applyNodeReplacement(new HashtagNode(text));
}

export function $isHashtagNode(
Expand Down
3 changes: 2 additions & 1 deletion packages/lexical-list/src/LexicalListItemNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
removeClassNamesFromElement,
} from '@lexical/utils';
import {
$applyNodeReplacement,
$createParagraphNode,
$isElementNode,
$isParagraphNode,
Expand Down Expand Up @@ -509,7 +510,7 @@ function convertListItemElement(domNode: Node): DOMConversionOutput {
}

export function $createListItemNode(checked?: boolean): ListItemNode {
return new ListItemNode(undefined, checked);
return $applyNodeReplacement(new ListItemNode(undefined, checked));
}

export function $isListItemNode(
Expand Down
3 changes: 2 additions & 1 deletion packages/lexical-list/src/LexicalListNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
removeClassNamesFromElement,
} from '@lexical/utils';
import {
$applyNodeReplacement,
$createTextNode,
$isElementNode,
DOMConversionMap,
Expand Down Expand Up @@ -282,7 +283,7 @@ const TAG_TO_LIST_TYPE: Record<string, ListType> = {
};

export function $createListNode(listType: ListType, start = 1): ListNode {
return new ListNode(listType, start);
return $applyNodeReplacement(new ListNode(listType, start));
}

export function $isListNode(
Expand Down
9 changes: 7 additions & 2 deletions packages/lexical-mark/src/MarkNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ import {
addClassNamesToElement,
removeClassNamesFromElement,
} from '@lexical/utils';
import {$isElementNode, $isRangeSelection, ElementNode} from 'lexical';
import {
$applyNodeReplacement,
$isElementNode,
$isRangeSelection,
ElementNode,
} from 'lexical';

export type SerializedMarkNode = Spread<
{
Expand Down Expand Up @@ -200,7 +205,7 @@ export class MarkNode extends ElementNode {
}

export function $createMarkNode(ids: Array<string>): MarkNode {
return new MarkNode(ids);
return $applyNodeReplacement(new MarkNode(ids));
}

export function $isMarkNode(node: LexicalNode | null): node is MarkNode {
Expand Down
5 changes: 3 additions & 2 deletions packages/lexical-playground/src/nodes/EmojiNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
Spread,
} from 'lexical';

import {TextNode} from 'lexical';
import {$applyNodeReplacement, TextNode} from 'lexical';

export type SerializedEmojiNode = Spread<
{
Expand Down Expand Up @@ -98,5 +98,6 @@ export function $createEmojiNode(
className: string,
emojiText: string,
): EmojiNode {
return new EmojiNode(className, emojiText).setMode('token');
const node = new EmojiNode(className, emojiText).setMode('token');
return $applyNodeReplacement(node);
}
4 changes: 2 additions & 2 deletions packages/lexical-playground/src/nodes/EquationNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
Spread,
} from 'lexical';

import {DecoratorNode} from 'lexical';
import {$applyNodeReplacement, DecoratorNode} from 'lexical';
import * as React from 'react';
import {Suspense} from 'react';

Expand Down Expand Up @@ -103,7 +103,7 @@ export function $createEquationNode(
inline = false,
): EquationNode {
const equationNode = new EquationNode(equation, inline);
return equationNode;
return $applyNodeReplacement(equationNode);
}

export function $isEquationNode(
Expand Down
24 changes: 13 additions & 11 deletions packages/lexical-playground/src/nodes/ImageNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type {
Spread,
} from 'lexical';

import {createEditor, DecoratorNode} from 'lexical';
import {$applyNodeReplacement, createEditor, DecoratorNode} from 'lexical';
import * as React from 'react';
import {Suspense} from 'react';

Expand Down Expand Up @@ -233,16 +233,18 @@ export function $createImageNode({
caption,
key,
}: ImagePayload): ImageNode {
return new ImageNode(
src,
altText,
maxWidth,
width,
height,
showCaption,
caption,
captionsEnabled,
key,
return $applyNodeReplacement(
new ImageNode(
src,
altText,
maxWidth,
width,
height,
showCaption,
caption,
captionsEnabled,
key,
),
);
}

Expand Down
17 changes: 9 additions & 8 deletions packages/lexical-playground/src/nodes/MentionNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
import type {Spread} from 'lexical';

import {
DOMConversionMap,
DOMConversionOutput,
DOMExportOutput,
EditorConfig,
LexicalNode,
NodeKey,
SerializedTextNode,
type DOMConversionMap,
type DOMConversionOutput,
type DOMExportOutput,
type EditorConfig,
type LexicalNode,
type NodeKey,
type SerializedTextNode,
$applyNodeReplacement,
TextNode,
} from 'lexical';

Expand Down Expand Up @@ -114,7 +115,7 @@ export class MentionNode extends TextNode {
export function $createMentionNode(mentionName: string): MentionNode {
const mentionNode = new MentionNode(mentionName);
mentionNode.setMode('segmented').toggleDirectionless();
return mentionNode;
return $applyNodeReplacement(mentionNode);
}

export function $isMentionNode(
Expand Down
5 changes: 4 additions & 1 deletion packages/lexical-react/flow/LexicalComposer.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ type Props = {
editor__DEPRECATED?: LexicalEditor | null,
editable?: boolean,
namespace: string,
nodes?: $ReadOnlyArray<Class<LexicalNode>>,
nodes?: $ReadOnlyArray<
| Class<LexicalNode>
| {replace: Class<LexicalNode>, with: (node: LexicalNode) => LexicalNode},
>,
theme?: EditorThemeClasses,
editorState?: InitialEditorStateType,
onError: (error: Error, editor: LexicalEditor) => void,
Expand Down
11 changes: 10 additions & 1 deletion packages/lexical-react/src/LexicalComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,16 @@ type Props = {
initialConfig: Readonly<{
editor__DEPRECATED?: LexicalEditor | null;
namespace: string;
nodes?: ReadonlyArray<Klass<LexicalNode>>;
nodes?: ReadonlyArray<
| Klass<LexicalNode>
| {
replace: Klass<LexicalNode>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
with: <T extends {new (...args: any): any}>(
node: InstanceType<T>,
) => LexicalNode;
}
>;
onError: (error: Error, editor: LexicalEditor) => void;
editable?: boolean;
theme?: EditorThemeClasses;
Expand Down
3 changes: 2 additions & 1 deletion packages/lexical-react/src/LexicalHorizontalRuleNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {useLexicalNodeSelection} from '@lexical/react/useLexicalNodeSelection';
import {mergeRegister} from '@lexical/utils';
import {
$applyNodeReplacement,
$getNodeByKey,
$getSelection,
$isNodeSelection,
Expand Down Expand Up @@ -161,7 +162,7 @@ function convertHorizontalRuleElement(): DOMConversionOutput {
}

export function $createHorizontalRuleNode(): HorizontalRuleNode {
return new HorizontalRuleNode();
return $applyNodeReplacement(new HorizontalRuleNode());
}

export function $isHorizontalRuleNode(
Expand Down
2 changes: 2 additions & 0 deletions packages/lexical-react/src/LexicalNestedComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export function LexicalNestedComposer({
for (const [type, entry] of parentNodes) {
initialEditor._nodes.set(type, {
klass: entry.klass,
replace: entry.replace,
transforms: new Set(),
});
}
Expand All @@ -75,6 +76,7 @@ export function LexicalNestedComposer({
const type = klass.getType();
initialEditor._nodes.set(type, {
klass,
replace: null,
transforms: new Set(),
});
}
Expand Down
5 changes: 3 additions & 2 deletions packages/lexical-rich-text/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
mergeRegister,
} from '@lexical/utils';
import {
$applyNodeReplacement,
$createParagraphNode,
$createRangeSelection,
$getNearestNodeFromDOMNode,
Expand Down Expand Up @@ -174,7 +175,7 @@ export class QuoteNode extends ElementNode {
}

export function $createQuoteNode(): QuoteNode {
return new QuoteNode();
return $applyNodeReplacement(new QuoteNode());
}

export function $isQuoteNode(
Expand Down Expand Up @@ -347,7 +348,7 @@ function convertBlockquoteElement(): DOMConversionOutput {
}

export function $createHeadingNode(headingTag: HeadingTagType): HeadingNode {
return new HeadingNode(headingTag);
return $applyNodeReplacement(new HeadingNode(headingTag));
}

export function $isHeadingNode(
Expand Down
3 changes: 2 additions & 1 deletion packages/lexical-table/src/LexicalTableCellNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {

import {addClassNamesToElement} from '@lexical/utils';
import {
$applyNodeReplacement,
$createParagraphNode,
$isElementNode,
$isLineBreakNode,
Expand Down Expand Up @@ -251,7 +252,7 @@ export function $createTableCellNode(
colSpan = 1,
width?: number,
): TableCellNode {
return new TableCellNode(headerState, colSpan, width);
return $applyNodeReplacement(new TableCellNode(headerState, colSpan, width));
}

export function $isTableCellNode(
Expand Down
8 changes: 6 additions & 2 deletions packages/lexical-table/src/LexicalTableNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ import type {
} from 'lexical';

import {addClassNamesToElement} from '@lexical/utils';
import {$getNearestNodeFromDOMNode, DEPRECATED_GridNode} from 'lexical';
import {
$applyNodeReplacement,
$getNearestNodeFromDOMNode,
DEPRECATED_GridNode,
} from 'lexical';

import {$isTableCellNode} from './LexicalTableCellNode';
import {$isTableRowNode, TableRowNode} from './LexicalTableRowNode';
Expand Down Expand Up @@ -234,7 +238,7 @@ export function convertTableElement(_domNode: Node): DOMConversionOutput {
}

export function $createTableNode(): TableNode {
return new TableNode();
return $applyNodeReplacement(new TableNode());
}

export function $isTableNode(
Expand Down
3 changes: 2 additions & 1 deletion packages/lexical-table/src/LexicalTableRowNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {Spread} from 'lexical';

import {addClassNamesToElement} from '@lexical/utils';
import {
$applyNodeReplacement,
DEPRECATED_GridRowNode,
DOMConversionMap,
DOMConversionOutput,
Expand Down Expand Up @@ -111,7 +112,7 @@ export function convertTableRowElement(domNode: Node): DOMConversionOutput {
}

export function $createTableRowNode(height?: number): TableRowNode {
return new TableRowNode(height);
return $applyNodeReplacement(new TableRowNode(height));
}

export function $isTableRowNode(
Expand Down
9 changes: 8 additions & 1 deletion packages/lexical/flow/Lexical.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,10 @@ declare export function createEditor(editorConfig?: {
namespace: string,
theme?: EditorThemeClasses,
parentEditor?: LexicalEditor,
nodes?: $ReadOnlyArray<Class<LexicalNode>>,
nodes?: $ReadOnlyArray<
| Class<LexicalNode>
| {replace: Class<LexicalNode>, with: (node: LexicalNode) => LexicalNode},
>,
onError: (error: Error) => void,
disableEvents?: boolean,
editable?: boolean,
Expand Down Expand Up @@ -849,6 +852,10 @@ declare export function $parseSerializedNode(
serializedNode: InternalSerializedNode,
): LexicalNode;

declare export function $applyNodeReplacement<N: LexicalNode>(
node: LexicalNode,
): N;

export type SerializedLexicalNode = {
type: string,
version: number,
Expand Down
Loading

2 comments on commit 102b01d

@vercel
Copy link

@vercel vercel bot commented on 102b01d Nov 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

lexical – ./packages/lexical-website

lexical-git-main-fbopensource.vercel.app
lexical-fbopensource.vercel.app
lexical.dev
lexicaljs.com
www.lexical.dev
lexicaljs.org

@vercel
Copy link

@vercel vercel bot commented on 102b01d Nov 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

lexical-playground – ./packages/lexical-playground

lexical-playground.vercel.app
lexical-playground-fbopensource.vercel.app
lexical-playground-git-main-fbopensource.vercel.app
playground.lexical.dev

Please sign in to comment.