Created
March 25, 2025 12:08
-
-
Save davidnus/04da9d3dc693fd64c8b62944ef1b3d1f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { TextNode } from 'lexical'; | |
| /*** | |
| * Example of custom warning node. | |
| * This node adds the additional properties for rendering on top of | |
| * a basic Lexical TextNode. | |
| */ | |
| export class WarningNode extends TextNode { | |
| /** | |
| * Assume you want to add the following attributes to an extended node | |
| */ | |
| __id; //some custom id that's immutable | |
| __color; //color attribute that holds a string, and is mutable | |
| __backgroundColor; //background color attribute that holds a string, and is mutable | |
| /* | |
| * Override TextNode getType | |
| */ | |
| static getType() { | |
| return 'warning'; //give your node a custom type | |
| } | |
| /* | |
| * Override TextNode clone | |
| */ | |
| static clone(node) { | |
| return new WarningNode(node.__id, node.__color, node.__backgroundColor, node.__text, node.__key); | |
| } | |
| /* | |
| * Override TextNode importJSON | |
| */ | |
| static importJSON(serializedNode) { | |
| /** | |
| * this is a common recipe to import a custom json text-like node in lexical: | |
| */ | |
| const node = $createWarningNode(serializedNode.id, serializedNode.color, serializedNode.backgroundColor); | |
| node.setTextContent(serializedNode.text); | |
| node.setFormat(serializedNode.format); | |
| node.setDetail(serializedNode.detail); | |
| node.setMode(serializedNode.mode); | |
| node.setStyle(serializedNode.style); | |
| return node; | |
| } | |
| /* | |
| * Override TextNode constructor | |
| */ | |
| constructor(id, color, backgroundColor, text, key) { | |
| // invoke parent constructor | |
| super(text, key); | |
| // extension: set custom attributes, with default values | |
| this.__id = id || 'mock_id'; | |
| this.__color = color || '#ffffff'; | |
| this.__backgroundColor = backgroundColor || '#ff4902'; | |
| } | |
| /* | |
| * Override TextNode exportJSON | |
| */ | |
| exportJSON() { | |
| return { | |
| // invoke parent text node export | |
| ...super.exportJSON(), | |
| version: 1, | |
| /** | |
| * extension: attach custom properties to the exported node | |
| */ | |
| id: this.__id, | |
| color: this.__color, | |
| backgroundColor: this.__backgroundColor, | |
| type: 'warning', | |
| }; | |
| } | |
| /* | |
| * Override TextNode createDOM | |
| */ | |
| createDOM(config) { | |
| //Invoke parent createDOM | |
| const dom = super.createDOM(config); | |
| /** | |
| * extension: Compose custom css styles string from custom attributes | |
| */ | |
| dom.style.cssText = `color:${this.__color};background-color:${this.__backgroundColor};`; | |
| dom.className = 'warning-text-frame'; | |
| return dom; | |
| } | |
| updateDOM() { | |
| return true; | |
| } | |
| //optional: getters and setters | |
| getColor() { | |
| return this.__color; | |
| } | |
| setColor(color) { | |
| const writable = this.getWritable(); | |
| writable.__color = color; | |
| } | |
| getBackgroundColor() { | |
| return this.__backgroundColor; | |
| } | |
| setBackgroundColor(backgroundColor) { | |
| const writable = this.getWritable(); | |
| writable.__backgroundColor = backgroundColor; | |
| } | |
| /** | |
| * Implement the following API methods to interoperate with Codox | |
| * Lexical -> Codox Node | |
| * Converts lexical node to json node, acceptable by Codox. | |
| */ | |
| toCodoxNode() { | |
| /** | |
| * Step 1: Get original text node json. You should/must use .exportJSON() | |
| */ | |
| const originalJsonNode = this.exportJSON(); | |
| /** | |
| * Step 2: Extend with additional properties. | |
| */ | |
| const convertedNode = { | |
| type: 'text', // type property must be one of core or playground node types | |
| // preserve default text node attributes | |
| text: originalJsonNode.text, | |
| format: originalJsonNode.format, | |
| mode: originalJsonNode.mode, | |
| detail: originalJsonNode.detail, | |
| version: originalJsonNode.version, | |
| // extension: all mutable style properties should be serialized as a style string, as per TextNode definition | |
| // assumption is the lexical node style is empty, if not, concat the styles. | |
| style: `color:${originalJsonNode.color};background-color:${originalJsonNode.backgroundColor};`, | |
| /** | |
| * extension: codox_metadata should hold immutables: | |
| * - required: your extended node type, e.g. 'warning' | |
| * - optional: any immutable properties of an original node - these fields are not merged and synchronized. | |
| */ | |
| codox_metadata: { | |
| type: originalJsonNode.type, //type == 'warning' | |
| id: originalJsonNode.id, //some custom id an immutable property | |
| }, | |
| }; | |
| console.log('[DEMO DEBUG][WarningNode][toCodoxNode]: ', { convertedNode, originalJsonNode }); | |
| return convertedNode; | |
| } | |
| /** | |
| * Implement the following API methods to interoperate with Codox | |
| * Codox -> Lexical Node | |
| * Converts synchronized codox json node to lexical json node | |
| * must be class 'static' method | |
| */ | |
| static fromCodoxNode(codoxNode) { | |
| /** | |
| * extension: all mutable properties should be deserialized from the style string, | |
| */ | |
| let color = ''; | |
| let backgroundColor = ''; | |
| codoxNode.style.split(';').forEach((css) => { | |
| if (css.startsWith('color:')) { | |
| color = css.split(':')[1]; | |
| } | |
| if (css.startsWith('background-color:')) { | |
| backgroundColor = css.split(':')[1]; | |
| } | |
| }); | |
| // compose original json node from codox node | |
| const originalJsonNode = { | |
| // set original type - in this example it will be "warning" | |
| type: codoxNode.codox_metadata.type, | |
| // set base attributes | |
| text: codoxNode.text, | |
| format: codoxNode.format, | |
| mode: codoxNode.mode, | |
| detail: codoxNode.detail, | |
| version: codoxNode.version, | |
| style: '', // assumption here is the lexical node style is empty, if not, splice out the extended mutable properties | |
| /** | |
| * set custom attributes | |
| */ | |
| id: codoxNode.codox_metadata.id, | |
| color: color, | |
| backgroundColor: backgroundColor, | |
| }; | |
| console.log('[DEMO DEBUG][WarningNode][fromCodoxNode]: ', { codoxNode, originalJsonNode }); | |
| return originalJsonNode; | |
| } | |
| } | |
| // optional: best practice | |
| export function $createWarningNode(id, color, backgroundColor, text, key) { | |
| const warntextNode = new WarningNode(id, color, backgroundColor, text, key); | |
| return warntextNode; | |
| } | |
| export function $isWarningNode(node) { | |
| return node instanceof WarningNode; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment