diff --git a/examples/06-custom-schema/04-pdf-file-block/src/PDF.tsx b/examples/06-custom-schema/04-pdf-file-block/src/PDF.tsx index e43439100f..081b3b0b17 100644 --- a/examples/06-custom-schema/04-pdf-file-block/src/PDF.tsx +++ b/examples/06-custom-schema/04-pdf-file-block/src/PDF.tsx @@ -2,7 +2,7 @@ import { FileBlockConfig } from "@blocknote/core"; import { createReactBlockSpec, ReactCustomBlockRenderProps, - ResizableFileBlockWrapper, + ResizableFileWithCaption, } from "@blocknote/react"; import { RiFilePdfFill } from "react-icons/ri"; @@ -14,17 +14,15 @@ export const PDFPreview = ( ReactCustomBlockRenderProps, "contentRef" >, -) => { - return ( - props.editor.setTextCursorPosition(props.block)} - /> - ); -}; +) => ( + props.editor.setTextCursorPosition(props.block)} + /> +); export const PDF = createReactBlockSpec( { @@ -52,13 +50,13 @@ export const PDF = createReactBlockSpec( }, { render: (props) => ( - } > - + ), }, ); diff --git a/packages/core/src/blocks/AudioBlockContent/AudioBlockContent.ts b/packages/core/src/blocks/AudioBlockContent/AudioBlockContent.ts index 7a3e0101fe..3832e79207 100644 --- a/packages/core/src/blocks/AudioBlockContent/AudioBlockContent.ts +++ b/packages/core/src/blocks/AudioBlockContent/AudioBlockContent.ts @@ -9,7 +9,7 @@ import { import { defaultProps } from "../defaultProps.js"; import { parseFigureElement } from "../FileBlockContent/helpers/parse/parseFigureElement.js"; -import { createFileBlockWrapper } from "../FileBlockContent/helpers/render/createFileBlockWrapper.js"; +import { createFileWithCaption } from "../FileBlockContent/helpers/render/createFileWithCaption.js"; import { createFigureWithCaption } from "../FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.js"; import { createLinkWithCaption } from "../FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.js"; import { parseAudioElement } from "./parseAudioElement.js"; @@ -65,10 +65,10 @@ export const audioRender = ( audio.contentEditable = "false"; audio.draggable = false; - return createFileBlockWrapper( + return createFileWithCaption( block, editor, - { dom: audio }, + audio, editor.dictionary.file_blocks.audio.add_button_text, icon.firstElementChild as HTMLElement, ); diff --git a/packages/core/src/blocks/FileBlockContent/FileBlockContent.ts b/packages/core/src/blocks/FileBlockContent/FileBlockContent.ts index 433487d8e0..6db4614cdb 100644 --- a/packages/core/src/blocks/FileBlockContent/FileBlockContent.ts +++ b/packages/core/src/blocks/FileBlockContent/FileBlockContent.ts @@ -8,7 +8,7 @@ import { import { defaultProps } from "../defaultProps.js"; import { parseEmbedElement } from "./helpers/parse/parseEmbedElement.js"; import { parseFigureElement } from "./helpers/parse/parseFigureElement.js"; -import { createFileBlockWrapper } from "./helpers/render/createFileBlockWrapper.js"; +import { createFileWithCaption } from "./helpers/render/createFileWithCaption.js"; import { createLinkWithCaption } from "./helpers/toExternalHTML/createLinkWithCaption.js"; export const filePropSchema = { @@ -38,7 +38,7 @@ export const fileRender = ( block: BlockFromConfig, editor: BlockNoteEditor, ) => { - return createFileBlockWrapper(block, editor); + return createFileWithCaption(block, editor); }; export const fileParse = (element: HTMLElement) => { diff --git a/packages/core/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.ts b/packages/core/src/blocks/FileBlockContent/helpers/render/createFileWithCaption.ts similarity index 74% rename from packages/core/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.ts rename to packages/core/src/blocks/FileBlockContent/helpers/render/createFileWithCaption.ts index 02af916f2d..8ee110b995 100644 --- a/packages/core/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.ts +++ b/packages/core/src/blocks/FileBlockContent/helpers/render/createFileWithCaption.ts @@ -7,19 +7,23 @@ import { import { createAddFileButton } from "./createAddFileButton.js"; import { createFileNameWithIcon } from "./createFileNameWithIcon.js"; -export const createFileBlockWrapper = ( +export const createFileWithCaption = ( block: BlockFromConfig, editor: BlockNoteEditor< BlockSchemaWithBlock, any, any >, - element?: { dom: HTMLElement; destroy?: () => void }, + element?: HTMLElement, buttonText?: string, buttonIcon?: HTMLElement, ) => { - const wrapper = document.createElement("div"); - wrapper.className = "bn-file-block-content-wrapper"; + const fileWithCaption = document.createElement("div"); + fileWithCaption.className = "bn-file-with-caption"; + + const file = document.createElement("div"); + file.className = "bn-file"; + fileWithCaption.appendChild(file); // Show the add file button if the file has not been uploaded yet. Change to // show a loader if a file upload for the block begins. @@ -30,42 +34,41 @@ export const createFileBlockWrapper = ( buttonText, buttonIcon, ); - wrapper.appendChild(addFileButton.dom); const destroyUploadStartHandler = editor.onUploadStart((blockId) => { if (blockId === block.id) { - wrapper.removeChild(addFileButton.dom); - const loading = document.createElement("div"); loading.className = "bn-file-loading-preview"; loading.textContent = "Loading..."; - wrapper.appendChild(loading); + addFileButton.dom.replaceWith(loading); } }); return { - dom: wrapper, + dom: addFileButton.dom, destroy: () => { destroyUploadStartHandler(); - addFileButton.destroy(); + addFileButton.destroy?.(); }, }; } - const ret: { dom: HTMLElement; destroy?: () => void } = { dom: wrapper }; + const ret: { dom: HTMLElement; destroy?: () => void } = { + dom: fileWithCaption, + }; // Show the file preview, or the file name and icon. if (block.props.showPreview === false || !element) { // Show file name and icon. const fileNameWithIcon = createFileNameWithIcon(block); - wrapper.appendChild(fileNameWithIcon.dom); + file.appendChild(fileNameWithIcon.dom); ret.destroy = () => { fileNameWithIcon.destroy?.(); }; } else { // Show file preview. - wrapper.appendChild(element.dom); + file.appendChild(element); } // Show the caption if there is one. @@ -73,7 +76,7 @@ export const createFileBlockWrapper = ( const caption = document.createElement("p"); caption.className = "bn-file-caption"; caption.textContent = block.props.caption; - wrapper.appendChild(caption); + fileWithCaption.appendChild(caption); } return ret; diff --git a/packages/core/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.ts b/packages/core/src/blocks/FileBlockContent/helpers/render/createResizableFileWithCaption.ts similarity index 66% rename from packages/core/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.ts rename to packages/core/src/blocks/FileBlockContent/helpers/render/createResizableFileWithCaption.ts index b4c4ae95d7..ef638e70c6 100644 --- a/packages/core/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.ts +++ b/packages/core/src/blocks/FileBlockContent/helpers/render/createResizableFileWithCaption.ts @@ -1,30 +1,30 @@ import type { BlockNoteEditor } from "../../../../editor/BlockNoteEditor.js"; import { BlockFromConfig, FileBlockConfig } from "../../../../schema/index.js"; -import { createFileBlockWrapper } from "./createFileBlockWrapper.js"; +import { createFileWithCaption } from "./createFileWithCaption.js"; -export const createResizableFileBlockWrapper = ( +export const createResizableFileWithCaption = ( block: BlockFromConfig, editor: BlockNoteEditor, - element: { dom: HTMLElement; destroy?: () => void }, - resizeHandlesContainerElement: HTMLElement, + element: HTMLElement, buttonText: string, buttonIcon: HTMLElement, ): { dom: HTMLElement; destroy: () => void } => { - const { dom, destroy } = createFileBlockWrapper( + const { dom, destroy } = createFileWithCaption( block, editor, element, buttonText, buttonIcon, ); - const wrapper = dom; + const fileWithCaption = dom; if (block.props.url && block.props.showPreview) { if (block.props.previewWidth) { - wrapper.style.width = `${block.props.previewWidth}px`; + fileWithCaption.style.width = `${block.props.previewWidth}px`; } else { - wrapper.style.width = "fit-content"; + fileWithCaption.style.width = "fit-content"; } } + const file = fileWithCaption.querySelector(".bn-file") as HTMLElement; const leftResizeHandle = document.createElement("div"); leftResizeHandle.className = "bn-resize-handle"; @@ -33,6 +33,15 @@ export const createResizableFileBlockWrapper = ( rightResizeHandle.className = "bn-resize-handle"; rightResizeHandle.style.right = "4px"; + // This element ensures `mousemove` and `mouseup` events are captured while + // resizing when the cursor is over the wrapper content. This is because + // embeds are treated as separate HTML documents, so if the content is an + // embed, the events will only fire within that document. + const eventCaptureElement = document.createElement("div"); + eventCaptureElement.style.position = "absolute"; + eventCaptureElement.style.height = "100%"; + eventCaptureElement.style.width = "100%"; + // Temporary parameters set when the user begins resizing the element, used to // calculate the new width of the element. let resizeParams: @@ -50,11 +59,11 @@ export const createResizableFileBlockWrapper = ( if (!resizeParams) { if ( !editor.isEditable && - resizeHandlesContainerElement.contains(leftResizeHandle) && - resizeHandlesContainerElement.contains(rightResizeHandle) + file.contains(leftResizeHandle) && + file.contains(rightResizeHandle) ) { - resizeHandlesContainerElement.removeChild(leftResizeHandle); - resizeHandlesContainerElement.removeChild(rightResizeHandle); + file.removeChild(leftResizeHandle); + file.removeChild(rightResizeHandle); } return; @@ -95,7 +104,7 @@ export const createResizableFileBlockWrapper = ( Math.max(newWidth, minWidth), editor.domElement?.firstElementChild?.clientWidth || Number.MAX_VALUE, ); - wrapper.style.width = `${width}px`; + fileWithCaption.style.width = `${width}px`; }; // Stops mouse movements from resizing the element and updates the block's // `width` prop to the new value. @@ -103,13 +112,13 @@ export const createResizableFileBlockWrapper = ( // Hides the drag handles if the cursor is no longer over the element. if ( (!event.target || - !wrapper.contains(event.target as Node) || + !file.contains(event.target as Node) || !editor.isEditable) && - resizeHandlesContainerElement.contains(leftResizeHandle) && - resizeHandlesContainerElement.contains(rightResizeHandle) + file.contains(leftResizeHandle) && + file.contains(rightResizeHandle) ) { - resizeHandlesContainerElement.removeChild(leftResizeHandle); - resizeHandlesContainerElement.removeChild(rightResizeHandle); + file.removeChild(leftResizeHandle); + file.removeChild(rightResizeHandle); } if (!resizeParams) { @@ -118,6 +127,10 @@ export const createResizableFileBlockWrapper = ( resizeParams = undefined; + if (file.contains(eventCaptureElement)) { + file.removeChild(eventCaptureElement); + } + editor.updateBlock(block, { props: { previewWidth: width, @@ -127,15 +140,20 @@ export const createResizableFileBlockWrapper = ( // Shows the resize handles when hovering over the wrapper with the cursor. const wrapperMouseEnterHandler = () => { + if (resizeParams) { + return; + } + if (editor.isEditable) { - resizeHandlesContainerElement.appendChild(leftResizeHandle); - resizeHandlesContainerElement.appendChild(rightResizeHandle); + file.appendChild(leftResizeHandle); + file.appendChild(rightResizeHandle); } }; // Hides the resize handles when the cursor leaves the wrapper, unless the // cursor moves to one of the resize handles. const wrapperMouseLeaveHandler = (event: MouseEvent) => { if ( + resizeParams || event.relatedTarget === leftResizeHandle || event.relatedTarget === rightResizeHandle ) { @@ -148,11 +166,11 @@ export const createResizableFileBlockWrapper = ( if ( editor.isEditable && - resizeHandlesContainerElement.contains(leftResizeHandle) && - resizeHandlesContainerElement.contains(rightResizeHandle) + file.contains(leftResizeHandle) && + file.contains(rightResizeHandle) ) { - resizeHandlesContainerElement.removeChild(leftResizeHandle); - resizeHandlesContainerElement.removeChild(rightResizeHandle); + file.removeChild(leftResizeHandle); + file.removeChild(rightResizeHandle); } }; @@ -161,26 +179,34 @@ export const createResizableFileBlockWrapper = ( const leftResizeHandleMouseDownHandler = (event: MouseEvent) => { event.preventDefault(); + if (!file.contains(eventCaptureElement)) { + file.appendChild(eventCaptureElement); + } + resizeParams = { handleUsed: "left", - initialWidth: wrapper.clientWidth, + initialWidth: fileWithCaption.clientWidth, initialClientX: event.clientX, }; }; const rightResizeHandleMouseDownHandler = (event: MouseEvent) => { event.preventDefault(); + if (!file.contains(eventCaptureElement)) { + file.appendChild(eventCaptureElement); + } + resizeParams = { handleUsed: "right", - initialWidth: wrapper.clientWidth, + initialWidth: fileWithCaption.clientWidth, initialClientX: event.clientX, }; }; window.addEventListener("mousemove", windowMouseMoveHandler); window.addEventListener("mouseup", windowMouseUpHandler); - wrapper.addEventListener("mouseenter", wrapperMouseEnterHandler); - wrapper.addEventListener("mouseleave", wrapperMouseLeaveHandler); + fileWithCaption.addEventListener("mouseenter", wrapperMouseEnterHandler); + fileWithCaption.addEventListener("mouseleave", wrapperMouseLeaveHandler); leftResizeHandle.addEventListener( "mousedown", leftResizeHandleMouseDownHandler, @@ -191,13 +217,19 @@ export const createResizableFileBlockWrapper = ( ); return { - dom: wrapper, + dom: fileWithCaption, destroy: () => { destroy?.(); window.removeEventListener("mousemove", windowMouseMoveHandler); window.removeEventListener("mouseup", windowMouseUpHandler); - wrapper.removeEventListener("mouseenter", wrapperMouseEnterHandler); - wrapper.removeEventListener("mouseleave", wrapperMouseLeaveHandler); + fileWithCaption.removeEventListener( + "mouseenter", + wrapperMouseEnterHandler, + ); + fileWithCaption.removeEventListener( + "mouseleave", + wrapperMouseLeaveHandler, + ); leftResizeHandle.removeEventListener( "mousedown", leftResizeHandleMouseDownHandler, diff --git a/packages/core/src/blocks/ImageBlockContent/ImageBlockContent.ts b/packages/core/src/blocks/ImageBlockContent/ImageBlockContent.ts index 32b7338640..2a419f7e52 100644 --- a/packages/core/src/blocks/ImageBlockContent/ImageBlockContent.ts +++ b/packages/core/src/blocks/ImageBlockContent/ImageBlockContent.ts @@ -10,7 +10,7 @@ import { defaultProps } from "../defaultProps.js"; import { parseFigureElement } from "../FileBlockContent/helpers/parse/parseFigureElement.js"; import { createFigureWithCaption } from "../FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.js"; import { createLinkWithCaption } from "../FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.js"; -import { createResizableFileBlockWrapper } from "../FileBlockContent/helpers/render/createResizableFileBlockWrapper.js"; +import { createResizableFileWithCaption } from "../FileBlockContent/helpers/render/createResizableFileWithCaption.js"; import { parseImageElement } from "./parseImageElement.js"; export const FILE_IMAGE_ICON_SVG = @@ -57,9 +57,6 @@ export const imageRender = ( const icon = document.createElement("div"); icon.innerHTML = FILE_IMAGE_ICON_SVG; - const imageWrapper = document.createElement("div"); - imageWrapper.className = "bn-visual-media-wrapper"; - const image = document.createElement("img"); image.className = "bn-visual-media"; if (editor.resolveFileUrl) { @@ -73,13 +70,11 @@ export const imageRender = ( image.alt = block.props.name || block.props.caption || "BlockNote image"; image.contentEditable = "false"; image.draggable = false; - imageWrapper.appendChild(image); - return createResizableFileBlockWrapper( + return createResizableFileWithCaption( block, editor, - { dom: imageWrapper }, - imageWrapper, + image, editor.dictionary.file_blocks.image.add_button_text, icon.firstElementChild as HTMLElement, ); diff --git a/packages/core/src/blocks/VideoBlockContent/VideoBlockContent.ts b/packages/core/src/blocks/VideoBlockContent/VideoBlockContent.ts index af65e3d0df..f2133c2d9c 100644 --- a/packages/core/src/blocks/VideoBlockContent/VideoBlockContent.ts +++ b/packages/core/src/blocks/VideoBlockContent/VideoBlockContent.ts @@ -10,7 +10,7 @@ import { defaultProps } from "../defaultProps.js"; import { parseFigureElement } from "../FileBlockContent/helpers/parse/parseFigureElement.js"; import { createFigureWithCaption } from "../FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.js"; import { createLinkWithCaption } from "../FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.js"; -import { createResizableFileBlockWrapper } from "../FileBlockContent/helpers/render/createResizableFileBlockWrapper.js"; +import { createResizableFileWithCaption } from "../FileBlockContent/helpers/render/createResizableFileWithCaption.js"; import { parseVideoElement } from "./parseVideoElement.js"; export const FILE_VIDEO_ICON_SVG = @@ -57,9 +57,6 @@ export const videoRender = ( const icon = document.createElement("div"); icon.innerHTML = FILE_VIDEO_ICON_SVG; - const videoWrapper = document.createElement("div"); - videoWrapper.className = "bn-visual-media-wrapper"; - const video = document.createElement("video"); video.className = "bn-visual-media"; if (editor.resolveFileUrl) { @@ -72,14 +69,11 @@ export const videoRender = ( video.controls = true; video.contentEditable = "false"; video.draggable = false; - video.width = block.props.previewWidth; - videoWrapper.appendChild(video); - return createResizableFileBlockWrapper( + return createResizableFileWithCaption( block, editor, - { dom: videoWrapper }, - videoWrapper, + video, editor.dictionary.file_blocks.video.add_button_text, icon.firstElementChild as HTMLElement, ); diff --git a/packages/core/src/editor/Block.css b/packages/core/src/editor/Block.css index 88a7c6d57c..7ebb8b6b59 100644 --- a/packages/core/src/editor/Block.css +++ b/packages/core/src/editor/Block.css @@ -254,14 +254,6 @@ NESTED BLOCKS text-decoration: line-through; } -.bn-block-content[data-text-alignment="center"] { - justify-content: center; -} - -.bn-block-content[data-text-alignment="right"] { - justify-content: flex-end; -} - /* Toggle */ .bn-block-content:has(.bn-toggle-wrapper) > div { display: flex; @@ -460,7 +452,7 @@ NESTED BLOCKS /* FILES */ /* Element that wraps content for all file blocks */ -[data-file-block] .bn-file-block-content-wrapper { +[data-file-block] .bn-file-with-caption { cursor: pointer; display: flex; flex-direction: column; @@ -468,8 +460,8 @@ NESTED BLOCKS } /* Add block button & default element (name with icon) */ -[data-file-block] .bn-file-block-content-wrapper:has(.bn-add-file-button), -[data-file-block] .bn-file-block-content-wrapper:has(.bn-file-name-with-icon) { +[data-file-block] .bn-file-with-caption:has(.bn-add-file-button), +[data-file-block] .bn-file-with-caption:has(.bn-file-name-with-icon) { width: 100%; } @@ -478,14 +470,14 @@ NESTED BLOCKS background-color: rgb(242, 241, 238); border-radius: 4px; color: rgb(125, 121, 122); + cursor: pointer; display: flex; gap: 10px; padding: 12px; + width: 100%; } -.bn-editor[contenteditable="true"] [data-file-block] .bn-add-file-button:hover, -[data-file-block] .bn-file-name-with-icon:hover, -.ProseMirror-selectednode .bn-file-name-with-icon { +.bn-editor[contenteditable="true"] [data-file-block] .bn-add-file-button:hover { background-color: rgb(225, 225, 225); } @@ -529,7 +521,7 @@ NESTED BLOCKS } /* Visual media file blocks, e.g. images & videos */ -[data-file-block] .bn-visual-media-wrapper { +[data-file-block] .bn-file { display: flex; align-items: center; position: relative; @@ -542,7 +534,7 @@ NESTED BLOCKS } /* Block-specific styles */ -[data-content-type="audio"] > .bn-file-block-content-wrapper, +[data-content-type="audio"] > .bn-file-with-caption, .bn-audio { width: 100%; } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 74f91bee5c..95da2432a8 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -16,9 +16,9 @@ export * from "./blocks/FileBlockContent/FileBlockContent.js"; export * from "./blocks/FileBlockContent/helpers/parse/parseEmbedElement.js"; export * from "./blocks/FileBlockContent/helpers/parse/parseFigureElement.js"; export * from "./blocks/FileBlockContent/helpers/render/createAddFileButton.js"; -export * from "./blocks/FileBlockContent/helpers/render/createFileBlockWrapper.js"; +export * from "./blocks/FileBlockContent/helpers/render/createFileWithCaption.js"; export * from "./blocks/FileBlockContent/helpers/render/createFileNameWithIcon.js"; -export * from "./blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.js"; +export * from "./blocks/FileBlockContent/helpers/render/createResizableFileWithCaption.js"; export * from "./blocks/FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.js"; export * from "./blocks/FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.js"; export * from "./blocks/FileBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.js"; diff --git a/packages/react/src/blocks/AudioBlockContent/AudioBlockContent.tsx b/packages/react/src/blocks/AudioBlockContent/AudioBlockContent.tsx index b602aaa971..9ef53192c1 100644 --- a/packages/react/src/blocks/AudioBlockContent/AudioBlockContent.tsx +++ b/packages/react/src/blocks/AudioBlockContent/AudioBlockContent.tsx @@ -8,7 +8,7 @@ import { } from "../../schema/ReactBlockSpec.js"; import { useResolveUrl } from "../FileBlockContent/useResolveUrl.js"; import { FigureWithCaption } from "../FileBlockContent/helpers/toExternalHTML/FigureWithCaption.js"; -import { FileBlockWrapper } from "../FileBlockContent/helpers/render/FileBlockWrapper.js"; +import { FileWithCaption } from "../FileBlockContent/helpers/render/FileWithCaption.js"; import { LinkWithCaption } from "../FileBlockContent/helpers/toExternalHTML/LinkWithCaption.js"; export const AudioPreview = ( @@ -71,13 +71,13 @@ export const AudioBlock = ( props: ReactCustomBlockRenderProps, ) => { return ( - } > - + ); }; diff --git a/packages/react/src/blocks/FileBlockContent/FileBlockContent.tsx b/packages/react/src/blocks/FileBlockContent/FileBlockContent.tsx index 78bac8230b..e31f5cc8bb 100644 --- a/packages/react/src/blocks/FileBlockContent/FileBlockContent.tsx +++ b/packages/react/src/blocks/FileBlockContent/FileBlockContent.tsx @@ -4,7 +4,7 @@ import { createReactBlockSpec, ReactCustomBlockRenderProps, } from "../../schema/ReactBlockSpec.js"; -import { FileBlockWrapper } from "./helpers/render/FileBlockWrapper.js"; +import { FileWithCaption } from "./helpers/render/FileWithCaption.js"; import { LinkWithCaption } from "./helpers/toExternalHTML/LinkWithCaption.js"; export const FileToExternalHTML = ( @@ -37,7 +37,7 @@ export const FileToExternalHTML = ( export const FileBlock = ( props: ReactCustomBlockRenderProps, ) => { - return ; + return ; }; export const ReactFileBlock = createReactBlockSpec(fileBlockConfig, { diff --git a/packages/react/src/blocks/FileBlockContent/helpers/render/FileBlockWrapper.tsx b/packages/react/src/blocks/FileBlockContent/helpers/render/FileWithCaption.tsx similarity index 51% rename from packages/react/src/blocks/FileBlockContent/helpers/render/FileBlockWrapper.tsx rename to packages/react/src/blocks/FileBlockContent/helpers/render/FileWithCaption.tsx index dc47c288b4..a7536872a6 100644 --- a/packages/react/src/blocks/FileBlockContent/helpers/render/FileBlockWrapper.tsx +++ b/packages/react/src/blocks/FileBlockContent/helpers/render/FileWithCaption.tsx @@ -6,7 +6,7 @@ import { ReactCustomBlockRenderProps } from "../../../../schema/ReactBlockSpec.j import { AddFileButton } from "./AddFileButton.js"; import { FileNameWithIcon } from "./FileNameWithIcon.js"; -export const FileBlockWrapper = ( +export const FileWithCaption = ( props: Omit< ReactCustomBlockRenderProps, "contentRef" @@ -24,35 +24,35 @@ export const FileBlockWrapper = ( ) => { const showLoader = useUploadLoading(props.block.id); + if (showLoader) { + return
Loading...
; + } + + if (props.block.props.url === "") { + return ; + } + return (
- {showLoader ? ( - // Show loader while a file is being uploaded. -
Loading...
- ) : props.block.props.url === "" ? ( - // Show the add file button if the file has not been uploaded yet. - - ) : ( - // Show the file preview, or the file name and icon. - <> - {props.block.props.showPreview === false || !props.children ? ( - // Show file name and icon. - - ) : ( - // Show preview. - props.children - )} - {props.block.props.caption && ( - // Show the caption if there is one. -

{props.block.props.caption}

- )} - - )} + {/* Show the file preview, or the file name and icon. */} + <> + {props.block.props.showPreview === false || !props.children ? ( + // Show file name and icon. + + ) : ( + // Show preview. + props.children + )} + {props.block.props.caption && ( + // Show the caption if there is one. +

{props.block.props.caption}

+ )} +
); }; diff --git a/packages/react/src/blocks/FileBlockContent/helpers/render/ResizableFileBlockWrapper.tsx b/packages/react/src/blocks/FileBlockContent/helpers/render/ResizableFileWithCaption.tsx similarity index 86% rename from packages/react/src/blocks/FileBlockContent/helpers/render/ResizableFileBlockWrapper.tsx rename to packages/react/src/blocks/FileBlockContent/helpers/render/ResizableFileWithCaption.tsx index c5631dac5f..8e307ca6c0 100644 --- a/packages/react/src/blocks/FileBlockContent/helpers/render/ResizableFileBlockWrapper.tsx +++ b/packages/react/src/blocks/FileBlockContent/helpers/render/ResizableFileWithCaption.tsx @@ -3,9 +3,9 @@ import { ReactNode, useCallback, useEffect, useRef, useState } from "react"; import { useUploadLoading } from "../../../../hooks/useUploadLoading.js"; import { ReactCustomBlockRenderProps } from "../../../../schema/ReactBlockSpec.js"; -import { FileBlockWrapper } from "./FileBlockWrapper.js"; +import { FileWithCaption } from "./FileWithCaption.js"; -export const ResizableFileBlockWrapper = ( +export const ResizableFileWithCaption = ( props: Omit< ReactCustomBlockRenderProps, "contentRef" @@ -89,13 +89,13 @@ export const ResizableFileBlockWrapper = ( }; if (resizeParams) { - window.addEventListener("mousemove", windowMouseMoveHandler); - window.addEventListener("mouseup", windowMouseUpHandler); + window.addEventListener("mousemove", windowMouseMoveHandler, true); + window.addEventListener("mouseup", windowMouseUpHandler, true); } return () => { - window.removeEventListener("mousemove", windowMouseMoveHandler); - window.removeEventListener("mouseup", windowMouseUpHandler); + window.removeEventListener("mousemove", windowMouseMoveHandler, true); + window.removeEventListener("mouseup", windowMouseUpHandler, true); }; }, [props, resizeParams, width]); @@ -142,7 +142,7 @@ export const ResizableFileBlockWrapper = ( const showLoader = useUploadLoading(props.block.id); return ( - -
+
{props.children} {(hovered || resizeParams) && ( <> @@ -170,7 +170,20 @@ export const ResizableFileBlockWrapper = ( /> )} + {/* This element ensures `mousemove` and `mouseup` events are captured + while resizing when the cursor is over the wrapper content. This is + because embeds are treated as separate HTML documents, so if the + content is an embed, the events will only fire within that document. */} + {resizeParams && ( +
+ )}
- + ); }; diff --git a/packages/react/src/blocks/ImageBlockContent/ImageBlockContent.tsx b/packages/react/src/blocks/ImageBlockContent/ImageBlockContent.tsx index 3e7d6e7a67..34e6f8ed3a 100644 --- a/packages/react/src/blocks/ImageBlockContent/ImageBlockContent.tsx +++ b/packages/react/src/blocks/ImageBlockContent/ImageBlockContent.tsx @@ -7,7 +7,7 @@ import { } from "../../schema/ReactBlockSpec.js"; import { useResolveUrl } from "../FileBlockContent/useResolveUrl.js"; import { FigureWithCaption } from "../FileBlockContent/helpers/toExternalHTML/FigureWithCaption.js"; -import { ResizableFileBlockWrapper } from "../FileBlockContent/helpers/render/ResizableFileBlockWrapper.js"; +import { ResizableFileWithCaption } from "../FileBlockContent/helpers/render/ResizableFileWithCaption.js"; import { LinkWithCaption } from "../FileBlockContent/helpers/toExternalHTML/LinkWithCaption.js"; export const ImagePreview = ( @@ -76,13 +76,13 @@ export const ImageBlock = ( props: ReactCustomBlockRenderProps, ) => { return ( - } > - + ); }; diff --git a/packages/react/src/blocks/VideoBlockContent/VideoBlockContent.tsx b/packages/react/src/blocks/VideoBlockContent/VideoBlockContent.tsx index 8ad81f11e6..b2107093cf 100644 --- a/packages/react/src/blocks/VideoBlockContent/VideoBlockContent.tsx +++ b/packages/react/src/blocks/VideoBlockContent/VideoBlockContent.tsx @@ -7,7 +7,7 @@ import { } from "../../schema/ReactBlockSpec.js"; import { useResolveUrl } from "../FileBlockContent/useResolveUrl.js"; import { FigureWithCaption } from "../FileBlockContent/helpers/toExternalHTML/FigureWithCaption.js"; -import { ResizableFileBlockWrapper } from "../FileBlockContent/helpers/render/ResizableFileBlockWrapper.js"; +import { ResizableFileWithCaption } from "../FileBlockContent/helpers/render/ResizableFileWithCaption.js"; import { LinkWithCaption } from "../FileBlockContent/helpers/toExternalHTML/LinkWithCaption.js"; export const VideoPreview = ( @@ -70,13 +70,13 @@ export const VideoBlock = ( props: ReactCustomBlockRenderProps, ) => { return ( - } > - + ); }; diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index fc50be2bb4..50abfe2e51 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -8,9 +8,9 @@ export * from "./i18n/dictionary.js"; export * from "./blocks/AudioBlockContent/AudioBlockContent.js"; export * from "./blocks/FileBlockContent/FileBlockContent.js"; export * from "./blocks/FileBlockContent/helpers/render/AddFileButton.js"; -export * from "./blocks/FileBlockContent/helpers/render/FileBlockWrapper.js"; +export * from "./blocks/FileBlockContent/helpers/render/FileWithCaption.js"; export * from "./blocks/FileBlockContent/helpers/render/FileNameWithIcon.js"; -export * from "./blocks/FileBlockContent/helpers/render/ResizableFileBlockWrapper.js"; +export * from "./blocks/FileBlockContent/helpers/render/ResizableFileWithCaption.js"; export * from "./blocks/FileBlockContent/helpers/toExternalHTML/FigureWithCaption.js"; export * from "./blocks/FileBlockContent/helpers/toExternalHTML/LinkWithCaption.js"; export * from "./blocks/FileBlockContent/useResolveUrl.js"; 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 f2522c662a..00f77cba09 100644 --- a/packages/server-util/src/context/__snapshots__/ServerBlockNoteEditor.test.ts.snap +++ b/packages/server-util/src/context/__snapshots__/ServerBlockNoteEditor.test.ts.snap @@ -1,6 +1,6 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Test ServerBlockNoteEditor > converts to HTML (blocksToFullHTML) 1`] = `"

Heading 2

Paragraph

list item

Example

Caption

Example

Caption

"`; +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

"`; diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/basic.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/basic.html index 9974d8d975..d4e6221f30 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/basic.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/basic.html @@ -9,16 +9,18 @@ data-caption="Caption" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

example

-

example

Caption

diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/button.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/button.html index db235fd792..2f282562f2 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/button.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/button.html @@ -2,17 +2,15 @@
-
-
-
- - - -
-

Add file

+
+
+ + +
+

Add file

diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/nested.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/nested.html index 6553a5c4a8..30de2559ea 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/nested.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/nested.html @@ -9,16 +9,18 @@ data-caption="Caption" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

example

-

example

Caption

@@ -34,16 +36,18 @@ data-caption="Caption" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

example

-

example

Caption

diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/noCaption.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/noCaption.html index 48340682e8..203b273440 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/noCaption.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/noCaption.html @@ -8,16 +8,18 @@ data-url="exampleURL" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

example

-

example

diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/noName.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/noName.html index 47ae5b3bf9..5786d6d83c 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/noName.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/file/noName.html @@ -8,16 +8,18 @@ data-caption="Caption" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

-

Caption

diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/basic.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/basic.html index fe9509a5e3..c5548fbe2b 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/basic.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/basic.html @@ -10,8 +10,8 @@ data-preview-width="256" data-file-block="" > -
-
+
+
example

Caption

diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/button.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/button.html index 250700bb22..34552f0de7 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/button.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/button.html @@ -2,17 +2,15 @@
-
-
-
- - - -
-

Add image

+
+
+ + +
+

Add image

diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/nested.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/nested.html index 90e46213fe..41723a4cd1 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/nested.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/nested.html @@ -9,8 +9,8 @@ data-preview-width="256" data-file-block="" > -
-
+
+
Caption

Caption

@@ -27,8 +27,8 @@ data-preview-width="256" data-file-block="" > -
-
+
+
Caption

Caption

diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noCaption.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noCaption.html index 2daf51143b..a3a774f51f 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noCaption.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noCaption.html @@ -9,8 +9,8 @@ data-preview-width="256" data-file-block="" > -
-
+
+
example
diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noName.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noName.html index 05bc98c060..3fad21469b 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noName.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noName.html @@ -9,8 +9,8 @@ data-preview-width="256" data-file-block="" > -
-
+
+
Caption

Caption

diff --git a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noPreview.html b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noPreview.html index 84f2dbfc76..3f16c8e654 100644 --- a/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noPreview.html +++ b/tests/src/unit/core/formatConversion/export/__snapshots__/blocknoteHTML/image/noPreview.html @@ -11,16 +11,18 @@ data-preview-width="256" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

example

-

example

Caption

diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/basic.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/basic.html index 9974d8d975..d4e6221f30 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/basic.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/basic.html @@ -9,16 +9,18 @@ data-caption="Caption" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

example

-

example

Caption

diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/button.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/button.html index db235fd792..2f282562f2 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/button.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/button.html @@ -2,17 +2,15 @@
-
-
-
- - - -
-

Add file

+
+
+ + +
+

Add file

diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/nested.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/nested.html index 6553a5c4a8..30de2559ea 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/nested.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/nested.html @@ -9,16 +9,18 @@ data-caption="Caption" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

example

-

example

Caption

@@ -34,16 +36,18 @@ data-caption="Caption" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

example

-

example

Caption

diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/noCaption.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/noCaption.html index 48340682e8..203b273440 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/noCaption.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/noCaption.html @@ -8,16 +8,18 @@ data-url="exampleURL" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

example

-

example

diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/noName.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/noName.html index 47ae5b3bf9..5786d6d83c 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/noName.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactFile/noName.html @@ -8,16 +8,18 @@ data-caption="Caption" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

-

Caption

diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/basic.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/basic.html index fe9509a5e3..c5548fbe2b 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/basic.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/basic.html @@ -10,8 +10,8 @@ data-preview-width="256" data-file-block="" > -
-
+
+
example

Caption

diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/button.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/button.html index 250700bb22..34552f0de7 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/button.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/button.html @@ -2,17 +2,15 @@
-
-
-
- - - -
-

Add image

+
+
+ + +
+

Add image

diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/nested.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/nested.html index 59718524c9..2c447b1655 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/nested.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/nested.html @@ -10,8 +10,8 @@ data-preview-width="256" data-file-block="" > -
-
+
+
example

Caption

@@ -29,8 +29,8 @@ data-preview-width="256" data-file-block="" > -
-
+
+
example

Caption

diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noCaption.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noCaption.html index 2daf51143b..a3a774f51f 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noCaption.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noCaption.html @@ -9,8 +9,8 @@ data-preview-width="256" data-file-block="" > -
-
+
+
example
diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noName.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noName.html index 05bc98c060..3fad21469b 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noName.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noName.html @@ -9,8 +9,8 @@ data-preview-width="256" data-file-block="" > -
-
+
+
Caption

Caption

diff --git a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noPreview.html b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noPreview.html index 84f2dbfc76..3f16c8e654 100644 --- a/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noPreview.html +++ b/tests/src/unit/react/formatConversion/export/__snapshots__/blocknoteHTML/reactImage/noPreview.html @@ -11,16 +11,18 @@ data-preview-width="256" data-file-block="" > -
-
-
- - - +
+
+
+
+ + + +
+

example

-

example

Caption