Skip to content
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 @@ -48,7 +48,11 @@ export const FilePanelController = (props: {
const Component = props.filePanel || FilePanel;

return (
<BlockPopover blockId={blockId} {...floatingUIOptions}>
<BlockPopover
blockId={blockId}
includeNestedBlocks={false}
{...floatingUIOptions}
>
{blockId && <Component blockId={blockId} />}
</BlockPopover>
);
Expand Down
49 changes: 42 additions & 7 deletions packages/react/src/components/Popovers/BlockPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { GenericPopover, GenericPopoverReference } from "./GenericPopover.js";
export const BlockPopover = (
props: FloatingUIOptions & {
blockId: string | undefined;
spanEditorWidth?: boolean;
includeNestedBlocks?: boolean;
children: ReactNode;
},
) => {
Expand All @@ -28,18 +30,51 @@ export const BlockPopover = (
return undefined;
}

const { node } = editor.prosemirrorView.domAtPos(
const blockElement = editor.prosemirrorView.domAtPos(
nodePosInfo.posBeforeNode + 1,
);
if (!(node instanceof Element)) {
).node;
if (!(blockElement instanceof Element)) {
return undefined;
}

return {
element: node,
};
const blockContentElement = blockElement.firstElementChild;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure I like the use of firstElementChild. It assumes a specific dom structure to get the dom element - which is not typesafe / futureproof.

Better approach would be to use the methods we have like getblockinfo to get the content block, and then call getdomatpos for it

(example; the current approach would probably break for column blocks which don't have blockContent)

if (!(blockContentElement instanceof Element)) {
return undefined;
}

const element =
props.includeNestedBlocks === false
? blockContentElement
: blockElement;

if (props.spanEditorWidth) {
return {
element,
getBoundingClientRect: () => {
const boundingClientRect = element.getBoundingClientRect();

const outerBlockGroupElement =
editor.domElement?.firstElementChild;
if (!(outerBlockGroupElement instanceof Element)) {
return undefined;
}

const outerBlockGroupBoundingClientRect =
outerBlockGroupElement.getBoundingClientRect();

return new DOMRect(
outerBlockGroupBoundingClientRect.x,
boundingClientRect.y,
outerBlockGroupBoundingClientRect.width,
boundingClientRect.height,
);
},
};
}

return { element };
}),
[editor, blockId],
[editor, blockId, props.includeNestedBlocks, props.spanEditorWidth],
);

return (
Expand Down
40 changes: 2 additions & 38 deletions packages/react/src/components/SideMenu/SideMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { SideMenuExtension } from "@blocknote/core/extensions";
import { ReactNode, useMemo } from "react";
import { ReactNode } from "react";

import { useComponentsContext } from "../../editor/ComponentsContext.js";
import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js";
import { useExtensionState } from "../../hooks/useExtension.js";
import { AddBlockButton } from "./DefaultButtons/AddBlockButton.js";
import { DragHandleButton } from "./DefaultButtons/DragHandleButton.js";
import { SideMenuProps } from "./SideMenuProps.js";
Expand All @@ -20,41 +17,8 @@ import { SideMenuProps } from "./SideMenuProps.js";
export const SideMenu = (props: SideMenuProps & { children?: ReactNode }) => {
const Components = useComponentsContext()!;

const editor = useBlockNoteEditor<any, any, any>();

const block = useExtensionState(SideMenuExtension, {
editor,
selector: (state) => state?.block,
});

const dataAttributes = useMemo(() => {
if (block === undefined) {
return {};
}

const attrs: Record<string, string> = {
"data-block-type": block.type,
};

if (block.type === "heading") {
attrs["data-level"] = (block.props as any).level.toString();
}

if (
editor.schema.blockSpecs[block.type].implementation.meta?.fileBlockAccept
) {
if (block.props.url) {
attrs["data-url"] = "true";
} else {
attrs["data-url"] = "false";
}
}

return attrs;
}, [block, editor.schema.blockSpecs]);

return (
<Components.SideMenu.Root className={"bn-side-menu"} {...dataAttributes}>
<Components.SideMenu.Root className={"bn-side-menu"}>
{props.children || (
<>
<AddBlockButton />
Expand Down
79 changes: 77 additions & 2 deletions packages/react/src/components/SideMenu/SideMenuController.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { blockHasType } from "@blocknote/core";
import { SideMenuExtension } from "@blocknote/core/extensions";
import { size } from "@floating-ui/react";
import { FC, useMemo } from "react";

import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js";
import { useExtensionState } from "../../hooks/useExtension.js";
import { BlockPopover } from "../Popovers/BlockPopover.js";
import { FloatingUIOptions } from "../Popovers/FloatingUIOptions.js";
Expand All @@ -11,6 +14,8 @@ export const SideMenuController = (props: {
sideMenu?: FC<SideMenuProps>;
floatingUIOptions?: Partial<FloatingUIOptions>;
}) => {
const editor = useBlockNoteEditor<any, any, any>();

const state = useExtensionState(SideMenuExtension, {
selector: (state) => {
return state !== undefined
Expand All @@ -29,6 +34,72 @@ export const SideMenuController = (props: {
useFloatingOptions: {
open: show,
placement: "left-start",
middleware: [
size({
apply({ elements }) {
// TODO: Need to fetch the block from extension, else it's
Copy link
Collaborator

Choose a reason for hiding this comment

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

this code is called in useMemo, so the apply function only gets recreated when the deps array changes

// always `undefined` for some reason? Shouldn't the `apply`
// function get recreated with the updated `block` object each
// time it changes?
const block =
editor.getExtension(SideMenuExtension)?.store.state?.block;
if (block === undefined) {
return;
}

if (block.type === "heading") {
if (!block.props.level || block.props.level === 1) {
elements.floating.style.setProperty("height", "78px");
Copy link
Collaborator

Choose a reason for hiding this comment

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

we can't base this on pixels here. What if someone changes the font or font-size in css?

return;
}

if (block.props.level === 2) {
elements.floating.style.setProperty("height", "54px");
return;
}

if (block.props.level === 2) {
elements.floating.style.setProperty("height", "37px");
return;
}
}

if (
editor.schema.blockSpecs[block.type].implementation.meta
?.fileBlockAccept
) {
if (
blockHasType(block, editor, block.type, {
url: "string",
}) &&
block.props.url === ""
) {
elements.floating.style.setProperty("height", "54px");
return;
}

if (
block.type === "file" ||
(blockHasType(block, editor, block.type, {
showPreview: "boolean",
}) &&
!block.props.showPreview)
) {
elements.floating.style.setProperty("height", "38px");
return;
}

if (block.type === "audio") {
elements.floating.style.setProperty("height", "60px");
return;
}
}

elements.floating.style.setProperty("height", "30px");
elements.floating.style.height = "30px";
},
}),
],
},
useDismissProps: {
enabled: false,
Expand All @@ -40,13 +111,17 @@ export const SideMenuController = (props: {
},
...props.floatingUIOptions,
}),
[props.floatingUIOptions, show],
[editor, props.floatingUIOptions, show],
);

const Component = props.sideMenu || SideMenu;

return (
<BlockPopover blockId={show ? block?.id : undefined} {...floatingUIOptions}>
<BlockPopover
blockId={show ? block?.id : undefined}
spanEditorWidth={true}
{...floatingUIOptions}
>
{block?.id && <Component />}
</BlockPopover>
);
Expand Down
29 changes: 0 additions & 29 deletions packages/react/src/editor/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -237,35 +237,6 @@ inline styles, it is added to the base z-index. */
--bn-ui-base-z-index: 0;
}

/* Matches Side Menu height to block line height */
.bn-side-menu {
height: 30px;
}

.bn-side-menu[data-block-type="heading"][data-level="1"] {
height: 78px;
}

.bn-side-menu[data-block-type="heading"][data-level="2"] {
height: 54px;
}

.bn-side-menu[data-block-type="heading"][data-level="3"] {
height: 37px;
}

.bn-side-menu[data-block-type="file"] {
height: 38px;
}

.bn-side-menu[data-block-type="audio"] {
height: 60px;
}

.bn-side-menu[data-url="false"] {
height: 54px;
}

/* Thread sidebar styling */
.bn-threads-sidebar {
border-radius: var(--bn-border-radius-medium);
Expand Down
Loading