diff --git a/packages/picasso/src/LexicalEditor/LexicalEditor.tsx b/packages/picasso/src/LexicalEditor/LexicalEditor.tsx index 53ef662a7a..6b95eb5dba 100644 --- a/packages/picasso/src/LexicalEditor/LexicalEditor.tsx +++ b/packages/picasso/src/LexicalEditor/LexicalEditor.tsx @@ -14,6 +14,7 @@ import { ListItemNode, ListNode } from '@lexical/list' import { $isRootTextContentEmpty } from '@lexical/text' import type { LexicalEditor as LexicalEditorType } from 'lexical' import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin' +import { TextNode } from 'lexical' import { TriggerInitialOnChangePlugin } from './plugins' import { createLexicalTheme, setEditorValue } from './utils' @@ -28,13 +29,42 @@ import LexicalTextLengthPlugin from '../LexicalTextLengthPlugin' import LexicalListPlugin from '../LexicalListPlugin' import LexicalHeadingsReplacementPlugin from '../LexicalHeadingsReplacementPlugin' import type { ASTType } from '../RichText' +import { PicassoTextNode } from './nodes' const useStyles = makeStyles(styles, { name: 'LexicalEditor', }) const removeAttributesFromString = (htmlString: string) => { - return htmlString.replace(/\s(class|dir|value)="[^"]*"/g, '') + return htmlString.replace(/\s(class|dir|value|style)="[^"]*"/g, '') +} + +// Courtesy of ChatGPT +const removeTagsAndKeepContent = (html: string, tagsToRemove: string[]) => { + const parser = new DOMParser() + const htmlDoc = parser.parseFromString(html, 'text/html') + + tagsToRemove.forEach(function (tag) { + const elements = htmlDoc.getElementsByTagName(tag) + + for (let counter = elements.length - 1; counter >= 0; counter--) { + const parent = elements[counter].parentNode + + if (parent) { + while (elements[counter].firstChild) { + if (elements[counter].firstChild) { + parent.insertBefore( + elements[counter].firstChild as Node, + elements[counter] + ) + } + } + parent.removeChild(elements[counter]) + } + } + }) + + return htmlDoc.body.innerHTML } export type Props = BaseProps & { @@ -143,7 +173,20 @@ const LexicalEditor = forwardRef(function LexicalEditor( throw error }, namespace: 'editor', - nodes: [ListNode, ListItemNode, HeadingNode], + nodes: [ + ListNode, + ListItemNode, + HeadingNode, + PicassoTextNode, + // { + // replace: TextNode, + // with: (node: TextNode) => { + // console.log('@@@ create new PicassoTextNode') + + // return new PicassoTextNode(node.getTextContent(), node.getKey()) + // }, + // }, + ], editable: !disabled, }), [defaultValue, theme, disabled] @@ -158,6 +201,12 @@ const LexicalEditor = forwardRef(function LexicalEditor( ? '' : removeAttributesFromString($generateHtmlFromNodes(editor, null)) + // const cleanedHtmlValue = removeTagsAndKeepContent(htmlValue, [ + // 'b', + // 'i', + // 'span', + // ]) + onChange(htmlValue) }) }, diff --git a/packages/picasso/src/LexicalEditor/nodes/PicassoTextNode.ts b/packages/picasso/src/LexicalEditor/nodes/PicassoTextNode.ts new file mode 100644 index 0000000000..dd5bf5e325 --- /dev/null +++ b/packages/picasso/src/LexicalEditor/nodes/PicassoTextNode.ts @@ -0,0 +1,39 @@ +import type { + DOMExportOutput, + LexicalEditor, + NodeKey, + SerializedTextNode, +} from 'lexical' +import { TextNode } from 'lexical' + +export class PicassoTextNode extends TextNode { + constructor(text: string, key?: NodeKey) { + super(text, key) + } + + static getType(): string { + return 'picasso-text' + } + + static clone(node: PicassoTextNode): PicassoTextNode { + console.log('@@@ clone') + + return super.clone(node) + } + + exportDOM(editor: LexicalEditor): DOMExportOutput { + const { element } = super.exportDOM(editor) + + console.log('@@@ element', element, this.getFormat()) + + return { element } + } + + static importJSON(serializedNode: SerializedTextNode): PicassoTextNode { + return super.importJSON(serializedNode) + } + + exportJSON(): SerializedTextNode { + return super.exportJSON() + } +} diff --git a/packages/picasso/src/LexicalEditor/nodes/index.ts b/packages/picasso/src/LexicalEditor/nodes/index.ts new file mode 100644 index 0000000000..a56f826ae5 --- /dev/null +++ b/packages/picasso/src/LexicalEditor/nodes/index.ts @@ -0,0 +1 @@ +export { PicassoTextNode } from './PicassoTextNode' diff --git a/packages/picasso/src/LexicalHeadingsReplacementPlugin/LexicalHeadingsReplacementPlugin.ts b/packages/picasso/src/LexicalHeadingsReplacementPlugin/LexicalHeadingsReplacementPlugin.ts index c9bb5129ef..f099cf401a 100644 --- a/packages/picasso/src/LexicalHeadingsReplacementPlugin/LexicalHeadingsReplacementPlugin.ts +++ b/packages/picasso/src/LexicalHeadingsReplacementPlugin/LexicalHeadingsReplacementPlugin.ts @@ -3,6 +3,8 @@ import { HeadingNode } from '@lexical/rich-text' import { useEffect } from 'react' import { replaceHeadingNodes } from './utils' +import { TextNode } from 'lexical' +import { PicassoTextNode } from '../LexicalEditor/nodes' const LexicalHeadingsReplacementPlugin = () => { const [editor] = useLexicalComposerContext() @@ -11,6 +13,14 @@ const LexicalHeadingsReplacementPlugin = () => { return editor.registerNodeTransform(HeadingNode, replaceHeadingNodes) }, [editor]) + // useEffect(() => { + // return editor.registerNodeTransform(TextNode, (node: TextNode) => { + // console.log('@@@ replacing') + // const newNode = PicassoTextNode.clone(node) + // node.replace(newNode) + // }) + // }, [editor]) + return null }