Skip to content
Merged
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
89 changes: 34 additions & 55 deletions examples/03-ui-components/02-formatting-toolbar-buttons/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,39 @@ import {

import { BlueButton } from "./BlueButton";

const CustomFormattingToolbar = () => (
<FormattingToolbar>
<BlockTypeSelect key={"blockTypeSelect"} />

{/* Extra button to toggle blue text & background */}
<BlueButton key={"customButton"} />

<FileCaptionButton key={"fileCaptionButton"} />
<FileReplaceButton key={"replaceFileButton"} />

<BasicTextStyleButton basicTextStyle={"bold"} key={"boldStyleButton"} />
<BasicTextStyleButton basicTextStyle={"italic"} key={"italicStyleButton"} />
<BasicTextStyleButton
basicTextStyle={"underline"}
key={"underlineStyleButton"}
/>
<BasicTextStyleButton basicTextStyle={"strike"} key={"strikeStyleButton"} />
{/* Extra button to toggle code styles */}
<BasicTextStyleButton key={"codeStyleButton"} basicTextStyle={"code"} />

<TextAlignButton textAlignment={"left"} key={"textAlignLeftButton"} />
<TextAlignButton textAlignment={"center"} key={"textAlignCenterButton"} />
<TextAlignButton textAlignment={"right"} key={"textAlignRightButton"} />

<ColorStyleButton key={"colorStyleButton"} />

<NestBlockButton key={"nestBlockButton"} />
<UnnestBlockButton key={"unnestBlockButton"} />

<CreateLinkButton key={"createLinkButton"} />
</FormattingToolbar>
);

export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
Expand Down Expand Up @@ -80,61 +113,7 @@ export default function App() {
// Renders the editor instance.
return (
<BlockNoteView editor={editor} formattingToolbar={false}>
<FormattingToolbarController
formattingToolbar={() => (
<FormattingToolbar>
<BlockTypeSelect key={"blockTypeSelect"} />

{/* Extra button to toggle blue text & background */}
<BlueButton key={"customButton"} />

<FileCaptionButton key={"fileCaptionButton"} />
<FileReplaceButton key={"replaceFileButton"} />

<BasicTextStyleButton
basicTextStyle={"bold"}
key={"boldStyleButton"}
/>
<BasicTextStyleButton
basicTextStyle={"italic"}
key={"italicStyleButton"}
/>
<BasicTextStyleButton
basicTextStyle={"underline"}
key={"underlineStyleButton"}
/>
<BasicTextStyleButton
basicTextStyle={"strike"}
key={"strikeStyleButton"}
/>
{/* Extra button to toggle code styles */}
<BasicTextStyleButton
key={"codeStyleButton"}
basicTextStyle={"code"}
/>

<TextAlignButton
textAlignment={"left"}
key={"textAlignLeftButton"}
/>
<TextAlignButton
textAlignment={"center"}
key={"textAlignCenterButton"}
/>
<TextAlignButton
textAlignment={"right"}
key={"textAlignRightButton"}
/>

<ColorStyleButton key={"colorStyleButton"} />

<NestBlockButton key={"nestBlockButton"} />
<UnnestBlockButton key={"unnestBlockButton"} />

<CreateLinkButton key={"createLinkButton"} />
</FormattingToolbar>
)}
/>
<FormattingToolbarController formattingToolbar={CustomFormattingToolbar} />
</BlockNoteView>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "@blocknote/mantine/style.css";
import {
FormattingToolbarController,
blockTypeSelectItems,
useBlockNoteEditor,
useCreateBlockNote,
BlockTypeSelectItem,
FormattingToolbar,
Expand All @@ -24,6 +25,31 @@ const schema = BlockNoteSchema.create({
},
});

const CustomFormattingToolbar = () => {
const editor = useBlockNoteEditor<
typeof schema.blockSchema,
typeof schema.inlineContentSchema,
typeof schema.styleSchema
>();

return (
// Uses the default Formatting Toolbar.
<FormattingToolbar
// Sets the items in the Block Type Select.
blockTypeSelectItems={[
// Gets the default Block Type Select items.
...blockTypeSelectItems(editor.dictionary),
// Adds an item for the Alert block.
{
name: "Alert",
type: "alert",
icon: RiAlertFill,
} satisfies BlockTypeSelectItem,
]}
/>
);
};

export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
Expand Down Expand Up @@ -53,24 +79,7 @@ export default function App() {
return (
<BlockNoteView editor={editor} formattingToolbar={false}>
{/* Replaces the default Formatting Toolbar */}
<FormattingToolbarController
formattingToolbar={() => (
// Uses the default Formatting Toolbar.
<FormattingToolbar
// Sets the items in the Block Type Select.
blockTypeSelectItems={[
// Gets the default Block Type Select items.
...blockTypeSelectItems(editor.dictionary),
// Adds an item for the Alert block.
{
name: "Alert",
type: "alert",
icon: RiAlertFill,
} satisfies BlockTypeSelectItem,
]}
/>
)}
/>
<FormattingToolbarController formattingToolbar={CustomFormattingToolbar} />
</BlockNoteView>
);
}
19 changes: 10 additions & 9 deletions examples/03-ui-components/04-side-menu-buttons/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ import {
DragHandleButton,
SideMenu,
SideMenuController,
SideMenuProps,
useCreateBlockNote,
} from "@blocknote/react";

import { RemoveBlockButton } from "./RemoveBlockButton";

const CustomSideMenu = (props: SideMenuProps) => (
<SideMenu {...props}>
{/* Button which removes the hovered block. */}
<RemoveBlockButton />
<DragHandleButton {...props} />
</SideMenu>
);

export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
Expand All @@ -35,15 +44,7 @@ export default function App() {
// Renders the editor instance.
return (
<BlockNoteView editor={editor} sideMenu={false}>
<SideMenuController
sideMenu={(props) => (
<SideMenu {...props}>
{/* Button which removes the hovered block. */}
<RemoveBlockButton />
<DragHandleButton {...props} />
</SideMenu>
)}
/>
<SideMenuController sideMenu={CustomSideMenu} />
</BlockNoteView>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
RemoveBlockItem,
SideMenu,
SideMenuController,
SideMenuProps,
useCreateBlockNote,
} from "@blocknote/react";

Expand All @@ -24,6 +25,10 @@ const CustomDragHandleMenu = () => (
</DragHandleMenu>
);

const CustomSideMenu = (props: SideMenuProps) => (
<SideMenu {...props} dragHandleMenu={CustomDragHandleMenu} />
);

export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
Expand All @@ -50,11 +55,7 @@ export default function App() {
// Renders the editor instance.
return (
<BlockNoteView editor={editor} sideMenu={false}>
<SideMenuController
sideMenu={(props) => (
<SideMenu {...props} dragHandleMenu={CustomDragHandleMenu} />
)}
/>
<SideMenuController sideMenu={CustomSideMenu} />
</BlockNoteView>
);
}
27 changes: 14 additions & 13 deletions examples/03-ui-components/11-uppy-file-panel/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,26 @@ import {
FilePanelController,
FormattingToolbar,
FormattingToolbarController,
FormattingToolbarProps,
getFormattingToolbarItems,
useCreateBlockNote,
} from "@blocknote/react";

import { FileReplaceButton } from "./FileReplaceButton";
import { uploadFile, UppyFilePanel } from "./UppyFilePanel";

const CustomFormattingToolbar = (props: FormattingToolbarProps) => {
// Replaces default file replace button with one that opens Uppy.
const items = getFormattingToolbarItems();
items.splice(
items.findIndex((c) => c.key === "replaceFileButton"),
1,
<FileReplaceButton key={"fileReplaceButton"} />,
);
Comment on lines +19 to +23
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

findIndex returning -1 causes the last toolbar item to be silently replaced.

When "replaceFileButton" is absent from the items array (e.g., the cursor is on a paragraph or heading block rather than a file/image block), findIndex returns -1. Array.prototype.splice(-1, 1, …) interprets -1 as the last index, so the last toolbar item is removed and <FileReplaceButton /> is inserted in its place instead.

🐛 Proposed fix — guard against missing key
-  items.splice(
-    items.findIndex((c) => c.key === "replaceFileButton"),
-    1,
-    <FileReplaceButton key={"fileReplaceButton"} />,
-  );
+  const replaceIdx = items.findIndex((c) => c.key === "replaceFileButton");
+  if (replaceIdx !== -1) {
+    items.splice(replaceIdx, 1, <FileReplaceButton key={"fileReplaceButton"} />);
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
items.splice(
items.findIndex((c) => c.key === "replaceFileButton"),
1,
<FileReplaceButton key={"fileReplaceButton"} />,
);
const replaceIdx = items.findIndex((c) => c.key === "replaceFileButton");
if (replaceIdx !== -1) {
items.splice(replaceIdx, 1, <FileReplaceButton key={"fileReplaceButton"} />);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/03-ui-components/11-uppy-file-panel/src/App.tsx` around lines 19 -
23, The splice call uses items.findIndex((c) => c.key === "replaceFileButton")
which can return -1 and cause Array.splice(-1, ...) to replace the last toolbar
item; change the logic to first store the result (e.g., const idx =
items.findIndex(...)) and only call items.splice(idx, 1, <FileReplaceButton
key={"fileReplaceButton"} />) when idx !== -1 (no-op otherwise) so you only
replace when the "replaceFileButton" key actually exists.


return <FormattingToolbar {...props}>{items}</FormattingToolbar>;
};

export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
Expand All @@ -37,19 +50,7 @@ export default function App() {
// Renders the editor instance using a React component.
return (
<BlockNoteView editor={editor} formattingToolbar={false} filePanel={false}>
<FormattingToolbarController
formattingToolbar={(props) => {
// Replaces default file replace button with one that opens Uppy.
const items = getFormattingToolbarItems();
items.splice(
items.findIndex((c) => c.key === "replaceFileButton"),
1,
<FileReplaceButton key={"fileReplaceButton"} />,
);

return <FormattingToolbar {...props}>{items}</FormattingToolbar>;
}}
/>
<FormattingToolbarController formattingToolbar={CustomFormattingToolbar} />
{/* Replaces default file panel with Uppy one. */}
<FilePanelController filePanel={UppyFilePanel} />
</BlockNoteView>
Expand Down
41 changes: 21 additions & 20 deletions examples/03-ui-components/16-link-toolbar-buttons/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,32 @@ import {
EditLinkButton,
LinkToolbar,
LinkToolbarController,
LinkToolbarProps,
OpenLinkButton,
useCreateBlockNote,
} from "@blocknote/react";

import { AlertButton } from "./AlertButton";

const CustomLinkToolbar = (props: LinkToolbarProps) => (
<LinkToolbar {...props}>
<EditLinkButton
url={props.url}
text={props.text}
range={props.range}
setToolbarOpen={props.setToolbarOpen}
setToolbarPositionFrozen={props.setToolbarPositionFrozen}
/>
<OpenLinkButton url={props.url} />
<DeleteLinkButton
range={props.range}
setToolbarOpen={props.setToolbarOpen}
/>
{/* Extra button to open alert. */}
<AlertButton {...props} />
</LinkToolbar>
);

export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
Expand Down Expand Up @@ -49,26 +69,7 @@ export default function App() {
// Renders the editor instance.
return (
<BlockNoteView editor={editor} linkToolbar={false}>
<LinkToolbarController
linkToolbar={(props) => (
<LinkToolbar {...props}>
<EditLinkButton
url={props.url}
text={props.text}
range={props.range}
setToolbarOpen={props.setToolbarOpen}
setToolbarPositionFrozen={props.setToolbarPositionFrozen}
/>
<OpenLinkButton url={props.url} />
<DeleteLinkButton
range={props.range}
setToolbarOpen={props.setToolbarOpen}
/>
{/* Extra button to open alert. */}
<AlertButton {...props} />
</LinkToolbar>
)}
/>
<LinkToolbarController linkToolbar={CustomLinkToolbar} />
</BlockNoteView>
);
}
Loading
Loading