diff --git a/packages/lexical/src/nodes/LexicalTextNode.ts b/packages/lexical/src/nodes/LexicalTextNode.ts index b66dbd55014..dc998703eca 100644 --- a/packages/lexical/src/nodes/LexicalTextNode.ts +++ b/packages/lexical/src/nodes/LexicalTextNode.ts @@ -1092,45 +1092,9 @@ function convertSpanElement(domNode: Node): DOMConversionOutput { // domNode is a since we matched it by nodeName const span = domNode as HTMLSpanElement; const style = span.style; - const fontWeight = style.fontWeight; - const textDecoration = style.textDecoration.split(' '); - // Google Docs uses span tags + font-weight for bold text - const hasBoldFontWeight = fontWeight === '700' || fontWeight === 'bold'; - // Google Docs uses span tags + text-decoration: line-through for strikethrough text - const hasLinethroughTextDecoration = textDecoration.includes('line-through'); - // Google Docs uses span tags + font-style for italic text - const hasItalicFontStyle = style.fontStyle === 'italic'; - // Google Docs uses span tags + text-decoration: underline for underline text - const hasUnderlineTextDecoration = textDecoration.includes('underline'); - // Google Docs uses span tags + vertical-align to specify subscript and superscript - const verticalAlign = style.verticalAlign; return { - forChild: (lexicalNode) => { - if (!$isTextNode(lexicalNode)) { - return lexicalNode; - } - if (hasBoldFontWeight) { - lexicalNode.toggleFormat('bold'); - } - if (hasLinethroughTextDecoration) { - lexicalNode.toggleFormat('strikethrough'); - } - if (hasItalicFontStyle) { - lexicalNode.toggleFormat('italic'); - } - if (hasUnderlineTextDecoration) { - lexicalNode.toggleFormat('underline'); - } - if (verticalAlign === 'sub') { - lexicalNode.toggleFormat('subscript'); - } - if (verticalAlign === 'super') { - lexicalNode.toggleFormat('superscript'); - } - - return lexicalNode; - }, + forChild: applyTextFormatFromStyle(style), node: null, }; } @@ -1140,14 +1104,12 @@ function convertBringAttentionToElement(domNode: Node): DOMConversionOutput { const b = domNode as HTMLElement; // Google Docs wraps all copied HTML in a with font-weight normal const hasNormalFontWeight = b.style.fontWeight === 'normal'; - return { - forChild: (lexicalNode) => { - if ($isTextNode(lexicalNode) && !hasNormalFontWeight) { - lexicalNode.toggleFormat('bold'); - } - return lexicalNode; - }, + return { + forChild: applyTextFormatFromStyle( + b.style, + hasNormalFontWeight ? undefined : 'bold', + ), node: null, }; } @@ -1298,30 +1260,13 @@ function findTextInLine(text: Text, forward: boolean): null | Text { } } -const nodeNameToTextFormat: Record = { - code: 'code', - em: 'italic', - i: 'italic', - s: 'strikethrough', - strong: 'bold', - sub: 'subscript', - sup: 'superscript', - u: 'underline', -}; - function convertTextFormatElement(domNode: Node): DOMConversionOutput { const format = nodeNameToTextFormat[domNode.nodeName.toLowerCase()]; if (format === undefined) { return {node: null}; } return { - forChild: (lexicalNode) => { - if ($isTextNode(lexicalNode) && !lexicalNode.hasFormat(format)) { - lexicalNode.toggleFormat(format); - } - - return lexicalNode; - }, + forChild: applyTextFormatFromStyle((domNode as HTMLElement).style, format), node: null, }; } @@ -1335,3 +1280,62 @@ export function $isTextNode( ): node is TextNode { return node instanceof TextNode; } + +const nodeNameToTextFormat: Record = { + code: 'code', + em: 'italic', + i: 'italic', + s: 'strikethrough', + strong: 'bold', + sub: 'subscript', + sup: 'superscript', + u: 'underline', +}; + +function applyTextFormatFromStyle( + style: CSSStyleDeclaration, + shouldApply?: TextFormatType, +) { + const fontWeight = style.fontWeight; + const textDecoration = style.textDecoration.split(' '); + // Google Docs uses span tags + font-weight for bold text + const hasBoldFontWeight = fontWeight === '700' || fontWeight === 'bold'; + // Google Docs uses span tags + text-decoration: line-through for strikethrough text + const hasLinethroughTextDecoration = textDecoration.includes('line-through'); + // Google Docs uses span tags + font-style for italic text + const hasItalicFontStyle = style.fontStyle === 'italic'; + // Google Docs uses span tags + text-decoration: underline for underline text + const hasUnderlineTextDecoration = textDecoration.includes('underline'); + // Google Docs uses span tags + vertical-align to specify subscript and superscript + const verticalAlign = style.verticalAlign; + + return (lexicalNode: LexicalNode) => { + if (!$isTextNode(lexicalNode)) { + return lexicalNode; + } + if (hasBoldFontWeight) { + lexicalNode.toggleFormat('bold'); + } + if (hasLinethroughTextDecoration) { + lexicalNode.toggleFormat('strikethrough'); + } + if (hasItalicFontStyle) { + lexicalNode.toggleFormat('italic'); + } + if (hasUnderlineTextDecoration) { + lexicalNode.toggleFormat('underline'); + } + if (verticalAlign === 'sub') { + lexicalNode.toggleFormat('subscript'); + } + if (verticalAlign === 'super') { + lexicalNode.toggleFormat('superscript'); + } + + if (shouldApply && !lexicalNode.hasFormat(shouldApply)) { + lexicalNode.toggleFormat(shouldApply); + } + + return lexicalNode; + }; +}