From e4fb5c19072b249ce7dcd300b8b105e1860e7cd9 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Thu, 28 May 2026 02:01:51 +0200 Subject: [PATCH 01/11] ci: add github-actions ecosystem to dependabot --- .github/dependabot.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ce593666e8..4cd39c8b21 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -57,3 +57,12 @@ updates: - "y-prosemirror" cooldown: default-days: 7 + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + commit-message: + prefix: "ci" + include: "scope" + cooldown: + default-days: 7 From 9cbf2adab52f9b36712ca1f4131073876ebf6c83 Mon Sep 17 00:00:00 2001 From: Yuki Terashima <13657589+y-temp4@users.noreply.github.com> Date: Fri, 29 May 2026 17:59:38 +0900 Subject: [PATCH 02/11] fix(table): prevent crash when pressing Enter in a table cell (#2793) --- .../src/blocks/Table/TableExtension.test.ts | 126 ++++++++++++++++++ .../core/src/blocks/Table/TableExtension.ts | 17 +-- 2 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 packages/core/src/blocks/Table/TableExtension.test.ts diff --git a/packages/core/src/blocks/Table/TableExtension.test.ts b/packages/core/src/blocks/Table/TableExtension.test.ts new file mode 100644 index 0000000000..72596c9795 --- /dev/null +++ b/packages/core/src/blocks/Table/TableExtension.test.ts @@ -0,0 +1,126 @@ +import { TextSelection } from "prosemirror-state"; +import { CellSelection } from "prosemirror-tables"; +import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +import { BlockNoteEditor } from "../../editor/BlockNoteEditor.js"; +import type { PartialBlock } from "../defaultBlocks.js"; + +/** + * @vitest-environment jsdom + */ + +function pressEnter(editor: BlockNoteEditor) { + const view = editor.prosemirrorView; + const event = new KeyboardEvent("keydown", { key: "Enter" }); + view.someProp("handleKeyDown", (f) => f(view, event)); +} + +const testDocument: PartialBlock[] = [ + { + id: "table-0", + type: "table", + content: { + type: "tableContent", + rows: [ + { cells: ["Cell 1", "Cell 2", "Cell 3"] }, + { cells: ["Cell 4", "Cell 5", "Cell 6"] }, + { cells: ["Cell 7", "Cell 8", "Cell 9"] }, + ], + }, + }, +]; + +describe("Table Enter keyboard shortcut", () => { + let editor: BlockNoteEditor; + const div = document.createElement("div"); + + beforeAll(() => { + editor = BlockNoteEditor.create(); + editor.mount(div); + }); + + afterAll(() => { + editor._tiptapEditor.destroy(); + editor = undefined as any; + }); + + beforeEach(() => { + editor.replaceBlocks(editor.document, testDocument); + }); + + function posInCell(cellText: string): number { + const view = editor.prosemirrorView; + let pos = -1; + view.state.doc.descendants((node, nodePos) => { + if (pos === -1 && node.isText && node.text === cellText) { + pos = nodePos; + } + return true; + }); + if (pos === -1) { + throw new Error(`Cell with text "${cellText}" not found`); + } + return pos; + } + + function setCursorInCell(cellText: string, offset = 1) { + const pos = posInCell(cellText); + editor.transact((tr) => + tr.setSelection(TextSelection.create(tr.doc, pos + offset)), + ); + } + + it("moves the selection to the cell below", () => { + setCursorInCell("Cell 5"); + + pressEnter(editor); + + const parentText = + editor.prosemirrorView.state.selection.$head.parent.textContent; + expect(parentText).toBe("Cell 8"); + }); + + it("does not crash and is a no-op on the last row", () => { + setCursorInCell("Cell 8"); + + const before = editor.document; + expect(() => pressEnter(editor)).not.toThrow(); + expect(editor.document).toStrictEqual(before); + }); + + it("does not crash with a (non-empty) text selection in the last row", () => { + const start = posInCell("Cell 8"); + editor.transact((tr) => + tr.setSelection(TextSelection.create(tr.doc, start, start + 4)), + ); + + const before = editor.document; + expect(() => pressEnter(editor)).not.toThrow(); + expect(editor.document).toStrictEqual(before); + }); + + it("does not crash with a multi-cell selection", () => { + const view = editor.prosemirrorView; + const cellPositions: number[] = []; + view.state.doc.descendants((node, pos) => { + if (node.type.name === "tableCell" || node.type.name === "tableHeader") { + cellPositions.push(pos); + } + return true; + }); + + editor.transact((tr) => + tr.setSelection( + CellSelection.create( + tr.doc, + cellPositions[0], + cellPositions[1], + ) as any, + ), + ); + + const before = editor.document; + expect(() => pressEnter(editor)).not.toThrow(); + expect(editor.document).toStrictEqual(before); + }); +}); diff --git a/packages/core/src/blocks/Table/TableExtension.ts b/packages/core/src/blocks/Table/TableExtension.ts index 1d2cf9d47f..bd8d8bcfab 100644 --- a/packages/core/src/blocks/Table/TableExtension.ts +++ b/packages/core/src/blocks/Table/TableExtension.ts @@ -35,26 +35,15 @@ export const TableExtension = Extension.create({ return { // Moves the selection to the cell below. Enter: () => { - if ( - this.editor.state.selection.$head.parent.type.name !== - "tableParagraph" - ) { + if (!isInTable(this.editor.state)) { return false; } return this.editor.commands.command(({ state, dispatch }) => { - if (!isInTable(state)) { - return false; - } - const $cell = selectionCell(state); - const $nextCell = nextCell($cell, "vert", 1); - - if (!$nextCell) { - return false; - } + const $nextCell = $cell ? nextCell($cell, "vert", 1) : null; - if (dispatch) { + if ($nextCell && dispatch) { dispatch( state.tr .setSelection( From f8b59e93d58886df57598784297413148180270e Mon Sep 17 00:00:00 2001 From: Yousef Date: Mon, 1 Jun 2026 13:52:45 +0200 Subject: [PATCH 03/11] docs: remove private discord support (#2805) --- docs/content/pages/thanks.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/content/pages/thanks.mdx b/docs/content/pages/thanks.mdx index 94a7a2ba9b..9f9ca6c9f0 100644 --- a/docs/content/pages/thanks.mdx +++ b/docs/content/pages/thanks.mdx @@ -13,9 +13,8 @@ Your support means the world to us and helps us continue developing and maintain ## What's Next? -- **Access to Examples:** You now have full access to our comprehensive [examples](/examples) to help you get the most out of BlockNote. +- **Get started with BlockNote:** Head to our [documentation](/docs) to get started with BlockNote. - **Priority GitHub Support:** As a subscriber, your GitHub issues will be prioritized, ensuring a faster resolution. -- **Private Discord Channel:** Want to connect with us and other power users? Contact us via our [about page](/about) to get an invite to our private Discord channel. - **Showcase Your Support:** We'd love to show our gratitude for your sponsorship! If you'd like, you can send us your company logo by contacting us via our [about page](/about), and we'll feature it on our site. We truly appreciate your subscription and your commitment to open-source software. From faae3d5a0454e95adc39c399623199edbe7cad3e Mon Sep 17 00:00:00 2001 From: Nick Perez Date: Mon, 1 Jun 2026 15:48:18 +0200 Subject: [PATCH 04/11] fix: add explicit type annotations for callback params losing contextual typing (#2815) When @ariakit/react updates its internal module structure (e.g. from @ariakit/react-core to @ariakit/react-components), contextual typing from external library component props can break, causing TS7006 'Parameter implicitly has an any type' errors in the Fresh Install Tests CI workflow. Add explicit type annotations to 5 callback parameters that depend on external library types for inference: - packages/ariakit/src/panel/Panel.tsx: setActiveId callback - packages/ariakit/src/toolbar/ToolbarButton.tsx: onMouseDown callback - packages/ariakit/src/panel/PanelFileInput.tsx: onChange callback - packages/ariakit/src/badge/Badge.tsx: onClick callback - packages/xl-ai/src/components/AIMenu/AIMenuController.tsx: outsidePress callback All annotations use React/DOM built-in types (MouseEvent, ChangeEvent) rather than library-specific types, making them resilient to future dependency updates. --- packages/ariakit/src/badge/Badge.tsx | 4 ++-- packages/ariakit/src/panel/Panel.tsx | 2 +- packages/ariakit/src/panel/PanelFileInput.tsx | 4 ++-- packages/ariakit/src/toolbar/ToolbarButton.tsx | 4 ++-- packages/xl-ai/src/components/AIMenu/AIMenuController.tsx | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/ariakit/src/badge/Badge.tsx b/packages/ariakit/src/badge/Badge.tsx index 43b6cdd7d5..f81ca9ce5a 100644 --- a/packages/ariakit/src/badge/Badge.tsx +++ b/packages/ariakit/src/badge/Badge.tsx @@ -8,7 +8,7 @@ import { import { assertEmpty, mergeCSSClasses } from "@blocknote/core"; import { ComponentProps } from "@blocknote/react"; -import { forwardRef } from "react"; +import { type MouseEvent, forwardRef } from "react"; export const Badge = forwardRef< HTMLButtonElement, @@ -36,7 +36,7 @@ export const Badge = forwardRef< isSelected && "bn-ak-primary", )} aria-selected={isSelected === true} - onClick={(event) => onClick?.(event)} + onClick={(event: MouseEvent) => onClick?.(event)} onMouseEnter={onMouseEnter} ref={ref} > diff --git a/packages/ariakit/src/panel/Panel.tsx b/packages/ariakit/src/panel/Panel.tsx index 376f04a534..b988cbec01 100644 --- a/packages/ariakit/src/panel/Panel.tsx +++ b/packages/ariakit/src/panel/Panel.tsx @@ -32,7 +32,7 @@ export const Panel = forwardRef< { + setActiveId={(activeId: string | null | undefined) => { if (activeId) { setOpenTab(activeId); } diff --git a/packages/ariakit/src/panel/PanelFileInput.tsx b/packages/ariakit/src/panel/PanelFileInput.tsx index 4c6a876931..36917ff5a5 100644 --- a/packages/ariakit/src/panel/PanelFileInput.tsx +++ b/packages/ariakit/src/panel/PanelFileInput.tsx @@ -5,7 +5,7 @@ import { import { assertEmpty } from "@blocknote/core"; import { ComponentProps } from "@blocknote/react"; -import { forwardRef } from "react"; +import { forwardRef, type ChangeEvent } from "react"; export const PanelFileInput = forwardRef< HTMLInputElement, @@ -24,7 +24,7 @@ export const PanelFileInput = forwardRef< type={"file"} accept={accept} value={value ? value.name : undefined} - onChange={async (e) => onChange?.(e.target.files![0])} + onChange={async (e: ChangeEvent) => onChange?.(e.target.files![0])} placeholder={placeholder} /> diff --git a/packages/ariakit/src/toolbar/ToolbarButton.tsx b/packages/ariakit/src/toolbar/ToolbarButton.tsx index 0fddcb5905..cb2bf26cca 100644 --- a/packages/ariakit/src/toolbar/ToolbarButton.tsx +++ b/packages/ariakit/src/toolbar/ToolbarButton.tsx @@ -7,7 +7,7 @@ import { import { assertEmpty, isSafari, mergeCSSClasses } from "@blocknote/core"; import { ComponentProps } from "@blocknote/react"; -import { forwardRef } from "react"; +import { forwardRef, type MouseEvent } from "react"; type ToolbarButtonProps = ComponentProps["Generic"]["Toolbar"]["Button"]; @@ -46,7 +46,7 @@ export const ToolbarButton = forwardRef( )} // Needed as Safari doesn't focus button elements on mouse down // unlike other browsers. - onMouseDown={(e) => { + onMouseDown={(e: MouseEvent) => { if (isSafari()) { (e.currentTarget as HTMLButtonElement).focus(); } diff --git a/packages/xl-ai/src/components/AIMenu/AIMenuController.tsx b/packages/xl-ai/src/components/AIMenu/AIMenuController.tsx index 930c317fa6..be8f21f555 100644 --- a/packages/xl-ai/src/components/AIMenu/AIMenuController.tsx +++ b/packages/xl-ai/src/components/AIMenu/AIMenuController.tsx @@ -70,7 +70,7 @@ export const AIMenuController = (props: { // We should just be able to set `referencePress: true` instead of // using this listener, but this doesn't seem to trigger. // (probably because we don't assign the referenceProps to the reference element) - outsidePress: (event) => { + outsidePress: (event: MouseEvent) => { if (event.target instanceof Element) { const blockElement = event.target.closest(".bn-block"); if ( From 8b3118f652585da7b421d9cac4285d9f1ab28dda Mon Sep 17 00:00:00 2001 From: Nick Perez Date: Mon, 1 Jun 2026 16:23:19 +0200 Subject: [PATCH 05/11] fix(core): add editor cleanup in BlockNoteEditor.test.ts to prevent unhandled DOMObserver errors (#2816) Tests that mount editors were not calling unmount() afterward, leaving ProseMirror's DOMObserver timers active. When prosemirror-view is updated to newer versions (e.g. 1.41.8 via fresh dep resolution), a dangling setTimeout in DOMObserver.flush() fires after jsdom teardown, causing 'document is not defined' ReferenceError. Add afterEach cleanup following the same pattern as transformPasted.test.ts. --- .../core/src/editor/BlockNoteEditor.test.ts | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/core/src/editor/BlockNoteEditor.test.ts b/packages/core/src/editor/BlockNoteEditor.test.ts index 6a4f5f023e..a6ca022e03 100644 --- a/packages/core/src/editor/BlockNoteEditor.test.ts +++ b/packages/core/src/editor/BlockNoteEditor.test.ts @@ -1,4 +1,4 @@ -import { expect, it } from "vitest"; +import { afterEach, expect, it } from "vitest"; import * as Y from "yjs"; import { @@ -11,8 +11,19 @@ import { BlocksChanged } from "../api/getBlocksChangedByTransaction.js"; /** * @vitest-environment jsdom */ + +const editorsToCleanup: BlockNoteEditor[] = []; + +afterEach(() => { + for (const editor of editorsToCleanup) { + editor.unmount(); + } + editorsToCleanup.length = 0; +}); + it("creates an editor", () => { const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); const posInfo = editor.transact((tr) => getNearestBlockPos(tr.doc, 2)); const info = getBlockInfo(posInfo); expect(info.blockNoteType).toEqual("paragraph"); @@ -20,6 +31,7 @@ it("creates an editor", () => { it("immediately replaces doc", async () => { const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); const blocks = await editor.tryParseMarkdownToBlocks( "This is a normal text\n\n# And this is a large heading", ); @@ -70,6 +82,7 @@ it("adds id attribute when requested", async () => { const editor = BlockNoteEditor.create({ setIdAttribute: true, }); + editorsToCleanup.push(editor); const blocks = await editor.tryParseMarkdownToBlocks( "This is a normal text\n\n# And this is a large heading", ); @@ -81,6 +94,7 @@ it("adds id attribute when requested", async () => { it("updates block", () => { const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); editor.updateBlock(editor.document[0], { content: "hello", }); @@ -89,6 +103,7 @@ it("updates block", () => { it("block prop types", () => { // this test checks whether the block props are correctly typed in typescript const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); const block = editor.document[0]; if (block.type === "paragraph") { // @ts-expect-error @@ -108,6 +123,7 @@ it("block prop types", () => { it("onMount and onUnmount", async () => { const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); let mounted = false; let unmounted = false; editor.onMount(() => { @@ -143,6 +159,7 @@ it("sets an initial block id when using Y.js", async () => { }, }, }); + editorsToCleanup.push(editor); editor.mount(document.createElement("div")); @@ -193,6 +210,7 @@ it("sets an initial block id when using Y.js", async () => { it("onBeforeChange", () => { const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); let beforeChangeCalled = false; let changes: BlocksChanged = []; editor.onBeforeChange(({ getChanges }) => { From e6493ee0eae939fdcce8b77969f3e35a9bbe4f4c Mon Sep 17 00:00:00 2001 From: Matthew Lipski <50169049+matthewlipski@users.noreply.github.com> Date: Tue, 2 Jun 2026 02:39:06 +0200 Subject: [PATCH 06/11] fix: Comments emoji picker button issues (BLO-1199) (#2769) * Memoized `actions` prop in consumers of `CommentEditor` * Added e2e test, minor changes to existing tests * refactor: extract actions into memo components with render prop pattern - Change CommentEditor actions prop from FC to render prop (function returning ReactNode) - Extract inline action components into separate memo-wrapped components - Remove unnecessary useCallback/useMemo wrappers around render props - React.memo on child components handles re-render optimization --------- Co-authored-by: Nick the Sick --- .../react/src/components/Comments/Comment.tsx | 182 +++++++++++------- .../src/components/Comments/CommentEditor.tsx | 9 +- .../components/Comments/FloatingComposer.tsx | 85 ++++---- .../react/src/components/Comments/Thread.tsx | 71 ++++--- .../src/end-to-end/comments/comments.test.ts | 46 ++++- 5 files changed, 259 insertions(+), 134 deletions(-) diff --git a/packages/react/src/components/Comments/Comment.tsx b/packages/react/src/components/Comments/Comment.tsx index e1dd66871a..9ebe8dc212 100644 --- a/packages/react/src/components/Comments/Comment.tsx +++ b/packages/react/src/components/Comments/Comment.tsx @@ -1,9 +1,10 @@ "use client"; -import { mergeCSSClasses } from "@blocknote/core"; +import { Dictionary, mergeCSSClasses } from "@blocknote/core"; import { CommentsExtension } from "@blocknote/core/comments"; import type { CommentData, ThreadData } from "@blocknote/core/comments"; -import { MouseEvent, ReactNode, useCallback, useState } from "react"; +import { ThreadStore } from "@blocknote/core/comments"; +import { MouseEvent, ReactNode, memo, useCallback, useState } from "react"; import { RiArrowGoBackFill, RiCheckFill, @@ -13,7 +14,7 @@ import { RiMoreFill, } from "react-icons/ri"; -import { useComponentsContext } from "../../editor/ComponentsContext.js"; +import { Components, useComponentsContext } from "../../editor/ComponentsContext.js"; import { useCreateBlockNote } from "../../hooks/useCreateBlockNote.js"; import { useExtension } from "../../hooks/useExtension.js"; import { useDictionary } from "../../i18n/dictionary.js"; @@ -23,6 +24,103 @@ import { ReactionBadge } from "./ReactionBadge.js"; import { defaultCommentEditorSchema } from "./defaultCommentEditorSchema.js"; import { useUser } from "./useUsers.js"; +type CommentEditorActionsProps = { + isFocused: boolean; + isEmpty: boolean; + comment: CommentData; + isEditing: boolean; + threadStore: ThreadStore; + onReactionSelect: (emoji: string) => Promise; + onEditSubmit: (event: MouseEvent) => Promise; + onEditCancel: () => void; + onEmojiPickerOpenChange: (open: boolean) => void; + Components: Components; + dict: Dictionary; +}; + +const CommentEditorActionsComponent = memo( + ({ + isEmpty: _isEmpty, + comment, + isEditing, + threadStore, + onReactionSelect, + onEditSubmit, + onEditCancel, + onEmojiPickerOpenChange, + Components, + dict, + }: CommentEditorActionsProps) => { + const canAddReaction = threadStore.auth.canAddReaction(comment); + + return ( + <> + {comment.reactions.length > 0 && !isEditing && ( + + {comment.reactions.map((reaction) => ( + + ))} + {canAddReaction && ( + + onReactionSelect(emoji.native) + } + onOpenChange={onEmojiPickerOpenChange} + > + } + mainTooltip={dict.comments.actions.add_reaction} + /> + + )} + + )} + {isEditing && ( + + + {dict.comments.save_button_text} + + + {dict.comments.cancel_button_text} + + + )} + + ); + }, +); + export type CommentProps = { comment: CommentData; thread: ThreadData; @@ -249,70 +347,20 @@ export const Comment = ({ editable={isEditing} actions={ comment.reactions.length > 0 || isEditing - ? ({ isEmpty }) => ( - <> - {comment.reactions.length > 0 && !isEditing && ( - - {comment.reactions.map((reaction) => ( - - ))} - {canAddReaction && ( - - onReactionSelect(emoji.native) - } - onOpenChange={setEmojiPickerOpen} - > - } - mainTooltip={dict.comments.actions.add_reaction} - /> - - )} - - )} - {isEditing && ( - - - {dict.comments.save_button_text} - - - {dict.comments.cancel_button_text} - - - )} - + ? ({ isFocused, isEmpty }) => ( + ) : undefined } diff --git a/packages/react/src/components/Comments/CommentEditor.tsx b/packages/react/src/components/Comments/CommentEditor.tsx index 6030cb528e..f8eaa05d46 100644 --- a/packages/react/src/components/Comments/CommentEditor.tsx +++ b/packages/react/src/components/Comments/CommentEditor.tsx @@ -1,5 +1,5 @@ import { BlockNoteEditor } from "@blocknote/core"; -import { FC, useCallback, useEffect, useState } from "react"; +import { ReactNode, useCallback, useEffect, useState } from "react"; import { useComponentsContext } from "../../editor/ComponentsContext.js"; import { useEditorState } from "../../hooks/useEditorState.js"; @@ -16,10 +16,7 @@ import { useEditorState } from "../../hooks/useEditorState.js"; export const CommentEditor = (props: { autoFocus?: boolean; editable: boolean; - actions?: FC<{ - isFocused: boolean; - isEmpty: boolean; - }>; + actions?: (args: { isFocused: boolean; isEmpty: boolean }) => ReactNode; editor: BlockNoteEditor; }) => { const [isFocused, setIsFocused] = useState(false); @@ -58,7 +55,7 @@ export const CommentEditor = (props: { /> {props.actions && (
- + {props.actions({ isFocused, isEmpty })}
)} diff --git a/packages/react/src/components/Comments/FloatingComposer.tsx b/packages/react/src/components/Comments/FloatingComposer.tsx index 023a8eccf6..1344f90cb9 100644 --- a/packages/react/src/components/Comments/FloatingComposer.tsx +++ b/packages/react/src/components/Comments/FloatingComposer.tsx @@ -3,13 +3,15 @@ import { DefaultBlockSchema, DefaultInlineContentSchema, DefaultStyleSchema, + Dictionary, InlineContentSchema, mergeCSSClasses, StyleSchema, } from "@blocknote/core"; import { CommentsExtension } from "@blocknote/core/comments"; +import { memo, useCallback } from "react"; -import { useComponentsContext } from "../../editor/ComponentsContext.js"; +import { Components, useComponentsContext } from "../../editor/ComponentsContext.js"; import { useCreateBlockNote } from "../../hooks/useCreateBlockNote.js"; import { useExtension } from "../../hooks/useExtension.js"; import { useDictionary } from "../../i18n/dictionary.js"; @@ -18,6 +20,33 @@ import { defaultCommentEditorSchema } from "./defaultCommentEditorSchema.js"; import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js"; import { TextSelection } from "@tiptap/pm/state"; +type FloatingComposerActionsProps = { + isFocused: boolean; + isEmpty: boolean; + onSave: () => Promise; + Components: Components; + dict: Dictionary; +}; + +const FloatingComposerActionsComponent = memo( + ({ isEmpty, onSave, Components, dict }: FloatingComposerActionsProps) => ( + + + {dict.comments.save_button_text} + + + ), +); + /** * The FloatingComposer component displays a comment editor "floating" card. * @@ -46,44 +75,34 @@ export function FloatingComposer< schema: comments.commentEditorSchema || defaultCommentEditorSchema, }); + const onSave = useCallback(async () => { + // (later) For REST API, we should implement a loading state and error state + await comments.createThread({ + initialComment: { + body: newCommentEditor.document, + }, + }); + comments.stopPendingComment(); + editor.transact((tr) => { + tr.setSelection(TextSelection.create(tr.doc, tr.selection.to)); + }); + editor.focus(); + }, [comments, newCommentEditor, editor]); + return ( ( - - { - // (later) For REST API, we should implement a loading state and error state - await comments.createThread({ - initialComment: { - body: newCommentEditor.document, - }, - }); - comments.stopPendingComment(); - editor.transact((tr) => { - tr.setSelection( - TextSelection.create(tr.doc, tr.selection.to), - ); - }); - editor.focus(); - }} - > - {dict.comments.save_button_text} - - + actions={({ isFocused, isEmpty }) => ( + )} /> diff --git a/packages/react/src/components/Comments/Thread.tsx b/packages/react/src/components/Comments/Thread.tsx index c666cd33e2..284e923b6b 100644 --- a/packages/react/src/components/Comments/Thread.tsx +++ b/packages/react/src/components/Comments/Thread.tsx @@ -1,9 +1,9 @@ -import { mergeCSSClasses } from "@blocknote/core"; +import { Dictionary, mergeCSSClasses } from "@blocknote/core"; import { CommentsExtension } from "@blocknote/core/comments"; import { ThreadData } from "@blocknote/core/comments"; -import { FocusEvent, useCallback } from "react"; +import { FocusEvent, memo, useCallback } from "react"; -import { useComponentsContext } from "../../editor/ComponentsContext.js"; +import { Components, useComponentsContext } from "../../editor/ComponentsContext.js"; import { useCreateBlockNote } from "../../hooks/useCreateBlockNote.js"; import { useExtension } from "../../hooks/useExtension.js"; import { useDictionary } from "../../i18n/dictionary.js"; @@ -11,6 +11,38 @@ import { CommentEditor } from "./CommentEditor.js"; import { Comments } from "./Comments.js"; import { defaultCommentEditorSchema } from "./defaultCommentEditorSchema.js"; +type ReplyActionsProps = { + isFocused: boolean; + isEmpty: boolean; + onNewCommentSave: () => Promise; + Components: Components; + dict: Dictionary; +}; + +const ReplyActionsComponent = memo( + ({ isEmpty, onNewCommentSave, Components, dict }: ReplyActionsProps) => { + if (isEmpty) { + return null; + } + + return ( + + + {dict.comments.save_button_text} + + + ); + }, +); + export type ThreadProps = { /** * The thread to display - you can use the `useThreads` hook to retrieve a @@ -122,30 +154,15 @@ export const Thread = ({ autoFocus={false} editable={true} editor={newCommentEditor} - actions={({ isEmpty }) => { - if (isEmpty) { - return null; - } - - return ( - - - {dict.comments.save_button_text} - - - ); - }} + actions={({ isFocused, isEmpty }) => ( + + )} /> )} diff --git a/tests/src/end-to-end/comments/comments.test.ts b/tests/src/end-to-end/comments/comments.test.ts index 198a8e1ced..9ae1c8284f 100644 --- a/tests/src/end-to-end/comments/comments.test.ts +++ b/tests/src/end-to-end/comments/comments.test.ts @@ -3,11 +3,54 @@ import { test } from "../../setup/setupScript.js"; import { COMMENTS_URL, LINK_BUTTON_SELECTOR } from "../../utils/const.js"; import { focusOnEditor } from "../../utils/editor.js"; +const EMOJI_BUTTON_SELECTOR = "em-emoji-picker button[aria-posinset]"; + test.beforeEach(async ({ page }) => { await page.goto(COMMENTS_URL); }); test.describe("Check Comments functionality", () => { + test("Should be able to add reactions", async ({ page }) => { + await focusOnEditor(page); + + await page.keyboard.type("hello"); + await page.locator("text=hello").dblclick(); + + await page.click('[data-test="addcomment"]'); + await page.waitForSelector(".bn-thread"); + + await page.keyboard.type("test comment"); + await page.click('button[data-test="save"]'); + + // Wait for comment composer to close. + await expect(page.locator(".bn-thread")).toHaveCount(0); + + await page.locator("span.bn-thread-mark").first().click(); + await expect(page.locator(".bn-thread-comment")).toBeVisible(); + + // Hover comment to reveal action toolbar. + await page.locator(".bn-thread-comment").first().hover(); + await expect(page.locator('[data-test="addreaction"]')).toBeVisible(); + + // Add a reaction via the action toolbar's add-reaction button. + await page.click('[data-test="addreaction"]'); + await expect(page.locator(EMOJI_BUTTON_SELECTOR).first()).toBeVisible(); + await page.locator(EMOJI_BUTTON_SELECTOR).first().click(); + await expect(page.locator("em-emoji-picker")).toHaveCount(0); + await expect(page.locator(".bn-comment-reaction")).toHaveCount(1); + + // Add a second reaction via the add-reaction badge. + await page.locator(".bn-thread-comment").first().hover(); + await page.click(".bn-comment-add-reaction"); + await expect(page.locator(EMOJI_BUTTON_SELECTOR).first()).toBeVisible(); + + // Pick a different emoji so it's added as a new reaction rather than + // toggling the first one off. + await page.locator(EMOJI_BUTTON_SELECTOR).nth(5).click(); + await expect(page.locator("em-emoji-picker")).toHaveCount(0); + await expect(page.locator(".bn-comment-reaction")).toHaveCount(2); + }); + test("Should preserve existing comments when adding a link", async ({ page, }) => { @@ -30,7 +73,7 @@ test.describe("Check Comments functionality", () => { await page.keyboard.type("https://example.com"); await page.keyboard.press("Enter"); - await expect(await page.locator("span.bn-thread-mark")).toBeVisible(); + await expect(page.locator("span.bn-thread-mark")).toBeVisible(); }); test("Should select thread on first click and open link on second click", async ({ @@ -64,6 +107,7 @@ test.describe("Check Comments functionality", () => { await page.keyboard.press("ArrowDown"); await page.waitForTimeout(500); await expect(page.locator(".bn-thread-mark-selected")).toHaveCount(0); + await expect(page.locator(".bn-formatting-toolbar")).toBeHidden(); const link = page.locator('a[data-inline-content-type="link"]').first(); From 320949198e6db8d7cdaf970c2af7071ab61ed6d9 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 2 Jun 2026 12:48:54 +0200 Subject: [PATCH 07/11] chore(release): publish 0.51.4 --- CHANGELOG.md | 16 ++++++++ packages/ariakit/package.json | 6 +-- packages/code-block/package.json | 6 +-- packages/core/package.json | 2 +- packages/dev-scripts/package.json | 2 +- packages/mantine/package.json | 6 +-- packages/react/package.json | 4 +- packages/server-util/package.json | 6 +-- packages/shadcn/package.json | 6 +-- packages/xl-ai-server/package.json | 4 +- packages/xl-ai/package.json | 10 ++--- packages/xl-docx-exporter/package.json | 6 +-- packages/xl-email-exporter/package.json | 6 +-- packages/xl-multi-column/package.json | 6 +-- packages/xl-odt-exporter/package.json | 6 +-- packages/xl-pdf-exporter/package.json | 8 ++-- pnpm-lock.yaml | 52 ++++++++++++------------- 17 files changed, 84 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c7a35189c..87fed6062a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## 0.51.4 (2026-06-02) + +### 🩹 Fixes + +- add explicit type annotations for callback params losing contextual typing ([#2815](https://github.com/TypeCellOS/BlockNote/pull/2815)) +- Comments emoji picker button issues (BLO-1199) ([#2769](https://github.com/TypeCellOS/BlockNote/pull/2769)) +- **core:** add editor cleanup in BlockNoteEditor.test.ts to prevent unhandled DOMObserver errors ([#2816](https://github.com/TypeCellOS/BlockNote/pull/2816)) +- **table:** prevent crash when pressing Enter in a table cell ([#2793](https://github.com/TypeCellOS/BlockNote/pull/2793)) + +### ❤️ Thank You + +- Matthew Lipski @matthewlipski +- Nick Perez +- Nick the Sick @nperez0111 +- Yuki Terashima @y-temp4 + ## 0.51.3 (2026-05-26) ### 🩹 Fixes diff --git a/packages/ariakit/package.json b/packages/ariakit/package.json index 1fa844ab18..e30d24a70b 100644 --- a/packages/ariakit/package.json +++ b/packages/ariakit/package.json @@ -11,7 +11,7 @@ "directory": "packages/ariakit" }, "license": "MPL-2.0", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -57,8 +57,8 @@ }, "dependencies": { "@ariakit/react": "^0.4.19", - "@blocknote/core": "0.51.3", - "@blocknote/react": "0.51.3" + "@blocknote/core": "0.51.4", + "@blocknote/react": "0.51.4" }, "devDependencies": { "@types/react": "^19.2.3", diff --git a/packages/code-block/package.json b/packages/code-block/package.json index 9b4301ffa4..f8e96b417e 100644 --- a/packages/code-block/package.json +++ b/packages/code-block/package.json @@ -9,7 +9,7 @@ "directory": "packages/code-block" }, "license": "MPL-2.0", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -49,7 +49,7 @@ "test-watch": "vitest watch" }, "dependencies": { - "@blocknote/core": "0.51.3", + "@blocknote/core": "0.51.4", "@shikijs/core": "^4", "@shikijs/engine-javascript": "^4", "@shikijs/langs-precompiled": "^4", @@ -65,7 +65,7 @@ "vitest": "^4.1.2" }, "peerDependencies": { - "@blocknote/core": "0.51.3" + "@blocknote/core": "0.51.4" }, "eslintConfig": { "extends": [ diff --git a/packages/core/package.json b/packages/core/package.json index 9713075085..4702aad444 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -11,7 +11,7 @@ "directory": "packages/core" }, "license": "MPL-2.0", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", diff --git a/packages/dev-scripts/package.json b/packages/dev-scripts/package.json index 833b9cc966..902ead65f8 100644 --- a/packages/dev-scripts/package.json +++ b/packages/dev-scripts/package.json @@ -8,7 +8,7 @@ "directory": "packages/dev-scripts" }, "license": "MPL-2.0", - "version": "0.51.3", + "version": "0.51.4", "description": "", "type": "module", "scripts": { diff --git a/packages/mantine/package.json b/packages/mantine/package.json index db7dbdce23..7fc0ef9c0f 100644 --- a/packages/mantine/package.json +++ b/packages/mantine/package.json @@ -11,7 +11,7 @@ "directory": "packages/mantine" }, "license": "MPL-2.0", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -61,8 +61,8 @@ "clean": "rimraf dist && rimraf types" }, "dependencies": { - "@blocknote/core": "0.51.3", - "@blocknote/react": "0.51.3", + "@blocknote/core": "0.51.4", + "@blocknote/react": "0.51.4", "react-icons": "^5.5.0" }, "devDependencies": { diff --git a/packages/react/package.json b/packages/react/package.json index 2903e18c55..1e62c1e2ad 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -11,7 +11,7 @@ "directory": "packages/react" }, "license": "MPL-2.0", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -58,7 +58,7 @@ "clean": "rimraf dist && rimraf types" }, "dependencies": { - "@blocknote/core": "0.51.3", + "@blocknote/core": "0.51.4", "@emoji-mart/data": "^1.2.1", "@floating-ui/react": "^0.27.18", "@floating-ui/utils": "^0.2.10", diff --git a/packages/server-util/package.json b/packages/server-util/package.json index 11c03e1e8b..a6b62c702d 100644 --- a/packages/server-util/package.json +++ b/packages/server-util/package.json @@ -11,7 +11,7 @@ "directory": "packages/server-util" }, "license": "MPL-2.0", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -56,8 +56,8 @@ "test-watch": "vitest watch" }, "dependencies": { - "@blocknote/core": "0.51.3", - "@blocknote/react": "0.51.3", + "@blocknote/core": "0.51.4", + "@blocknote/react": "0.51.4", "@tiptap/core": "^3.13.0", "@tiptap/pm": "^3.13.0", "jsdom": "^25.0.1", diff --git a/packages/shadcn/package.json b/packages/shadcn/package.json index 557c261ec4..e20854d9a9 100644 --- a/packages/shadcn/package.json +++ b/packages/shadcn/package.json @@ -11,7 +11,7 @@ "directory": "packages/shadcn" }, "license": "MPL-2.0", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -56,8 +56,8 @@ "clean": "rimraf dist && rimraf types" }, "dependencies": { - "@blocknote/core": "0.51.3", - "@blocknote/react": "0.51.3", + "@blocknote/core": "0.51.4", + "@blocknote/react": "0.51.4", "@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-label": "^2.1.7", diff --git a/packages/xl-ai-server/package.json b/packages/xl-ai-server/package.json index 69f9925266..7dafdb47ed 100644 --- a/packages/xl-ai-server/package.json +++ b/packages/xl-ai-server/package.json @@ -3,7 +3,7 @@ "homepage": "https://github.com/TypeCellOS/BlockNote", "private": true, "license": "GPL-3.0 OR PROPRIETARY", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -49,7 +49,7 @@ "@ai-sdk/mistral": "^3.0.2", "@ai-sdk/openai": "^3.0.2", "@ai-sdk/openai-compatible": "^2.0.2", - "@blocknote/xl-ai": "0.51.3", + "@blocknote/xl-ai": "0.51.4", "@hono/node-server": "^1.19.5", "ai": "^6.0.5", "hono": "^4.10.3" diff --git a/packages/xl-ai/package.json b/packages/xl-ai/package.json index 12bd5dea77..0788136c29 100644 --- a/packages/xl-ai/package.json +++ b/packages/xl-ai/package.json @@ -11,7 +11,7 @@ "directory": "packages/xl-ai" }, "license": "GPL-3.0 OR PROPRIETARY", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -72,9 +72,9 @@ "dependencies": { "@ai-sdk/provider-utils": "^4.0.2", "@ai-sdk/react": "^3.0.5", - "@blocknote/core": "0.51.3", - "@blocknote/mantine": "0.51.3", - "@blocknote/react": "0.51.3", + "@blocknote/core": "0.51.4", + "@blocknote/mantine": "0.51.4", + "@blocknote/react": "0.51.4", "@floating-ui/react": "^0.27.18", "@handlewithcare/prosemirror-suggest-changes": "^0.1.8", "@tiptap/core": "^3.13.0", @@ -99,7 +99,7 @@ "@ai-sdk/mistral": "^3.0.2", "@ai-sdk/openai": "^3.0.2", "@ai-sdk/openai-compatible": "^2.0.2", - "@blocknote/xl-multi-column": "0.51.3", + "@blocknote/xl-multi-column": "0.51.4", "@mswjs/interceptors": "^0.37.6", "@types/diff": "^6.0.0", "@types/json-diff": "^1.0.3", diff --git a/packages/xl-docx-exporter/package.json b/packages/xl-docx-exporter/package.json index 72d8dd8662..7295fdd71f 100644 --- a/packages/xl-docx-exporter/package.json +++ b/packages/xl-docx-exporter/package.json @@ -9,7 +9,7 @@ "directory": "packages/xl-docx-exporter" }, "license": "GPL-3.0 OR PROPRIETARY", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -57,8 +57,8 @@ "email": "email dev" }, "dependencies": { - "@blocknote/core": "0.51.3", - "@blocknote/xl-multi-column": "0.51.3", + "@blocknote/core": "0.51.4", + "@blocknote/xl-multi-column": "0.51.4", "buffer": "^6.0.3", "docx": "^9.6.1", "image-meta": "^0.2.2" diff --git a/packages/xl-email-exporter/package.json b/packages/xl-email-exporter/package.json index eca57501c1..8cadc3bad6 100644 --- a/packages/xl-email-exporter/package.json +++ b/packages/xl-email-exporter/package.json @@ -9,7 +9,7 @@ "directory": "packages/xl-email-exporter" }, "license": "GPL-3.0 OR PROPRIETARY", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -54,8 +54,8 @@ "email": "email dev" }, "dependencies": { - "@blocknote/core": "0.51.3", - "@blocknote/react": "0.51.3", + "@blocknote/core": "0.51.4", + "@blocknote/react": "0.51.4", "@react-email/components": "^1.0.5", "@react-email/render": "^2.0.4", "buffer": "^6.0.3", diff --git a/packages/xl-multi-column/package.json b/packages/xl-multi-column/package.json index ae8784430f..0fa0f1c159 100644 --- a/packages/xl-multi-column/package.json +++ b/packages/xl-multi-column/package.json @@ -9,7 +9,7 @@ "directory": "packages/xl-multi-column" }, "license": "GPL-3.0 OR PROPRIETARY", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -51,8 +51,8 @@ "clean": "rimraf dist && rimraf types" }, "dependencies": { - "@blocknote/core": "0.51.3", - "@blocknote/react": "0.51.3", + "@blocknote/core": "0.51.4", + "@blocknote/react": "0.51.4", "@tiptap/core": "^3.13.0", "prosemirror-model": "^1.25.4", "prosemirror-state": "^1.4.4", diff --git a/packages/xl-odt-exporter/package.json b/packages/xl-odt-exporter/package.json index 6e47dd09ef..40267839d8 100644 --- a/packages/xl-odt-exporter/package.json +++ b/packages/xl-odt-exporter/package.json @@ -9,7 +9,7 @@ "directory": "packages/xl-odt-exporter" }, "license": "GPL-3.0 OR PROPRIETARY", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -57,8 +57,8 @@ "clean": "rimraf dist && rimraf types" }, "dependencies": { - "@blocknote/core": "0.51.3", - "@blocknote/xl-multi-column": "0.51.3", + "@blocknote/core": "0.51.4", + "@blocknote/xl-multi-column": "0.51.4", "@zip.js/zip.js": "^2.8.8", "buffer": "^6.0.3", "image-meta": "^0.2.2" diff --git a/packages/xl-pdf-exporter/package.json b/packages/xl-pdf-exporter/package.json index f46320cdc9..707fb9e453 100644 --- a/packages/xl-pdf-exporter/package.json +++ b/packages/xl-pdf-exporter/package.json @@ -9,7 +9,7 @@ "directory": "packages/xl-pdf-exporter" }, "license": "GPL-3.0 OR PROPRIETARY", - "version": "0.51.3", + "version": "0.51.4", "files": [ "dist", "types", @@ -56,9 +56,9 @@ "email": "email dev" }, "dependencies": { - "@blocknote/core": "0.51.3", - "@blocknote/react": "0.51.3", - "@blocknote/xl-multi-column": "0.51.3", + "@blocknote/core": "0.51.4", + "@blocknote/react": "0.51.4", + "@blocknote/xl-multi-column": "0.51.4", "@react-pdf/renderer": "^4.3.0", "buffer": "^6.0.3", "docx": "^9.5.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dfc4d65cde..4046c1d4ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4530,10 +4530,10 @@ importers: specifier: ^0.4.19 version: 0.4.24(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@blocknote/react': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../react devDependencies: '@types/react': @@ -4576,7 +4576,7 @@ importers: packages/code-block: dependencies: '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@shikijs/core': specifier: ^4 @@ -4759,10 +4759,10 @@ importers: packages/mantine: dependencies: '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@blocknote/react': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../react '@mantine/core': specifier: ^8.3.11 || ^9.0.2 @@ -4814,7 +4814,7 @@ importers: packages/react: dependencies: '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@emoji-mart/data': specifier: ^1.2.1 @@ -4908,10 +4908,10 @@ importers: packages/server-util: dependencies: '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@blocknote/react': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../react '@tiptap/core': specifier: ^3.0.0 @@ -4969,10 +4969,10 @@ importers: packages/shadcn: dependencies: '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@blocknote/react': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../react '@radix-ui/react-avatar': specifier: ^1.1.10 @@ -5075,13 +5075,13 @@ importers: specifier: ^3.0.5 version: 3.0.5(react@19.2.5)(zod@4.3.6) '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@blocknote/mantine': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../mantine '@blocknote/react': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../react '@floating-ui/react': specifier: ^0.27.18 @@ -5151,7 +5151,7 @@ importers: specifier: ^2.0.2 version: 2.0.2(zod@4.3.6) '@blocknote/xl-multi-column': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../xl-multi-column '@mswjs/interceptors': specifier: ^0.37.6 @@ -5244,7 +5244,7 @@ importers: specifier: ^2.0.2 version: 2.0.2(zod@4.3.6) '@blocknote/xl-ai': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../xl-ai '@hono/node-server': specifier: ^1.19.5 @@ -5290,10 +5290,10 @@ importers: packages/xl-docx-exporter: dependencies: '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@blocknote/xl-multi-column': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../xl-multi-column buffer: specifier: ^6.0.3 @@ -5345,10 +5345,10 @@ importers: packages/xl-email-exporter: dependencies: '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@blocknote/react': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../react '@react-email/components': specifier: ^1.0.5 @@ -5403,10 +5403,10 @@ importers: packages/xl-multi-column: dependencies: '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@blocknote/react': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../react '@tiptap/core': specifier: ^3.0.0 @@ -5470,10 +5470,10 @@ importers: packages/xl-odt-exporter: dependencies: '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@blocknote/xl-multi-column': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../xl-multi-column '@zip.js/zip.js': specifier: ^2.8.8 @@ -5525,13 +5525,13 @@ importers: packages/xl-pdf-exporter: dependencies: '@blocknote/core': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../core '@blocknote/react': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../react '@blocknote/xl-multi-column': - specifier: 0.51.3 + specifier: 0.51.4 version: link:../xl-multi-column '@react-pdf/renderer': specifier: ^4.3.0 From e0c67afe393deb53d2290f37051bb14d2bd00847 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 2 Jun 2026 12:49:17 +0200 Subject: [PATCH 08/11] chore: use pnpm@11.5.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d40852a827..95baf78b32 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "vitest": "^4.1.2", "wait-on": "9.0.5" }, - "packageManager": "pnpm@11.3.0+sha512.2c403d6594527287672b1f7056343a1f7c3634036a67ffabfcc2b3d7595d843768f8787148d1b57cf7956c90606bbd192857c363af19e96d2d0ec9ec5741d215", + "packageManager": "pnpm@11.5.1+sha512.93f7b57422ea7068257235b4c16eb60762eb68e1dc23723199cc739043ea9be2c4143274a399d8c6defa2b1176226d9ca1c4b63482d6200c1a8fbaa78c1d1485", "private": true, "scripts": { "dev": "nx run @blocknote/example-editor:dev", From 4f499f8874d354f79fe8f49692b73830b820cd5e Mon Sep 17 00:00:00 2001 From: Nick Perez Date: Tue, 2 Jun 2026 13:12:50 +0200 Subject: [PATCH 09/11] build: remove unused dependencies and bundle react-icons (#2796) --- packages/code-block/package.json | 5 +- packages/core/package.json | 3 - .../threadstore/yjs/YjsThreadStore.test.ts | 15 +- .../threadstore/yjs/YjsThreadStore.ts | 7 +- .../src/extensions/Placeholder/Placeholder.ts | 4 +- .../tiptap-extensions/UniqueID/UniqueID.ts | 4 +- packages/mantine/package.json | 4 +- packages/mantine/vite.config.ts | 10 ++ packages/react/package.json | 9 +- .../DefaultButtons/BasicTextStyleButton.tsx | 2 +- .../DefaultButtons/TextAlignButton.tsx | 2 +- .../DefaultSelects/BlockTypeSelect.tsx | 2 +- .../getDefaultReactSlashMenuItems.tsx | 2 +- packages/react/src/icons.ts | 12 ++ packages/react/src/index.ts | 2 + packages/react/vite.config.ts | 10 ++ packages/server-util/package.json | 5 +- packages/shadcn/package.json | 1 - packages/xl-ai/package.json | 6 +- packages/xl-ai/vite.config.ts | 10 ++ packages/xl-email-exporter/package.json | 8 +- packages/xl-multi-column/package.json | 6 +- packages/xl-multi-column/vite.config.ts | 10 ++ packages/xl-odt-exporter/package.json | 1 - packages/xl-pdf-exporter/package.json | 5 +- pnpm-lock.yaml | 149 +++++------------- 26 files changed, 131 insertions(+), 163 deletions(-) create mode 100644 packages/react/src/icons.ts diff --git a/packages/code-block/package.json b/packages/code-block/package.json index f8e96b417e..8180581834 100644 --- a/packages/code-block/package.json +++ b/packages/code-block/package.json @@ -49,11 +49,12 @@ "test-watch": "vitest watch" }, "dependencies": { - "@blocknote/core": "0.51.4", "@shikijs/core": "^4", "@shikijs/engine-javascript": "^4", "@shikijs/langs-precompiled": "^4", - "@shikijs/themes": "^4", + "@shikijs/themes": "^4" + }, + "optionalDependencies": { "@shikijs/types": "^4" }, "devDependencies": { diff --git a/packages/core/package.json b/packages/core/package.json index 4702aad444..e92d50f1f3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -97,9 +97,7 @@ "@tiptap/core": "^3.13.0", "@tiptap/extension-bold": "^3.13.0", "@tiptap/extension-code": "^3.13.0", - "@tiptap/extension-horizontal-rule": "^3.13.0", "@tiptap/extension-italic": "^3.13.0", - "@tiptap/extension-paragraph": "^3.13.0", "@tiptap/extension-strike": "^3.13.0", "@tiptap/extension-text": "^3.13.0", "@tiptap/extension-underline": "^3.13.0", @@ -107,7 +105,6 @@ "@tiptap/pm": "^3.13.0", "emoji-mart": "^5.6.0", "fast-deep-equal": "^3.1.3", - "lib0": "^0.2.99", "prosemirror-highlight": "^0.15.1", "prosemirror-model": "^1.25.4", "prosemirror-state": "^1.4.4", diff --git a/packages/core/src/comments/threadstore/yjs/YjsThreadStore.test.ts b/packages/core/src/comments/threadstore/yjs/YjsThreadStore.test.ts index b73b7c1ec8..c7be2f203c 100644 --- a/packages/core/src/comments/threadstore/yjs/YjsThreadStore.test.ts +++ b/packages/core/src/comments/threadstore/yjs/YjsThreadStore.test.ts @@ -1,15 +1,18 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { afterAll, beforeEach, describe, expect, it, vi } from "vitest"; import * as Y from "yjs"; import { CommentBody } from "../../types.js"; import { DefaultThreadStoreAuth } from "../DefaultThreadStoreAuth.js"; import { YjsThreadStore } from "./YjsThreadStore.js"; -// Mock UUID to generate sequential IDs +// Mock crypto.randomUUID to generate sequential IDs let mockUuidCounter = 0; -vi.mock("lib0/random", async (importOriginal) => ({ - ...(await importOriginal()), - uuidv4: () => `mocked-uuid-${++mockUuidCounter}`, -})); +const randomUUIDSpy = vi.spyOn(crypto, "randomUUID").mockImplementation( + () => `mocked-uuid-${++mockUuidCounter}` as `${string}-${string}-${string}-${string}-${string}`, +); + +afterAll(() => { + randomUUIDSpy.mockRestore(); +}); describe("YjsThreadStore", () => { let store: YjsThreadStore; diff --git a/packages/core/src/comments/threadstore/yjs/YjsThreadStore.ts b/packages/core/src/comments/threadstore/yjs/YjsThreadStore.ts index f9754c6063..6d7a18fd1f 100644 --- a/packages/core/src/comments/threadstore/yjs/YjsThreadStore.ts +++ b/packages/core/src/comments/threadstore/yjs/YjsThreadStore.ts @@ -1,4 +1,3 @@ -import { uuidv4 } from "lib0/random"; import * as Y from "yjs"; import { CommentBody, CommentData, ThreadData } from "../../types.js"; import { ThreadStoreAuth } from "../ThreadStoreAuth.js"; @@ -57,7 +56,7 @@ export class YjsThreadStore extends YjsThreadStoreBase { const comment: CommentData = { type: "comment", - id: uuidv4(), + id: crypto.randomUUID(), userId: this.userId, createdAt: date, updatedAt: date, @@ -68,7 +67,7 @@ export class YjsThreadStore extends YjsThreadStoreBase { const thread: ThreadData = { type: "thread", - id: uuidv4(), + id: crypto.randomUUID(), createdAt: date, updatedAt: date, comments: [comment], @@ -105,7 +104,7 @@ export class YjsThreadStore extends YjsThreadStoreBase { const date = new Date(); const comment: CommentData = { type: "comment", - id: uuidv4(), + id: crypto.randomUUID(), userId: this.userId, createdAt: date, updatedAt: date, diff --git a/packages/core/src/extensions/Placeholder/Placeholder.ts b/packages/core/src/extensions/Placeholder/Placeholder.ts index b8ff2e14ed..37556e5ecd 100644 --- a/packages/core/src/extensions/Placeholder/Placeholder.ts +++ b/packages/core/src/extensions/Placeholder/Placeholder.ts @@ -1,6 +1,6 @@ import { Plugin, PluginKey } from "prosemirror-state"; import { Decoration, DecorationSet } from "prosemirror-view"; -import { uuidv4 } from "lib0/random"; + import { createExtension, ExtensionOptions, @@ -23,7 +23,7 @@ export const PlaceholderExtension = createExtension( new Plugin({ key: PLUGIN_KEY, view: (view) => { - const uniqueEditorSelector = `placeholder-selector-${uuidv4()}`; + const uniqueEditorSelector = `placeholder-selector-${crypto.randomUUID()}`; view.dom.classList.add(uniqueEditorSelector); const styleEl = document.createElement("style"); diff --git a/packages/core/src/extensions/tiptap-extensions/UniqueID/UniqueID.ts b/packages/core/src/extensions/tiptap-extensions/UniqueID/UniqueID.ts index a3ce6f3828..2088870098 100644 --- a/packages/core/src/extensions/tiptap-extensions/UniqueID/UniqueID.ts +++ b/packages/core/src/extensions/tiptap-extensions/UniqueID/UniqueID.ts @@ -6,7 +6,7 @@ import { } from "@tiptap/core"; import { Fragment, Slice } from "prosemirror-model"; import { Plugin, PluginKey } from "prosemirror-state"; -import { uuidv4 } from "lib0/random"; + /** * Code from Tiptap UniqueID extension (https://tiptap.dev/api/extensions/unique-id) @@ -65,7 +65,7 @@ const UniqueID = Extension.create({ return testOptions.mockID.toString() as string; } - return uuidv4(); + return crypto.randomUUID(); }, filterTransaction: null, }; diff --git a/packages/mantine/package.json b/packages/mantine/package.json index 7fc0ef9c0f..ed58b24b05 100644 --- a/packages/mantine/package.json +++ b/packages/mantine/package.json @@ -62,10 +62,10 @@ }, "dependencies": { "@blocknote/core": "0.51.4", - "@blocknote/react": "0.51.4", - "react-icons": "^5.5.0" + "@blocknote/react": "0.51.4" }, "devDependencies": { + "react-icons": "^5.5.0", "@types/react": "^19.2.3", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", diff --git a/packages/mantine/vite.config.ts b/packages/mantine/vite.config.ts index db1342b975..6a44bf5424 100644 --- a/packages/mantine/vite.config.ts +++ b/packages/mantine/vite.config.ts @@ -45,6 +45,16 @@ export default defineConfig((conf) => ({ // make sure to externalize deps that shouldn't be bundled // into your library external: (source) => { + // Bundle react-icons into the output (tree-shaken) so consumers + // don't need to install it as a peer/runtime dependency. + const bundledDeps = ["react-icons"]; + if ( + bundledDeps.some( + (dep) => source === dep || source.startsWith(dep + "/") + ) + ) { + return false; + } if ( Object.keys({ ...pkg.dependencies, diff --git a/packages/react/package.json b/packages/react/package.json index 1e62c1e2ad..ed2f550be9 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -61,22 +61,18 @@ "@blocknote/core": "0.51.4", "@emoji-mart/data": "^1.2.1", "@floating-ui/react": "^0.27.18", - "@floating-ui/utils": "^0.2.10", "@tanstack/react-store": "0.7.7", "@tiptap/core": "^3.13.0", "@tiptap/pm": "^3.13.0", "@tiptap/react": "^3.13.0", - "@types/use-sync-external-store": "1.5.0", "emoji-mart": "^5.6.0", "fast-deep-equal": "^3.1.3", - "lodash.merge": "^4.6.2", - "react-icons": "^5.5.0", "use-sync-external-store": "1.6.0" }, "devDependencies": { "@types/lodash.foreach": "^4.5.9", "@types/lodash.groupby": "^4.6.9", - "@types/lodash.merge": "^4.6.9", + "react-icons": "^5.5.0", "@types/react": "^19.2.3", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", @@ -91,6 +87,9 @@ "vite-plugin-externalize-deps": "^0.10.0", "vitest": "^4.1.2" }, + "optionalDependencies": { + "@types/use-sync-external-store": "1.5.0" + }, "peerDependencies": { "react": "^18.0 || ^19.0 || >= 19.0.0-rc", "react-dom": "^18.0 || ^19.0 || >= 19.0.0-rc" diff --git a/packages/react/src/components/FormattingToolbar/DefaultButtons/BasicTextStyleButton.tsx b/packages/react/src/components/FormattingToolbar/DefaultButtons/BasicTextStyleButton.tsx index f2ae1e9ac6..66de89fe49 100644 --- a/packages/react/src/components/FormattingToolbar/DefaultButtons/BasicTextStyleButton.tsx +++ b/packages/react/src/components/FormattingToolbar/DefaultButtons/BasicTextStyleButton.tsx @@ -6,7 +6,7 @@ import { formatKeyboardShortcut, } from "@blocknote/core"; import { useCallback } from "react"; -import { IconType } from "react-icons"; +import type { IconType } from "../../../icons.js"; import { RiBold, RiCodeFill, diff --git a/packages/react/src/components/FormattingToolbar/DefaultButtons/TextAlignButton.tsx b/packages/react/src/components/FormattingToolbar/DefaultButtons/TextAlignButton.tsx index a21f1006cb..dde40e4d9c 100644 --- a/packages/react/src/components/FormattingToolbar/DefaultButtons/TextAlignButton.tsx +++ b/packages/react/src/components/FormattingToolbar/DefaultButtons/TextAlignButton.tsx @@ -11,7 +11,7 @@ import { } from "@blocknote/core"; import { TableHandlesExtension } from "@blocknote/core/extensions"; import { useCallback } from "react"; -import { IconType } from "react-icons"; +import type { IconType } from "../../../icons.js"; import { RiAlignCenter, RiAlignJustify, diff --git a/packages/react/src/components/FormattingToolbar/DefaultSelects/BlockTypeSelect.tsx b/packages/react/src/components/FormattingToolbar/DefaultSelects/BlockTypeSelect.tsx index d9bb12a00a..77a929271d 100644 --- a/packages/react/src/components/FormattingToolbar/DefaultSelects/BlockTypeSelect.tsx +++ b/packages/react/src/components/FormattingToolbar/DefaultSelects/BlockTypeSelect.tsx @@ -6,7 +6,7 @@ import { StyleSchema, } from "@blocknote/core"; import { useMemo } from "react"; -import type { IconType } from "react-icons"; +import type { IconType } from "../../../icons.js"; import { RiH1, RiH2, diff --git a/packages/react/src/components/SuggestionMenu/getDefaultReactSlashMenuItems.tsx b/packages/react/src/components/SuggestionMenu/getDefaultReactSlashMenuItems.tsx index 0c62e30f23..722edcb613 100644 --- a/packages/react/src/components/SuggestionMenu/getDefaultReactSlashMenuItems.tsx +++ b/packages/react/src/components/SuggestionMenu/getDefaultReactSlashMenuItems.tsx @@ -28,7 +28,7 @@ import { RiVolumeUpFill, } from "react-icons/ri"; -import { IconType } from "react-icons"; +import type { IconType } from "../../icons.js"; import { DefaultReactSuggestionItem } from "./types.js"; const icons: Record = { diff --git a/packages/react/src/icons.ts b/packages/react/src/icons.ts new file mode 100644 index 0000000000..055f23a560 --- /dev/null +++ b/packages/react/src/icons.ts @@ -0,0 +1,12 @@ +/** + * Compatible replacement for `IconType` from react-icons. + * Defined locally so consumers don't need react-icons installed for + * type-checking. + */ +export type IconType = ( + props: React.SVGAttributes & { + size?: string | number; + color?: string; + title?: string; + } +) => React.ReactNode; diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 6ed745a789..6beb5a7082 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -133,6 +133,8 @@ export * from "./schema/ReactBlockSpec.js"; export * from "./schema/ReactInlineContentSpec.js"; export * from "./schema/ReactStyleSpec.js"; +export * from "./icons.js"; + export * from "./util/elementOverflow.js"; export * from "./util/mergeRefs.js"; diff --git a/packages/react/vite.config.ts b/packages/react/vite.config.ts index dde82555a5..abbbfb3dc9 100644 --- a/packages/react/vite.config.ts +++ b/packages/react/vite.config.ts @@ -44,6 +44,16 @@ export default defineConfig((conf) => ({ // make sure to externalize deps that shouldn't be bundled // into your library external: (source) => { + // Bundle react-icons into the output (tree-shaken) so consumers + // don't need to install it as a peer/runtime dependency. + const bundledDeps = ["react-icons"]; + if ( + bundledDeps.some( + (dep) => source === dep || source.startsWith(dep + "/") + ) + ) { + return false; + } if ( Object.keys({ ...pkg.dependencies, diff --git a/packages/server-util/package.json b/packages/server-util/package.json index a6b62c702d..1e00f7fa26 100644 --- a/packages/server-util/package.json +++ b/packages/server-util/package.json @@ -58,15 +58,14 @@ "dependencies": { "@blocknote/core": "0.51.4", "@blocknote/react": "0.51.4", - "@tiptap/core": "^3.13.0", "@tiptap/pm": "^3.13.0", "jsdom": "^25.0.1", - "y-prosemirror": "^1.3.7", - "y-protocols": "^1.0.6", "yjs": "^13.6.27" }, "devDependencies": { "@types/jsdom": "^21.1.7", + "y-prosemirror": "^1.3.7", + "y-protocols": "^1.0.6", "@types/react": "^19.2.3", "@types/react-dom": "^19.2.3", "eslint": "^8.57.1", diff --git a/packages/shadcn/package.json b/packages/shadcn/package.json index e20854d9a9..84780af8d2 100644 --- a/packages/shadcn/package.json +++ b/packages/shadcn/package.json @@ -67,7 +67,6 @@ "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-toggle": "^1.1.10", "@radix-ui/react-tooltip": "^1.2.8", - "autoprefixer": "^10.4.21", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.525.0", diff --git a/packages/xl-ai/package.json b/packages/xl-ai/package.json index 0788136c29..754c9b9f25 100644 --- a/packages/xl-ai/package.json +++ b/packages/xl-ai/package.json @@ -73,11 +73,9 @@ "@ai-sdk/provider-utils": "^4.0.2", "@ai-sdk/react": "^3.0.5", "@blocknote/core": "0.51.4", - "@blocknote/mantine": "0.51.4", "@blocknote/react": "0.51.4", "@floating-ui/react": "^0.27.18", "@handlewithcare/prosemirror-suggest-changes": "^0.1.8", - "@tiptap/core": "^3.13.0", "ai": "^6.0.5", "lodash.isequal": "^4.5.0", "lodash.merge": "^4.6.2", @@ -87,12 +85,10 @@ "prosemirror-tables": "^1.8.3", "prosemirror-transform": "^1.11.0", "prosemirror-view": "^1.41.4", - "react": "^19.2.5", - "react-dom": "^19.2.5", - "react-icons": "^5.5.0", "y-prosemirror": "^1.3.7" }, "devDependencies": { + "react-icons": "^5.5.0", "@ai-sdk/anthropic": "^3.0.2", "@ai-sdk/google": "^3.0.2", "@ai-sdk/groq": "^3.0.2", diff --git a/packages/xl-ai/vite.config.ts b/packages/xl-ai/vite.config.ts index 2c56391772..d8b37eb6fb 100644 --- a/packages/xl-ai/vite.config.ts +++ b/packages/xl-ai/vite.config.ts @@ -51,6 +51,16 @@ export default defineConfig((conf) => ({ // make sure to externalize deps that shouldn't be bundled // into your library external: (source) => { + // Bundle react-icons into the output (tree-shaken) so consumers + // don't need to install it as a peer/runtime dependency. + const bundledDeps = ["react-icons"]; + if ( + bundledDeps.some( + (dep) => source === dep || source.startsWith(dep + "/") + ) + ) { + return false; + } if ( Object.keys({ ...pkg.dependencies, diff --git a/packages/xl-email-exporter/package.json b/packages/xl-email-exporter/package.json index 8cadc3bad6..4b2097d4b3 100644 --- a/packages/xl-email-exporter/package.json +++ b/packages/xl-email-exporter/package.json @@ -55,17 +55,15 @@ }, "dependencies": { "@blocknote/core": "0.51.4", - "@blocknote/react": "0.51.4", "@react-email/components": "^1.0.5", "@react-email/render": "^2.0.4", - "buffer": "^6.0.3", - "react": "^19.2.5", - "react-dom": "^19.2.5", - "react-email": "^5.2.5", "web-streams-polyfill": "^4.2.0" }, "devDependencies": { "@types/jsdom": "^21.1.7", + "react": "^19.2.5", + "react-dom": "^19.2.5", + "react-email": "^5.2.5", "@types/react": "^19.2.3", "@types/react-dom": "^19.2.3", "eslint": "^8.57.1", diff --git a/packages/xl-multi-column/package.json b/packages/xl-multi-column/package.json index 0fa0f1c159..b015af9469 100644 --- a/packages/xl-multi-column/package.json +++ b/packages/xl-multi-column/package.json @@ -56,12 +56,10 @@ "@tiptap/core": "^3.13.0", "prosemirror-model": "^1.25.4", "prosemirror-state": "^1.4.4", - "prosemirror-tables": "^1.8.3", - "prosemirror-transform": "^1.11.0", - "prosemirror-view": "^1.41.4", - "react-icons": "^5.5.0" + "prosemirror-view": "^1.41.4" }, "devDependencies": { + "react-icons": "^5.5.0", "@types/react": "^19.2.3", "@types/react-dom": "^19.2.3", "eslint": "^8.57.1", diff --git a/packages/xl-multi-column/vite.config.ts b/packages/xl-multi-column/vite.config.ts index 67d5f30b4d..645c3d60c6 100644 --- a/packages/xl-multi-column/vite.config.ts +++ b/packages/xl-multi-column/vite.config.ts @@ -38,6 +38,16 @@ export default defineConfig((conf) => ({ // make sure to externalize deps that shouldn't be bundled // into your library external: (source) => { + // Bundle react-icons into the output (tree-shaken) so consumers + // don't need to install it as a peer/runtime dependency. + const bundledDeps = ["react-icons"]; + if ( + bundledDeps.some( + (dep) => source === dep || source.startsWith(dep + "/") + ) + ) { + return false; + } if ( Object.keys({ ...pkg.dependencies, diff --git a/packages/xl-odt-exporter/package.json b/packages/xl-odt-exporter/package.json index 40267839d8..35b9063ad6 100644 --- a/packages/xl-odt-exporter/package.json +++ b/packages/xl-odt-exporter/package.json @@ -60,7 +60,6 @@ "@blocknote/core": "0.51.4", "@blocknote/xl-multi-column": "0.51.4", "@zip.js/zip.js": "^2.8.8", - "buffer": "^6.0.3", "image-meta": "^0.2.2" }, "devDependencies": { diff --git a/packages/xl-pdf-exporter/package.json b/packages/xl-pdf-exporter/package.json index 707fb9e453..5c2524fe81 100644 --- a/packages/xl-pdf-exporter/package.json +++ b/packages/xl-pdf-exporter/package.json @@ -57,11 +57,8 @@ }, "dependencies": { "@blocknote/core": "0.51.4", - "@blocknote/react": "0.51.4", "@blocknote/xl-multi-column": "0.51.4", - "@react-pdf/renderer": "^4.3.0", - "buffer": "^6.0.3", - "docx": "^9.5.1" + "@react-pdf/renderer": "^4.3.0" }, "devDependencies": { "@testing-library/react": "^16.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4046c1d4ae..f7dc307d42 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4590,9 +4590,6 @@ importers: '@shikijs/themes': specifier: ^4 version: 4.0.2 - '@shikijs/types': - specifier: ^4 - version: 4.0.2 devDependencies: eslint: specifier: ^8.57.1 @@ -4612,6 +4609,10 @@ importers: vitest: specifier: 4.1.2 version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.9.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) + optionalDependencies: + '@shikijs/types': + specifier: ^4 + version: 4.0.2 packages/core: dependencies: @@ -4636,15 +4637,9 @@ importers: '@tiptap/extension-code': specifier: ^3.13.0 version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4)) - '@tiptap/extension-horizontal-rule': - specifier: ^3.13.0 - version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4) '@tiptap/extension-italic': specifier: ^3.13.0 version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4)) - '@tiptap/extension-paragraph': - specifier: ^3.13.0 - version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4)) '@tiptap/extension-strike': specifier: ^3.13.0 version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4)) @@ -4666,9 +4661,6 @@ importers: fast-deep-equal: specifier: ^3.1.3 version: 3.1.3 - lib0: - specifier: ^0.2.99 - version: 0.2.117 prosemirror-highlight: specifier: ^0.15.1 version: 0.15.1(@shikijs/types@4.0.2)(@types/hast@3.0.4)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-transform@1.12.0)(prosemirror-view@1.41.8) @@ -4770,9 +4762,6 @@ importers: '@mantine/hooks': specifier: ^8.3.11 || ^9.0.2 version: 9.1.1(react@19.2.5) - react-icons: - specifier: ^5.5.0 - version: 5.6.0(react@19.2.5) devDependencies: '@types/react': specifier: ^19.2.3 @@ -4792,6 +4781,9 @@ importers: react-dom: specifier: ^19.2.5 version: 19.2.5(react@19.2.5) + react-icons: + specifier: ^5.5.0 + version: 5.6.0(react@19.2.5) rimraf: specifier: ^5.0.10 version: 5.0.10 @@ -4822,9 +4814,6 @@ importers: '@floating-ui/react': specifier: ^0.27.18 version: 0.27.19(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@floating-ui/utils': - specifier: ^0.2.10 - version: 0.2.11 '@tanstack/react-store': specifier: 0.7.7 version: 0.7.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -4837,21 +4826,12 @@ importers: '@tiptap/react': specifier: ^3.13.0 version: 3.22.4(@floating-ui/dom@1.7.6)(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@types/use-sync-external-store': - specifier: 1.5.0 - version: 1.5.0 emoji-mart: specifier: ^5.6.0 version: 5.6.0 fast-deep-equal: specifier: ^3.1.3 version: 3.1.3 - lodash.merge: - specifier: ^4.6.2 - version: 4.6.2 - react-icons: - specifier: ^5.5.0 - version: 5.6.0(react@19.2.5) use-sync-external-store: specifier: 1.6.0 version: 1.6.0(react@19.2.5) @@ -4862,9 +4842,6 @@ importers: '@types/lodash.groupby': specifier: ^4.6.9 version: 4.6.9 - '@types/lodash.merge': - specifier: ^4.6.9 - version: 4.6.9 '@types/react': specifier: ^19.2.3 version: 19.2.14 @@ -4883,6 +4860,9 @@ importers: react-dom: specifier: ^19.2.5 version: 19.2.5(react@19.2.5) + react-icons: + specifier: ^5.5.0 + version: 5.6.0(react@19.2.5) rimraf: specifier: ^5.0.10 version: 5.0.10 @@ -4904,6 +4884,10 @@ importers: vitest: specifier: 4.1.2 version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.9.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) + optionalDependencies: + '@types/use-sync-external-store': + specifier: 1.5.0 + version: 1.5.0 packages/server-util: dependencies: @@ -4913,21 +4897,12 @@ importers: '@blocknote/react': specifier: 0.51.4 version: link:../react - '@tiptap/core': - specifier: ^3.0.0 - version: 3.22.4(@tiptap/pm@3.22.4) '@tiptap/pm': specifier: ^3.0.0 version: 3.22.4 jsdom: specifier: ^25.0.1 version: 25.0.1(canvas@2.11.2) - y-prosemirror: - specifier: ^1.3.7 - version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) - y-protocols: - specifier: ^1.0.6 - version: 1.0.7(yjs@13.6.30) yjs: specifier: ^13.6.27 version: 13.6.30 @@ -4965,6 +4940,12 @@ importers: vitest: specifier: 4.1.2 version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(jsdom@25.0.1(canvas@2.11.2))(msw@2.11.5(@types/node@25.9.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) + y-prosemirror: + specifier: ^1.3.7 + version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) + y-protocols: + specifier: ^1.0.6 + version: 1.0.7(yjs@13.6.30) packages/shadcn: dependencies: @@ -5001,9 +4982,6 @@ importers: '@radix-ui/react-tooltip': specifier: ^1.2.8 version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - autoprefixer: - specifier: ^10.4.21 - version: 10.4.21(postcss@8.5.14) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -5077,9 +5055,6 @@ importers: '@blocknote/core': specifier: 0.51.4 version: link:../core - '@blocknote/mantine': - specifier: 0.51.4 - version: link:../mantine '@blocknote/react': specifier: 0.51.4 version: link:../react @@ -5089,9 +5064,6 @@ importers: '@handlewithcare/prosemirror-suggest-changes': specifier: ^0.1.8 version: 0.1.8(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-transform@1.12.0)(prosemirror-view@1.41.8) - '@tiptap/core': - specifier: ^3.0.0 - version: 3.22.4(@tiptap/pm@3.22.4) ai: specifier: ^6.0.5 version: 6.0.5(zod@4.3.6) @@ -5120,14 +5092,11 @@ importers: specifier: ^1.41.4 version: 1.41.8 react: - specifier: ^19.2.5 + specifier: ^18.0 || ^19.0 || >= 19.0.0-rc version: 19.2.5 react-dom: - specifier: ^19.2.5 + specifier: ^18.0 || ^19.0 || >= 19.0.0-rc version: 19.2.5(react@19.2.5) - react-icons: - specifier: ^5.5.0 - version: 5.6.0(react@19.2.5) y-prosemirror: specifier: ^1.3.7 version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) @@ -5198,6 +5167,9 @@ importers: msw-snapshot: specifier: ^5.3.0 version: 5.3.0(msw@2.11.5(@types/node@25.9.0)(typescript@5.9.3)) + react-icons: + specifier: ^5.5.0 + version: 5.6.0(react@19.2.5) rimraf: specifier: ^5.0.10 version: 5.0.10 @@ -5347,27 +5319,12 @@ importers: '@blocknote/core': specifier: 0.51.4 version: link:../core - '@blocknote/react': - specifier: 0.51.4 - version: link:../react '@react-email/components': specifier: ^1.0.5 version: 1.0.11(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@react-email/render': specifier: ^2.0.4 version: 2.0.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - buffer: - specifier: ^6.0.3 - version: 6.0.3 - react: - specifier: ^19.2.5 - version: 19.2.5 - react-dom: - specifier: ^19.2.5 - version: 19.2.5(react@19.2.5) - react-email: - specifier: ^5.2.5 - version: 5.2.10 web-streams-polyfill: specifier: ^4.2.0 version: 4.2.0 @@ -5384,6 +5341,15 @@ importers: eslint: specifier: ^8.57.1 version: 8.57.1 + react: + specifier: ^19.2.5 + version: 19.2.5 + react-dom: + specifier: ^19.2.5 + version: 19.2.5(react@19.2.5) + react-email: + specifier: ^5.2.5 + version: 5.2.10 rollup-plugin-webpack-stats: specifier: ^0.2.6 version: 0.2.6(rollup@4.60.1) @@ -5417,18 +5383,9 @@ importers: prosemirror-state: specifier: ^1.4.4 version: 1.4.4 - prosemirror-tables: - specifier: ^1.8.3 - version: 1.8.5 - prosemirror-transform: - specifier: ^1.11.0 - version: 1.12.0 prosemirror-view: specifier: ^1.41.4 version: 1.41.8 - react-icons: - specifier: ^5.5.0 - version: 5.6.0(react@19.2.5) devDependencies: '@types/react': specifier: ^19.2.3 @@ -5448,6 +5405,9 @@ importers: react-dom: specifier: ^19.2.5 version: 19.2.5(react@19.2.5) + react-icons: + specifier: ^5.5.0 + version: 5.6.0(react@19.2.5) rimraf: specifier: ^5.0.10 version: 5.0.10 @@ -5478,9 +5438,6 @@ importers: '@zip.js/zip.js': specifier: ^2.8.8 version: 2.8.26 - buffer: - specifier: ^6.0.3 - version: 6.0.3 image-meta: specifier: ^0.2.2 version: 0.2.2 @@ -5527,21 +5484,12 @@ importers: '@blocknote/core': specifier: 0.51.4 version: link:../core - '@blocknote/react': - specifier: 0.51.4 - version: link:../react '@blocknote/xl-multi-column': specifier: 0.51.4 version: link:../xl-multi-column '@react-pdf/renderer': specifier: ^4.3.0 version: 4.3.2(react@19.2.5) - buffer: - specifier: ^6.0.3 - version: 6.0.3 - docx: - specifier: ^9.5.1 - version: 9.5.1 devDependencies: '@testing-library/react': specifier: ^16.3.0 @@ -10401,22 +10349,11 @@ packages: '@tiptap/core': ^3.0.0 '@tiptap/pm': ^3.0.0 - '@tiptap/extension-horizontal-rule@3.22.4': - resolution: {integrity: sha512-cCI1HekGQwhY/MbgaKQ0R/7HcH5ZM1oFAyI/J72QGLC0XnF403S/OXoHMuBWr1mCu8hNiQWCzeNRJUty0iytNw==} - peerDependencies: - '@tiptap/core': ^3.0.0 - '@tiptap/pm': ^3.0.0 - '@tiptap/extension-italic@3.22.4': resolution: {integrity: sha512-fVSDx5AYXgDI3v2zZIqb7V8EewthwM2NJ/ZCX+XaxRsqNEpnjVhgHs7UlvDqK1wj2OJ6zmUNjPtVlAFRxwT+HQ==} peerDependencies: '@tiptap/core': ^3.0.0 - '@tiptap/extension-paragraph@3.22.4': - resolution: {integrity: sha512-de6dFkIhigiENESY6rNJ3yTVS/337ybfP30dNPudTwGe9oAu9ZCS+04j6QCvXSjhlI3ULiv7wiSHqrP26Gd+Hw==} - peerDependencies: - '@tiptap/core': ^3.0.0 - '@tiptap/extension-strike@3.22.4': resolution: {integrity: sha512-aRHWQj42HiailXSC9LkKYM3jWMcSeGwOjbqM4PiuxQZmHVDRFmeHkfJItOdn2cSHaO0vuEVK+TvrWUWsBFi3pg==} peerDependencies: @@ -21664,19 +21601,10 @@ snapshots: '@tiptap/pm': 3.22.4 optional: true - '@tiptap/extension-horizontal-rule@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)': - dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) - '@tiptap/pm': 3.22.4 - '@tiptap/extension-italic@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))': dependencies: '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) - '@tiptap/extension-paragraph@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))': - dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) - '@tiptap/extension-strike@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))': dependencies: '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) @@ -21998,7 +21926,8 @@ snapshots: '@types/use-sync-external-store@0.0.6': {} - '@types/use-sync-external-store@1.5.0': {} + '@types/use-sync-external-store@1.5.0': + optional: true '@types/ws@8.18.1': dependencies: From 767a82f71ad1390b67cdd344bcabb5b690eeb60a Mon Sep 17 00:00:00 2001 From: Matthew Lipski <50169049+matthewlipski@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:25:59 +0200 Subject: [PATCH 10/11] feat: migrate to Vite+ (#2745) --- .eslintrc.json | 42 - .github/ISSUE_TEMPLATE/config.yml | 2 +- .github/workflows/build.yml | 102 +- .github/workflows/fresh-install-tests.yml | 37 +- .github/workflows/publish.yaml | 66 +- .github/workflows/zizmor.yml | 2 +- .node-version | 1 + .nvmrc | 1 - .prettierrc | 12 - .vite-hooks/pre-commit | 1 + AGENTS.md | 16 + CONTRIBUTING.md | 10 +- docs/app/(home)/_components/BlockCatalog.tsx | 6 +- .../app/(home)/_components/DigitalCommons.tsx | 4 +- docs/app/(home)/_components/FAQ.tsx | 2 +- .../app/(home)/_components/FeatureSection.tsx | 2 +- docs/app/(home)/_components/FrameworkPill.tsx | 2 +- docs/app/(home)/_components/Hero.tsx | 8 +- docs/app/(home)/_components/Letter.tsx | 8 +- docs/app/(home)/_components/Marquee.tsx | 4 +- docs/app/(home)/_components/Pricing.tsx | 2 +- docs/app/(home)/_components/SpotlightCard.tsx | 4 +- docs/app/(home)/_components/TextLoop.tsx | 4 +- docs/app/(home)/_components/USP.tsx | 2 +- docs/app/[...slug]/page.tsx | 8 +- docs/app/demo/_components/DemoEditor.tsx | 10 +- docs/app/demo/_components/EditorMenu.tsx | 8 +- docs/app/docs/[[...slug]]/page.tsx | 8 +- docs/app/examples/[[...slug]]/page.tsx | 6 +- docs/app/og/docs/[...slug]/route.tsx | 4 +- docs/app/og/examples/[...slug]/route.tsx | 4 +- docs/app/og/pages/[...slug]/route.tsx | 4 +- docs/app/pricing/page.tsx | 2 +- docs/app/pricing/tiers.tsx | 19 +- docs/components/AuthNavButton.tsx | 4 +- docs/components/AuthenticationPage.tsx | 4 +- docs/components/CustomDocsLayout.tsx | 2 +- docs/components/ProBadge.tsx | 2 +- .../fumadocs/layout/home/client.tsx | 29 +- .../fumadocs/layout/language-toggle.tsx | 36 +- docs/components/fumadocs/layout/link-item.tsx | 42 +- .../fumadocs/layout/search-toggle.tsx | 35 +- docs/components/fumadocs/layout/shared.tsx | 35 +- .../fumadocs/layout/sidebar/base.tsx | 194 +- .../fumadocs/layout/sidebar/link-item.tsx | 32 +- .../fumadocs/layout/sidebar/page-tree.tsx | 60 +- .../fumadocs/layout/sidebar/tabs/dropdown.tsx | 58 +- .../fumadocs/layout/sidebar/tabs/index.tsx | 50 +- .../fumadocs/layout/theme-toggle.tsx | 52 +- docs/components/fumadocs/ui/button.tsx | 20 +- docs/components/fumadocs/ui/collapsible.tsx | 10 +- .../fumadocs/ui/navigation-menu.tsx | 31 +- docs/components/fumadocs/ui/popover.tsx | 23 +- docs/components/fumadocs/ui/scroll-area.tsx | 30 +- docs/components/search.tsx | 25 +- docs/content/docs/reference/editor/meta.json | 8 +- docs/eslint.config.mjs | 17 - docs/lib/fumadocs/cn.ts | 2 +- docs/lib/fumadocs/merge-refs.ts | 8 +- docs/lib/fumadocs/urls.ts | 10 +- docs/package.json | 10 +- examples/.eslintrc.js | 6 - examples/01-basic/01-minimal/main.tsx | 2 +- examples/01-basic/01-minimal/package.json | 12 +- examples/01-basic/01-minimal/tsconfig.json | 13 +- examples/01-basic/01-minimal/vite.config.ts | 11 +- examples/01-basic/02-block-objects/main.tsx | 2 +- .../01-basic/02-block-objects/package.json | 12 +- .../01-basic/02-block-objects/tsconfig.json | 13 +- .../01-basic/02-block-objects/vite.config.ts | 11 +- examples/01-basic/03-multi-column/main.tsx | 2 +- .../01-basic/03-multi-column/package.json | 12 +- examples/01-basic/03-multi-column/src/App.tsx | 5 +- .../01-basic/03-multi-column/tsconfig.json | 13 +- .../01-basic/03-multi-column/vite.config.ts | 11 +- examples/01-basic/04-default-blocks/main.tsx | 2 +- .../01-basic/04-default-blocks/package.json | 12 +- .../01-basic/04-default-blocks/tsconfig.json | 13 +- .../01-basic/04-default-blocks/vite.config.ts | 11 +- .../05-removing-default-blocks/main.tsx | 2 +- .../05-removing-default-blocks/package.json | 12 +- .../05-removing-default-blocks/tsconfig.json | 13 +- .../05-removing-default-blocks/vite.config.ts | 11 +- .../01-basic/06-block-manipulation/main.tsx | 2 +- .../06-block-manipulation/package.json | 12 +- .../06-block-manipulation/tsconfig.json | 13 +- .../06-block-manipulation/vite.config.ts | 11 +- .../01-basic/07-selection-blocks/main.tsx | 2 +- .../01-basic/07-selection-blocks/package.json | 12 +- .../07-selection-blocks/tsconfig.json | 13 +- .../07-selection-blocks/vite.config.ts | 11 +- examples/01-basic/08-ariakit/main.tsx | 2 +- examples/01-basic/08-ariakit/package.json | 12 +- examples/01-basic/08-ariakit/tsconfig.json | 13 +- examples/01-basic/08-ariakit/vite.config.ts | 11 +- examples/01-basic/09-shadcn/main.tsx | 2 +- examples/01-basic/09-shadcn/package.json | 12 +- examples/01-basic/09-shadcn/src/App.tsx | 10 +- examples/01-basic/09-shadcn/tsconfig.json | 13 +- examples/01-basic/09-shadcn/vite.config.ts | 11 +- examples/01-basic/10-localization/main.tsx | 2 +- .../01-basic/10-localization/package.json | 12 +- .../01-basic/10-localization/tsconfig.json | 13 +- .../01-basic/10-localization/vite.config.ts | 11 +- .../01-basic/11-custom-placeholder/main.tsx | 2 +- .../11-custom-placeholder/package.json | 12 +- .../11-custom-placeholder/tsconfig.json | 13 +- .../11-custom-placeholder/vite.config.ts | 11 +- examples/01-basic/12-multi-editor/main.tsx | 2 +- .../01-basic/12-multi-editor/package.json | 12 +- .../01-basic/12-multi-editor/tsconfig.json | 13 +- .../01-basic/12-multi-editor/vite.config.ts | 11 +- .../01-basic/13-custom-paste-handler/main.tsx | 2 +- .../13-custom-paste-handler/package.json | 12 +- .../13-custom-paste-handler/tsconfig.json | 13 +- .../13-custom-paste-handler/vite.config.ts | 11 +- .../01-basic/14-editor-scrollable/main.tsx | 2 +- .../14-editor-scrollable/package.json | 12 +- .../14-editor-scrollable/tsconfig.json | 13 +- .../14-editor-scrollable/vite.config.ts | 11 +- examples/01-basic/15-shadowdom/main.tsx | 2 +- examples/01-basic/15-shadowdom/package.json | 12 +- examples/01-basic/15-shadowdom/src/App.tsx | 5 +- .../01-basic/15-shadowdom/src/vite-env.d.ts | 2 +- examples/01-basic/15-shadowdom/tsconfig.json | 13 +- examples/01-basic/15-shadowdom/vite.config.ts | 11 +- .../01-basic/16-read-only-editor/main.tsx | 2 +- .../01-basic/16-read-only-editor/package.json | 12 +- .../16-read-only-editor/tsconfig.json | 13 +- .../16-read-only-editor/vite.config.ts | 11 +- .../01-basic/17-no-trailing-block/main.tsx | 2 +- .../17-no-trailing-block/package.json | 12 +- .../17-no-trailing-block/tsconfig.json | 13 +- .../17-no-trailing-block/vite.config.ts | 11 +- examples/01-basic/testing/main.tsx | 2 +- examples/01-basic/testing/package.json | 12 +- examples/01-basic/testing/tsconfig.json | 13 +- examples/01-basic/testing/vite.config.ts | 11 +- .../02-backend/01-file-uploading/main.tsx | 2 +- .../02-backend/01-file-uploading/package.json | 12 +- .../01-file-uploading/tsconfig.json | 13 +- .../01-file-uploading/vite.config.ts | 11 +- .../02-backend/02-saving-loading/main.tsx | 2 +- .../02-backend/02-saving-loading/package.json | 12 +- .../02-saving-loading/tsconfig.json | 13 +- .../02-saving-loading/vite.config.ts | 11 +- examples/02-backend/03-s3/main.tsx | 2 +- examples/02-backend/03-s3/package.json | 12 +- examples/02-backend/03-s3/tsconfig.json | 13 +- examples/02-backend/03-s3/vite.config.ts | 11 +- .../04-rendering-static-documents/main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../01-ui-elements-remove/main.tsx | 2 +- .../01-ui-elements-remove/package.json | 12 +- .../01-ui-elements-remove/tsconfig.json | 13 +- .../01-ui-elements-remove/vite.config.ts | 11 +- .../02-formatting-toolbar-buttons/main.tsx | 2 +- .../package.json | 12 +- .../02-formatting-toolbar-buttons/src/App.tsx | 4 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../main.tsx | 2 +- .../package.json | 12 +- .../src/App.tsx | 4 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../04-side-menu-buttons/main.tsx | 2 +- .../04-side-menu-buttons/package.json | 12 +- .../04-side-menu-buttons/tsconfig.json | 13 +- .../04-side-menu-buttons/vite.config.ts | 11 +- .../05-side-menu-drag-handle-items/main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../main.tsx | 2 +- .../package.json | 12 +- .../src/App.tsx | 5 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../11-uppy-file-panel/main.tsx | 2 +- .../11-uppy-file-panel/package.json | 12 +- .../11-uppy-file-panel/src/App.tsx | 4 +- .../11-uppy-file-panel/tsconfig.json | 13 +- .../11-uppy-file-panel/vite.config.ts | 11 +- .../12-static-formatting-toolbar/main.tsx | 2 +- .../12-static-formatting-toolbar/package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../03-ui-components/13-custom-ui/main.tsx | 2 +- .../13-custom-ui/package.json | 12 +- .../13-custom-ui/tsconfig.json | 13 +- .../13-custom-ui/vite.config.ts | 11 +- .../main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../15-advanced-tables/main.tsx | 2 +- .../15-advanced-tables/package.json | 12 +- .../15-advanced-tables/tsconfig.json | 13 +- .../15-advanced-tables/vite.config.ts | 11 +- .../16-link-toolbar-buttons/main.tsx | 2 +- .../16-link-toolbar-buttons/package.json | 12 +- .../16-link-toolbar-buttons/tsconfig.json | 13 +- .../16-link-toolbar-buttons/vite.config.ts | 11 +- .../17-advanced-tables-2/.bnexample.json | 9 +- .../17-advanced-tables-2/main.tsx | 2 +- .../17-advanced-tables-2/package.json | 12 +- .../17-advanced-tables-2/src/App.tsx | 24 +- .../17-advanced-tables-2/tsconfig.json | 13 +- .../17-advanced-tables-2/vite.config.ts | 11 +- .../03-ui-components/18-drag-n-drop/main.tsx | 2 +- .../18-drag-n-drop/package.json | 12 +- .../18-drag-n-drop/tsconfig.json | 13 +- .../18-drag-n-drop/vite.config.ts | 11 +- .../main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../20-portal-elements/README.md | 5 +- .../20-portal-elements/main.tsx | 2 +- .../20-portal-elements/package.json | 12 +- .../20-portal-elements/src/App.tsx | 3 +- .../20-portal-elements/tsconfig.json | 13 +- .../20-portal-elements/vite.config.ts | 11 +- .../01-theming-dom-attributes/main.tsx | 2 +- .../01-theming-dom-attributes/package.json | 12 +- .../01-theming-dom-attributes/tsconfig.json | 13 +- .../01-theming-dom-attributes/vite.config.ts | 11 +- examples/04-theming/02-changing-font/main.tsx | 2 +- .../04-theming/02-changing-font/package.json | 12 +- .../04-theming/02-changing-font/tsconfig.json | 13 +- .../02-changing-font/vite.config.ts | 11 +- examples/04-theming/03-theming-css/main.tsx | 2 +- .../04-theming/03-theming-css/package.json | 12 +- .../04-theming/03-theming-css/tsconfig.json | 13 +- .../04-theming/03-theming-css/vite.config.ts | 11 +- .../04-theming-css-variables/main.tsx | 2 +- .../04-theming-css-variables/package.json | 12 +- .../04-theming-css-variables/tsconfig.json | 13 +- .../04-theming-css-variables/vite.config.ts | 11 +- .../05-theming-css-variables-code/main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- examples/04-theming/06-code-block/main.tsx | 2 +- .../04-theming/06-code-block/package.json | 12 +- .../04-theming/06-code-block/tsconfig.json | 13 +- .../04-theming/06-code-block/vite.config.ts | 11 +- .../04-theming/07-custom-code-block/main.tsx | 2 +- .../07-custom-code-block/package.json | 12 +- .../07-custom-code-block/tsconfig.json | 13 +- .../07-custom-code-block/vite.config.ts | 11 +- .../01-converting-blocks-to-html/main.tsx | 2 +- .../01-converting-blocks-to-html/package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../02-converting-blocks-from-html/main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../03-converting-blocks-to-md/main.tsx | 2 +- .../03-converting-blocks-to-md/package.json | 12 +- .../03-converting-blocks-to-md/tsconfig.json | 13 +- .../03-converting-blocks-to-md/vite.config.ts | 11 +- .../04-converting-blocks-from-md/main.tsx | 2 +- .../04-converting-blocks-from-md/package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../05-converting-blocks-to-pdf/main.tsx | 2 +- .../05-converting-blocks-to-pdf/package.json | 12 +- .../05-converting-blocks-to-pdf/tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../06-converting-blocks-to-docx/main.tsx | 2 +- .../06-converting-blocks-to-docx/package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../07-converting-blocks-to-odt/main.tsx | 2 +- .../07-converting-blocks-to-odt/package.json | 12 +- .../07-converting-blocks-to-odt/tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../09-blocks-to-html-static-render/main.tsx | 2 +- .../package.json | 12 +- .../src/App.tsx | 2 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../10-static-html-render/main.tsx | 2 +- .../10-static-html-render/package.json | 12 +- .../10-static-html-render/tsconfig.json | 13 +- .../10-static-html-render/vite.config.ts | 11 +- .../06-custom-schema/01-alert-block/main.tsx | 2 +- .../01-alert-block/package.json | 12 +- .../01-alert-block/tsconfig.json | 13 +- .../01-alert-block/vite.config.ts | 11 +- .../02-suggestion-menus-mentions/main.tsx | 2 +- .../02-suggestion-menus-mentions/package.json | 12 +- .../02-suggestion-menus-mentions/src/App.tsx | 5 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../06-custom-schema/03-font-style/main.tsx | 2 +- .../03-font-style/package.json | 12 +- .../03-font-style/src/App.tsx | 4 +- .../03-font-style/tsconfig.json | 13 +- .../03-font-style/vite.config.ts | 11 +- .../04-pdf-file-block/main.tsx | 2 +- .../04-pdf-file-block/package.json | 12 +- .../04-pdf-file-block/tsconfig.json | 13 +- .../04-pdf-file-block/vite.config.ts | 11 +- .../05-alert-block-full-ux/main.tsx | 2 +- .../05-alert-block-full-ux/package.json | 12 +- .../05-alert-block-full-ux/src/App.tsx | 4 +- .../05-alert-block-full-ux/tsconfig.json | 13 +- .../05-alert-block-full-ux/vite.config.ts | 11 +- .../06-toggleable-blocks/main.tsx | 2 +- .../06-toggleable-blocks/package.json | 12 +- .../06-toggleable-blocks/tsconfig.json | 13 +- .../06-toggleable-blocks/vite.config.ts | 11 +- .../07-configuring-blocks/main.tsx | 2 +- .../07-configuring-blocks/package.json | 12 +- .../07-configuring-blocks/tsconfig.json | 13 +- .../07-configuring-blocks/vite.config.ts | 11 +- .../08-non-editable-block/main.tsx | 2 +- .../08-non-editable-block/package.json | 12 +- .../08-non-editable-block/tsconfig.json | 13 +- .../08-non-editable-block/vite.config.ts | 11 +- .../draggable-inline-content/main.tsx | 2 +- .../draggable-inline-content/package.json | 12 +- .../draggable-inline-content/tsconfig.json | 13 +- .../draggable-inline-content/vite.config.ts | 11 +- .../react-custom-blocks/main.tsx | 2 +- .../react-custom-blocks/package.json | 12 +- .../react-custom-blocks/tsconfig.json | 13 +- .../react-custom-blocks/vite.config.ts | 11 +- .../react-custom-inline-content/main.tsx | 2 +- .../react-custom-inline-content/package.json | 12 +- .../react-custom-inline-content/tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../react-custom-styles/main.tsx | 2 +- .../react-custom-styles/package.json | 12 +- .../react-custom-styles/tsconfig.json | 13 +- .../react-custom-styles/vite.config.ts | 11 +- .../07-collaboration/01-partykit/main.tsx | 2 +- .../07-collaboration/01-partykit/package.json | 12 +- .../01-partykit/tsconfig.json | 13 +- .../01-partykit/vite.config.ts | 11 +- .../07-collaboration/02-liveblocks/main.tsx | 2 +- .../02-liveblocks/package.json | 12 +- .../02-liveblocks/tsconfig.json | 13 +- .../02-liveblocks/vite.config.ts | 11 +- examples/07-collaboration/03-y-sweet/main.tsx | 2 +- .../07-collaboration/03-y-sweet/package.json | 12 +- .../07-collaboration/03-y-sweet/tsconfig.json | 13 +- .../03-y-sweet/vite.config.ts | 11 +- .../07-collaboration/04-electric-sql/main.tsx | 2 +- .../04-electric-sql/package.json | 12 +- .../04-electric-sql/tsconfig.json | 13 +- .../04-electric-sql/vite.config.ts | 11 +- .../07-collaboration/05-comments/main.tsx | 2 +- .../07-collaboration/05-comments/package.json | 12 +- .../05-comments/tsconfig.json | 13 +- .../05-comments/vite.config.ts | 11 +- .../06-comments-with-sidebar/main.tsx | 2 +- .../06-comments-with-sidebar/package.json | 12 +- .../06-comments-with-sidebar/src/App.tsx | 2 +- .../06-comments-with-sidebar/tsconfig.json | 13 +- .../06-comments-with-sidebar/vite.config.ts | 11 +- .../07-collaboration/07-ghost-writer/main.tsx | 2 +- .../07-ghost-writer/package.json | 12 +- .../07-ghost-writer/src/App.tsx | 5 +- .../07-ghost-writer/tsconfig.json | 13 +- .../07-ghost-writer/vite.config.ts | 11 +- examples/07-collaboration/08-forking/main.tsx | 2 +- .../07-collaboration/08-forking/package.json | 12 +- .../07-collaboration/08-forking/tsconfig.json | 13 +- .../08-forking/vite.config.ts | 11 +- .../09-comments-testing/main.tsx | 2 +- .../09-comments-testing/package.json | 12 +- .../09-comments-testing/tsconfig.json | 13 +- .../09-comments-testing/vite.config.ts | 11 +- .../01-tiptap-arrow-conversion/main.tsx | 2 +- .../01-tiptap-arrow-conversion/package.json | 12 +- .../01-tiptap-arrow-conversion/tsconfig.json | 13 +- .../01-tiptap-arrow-conversion/vite.config.ts | 11 +- examples/09-ai/01-minimal/main.tsx | 2 +- examples/09-ai/01-minimal/package.json | 12 +- examples/09-ai/01-minimal/src/App.tsx | 4 +- examples/09-ai/01-minimal/tsconfig.json | 13 +- examples/09-ai/01-minimal/vite.config.ts | 11 +- examples/09-ai/02-playground/main.tsx | 2 +- examples/09-ai/02-playground/package.json | 12 +- examples/09-ai/02-playground/src/App.tsx | 6 +- examples/09-ai/02-playground/tsconfig.json | 13 +- examples/09-ai/02-playground/vite.config.ts | 11 +- .../09-ai/03-custom-ai-menu-items/main.tsx | 2 +- .../03-custom-ai-menu-items/package.json | 12 +- .../09-ai/03-custom-ai-menu-items/src/App.tsx | 8 +- .../03-custom-ai-menu-items/tsconfig.json | 13 +- .../03-custom-ai-menu-items/vite.config.ts | 11 +- examples/09-ai/04-with-collaboration/main.tsx | 2 +- .../09-ai/04-with-collaboration/package.json | 12 +- .../09-ai/04-with-collaboration/src/App.tsx | 8 +- .../09-ai/04-with-collaboration/tsconfig.json | 13 +- .../04-with-collaboration/vite.config.ts | 11 +- examples/09-ai/05-manual-execution/main.tsx | 2 +- .../09-ai/05-manual-execution/package.json | 12 +- .../09-ai/05-manual-execution/tsconfig.json | 13 +- .../09-ai/05-manual-execution/vite.config.ts | 11 +- .../09-ai/06-client-side-transport/main.tsx | 2 +- .../06-client-side-transport/package.json | 12 +- .../06-client-side-transport/src/App.tsx | 6 +- .../06-client-side-transport/tsconfig.json | 13 +- .../06-client-side-transport/vite.config.ts | 11 +- examples/09-ai/07-server-persistence/main.tsx | 2 +- .../09-ai/07-server-persistence/package.json | 12 +- .../09-ai/07-server-persistence/src/App.tsx | 6 +- .../09-ai/07-server-persistence/tsconfig.json | 13 +- .../07-server-persistence/vite.config.ts | 11 +- .../react-vanilla-custom-blocks/main.tsx | 2 +- .../react-vanilla-custom-blocks/package.json | 12 +- .../react-vanilla-custom-blocks/tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../main.tsx | 2 +- .../package.json | 12 +- .../tsconfig.json | 13 +- .../vite.config.ts | 11 +- .../react-vanilla-custom-styles/main.tsx | 2 +- .../react-vanilla-custom-styles/package.json | 12 +- .../react-vanilla-custom-styles/tsconfig.json | 13 +- .../vite.config.ts | 11 +- nx.json | 57 - package.json | 43 +- packages/ariakit/package.json | 22 +- packages/ariakit/src/panel/PanelFileInput.tsx | 4 +- packages/ariakit/tsconfig.json | 2 +- packages/ariakit/vite.config.ts | 146 +- packages/code-block/package.json | 23 +- packages/code-block/src/index.test.ts | 2 +- packages/code-block/vite.config.ts | 126 +- packages/code-block/vitestSetup.ts | 2 +- packages/core/package.json | 24 +- .../insertBlocks/insertBlocks.test.ts | 2 +- .../commands/mergeBlocks/mergeBlocks.test.ts | 2 +- .../commands/moveBlocks/moveBlocks.test.ts | 2 +- .../commands/nestBlock/nestBlock.test.ts | 4 +- .../commands/nestBlock/nestBlock.ts | 6 +- .../replaceBlocks/replaceBlocks.test.ts | 2 +- .../commands/splitBlock/splitBlock.test.ts | 2 +- .../commands/updateBlock/updateBlock.test.ts | 2 +- .../src/api/blockManipulation/setupTestEnv.ts | 2 +- .../blockManipulation/tables/tables.test.ts | 2 +- .../api/exporters/markdown/htmlToMarkdown.ts | 122 +- .../api/getBlocksChangedByTransaction.test.ts | 2 +- .../api/parsers/html/util/nestedLists.test.ts | 2 +- .../parsers/markdown/detectMarkdown.test.ts | 2 +- .../api/parsers/markdown/markdownToHtml.ts | 310 +- packages/core/src/api/positionMapping.test.ts | 2 +- packages/core/src/blocks/Code/block.test.ts | 21 +- .../ListItem/CheckListItem/block.test.ts | 2 +- .../NumberedListItem/IndexingPlugin.test.ts | 15 +- .../NumberedListItem/IndexingPlugin.ts | 97 +- .../src/blocks/Table/TableExtension.test.ts | 15 +- packages/core/src/blocks/Table/block.ts | 6 +- .../threadstore/yjs/YjsThreadStore.test.ts | 15 +- .../threadstore/yjs/YjsThreadStore.ts | 7 +- .../core/src/editor/BlockNoteEditor.test.ts | 2 +- .../src/editor/BlockNoteExtension.test.ts | 2 +- packages/core/src/editor/performance.test.ts | 2 +- .../core/src/editor/transformPasted.test.ts | 2 +- .../extensions/Collaboration/ForkYDoc.test.ts | 2 +- .../moveColorAttributes.test.ts | 2 +- .../src/extensions/Placeholder/Placeholder.ts | 3 +- .../PreviousBlockType.test.ts | 2 +- .../PreviousBlockType/PreviousBlockType.ts | 5 +- .../core/src/extensions/SideMenu/SideMenu.ts | 3 +- .../SuggestionMenu/SuggestionMenu.test.ts | 2 +- .../KeyboardShortcutsExtension.ts | 6 +- .../Link/helpers/autolink.ts | 18 +- .../Link/helpers/linkDetector.ts | 18 +- .../Link/helpers/whitespace.ts | 4 +- .../tiptap-extensions/Link/link.test.ts | 48 +- .../tiptap-extensions/UniqueID/UniqueID.ts | 4 +- packages/core/src/schema/blocks/types.ts | 4 +- packages/core/src/util/topo-sort.test.ts | 2 +- packages/core/src/vite-env.d.ts | 2 +- packages/core/src/yjs/utils.test.ts | 2 +- packages/core/vite.config.bundled.ts | 2 +- packages/core/vite.config.ts | 13 +- packages/core/vitestSetup.ts | 2 +- packages/dev-scripts/examples/gen.ts | 12 + packages/dev-scripts/examples/genDocs.ts | 14 +- .../template-react/index.html.template.tsx | 1 - .../template-react/package.json.template.tsx | 10 +- .../template-react/tailwind.css.template.tsx | 4 +- .../template-react/tsconfig.json.template.tsx | 5 +- .../vite.config.ts.template.tsx | 7 +- packages/dev-scripts/examples/util.ts | 6 +- packages/dev-scripts/package.json | 21 +- packages/dev-scripts/tsconfig.json | 10 +- packages/dev-scripts/vite.config.ts | 15 + packages/mantine/package.json | 22 +- packages/mantine/tsconfig.json | 2 +- packages/mantine/vite.config.ts | 166 +- packages/react/package.json | 23 +- packages/react/src/blocks/Video/block.tsx | 5 +- .../react/src/components/Comments/Comment.tsx | 5 +- .../components/Comments/FloatingComposer.tsx | 5 +- .../react/src/components/Comments/Thread.tsx | 5 +- .../DefaultButtons/FileCaptionButton.tsx | 7 +- .../DefaultButtons/FileRenameButton.tsx | 7 +- ...entalMobileFormattingToolbarController.tsx | 20 +- .../components/Popovers/GenericPopover.tsx | 3 +- .../SuggestionMenu/SuggestionMenu.test.tsx | 2 +- .../TableHandles/TableHandlesController.tsx | 4 +- .../react/src/editor/BlockNoteDefaultUI.tsx | 9 +- packages/react/src/icons.ts | 2 +- packages/react/src/schema/ReactBlockSpec.tsx | 8 +- packages/react/vite.config.ts | 164 +- packages/react/vitestSetup.ts | 2 +- packages/server-util/package.json | 25 +- .../src/context/ServerBlockNoteEditor.test.ts | 2 +- .../src/context/react/ReactServer.test.tsx | 2 +- packages/server-util/vite.config.ts | 130 +- packages/server-util/vitestSetup.ts | 2 +- packages/shadcn/package.json | 22 +- packages/shadcn/src/comments/Comment.tsx | 2 +- packages/shadcn/tsconfig.json | 2 +- packages/shadcn/vite.config.ts | 150 +- packages/xl-ai-server/package.json | 15 +- packages/xl-ai-server/tsconfig.json | 1 + packages/xl-ai-server/vite.config.ts | 126 +- packages/xl-ai/package.json | 28 +- .../xl-ai/scripts/rename-msw-snapshots.mjs | 20 +- .../columnContainerDocumentState.test.ts | 2 +- .../formats/html-blocks/htmlBlocks.test.ts | 2 +- .../html-blocks/tools/getPartialHTML.test.ts | 2 +- .../api/formats/json/errorHandling.test.ts | 9 +- .../xl-ai/src/api/formats/json/json.test.ts | 2 +- .../api/formats/json/tools/jsontools.test.ts | 2 +- .../markdown-blocks/markdownBlocks.test.ts | 2 +- .../src/api/formats/tests/sharedTestCases.ts | 5 +- .../src/api/formats/tests/snapshotPath.ts | 4 +- .../tests/validateTestEnvironment.test.ts | 2 +- .../src/api/schema/schemaToJSONSchema.test.ts | 2 +- packages/xl-ai/src/prosemirror/agent.test.ts | 2 +- .../xl-ai/src/prosemirror/changeset.test.ts | 2 +- .../src/prosemirror/fragmentUtil.test.ts | 2 +- .../xl-ai/src/prosemirror/rebaseTool.test.ts | 2 +- .../filterNewOrUpdatedOperations.test.ts | 2 +- .../streamTool/filterValidOperations.test.ts | 2 +- .../xl-ai/src/streamTool/preprocess.test.ts | 2 +- .../streamTool/toValidatedOperations.test.ts | 2 +- .../clientside/ClientSideTransport.ts | 6 +- .../vercelAiSdk/util/appendableStream.test.ts | 2 +- .../vercelAiSdk/util/chatHandlers.test.ts | 2 +- .../src/testUtil/suggestChangesTestUtil.ts | 2 +- packages/xl-ai/tsconfig.json | 4 + packages/xl-ai/vite.config.ts | 181 +- packages/xl-ai/vitestSetup.ts | 2 +- packages/xl-docx-exporter/package.json | 28 +- .../src/docx/docxExporter.test.ts | 6 +- packages/xl-docx-exporter/src/vite-env.d.ts | 2 +- packages/xl-docx-exporter/tsconfig.json | 5 +- packages/xl-docx-exporter/vite.config.ts | 155 +- packages/xl-docx-exporter/vitestSetup.ts | 2 +- packages/xl-email-exporter/package.json | 24 +- .../react-email/reactEmailExporter.test.tsx | 2 +- packages/xl-email-exporter/src/vite-env.d.ts | 2 +- packages/xl-email-exporter/tsconfig.json | 3 +- packages/xl-email-exporter/vite.config.ts | 150 +- packages/xl-email-exporter/viteSetup.ts | 10 - packages/xl-email-exporter/vitestSetup.ts | 2 +- packages/xl-multi-column/package.json | 26 +- .../src/test/commands/backspace.test.ts | 2 +- .../src/test/commands/insertBlocks.test.ts | 2 +- .../src/test/commands/moveBlocks.test.ts | 2 +- .../src/test/commands/removeBlocks.test.ts | 2 +- .../src/test/commands/replaceBlocks.test.ts | 2 +- .../src/test/commands/selection.test.ts | 2 +- .../test/commands/textCursorPosition.test.ts | 2 +- .../src/test/commands/updateBlock.test.ts | 2 +- .../test/commands/util/fixColumnLists.test.ts | 2 +- .../test/conversions/htmlConversion.test.ts | 2 +- .../test/conversions/nodeConversion.test.ts | 2 +- .../xl-multi-column/src/test/setupTestEnv.ts | 2 +- packages/xl-multi-column/src/vite-env.d.ts | 2 +- packages/xl-multi-column/vite.config.ts | 153 +- packages/xl-multi-column/vitestSetup.ts | 2 +- packages/xl-odt-exporter/package.json | 27 +- .../src/odt/odtExporter.test.ts | 2 +- packages/xl-odt-exporter/src/vite-env.d.ts | 2 +- packages/xl-odt-exporter/tsconfig.json | 6 +- packages/xl-odt-exporter/vite.config.ts | 144 +- packages/xl-odt-exporter/vitestSetup.ts | 2 +- packages/xl-pdf-exporter/package.json | 26 +- .../src/pdf/pdfExporter.test.tsx | 2 +- packages/xl-pdf-exporter/src/vite-env.d.ts | 2 +- packages/xl-pdf-exporter/tsconfig.json | 5 +- packages/xl-pdf-exporter/vite.config.ts | 171 +- packages/xl-pdf-exporter/vitestSetup.ts | 2 +- playground/package.json | 18 +- playground/serve.json | 3 - playground/src/examples.gen.tsx | 3538 +++-- playground/src/vite-env.d.ts | 2 +- playground/tsconfig.json | 1 - playground/vite.config.ts | 129 +- pnpm-lock.yaml | 11096 ++++++---------- pnpm-workspace.yaml | 14 +- shared/package.json | 9 +- shared/tsconfig.json | 3 +- shared/vite-env.d.ts | 2 +- shared/vite.config.ts | 15 + .../app/api/server-util/route.tsx | 7 +- tests/nextjs-test-app/app/layout.tsx | 6 +- tests/nextjs-test-app/tsconfig.json | 10 +- tests/package.json | 17 +- tests/playwright/index.html | 2 +- tests/src/end-to-end/ai/ai-selection.test.ts | 108 +- .../src/end-to-end/comments/comments.test.ts | 2 +- .../unit/core/clipboard/copy/runTests.test.ts | 2 +- .../core/clipboard/copyPaste/runTests.test.ts | 2 +- .../copyPasteEquality/runTests.test.ts | 2 +- .../core/clipboard/paste/runTests.test.ts | 2 +- tests/src/unit/core/createTestEditor.ts | 2 +- .../formatConversion/export/runTests.test.ts | 2 +- .../exportParseEqualityTestInstances.ts | 3 +- .../exportParseEquality/runTests.test.ts | 2 +- .../formatConversion/parse/runTests.test.ts | 2 +- tests/src/unit/core/schema/runTests.test.ts | 2 +- .../selection/getSelection/runTests.test.ts | 2 +- .../incrementSelection/runTests.test.ts | 2 +- .../textCursorPosition/runTests.test.ts | 2 +- .../src/unit/core/typeGuards/runTests.test.ts | 2 +- tests/src/unit/nextjs/serverUtil.test.ts | 16 +- .../react/BlockNoteViewRapidRemount.test.tsx | 2 +- .../unit/react/BlockNoteViewRemount.test.tsx | 2 +- .../react/BlockNoteViewRemountHover.test.tsx | 2 +- .../formatConversion/export/runTests.test.ts | 2 +- .../exportParseEquality/runTests.test.ts | 2 +- tests/src/unit/react/setupTestEditor.tsx | 2 +- .../clipboard/copy/copyTestExecutors.ts | 2 +- .../copyPaste/copyPasteTestExecutors.ts | 2 +- .../copyPasteEqualityTestExecutors.ts | 2 +- .../clipboard/paste/pasteTestExecutors.ts | 2 +- .../export/exportTestExecutors.ts | 7 +- .../exportParseEqualityTestExecutors.ts | 6 +- .../parse/parseTestExecutors.ts | 2 +- .../getSelection/getSelectionTestExecutors.ts | 2 +- .../incrementSelectionTestExecutors.ts | 2 +- .../textCursorPositionTestExecutors.ts | 2 +- tests/vite.config.ts | 65 +- tests/vitestSetup.ts | 2 +- vite.config.ts | 142 + vitest.workspace.ts | 16 - 674 files changed, 10343 insertions(+), 13374 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 .node-version delete mode 100644 .nvmrc delete mode 100644 .prettierrc create mode 100755 .vite-hooks/pre-commit create mode 100644 AGENTS.md delete mode 100644 docs/eslint.config.mjs delete mode 100644 examples/.eslintrc.js delete mode 100644 nx.json create mode 100644 packages/dev-scripts/vite.config.ts delete mode 100644 packages/xl-email-exporter/viteSetup.ts delete mode 100644 playground/serve.json create mode 100644 shared/vite.config.ts create mode 100644 vite.config.ts delete mode 100644 vitest.workspace.ts diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index e9511bbf61..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "root": true, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "react-app", - "react-app/jest" - ], - "parser": "@typescript-eslint/parser", - "plugins": ["import", "@typescript-eslint"], - "settings": { - "import/extensions": [".ts", ".cts", ".mts", ".tsx", ".js", ".jsx"], - "import/external-module-folders": ["node_modules", "node_modules/@types"], - "import/parsers": { - "@typescript-eslint/parser": [".ts", ".cts", ".mts", ".tsx"] - }, - "import/resolver": { - "node": { - "extensions": [".ts", ".cts", ".mts", ".tsx", ".js", ".jsx"] - } - } - }, - "ignorePatterns": ["**/ui/*"], - "rules": { - "no-console": "error", - "curly": 1, - "import/extensions": ["error", "always", { "ignorePackages": true }], - "import/no-extraneous-dependencies": [ - "error", - { - "devDependencies": true, - "peerDependencies": true, - "optionalDependencies": false, - "bundledDependencies": false - } - ], - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/ban-ts-comment": "off", - "import/no-cycle": "error" - } -} diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f258f05126..d431145bc6 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,4 +3,4 @@ blank_issues_enabled: false contact_links: - name: Share an idea or suggest an enhancement url: https://github.com/TypeCellOS/BlockNote/discussions/categories/ideas-enhancements - about: Share feature ideas, enhancement suggestions, or other ideas for the BlockNote project. \ No newline at end of file + about: Share feature ideas, enhancement suggestions, or other ideas for the BlockNote project. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fef3e24484..f743c98afc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,9 +11,6 @@ permissions: env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN: ${{ secrets.NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN }} - NX_SELF_HOSTED_REMOTE_CACHE_SERVER: ${{ secrets.NX_SELF_HOSTED_REMOTE_CACHE_SERVER }} - pnpm_config_store_dir: ./node_modules/.pnpm-store jobs: build: @@ -21,46 +18,31 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 60 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 100 persist-credentials: false - - name: Install pnpm - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 - - - uses: nrwl/nx-set-shas@afb73a62d26e41464e9254689e1fd6122ee683c1 # v5 - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 - with: - cache: "pnpm" - cache-dependency-path: "**/pnpm-lock.yaml" - node-version-file: ".nvmrc" - - - name: Cache NX - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + - uses: voidzero-dev/setup-vp@2dec1e33f4ab2c6d5bce1b0c4607961bb1a3f7a1 # v1 with: - path: .nx/cache - key: nx-${{ env.NX_BRANCH }}-${{ env.NX_RUN_GROUP }}-${{ github.sha }} - restore-keys: | - nx-${{ env.NX_BRANCH }}-${{ env.NX_RUN_GROUP }}- - nx-${{ env.NX_BRANCH }}- - nx- + node-version-file: ".node-version" + cache: true - name: Install Dependencies - run: pnpm install + run: vp install - name: Lint packages - run: pnpm run lint + run: vp lint - name: Build packages - run: pnpm run build + run: vp run -r build - name: Run unit tests - run: pnpm run test + run: vp run -r test - name: Run Next.js integration test (production build) - run: NEXTJS_TEST_MODE=build npx vitest run tests/src/unit/nextjs/serverUtil.test.ts + run: NEXTJS_TEST_MODE=build vp test run src/unit/nextjs/serverUtil.test.ts + working-directory: tests - name: Upload webpack stats artifact (editor) uses: relative-ci/agent-upload-artifact-action@a2b5741b4f7e6a989c84ec1a3059696b23c152e5 # v2 @@ -70,44 +52,28 @@ jobs: - name: Soft release id: soft-release - run: pnpx pkg-pr-new publish './packages/*' # TODO disabled only for AI branch--compact + run: vp dlx pkg-pr-new publish './packages/*' # TODO disabled only for AI branch--compact playwright-build: name: "Playwright Build" runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 100 persist-credentials: false - - name: Install pnpm - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 - - - uses: nrwl/nx-set-shas@afb73a62d26e41464e9254689e1fd6122ee683c1 # v5 - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 - with: - cache: "pnpm" - cache-dependency-path: "**/pnpm-lock.yaml" - node-version-file: ".nvmrc" - - - name: Cache NX - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + - uses: voidzero-dev/setup-vp@2dec1e33f4ab2c6d5bce1b0c4607961bb1a3f7a1 # v1 with: - path: .nx/cache - key: nx-playwright-${{ env.NX_BRANCH }}-${{ env.NX_RUN_GROUP }}-${{ github.sha }} - restore-keys: | - nx-playwright-${{ env.NX_BRANCH }}-${{ env.NX_RUN_GROUP }}- - nx-playwright-${{ env.NX_BRANCH }}- - nx- + node-version-file: ".node-version" + cache: true - name: Install dependencies - run: pnpm install + run: vp install - name: Build packages - run: pnpm run build + run: vp run -r build - name: Upload build artifacts uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 @@ -132,19 +98,15 @@ jobs: shardIndex: [1, 2] shardTotal: [2] steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 100 persist-credentials: false - - name: Install pnpm - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + - uses: voidzero-dev/setup-vp@2dec1e33f4ab2c6d5bce1b0c4607961bb1a3f7a1 # v1 with: - cache: "pnpm" - cache-dependency-path: "**/pnpm-lock.yaml" - node-version-file: ".nvmrc" + node-version-file: ".node-version" + cache: true - name: Download build artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 @@ -152,11 +114,13 @@ jobs: name: playwright-build - name: Install dependencies - run: pnpm install + run: vp install - name: Run server and Playwright tests run: | - HOME=/root PLAYWRIGHT_CONFIG="--project ${{ matrix.browser }} --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}" pnpm run e2e + HOME=/root vp exec concurrently --success=first -r --kill-others \ + "vp run --filter @blocknote/example-editor preview" \ + "wait-on http://localhost:3000 && cd tests && vp exec playwright test --project ${{ matrix.browser }} --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}" - name: Upload blob report uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 @@ -180,21 +144,17 @@ jobs: needs: playwright runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false - - name: Install pnpm - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + - uses: voidzero-dev/setup-vp@2dec1e33f4ab2c6d5bce1b0c4607961bb1a3f7a1 # v1 with: - cache: "pnpm" - cache-dependency-path: "**/pnpm-lock.yaml" - node-version-file: ".nvmrc" + node-version-file: ".node-version" + cache: true - name: Install dependencies - run: pnpm install + run: vp install - name: Download blob reports uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 @@ -204,7 +164,7 @@ jobs: merge-multiple: true - name: Merge reports - run: npx playwright merge-reports --reporter html ./all-blob-reports + run: vp exec playwright merge-reports --reporter html ./all-blob-reports working-directory: tests - name: Upload merged HTML report diff --git a/.github/workflows/fresh-install-tests.yml b/.github/workflows/fresh-install-tests.yml index d5698a1fbc..a1b441678d 100644 --- a/.github/workflows/fresh-install-tests.yml +++ b/.github/workflows/fresh-install-tests.yml @@ -20,7 +20,6 @@ permissions: env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - pnpm_config_store_dir: ./node_modules/.pnpm-store jobs: fresh-install-unit-tests: @@ -30,23 +29,20 @@ jobs: steps: - id: checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false - - id: install_pnpm - name: Install pnpm - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 - - - id: setup_node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + - id: setup_vp + uses: voidzero-dev/setup-vp@2dec1e33f4ab2c6d5bce1b0c4607961bb1a3f7a1 # v1 with: - node-version-file: ".nvmrc" - # Intentionally no pnpm cache — we want fresh prod dep resolution + node-version-file: ".node-version" + # Intentionally no install cache — we want fresh prod dep resolution. + cache: false - id: install_dependencies name: Install dependencies - run: pnpm install + run: vp install - id: update_prod_deps name: Update prod deps of published packages @@ -55,6 +51,8 @@ jobs: # ranges. This simulates what a user gets when running # `npm install @blocknote/react` in a fresh project. # DevDependencies are left at their lockfile versions. + # NB: this uses pnpm directly because vp doesn't expose a `--prod`-only + # update flow; setup-vp installs pnpm on PATH so this still works. run: | FILTERS=$(node -e " const fs = require('fs'); @@ -84,15 +82,11 @@ jobs: - id: build_packages name: Build packages - run: pnpm run build - env: - NX_SKIP_NX_CACHE: "true" + run: vp run -r build - id: run_unit_tests name: Run unit tests - run: pnpm run test - env: - NX_SKIP_NX_CACHE: "true" + run: vp run -r test - name: Notify Slack on workflow failure if: ${{ failure() }} @@ -105,8 +99,7 @@ jobs: RUN_ATTEMPT: ${{ github.run_attempt }} BRANCH: ${{ github.ref_name }} STEPS_CHECKOUT_OUTCOME: ${{ steps.checkout.outcome }} - STEPS_INSTALL_PNPM_OUTCOME: ${{ steps.install_pnpm.outcome }} - STEPS_SETUP_NODE_OUTCOME: ${{ steps.setup_node.outcome }} + STEPS_SETUP_VP_OUTCOME: ${{ steps.setup_vp.outcome }} STEPS_INSTALL_DEPENDENCIES_OUTCOME: ${{ steps.install_dependencies.outcome }} STEPS_UPDATE_PROD_DEPS_OUTCOME: ${{ steps.update_prod_deps.outcome }} STEPS_DEDUPE_DEPS_OUTCOME: ${{ steps.dedupe_deps.outcome }} @@ -121,10 +114,8 @@ jobs: failed_step="Unknown step" if [ "${STEPS_CHECKOUT_OUTCOME}" = "failure" ]; then failed_step="Checkout repository" - elif [ "${STEPS_INSTALL_PNPM_OUTCOME}" = "failure" ]; then - failed_step="Install pnpm" - elif [ "${STEPS_SETUP_NODE_OUTCOME}" = "failure" ]; then - failed_step="Setup Node.js" + elif [ "${STEPS_SETUP_VP_OUTCOME}" = "failure" ]; then + failed_step="Setup Vite+" elif [ "${STEPS_INSTALL_DEPENDENCIES_OUTCOME}" = "failure" ]; then failed_step="Install dependencies" elif [ "${STEPS_UPDATE_PROD_DEPS_OUTCOME}" = "failure" ]; then diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 12bda34238..b39deb9957 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -13,65 +13,21 @@ on: required: true type: string -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN: ${{ secrets.NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN }} - NX_SELF_HOSTED_REMOTE_CACHE_SERVER: ${{ secrets.NX_SELF_HOSTED_REMOTE_CACHE_SERVER }} - pnpm_config_store_dir: ./node_modules/.pnpm-store +permissions: {} jobs: publish: name: Publish runs-on: ubuntu-latest - permissions: - contents: write - id-token: write # needed for provenance data generation - attestations: write - timeout-minutes: 10 + timeout-minutes: 5 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - ref: ${{ inputs.version }} - fetch-depth: 100 - persist-credentials: false - - name: Display version being published + - name: Publish disabled + # NX has been removed (it was driving `nx release publish`) and the + # replacement release tool is not yet in place. This workflow is + # intentionally a no-op so a stray tag push doesn't silently succeed + # without actually publishing anything. Once a release tool is wired + # up, restore the publish steps and remove this guard. run: | - echo "Publishing version: ${INPUTS_VERSION}" - env: - INPUTS_VERSION: ${{ inputs.version }} - - - run: jq '.packageManager' package.json | tr -d '"pnpm@' - id: package-manager-version - - - name: Install pnpm - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 - with: - version: ${{ steps.package-manager-version.outputs.stdout }} - - - uses: nrwl/nx-set-shas@afb73a62d26e41464e9254689e1fd6122ee683c1 # v5 - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 # zizmor: ignore[cache-poisoning] - with: - # No pnpm cache -- correctness over speed for publish workflows - node-version-file: ".nvmrc" - - - name: Cache NX - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 - with: - path: .nx/cache - key: nx-${{ env.NX_BRANCH }}-${{ env.NX_RUN_GROUP }}-${{ github.sha }} - restore-keys: | - nx-${{ env.NX_BRANCH }}-${{ env.NX_RUN_GROUP }}- - nx-${{ env.NX_BRANCH }}- - nx- - lookup-only: true - - - name: Install Dependencies & Build - run: pnpm install && pnpm build - - - name: Print Environment Info - run: pnpm exec nx report - - - name: Publish packages - # Ensure npm 11.5.1 or later for trusted publishing - run: npm install -g npm@latest && pnpm exec nx release publish --access public + echo "::error::Publish workflow is disabled — release tooling is being replaced." + echo "::error::Re-enable this workflow once a release tool is wired up." + exit 1 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 1111b104a8..0b9ea34841 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -18,7 +18,7 @@ jobs: actions: read steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false diff --git a/.node-version b/.node-version new file mode 100644 index 0000000000..5bf4400f22 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +24.15.0 diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index c5ddcef4e7..0000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v22.14.0 \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 0f4e5b7d67..0000000000 --- a/.prettierrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/prettierrc", - "semi": true, - "singleQuote": false, - "tabWidth": 2, - "printWidth": 80, - "trailingComma": "all", - "bracketSpacing": true, - "arrowParens": "always", - "endOfLine": "lf", - "plugins": ["prettier-plugin-tailwindcss"] -} diff --git a/.vite-hooks/pre-commit b/.vite-hooks/pre-commit new file mode 100755 index 0000000000..85fb65b4fc --- /dev/null +++ b/.vite-hooks/pre-commit @@ -0,0 +1 @@ +vp staged diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..362b82a43a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,16 @@ + + +# Using Vite+, the Unified Toolchain for the Web + +This project is using Vite+, a unified toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt, and Vite Task. Vite+ wraps runtime management, package management, and frontend tooling in a single global CLI called `vp`. Vite+ is distinct from Vite, and it invokes Vite through `vp dev` and `vp build`. Run `vp help` to print a list of commands and `vp --help` for information about a specific command. + +Docs are local at `node_modules/vite-plus/docs` or online at https://viteplus.dev/guide/. + +## Review Checklist + +- [ ] Run `vp install` after pulling remote changes and before getting started. +- [ ] Run `vp check` and `vp test` to format, lint, type check and test changes. +- [ ] Check if there are `vite.config.ts` tasks or `package.json` scripts necessary for validation, run via `vp run