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 ( <>