Skip to content
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

fix: File resize UX #1223

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ export const audioRender = (
audio.contentEditable = "false";
audio.draggable = false;

const element = createFileAndCaptionWrapper(block, audio);
const fileAndCaptionWrapper = createFileAndCaptionWrapper(block, audio);

return createFileBlockWrapper(
block,
editor,
element,
fileAndCaptionWrapper,
editor.dictionary.file_blocks.audio.add_button_text,
icon.firstElementChild as HTMLElement
);
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/blocks/FileBlockContent/FileBlockContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ export const fileRender = (
editor: BlockNoteEditor<any, any, any>
) => {
const file = createDefaultFilePreview(block).dom;
const element = createFileAndCaptionWrapper(block, file);

return createFileBlockWrapper(block, editor, element);
const fileAndCaptionWrapper = createFileAndCaptionWrapper(block, file);

return createFileBlockWrapper(block, editor, fileAndCaptionWrapper);
};

export const fileParse = (element: HTMLElement) => {
Expand Down
29 changes: 11 additions & 18 deletions packages/core/src/blocks/FileBlockContent/fileBlockHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,6 @@ export const createFileAndCaptionWrapper = (
caption.className = "bn-file-caption";
caption.textContent = block.props.caption;

if (
typeof block.props.previewWidth === "number" &&
block.props.previewWidth > 0 &&
block.props.caption !== undefined
) {
caption.style.width = `${block.props.previewWidth}px`;
}

fileAndCaptionWrapper.appendChild(file);
fileAndCaptionWrapper.appendChild(caption);

Expand Down Expand Up @@ -250,24 +242,23 @@ export const createFigureWithCaption = (
export const createResizeHandlesWrapper = (
block: BlockFromConfig<FileBlockConfig, any, any>,
editor: BlockNoteEditor<any, any, any>,
element: HTMLElement,
getWidth: () => number,
setWidth: (width: number) => void
element: HTMLElement
): { dom: HTMLElement; destroy: () => void } => {
if (!block.props.previewWidth) {
throw new Error("Block must have a `previewWidth` prop.");
}

// Wrapper element for rendered element and resize handles.
const wrapper = document.createElement("div");
wrapper.className = "bn-visual-media-wrapper";
wrapper.className = "bn-resize-handles-wrapper";
wrapper.style.width = `${block.props.previewWidth}px`;

// Resize handle elements.
const leftResizeHandle = document.createElement("div");
leftResizeHandle.className = "bn-visual-media-resize-handle";
leftResizeHandle.className = "bn-resize-handle";
leftResizeHandle.style.left = "4px";
const rightResizeHandle = document.createElement("div");
rightResizeHandle.className = "bn-visual-media-resize-handle";
rightResizeHandle.className = "bn-resize-handle";
rightResizeHandle.style.right = "4px";

// Temporary parameters set when the user begins resizing the element, used to
Expand Down Expand Up @@ -328,11 +319,13 @@ export const createResizeHandlesWrapper = (
// Ensures the element is not wider than the editor and not smaller than a
// predetermined minimum width.
if (newWidth < minWidth) {
setWidth(minWidth);
wrapper.style.width = `${minWidth}`;
} else if (newWidth > editor.domElement.firstElementChild!.clientWidth) {
setWidth(editor.domElement.firstElementChild!.clientWidth);
wrapper.style.width = `${
editor.domElement.firstElementChild!.clientWidth
}px`;
} else {
setWidth(newWidth);
wrapper.style.width = `${newWidth}px`;
}
};
// Stops mouse movements from resizing the element and updates the block's
Expand All @@ -358,7 +351,7 @@ export const createResizeHandlesWrapper = (

editor.updateBlock(block, {
props: {
previewWidth: getWidth(),
previewWidth: parseInt(wrapper.style.width.replace("px", "")),
},
});
};
Expand Down
27 changes: 16 additions & 11 deletions packages/core/src/blocks/ImageBlockContent/ImageBlockContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ export const imageRender = (
block: BlockFromConfig<typeof imageBlockConfig, any, any>,
editor: BlockNoteEditor<any, any, any>
) => {
// Immediately updates & re-renders the block if it's wider than the editor.
if (
Copy link
Collaborator

Choose a reason for hiding this comment

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

My first feeling is I don't really like this approach:

  • what if a user opens the document on a small screen, and later on a large screen?
  • what if the user is in read-only mode?

block.props.previewWidth > editor.domElement.firstElementChild!.clientWidth
) {
editor.updateBlock(block, {
props: {
previewWidth: editor.domElement.firstElementChild!.clientWidth,
},
});
}

const icon = document.createElement("div");
icon.innerHTML = FILE_IMAGE_ICON_SVG;

Expand All @@ -68,25 +79,19 @@ export const imageRender = (
image.alt = block.props.name || block.props.caption || "BlockNote image";
image.contentEditable = "false";
image.draggable = false;
image.width = Math.min(
block.props.previewWidth,
editor.domElement.firstElementChild!.clientWidth
);

const file = createResizeHandlesWrapper(
const fileAndCaptionWrapper = createFileAndCaptionWrapper(block, image);

const resizeHandlesWrapper = createResizeHandlesWrapper(
block,
editor,
image,
() => image.width,
(width) => (image.width = width)
fileAndCaptionWrapper.dom
);

const element = createFileAndCaptionWrapper(block, file.dom);

return createFileBlockWrapper(
block,
editor,
element,
resizeHandlesWrapper,
editor.dictionary.file_blocks.image.add_button_text,
icon.firstElementChild as HTMLElement
);
Expand Down
27 changes: 16 additions & 11 deletions packages/core/src/blocks/VideoBlockContent/VideoBlockContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ export const videoRender = (
block: BlockFromConfig<typeof videoBlockConfig, any, any>,
editor: BlockNoteEditor<any, any, any>
) => {
// Immediately updates & re-renders the block if it's wider than the editor.
if (
block.props.previewWidth > editor.domElement.firstElementChild!.clientWidth
) {
editor.updateBlock(block, {
props: {
previewWidth: editor.domElement.firstElementChild!.clientWidth,
},
});
}

const icon = document.createElement("div");
icon.innerHTML = FILE_VIDEO_ICON_SVG;

Expand All @@ -67,25 +78,19 @@ export const videoRender = (
video.controls = true;
video.contentEditable = "false";
video.draggable = false;
video.width = Math.min(
block.props.previewWidth,
editor.domElement.firstElementChild!.clientWidth
);

const file = createResizeHandlesWrapper(
const fileAndCaptionWrapper = createFileAndCaptionWrapper(block, video);

const resizeHandlesWrapper = createResizeHandlesWrapper(
block,
editor,
video,
() => video.width,
(width) => (video.width = width)
fileAndCaptionWrapper.dom
);

const element = createFileAndCaptionWrapper(block, file.dom);

return createFileBlockWrapper(
block,
editor,
element,
resizeHandlesWrapper,
editor.dictionary.file_blocks.video.add_button_text,
icon.firstElementChild as HTMLElement
);
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/editor/Block.css
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ NESTED BLOCKS
display: flex;
flex-direction: column;
border-radius: 4px;
width: 100%;
}

[data-file-block] .bn-file-default-preview {
Expand All @@ -372,20 +373,19 @@ NESTED BLOCKS
height: 24px;
}

[data-file-block] .bn-visual-media-wrapper {
[data-file-block] .bn-resize-handles-wrapper {
Copy link
Collaborator

Choose a reason for hiding this comment

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

make sure DO etc isn't using the old classnames. I suppose you didn't like the earlier name / just a cleanup right?

display: flex;
flex-direction: row;
align-items: center;
position: relative;
width: fit-content;
}

[data-file-block] .bn-visual-media {
border-radius: 4px;
max-width: 100%;
}

[data-file-block] .bn-visual-media-resize-handle {
[data-file-block] .bn-resize-handle {
position: absolute;
width: 8px;
height: 30px;
Expand Down
19 changes: 11 additions & 8 deletions packages/react/src/blocks/AudioBlockContent/AudioBlockContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "../../schema/ReactBlockSpec.js";
import {
FigureWithCaption,
FileAndCaptionWrapper,
FileBlockWrapper,
LinkWithCaption,
} from "../FileBlockContent/fileBlockHelpers.js";
Expand All @@ -26,13 +27,15 @@ export const AudioPreview = (
}

return (
<audio
className={"bn-audio"}
src={resolved.downloadUrl}
controls={true}
contentEditable={false}
draggable={false}
/>
<FileAndCaptionWrapper {...props}>
<audio
className={"bn-audio"}
src={resolved.downloadUrl}
controls={true}
contentEditable={false}
draggable={false}
/>
</FileAndCaptionWrapper>
);
};

Expand Down Expand Up @@ -77,7 +80,7 @@ export const AudioBlock = (
{...(props as any)}
buttonText={props.editor.dictionary.file_blocks.audio.add_button_text}
buttonIcon={<RiVolumeUpFill size={24} />}>
<AudioPreview block={props.block} editor={props.editor as any} />
<AudioPreview {...(props as any)} />
</FileBlockWrapper>
);
};
Expand Down
16 changes: 14 additions & 2 deletions packages/react/src/blocks/FileBlockContent/FileBlockContent.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import { fileBlockConfig, fileParse } from "@blocknote/core";
import { FileBlockConfig, fileBlockConfig, fileParse } from "@blocknote/core";

import {
createReactBlockSpec,
ReactCustomBlockRenderProps,
} from "../../schema/ReactBlockSpec.js";
import {
DefaultFilePreview,
FileAndCaptionWrapper,
FileBlockWrapper,
LinkWithCaption,
} from "./fileBlockHelpers.js";

export const FilePreview = (
props: Omit<
ReactCustomBlockRenderProps<FileBlockConfig, any, any>,
"contentRef"
>
) => (
<FileAndCaptionWrapper {...props}>
<DefaultFilePreview {...props} />
</FileAndCaptionWrapper>
);

export const FileToExternalHTML = (
props: Omit<
ReactCustomBlockRenderProps<typeof fileBlockConfig, any, any>,
Expand Down Expand Up @@ -42,7 +54,7 @@ export const FileBlock = (
) => {
return (
<FileBlockWrapper {...(props as any)}>
<DefaultFilePreview block={props.block} editor={props.editor as any} />
<FilePreview {...(props as any)} />
</FileBlockWrapper>
);
};
Expand Down
Loading
Loading