-
-
Notifications
You must be signed in to change notification settings - Fork 673
fix: Visual differences between live editor and rendered exported HTML #2348
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
matthewlipski
wants to merge
5
commits into
main
Choose a base branch
from
exported-html-render-fixes
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
fe72df4
Fixed visual differences between live editor and rendered exported HTML
matthewlipski 8778e44
Updated screenshots
matthewlipski 0ffea59
Fixed unit tests & added static version of default blocks example
matthewlipski 8f532a1
Added e2e test
matthewlipski 3d85b3e
Implemented PR feedback
matthewlipski File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
6 changes: 6 additions & 0 deletions
6
examples/05-interoperability/09-blocks-to-html-static-render/.bnexample.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| { | ||
| "playground": true, | ||
| "docs": false, | ||
| "author": "matthewlipski", | ||
| "tags": ["Basic", "Blocks", "Import/Export"] | ||
| } |
9 changes: 9 additions & 0 deletions
9
examples/05-interoperability/09-blocks-to-html-static-render/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # Rendering HTML Converted From Blocks (Side by Side) | ||
|
|
||
| This example exports the current document (all blocks) as HTML and renders it below the editor. | ||
|
|
||
| **Try it out:** Edit the document to see the rendered static HTML! | ||
|
|
||
| **Relevant Docs:** | ||
|
|
||
| - [Converting Blocks to HTML](/docs/features/export/html) |
14 changes: 14 additions & 0 deletions
14
examples/05-interoperability/09-blocks-to-html-static-render/index.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <title>Rendering HTML Converted From Blocks (Side by Side)</title> | ||
| <script> | ||
| <!-- AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY --> | ||
| </script> | ||
| </head> | ||
| <body> | ||
| <div id="root"></div> | ||
| <script type="module" src="./main.tsx"></script> | ||
| </body> | ||
| </html> |
11 changes: 11 additions & 0 deletions
11
examples/05-interoperability/09-blocks-to-html-static-render/main.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| // AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY | ||
| import React from "react"; | ||
| import { createRoot } from "react-dom/client"; | ||
| import App from "./src/App.jsx"; | ||
|
|
||
| const root = createRoot(document.getElementById("root")!); | ||
| root.render( | ||
| <React.StrictMode> | ||
| <App /> | ||
| </React.StrictMode> | ||
| ); |
31 changes: 31 additions & 0 deletions
31
examples/05-interoperability/09-blocks-to-html-static-render/package.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| { | ||
| "name": "@blocknote/example-interoperability-blocks-to-html-static-render", | ||
| "description": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY", | ||
| "type": "module", | ||
| "private": true, | ||
| "version": "0.12.4", | ||
| "scripts": { | ||
| "start": "vite", | ||
| "dev": "vite", | ||
| "build:prod": "tsc && vite build", | ||
| "preview": "vite preview" | ||
| }, | ||
| "dependencies": { | ||
| "@blocknote/ariakit": "latest", | ||
| "@blocknote/core": "latest", | ||
| "@blocknote/mantine": "latest", | ||
| "@blocknote/react": "latest", | ||
| "@blocknote/shadcn": "latest", | ||
| "@mantine/core": "^8.3.11", | ||
| "@mantine/hooks": "^8.3.11", | ||
| "@mantine/utils": "^6.0.22", | ||
| "react": "^19.2.1", | ||
| "react-dom": "^19.2.1" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/react": "^19.2.2", | ||
| "@types/react-dom": "^19.2.2", | ||
| "@vitejs/plugin-react": "^4.7.0", | ||
| "vite": "^5.4.20" | ||
| } | ||
| } |
208 changes: 208 additions & 0 deletions
208
examples/05-interoperability/09-blocks-to-html-static-render/src/App.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,208 @@ | ||
| import "@blocknote/core/fonts/inter.css"; | ||
| import { BlockNoteView } from "@blocknote/mantine"; | ||
| import "@blocknote/mantine/style.css"; | ||
| import { useCreateBlockNote, usePrefersColorScheme } from "@blocknote/react"; | ||
| import { useCallback, useEffect, useRef } from "react"; | ||
|
|
||
| import "./styles.css"; | ||
|
|
||
| export default function App() { | ||
| // Creates a new editor instance with some initial content. | ||
| const editor = useCreateBlockNote({ | ||
| initialContent: [ | ||
| { | ||
| type: "paragraph", | ||
| content: "Welcome to this demo!", | ||
| }, | ||
| { | ||
| type: "paragraph", | ||
| }, | ||
| { | ||
| type: "paragraph", | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: "Blocks:", | ||
| styles: { bold: true }, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| type: "paragraph", | ||
| content: "Paragraph", | ||
| }, | ||
| { | ||
| type: "heading", | ||
| content: "Heading", | ||
| }, | ||
| { | ||
| id: "toggle-heading", | ||
| type: "heading", | ||
| props: { isToggleable: true }, | ||
| content: "Toggle Heading", | ||
| }, | ||
| { | ||
| type: "quote", | ||
| content: "Quote", | ||
| }, | ||
| { | ||
| type: "bulletListItem", | ||
| content: "Bullet List Item", | ||
| }, | ||
| { | ||
| type: "numberedListItem", | ||
| content: "Numbered List Item", | ||
| }, | ||
| { | ||
| type: "checkListItem", | ||
| content: "Check List Item", | ||
| }, | ||
| { | ||
| id: "toggle-list-item", | ||
| type: "toggleListItem", | ||
| content: "Toggle List Item", | ||
| }, | ||
| { | ||
| type: "codeBlock", | ||
| props: { language: "javascript" }, | ||
| content: "console.log('Hello, world!');", | ||
| }, | ||
| { | ||
| type: "table", | ||
| content: { | ||
| type: "tableContent", | ||
| rows: [ | ||
| { | ||
| cells: ["Table Cell", "Table Cell", "Table Cell"], | ||
| }, | ||
| { | ||
| cells: ["Table Cell", "Table Cell", "Table Cell"], | ||
| }, | ||
| { | ||
| cells: ["Table Cell", "Table Cell", "Table Cell"], | ||
| }, | ||
| ], | ||
| }, | ||
| }, | ||
| { | ||
| type: "file", | ||
| }, | ||
| { | ||
| type: "image", | ||
| props: { | ||
| url: "https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg", | ||
| caption: | ||
| "From https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg", | ||
| }, | ||
| }, | ||
| { | ||
| type: "video", | ||
| props: { | ||
| url: "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm", | ||
| caption: | ||
| "From https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm", | ||
| }, | ||
| }, | ||
| { | ||
| type: "audio", | ||
| props: { | ||
| url: "https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3", | ||
| caption: | ||
| "From https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3", | ||
| }, | ||
| }, | ||
| { | ||
| type: "paragraph", | ||
| }, | ||
| { | ||
| type: "paragraph", | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: "Inline Content:", | ||
| styles: { bold: true }, | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| type: "paragraph", | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: "Styled Text", | ||
| styles: { | ||
| bold: true, | ||
| italic: true, | ||
| textColor: "red", | ||
| backgroundColor: "blue", | ||
| }, | ||
| }, | ||
| { | ||
| type: "text", | ||
| text: " ", | ||
| styles: {}, | ||
| }, | ||
| { | ||
| type: "link", | ||
| content: "Link", | ||
| href: "https://www.blocknotejs.org", | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| type: "paragraph", | ||
| }, | ||
| ], | ||
| }); | ||
|
|
||
| const ref = useRef<HTMLDivElement>(null); | ||
| const systemColorScheme = usePrefersColorScheme(); | ||
| const theme = | ||
| systemColorScheme === "no-preference" ? "light" : systemColorScheme; | ||
|
|
||
| // Function to update the rendered static HTML. | ||
| const updateRenderedHTML = useCallback(async () => { | ||
| if (ref.current) { | ||
| ref.current.innerHTML = editor.blocksToFullHTML(editor.document); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the more standard way would be to use
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is still not fixed right @matthewlipski |
||
| } | ||
| }, []); | ||
| // Updates rendered static HTML with initial editor content. | ||
| useEffect(() => { | ||
| updateRenderedHTML(); | ||
| }, []); | ||
|
|
||
| // Renders the editor instance and HTML output. | ||
| return ( | ||
| <div className="views"> | ||
| <div className="view-wrapper"> | ||
| <div className="view-label">Editor Input</div> | ||
| <div className="view"> | ||
| <BlockNoteView editor={editor} onChange={updateRenderedHTML} /> | ||
| </div> | ||
| </div> | ||
| <div className="view-wrapper"> | ||
| <div className="view-label">Rendered Static HTML Output</div> | ||
| <div className="view"> | ||
| {/* To make the static HTML look identical to the editor, we need to | ||
| add these two wrapping divs to the exported blocks. These mock the | ||
| wrapping elements of a BlockNote editor, and are needed as the | ||
| exported HTML only holds the contents of the editor. You need will | ||
| need to add additional class names/attributes depend on the UI | ||
| library you're using, whether you want to show light or dark mode, | ||
| etc. It's easiest to just copy the class names and HTML attributes | ||
| from an actual BlockNote editor. */} | ||
| <div | ||
| className="bn-container bn-mantine" | ||
| data-color-scheme={theme} | ||
| data-mantine-color-scheme={theme} | ||
| > | ||
| <div | ||
| className="ProseMirror bn-editor bn-default-styles" | ||
| ref={ref} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
53 changes: 53 additions & 0 deletions
53
examples/05-interoperability/09-blocks-to-html-static-render/src/styles.css
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| .views { | ||
| container-name: views; | ||
| container-type: inline-size; | ||
| display: flex; | ||
| flex-direction: row; | ||
| flex-wrap: wrap; | ||
| gap: 8px; | ||
| height: 100%; | ||
| padding: 8px; | ||
| } | ||
|
|
||
| .view-wrapper { | ||
| display: flex; | ||
| flex-direction: column; | ||
| height: calc(50% - 4px); | ||
| width: 100%; | ||
| } | ||
|
|
||
| @container views (width > 1024px) { | ||
| .view-wrapper { | ||
| height: 100%; | ||
| width: calc(50% - 4px); | ||
| } | ||
| } | ||
|
|
||
| .view-label { | ||
| color: #0090ff; | ||
| display: flex; | ||
| font-size: 12px; | ||
| font-weight: bold; | ||
| justify-content: space-between; | ||
| margin-inline: 16px; | ||
| } | ||
|
|
||
| .view { | ||
| border: solid #0090ff 1px; | ||
| border-radius: 16px; | ||
| flex: 1; | ||
| height: 0; | ||
| padding: 8px; | ||
| } | ||
|
|
||
| .view .bn-container { | ||
| height: 100%; | ||
| margin: 0; | ||
| max-width: none; | ||
| padding: 0; | ||
| } | ||
|
|
||
| .view .bn-editor { | ||
| height: 100%; | ||
| overflow: auto; | ||
| } |
36 changes: 36 additions & 0 deletions
36
examples/05-interoperability/09-blocks-to-html-static-render/tsconfig.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| { | ||
| "__comment": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY", | ||
| "compilerOptions": { | ||
| "target": "ESNext", | ||
| "useDefineForClassFields": true, | ||
| "lib": [ | ||
| "DOM", | ||
| "DOM.Iterable", | ||
| "ESNext" | ||
| ], | ||
| "allowJs": false, | ||
| "skipLibCheck": true, | ||
| "esModuleInterop": false, | ||
| "allowSyntheticDefaultImports": true, | ||
| "strict": true, | ||
| "forceConsistentCasingInFileNames": true, | ||
| "module": "ESNext", | ||
| "moduleResolution": "bundler", | ||
| "resolveJsonModule": true, | ||
| "isolatedModules": true, | ||
| "noEmit": true, | ||
| "jsx": "react-jsx", | ||
| "composite": true | ||
| }, | ||
| "include": [ | ||
| "." | ||
| ], | ||
| "__ADD_FOR_LOCAL_DEV_references": [ | ||
| { | ||
| "path": "../../../packages/core/" | ||
| }, | ||
| { | ||
| "path": "../../../packages/react/" | ||
| } | ||
| ] | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would bet that if we made this a local video that the vite server served out of the public folder, that we'd have less flaky tests since it wouldn't depend on the network. Same for images