diff --git a/app/src/components/composer-editor/conversion.tsx b/app/src/components/composer-editor/conversion.tsx index 026240376..b685a5352 100644 --- a/app/src/components/composer-editor/conversion.tsx +++ b/app/src/components/composer-editor/conversion.tsx @@ -187,7 +187,7 @@ const TEXT_RULE_IMPROVED: Rule = { if (obj.object === 'string') { return children.split('\n').reduce((array, text, i) => { if (i !== 0) array.push(
); - // BEGIN CHANGE + // BEGIN CHANGES // Replace "a b c" with "a   b c" (to match Gmail's behavior exactly.) // In a long run of spaces, all but the last space are converted to  . @@ -200,7 +200,20 @@ const TEXT_RULE_IMPROVED: Rule = { // considered HTML whitespace. text = text.replace(/^ /, '\u00A0'); - // END CHANGE + // \r handling: CRLF delimited text pasted into the editor (on Windows) is not processed + // properly by Slate. It splits on \n leaving the preceding \r lying around. When the + // serializer encounters text nodes containing just a `\r`, it doesn't flip them to + //
tags because they're not empty, but the character is HTML whitespace and + // renders with zero height causing blank newlines to disappear. + + // If the only character is a \r, replace it with an nbsp. + if (text === '\r') text = '\u00A0'; + + // If the text contains a trailing \r, remove it. This stray char shouldn't matter but + // also shouldn't be in the HTML string. + text = text.replace(/\r$/, ''); + + // END CHANGES array.push(text); return array; }, []);