diff --git a/docs/content/docs/features/ai/custom-commands.mdx b/docs/content/docs/features/ai/custom-commands.mdx
index de02f19743..75b5c029db 100644
--- a/docs/content/docs/features/ai/custom-commands.mdx
+++ b/docs/content/docs/features/ai/custom-commands.mdx
@@ -26,8 +26,8 @@ First, we define a new AI command. Let's create one that makes selected text mor
```tsx
import {
+ AIExtension,
AIMenuSuggestionItem,
- getAIExtension,
aiDocumentFormats,
} from "@blocknote/xl-ai";
@@ -40,7 +40,7 @@ export const makeInformal = (
aliases: ["informal", "make informal", "casual"],
icon: ,
onItemClick: async () => {
- await getAIExtension(editor).invokeAI({
+ await editor.getExtension(AIExtension)?.invokeAI({
// The prompt to send to the LLM:
userPrompt: "Give the selected text a more informal (casual) tone",
// Tell the LLM to specifically use the selected content as context (instead of the whole document)
diff --git a/docs/content/docs/features/ai/reference.mdx b/docs/content/docs/features/ai/reference.mdx
index 2bafd6b647..1197efcc6b 100644
--- a/docs/content/docs/features/ai/reference.mdx
+++ b/docs/content/docs/features/ai/reference.mdx
@@ -52,14 +52,6 @@ type AIRequestHelpers = {
};
```
-## `getAIExtension`
-
-Use `getAIExtension` to retrieve the AI extension instance registered to the editor:
-
-```typescript
-function getAIExtension(editor: BlockNoteEditor): AIExtension;
-```
-
## `AIExtension`
The `AIExtension` class is the main class for the AI extension. It exposes state and methods to interact with BlockNote's AI features.
diff --git a/docs/content/docs/features/extensions.mdx b/docs/content/docs/features/extensions.mdx
index e2fa8e904e..8b1dcd37c0 100644
--- a/docs/content/docs/features/extensions.mdx
+++ b/docs/content/docs/features/extensions.mdx
@@ -14,7 +14,7 @@ BlockNote includes an extensions system which lets you expand the editor's behav
## Creating an extension
-An extension is an instance of the [`BlockNoteExtension`](https://github.com/TypeCellOS/BlockNote/blob/10cdbfb5f77ef82f3617c0fa1191e0bf5b7358c5/packages/core/src/editor/BlockNoteExtension.ts#L13) class. However, it's recommended for most use cases to create extensions using the `createBlockNoteExtension` function, rather than instanciating the class directly:
+An extension is an instance of the [`BlockNoteExtension`](https://github.com/TypeCellOS/BlockNote/blob/10cdbfb5f77ef82f3617c0fa1191e0bf5b7358c5/packages/core/src/editor/BlockNoteExtension.ts#L13) class. However, it's recommended for most use cases to create extensions using the `createExtension` function, rather than instanciating the class directly:
```typescript
type BlockNoteExtensionOptions = {
@@ -43,10 +43,10 @@ const customBlockExtensionOptions: BlockNoteExtensionOptions = {
tiptapExtensions: ...,
}
-const CustomExtension = createBlockNoteExtension(customBlockExtensionOptions);
+const CustomExtension = createExtension(customBlockExtensionOptions);
```
-Let's go over the options that can be passed into `createBlockNoteExtension`:
+Let's go over the options that can be passed into `createExtension`:
`key:` The name of the extension.
@@ -74,7 +74,7 @@ The `extensions` [editor option](/docs/reference/editor/overview#options) takes
const editor = useCreateBlockNote({
extensions: [
// Add extensions here:
- createBlockNoteExtension({ ... })
+ createExtension({ ... })
],
});
```
@@ -95,7 +95,7 @@ const createCustomBlock = createReactBlockSpec(
}
[
// Add extensions here:
- createBlockNoteExtension({ ... })
+ createExtension({ ... })
],
});
```
diff --git a/docs/content/docs/reference/editor/events.mdx b/docs/content/docs/reference/editor/events.mdx
index 61349c79c9..e575c8b883 100644
--- a/docs/content/docs/reference/editor/events.mdx
+++ b/docs/content/docs/reference/editor/events.mdx
@@ -16,17 +16,6 @@ The editor emits events for:
- **Content changes** - When blocks are inserted, updated, or deleted
- **Selection changes** - When the cursor position or selection changes
-## `onCreate`
-
-The `onCreate` callback is called when the editor has been initialized and is ready for use.
-
-```typescript
-editor.onCreate(() => {
- console.log("Editor is ready for use");
- // Initialize plugins, set up event listeners, etc.
-});
-```
-
## `onMount`
The `onMount` callback is called when the editor has been mounted.
diff --git a/docs/package.json b/docs/package.json
index 59d4ba136d..9a7d3a4b3f 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -77,7 +77,7 @@
"better-sqlite3": "^11.10.0",
"classnames": "2.3.2",
"clsx": "2.1.1",
- "docx": "^9.0.2",
+ "docx": "^9.5.1",
"framer-motion": "^11.18.2",
"fumadocs-core": "15.5.4",
"fumadocs-docgen": "2.0.1",
diff --git a/examples/01-basic/03-multi-column/src/App.tsx b/examples/01-basic/03-multi-column/src/App.tsx
index c126a9d2bf..3a0d10d8d9 100644
--- a/examples/01-basic/03-multi-column/src/App.tsx
+++ b/examples/01-basic/03-multi-column/src/App.tsx
@@ -1,8 +1,8 @@
import {
BlockNoteSchema,
combineByGroup,
- filterSuggestionItems,
} from "@blocknote/core";
+import { filterSuggestionItems } from "@blocknote/core/extensions";
import * as locales from "@blocknote/core/locales";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
diff --git a/examples/03-ui-components/02-formatting-toolbar-buttons/src/BlueButton.tsx b/examples/03-ui-components/02-formatting-toolbar-buttons/src/BlueButton.tsx
index b469360c8f..eedb7c6685 100644
--- a/examples/03-ui-components/02-formatting-toolbar-buttons/src/BlueButton.tsx
+++ b/examples/03-ui-components/02-formatting-toolbar-buttons/src/BlueButton.tsx
@@ -2,10 +2,9 @@ import "@blocknote/mantine/style.css";
import {
useBlockNoteEditor,
useComponentsContext,
- useEditorContentOrSelectionChange,
+ useEditorState,
useSelectedBlocks,
} from "@blocknote/react";
-import { useState } from "react";
// Custom Formatting Toolbar Button to toggle blue text & background color.
export function BlueButton() {
@@ -14,18 +13,12 @@ export function BlueButton() {
const Components = useComponentsContext()!;
// Tracks whether the text & background are both blue.
- const [isSelected, setIsSelected] = useState(
- editor.getActiveStyles().textColor === "blue" &&
- editor.getActiveStyles().backgroundColor === "blue",
- );
-
- // Updates state on content or selection change.
- useEditorContentOrSelectionChange(() => {
- setIsSelected(
+ const isSelected = useEditorState({
+ editor,
+ selector: ({ editor }) =>
editor.getActiveStyles().textColor === "blue" &&
- editor.getActiveStyles().backgroundColor === "blue",
- );
- }, editor);
+ editor.getActiveStyles().backgroundColor === "blue",
+ });
// Doesn't render unless a at least one block with inline content is
// selected. You can use a similar pattern of returning `null` to
diff --git a/examples/03-ui-components/04-side-menu-buttons/src/App.tsx b/examples/03-ui-components/04-side-menu-buttons/src/App.tsx
index 8661c08baa..96ef099ef3 100644
--- a/examples/03-ui-components/04-side-menu-buttons/src/App.tsx
+++ b/examples/03-ui-components/04-side-menu-buttons/src/App.tsx
@@ -39,7 +39,7 @@ export default function App() {
sideMenu={(props) => (
{/* Button which removes the hovered block. */}
-
+
)}
diff --git a/examples/03-ui-components/04-side-menu-buttons/src/RemoveBlockButton.tsx b/examples/03-ui-components/04-side-menu-buttons/src/RemoveBlockButton.tsx
index c387f67f1e..6c8e21d0e2 100644
--- a/examples/03-ui-components/04-side-menu-buttons/src/RemoveBlockButton.tsx
+++ b/examples/03-ui-components/04-side-menu-buttons/src/RemoveBlockButton.tsx
@@ -1,16 +1,20 @@
+import {} from "@blocknote/core";
+import { SideMenuExtension } from "@blocknote/core/extensions";
import {
- SideMenuProps,
useBlockNoteEditor,
useComponentsContext,
+ useExtension,
} from "@blocknote/react";
import { MdDelete } from "react-icons/md";
// Custom Side Menu button to remove the hovered block.
-export function RemoveBlockButton(props: SideMenuProps) {
+export function RemoveBlockButton() {
const editor = useBlockNoteEditor();
const Components = useComponentsContext()!;
+ const sideMenu = useExtension(SideMenuExtension);
+
return (
{
- editor.removeBlocks([props.block]);
+ editor.removeBlocks([sideMenu.store.state!.block]);
}}
/>
}
diff --git a/examples/03-ui-components/05-side-menu-drag-handle-items/src/App.tsx b/examples/03-ui-components/05-side-menu-drag-handle-items/src/App.tsx
index 88d82aad2d..0ff3a07174 100644
--- a/examples/03-ui-components/05-side-menu-drag-handle-items/src/App.tsx
+++ b/examples/03-ui-components/05-side-menu-drag-handle-items/src/App.tsx
@@ -4,7 +4,6 @@ import "@blocknote/mantine/style.css";
import {
BlockColorsItem,
DragHandleMenu,
- DragHandleMenuProps,
RemoveBlockItem,
SideMenu,
SideMenuController,
@@ -16,12 +15,12 @@ import { ResetBlockTypeItem } from "./ResetBlockTypeItem";
// To avoid rendering issues, it's good practice to define your custom drag
// handle menu in a separate component, instead of inline within the `sideMenu`
// prop of `SideMenuController`.
-const CustomDragHandleMenu = (props: DragHandleMenuProps) => (
-
- Delete
- Colors
+const CustomDragHandleMenu = () => (
+
+ Delete
+ Colors
{/* Item which resets the hovered block's type. */}
- Reset Type
+ Reset Type
);
diff --git a/examples/03-ui-components/05-side-menu-drag-handle-items/src/ResetBlockTypeItem.tsx b/examples/03-ui-components/05-side-menu-drag-handle-items/src/ResetBlockTypeItem.tsx
index 847c7b9f6c..f81e129a3d 100644
--- a/examples/03-ui-components/05-side-menu-drag-handle-items/src/ResetBlockTypeItem.tsx
+++ b/examples/03-ui-components/05-side-menu-drag-handle-items/src/ResetBlockTypeItem.tsx
@@ -1,21 +1,26 @@
+import {} from "@blocknote/core";
+import { SideMenuExtension } from "@blocknote/core/extensions";
import {
- DragHandleMenuProps,
useBlockNoteEditor,
useComponentsContext,
+ useExtension,
} from "@blocknote/react";
+import { ReactNode } from "react";
-export function ResetBlockTypeItem(props: DragHandleMenuProps) {
+export function ResetBlockTypeItem(props: { children: ReactNode }) {
const editor = useBlockNoteEditor();
const Components = useComponentsContext()!;
+ const sideMenu = useExtension(SideMenuExtension);
+
return (
{
- editor.updateBlock(props.block, { type: "paragraph" });
+ editor.updateBlock(sideMenu.store.state!.block, { type: "paragraph" });
}}
>
- Reset Type
+ {props.children}
);
}
diff --git a/examples/03-ui-components/06-suggestion-menus-slash-menu-items/src/App.tsx b/examples/03-ui-components/06-suggestion-menus-slash-menu-items/src/App.tsx
index 61fc407ff7..c5f65cfdd8 100644
--- a/examples/03-ui-components/06-suggestion-menus-slash-menu-items/src/App.tsx
+++ b/examples/03-ui-components/06-suggestion-menus-slash-menu-items/src/App.tsx
@@ -1,8 +1,8 @@
+import { BlockNoteEditor } from "@blocknote/core";
import {
- BlockNoteEditor,
filterSuggestionItems,
- insertOrUpdateBlock,
-} from "@blocknote/core";
+ insertOrUpdateBlockForSlashMenu,
+} from "@blocknote/core/extensions";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
@@ -22,7 +22,7 @@ const insertHelloWorldItem = (editor: BlockNoteEditor) => ({
// changes its type to the provided block. Otherwise, it inserts the new
// block below and moves the text caret to it. We use this function with
// a block containing 'Hello World' in bold.
- insertOrUpdateBlock(editor, {
+ insertOrUpdateBlockForSlashMenu(editor, {
type: "paragraph",
content: [{ type: "text", text: "Hello World", styles: { bold: true } }],
}),
diff --git a/examples/03-ui-components/10-suggestion-menus-grid-mentions/src/App.tsx b/examples/03-ui-components/10-suggestion-menus-grid-mentions/src/App.tsx
index 333c645135..0c2f9f6c21 100644
--- a/examples/03-ui-components/10-suggestion-menus-grid-mentions/src/App.tsx
+++ b/examples/03-ui-components/10-suggestion-menus-grid-mentions/src/App.tsx
@@ -1,8 +1,8 @@
import {
BlockNoteSchema,
defaultInlineContentSpecs,
- filterSuggestionItems,
} from "@blocknote/core";
+import { filterSuggestionItems } from "@blocknote/core/extensions";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
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
index e73723a9f9..d3f393b04c 100644
--- a/examples/03-ui-components/11-uppy-file-panel/src/FileReplaceButton.tsx
+++ b/examples/03-ui-components/11-uppy-file-panel/src/FileReplaceButton.tsx
@@ -48,7 +48,7 @@ export const FileReplaceButton = () => {
}
return (
-
+
{
variant={"panel-popover"}
>
{/* Replaces default file panel with our Uppy one. */}
-
+
);
diff --git a/examples/03-ui-components/11-uppy-file-panel/src/UppyFilePanel.tsx b/examples/03-ui-components/11-uppy-file-panel/src/UppyFilePanel.tsx
index eaf2d4c253..4094bc4441 100644
--- a/examples/03-ui-components/11-uppy-file-panel/src/UppyFilePanel.tsx
+++ b/examples/03-ui-components/11-uppy-file-panel/src/UppyFilePanel.tsx
@@ -43,7 +43,7 @@ const uppy = new Uppy()
});
export function UppyFilePanel(props: FilePanelProps) {
- const { block } = props;
+ const { blockId } = props;
const editor = useBlockNoteEditor();
useEffect(() => {
@@ -68,7 +68,7 @@ export function UppyFilePanel(props: FilePanelProps) {
url: response.uploadURL,
},
};
- editor.updateBlock(block, updateData);
+ editor.updateBlock(blockId, updateData);
// File should be removed from the Uppy instance after upload.
uppy.removeFile(file.id);
@@ -78,7 +78,7 @@ export function UppyFilePanel(props: FilePanelProps) {
return () => {
uppy.off("upload-success", handler);
};
- }, [block, editor]);
+ }, [blockId, editor]);
// set up dashboard as in https://uppy.io/examples/
return ;
diff --git a/examples/03-ui-components/13-custom-ui/src/App.tsx b/examples/03-ui-components/13-custom-ui/src/App.tsx
index 4fe6427ded..3a351264cd 100644
--- a/examples/03-ui-components/13-custom-ui/src/App.tsx
+++ b/examples/03-ui-components/13-custom-ui/src/App.tsx
@@ -1,4 +1,5 @@
-import { filterSuggestionItems } from "@blocknote/core";
+import { } from "@blocknote/core";
+import { filterSuggestionItems } from "@blocknote/core/extensions";
import "@blocknote/core/fonts/inter.css";
import {
BlockNoteViewRaw,
diff --git a/examples/03-ui-components/13-custom-ui/src/MUIFormattingToolbar.tsx b/examples/03-ui-components/13-custom-ui/src/MUIFormattingToolbar.tsx
index f795be6641..9c5ff9f829 100644
--- a/examples/03-ui-components/13-custom-ui/src/MUIFormattingToolbar.tsx
+++ b/examples/03-ui-components/13-custom-ui/src/MUIFormattingToolbar.tsx
@@ -2,7 +2,7 @@ import { Block } from "@blocknote/core";
import {
blockTypeSelectItems,
useBlockNoteEditor,
- useEditorContentOrSelectionChange,
+ useEditorState,
} from "@blocknote/react";
import {
Done,
@@ -108,17 +108,10 @@ function MUIToolbarSelect- (props: {
function MUIBlockTypeSelect() {
const editor = useBlockNoteEditor();
- // The block currently containing the text cursor.
- const [block, setBlock] = useState(
- editor.getTextCursorPosition().block,
- );
-
- // Updates the block currently containing the text cursor whenever the editor
- // content or selection changes.
- useEditorContentOrSelectionChange(
- () => setBlock(editor.getTextCursorPosition().block),
+ const block = useEditorState({
editor,
- );
+ selector: ({ editor }) => editor.getTextCursorPosition().block,
+ });
// Gets the default items for the select.
const defaultBlockTypeSelectItems = useMemo(
@@ -154,8 +147,6 @@ function MUIBlockTypeSelect() {
props: newSelectedItem.props,
});
editor.focus();
-
- setBlock(editor.getTextCursorPosition().block);
},
[block, defaultBlockTypeSelectItems, editor],
);
@@ -220,16 +211,10 @@ function MUIBasicTextStyleButton(props: {
const editor = useBlockNoteEditor();
// Whether the text style is currently active.
- const [textStyleActive, setTextStyleActive] = useState(
- !!editor.getActiveStyles()[props.textStyle],
- );
-
- // Updates whether the text style is active when the editor content or
- // selection changes.
- useEditorContentOrSelectionChange(
- () => setTextStyleActive(props.textStyle in editor.getActiveStyles()),
+ const textStyleActive = useEditorState({
editor,
- );
+ selector: ({ editor }) => props.textStyle in editor.getActiveStyles(),
+ });
// Tooltip for the button.
const tooltip = useMemo(
@@ -273,24 +258,16 @@ function MUITextAlignButton(props: {
const editor = useBlockNoteEditor();
// The text alignment of the block currently containing the text cursor.
- const [activeTextAlignment, setActiveTextAlignment] = useState(() => {
- const props = editor.getTextCursorPosition().block.props;
- if ("textAlignment" in props) {
- return props.textAlignment;
- }
- return undefined;
- });
-
- // Updates the text alignment when the editor content or selection changes.
- useEditorContentOrSelectionChange(() => {
- setActiveTextAlignment(() => {
+ const activeTextAlignment = useEditorState({
+ editor,
+ selector: ({ editor }) => {
const props = editor.getTextCursorPosition().block.props;
if ("textAlignment" in props) {
return props.textAlignment;
}
return undefined;
- });
- }, editor);
+ },
+ });
// Tooltip for the button.
const tooltip = useMemo(
@@ -346,21 +323,15 @@ function MUIColorStyleButton() {
const [anchorEl, setAnchorEl] = useState(null);
// The active text and background colors.
- const [activeTextColor, setActiveTextColor] = useState(
- () => editor.getActiveStyles().textColor || "default",
- );
- const [activeBackgroundColor, setActiveBackgroundColor] = useState(
- () => editor.getActiveStyles().backgroundColor || "default",
- );
-
- // Updates the active text and background colors when the editor content or
- // selection changes.
- useEditorContentOrSelectionChange(() => {
- const activeStyles = editor.getActiveStyles();
-
- setActiveTextColor(activeStyles.textColor || "default");
- setActiveBackgroundColor(activeStyles.backgroundColor || "default");
- }, editor);
+ const activeTextColor = useEditorState({
+ editor,
+ selector: ({ editor }) => editor.getActiveStyles().textColor || "default",
+ });
+ const activeBackgroundColor = useEditorState({
+ editor,
+ selector: ({ editor }) =>
+ editor.getActiveStyles().backgroundColor || "default",
+ });
// Handles opening and closing the color menu.
const onClick = useCallback(
diff --git a/examples/03-ui-components/13-custom-ui/src/MUISideMenu.tsx b/examples/03-ui-components/13-custom-ui/src/MUISideMenu.tsx
index 8f42580c1f..daa4155f0f 100644
--- a/examples/03-ui-components/13-custom-ui/src/MUISideMenu.tsx
+++ b/examples/03-ui-components/13-custom-ui/src/MUISideMenu.tsx
@@ -1,4 +1,11 @@
-import { SideMenuProps } from "@blocknote/react";
+import {} from "@blocknote/core";
+import { SideMenuExtension } from "@blocknote/core/extensions";
+import {
+ SideMenuProps,
+ useBlockNoteEditor,
+ useExtension,
+ useExtensionState,
+} from "@blocknote/react";
import { Delete, DragIndicator } from "@mui/icons-material";
import {
Box,
@@ -9,22 +16,22 @@ import {
MenuItem,
Typography,
} from "@mui/material";
-import { MouseEvent, ReactNode, useCallback, useMemo, useState } from "react";
-
-import { TextBlockSchema } from "./schema";
+import { MouseEvent, ReactNode, useCallback, useState } from "react";
// This replaces the default `RemoveBlockItem` component with a simplified
// MUI version:
// https://github.com/TypeCellOS/BlockNote/blob/main/packages/react/src/components/SideMenu/DragHandleMenu/DefaultItems/RemoveBlockItem.tsx
function MUIRemoveBlockItem(
- props: SideMenuProps & { closeDragHandleMenu: () => void },
+ props: SideMenuProps & { closeDragHandleMenu: () => void },
) {
+ const editor = useBlockNoteEditor();
+ const sideMenu = useExtension(SideMenuExtension, { editor });
// Deletes the block next to the side menu.
const onClick = useCallback(() => {
- props.unfreezeMenu();
+ sideMenu.unfreezeMenu();
props.closeDragHandleMenu();
- props.editor.removeBlocks([props.editor.getTextCursorPosition().block]);
- props.editor.focus();
+ editor.removeBlocks([editor.getTextCursorPosition().block]);
+ editor.focus();
}, [props]);
return (
@@ -70,17 +77,19 @@ function MUIDragHandleMenu(props: {
// This replaces the default `DragHandleButton` component with a simplified MUI
// version:
// https://github.com/TypeCellOS/BlockNote/blob/main/packages/react/src/components/SideMenu/DefaultButtons/DragHandleButton.tsx
-function MUIDragHandleButton(props: SideMenuProps) {
+function MUIDragHandleButton(props: SideMenuProps) {
// Anchor/trigger element for the color menu.
const [anchorEl, setAnchorEl] = useState(null);
+ const editor = useBlockNoteEditor();
+ const sideMenu = useExtension(SideMenuExtension, { editor });
// Handles opening and closing the drag handle menu.
const onClick = useCallback(
(event: MouseEvent) => {
- props.freezeMenu();
+ sideMenu.freezeMenu();
setAnchorEl(event.currentTarget);
},
- [props],
+ [sideMenu],
);
const onClose = useCallback(() => {
setAnchorEl(null);
@@ -93,8 +102,10 @@ function MUIDragHandleButton(props: SideMenuProps) {
component={"button"}
draggable={"true"}
onClick={onClick}
- onDragStart={(e) => props.blockDragStart(e, props.block)}
- onDragEnd={props.blockDragEnd}
+ onDragStart={(e) =>
+ sideMenu.blockDragStart(e, sideMenu.store.state!.block)
+ }
+ onDragEnd={sideMenu.blockDragEnd}
>
) {
// This replaces the generic Mantine `SideMenu` component:
// https://github.com/TypeCellOS/BlockNote/blob/main/packages/mantine/src/sideMenu/SideMenu.tsx
-function MUISideMenu(
- props: SideMenuProps & { children: ReactNode },
-) {
+function MUISideMenu(props: SideMenuProps & { children: ReactNode }) {
// Since the side menu is positioned by the top-left corner of a block, we
// manually set its height based on the hovered block so that it's vertically
// centered.
- const sideMenuHeight = useMemo(() => {
- if (props.block.type === "heading") {
- if (props.block.props.level === 1) {
- return 78;
- }
+ const sideMenuHeight = useExtensionState(SideMenuExtension, {
+ selector: (state) => {
+ // TODO this feels like a hack
+ if (state && state.block.type === "heading") {
+ if (state.block.props.level === 1) {
+ return 78;
+ }
- if (props.block.props.level === 2) {
- return 54;
- }
+ if (state.block.props.level === 2) {
+ return 54;
+ }
- if (props.block.props.level === 3) {
- return 37;
+ if (state.block.props.level === 3) {
+ return 37;
+ }
}
- }
- return 30;
- }, [props.block]);
+ return 30;
+ },
+ });
return (
) {
+export function CustomMUISideMenu(props: SideMenuProps) {
return (
diff --git a/examples/03-ui-components/16-link-toolbar-buttons/src/App.tsx b/examples/03-ui-components/16-link-toolbar-buttons/src/App.tsx
index 744a1e2bd1..f2c26763b1 100644
--- a/examples/03-ui-components/16-link-toolbar-buttons/src/App.tsx
+++ b/examples/03-ui-components/16-link-toolbar-buttons/src/App.tsx
@@ -55,10 +55,15 @@ export default function App() {
-
+
{/* Extra button to open alert. */}
diff --git a/examples/05-interoperability/05-converting-blocks-to-pdf/src/App.tsx b/examples/05-interoperability/05-converting-blocks-to-pdf/src/App.tsx
index d910886113..7a34932ec8 100644
--- a/examples/05-interoperability/05-converting-blocks-to-pdf/src/App.tsx
+++ b/examples/05-interoperability/05-converting-blocks-to-pdf/src/App.tsx
@@ -1,9 +1,9 @@
import {
BlockNoteSchema,
combineByGroup,
- filterSuggestionItems,
withPageBreak,
} from "@blocknote/core";
+import { filterSuggestionItems } from "@blocknote/core/extensions";
import "@blocknote/core/fonts/inter.css";
import * as locales from "@blocknote/core/locales";
import { BlockNoteView } from "@blocknote/mantine";
diff --git a/examples/05-interoperability/06-converting-blocks-to-docx/.bnexample.json b/examples/05-interoperability/06-converting-blocks-to-docx/.bnexample.json
index e823472a1b..9c92212421 100644
--- a/examples/05-interoperability/06-converting-blocks-to-docx/.bnexample.json
+++ b/examples/05-interoperability/06-converting-blocks-to-docx/.bnexample.json
@@ -6,7 +6,7 @@
"dependencies": {
"@blocknote/xl-docx-exporter": "latest",
"@blocknote/xl-multi-column": "latest",
- "docx": "^9.0.2"
+ "docx": "^9.5.1"
},
"pro": true
}
diff --git a/examples/05-interoperability/06-converting-blocks-to-docx/package.json b/examples/05-interoperability/06-converting-blocks-to-docx/package.json
index 542f835b4d..af9cd10207 100644
--- a/examples/05-interoperability/06-converting-blocks-to-docx/package.json
+++ b/examples/05-interoperability/06-converting-blocks-to-docx/package.json
@@ -23,7 +23,7 @@
"react-dom": "^19.2.0",
"@blocknote/xl-docx-exporter": "latest",
"@blocknote/xl-multi-column": "latest",
- "docx": "^9.0.2"
+ "docx": "^9.5.1"
},
"devDependencies": {
"@types/react": "^19.2.2",
diff --git a/examples/05-interoperability/06-converting-blocks-to-docx/src/App.tsx b/examples/05-interoperability/06-converting-blocks-to-docx/src/App.tsx
index 9c91a99aff..8c5ae2398f 100644
--- a/examples/05-interoperability/06-converting-blocks-to-docx/src/App.tsx
+++ b/examples/05-interoperability/06-converting-blocks-to-docx/src/App.tsx
@@ -1,9 +1,9 @@
import {
BlockNoteSchema,
combineByGroup,
- filterSuggestionItems,
withPageBreak,
} from "@blocknote/core";
+import { filterSuggestionItems } from "@blocknote/core/extensions";
import "@blocknote/core/fonts/inter.css";
import * as locales from "@blocknote/core/locales";
import { BlockNoteView } from "@blocknote/mantine";
diff --git a/examples/05-interoperability/07-converting-blocks-to-odt/src/App.tsx b/examples/05-interoperability/07-converting-blocks-to-odt/src/App.tsx
index 9ece22d905..fcfa07ff85 100644
--- a/examples/05-interoperability/07-converting-blocks-to-odt/src/App.tsx
+++ b/examples/05-interoperability/07-converting-blocks-to-odt/src/App.tsx
@@ -2,8 +2,8 @@ import {
BlockNoteSchema,
combineByGroup,
withPageBreak,
- filterSuggestionItems,
} from "@blocknote/core";
+import { filterSuggestionItems } from "@blocknote/core/extensions";
import * as locales from "@blocknote/core/locales";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
diff --git a/examples/05-interoperability/08-converting-blocks-to-react-email/src/App.tsx b/examples/05-interoperability/08-converting-blocks-to-react-email/src/App.tsx
index 9b46d8e927..5d3d896b8f 100644
--- a/examples/05-interoperability/08-converting-blocks-to-react-email/src/App.tsx
+++ b/examples/05-interoperability/08-converting-blocks-to-react-email/src/App.tsx
@@ -3,9 +3,9 @@ import {
COLORS_DARK_MODE_DEFAULT,
COLORS_DEFAULT,
combineByGroup,
- filterSuggestionItems,
withPageBreak,
} from "@blocknote/core";
+import { filterSuggestionItems } from "@blocknote/core/extensions";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
diff --git a/examples/06-custom-schema/02-suggestion-menus-mentions/src/App.tsx b/examples/06-custom-schema/02-suggestion-menus-mentions/src/App.tsx
index 82bbccdf59..4339153441 100644
--- a/examples/06-custom-schema/02-suggestion-menus-mentions/src/App.tsx
+++ b/examples/06-custom-schema/02-suggestion-menus-mentions/src/App.tsx
@@ -1,8 +1,8 @@
import {
BlockNoteSchema,
defaultInlineContentSpecs,
- filterSuggestionItems,
} from "@blocknote/core";
+import { filterSuggestionItems } from "@blocknote/core/extensions";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
diff --git a/examples/06-custom-schema/04-pdf-file-block/src/App.tsx b/examples/06-custom-schema/04-pdf-file-block/src/App.tsx
index f0252e4dc4..3c244a2840 100644
--- a/examples/06-custom-schema/04-pdf-file-block/src/App.tsx
+++ b/examples/06-custom-schema/04-pdf-file-block/src/App.tsx
@@ -1,9 +1,8 @@
+import { BlockNoteSchema, defaultBlockSpecs } from "@blocknote/core";
import {
- BlockNoteSchema,
- defaultBlockSpecs,
filterSuggestionItems,
- insertOrUpdateBlock,
-} from "@blocknote/core";
+ insertOrUpdateBlockForSlashMenu,
+} from "@blocknote/core/extensions";
import { en } from "@blocknote/core/locales";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
@@ -39,7 +38,7 @@ const schema = BlockNoteSchema.create({
const insertPDF = (editor: typeof schema.BlockNoteEditor) => ({
title: "PDF",
onItemClick: () => {
- insertOrUpdateBlock(editor, {
+ insertOrUpdateBlockForSlashMenu(editor, {
type: "pdf",
});
},
diff --git a/examples/06-custom-schema/05-alert-block-full-ux/src/App.tsx b/examples/06-custom-schema/05-alert-block-full-ux/src/App.tsx
index 21dc29650a..625dcce896 100644
--- a/examples/06-custom-schema/05-alert-block-full-ux/src/App.tsx
+++ b/examples/06-custom-schema/05-alert-block-full-ux/src/App.tsx
@@ -1,9 +1,8 @@
+import { BlockNoteSchema, defaultBlockSpecs } from "@blocknote/core";
import {
- BlockNoteSchema,
- defaultBlockSpecs,
filterSuggestionItems,
- insertOrUpdateBlock,
-} from "@blocknote/core";
+ insertOrUpdateBlockForSlashMenu,
+} from "@blocknote/core/extensions";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
@@ -38,7 +37,7 @@ const insertAlert = (editor: typeof schema.BlockNoteEditor) => ({
// changes its type to the provided block. Otherwise, it inserts the new
// block below and moves the text caret to it. We use this function with an
// Alert block.
- insertOrUpdateBlock(editor, {
+ insertOrUpdateBlockForSlashMenu(editor, {
type: "alert",
}),
aliases: [
diff --git a/examples/07-collaboration/05-comments/src/App.tsx b/examples/07-collaboration/05-comments/src/App.tsx
index bd11b2539e..7756abedf1 100644
--- a/examples/07-collaboration/05-comments/src/App.tsx
+++ b/examples/07-collaboration/05-comments/src/App.tsx
@@ -1,6 +1,7 @@
"use client";
import {
+ CommentsExtension,
DefaultThreadStoreAuth,
YjsThreadStore,
} from "@blocknote/core/comments";
@@ -74,10 +75,7 @@ function Document() {
// setup the editor with comments and collaboration
const editor = useCreateBlockNote(
{
- resolveUsers,
- comments: {
- threadStore,
- },
+ extensions: [CommentsExtension({ threadStore, resolveUsers })],
collaboration: {
provider,
fragment: doc.getXmlFragment("blocknote"),
diff --git a/examples/07-collaboration/06-comments-with-sidebar/src/App.tsx b/examples/07-collaboration/06-comments-with-sidebar/src/App.tsx
index d743eb3803..84ad0d577a 100644
--- a/examples/07-collaboration/06-comments-with-sidebar/src/App.tsx
+++ b/examples/07-collaboration/06-comments-with-sidebar/src/App.tsx
@@ -3,6 +3,7 @@
import {
DefaultThreadStoreAuth,
YjsThreadStore,
+ CommentsExtension,
} from "@blocknote/core/comments";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
@@ -77,15 +78,12 @@ export default function App() {
// setup the editor with comments and collaboration
const editor = useCreateBlockNote(
{
- resolveUsers,
- comments: {
- threadStore,
- },
collaboration: {
provider,
fragment: doc.getXmlFragment("blocknote"),
user: { color: getRandomColor(), name: activeUser.username },
},
+ extensions: [CommentsExtension({ threadStore, resolveUsers })],
},
[activeUser, threadStore],
);
diff --git a/examples/07-collaboration/08-forking/src/App.tsx b/examples/07-collaboration/08-forking/src/App.tsx
index ba6398bb51..d338e133d7 100644
--- a/examples/07-collaboration/08-forking/src/App.tsx
+++ b/examples/07-collaboration/08-forking/src/App.tsx
@@ -1,11 +1,15 @@
import "@blocknote/core/fonts/inter.css";
-import { useCreateBlockNote } from "@blocknote/react";
+import {} from "@blocknote/core";
+import { ForkYDocExtension } from "@blocknote/core/extensions";
+import {
+ useCreateBlockNote,
+ useExtension,
+ useExtensionState,
+} from "@blocknote/react";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import YPartyKitProvider from "y-partykit/provider";
import * as Y from "yjs";
-import { useEffect } from "react";
-import { useState } from "react";
// Sets up Yjs document and PartyKit Yjs provider.
const doc = new Y.Doc();
@@ -30,18 +34,18 @@ export default function App() {
},
},
});
- const [isForked, setIsForked] = useState(false);
-
- useEffect(() => {
- editor.forkYDocPlugin!.on("forked", setIsForked);
- }, [editor]);
+ const forkYDocPlugin = useExtension(ForkYDocExtension, { editor });
+ const isForked = useExtensionState(ForkYDocExtension, {
+ editor,
+ selector: (state) => state.isForked,
+ });
// Renders the editor instance.
return (
<>