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 @@ -8,6 +8,7 @@ import {
} from "@blocknote/core";
import { CommentsExtension } from "@blocknote/core/comments";
import { flip, offset, shift } from "@floating-ui/react";
import merge from "lodash.merge";
import { ComponentProps, FC, useMemo } from "react";

import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js";
Expand Down Expand Up @@ -46,28 +47,31 @@ export default function FloatingComposerController<
});

const floatingUIOptions = useMemo<FloatingUIOptions>(
() => ({
useFloatingOptions: {
open: !!pendingComment,
// Needed as hooks like `useDismiss` call `onOpenChange` to change the
// open state.
onOpenChange: (open) => {
if (!open) {
comments.stopPendingComment();
editor.focus();
}
},
placement: "bottom",
middleware: [offset(10), shift(), flip()],
},
elementProps: {
style: {
zIndex: 60,
},
},
...props.floatingUIOptions,
}),
[comments, editor, pendingComment, props.floatingUIOptions],
() =>
merge(
{
useFloatingOptions: {
open: !!pendingComment,
// Needed as hooks like `useDismiss` call `onOpenChange` to change the
// open state.
onOpenChange: (open) => {
if (!open) {
comments.stopPendingComment();
editor.focus();
}
},
placement: "bottom",
middleware: [offset(10), shift(), flip()],
},
elementProps: {
style: {
zIndex: 60,
},
},
} satisfies FloatingUIOptions,
props.floatingUIOptions
),
[comments, editor, pendingComment, props.floatingUIOptions]
);

// nice to have improvements would be:
Expand Down
52 changes: 28 additions & 24 deletions packages/react/src/components/Comments/FloatingThreadController.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CommentsExtension } from "@blocknote/core/comments";
import { flip, offset, shift } from "@floating-ui/react";
import merge from "lodash.merge";
import { ComponentProps, FC, useMemo } from "react";

import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js";
Expand Down Expand Up @@ -39,31 +40,34 @@ export default function FloatingThreadController(props: {
);

const floatingUIOptions = useMemo<FloatingUIOptions>(
() => ({
useFloatingOptions: {
open: !!selectedThread,
// Needed as hooks like `useDismiss` call `onOpenChange` to change the
// open state.
onOpenChange: (open, _event, reason) => {
if (reason === "escape-key") {
editor.focus();
}
() =>
merge(
{
useFloatingOptions: {
open: !!selectedThread,
// Needed as hooks like `useDismiss` call `onOpenChange` to change the
// open state.
onOpenChange: (open, _event, reason) => {
if (reason === "escape-key") {
editor.focus();
}

if (!open) {
comments.selectThread(undefined);
}
},
placement: "bottom",
middleware: [offset(10), shift(), flip()],
},
elementProps: {
style: {
zIndex: 30,
},
},
...props.floatingUIOptions,
}),
[comments, editor, props.floatingUIOptions, selectedThread],
if (!open) {
comments.selectThread(undefined);
}
},
placement: "bottom",
middleware: [offset(10), shift(), flip()],
},
elementProps: {
style: {
zIndex: 30,
},
},
} satisfies FloatingUIOptions,
props.floatingUIOptions
),
[comments, editor, props.floatingUIOptions, selectedThread]
);

// nice to have improvements:
Expand Down
50 changes: 27 additions & 23 deletions packages/react/src/components/FilePanel/FilePanelController.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FilePanelExtension } from "@blocknote/core/extensions";
import { flip, offset } from "@floating-ui/react";
import merge from "lodash.merge";
import { FC, useMemo } from "react";

import { FilePanel } from "./FilePanel.js";
Expand All @@ -19,30 +20,33 @@ export const FilePanelController = (props: {
const blockId = useExtensionState(FilePanelExtension);

const floatingUIOptions = useMemo<FloatingUIOptions>(
() => ({
useFloatingOptions: {
open: !!blockId,
// Needed as hooks like `useDismiss` call `onOpenChange` to change the
// open state.
onOpenChange: (open, _event, reason) => {
if (!open) {
filePanel.closeMenu();
}
() =>
merge(
{
useFloatingOptions: {
open: !!blockId,
// Needed as hooks like `useDismiss` call `onOpenChange` to change the
// open state.
onOpenChange: (open, _event, reason) => {
if (!open) {
filePanel.closeMenu();
}

if (reason === "escape-key") {
editor.focus();
}
},
middleware: [offset(10), flip()],
},
elementProps: {
style: {
zIndex: 90,
},
},
...props.floatingUIOptions,
}),
[blockId, editor, filePanel, props.floatingUIOptions],
if (reason === "escape-key") {
editor.focus();
}
},
middleware: [offset(10), flip()],
},
elementProps: {
style: {
zIndex: 90,
},
},
} satisfies FloatingUIOptions,
props.floatingUIOptions
),
[blockId, editor, filePanel, props.floatingUIOptions]
);

const Component = props.filePanel || FilePanel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "@blocknote/core";
import { FormattingToolbarExtension } from "@blocknote/core/extensions";
import { flip, offset, shift } from "@floating-ui/react";
import merge from "lodash.merge";
import { FC, useMemo } from "react";

import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js";
Expand Down Expand Up @@ -78,29 +79,32 @@ export const FormattingToolbarController = (props: {
});

const floatingUIOptions = useMemo<FloatingUIOptions>(
() => ({
useFloatingOptions: {
open: show,
// Needed as hooks like `useDismiss` call `onOpenChange` to change the
// open state.
onOpenChange: (open, _event, reason) => {
formattingToolbar.store.setState(open);
() =>
merge(
{
useFloatingOptions: {
open: show,
// Needed as hooks like `useDismiss` call `onOpenChange` to change the
// open state.
onOpenChange: (open, _event, reason) => {
formattingToolbar.store.setState(open);

if (reason === "escape-key") {
editor.focus();
}
},
placement,
middleware: [offset(10), shift(), flip()],
},
elementProps: {
style: {
zIndex: 40,
},
},
...props.floatingUIOptions,
}),
[show, placement, props.floatingUIOptions, formattingToolbar.store, editor],
if (reason === "escape-key") {
editor.focus();
}
},
placement,
middleware: [offset(10), shift(), flip()],
},
elementProps: {
style: {
zIndex: 40,
},
},
} satisfies FloatingUIOptions,
props.floatingUIOptions
),
[show, placement, props.floatingUIOptions, formattingToolbar.store, editor]
);

const Component = props.formattingToolbar || FormattingToolbar;
Expand Down
94 changes: 49 additions & 45 deletions packages/react/src/components/LinkToolbar/LinkToolbarController.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { LinkToolbarExtension } from "@blocknote/core/extensions";
import { flip, offset, safePolygon } from "@floating-ui/react";
import { Range } from "@tiptap/core";
import merge from "lodash.merge";
import { FC, useEffect, useMemo, useState } from "react";

import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js";
Expand Down Expand Up @@ -109,51 +110,54 @@ export const LinkToolbarController = (props: {
}, [editor, linkToolbar, link, toolbarPositionFrozen]);

const floatingUIOptions = useMemo<FloatingUIOptions>(
() => ({
useFloatingOptions: {
open: toolbarOpen,
onOpenChange: (open, _event, reason) => {
if (toolbarPositionFrozen) {
return;
}

// We want to prioritize `selectionLink` over `mouseHoverLink`, so we
// ignore opening/closing from hover events.
if (
link !== undefined &&
link.cursorType === "text" &&
reason === "hover"
) {
return;
}

if (reason === "escape-key") {
editor.focus();
}

setToolbarOpen(open);
},
placement: "top-start",
middleware: [offset(10), flip()],
},
useHoverProps: {
// `useHover` hook only enabled when a link is hovered with the
// mouse.
enabled: link !== undefined && link.cursorType === "mouse",
delay: {
open: 250,
close: 250,
},
handleClose: safePolygon(),
},
elementProps: {
style: {
zIndex: 50,
},
},
...props.floatingUIOptions,
}),
[editor, link, props.floatingUIOptions, toolbarOpen, toolbarPositionFrozen],
() =>
merge(
{
useFloatingOptions: {
open: toolbarOpen,
onOpenChange: (open, _event, reason) => {
if (toolbarPositionFrozen) {
return;
}

// We want to prioritize `selectionLink` over `mouseHoverLink`, so we
// ignore opening/closing from hover events.
if (
link !== undefined &&
link.cursorType === "text" &&
reason === "hover"
) {
return;
}

if (reason === "escape-key") {
editor.focus();
}

setToolbarOpen(open);
},
placement: "top-start",
middleware: [offset(10), flip()],
},
useHoverProps: {
// `useHover` hook only enabled when a link is hovered with the
// mouse.
enabled: link !== undefined && link.cursorType === "mouse",
delay: {
open: 250,
close: 250,
},
handleClose: safePolygon(),
},
elementProps: {
style: {
zIndex: 50,
},
},
} satisfies FloatingUIOptions,
props.floatingUIOptions
),
[editor, link, props.floatingUIOptions, toolbarOpen, toolbarPositionFrozen]
);

const reference = useMemo<GenericPopoverReference | undefined>(
Expand Down
Loading