From ba2f11daddaef613b003464a52bb2dc091a6974b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:40:28 -0300 Subject: [PATCH] revert unused changes --- .../__tests__/unit/LexicalHistory.test.tsx | 27 +++--- .../unit/LexicalSelectionHelpers.test.ts | 82 ------------------- .../docs/concepts/node-replacement.md | 38 +-------- packages/lexical/src/LexicalEditorState.ts | 3 - packages/lexical/src/LexicalNode.ts | 60 -------------- packages/lexical/src/LexicalNormalization.ts | 8 +- packages/lexical/src/LexicalReconciler.ts | 19 +---- packages/lexical/src/LexicalUpdates.ts | 10 +-- packages/lexical/src/nodes/LexicalTextNode.ts | 3 - 9 files changed, 17 insertions(+), 233 deletions(-) diff --git a/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx b/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx index 902c6d24bd1..0cef7f59210 100644 --- a/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx +++ b/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx @@ -44,52 +44,49 @@ import {createRoot, Root} from 'react-dom/client'; import * as ReactTestUtils from 'shared/react-test-utils'; type SerializedCustomTextNode = Spread< - {type: ReturnType; classList: string[]}, + {type: ReturnType; classes: string[]}, SerializedTextNode >; class CustomTextNode extends TextNode { ['constructor']!: KlassConstructor; - __classlist: Set; + __classes: Set; constructor(text: string, classes: Iterable, key?: NodeKey) { super(text, key); - this.__classlist = new Set(classes); + this.__classes = new Set(classes); } static getType(): 'custom-text' { return 'custom-text'; } static clone(node: CustomTextNode): CustomTextNode { - return new CustomTextNode(node.__text, node.__classlist, node.__key); + return new CustomTextNode(node.__text, node.__classes, node.__key); } addClass(className: string): this { const self = this.getWritable(); - self.__classlist.add(className); + self.__classes.add(className); return self; } removeClass(className: string): this { const self = this.getWritable(); - self.__classlist.delete(className); + self.__classes.delete(className); return self; } setClasses(classes: Iterable): this { const self = this.getWritable(); - self.__classlist = new Set(classes); + self.__classes = new Set(classes); return self; } - getClassList(): ReadonlySet { - return this.getLatest().__classlist; + getClasses(): ReadonlySet { + return this.getLatest().__classes; } - static importJSON({ - text, - classList, - }: SerializedCustomTextNode): CustomTextNode { - return $createCustomTextNode(text, classList); + static importJSON({text, classes}: SerializedCustomTextNode): CustomTextNode { + return $createCustomTextNode(text, classes); } exportJSON(): SerializedCustomTextNode { return { ...super.exportJSON(), - classList: Array.from(this.getClassList()), + classes: Array.from(this.getClasses()), type: this.constructor.getType(), }; } diff --git a/packages/lexical-selection/src/__tests__/unit/LexicalSelectionHelpers.test.ts b/packages/lexical-selection/src/__tests__/unit/LexicalSelectionHelpers.test.ts index 386984258a9..01390ed7180 100644 --- a/packages/lexical-selection/src/__tests__/unit/LexicalSelectionHelpers.test.ts +++ b/packages/lexical-selection/src/__tests__/unit/LexicalSelectionHelpers.test.ts @@ -43,7 +43,6 @@ import { TestDecoratorNode, } from 'lexical/src/__tests__/utils'; -import {$forEachSelectedTextNode} from '../../lexical-node'; import {$setAnchorPoint, $setFocusPoint} from '../utils'; Range.prototype.getBoundingClientRect = function (): DOMRect { @@ -3172,84 +3171,3 @@ describe('$patchStyleText', () => { }); }); }); - -describe('classes property', () => { - test('can mutate classes using $forEachSelectedTextNode', async () => { - const editor = createTestEditor(); - const element = document.createElement('div'); - editor.setRootElement(element); - - await editor.update(() => { - const root = $getRoot(); - const paragraph = $createParagraphNode(); - root.append(paragraph); - const text = $createTextNode('first').setFormat('bold'); - paragraph.append(text); - - const textSecond = $createTextNode('second'); - paragraph.append(textSecond); - - $setAnchorPoint({ - key: text.getKey(), - offset: 'fir'.length, - type: 'text', - }); - - $setFocusPoint({ - key: textSecond.getKey(), - offset: 'sec'.length, - type: 'text', - }); - - $forEachSelectedTextNode((textNode) => { - textNode.setClass('bg', 'red'); - textNode.setClass('active', true); - textNode.setClass('highlight', 'yellow'); - textNode.setClass('disabled', false); - }); - }); - - expect(element.innerHTML).toBe( - '

' + - 'fir' + - 'st' + - 'sec' + - 'ond' + - '

', - ); - }); - test('exportJSON', async () => { - const editor = createTestEditor(); - const element = document.createElement('div'); - editor.setRootElement(element); - const getSerializedParagraph = (_editor: LexicalEditor) => { - return _editor.getEditorState().toJSON().root.children[0]; - }; - let p: ParagraphNode; - - await editor.update(() => { - p = $createParagraphNode(); - $getRoot().append(p); - }); - expect('classes' in getSerializedParagraph(editor)).toBe(false); - - // should ignore false, numbers or undefined - await editor.update(() => { - p.setClass('bg', 'red'); - p.setClass('active', true); - p.setClass('highlight', false); - }); - expect('classes' in getSerializedParagraph(editor)).toBe(true); - expect(getSerializedParagraph(editor).classes).toStrictEqual({ - active: true, - bg: 'red', - }); - - // should not export classes if empty - await editor.update(() => { - p.setClass('bg', false); - p.setClass('active', false); - }); - expect('classes' in getSerializedParagraph(editor)).toBe(false); - }); -}); diff --git a/packages/lexical-website/docs/concepts/node-replacement.md b/packages/lexical-website/docs/concepts/node-replacement.md index d157524d451..1aafbc50595 100644 --- a/packages/lexical-website/docs/concepts/node-replacement.md +++ b/packages/lexical-website/docs/concepts/node-replacement.md @@ -1,46 +1,12 @@ -# Node Customization -Originally the only way to customize nodes was using the node replacement API. Recently we have introduced a second way with the `classes` property which is easier to implement and is sufficient for most cases. - -## Classes Property (New) - -Most of the time when users want to customize a node they just want to add a property to it, which ends up being reflected as a class in the dom element. - -To satisfy that need we have introduced two new methods to all nodes: `getClasses` and `setClass`. - -```ts -export function CoolRedPlugin() { - const [editor] = useLexicalComposerContext(); - - return ( - - ); -} -``` - -## Node Overrides / Node Replacements +# Node Overrides / Node Replacements Some of the most commonly used Lexical Nodes are owned and maintained by the core library. For example, ParagraphNode, HeadingNode, QuoteNode, List(Item)Node etc - these are all provided by Lexical packages, which provides an easier out-of-the-box experience for some editor features, but makes it difficult to override their behavior. For instance, if you wanted to change the behavior of ListNode, you would typically extend the class and override the methods. However, how would you tell Lexical to use *your* ListNode subclass in the ListPlugin instead of using the core ListNode? That's where Node Overrides can help. Node Overrides allow you to replace all instances of a given node in your editor with instances of a different node class. This can be done through the nodes array in the Editor config: -```ts +``` const editorConfig = { ... nodes=[ diff --git a/packages/lexical/src/LexicalEditorState.ts b/packages/lexical/src/LexicalEditorState.ts index f31144fb978..aa14f45d87b 100644 --- a/packages/lexical/src/LexicalEditorState.ts +++ b/packages/lexical/src/LexicalEditorState.ts @@ -57,9 +57,6 @@ function exportNodeToJSON( node: LexicalNode, ): SerializedNode { const serializedNode = node.exportJSON(); - if (node.__classes && Object.keys(node.__classes).length > 0) { - serializedNode.classes = node.__classes; - } const nodeClass = node.constructor; if (serializedNode.type !== nodeClass.getType()) { diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index 67ee2b77b2d..0aa1d1ca487 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -54,7 +54,6 @@ export type NodeMap = Map; export type SerializedLexicalNode = { type: string; version: number; - classes?: ReadonlyClasses; }; /** @internal */ @@ -171,8 +170,6 @@ export type DOMExportOutput = { }; export type NodeKey = string; -export type MutableClasses = {[classSuffix: string]: true | string}; -export type ReadonlyClasses = {readonly [classSuffix: string]: true | string}; export class LexicalNode { // Allow us to look up the type including static props @@ -188,53 +185,6 @@ export class LexicalNode { __prev: null | NodeKey; /** @internal */ __next: null | NodeKey; - /** - * Don't use this directly, use `this.getClasses()` and `this.mutateClasses()` instead - * @internal - */ - __classes?: ReadonlyClasses; - - /** - * Returns an object of classes in the form of `prefix-suffix` for string values, or just `prefix` for true boolean values. - * @example - * const exampleClassesObject = { - * bg: 'red', // the node is rendered with class `bg-red` - * text: 'green', // node is rendered with class `text-green`, - * active: true, // node is rendered with class `active`, - * } - * // Resulting classes: 'bg-red', 'text-green', and 'active' - * - * @returns The classes object. - */ - getClasses() { - const self = this.getLatest(); - return self.__classes; - } - - /** - * Sets a class based on the provided key and value. - * - * @param key - The class key to set or modify. - * @param value - The class value. Possible options: - * - `true`: add the class if it doesn't exist. - * - `false`: remove the class if it exists. - * - `string`: Adds a class in the format `key-value` (e.g., `bg-blue`), useful for overwriting existing classes with the same key. - * - * @example - * node.setClass('active', true); // Adds the class `active`, replacing the one with the key `active` if it exists. - * node.setClass('active', false); // Removes any class with the key `active` (e.g., `active` or `active-blue`). - * node.setClass('bg', 'blue'); // Adds the class `bg-blue` - */ - setClass(key: string, value: boolean | string) { - const self = this.getWritable(); - const classes = {...self.__classes}; - if (value === false) { - delete classes[key]; - } else { - classes[key] = value; - } - self.__classes = classes; - } // Flow doesn't support abstract classes unfortunately, so we can't _force_ // subclasses of Node to implement statics. All subclasses of Node should have @@ -323,7 +273,6 @@ export class LexicalNode { this.__parent = prevNode.__parent; this.__next = prevNode.__next; this.__prev = prevNode.__prev; - this.__classes = prevNode.__classes; } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -909,15 +858,6 @@ export class LexicalNode { * */ exportDOM(editor: LexicalEditor): DOMExportOutput { const element = this.createDOM(editor._config, editor); - if (this.__classes) { - Object.entries(this.__classes).forEach(([classPrefix, classSufix]) => { - if (typeof classSufix === 'string') { - element.classList.add(`${classPrefix}-${classSufix}`); - } else if (typeof classSufix === 'boolean' && classSufix) { - element.classList.add(classPrefix); - } - }); - } return {element}; } diff --git a/packages/lexical/src/LexicalNormalization.ts b/packages/lexical/src/LexicalNormalization.ts index 957870d9501..59a7be64489 100644 --- a/packages/lexical/src/LexicalNormalization.ts +++ b/packages/lexical/src/LexicalNormalization.ts @@ -22,16 +22,10 @@ function $canSimpleTextNodesBeMerged( const node2Mode = node2.__mode; const node2Format = node2.__format; const node2Style = node2.__style; - const node1Classes = node1.__classes || {}; - const node2Classes = node2.__classes || {}; return ( (node1Mode === null || node1Mode === node2Mode) && (node1Format === null || node1Format === node2Format) && - (node1Style === null || node1Style === node2Style) && - Object.keys(node1Classes).length === Object.keys(node2Classes).length && - Object.keys(node1Classes).every( - (key) => node1Classes[key] === node2Classes[key], - ) + (node1Style === null || node1Style === node2Style) ); } diff --git a/packages/lexical/src/LexicalReconciler.ts b/packages/lexical/src/LexicalReconciler.ts index 216db70ea48..6fa946f61d6 100644 --- a/packages/lexical/src/LexicalReconciler.ts +++ b/packages/lexical/src/LexicalReconciler.ts @@ -173,15 +173,6 @@ function $createNode(key: NodeKey, slot: ElementDOMSlot | null): HTMLElement { invariant(false, 'createNode: node does not exist in nodeMap'); } const dom = node.createDOM(activeEditorConfig, activeEditor); - if (node.__classes) { - Object.entries(node.__classes).forEach(([classPrefix, classSufix]) => { - if (typeof classSufix === 'string') { - dom.classList.add(`${classPrefix}-${classSufix}`); - } else if (typeof classSufix === 'boolean' && classSufix) { - dom.classList.add(classPrefix); - } - }); - } storeDOMWithKey(key, dom, activeEditor); // This helps preserve the text, and stops spell check tools from @@ -641,16 +632,8 @@ function $reconcileNode( ); } - const nextClasses = nextNode.__classes || {}; - const prevClasses = prevNode.__classes || {}; - const classesChanged = !( - Object.keys(nextClasses).length === Object.keys(prevClasses).length && - Object.keys(nextClasses).every( - (_key) => nextClasses[_key] === prevClasses[_key], - ) - ); // Update node. If it returns true, we need to unmount and re-create the node - if (nextNode.updateDOM(prevNode, dom, activeEditorConfig) || classesChanged) { + if (nextNode.updateDOM(prevNode, dom, activeEditorConfig)) { const replacementDOM = $createNode(key, null); if (parentDOM === null) { diff --git a/packages/lexical/src/LexicalUpdates.ts b/packages/lexical/src/LexicalUpdates.ts index 64a49e470b4..11296a2be5a 100644 --- a/packages/lexical/src/LexicalUpdates.ts +++ b/packages/lexical/src/LexicalUpdates.ts @@ -7,11 +7,7 @@ */ import type {SerializedEditorState} from './LexicalEditorState'; -import type { - LexicalNode, - ReadonlyClasses, - SerializedLexicalNode, -} from './LexicalNode'; +import type {LexicalNode, SerializedLexicalNode} from './LexicalNode'; import invariant from 'shared/invariant'; @@ -342,7 +338,6 @@ type InternalSerializedNode = { children?: Array; type: string; version: number; - classes?: ReadonlyClasses; }; export function $parseSerializedNode( @@ -379,9 +374,6 @@ function $parseSerializedNodeImpl< } const node = nodeClass.importJSON(serializedNode); - if (serializedNode.classes) { - node.__classes = serializedNode.classes; - } const children = serializedNode.children; if ($isElementNode(node) && Array.isArray(children)) { diff --git a/packages/lexical/src/nodes/LexicalTextNode.ts b/packages/lexical/src/nodes/LexicalTextNode.ts index a9f4c618b78..fad639a1c72 100644 --- a/packages/lexical/src/nodes/LexicalTextNode.ts +++ b/packages/lexical/src/nodes/LexicalTextNode.ts @@ -947,7 +947,6 @@ export class TextNode extends LexicalNode { let writableNode; const format = self.getFormat(); const style = self.getStyle(); - const classes = self.getClasses(); const detail = self.__detail; let hasReplacedSelf = false; @@ -956,7 +955,6 @@ export class TextNode extends LexicalNode { writableNode = $createTextNode(firstPart); writableNode.__format = format; writableNode.__style = style; - writableNode.__classes = classes; writableNode.__detail = detail; hasReplacedSelf = true; } else { @@ -978,7 +976,6 @@ export class TextNode extends LexicalNode { const sibling = $createTextNode(part).getWritable(); sibling.__format = format; sibling.__style = style; - sibling.__classes = classes; sibling.__detail = detail; const siblingKey = sibling.__key; const nextTextSize = textSize + partSize;