Skip to content

Commit 563e5bc

Browse files
authored
fix: set width attribute on image and video elements in editor render (#2740)
* fix: set width attribute on image element in editor render When the editor is rendered with editable: false, the <img> tag did not include a width attribute even though the block's previewWidth prop was set — the width was only applied as inline style on the wrapper. This prevented the browser from reserving space before the image loaded (CLS) and made the rendered DOM lossy for downstream consumers reading innerHTML. Apply previewWidth directly to the <img> element in the editor render path, mirroring what imageToExternalHTML and the core Video block already do. CSS width: 100% on .bn-visual-media still controls layout so resize behavior is unaffected. Fixes #2726 * fix: also apply width attribute to video block Apply the same fix as the image block to video: - React VideoPreview now sets width on the <video> element so read-only rendering includes it. - React VideoToExternalHTML now serializes previewWidth (it was previously dropped entirely on export). - Core video render path guards `video.width = previewWidth` against undefined (assigning undefined to a numeric DOM property coerces to 0). Audio and File blocks don't have a previewWidth prop, so no change is needed there. Refs #2726 * test: update snapshots for image/video width fix - Image snapshots now include the new width attribute on the <img> element when previewWidth is set. - Video snapshots no longer include width="0" since the core video render now guards against an undefined previewWidth. Refs #2726 * fix: guard previewWidth to avoid emitting width="0" on video elements
1 parent 792c439 commit 563e5bc

15 files changed

Lines changed: 80 additions & 15 deletions

File tree

packages/core/src/blocks/Image/block.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ export const imageRender =
122122
image.alt = block.props.name || "";
123123
image.contentEditable = "false";
124124
image.draggable = false;
125+
if (block.props.previewWidth) {
126+
image.width = block.props.previewWidth;
127+
}
125128
imageWrapper.appendChild(image);
126129

127130
return createResizableFileBlockWrapper(

packages/core/src/blocks/Video/block.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ export const createVideoBlockSpec = createBlockSpec(
9292
video.controls = true;
9393
video.contentEditable = "false";
9494
video.draggable = false;
95-
video.width = block.props.previewWidth;
95+
if (block.props.previewWidth) {
96+
video.width = block.props.previewWidth;
97+
}
9698
videoWrapper.appendChild(video);
9799

98100
return createResizableFileBlockWrapper(

packages/react/src/blocks/Image/block.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const ImagePreview = (
3232
: resolved.downloadUrl
3333
}
3434
alt={alt}
35+
width={props.block.props.previewWidth}
3536
contentEditable={false}
3637
draggable={false}
3738
/>

packages/react/src/blocks/Video/block.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const VideoPreview = (
2727
: resolved.downloadUrl
2828
}
2929
controls={true}
30+
width={props.block.props.previewWidth || undefined}
3031
contentEditable={false}
3132
draggable={false}
3233
/>
@@ -44,7 +45,7 @@ export const VideoToExternalHTML = (
4445
}
4546

4647
const video = props.block.props.showPreview ? (
47-
<video src={props.block.props.url} />
48+
<video src={props.block.props.url} width={props.block.props.previewWidth || undefined} />
4849
) : (
4950
<a href={props.block.props.url}>
5051
{props.block.props.name || props.block.props.url}

packages/server-util/src/context/__snapshots__/ServerBlockNoteEditor.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`Test ServerBlockNoteEditor > converts to HTML (blocksToFullHTML) 1`] = `"<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1"><div class="bn-block-content" data-content-type="heading" data-background-color="blue" data-text-color="yellow" data-text-alignment="right" data-level="2"><h2 class="bn-inline-content"><strong><u>Heading </u></strong><em><s>2</s></em></h2></div><div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="2"><div class="bn-block" data-node-type="blockContainer" data-id="2"><div class="bn-block-content" data-content-type="paragraph" data-background-color="red"><p class="bn-inline-content">Paragraph</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="3"><div class="bn-block" data-node-type="blockContainer" data-id="3"><div class="bn-block-content" data-content-type="bulletListItem"><p class="bn-inline-content">list item</p></div></div></div></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="4"><div class="bn-block" data-node-type="blockContainer" data-id="4"><div class="bn-block-content" data-content-type="image" data-name="Example" data-url="exampleURL" data-caption="Caption" data-preview-width="256" data-file-block=""><figure class="bn-file-block-content-wrapper" style="position: relative; width: 256px;"><div class="bn-visual-media-wrapper"><img class="bn-visual-media" src="exampleURL" alt="Example" draggable="false"><div class="bn-resize-handle" style="left: 4px; display: none;"></div><div class="bn-resize-handle" style="right: 4px; display: none;"></div></div><figcaption class="bn-file-caption">Caption</figcaption></figure></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="5"><div class="bn-block" data-node-type="blockContainer" data-id="5"><div class="bn-block-content" data-content-type="image" data-name="Example" data-url="exampleURL" data-caption="Caption" data-show-preview="false" data-preview-width="256" data-file-block=""><figure class="bn-file-block-content-wrapper" style="position: relative;"><div class="bn-file-name-with-icon"><div class="bn-file-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M3 8L9.00319 2H19.9978C20.5513 2 21 2.45531 21 2.9918V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5501 3 20.9932V8ZM10 4V9H5V20H19V4H10Z"></path></svg></div><p class="bn-file-name">Example</p></div><figcaption class="bn-file-caption">Caption</figcaption></figure></div></div></div></div>"`;
3+
exports[`Test ServerBlockNoteEditor > converts to HTML (blocksToFullHTML) 1`] = `"<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1"><div class="bn-block-content" data-content-type="heading" data-background-color="blue" data-text-color="yellow" data-text-alignment="right" data-level="2"><h2 class="bn-inline-content"><strong><u>Heading </u></strong><em><s>2</s></em></h2></div><div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="2"><div class="bn-block" data-node-type="blockContainer" data-id="2"><div class="bn-block-content" data-content-type="paragraph" data-background-color="red"><p class="bn-inline-content">Paragraph</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="3"><div class="bn-block" data-node-type="blockContainer" data-id="3"><div class="bn-block-content" data-content-type="bulletListItem"><p class="bn-inline-content">list item</p></div></div></div></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="4"><div class="bn-block" data-node-type="blockContainer" data-id="4"><div class="bn-block-content" data-content-type="image" data-name="Example" data-url="exampleURL" data-caption="Caption" data-preview-width="256" data-file-block=""><figure class="bn-file-block-content-wrapper" style="position: relative; width: 256px;"><div class="bn-visual-media-wrapper"><img class="bn-visual-media" src="exampleURL" alt="Example" draggable="false" width="256"><div class="bn-resize-handle" style="left: 4px; display: none;"></div><div class="bn-resize-handle" style="right: 4px; display: none;"></div></div><figcaption class="bn-file-caption">Caption</figcaption></figure></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="5"><div class="bn-block" data-node-type="blockContainer" data-id="5"><div class="bn-block-content" data-content-type="image" data-name="Example" data-url="exampleURL" data-caption="Caption" data-show-preview="false" data-preview-width="256" data-file-block=""><figure class="bn-file-block-content-wrapper" style="position: relative;"><div class="bn-file-name-with-icon"><div class="bn-file-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M3 8L9.00319 2H19.9978C20.5513 2 21 2.45531 21 2.9918V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5501 3 20.9932V8ZM10 4V9H5V20H19V4H10Z"></path></svg></div><p class="bn-file-name">Example</p></div><figcaption class="bn-file-caption">Caption</figcaption></figure></div></div></div></div>"`;
44

55
exports[`Test ServerBlockNoteEditor > converts to and from HTML (blocksToHTMLLossy) 1`] = `"<h2 style="background-color: rgb(221, 235, 241); color: rgb(223, 171, 1); text-align: right;" data-background-color="blue" data-text-color="yellow" data-text-alignment="right" data-level="2"><strong><u>Heading </u></strong><em><s>2</s></em></h2><p style="background-color: rgb(251, 228, 228);" data-background-color="red" data-nesting-level="1">Paragraph</p><ul><li data-nesting-level="1"><p class="bn-inline-content">list item</p></li></ul><figure data-name="Example" data-url="exampleURL" data-caption="Caption" data-preview-width="256"><img src="exampleURL" alt="Example" width="256"><figcaption>Caption</figcaption></figure><div data-name="Example" data-url="exampleURL" data-caption="Caption" data-show-preview="false" data-preview-width="256"><a href="exampleURL">Example</a><p>Caption</p></div>"`;
66

tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/basic.html

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
style="position: relative; width: 256px;"
1616
>
1717
<div class="bn-visual-media-wrapper">
18-
<img class="bn-visual-media" src="exampleURL" alt="example" draggable="false" />
18+
<img
19+
class="bn-visual-media"
20+
src="exampleURL"
21+
alt="example"
22+
draggable="false"
23+
width="256"
24+
/>
1925
<div class="bn-resize-handle" style="left: 4px; display: none;"></div>
2026
<div class="bn-resize-handle" style="right: 4px; display: none;"></div>
2127
</div>

tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/nested.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@
1414
style="position: relative; width: 256px;"
1515
>
1616
<div class="bn-visual-media-wrapper">
17-
<img class="bn-visual-media" src="exampleURL" alt="" draggable="false" />
17+
<img
18+
class="bn-visual-media"
19+
src="exampleURL"
20+
alt=""
21+
draggable="false"
22+
width="256"
23+
/>
1824
<div class="bn-resize-handle" style="left: 4px; display: none;"></div>
1925
<div class="bn-resize-handle" style="right: 4px; display: none;"></div>
2026
</div>
@@ -37,7 +43,13 @@
3743
style="position: relative; width: 256px;"
3844
>
3945
<div class="bn-visual-media-wrapper">
40-
<img class="bn-visual-media" src="exampleURL" alt="" draggable="false" />
46+
<img
47+
class="bn-visual-media"
48+
src="exampleURL"
49+
alt=""
50+
draggable="false"
51+
width="256"
52+
/>
4153
<div class="bn-resize-handle" style="left: 4px; display: none;"></div>
4254
<div class="bn-resize-handle" style="right: 4px; display: none;"></div>
4355
</div>

tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noCaption.html

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@
1414
style="position: relative; width: 256px;"
1515
>
1616
<div class="bn-visual-media-wrapper">
17-
<img class="bn-visual-media" src="exampleURL" alt="example" draggable="false" />
17+
<img
18+
class="bn-visual-media"
19+
src="exampleURL"
20+
alt="example"
21+
draggable="false"
22+
width="256"
23+
/>
1824
<div class="bn-resize-handle" style="left: 4px; display: none;"></div>
1925
<div class="bn-resize-handle" style="right: 4px; display: none;"></div>
2026
</div>

tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noName.html

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@
1414
style="position: relative; width: 256px;"
1515
>
1616
<div class="bn-visual-media-wrapper">
17-
<img class="bn-visual-media" src="exampleURL" alt="" draggable="false" />
17+
<img
18+
class="bn-visual-media"
19+
src="exampleURL"
20+
alt=""
21+
draggable="false"
22+
width="256"
23+
/>
1824
<div class="bn-resize-handle" style="left: 4px; display: none;"></div>
1925
<div class="bn-resize-handle" style="right: 4px; display: none;"></div>
2026
</div>

tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/video.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm"
1818
controls=""
1919
draggable="false"
20-
width="0"
2120
></video>
2221
<div class="bn-resize-handle" style="left: 4px; display: none;"></div>
2322
<div class="bn-resize-handle" style="right: 4px; display: none;"></div>

0 commit comments

Comments
 (0)