facebook / lexical

Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance.
https://lexical.dev
MIT License
17.5k stars 1.45k forks source link

[lexical-html] Feature: Support copy pasting block and inline nodes properly #5857

Closed potatowagon closed 2 weeks ago

potatowagon commented 1 month ago

Description

Closes #4465 #5812

hasBlockAncestorElement means if a node has an ancestor element somewhere up the tree between itself and the root (or shadow root).

Paragraphs being block elements should not be nested in another block element, and the semantically right way to do so is to insert line breaks.

If hasBlockAncestorElement, wrap continuous child nodes in an Artificial Node, else, wrap continuous child nodes in paragraph node.

The implementation for wrapping continuous child nodes is reused from #5834

Afterwards insert line breaks (<br>) in between all Artificial nodes

[A,A] => [A <br> A] 

and unwrap the contents of the Artificial nodes, by replacing the Artificial node with its children at the parent node.

[A <br> A] => [123 <br> 456] 

This would hopefully insert paragraphs and line breaks correctly.

Big thanks to @zurfyx brainstorming this approach!

Test Plan

Case: nested divs

<div>
  a
  <div>
    b
    <div>
      c
      <div>
        <div>
        </div>
        z
      </div>
    </div>
    d
    e
  </div>
  fg
</div>
Screenshot 2024-04-09 at 10 20 22 PM

Before

Screenshot 2024-04-09 at 10 20 35 PM

After

Screenshot 2024-04-09 at 10 20 45 PM

Case: nested divs in list

<ol>
  <li>
    1
    <div>
      2
    </div>
    3
  </li>
  <li>
    A
    <div>
      B
    </div>
    3
  </li>
</ol>
Screenshot 2024-04-09 at 10 16 33 PM

Before

Screenshot 2024-04-09 at 10 16 20 PM

After

Screenshot 2024-04-09 at 10 19 35 PM
vercel[bot] commented 1 month ago

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
lexical ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 29, 2024 4:20pm
lexical-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 29, 2024 4:20pm
github-actions[bot] commented 1 month ago

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
packages/lexical/dist/Lexical.js 23.7 KB (+0.08% 🔺) 475 ms (+0.08% 🔺) 313 ms (-26.15% 🔽) 787 ms
packages/lexical-rich-text/dist/LexicalRichText.js 34.22 KB (+0.9% 🔺) 685 ms (+0.9% 🔺) 1.1 s (+2.86% 🔺) 1.8 s
packages/lexical-plain-text/dist/LexicalPlainText.js 34.26 KB (+1.04% 🔺) 686 ms (+1.04% 🔺) 1.2 s (+17.33% 🔺) 1.9 s
potatowagon commented 1 month ago

Case: nested spans and nested divs

<div>
  a b
  <span>
    c d
    <span>
      e
    </span>
  </span>
  <div>
    f
    <span>
      g h
    </span>
  </div>
</div>
Screenshot 2024-04-15 at 3 35 40 PM

before

Screenshot 2024-04-15 at 3 35 21 PM

after

Screenshot 2024-04-15 at 3 35 35 PM
potatowagon commented 1 month ago

Case: simple span in a div

<div>
  a
  <span>b</span>
</div>
Screenshot 2024-04-15 at 3 39 50 PM

Before

Screenshot 2024-04-15 at 3 40 26 PM

After

Screenshot 2024-04-15 at 3 40 49 PM
potatowagon commented 1 month ago

Case: github markdown tablecopypaste

A B C
1 2 3
4 5 6
new
line
bold italic
new
line
new
line
10 11

^ copy directly into lexical

Before

Screenshot 2024-04-15 at 10 05 45 PM

After

Screenshot 2024-04-15 at 10 06 16 PM
acywatson commented 2 weeks ago

Paragraphs being block elements should not be nested in another block element, and the semantically right way to do so is to insert line breaks.

Are we aligned on these semantics? Where did this invariant come from?

potatowagon commented 2 weeks ago

@acywatson

Paragraphs being block elements should not be nested in another block element, and the semantically right way to do so is to insert line breaks.

Are we aligned on these semantics? Where did this invariant come from?

from http://www.w3.org/TR/html401/struct/text.html#h-9.3.1

The P element represents a paragraph. It cannot contain block-level elements (including P itself).

for the line breaks, since <p> in a <li> will be block in a block, the most correct way would be <br> in a <li> which is what google doc does

potatowagon commented 2 weeks ago

Great work! Do you mind adding the test cases we whiteboarded please?

added!