diff --git a/examples/03-ui-components/11-uppy-file-panel/src/App.tsx b/examples/03-ui-components/11-uppy-file-panel/src/App.tsx
index 994710692b..124467dbea 100644
--- a/examples/03-ui-components/11-uppy-file-panel/src/App.tsx
+++ b/examples/03-ui-components/11-uppy-file-panel/src/App.tsx
@@ -3,6 +3,7 @@ import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import {
FilePanelController,
+ FileReplaceButton,
FormattingToolbar,
FormattingToolbarController,
FormattingToolbarProps,
@@ -10,7 +11,6 @@ import {
useCreateBlockNote,
} from "@blocknote/react";
-import { FileReplaceButton } from "./FileReplaceButton";
import { uploadFile, UppyFilePanel } from "./UppyFilePanel";
const CustomFormattingToolbar = (props: FormattingToolbarProps) => {
@@ -19,7 +19,7 @@ const CustomFormattingToolbar = (props: FormattingToolbarProps) => {
items.splice(
items.findIndex((c) => c.key === "replaceFileButton"),
1,
- ,
+ ,
);
return {items};
diff --git a/examples/03-ui-components/11-uppy-file-panel/src/FileReplaceButton.tsx b/examples/03-ui-components/11-uppy-file-panel/src/FileReplaceButton.tsx
deleted file mode 100644
index d3f393b04c..0000000000
--- a/examples/03-ui-components/11-uppy-file-panel/src/FileReplaceButton.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import {
- BlockSchema,
- blockHasType,
- InlineContentSchema,
- StyleSchema,
-} from "@blocknote/core";
-import {
- useBlockNoteEditor,
- useComponentsContext,
- useDictionary,
- useSelectedBlocks,
-} from "@blocknote/react";
-import { useEffect, useState } from "react";
-
-import { RiImageEditFill } from "react-icons/ri";
-
-import { UppyFilePanel } from "./UppyFilePanel";
-
-// Copied with minor changes from:
-// https://github.com/TypeCellOS/BlockNote/blob/main/packages/react/src/components/FormattingToolbar/DefaultButtons/FileReplaceButton.tsx
-// Opens Uppy file panel instead of the default one.
-export const FileReplaceButton = () => {
- const dict = useDictionary();
- const Components = useComponentsContext()!;
-
- const editor = useBlockNoteEditor<
- BlockSchema,
- InlineContentSchema,
- StyleSchema
- >();
-
- const selectedBlocks = useSelectedBlocks(editor);
-
- const [isOpen, setIsOpen] = useState(false);
-
- useEffect(() => {
- setIsOpen(false);
- }, [selectedBlocks]);
-
- const block = selectedBlocks.length === 1 ? selectedBlocks[0] : undefined;
-
- if (
- block === undefined ||
- !blockHasType(block, editor, "file", { url: "string" }) ||
- !editor.isEditable
- ) {
- return null;
- }
-
- return (
-
-
- setIsOpen(!isOpen)}
- isSelected={isOpen}
- mainTooltip={
- dict.formatting_toolbar.file_replace.tooltip[block.type] ||
- dict.formatting_toolbar.file_replace.tooltip["file"]
- }
- label={
- dict.formatting_toolbar.file_replace.tooltip[block.type] ||
- dict.formatting_toolbar.file_replace.tooltip["file"]
- }
- icon={}
- />
-
-
- {/* Replaces default file panel with our Uppy one. */}
-
-
-
- );
-};
diff --git a/packages/react/src/components/FormattingToolbar/DefaultButtons/FileReplaceButton.tsx b/packages/react/src/components/FormattingToolbar/DefaultButtons/FileReplaceButton.tsx
index 4eb7cb1117..c425abdfb6 100644
--- a/packages/react/src/components/FormattingToolbar/DefaultButtons/FileReplaceButton.tsx
+++ b/packages/react/src/components/FormattingToolbar/DefaultButtons/FileReplaceButton.tsx
@@ -5,16 +5,34 @@ import {
StyleSchema,
} from "@blocknote/core";
import { RiImageEditFill } from "react-icons/ri";
+import type { FC } from "react";
import { useComponentsContext } from "../../../editor/ComponentsContext.js";
import { useBlockNoteEditor } from "../../../hooks/useBlockNoteEditor.js";
import { useEditorState } from "../../../hooks/useEditorState.js";
import { useDictionary } from "../../../i18n/dictionary.js";
import { FilePanel } from "../../FilePanel/FilePanel.js";
+import type { FilePanelProps } from "../../FilePanel/FilePanelProps.js";
-export const FileReplaceButton = () => {
+export type FileReplaceButtonProps = {
+ /**
+ * The file panel rendered inside the replace-file popover.
+ *
+ * Defaults to {@link FilePanel}.
+ */
+ filePanel?: FC;
+};
+
+/**
+ * By default, the FileReplaceButton component renders a FilePanel in its
+ * popover. However, you can override the file panel by passing the
+ * `filePanel` prop. You can use the default FilePanel with custom tabs or make
+ * your own file panel component.
+ */
+export function FileReplaceButton(props: FileReplaceButtonProps) {
const dict = useDictionary();
const Components = useComponentsContext()!;
+ const FilePanelComponent = props.filePanel ?? FilePanel;
const editor = useBlockNoteEditor<
BlockSchema,
@@ -75,8 +93,8 @@ export const FileReplaceButton = () => {
className={"bn-popover-content bn-panel-popover"}
variant={"panel-popover"}
>
-
+
);
-};
+}