From 5a7a42b1752216d45d412f0cd9fb9b5e33553554 Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Wed, 23 Apr 2025 20:59:03 +0200 Subject: [PATCH 1/6] Added lossy HTML export/parse equality tests --- .../exportParseEqualityTestInstances.ts | 182 +++++++++++++++++- .../exportParseEquality/runTests.test.ts | 18 +- .../exportParseEqualityTestExecutors.ts | 23 +++ 3 files changed, 221 insertions(+), 2 deletions(-) diff --git a/tests/src/unit/core/formatConversion/exportParseEquality/exportParseEqualityTestInstances.ts b/tests/src/unit/core/formatConversion/exportParseEquality/exportParseEqualityTestInstances.ts index 63d3552df..f3bad1bc7 100644 --- a/tests/src/unit/core/formatConversion/exportParseEquality/exportParseEqualityTestInstances.ts +++ b/tests/src/unit/core/formatConversion/exportParseEquality/exportParseEqualityTestInstances.ts @@ -1,5 +1,8 @@ import { ExportParseEqualityTestCase } from "../../../shared/formatConversion/exportParseEquality/exportParseEqualityTestCase.js"; -import { testExportParseEqualityBlockNoteHTML } from "../../../shared/formatConversion/exportParseEquality/exportParseEqualityTestExecutors.js"; +import { + testExportParseEqualityBlockNoteHTML, + testExportParseEqualityHTML, +} from "../../../shared/formatConversion/exportParseEquality/exportParseEqualityTestExecutors.js"; import { TestInstance } from "../../../types.js"; import { TestBlockSchema, @@ -21,3 +24,180 @@ export const exportParseEqualityTestInstancesBlockNoteHTML: TestInstance< testCase, executeTest: testExportParseEqualityBlockNoteHTML, })); + +export const exportParseEqualityTestInstancesHTML: TestInstance< + ExportParseEqualityTestCase< + TestBlockSchema, + TestInlineContentSchema, + TestStyleSchema + >, + TestBlockSchema, + TestInlineContentSchema, + TestStyleSchema +>[] = [ + { + testCase: { + name: "schema/blocks", + content: [ + { + type: "paragraph", + content: "Paragraph", + }, + { + type: "heading", + content: "Heading", + }, + { + type: "quote", + content: "Quote", + }, + { + type: "bulletListItem", + content: "Bullet List Item", + }, + { + type: "numberedListItem", + content: "Numbered List Item", + }, + { + type: "checkListItem", + content: "Check List Item", + }, + { + type: "codeBlock", + content: "Code", + }, + { + type: "table", + content: { + type: "tableContent", + rows: [ + { + cells: ["Table Cell", "Table Cell"], + }, + { + cells: ["Table Cell", "Table Cell"], + }, + ], + }, + }, + ], + }, + executeTest: testExportParseEqualityHTML, + }, + { + testCase: { + name: "schema/blockProps", + content: [ + { + type: "paragraph", + content: "Paragraph", + props: { + textColor: "red", + backgroundColor: "blue", + textAlignment: "center", + }, + }, + { + type: "heading", + content: "Heading", + props: { + level: 2, + }, + }, + { + type: "checkListItem", + content: "Check List Item", + props: { + checked: true, + textColor: "red", + backgroundColor: "blue", + textAlignment: "center", + }, + }, + { + type: "codeBlock", + content: "Code", + props: { language: "javascript" }, + }, + ], + }, + executeTest: testExportParseEqualityHTML, + }, + { + testCase: { + name: "schema/inlineContent", + content: [ + { + type: "paragraph", + content: [ + { + type: "text", + text: "Text ", + styles: {}, + }, + { + type: "link", + content: "Link", + href: "https://example.com", + }, + ], + }, + ], + }, + executeTest: testExportParseEqualityHTML, + }, + { + testCase: { + name: "schema/styles", + content: [ + { + type: "paragraph", + content: [ + { + type: "text", + text: "T", + styles: { + bold: true, + italic: true, + underline: true, + strike: true, + // Code cannot be applied on top of other styles. + // code: true, + textColor: "red", + backgroundColor: "blue", + }, + }, + ], + }, + ], + }, + executeTest: testExportParseEqualityHTML, + }, + { + testCase: { + name: "lists/nested", + content: [ + { + type: "bulletListItem", + content: "List Item 1", + children: [ + { + type: "bulletListItem", + content: "Nested List Item 1", + }, + { + type: "bulletListItem", + content: "Nested List Item 2", + }, + ], + }, + { + type: "bulletListItem", + content: "List Item 2", + }, + ], + }, + executeTest: testExportParseEqualityHTML, + }, +]; diff --git a/tests/src/unit/core/formatConversion/exportParseEquality/runTests.test.ts b/tests/src/unit/core/formatConversion/exportParseEquality/runTests.test.ts index 3970bb02d..948a80d4e 100644 --- a/tests/src/unit/core/formatConversion/exportParseEquality/runTests.test.ts +++ b/tests/src/unit/core/formatConversion/exportParseEquality/runTests.test.ts @@ -2,7 +2,10 @@ import { describe, it } from "vitest"; import { setupTestEditor } from "../../setupTestEditor.js"; import { testSchema } from "../../testSchema.js"; -import { exportParseEqualityTestInstancesBlockNoteHTML } from "./exportParseEqualityTestInstances.js"; +import { + exportParseEqualityTestInstancesBlockNoteHTML, + exportParseEqualityTestInstancesHTML, +} from "./exportParseEqualityTestInstances.js"; // Tests for verifying that exporting blocks to another format, then importing // them back results in the same blocks as the original. Used for as many cases @@ -20,3 +23,16 @@ describe("Export/parse equality tests (BlockNote HTML)", () => { }); } }); + +describe("Export/parse equality tests (HTML)", () => { + const getEditor = setupTestEditor(testSchema); + + for (const { + testCase, + executeTest, + } of exportParseEqualityTestInstancesHTML) { + it(`${testCase.name}`, async () => { + await executeTest(getEditor(), testCase); + }); + } +}); diff --git a/tests/src/unit/shared/formatConversion/exportParseEquality/exportParseEqualityTestExecutors.ts b/tests/src/unit/shared/formatConversion/exportParseEquality/exportParseEqualityTestExecutors.ts index 42a75f61c..847ffee2b 100644 --- a/tests/src/unit/shared/formatConversion/exportParseEquality/exportParseEqualityTestExecutors.ts +++ b/tests/src/unit/shared/formatConversion/exportParseEquality/exportParseEqualityTestExecutors.ts @@ -33,6 +33,29 @@ export const testExportParseEqualityBlockNoteHTML = async < ); }; +export const testExportParseEqualityHTML = async < + B extends BlockSchema, + I extends InlineContentSchema, + S extends StyleSchema +>( + editor: BlockNoteEditor, + testCase: ExportParseEqualityTestCase +) => { + (window as any).__TEST_OPTIONS.mockID = 0; + + addIdsToBlocks(testCase.content); + + const exported = await editor.blocksToHTMLLossy(testCase.content); + + // Reset mock ID as we don't expect block IDs to be preserved in this + // conversion. + (window as any).__TEST_OPTIONS.mockID = 0; + + expect(await editor.tryParseHTMLToBlocks(exported)).toStrictEqual( + partialBlocksToBlocksForTesting(editor.schema, testCase.content) + ); +}; + export const testExportParseEqualityNodes = async < B extends BlockSchema, I extends InlineContentSchema, From 1202d051bba150a470d6e0c6d42733b96155a070 Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Wed, 23 Apr 2025 20:59:30 +0200 Subject: [PATCH 2/6] Fixed list item props in external HTML --- .../html/util/serializeBlocksExternalHTML.ts | 60 +++++++++++-------- .../text/html/basicBlocksWithProps.html | 12 ++-- .../__snapshots__/html/lists/basic.html | 4 +- .../__snapshots__/html/lists/nested.html | 4 +- 4 files changed, 44 insertions(+), 36 deletions(-) diff --git a/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts b/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts index 61a657ed7..4c57dcccd 100644 --- a/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +++ b/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts @@ -117,28 +117,40 @@ function serializeBlock< ].implementation.toExternalHTML({ ...block, props } as any, editor as any); const elementFragment = doc.createDocumentFragment(); - if (ret.dom.classList.contains("bn-block-content")) { - const blockContentDataAttributes = [ - ...attrs, - ...Array.from(ret.dom.attributes), - ].filter( - (attr) => - attr.name.startsWith("data") && - attr.name !== "data-content-type" && - attr.name !== "data-file-block" && - attr.name !== "data-node-view-wrapper" && - attr.name !== "data-node-type" && - attr.name !== "data-id" && - attr.name !== "data-index" && - attr.name !== "data-editable" - ); - // ret.dom = ret.dom.firstChild! as any; - for (const attr of blockContentDataAttributes) { - (ret.dom.firstChild! as HTMLElement).setAttribute(attr.name, attr.value); + let listType = undefined; + if (orderedListItemBlockTypes.has(block.type!)) { + listType = "OL"; + } else if (unorderedListItemBlockTypes.has(block.type!)) { + listType = "UL"; + } + + const blockContentDataAttributes = [ + ...attrs, + ...Array.from(ret.dom.attributes), + ].filter( + (attr) => + attr.name.startsWith("data") && + attr.name !== "data-content-type" && + attr.name !== "data-file-block" && + attr.name !== "data-node-view-wrapper" && + attr.name !== "data-node-type" && + attr.name !== "data-id" && + attr.name !== "data-index" && + attr.name !== "data-editable" + ); + + if (ret.dom.classList.contains("bn-block-content")) { + if (!listType) { + for (const attr of blockContentDataAttributes) { + (ret.dom.firstChild! as HTMLElement).setAttribute( + attr.name, + attr.value + ); + } } - addAttributesAndRemoveClasses(ret.dom.firstChild! as HTMLElement); + addAttributesAndRemoveClasses(ret.dom.firstChild as HTMLElement); elementFragment.append(...Array.from(ret.dom.childNodes)); } else { elementFragment.append(ret.dom); @@ -155,13 +167,6 @@ function serializeBlock< ret.contentDOM.appendChild(ic); } - let listType = undefined; - if (orderedListItemBlockTypes.has(block.type!)) { - listType = "OL"; - } else if (unorderedListItemBlockTypes.has(block.type!)) { - listType = "UL"; - } - if (listType) { if (fragment.lastChild?.nodeName !== listType) { const list = doc.createElement(listType); @@ -172,6 +177,9 @@ function serializeBlock< fragment.append(list); } const li = doc.createElement("li"); + for (const attr of blockContentDataAttributes) { + li.setAttribute(attr.name, attr.value); + } li.append(elementFragment); fragment.lastChild!.appendChild(li); } else { diff --git a/tests/src/unit/core/clipboard/copy/__snapshots__/text/html/basicBlocksWithProps.html b/tests/src/unit/core/clipboard/copy/__snapshots__/text/html/basicBlocksWithProps.html index aa29f7463..76545d350 100644 --- a/tests/src/unit/core/clipboard/copy/__snapshots__/text/html/basicBlocksWithProps.html +++ b/tests/src/unit/core/clipboard/copy/__snapshots__/text/html/basicBlocksWithProps.html @@ -1,16 +1,16 @@

Paragraph 1

Heading 1

    -
  1. -

    Numbered List Item 1

    +
  2. +

    Numbered List Item 1

    -
  • -

    Bullet List Item 1

    +
  • +

    Bullet List Item 1

  • -
  • - +
  • +

    Check List Item 1

diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/html/lists/basic.html b/tests/src/unit/core/formatConversion/export/__snapshots__/html/lists/basic.html index aee1048a8..6d3b10f9a 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/html/lists/basic.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/html/lists/basic.html @@ -19,8 +19,8 @@

Check List Item 1

-
  • - +
  • +

    Check List Item 2

  • \ No newline at end of file diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/html/lists/nested.html b/tests/src/unit/core/formatConversion/export/__snapshots__/html/lists/nested.html index b2497ae93..a708d5bb3 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/html/lists/nested.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/html/lists/nested.html @@ -15,8 +15,8 @@

    Check List Item 1

    -
  • - +
  • +

    Check List Item 2

  • From 0c01ed5874a22dceafe1e58ffffe76198b9f1454 Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Wed, 23 Apr 2025 21:16:15 +0200 Subject: [PATCH 3/6] Fixed tables in `partialBlockToBlockForTesting` --- .../formatConversionTestUtil.ts | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/tests/src/unit/core/formatConversion/formatConversionTestUtil.ts b/tests/src/unit/core/formatConversion/formatConversionTestUtil.ts index a71cdbda0..70ec3fc34 100644 --- a/tests/src/unit/core/formatConversion/formatConversionTestUtil.ts +++ b/tests/src/unit/core/formatConversion/formatConversionTestUtil.ts @@ -9,6 +9,7 @@ import { PartialBlock, PartialInlineContent, PartialTableCell, + PartialTableContent, StyledText, StyleSchema, TableCell, @@ -153,10 +154,10 @@ export function partialBlockToBlockForTesting< ); if (contentType === "inline") { - const content = withDefaults.content as InlineContent[] | undefined; + const content = withDefaults.content as PartialInlineContent; withDefaults.content = partialContentToInlineContent(content) as any; } else if (contentType === "table") { - const content = withDefaults.content as TableContent | undefined; + const content = withDefaults.content as PartialTableContent; withDefaults.content = { type: "tableContent", columnWidths: @@ -167,7 +168,34 @@ export function partialBlockToBlockForTesting< headerCols: content?.headerCols || undefined, rows: content?.rows.map((row) => ({ - cells: row.cells.map((cell) => partialContentToInlineContent(cell)), + cells: row.cells.map((cell) => + typeof cell === "object" && + "type" in cell && + cell.type === "tableCell" + ? { + type: "tableCell", + props: { + backgroundColor: "default", + colspan: 1, + rowspan: 1, + textAlignment: "left", + textColor: "default", + ...cell.props, + }, + content: partialContentToInlineContent(cell.content), + } + : { + type: "tableCell", + props: { + backgroundColor: "default", + colspan: 1, + rowspan: 1, + textAlignment: "left", + textColor: "default", + }, + content: partialContentToInlineContent(cell), + } + ), })) || [], } as any; } From 06b84af76709f16e4435a1474977176f754ab0f5 Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Thu, 24 Apr 2025 11:15:05 +0200 Subject: [PATCH 4/6] Added advanced table test --- .../exportParseEqualityTestInstances.ts | 111 ++++++++++++++++++ tests/src/unit/core/setupTestEditor.ts | 6 + 2 files changed, 117 insertions(+) diff --git a/tests/src/unit/core/formatConversion/exportParseEquality/exportParseEqualityTestInstances.ts b/tests/src/unit/core/formatConversion/exportParseEquality/exportParseEqualityTestInstances.ts index f3bad1bc7..74654d55e 100644 --- a/tests/src/unit/core/formatConversion/exportParseEquality/exportParseEqualityTestInstances.ts +++ b/tests/src/unit/core/formatConversion/exportParseEquality/exportParseEqualityTestInstances.ts @@ -200,4 +200,115 @@ export const exportParseEqualityTestInstancesHTML: TestInstance< }, executeTest: testExportParseEqualityHTML, }, + { + testCase: { + name: "tables/advanced", + content: [ + { + type: "table", + content: { + type: "tableContent", + columnWidths: [199, 148, 201], + headerRows: 1, + rows: [ + { + cells: [ + { + type: "tableCell", + content: "This row has headers", + props: { + textAlignment: "center", + }, + }, + { + type: "tableCell", + content: [ + { + type: "text", + text: "This is ", + styles: {}, + }, + { + type: "text", + text: "RED", + styles: { + bold: true, + }, + }, + ], + props: { + backgroundColor: "red", + textAlignment: "center", + }, + }, + { + type: "tableCell", + content: "Text is Blue", + props: { + textColor: "blue", + textAlignment: "center", + }, + }, + ], + }, + { + cells: [ + { + type: "tableCell", + content: "This spans 2 columns\nand 2 rows", + props: { + colspan: 2, + rowspan: 2, + backgroundColor: "yellow", + }, + }, + { + type: "tableCell", + content: "Sooo many features", + props: { + backgroundColor: "gray", + textColor: "default", + textAlignment: "left", + }, + }, + ], + }, + { + cells: [ + { + type: "tableCell", + content: [], + props: { + backgroundColor: "gray", + textColor: "purple", + }, + }, + ], + }, + { + cells: [ + { + type: "tableCell", + content: "A cell", + }, + { + type: "tableCell", + content: "Another Cell", + }, + { + type: "tableCell", + content: "Aligned center", + props: { + textAlignment: "center", + }, + }, + ], + }, + ], + }, + }, + ], + }, + executeTest: testExportParseEqualityHTML, + }, ]; diff --git a/tests/src/unit/core/setupTestEditor.ts b/tests/src/unit/core/setupTestEditor.ts index 5df422680..b98eaae56 100644 --- a/tests/src/unit/core/setupTestEditor.ts +++ b/tests/src/unit/core/setupTestEditor.ts @@ -36,6 +36,12 @@ export const setupTestEditor = < }, }, schema, + tables: { + splitCells: true, + cellBackgroundColor: true, + cellTextColor: true, + headers: true, + }, trailingBlock: false, uploadFile: uploadToTmpFilesDotOrg_DEV_ONLY, }); From ebe978556cf092c477d1ce1bb10889c1f54b50cf Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Thu, 24 Apr 2025 13:11:29 +0200 Subject: [PATCH 5/6] Added comment --- .../src/api/exporters/html/util/serializeBlocksExternalHTML.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts b/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts index 4c57dcccd..dd0350483 100644 --- a/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +++ b/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts @@ -141,6 +141,8 @@ function serializeBlock< ); if (ret.dom.classList.contains("bn-block-content")) { + // We wrap the output in an `li` element for list items, and so we want to + // add the attributes to that element instead as it is the "root". if (!listType) { for (const attr of blockContentDataAttributes) { (ret.dom.firstChild! as HTMLElement).setAttribute( From 4c38f3c62200ffd86f5c3608c8ccf2a7119598c2 Mon Sep 17 00:00:00 2001 From: Matthew Lipski <50169049+matthewlipski@users.noreply.github.com> Date: Mon, 28 Apr 2025 11:23:20 +0200 Subject: [PATCH 6/6] 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 --- .../html/util/serializeBlocksExternalHTML.ts | 28 ++ .../core/src/blocks/defaultBlockHelpers.ts | 76 ++- packages/core/src/blocks/defaultProps.ts | 18 + packages/core/src/schema/blocks/internal.ts | 3 +- .../ServerBlockNoteEditor.test.ts.snap | 2 +- .../text/html/basicBlocksWithProps.html | 8 +- .../__snapshots__/html/complex/misc.html | 6 +- .../__snapshots__/html/paragraph/styled.html | 4 +- .../html/backgroundColorProp.json | 23 +- .../html/backgroundColorStyle.json | 16 +- .../__snapshots__/html/textColorProp.json | 23 +- .../__snapshots__/html/textColorStyle.json | 16 +- .../parse/__snapshots__/html/twoTables.json | 2 +- .../parse/parseTestInstances.ts | 464 +++++++++--------- .../html/contextParagraph/basic.html | 2 +- .../html/customParagraph/basic.html | 2 +- .../html/customParagraph/lineBreaks.html | 2 +- .../html/customParagraph/nested.html | 6 +- .../html/customParagraph/styled.html | 1 + .../html/simpleCustomParagraph/basic.html | 6 +- .../html/simpleCustomParagraph/nested.html | 18 +- .../html/simpleCustomParagraph/styled.html | 1 + 22 files changed, 403 insertions(+), 324 deletions(-) diff --git a/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts b/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts index dd0350483..a39c2d7b9 100644 --- a/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +++ b/packages/core/src/api/exporters/html/util/serializeBlocksExternalHTML.ts @@ -144,6 +144,19 @@ function serializeBlock< // We wrap the output in an `li` element for list items, and so we want to // add the attributes to that element instead as it is the "root". if (!listType) { + // Copies the styles and prop-related attributes from the `blockContent` + // element onto its first child, as the `blockContent` element is omitted + // from external HTML. This is so prop data is preserved via `data-*` + // attributes or inline styles. + // + // The styles are specifically for default props on default blocks, as + // they get converted from `data-*` attributes for external HTML. Will + // need to revisit this when we convert default blocks to use the custom + // block API. + const style = ret.dom.getAttribute("style"); + if (style) { + (ret.dom.firstChild! as HTMLElement).setAttribute("style", style); + } for (const attr of blockContentDataAttributes) { (ret.dom.firstChild! as HTMLElement).setAttribute( attr.name, @@ -179,9 +192,24 @@ function serializeBlock< fragment.append(list); } const li = doc.createElement("li"); + + // Copies the styles and prop-related attributes from the `blockContent` + // element onto its first child, as the `blockContent` element is omitted + // from external HTML. This is so prop data is preserved via `data-*` + // attributes or inline styles. + // + // The styles are specifically for default props on default blocks, as + // they get converted from `data-*` attributes for external HTML. Will + // need to revisit this when we convert default blocks to use the custom + // block API. + const style = ret.dom.getAttribute("style"); + if (style) { + li.setAttribute("style", style); + } for (const attr of blockContentDataAttributes) { li.setAttribute(attr.name, attr.value); } + li.append(elementFragment); fragment.lastChild!.appendChild(li); } else { diff --git a/packages/core/src/blocks/defaultBlockHelpers.ts b/packages/core/src/blocks/defaultBlockHelpers.ts index fbba956c8..b8220e310 100644 --- a/packages/core/src/blocks/defaultBlockHelpers.ts +++ b/packages/core/src/blocks/defaultBlockHelpers.ts @@ -1,5 +1,6 @@ import { blockToNode } from "../api/nodeConversions/blockToNode.js"; import type { BlockNoteEditor } from "../editor/BlockNoteEditor.js"; +import { COLORS_DEFAULT } from "../editor/defaultColors.js"; import type { BlockNoDefaults, BlockSchema, @@ -55,14 +56,17 @@ export function createDefaultBlockDOMOutputSpec( // Function used to convert default blocks to HTML. It uses the corresponding // node's `renderHTML` method to do the conversion by using a default -// `DOMSerializer`. +// `DOMSerializer`. The `external` flag is used to modify the resulting HTML for +// external use. This just involves changing props being rendered from `data-*` +// attributes to inline styles. export const defaultBlockToHTML = < BSchema extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema >( block: BlockNoDefaults, - editor: BlockNoteEditor + editor: BlockNoteEditor, + external = false ): { dom: HTMLElement; contentDOM?: HTMLElement; @@ -90,6 +94,74 @@ export const defaultBlockToHTML = < ); } + // When exporting to external HTML, we convert from `data-*` attributes to + // inline styles properties which can be understood by external applications. + // + // Note: This is a bit hacky to do this here as we're just hardcoding this for + // props on default blocks. We should revisit this when we migrate internal + // blocks to use the custom blocks API. + if (external) { + const dom = renderSpec.dom as HTMLElement; + + if (dom.hasAttribute("data-background-color")) { + const backgroundColor = dom.getAttribute("data-background-color")!; + + // If the background color is one of the default colors, we set the + // color's hex code from the default theme, as this will look nicer than + // using regular CSS colors. For example, instead of + // `background-color: red`, we use `background-color: #fbe4e4`. + if (backgroundColor in COLORS_DEFAULT) { + const cssVariableName = + `--blocknote-background-${backgroundColor}` as any; + + dom.style.setProperty( + cssVariableName, + COLORS_DEFAULT[backgroundColor as keyof typeof COLORS_DEFAULT] + .background + ); + dom.style.backgroundColor = `var(${cssVariableName})`; + } else { + dom.style.backgroundColor = backgroundColor; + } + + dom.removeAttribute("data-background-color"); + } + + if (dom.hasAttribute("data-text-color")) { + const textColor = dom.getAttribute("data-text-color")!; + + // If the text color is one of the default colors, we set the color's hex + // code from the default theme, as this will look nicer than using regular + // CSS colors. For example, instead of `color: red`, we use + // `color: #e03e3e`. + if (textColor in COLORS_DEFAULT) { + const cssVariableName = `--blocknote-text-${textColor}` as any; + + dom.style.setProperty( + cssVariableName, + COLORS_DEFAULT[textColor as keyof typeof COLORS_DEFAULT].text + ); + dom.style.color = `var(${cssVariableName})`; + } else { + dom.style.color = textColor; + } + + dom.removeAttribute("data-text-color"); + } + + if (dom.hasAttribute("data-text-alignment")) { + dom.style.textAlign = dom.getAttribute("data-text-alignment")!; + dom.removeAttribute("data-text-alignment"); + } + + // We also remove the `data-level` attribute for heading blocks, as this + // information can be inferred from whether a `h1`, `h2`, or `h3 tag is + // used. + if (dom.hasAttribute("data-level")) { + dom.removeAttribute("data-level"); + } + } + return renderSpec as { dom: HTMLElement; contentDOM?: HTMLElement; diff --git a/packages/core/src/blocks/defaultProps.ts b/packages/core/src/blocks/defaultProps.ts index a524b19a9..44193cd01 100644 --- a/packages/core/src/blocks/defaultProps.ts +++ b/packages/core/src/blocks/defaultProps.ts @@ -30,6 +30,16 @@ const getBackgroundColorAttribute = ( } if (element.style.backgroundColor) { + // Check if `element.style.backgroundColor` matches the string: + // `var(--blocknote-background-)`. If it does, return the color + // name only. Otherwise, return `element.style.backgroundColor`. + const match = element.style.backgroundColor.match( + /var\(--blocknote-background-(.+)\)/ + ); + if (match) { + return match[1]; + } + return element.style.backgroundColor; } @@ -54,6 +64,14 @@ const getTextColorAttribute = (attributeName = "textColor"): Attribute => ({ } if (element.style.color) { + // Check if `element.style.color` matches the string: + // `var(--blocknote-text-)`. If it does, return the color name + // only. Otherwise, return `element.style.color`. + const match = element.style.color.match(/var\(--blocknote-text-(.+)\)/); + if (match) { + return match[1]; + } + return element.style.color; } diff --git a/packages/core/src/schema/blocks/internal.ts b/packages/core/src/schema/blocks/internal.ts index 9669f3db9..bbbb75b44 100644 --- a/packages/core/src/schema/blocks/internal.ts +++ b/packages/core/src/schema/blocks/internal.ts @@ -267,7 +267,8 @@ export function createBlockSpecFromStronglyTypedTiptapNode< node, requiredExtensions, toInternalHTML: defaultBlockToHTML, - toExternalHTML: defaultBlockToHTML, + toExternalHTML: (block, editor) => + defaultBlockToHTML(block, editor, true), // parse: () => undefined, // parse rules are in node already } ); diff --git a/packages/server-util/src/context/__snapshots__/ServerBlockNoteEditor.test.ts.snap b/packages/server-util/src/context/__snapshots__/ServerBlockNoteEditor.test.ts.snap index 7a991c453..c31fa3130 100644 --- a/packages/server-util/src/context/__snapshots__/ServerBlockNoteEditor.test.ts.snap +++ b/packages/server-util/src/context/__snapshots__/ServerBlockNoteEditor.test.ts.snap @@ -2,7 +2,7 @@ exports[`Test ServerBlockNoteEditor > converts to HTML (blocksToFullHTML) 1`] = `"

    Heading 2

    Paragraph

    list item

    Example

    Caption

    Example

    Caption

    "`; -exports[`Test ServerBlockNoteEditor > converts to and from HTML (blocksToHTMLLossy) 1`] = `"

    Heading 2

    Paragraph

    • list item

    Example
    Caption
    Example

    Caption

    "`; +exports[`Test ServerBlockNoteEditor > converts to and from HTML (blocksToHTMLLossy) 1`] = `"

    Heading 2

    Paragraph

    • list item

    Example
    Caption
    Example

    Caption

    "`; exports[`Test ServerBlockNoteEditor > converts to and from HTML (blocksToHTMLLossy) 2`] = ` [ diff --git a/tests/src/unit/core/clipboard/copy/__snapshots__/text/html/basicBlocksWithProps.html b/tests/src/unit/core/clipboard/copy/__snapshots__/text/html/basicBlocksWithProps.html index 76545d350..5c496bbf0 100644 --- a/tests/src/unit/core/clipboard/copy/__snapshots__/text/html/basicBlocksWithProps.html +++ b/tests/src/unit/core/clipboard/copy/__snapshots__/text/html/basicBlocksWithProps.html @@ -1,12 +1,14 @@ -

    Paragraph 1

    -

    Heading 1

    +

    Paragraph 1

    +

    Heading 1

    1. Numbered List Item 1

      -
    • +
    • Bullet List Item 1

    • diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/html/complex/misc.html b/tests/src/unit/core/formatConversion/export/__snapshots__/html/complex/misc.html index 0df8a1834..a5fd6fe7e 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/html/complex/misc.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/html/complex/misc.html @@ -1,4 +1,4 @@ -

      +

      Heading @@ -6,7 +6,9 @@

      Paragraph

      +

      Paragraph

      • diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/html/paragraph/styled.html b/tests/src/unit/core/formatConversion/export/__snapshots__/html/paragraph/styled.html index 65e55c08b..032aa7b89 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/html/paragraph/styled.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/html/paragraph/styled.html @@ -1,7 +1,5 @@

        Plain Red Text diff --git a/tests/src/unit/core/formatConversion/parse/__snapshots__/html/backgroundColorProp.json b/tests/src/unit/core/formatConversion/parse/__snapshots__/html/backgroundColorProp.json index f2ebc5ed9..15f5d0729 100644 --- a/tests/src/unit/core/formatConversion/parse/__snapshots__/html/backgroundColorProp.json +++ b/tests/src/unit/core/formatConversion/parse/__snapshots__/html/backgroundColorProp.json @@ -4,30 +4,13 @@ "content": [ { "styles": {}, - "text": "Red Background", + "text": "Blue Background", "type": "text", }, ], "id": "1", "props": { - "backgroundColor": "red", - "textAlignment": "left", - "textColor": "default", - }, - "type": "paragraph", - }, - { - "children": [], - "content": [ - { - "styles": {}, - "text": "Green Background", - "type": "text", - }, - ], - "id": "2", - "props": { - "backgroundColor": "green", + "backgroundColor": "blue", "textAlignment": "left", "textColor": "default", }, @@ -42,7 +25,7 @@ "type": "text", }, ], - "id": "3", + "id": "2", "props": { "backgroundColor": "blue", "textAlignment": "left", diff --git a/tests/src/unit/core/formatConversion/parse/__snapshots__/html/backgroundColorStyle.json b/tests/src/unit/core/formatConversion/parse/__snapshots__/html/backgroundColorStyle.json index 0f1dfc15e..8afe915ba 100644 --- a/tests/src/unit/core/formatConversion/parse/__snapshots__/html/backgroundColorStyle.json +++ b/tests/src/unit/core/formatConversion/parse/__snapshots__/html/backgroundColorStyle.json @@ -4,21 +4,9 @@ "content": [ { "styles": { - "backgroundColor": "red", - }, - "text": "Red Background", - "type": "text", - }, - { - "styles": {}, - "text": " ", - "type": "text", - }, - { - "styles": { - "backgroundColor": "green", + "backgroundColor": "blue", }, - "text": "Green Background", + "text": "Blue Background", "type": "text", }, { diff --git a/tests/src/unit/core/formatConversion/parse/__snapshots__/html/textColorProp.json b/tests/src/unit/core/formatConversion/parse/__snapshots__/html/textColorProp.json index 7480fcab3..4211362bf 100644 --- a/tests/src/unit/core/formatConversion/parse/__snapshots__/html/textColorProp.json +++ b/tests/src/unit/core/formatConversion/parse/__snapshots__/html/textColorProp.json @@ -4,7 +4,7 @@ "content": [ { "styles": {}, - "text": "Red Paragraph", + "text": "Blue Text", "type": "text", }, ], @@ -12,7 +12,7 @@ "props": { "backgroundColor": "default", "textAlignment": "left", - "textColor": "red", + "textColor": "blue", }, "type": "paragraph", }, @@ -21,28 +21,11 @@ "content": [ { "styles": {}, - "text": "Green Paragraph", + "text": "Blue Text", "type": "text", }, ], "id": "2", - "props": { - "backgroundColor": "default", - "textAlignment": "left", - "textColor": "green", - }, - "type": "paragraph", - }, - { - "children": [], - "content": [ - { - "styles": {}, - "text": "Blue Paragraph", - "type": "text", - }, - ], - "id": "3", "props": { "backgroundColor": "default", "textAlignment": "left", diff --git a/tests/src/unit/core/formatConversion/parse/__snapshots__/html/textColorStyle.json b/tests/src/unit/core/formatConversion/parse/__snapshots__/html/textColorStyle.json index faeeee527..e78e1a4b3 100644 --- a/tests/src/unit/core/formatConversion/parse/__snapshots__/html/textColorStyle.json +++ b/tests/src/unit/core/formatConversion/parse/__snapshots__/html/textColorStyle.json @@ -4,21 +4,9 @@ "content": [ { "styles": { - "textColor": "red", - }, - "text": "Red Text", - "type": "text", - }, - { - "styles": {}, - "text": " ", - "type": "text", - }, - { - "styles": { - "textColor": "green", + "textColor": "blue", }, - "text": "Green Text", + "text": "Blue Text", "type": "text", }, { diff --git a/tests/src/unit/core/formatConversion/parse/__snapshots__/html/twoTables.json b/tests/src/unit/core/formatConversion/parse/__snapshots__/html/twoTables.json index 3ffbb3ead..1def7a8e3 100644 --- a/tests/src/unit/core/formatConversion/parse/__snapshots__/html/twoTables.json +++ b/tests/src/unit/core/formatConversion/parse/__snapshots__/html/twoTables.json @@ -45,7 +45,7 @@ { "styles": {}, "text": " - + Name: [Company Representative] Title: Chief Executive Officer", "type": "text", diff --git a/tests/src/unit/core/formatConversion/parse/parseTestInstances.ts b/tests/src/unit/core/formatConversion/parse/parseTestInstances.ts index 375bfd098..2ec30e07d 100644 --- a/tests/src/unit/core/formatConversion/parse/parseTestInstances.ts +++ b/tests/src/unit/core/formatConversion/parse/parseTestInstances.ts @@ -20,11 +20,11 @@ export const parseTestInstancesHTML: TestInstance< testCase: { name: "basicBlockTypes", content: `

        Heading 1

        -

        Heading 2

        -

        Heading 3

        -

        Paragraph

        -
        Image Caption
        -

        None Bold Italic Underline Strikethrough All

        `, +

        Heading 2

        +

        Heading 3

        +

        Paragraph

        +
        Image Caption
        +

        None Bold Italic Underline Strikethrough All

        `, }, executeTest: testParseHTML, }, @@ -32,82 +32,82 @@ export const parseTestInstancesHTML: TestInstance< testCase: { name: "lists", content: `
          -
        • First
        • -
        • Second
        • -
        • Third
        • -
        • - - Fourth -
        • -
        • - - Fifth -
        • -
        • Five Parent -
            -
          • Child 1
          • -
          • Child 2
          • -
          • - - Child 3 -
          • -
          • - - Child 4 -
          • -
          -
        • -
        `, - }, - executeTest: testParseHTML, - }, - { - testCase: { - name: "nestedLists", - content: `
          -
        • Bullet List Item
        • -
        • Bullet List Item -
            -
          • Nested Bullet List Item
          • -
          • Nested Bullet List Item
          • -
          -
        • -
        • Bullet List Item
        • -
        -
          -
        1. Numbered List Item
        2. -
        3. Numbered List Item -
            -
          1. Nested Numbered List Item
          2. -
          3. Nested Numbered List Item
          4. -
          -
        4. -
        5. Numbered List Item
        6. -
        -
          +
        • First
        • +
        • Second
        • +
        • Third
        • - Check List Item + Fourth
        • - Check List Item + Fifth +
        • +
        • Five Parent
            +
          • Child 1
          • +
          • Child 2
          • - Nested Check List Item + Child 3
          • - Nested Check List Item + Child 4
        • -
        • - - Nested Check List Item -
        • -
        `, +
      `, + }, + executeTest: testParseHTML, + }, + { + testCase: { + name: "nestedLists", + content: `
        +
      • Bullet List Item
      • +
      • Bullet List Item +
          +
        • Nested Bullet List Item
        • +
        • Nested Bullet List Item
        • +
        +
      • +
      • Bullet List Item
      • +
      +
        +
      1. Numbered List Item
      2. +
      3. Numbered List Item +
          +
        1. Nested Numbered List Item
        2. +
        3. Nested Numbered List Item
        4. +
        +
      4. +
      5. Numbered List Item
      6. +
      +
        +
      • + + Check List Item +
      • +
      • + + Check List Item +
          +
        • + + Nested Check List Item +
        • +
        • + + Nested Check List Item +
        • +
        +
      • +
      • + + Nested Check List Item +
      • +
      `, }, executeTest: testParseHTML, }, @@ -115,67 +115,67 @@ export const parseTestInstancesHTML: TestInstance< testCase: { name: "nestedListsWithParagraphs", content: `
        -
      • -

        Bullet List Item

        -
      • -
      • -

        Bullet List Item

        -
          -
        • -

          Nested Bullet List Item

          -
        • -
        • -

          Nested Bullet List Item

          -
        • -
        -
      • -
      • -

        Bullet List Item

        -
      • -
      -
        -
      1. -

        Numbered List Item

        -
      2. -
      3. -

        Numbered List Item

        -
          -
        1. -

          Nested Numbered List Item

          -
        2. -
        3. -

          Nested Numbered List Item

          -
        4. -
        -
      4. -
      5. -

        Numbered List Item

        -
      6. -
      -
        -
      • - -

        Checked List Item

        -
      • -
      • - -

        Checked List Item

        -
          -
        • - -

          Nested Checked List Item

          -
        • -
        • - -

          Nested Checked List Item

          -
        • -
        -
      • -
      • - -

        Checked List Item

        -
      • -
      `, +
    • +

      Bullet List Item

      +
    • +
    • +

      Bullet List Item

      +
        +
      • +

        Nested Bullet List Item

        +
      • +
      • +

        Nested Bullet List Item

        +
      • +
      +
    • +
    • +

      Bullet List Item

      +
    • +

    +
      +
    1. +

      Numbered List Item

      +
    2. +
    3. +

      Numbered List Item

      +
        +
      1. +

        Nested Numbered List Item

        +
      2. +
      3. +

        Nested Numbered List Item

        +
      4. +
      +
    4. +
    5. +

      Numbered List Item

      +
    6. +
    +
      +
    • + +

      Checked List Item

      +
    • +
    • + +

      Checked List Item

      +
        +
      • + +

        Nested Checked List Item

        +
      • +
      • + +

        Nested Checked List Item

        +
      • +
      +
    • +
    • + +

      Checked List Item

      +
    • +
    `, }, executeTest: testParseHTML, }, @@ -183,49 +183,49 @@ export const parseTestInstancesHTML: TestInstance< testCase: { name: "mixedNestedLists", content: `
      -
    • Bullet List Item
    • -
    • Bullet List Item -
        -
      1. Nested Numbered List Item
      2. -
      3. Nested Numbered List Item
      4. -
      -
    • -
    • Bullet List Item
    • -
    -
      -
    1. Numbered List Item
    2. -
    3. Numbered List Item -
        -
      • - - Nested Check List Item -
      • -
      • - - Nested Check List Item -
      • -
      -
    4. -
    5. Numbered List Item
    6. -
    -
      -
    • - - Check List Item -
    • -
    • - - Check List Item -
        -
      • Nested Bullet List Item
      • -
      • Nested Bullet List Item
      • -
      -
    • -
    • - - Nested Check List Item -
    • -
    `, +
  • Bullet List Item
  • +
  • Bullet List Item +
      +
    1. Nested Numbered List Item
    2. +
    3. Nested Numbered List Item
    4. +
    +
  • +
  • Bullet List Item
  • + +
      +
    1. Numbered List Item
    2. +
    3. Numbered List Item +
        +
      • + + Nested Check List Item +
      • +
      • + + Nested Check List Item +
      • +
      +
    4. +
    5. Numbered List Item
    6. +
    +
      +
    • + + Check List Item +
    • +
    • + + Check List Item +
        +
      • Nested Bullet List Item
      • +
      • Nested Bullet List Item
      • +
      +
    • +
    • + + Nested Check List Item +
    • +
    `, }, executeTest: testParseHTML, }, @@ -233,16 +233,16 @@ export const parseTestInstancesHTML: TestInstance< testCase: { name: "divs", content: `
    Single Div
    -
    - Div -
    Nested Div
    -
    Nested Div
    -
    -
    Single Div 2
    -
    -
    Nested Div
    -
    Nested Div
    -
    `, +
    + Div +
    Nested Div
    +
    Nested Div
    +
    +
    Single Div 2
    +
    +
    Nested Div
    +
    Nested Div
    +
    `, }, executeTest: testParseHTML, }, @@ -257,8 +257,8 @@ export const parseTestInstancesHTML: TestInstance< testCase: { name: "imageInParagraph", content: `

    - -

    `, + +

    `, }, executeTest: testParseHTML, }, @@ -266,9 +266,9 @@ export const parseTestInstancesHTML: TestInstance< testCase: { name: "fakeImageCaption", content: `
    - -

    Image Caption

    -
    `, + +

    Image Caption

    + `, }, executeTest: testParseHTML, }, @@ -276,27 +276,27 @@ export const parseTestInstancesHTML: TestInstance< testCase: { name: "deepNestedContent", content: `
    - Outer 1 Div Before -
    - Outer 2 Div Before + Outer 1 Div Before
    - Outer 3 Div Before + Outer 2 Div Before
    - Outer 4 Div Before -

    Heading 1

    -

    Heading 2

    -

    Heading 3

    -

    Paragraph

    -
    Image Caption
    -

    Bold Italic Underline Strikethrough All

    - Outer 4 Div After + Outer 3 Div Before +
    + Outer 4 Div Before +

    Heading 1

    +

    Heading 2

    +

    Heading 3

    +

    Paragraph

    +
    Image Caption
    +

    Bold Italic Underline Strikethrough All

    + Outer 4 Div After +
    + Outer 3 Div After
    - Outer 3 Div After + Outer 2 Div After
    - Outer 2 Div After -
    - Outer 1 Div After -
    `, + Outer 1 Div After + `, }, executeTest: testParseHTML, }, @@ -304,10 +304,10 @@ export const parseTestInstancesHTML: TestInstance< testCase: { name: "inlineContentAndNestedBlocks", content: `
    - None Bold Italic Underline Strikethrough All -
    Nested Div
    -

    Nested Paragraph

    -
    `, + None Bold Italic Underline Strikethrough All +
    Nested Div
    +

    Nested Paragraph

    + `, }, executeTest: testParseHTML, }, @@ -315,21 +315,21 @@ export const parseTestInstancesHTML: TestInstance< testCase: { name: "twoTables", content: ` - - - - - - -
    -

    Company

    -
    -

    Example Company Inc.

    -

    -

    Name: [Company Representative]

    -

    -

    Title: Chief Executive Officer

    -
    + + +

    Company

    + + + + +

    Example Company Inc.

    +

    +

    Name: [Company Representative]

    +

    +

    Title: Chief Executive Officer

    + + + @@ -543,14 +543,14 @@ With Hard Break

    { testCase: { name: "textColorStyle", - content: `

    Red Text Green Text Blue Text

    `, + content: `

    Blue Text Blue Text

    `, }, executeTest: testParseHTML, }, { testCase: { name: "backgroundColorStyle", - content: `

    Red Background Green Background Blue Background

    `, + content: `

    Blue Background Blue Background

    `, }, executeTest: testParseHTML, }, @@ -558,9 +558,9 @@ With Hard Break

    testCase: { name: "orderedListStart", content: `
      -
    1. List Item 2
    2. -
    3. List Item 3
    4. -
    5. List Item 4
    6. +
    7. List Item 2
    8. +
    9. List Item 3
    10. +
    11. List Item 4
    `, }, executeTest: testParseHTML, @@ -582,18 +582,16 @@ With Hard Break

    { testCase: { name: "textColorProp", - content: `

    Red Paragraph

    -

    Green Paragraph

    -

    Blue Paragraph

    `, + content: `

    Blue Text

    +

    Blue Text

    `, }, executeTest: testParseHTML, }, { testCase: { name: "backgroundColorProp", - content: `

    Red Background

    -

    Green Background

    -

    Blue Background

    `, + content: `

    Blue Background

    +

    Blue Background

    `, }, executeTest: testParseHTML, }, diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/html/contextParagraph/basic.html b/tests/src/unit/react/formatConversion/export/__snapshots__/html/contextParagraph/basic.html index ca43744a1..f7b852f0f 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/html/contextParagraph/basic.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/html/contextParagraph/basic.html @@ -1 +1 @@ -
    React Context Paragraph
    \ No newline at end of file +
    React Context Paragraph
    \ No newline at end of file diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/basic.html b/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/basic.html index 2971f1105..ff100b250 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/basic.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/basic.html @@ -1 +1 @@ -

    Hello World

    \ No newline at end of file +

    Hello World

    \ No newline at end of file diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/lineBreaks.html b/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/lineBreaks.html index 2971f1105..ff100b250 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/lineBreaks.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/lineBreaks.html @@ -1 +1 @@ -

    Hello World

    \ No newline at end of file +

    Hello World

    \ No newline at end of file diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/nested.html b/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/nested.html index 6b2e1554c..863e2204e 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/nested.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/nested.html @@ -1,3 +1,3 @@ -

    Hello World

    -

    Hello World

    -

    Hello World

    \ No newline at end of file +

    Hello World

    +

    Hello World

    +

    Hello World

    \ No newline at end of file diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/styled.html b/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/styled.html index 7e7e60707..962c4cea9 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/styled.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/html/customParagraph/styled.html @@ -1,5 +1,6 @@

    React Custom Paragraph

    \ No newline at end of file +

    React Custom Paragraph

    \ No newline at end of file diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/html/simpleCustomParagraph/nested.html b/tests/src/unit/react/formatConversion/export/__snapshots__/html/simpleCustomParagraph/nested.html index 68e209191..677ec39d3 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/html/simpleCustomParagraph/nested.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/html/simpleCustomParagraph/nested.html @@ -1,3 +1,15 @@ -

    Custom React Paragraph

    -

    Nested React Custom Paragraph 1

    -

    Nested React Custom Paragraph 2

    \ No newline at end of file +

    Custom React Paragraph

    +

    Nested React Custom Paragraph 1

    +

    Nested React Custom Paragraph 2

    \ No newline at end of file diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/html/simpleCustomParagraph/styled.html b/tests/src/unit/react/formatConversion/export/__snapshots__/html/simpleCustomParagraph/styled.html index aff3d3abc..4d0b88207 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/html/simpleCustomParagraph/styled.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/html/simpleCustomParagraph/styled.html @@ -1,6 +1,7 @@