Skip to content

feat: Better parsing of external HTML attributes & inline styles #1605

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

matthewlipski
Copy link
Collaborator

@matthewlipski matthewlipski commented Apr 11, 2025

This PR adds tests for parsing various HTML attributes & inline styles, and provides fixes so that these tests pass. Namely, these tests include:

  • Parsing numbered list start props from start attribute.
  • Parsing image width props from width attribute.
  • Parsing bold, italic, underline, and strike marks from various tags & inline styles. This includes e.g. b tags and font-weight inline styles for bold marks as well as i tags and font-style inline styles for italic marks.
  • Parsing textColor and backgroundColor marks from inline styles.
  • Parsing textColor and backgroundColor props from inline styles.
  • Parsing textAlignment props from inline styles.

To ensure all tests pass, several changes have also been made to the code:

  • Parse rules have been added to textColor, backgroundColor, and textAlignment props for inline styles.
  • The textColor and backgroundColor props have been changed, so that they're now applied as attributes to blockContent nodes instead of blockContainer nodes. This is because we would only attempt to parse these props when a blockContainer node is found, i.e. when a div with [data-node-type="blockContainer"] is found. So we would never even attempt to parse these props from external HTML. The CSS has been updated also to account for this change. Also, all other block props are already stored on the blockContent node, so this makes the textColor and backgroundColor props also consistent with that.
  • Small fixes have been made to numbered list item and quote blocks.

Additionally, code for color props & marks has been cleaned up slightly.

The large negative diff in this PR is also because a bunch of redundant React unit test snapshots have been removed.

Copy link

vercel bot commented Apr 11, 2025

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

Name Status Preview Updated (UTC)
blocknote ✅ Ready (Inspect) Visit Preview Apr 28, 2025 9:59am
blocknote-website ✅ Ready (Inspect) Visit Preview Apr 28, 2025 9:59am

Copy link

pkg-pr-new bot commented Apr 11, 2025

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/ariakit@1605

@blocknote/code-block

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/code-block@1605

@blocknote/core

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/core@1605

@blocknote/mantine

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/mantine@1605

@blocknote/react

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/react@1605

@blocknote/server-util

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/server-util@1605

@blocknote/shadcn

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/shadcn@1605

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/xl-docx-exporter@1605

@blocknote/xl-multi-column

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/xl-multi-column@1605

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/xl-odt-exporter@1605

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/xl-pdf-exporter@1605

commit: 0f029ff

Copy link
Contributor

@nperez0111 nperez0111 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 this looks exactly as I'd have expected it to.

Great work @matthewlipski

Base automatically changed from unit-tests-setup to main April 17, 2025 08:20
if (element.hasAttribute("data-text-color")) {
return { stringValue: element.getAttribute("data-text-color") };
if (element.hasAttribute("data-text-color") || element.style.color) {
return {};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return {}?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we don't need to parse the color because it's already handled in the parseHTML function of the stringValue attribute.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't we omit line 25 / 26 then entirely? it's still a bit confusing right? (maybe tiptap issue)

Copy link
Collaborator Author

@matthewlipski matthewlipski Apr 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because return {} tells TipTap that the element should get parsed as a textColor mark, and to just use the default attribute values for that mark (here it is equivalent to return { textColor: defaultProps.textColor.default }). The parseHTML function of the stringValue attribute then does its thing, parsing the actual value of stringValue and replacing the default one. Returning false instead means the mark never gets parsed at all.

This is a kind of weird TipTap thing especially with return {}, but it does mostly make sense.

We could choose to parse the actual value of stringValue within the parseHTML function of TextColorMark, but this would result in duplicated code between TextColorMark and TextColorExtension.

@matthewlipski matthewlipski changed the title feat: Less data loss in external HTML feat: Better parsing of HTML attributes & inline styles Apr 23, 2025
@matthewlipski matthewlipski changed the title feat: Better parsing of HTML attributes & inline styles feat: Better parsing of external HTML attributes & inline styles Apr 24, 2025
Copy link
Collaborator

@YousefED YousefED left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

Just realized one caveat; for yjs stored documents the block color data will probably be lost when upgrading (or the document might break entirely, but I doubt that).

Perhaps you can see with Nick if there's a fix for that possible (or a migration path for people upgrading)

if (element.hasAttribute("data-text-color")) {
return { stringValue: element.getAttribute("data-text-color") };
if (element.hasAttribute("data-text-color") || element.style.color) {
return {};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't we omit line 25 / 26 then entirely? it's still a bit confusing right? (maybe tiptap issue)

* Added lossy HTML export/parse equality tests

* Fixed list item props in external HTML

* Fixed tables in `partialBlockToBlockForTesting`

* Added advanced table test

* Added comment

* feat: Inline style props in external HTML (#1636)

* Made default props on default blocks get rendered to inline styles for lossy HTML

* Updated unit test snapshots

* Implemented PR feedback

* Small fix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants