From 95e1f24cd7e1611f64f6fcdcd70bcc8afeda5f44 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Mon, 3 Aug 2026 18:40:34 +0200 Subject: [PATCH 1/4] chore: upgrade tiptap to 3.29.2 Bumps every `@tiptap/*` range from `^3.13.0` (resolving to 3.22.4) to `^3.29.2`, including the `pnpm-workspace.yaml` overrides that actually pin `@tiptap/core` and `@tiptap/pm`. Also bumps our direct `prosemirror-*` dependencies to match the ranges `@tiptap/pm@3.29.2` declares. Without this, `prosemirror-model` and `prosemirror-view` each resolved to two copies, which broke type-checking across the packages that import them directly. --- docs/package.json | 2 +- .../01-tiptap-arrow-conversion/package.json | 2 +- package.json | 4 +- packages/core/package.json | 26 +- packages/react/package.json | 6 +- packages/server-util/package.json | 2 +- packages/xl-ai/package.json | 12 +- packages/xl-multi-column/package.json | 6 +- pnpm-lock.yaml | 417 +++++++++--------- pnpm-workspace.yaml | 4 +- tests/package.json | 2 +- 11 files changed, 246 insertions(+), 237 deletions(-) diff --git a/docs/package.json b/docs/package.json index 24f5f3e410..18b6792b6f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -55,7 +55,7 @@ "@shikijs/langs-precompiled": "^4", "@shikijs/themes": "^4", "@shikijs/types": "^4", - "@tiptap/core": "^3.13.0", + "@tiptap/core": "^3.29.2", "@uppy/core": "^3.13.1", "@uppy/dashboard": "^3.9.1", "@uppy/drag-drop": "^3.1.1", diff --git a/examples/08-extensions/01-tiptap-arrow-conversion/package.json b/examples/08-extensions/01-tiptap-arrow-conversion/package.json index 84bd386a13..e2e2ce414d 100644 --- a/examples/08-extensions/01-tiptap-arrow-conversion/package.json +++ b/examples/08-extensions/01-tiptap-arrow-conversion/package.json @@ -20,7 +20,7 @@ "@mantine/hooks": "^9.0.2", "react": "^19.2.3", "react-dom": "^19.2.3", - "@tiptap/core": "^3.13.0" + "@tiptap/core": "^3.29.2" }, "devDependencies": { "@types/react": "^19.2.3", diff --git a/package.json b/package.json index 2012524d6a..c6a2b830cd 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,8 @@ "@ai-sdk/react": "3.0.5", "@ai-sdk/gateway": "3.0.4", "@headlessui/react": "^2.2.4", - "@tiptap/core": "^3.0.0", - "@tiptap/pm": "^3.0.0" + "@tiptap/core": "^3.29.2", + "@tiptap/pm": "^3.29.2" }, "workspaces": [ "packages/*", diff --git a/packages/core/package.json b/packages/core/package.json index 80535a0cb8..11e9d02eef 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -98,24 +98,24 @@ "@handlewithcare/prosemirror-inputrules": "^0.1.4", "@shikijs/types": "^4", "@tanstack/store": "^0.7.7", - "@tiptap/core": "^3.13.0", - "@tiptap/extension-bold": "^3.13.0", - "@tiptap/extension-code": "^3.13.0", - "@tiptap/extension-italic": "^3.13.0", - "@tiptap/extension-strike": "^3.13.0", - "@tiptap/extension-text": "^3.13.0", - "@tiptap/extension-underline": "^3.13.0", - "@tiptap/extensions": "^3.13.0", - "@tiptap/pm": "^3.13.0", + "@tiptap/core": "^3.29.2", + "@tiptap/extension-bold": "^3.29.2", + "@tiptap/extension-code": "^3.29.2", + "@tiptap/extension-italic": "^3.29.2", + "@tiptap/extension-strike": "^3.29.2", + "@tiptap/extension-text": "^3.29.2", + "@tiptap/extension-underline": "^3.29.2", + "@tiptap/extensions": "^3.29.2", + "@tiptap/pm": "^3.29.2", "emoji-mart": "^5.6.0", "fast-deep-equal": "^3.1.3", "lib0": "1.0.0-rc.22", "prosemirror-highlight": "^0.15.1", - "prosemirror-model": "^1.25.4", + "prosemirror-model": "^1.25.11", "prosemirror-state": "^1.4.4", - "prosemirror-tables": "^1.8.3", - "prosemirror-transform": "^1.11.0", - "prosemirror-view": "^1.41.4" + "prosemirror-tables": "^1.8.5", + "prosemirror-transform": "^1.12.0", + "prosemirror-view": "^1.41.9" }, "devDependencies": { "jsdom": "^29.0.2", diff --git a/packages/react/package.json b/packages/react/package.json index da4c0a6e69..7ad41c87db 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -61,9 +61,9 @@ "@emoji-mart/data": "^1.2.1", "@floating-ui/react": "^0.27.18", "@tanstack/react-store": "0.7.7", - "@tiptap/core": "^3.13.0", - "@tiptap/pm": "^3.13.0", - "@tiptap/react": "^3.13.0", + "@tiptap/core": "^3.29.2", + "@tiptap/pm": "^3.29.2", + "@tiptap/react": "^3.29.2", "emoji-mart": "^5.6.0", "fast-deep-equal": "^3.1.3", "use-sync-external-store": "1.6.0" diff --git a/packages/server-util/package.json b/packages/server-util/package.json index c7e60dd042..bd6fe5a23a 100644 --- a/packages/server-util/package.json +++ b/packages/server-util/package.json @@ -58,7 +58,7 @@ "dependencies": { "@blocknote/core": "workspace:^", "@blocknote/react": "workspace:^", - "@tiptap/pm": "^3.13.0", + "@tiptap/pm": "^3.29.2", "jsdom": "^25.0.1", "yjs": "^13.6.27" }, diff --git a/packages/xl-ai/package.json b/packages/xl-ai/package.json index 543cda210d..f9ed498783 100644 --- a/packages/xl-ai/package.json +++ b/packages/xl-ai/package.json @@ -74,16 +74,16 @@ "@blocknote/react": "workspace:^", "@floating-ui/react": "^0.27.18", "@handlewithcare/prosemirror-suggest-changes": "^0.1.8", - "@tiptap/core": "^3.13.0", + "@tiptap/core": "^3.29.2", "ai": "^6.0.5", "lodash.isequal": "^4.5.0", "lodash.merge": "^4.6.2", - "prosemirror-changeset": "^2.3.1", - "prosemirror-model": "^1.25.4", + "prosemirror-changeset": "^2.4.1", + "prosemirror-model": "^1.25.11", "prosemirror-state": "^1.4.4", - "prosemirror-tables": "^1.8.3", - "prosemirror-transform": "^1.11.0", - "prosemirror-view": "^1.41.4" + "prosemirror-tables": "^1.8.5", + "prosemirror-transform": "^1.12.0", + "prosemirror-view": "^1.41.9" }, "devDependencies": { "@blocknote/shared": "workspace:^", diff --git a/packages/xl-multi-column/package.json b/packages/xl-multi-column/package.json index 008ce36e0a..bf7e343256 100644 --- a/packages/xl-multi-column/package.json +++ b/packages/xl-multi-column/package.json @@ -52,10 +52,10 @@ "dependencies": { "@blocknote/core": "workspace:^", "@blocknote/react": "workspace:^", - "@tiptap/core": "^3.13.0", - "prosemirror-model": "^1.25.4", + "@tiptap/core": "^3.29.2", + "prosemirror-model": "^1.25.11", "prosemirror-state": "^1.4.4", - "prosemirror-view": "^1.41.4" + "prosemirror-view": "^1.41.9" }, "devDependencies": { "@blocknote/shared": "workspace:^", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 090c217f93..1a530aa87b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ catalogs: overrides: '@headlessui/react': ^2.2.4 - '@tiptap/core': ^3.0.0 - '@tiptap/pm': ^3.0.0 + '@tiptap/core': ^3.29.2 + '@tiptap/pm': ^3.29.2 vitest: 4.1.7 '@vitest/runner': 4.1.7 '@y/y': 14.0.0-rc.23 @@ -128,10 +128,10 @@ importers: version: 3.19.5(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react@19.2.5) '@liveblocks/react-blocknote': specifier: ^3.19.5 - version: 3.19.5(@blocknote/core@packages+core)(@blocknote/react@packages+react)(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) + version: 3.19.5(@blocknote/core@packages+core)(@blocknote/react@packages+react)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) '@liveblocks/react-tiptap': specifier: ^3.19.5 - version: 3.19.5(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) + version: 3.19.5(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) '@liveblocks/react-ui': specifier: ^3.19.5 version: 3.19.5(@types/json-schema@7.0.15)(@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) @@ -187,8 +187,8 @@ importers: specifier: ^4 version: 4.0.2 '@tiptap/core': - specifier: ^3.0.0 - version: 3.22.4(@tiptap/pm@3.22.4) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/pm@3.29.2) '@uppy/core': specifier: ^3.13.1 version: 3.13.1 @@ -230,7 +230,7 @@ importers: version: 0.6.4(react@19.2.5)(yjs@13.6.30) '@y/prosemirror': specifier: 2.0.0-6 - version: 2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) + version: 2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2) '@y/protocols': specifier: ^1.0.6-rc.1 version: 1.0.6-rc.1(@y/y@14.0.0-rc.23) @@ -3639,10 +3639,10 @@ importers: version: 3.19.5(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react@19.2.5) '@liveblocks/react-blocknote': specifier: ^3.19.5 - version: 3.19.5(@blocknote/core@packages+core)(@blocknote/react@packages+react)(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) + version: 3.19.5(@blocknote/core@packages+core)(@blocknote/react@packages+react)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) '@liveblocks/react-tiptap': specifier: ^3.19.5 - version: 3.19.5(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) + version: 3.19.5(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) '@liveblocks/react-ui': specifier: ^3.19.5 version: 3.19.5(@types/json-schema@7.0.15)(@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) @@ -4028,7 +4028,7 @@ importers: version: 9.1.1(react@19.2.5) '@y/prosemirror': specifier: 2.0.0-6 - version: 2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) + version: 2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2) '@y/protocols': specifier: ^1.0.6-rc.1 version: 1.0.6-rc.1(@y/y@14.0.0-rc.23) @@ -4190,7 +4190,7 @@ importers: version: 9.1.1(react@19.2.5) '@y/prosemirror': specifier: 2.0.0-6 - version: 2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) + version: 2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2) '@y/protocols': specifier: ^1.0.6-rc.1 version: 1.0.6-rc.1(@y/y@14.0.0-rc.23) @@ -4302,8 +4302,8 @@ importers: specifier: ^9.0.2 version: 9.1.1(react@19.2.5) '@tiptap/core': - specifier: ^3.0.0 - version: 3.22.4(@tiptap/pm@3.22.4) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/pm@3.29.2) react: specifier: ^19.2.3 version: 19.2.5 @@ -4349,7 +4349,7 @@ importers: version: 9.1.1(react@19.2.5) '@y/prosemirror': specifier: 2.0.0-6 - version: 2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) + version: 2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2) '@y/y': specifier: 14.0.0-rc.23 version: 14.0.0-rc.23 @@ -4948,7 +4948,7 @@ importers: version: 1.2.1 '@handlewithcare/prosemirror-inputrules': specifier: ^0.1.4 - version: 0.1.4(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) + version: 0.1.4(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2) '@shikijs/types': specifier: ^4 version: 4.0.2 @@ -4956,35 +4956,35 @@ importers: specifier: ^0.7.7 version: 0.7.7 '@tiptap/core': - specifier: ^3.0.0 - version: 3.22.4(@tiptap/pm@3.22.4) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/pm@3.29.2) '@tiptap/extension-bold': - specifier: ^3.13.0 - version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4)) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2)) '@tiptap/extension-code': - specifier: ^3.13.0 - version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4)) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2)) '@tiptap/extension-italic': - specifier: ^3.13.0 - version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4)) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2)) '@tiptap/extension-strike': - specifier: ^3.13.0 - version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4)) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2)) '@tiptap/extension-text': - specifier: ^3.13.0 - version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4)) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2)) '@tiptap/extension-underline': - specifier: ^3.13.0 - version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4)) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2)) '@tiptap/extensions': - specifier: ^3.13.0 - version: 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2) '@tiptap/pm': - specifier: ^3.0.0 - version: 3.22.4 + specifier: ^3.29.2 + version: 3.29.2 '@y/prosemirror': specifier: 2.0.0-6 - version: 2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) + version: 2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2) '@y/protocols': specifier: ^1.0.6-rc.1 version: 1.0.6-rc.1(@y/y@14.0.0-rc.23) @@ -5002,22 +5002,22 @@ importers: version: 1.0.0-rc.22 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) + version: 0.15.1(@shikijs/types@4.0.2)(@types/hast@3.0.4)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-transform@1.12.0)(prosemirror-view@1.42.2) prosemirror-model: - specifier: ^1.25.4 - version: 1.25.4 + specifier: ^1.25.11 + version: 1.25.11 prosemirror-state: specifier: ^1.4.4 version: 1.4.4 prosemirror-tables: - specifier: ^1.8.3 + specifier: ^1.8.5 version: 1.8.5 prosemirror-transform: - specifier: ^1.11.0 + specifier: ^1.12.0 version: 1.12.0 prosemirror-view: - specifier: ^1.41.4 - version: 1.41.8 + specifier: ^1.41.9 + version: 1.42.2 devDependencies: jsdom: specifier: ^29.0.2 @@ -5036,7 +5036,7 @@ importers: version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) 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) + version: 1.3.7(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(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) @@ -5141,14 +5141,14 @@ importers: specifier: 0.7.7 version: 0.7.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tiptap/core': - specifier: ^3.0.0 - version: 3.22.4(@tiptap/pm@3.22.4) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/pm@3.29.2) '@tiptap/pm': - specifier: ^3.0.0 - version: 3.22.4 + specifier: ^3.29.2 + version: 3.29.2 '@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) + specifier: ^3.29.2 + version: 3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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) emoji-mart: specifier: ^5.6.0 version: 5.6.0 @@ -5212,8 +5212,8 @@ importers: specifier: workspace:^ version: link:../react '@tiptap/pm': - specifier: ^3.0.0 - version: 3.22.4 + specifier: ^3.29.2 + version: 3.29.2 jsdom: specifier: ^25.0.1 version: 25.0.1(canvas@2.11.2) @@ -5250,7 +5250,7 @@ importers: version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) 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) + version: 1.3.7(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(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) @@ -5365,10 +5365,10 @@ importers: version: 0.27.19(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@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) + version: 0.1.8(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-transform@1.12.0)(prosemirror-view@1.42.2) '@tiptap/core': - specifier: ^3.0.0 - version: 3.22.4(@tiptap/pm@3.22.4) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/pm@3.29.2) ai: specifier: ^6.0.5 version: 6.0.5(zod@4.3.6) @@ -5379,23 +5379,23 @@ importers: specifier: ^4.6.2 version: 4.6.2 prosemirror-changeset: - specifier: ^2.3.1 + specifier: ^2.4.1 version: 2.4.1 prosemirror-model: - specifier: ^1.25.4 - version: 1.25.4 + specifier: ^1.25.11 + version: 1.25.11 prosemirror-state: specifier: ^1.4.4 version: 1.4.4 prosemirror-tables: - specifier: ^1.8.3 + specifier: ^1.8.5 version: 1.8.5 prosemirror-transform: - specifier: ^1.11.0 + specifier: ^1.12.0 version: 1.12.0 prosemirror-view: - specifier: ^1.41.4 - version: 1.41.8 + specifier: ^1.41.9 + version: 1.42.2 react: specifier: ^18.0 || ^19.0 || >= 19.0.0-rc version: 19.2.5 @@ -5659,17 +5659,17 @@ importers: specifier: workspace:^ version: link:../react '@tiptap/core': - specifier: ^3.0.0 - version: 3.22.4(@tiptap/pm@3.22.4) + specifier: ^3.29.2 + version: 3.29.2(@tiptap/pm@3.29.2) prosemirror-model: - specifier: ^1.25.4 - version: 1.25.4 + specifier: ^1.25.11 + version: 1.25.11 prosemirror-state: specifier: ^1.4.4 version: 1.4.4 prosemirror-view: - specifier: ^1.41.4 - version: 1.41.8 + specifier: ^1.41.9 + version: 1.42.2 devDependencies: '@blocknote/shared': specifier: workspace:^ @@ -5879,10 +5879,10 @@ importers: version: 3.17.0(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react@19.2.5) '@liveblocks/react-blocknote': specifier: ^3.17.0 - version: 3.17.0(@blocknote/core@packages+core)(@blocknote/react@packages+react)(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) + version: 3.17.0(@blocknote/core@packages+core)(@blocknote/react@packages+react)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) '@liveblocks/react-tiptap': specifier: ^3.17.0 - version: 3.17.0(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30)) + version: 3.17.0(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30)) '@liveblocks/react-ui': specifier: ^3.17.0 version: 3.17.0(@types/json-schema@7.0.15)(@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) @@ -6040,8 +6040,8 @@ importers: specifier: ^4.1.14 version: 4.2.2(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0)) '@tiptap/pm': - specifier: ^3.0.0 - version: 3.22.4 + specifier: ^3.29.2 + version: 3.29.2 '@types/node': specifier: ^20.19.22 version: 20.19.37 @@ -7362,7 +7362,7 @@ packages: peerDependencies: '@blocknote/core': 0.43.0 - 1.0.0 '@blocknote/react': 0.43.0 - 1.0.0 - '@tiptap/core': ^3.0.0 + '@tiptap/core': ^3.29.2 '@types/react': '*' '@types/react-dom': '*' react: ^18 || ^19 || ^19.0.0-rc @@ -7378,7 +7378,7 @@ packages: peerDependencies: '@blocknote/core': '>=0.43' '@blocknote/react': '>=0.43' - '@tiptap/core': ^3.0.0 + '@tiptap/core': ^3.29.2 '@types/react': ^18 || ^19 '@types/react-dom': ^18 || ^19 react: ^18 || ^19 || ^19.0.0-rc @@ -7392,7 +7392,7 @@ packages: '@liveblocks/react-tiptap@3.17.0': resolution: {integrity: sha512-IVAN5sZCOTtGy8alKw4EpArikBLu/dwjvbNya5IaH3ZiO6eoYmPFbHxinVN08BKPe208YjhZWefwrFr7bKAVNw==} peerDependencies: - '@tiptap/pm': ^3.0.0 + '@tiptap/pm': ^3.29.2 '@tiptap/react': ^3.19.0 '@tiptap/suggestion': ^3.19.0 '@types/react': '*' @@ -7408,8 +7408,8 @@ packages: '@liveblocks/react-tiptap@3.19.5': resolution: {integrity: sha512-XRafUZ/usOpAZNdC0kbvWga+tjGb4CyAi8j5XBKM38KWhh7sMhA0lpk3P8jjS9zBrl+NlApJym0NledF8LBRGw==} peerDependencies: - '@tiptap/core': ^3.0.0 - '@tiptap/pm': ^3.0.0 + '@tiptap/core': ^3.29.2 + '@tiptap/pm': ^3.29.2 '@tiptap/react': ^3 '@tiptap/suggestion': ^3 '@types/react': ^18 || ^19 @@ -10116,68 +10116,68 @@ packages: '@types/react-dom': optional: true - '@tiptap/core@3.22.4': - resolution: {integrity: sha512-vGIGm/HpqLg8EAAQXQ+koV+/S828OEpzocfWcPOwo1u2QUVf9dQG47Yy6JJ8zFFaJwfv4dBcOXli+7BrJwsxDQ==} + '@tiptap/core@3.29.2': + resolution: {integrity: sha512-oKUkiPUB7noilVYxI9lNzUD4rX17sHub+PYjMfHMWHG9A3nvIy+FdePIVIIhThKWF7ijhr3eIqHY51Bn+GAFtw==} peerDependencies: - '@tiptap/pm': ^3.0.0 + '@tiptap/pm': ^3.29.2 - '@tiptap/extension-bold@3.22.4': - resolution: {integrity: sha512-jIaPKfNOQu2lhpbLDvtwlQqM+mjF+Kk+auHpzYjBnsuwUli1Cl5ZOau7RH+rru/SQvZe1DtpQlANujDywugZAA==} + '@tiptap/extension-bold@3.29.2': + resolution: {integrity: sha512-elYbGxJsYnBb4leqrcjdIJuiG380BcOgN+UUzvOv+qEjfGVzHodFOMBl3qnmD6urYHNu5/qQK2S0qSSRXKCLNQ==} peerDependencies: - '@tiptap/core': ^3.0.0 + '@tiptap/core': ^3.29.2 - '@tiptap/extension-bubble-menu@3.22.4': - resolution: {integrity: sha512-v4pux5Ql3THAEjaLMY4ldtdy/Xy2qU7PJLBkq8ugLp8qicaKC+tpqxp6sGif4vLIjz7Ap5hurRbTNbXzszyyHA==} + '@tiptap/extension-bubble-menu@3.29.2': + resolution: {integrity: sha512-kzcWarcpr031rZu+R3Hzut5uxb3Qj/xxMDEYZIQ3uiq1yb5vEMXj8/SIyWautk6Nu8Rr1leV3rGdR4NzhzyFAA==} peerDependencies: - '@tiptap/core': ^3.0.0 - '@tiptap/pm': ^3.0.0 + '@tiptap/core': ^3.29.2 + '@tiptap/pm': ^3.29.2 - '@tiptap/extension-code@3.22.4': - resolution: {integrity: sha512-cnbxmVhAcc7X3G81QUYEmKP0ve2hRmvAiFXBuuv9RUtQlBiRnzmhHoJOMgkX0CsMR7+8kMRpTfeDUYq2xp5s5w==} + '@tiptap/extension-code@3.29.2': + resolution: {integrity: sha512-c6W5UGuB7WNLpYocsgRzpO2OOTI4QjaI9jjHRMuty9z+s9DtaYM/HrRLNwVh6MopkHb+i/89Wkv8gCS34fftig==} peerDependencies: - '@tiptap/core': ^3.0.0 + '@tiptap/core': ^3.29.2 - '@tiptap/extension-floating-menu@3.22.4': - resolution: {integrity: sha512-DFuyYxgaZPgxum5z1yvJPbfYCvDdO8geXsdyqt0qYYdiat3aGE4ncJhiLRIFDhSHBhaZg5eCgu/YPYAN6jZnrA==} + '@tiptap/extension-floating-menu@3.29.2': + resolution: {integrity: sha512-CBTq4Xs5aGWr65uFCIkKBms796OhmirWf/ax//iJ4fl9IfwqjwFuc2vQs9PmuwpKn9ctDHo2sMTtvyeCvIt5LQ==} peerDependencies: '@floating-ui/dom': ^1.0.0 - '@tiptap/core': ^3.0.0 - '@tiptap/pm': ^3.0.0 + '@tiptap/core': ^3.29.2 + '@tiptap/pm': ^3.29.2 - '@tiptap/extension-italic@3.22.4': - resolution: {integrity: sha512-fVSDx5AYXgDI3v2zZIqb7V8EewthwM2NJ/ZCX+XaxRsqNEpnjVhgHs7UlvDqK1wj2OJ6zmUNjPtVlAFRxwT+HQ==} + '@tiptap/extension-italic@3.29.2': + resolution: {integrity: sha512-iH63V/5wsaMnY4Jz0+meaAGhaec4AiOzOduzl6ZZr5IyGhZ1kthyW84ELt0dyLI3hNceAUhaNWc+I7+vX0aoXA==} peerDependencies: - '@tiptap/core': ^3.0.0 + '@tiptap/core': ^3.29.2 - '@tiptap/extension-strike@3.22.4': - resolution: {integrity: sha512-aRHWQj42HiailXSC9LkKYM3jWMcSeGwOjbqM4PiuxQZmHVDRFmeHkfJItOdn2cSHaO0vuEVK+TvrWUWsBFi3pg==} + '@tiptap/extension-strike@3.29.2': + resolution: {integrity: sha512-aEvLAbddUQZ+FukCreV3q4G2HfNI+odE7E9U+wbq6XsSWKyo8/pDu1muz+TFKNre4blSMOQ3JQmw5UeHDKy+fg==} peerDependencies: - '@tiptap/core': ^3.0.0 + '@tiptap/core': ^3.29.2 - '@tiptap/extension-text@3.22.4': - resolution: {integrity: sha512-mM69uUW5cSxIhyEpWXi/YcfyupcJMDLCPEfYi62awH0iOP/LRoCv/nHjJq4Hyj/KxRJbe8HKwIUnqaCUf7m5Pg==} + '@tiptap/extension-text@3.29.2': + resolution: {integrity: sha512-Ubko45JWWHe8glBt2PiGNF8hcbys/JNalFhiR7Y1X4iOOtAxAKJJxh3+eq+//NTlGuBPdWGp7zw8EEUp7anjKA==} peerDependencies: - '@tiptap/core': ^3.0.0 + '@tiptap/core': ^3.29.2 - '@tiptap/extension-underline@3.22.4': - resolution: {integrity: sha512-08kGdbhIrA6h10GWXqOkqIveaBj5tmxclK208/nUIAlonI9hPd739vu7fmVtpnmqCnSSNpoRtU4u6Gj5at0ZpA==} + '@tiptap/extension-underline@3.29.2': + resolution: {integrity: sha512-K7XwH/xS/5AIREWQ00VTEf/W5U0olp7j6wwit7cdd/8nHv6h6AGr1+iEApHKoLXWQZLfGQKzJlT9W61LAl+fHA==} peerDependencies: - '@tiptap/core': ^3.0.0 + '@tiptap/core': ^3.29.2 - '@tiptap/extensions@3.22.4': - resolution: {integrity: sha512-fOe8VptJvLPs32bNdUYo8SRyljwqKNQVXWW056VoXIc5en/59OdJlJQVeHI0jRRciH3MtrqODi/gfJR0VHNZ8A==} + '@tiptap/extensions@3.29.2': + resolution: {integrity: sha512-BCz+FCAChSYtUe4BFj97HEO+nSK+J7GxbJgZG4Hg7DT/gI+hRyeNndU8efiQAx3WGdzsFi3UxRpcF1tTQM7iMQ==} peerDependencies: - '@tiptap/core': ^3.0.0 - '@tiptap/pm': ^3.0.0 + '@tiptap/core': ^3.29.2 + '@tiptap/pm': ^3.29.2 - '@tiptap/pm@3.22.4': - resolution: {integrity: sha512-hj8Qka6WcHRllHUdeSjDnq2XaisUo4KsoGJc1WcFpoa1Yd+OeD861zUMnV7DFVGdZRy45Obht0CUYJpXQ4yA4w==} + '@tiptap/pm@3.29.2': + resolution: {integrity: sha512-GCOme7xHaS+DSoaA4CDcAD3l6JyBlvZhvCyfsy2Vp6j8tEoBkZWio7soYVosmlyn7zq8/64VeFZP5s47yfG7fQ==} - '@tiptap/react@3.22.4': - resolution: {integrity: sha512-XIQZPwLakR1t8+Q1UeCpr+kUHDWxpJzGy9r2xUi3mpPd6Wh8dtNltScBkUlCcr0sqc6J1GF6Is02JJVQGmCZMA==} + '@tiptap/react@3.29.2': + resolution: {integrity: sha512-ZMKgteYmZXnq7C22U9fbCTC6jAF8XlQM5n2K2FLWCdYAlP4FNV3XeQ9hY2a13KSQ0Q3yltWXZlcWBpt5ClxScg==} peerDependencies: - '@tiptap/core': ^3.0.0 - '@tiptap/pm': ^3.0.0 + '@tiptap/core': ^3.29.2 + '@tiptap/pm': ^3.29.2 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -10186,8 +10186,8 @@ packages: '@tiptap/suggestion@2.27.2': resolution: {integrity: sha512-dQyvCIg0hcAVeh4fCIVCxogvbp+bF+GpbUb8sNlgnGrmHXnapGxzkvrlHnvneXZxLk/j7CxmBPKJNnm4Pbx4zw==} peerDependencies: - '@tiptap/core': ^3.0.0 - '@tiptap/pm': ^3.0.0 + '@tiptap/core': ^3.29.2 + '@tiptap/pm': ^3.29.2 '@transloadit/prettier-bytes@0.3.5': resolution: {integrity: sha512-xF4A3d/ZyX2LJWeQZREZQw+qFX4TGQ8bGVP97OLRt6sPO6T0TNHBFTuRHOJh7RNmYOBmQ9MHxpolD9bXihpuVA==} @@ -14182,11 +14182,14 @@ packages: prosemirror-history@1.5.0: resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==} + prosemirror-inputrules@1.5.1: + resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==} + prosemirror-keymap@1.2.3: resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} - prosemirror-model@1.25.4: - resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==} + prosemirror-model@1.25.11: + resolution: {integrity: sha512-QWg9RhnpLlogAmp3p96uEFrE5txQpFynd4vhBAELkwgOCWQs/X0yCzB3/hrHqiPwf91RG5KyWq6553zs9JqIOQ==} prosemirror-schema-list@1.5.1: resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} @@ -14200,8 +14203,8 @@ packages: prosemirror-transform@1.12.0: resolution: {integrity: sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==} - prosemirror-view@1.41.8: - resolution: {integrity: sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==} + prosemirror-view@1.42.2: + resolution: {integrity: sha512-Pdg0l5kXm8aLDquFAnQFTCITg0q44sLqBlHlpsVLD9segdOao8TOfQdAhCrCXyVgPSRr6UDDROOIWA3bIrN9YQ==} proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -16943,20 +16946,20 @@ snapshots: next: 16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) tailwindcss: 4.2.2 - '@handlewithcare/prosemirror-inputrules@0.1.4(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)': + '@handlewithcare/prosemirror-inputrules@0.1.4(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)': dependencies: prosemirror-history: 1.5.0 - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 - '@handlewithcare/prosemirror-suggest-changes@0.1.8(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-transform@1.12.0)(prosemirror-view@1.41.8)': + '@handlewithcare/prosemirror-suggest-changes@0.1.8(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-transform@1.12.0)(prosemirror-view@1.42.2)': dependencies: - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 '@hapi/address@5.1.1': dependencies: @@ -17255,17 +17258,17 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@liveblocks/react-blocknote@3.17.0(@blocknote/core@packages+core)(@blocknote/react@packages+react)(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30)': + '@liveblocks/react-blocknote@3.17.0(@blocknote/core@packages+core)(@blocknote/react@packages+react)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30)': dependencies: '@blocknote/core': link:packages/core '@blocknote/react': link:packages/react '@liveblocks/client': 3.17.0(@types/json-schema@7.0.15) '@liveblocks/core': 3.17.0(@types/json-schema@7.0.15) '@liveblocks/react': 3.17.0(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react@19.2.5) - '@liveblocks/react-tiptap': 3.17.0(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30)) + '@liveblocks/react-tiptap': 3.17.0(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30)) '@liveblocks/react-ui': 3.17.0(@types/json-schema@7.0.15)(@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) '@liveblocks/yjs': 3.17.0(@types/json-schema@7.0.15)(yjs@13.6.30) - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) vitest-tsconfig-paths: 3.4.1 @@ -17284,17 +17287,17 @@ snapshots: - y-protocols - yjs - '@liveblocks/react-blocknote@3.19.5(@blocknote/core@packages+core)(@blocknote/react@packages+react)(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30)': + '@liveblocks/react-blocknote@3.19.5(@blocknote/core@packages+core)(@blocknote/react@packages+react)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30)': dependencies: '@blocknote/core': link:packages/core '@blocknote/react': link:packages/react '@liveblocks/client': 3.19.5(@types/json-schema@7.0.15) '@liveblocks/core': 3.19.5(@types/json-schema@7.0.15) '@liveblocks/react': 3.19.5(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react@19.2.5) - '@liveblocks/react-tiptap': 3.19.5(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) + '@liveblocks/react-tiptap': 3.19.5(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) '@liveblocks/react-ui': 3.19.5(@types/json-schema@7.0.15)(@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) '@liveblocks/yjs': 3.19.5(@types/json-schema@7.0.15)(yjs@13.6.30) - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) optionalDependencies: @@ -17311,7 +17314,7 @@ snapshots: - y-protocols - yjs - '@liveblocks/react-tiptap@3.17.0(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))': + '@liveblocks/react-tiptap@3.17.0(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))': dependencies: '@floating-ui/react-dom': 2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@liveblocks/client': 3.17.0(@types/json-schema@7.0.15) @@ -17319,15 +17322,15 @@ snapshots: '@liveblocks/react': 3.17.0(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react@19.2.5) '@liveblocks/react-ui': 3.17.0(@types/json-schema@7.0.15)(@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) '@liveblocks/yjs': 3.17.0(@types/json-schema@7.0.15)(yjs@13.6.30) - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) - '@tiptap/pm': 3.22.4 - '@tiptap/react': 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) - '@tiptap/suggestion': 2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4) + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) + '@tiptap/pm': 3.29.2 + '@tiptap/react': 3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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) + '@tiptap/suggestion': 2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2) cmdk: 1.1.1(@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) radix-ui: 1.4.3(@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) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - y-prosemirror: 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-prosemirror: 1.3.7(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) yjs: 13.6.30 optionalDependencies: '@types/react': 19.2.14 @@ -17339,7 +17342,7 @@ snapshots: - prosemirror-view - y-protocols - '@liveblocks/react-tiptap@3.19.5(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)(@tiptap/react@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30)': + '@liveblocks/react-tiptap@3.19.5(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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))(@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2))(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30)': dependencies: '@floating-ui/react-dom': 2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@liveblocks/client': 3.19.5(@types/json-schema@7.0.15) @@ -17347,15 +17350,15 @@ snapshots: '@liveblocks/react': 3.19.5(@types/json-schema@7.0.15)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react@19.2.5) '@liveblocks/react-ui': 3.19.5(@types/json-schema@7.0.15)(@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) '@liveblocks/yjs': 3.19.5(@types/json-schema@7.0.15)(yjs@13.6.30) - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) - '@tiptap/pm': 3.22.4 - '@tiptap/react': 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) - '@tiptap/suggestion': 2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4) + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) + '@tiptap/pm': 3.29.2 + '@tiptap/react': 3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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) + '@tiptap/suggestion': 2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2) cmdk: 1.1.1(@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) radix-ui: 1.4.3(@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) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - y-prosemirror: 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-prosemirror: 1.3.7(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) yjs: 13.6.30 optionalDependencies: '@types/react': 19.2.14 @@ -20204,72 +20207,73 @@ snapshots: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@tiptap/core@3.22.4(@tiptap/pm@3.22.4)': + '@tiptap/core@3.29.2(@tiptap/pm@3.29.2)': dependencies: - '@tiptap/pm': 3.22.4 + '@tiptap/pm': 3.29.2 - '@tiptap/extension-bold@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))': + '@tiptap/extension-bold@3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))': dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) - '@tiptap/extension-bubble-menu@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)': + '@tiptap/extension-bubble-menu@3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)': dependencies: '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) - '@tiptap/pm': 3.22.4 + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) + '@tiptap/pm': 3.29.2 optional: true - '@tiptap/extension-code@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))': + '@tiptap/extension-code@3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))': dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) - '@tiptap/extension-floating-menu@3.22.4(@floating-ui/dom@1.7.6)(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)': + '@tiptap/extension-floating-menu@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)': dependencies: '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) - '@tiptap/pm': 3.22.4 + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) + '@tiptap/pm': 3.29.2 optional: true - '@tiptap/extension-italic@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))': + '@tiptap/extension-italic@3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))': dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) - '@tiptap/extension-strike@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))': + '@tiptap/extension-strike@3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))': dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) - '@tiptap/extension-text@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))': + '@tiptap/extension-text@3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))': dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) - '@tiptap/extension-underline@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))': + '@tiptap/extension-underline@3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))': dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) - '@tiptap/extensions@3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)': + '@tiptap/extensions@3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)': dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) - '@tiptap/pm': 3.22.4 + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) + '@tiptap/pm': 3.29.2 - '@tiptap/pm@3.22.4': + '@tiptap/pm@3.29.2': dependencies: prosemirror-changeset: 2.4.1 prosemirror-commands: 1.7.1 prosemirror-dropcursor: 1.8.2 prosemirror-gapcursor: 1.4.1 prosemirror-history: 1.5.0 + prosemirror-inputrules: 1.5.1 prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-schema-list: 1.5.1 prosemirror-state: 1.4.4 prosemirror-tables: 1.8.5 prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 - '@tiptap/react@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)': + '@tiptap/react@3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)(@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)': dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) - '@tiptap/pm': 3.22.4 + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) + '@tiptap/pm': 3.29.2 '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) '@types/use-sync-external-store': 0.0.6 @@ -20278,15 +20282,15 @@ snapshots: react-dom: 19.2.5(react@19.2.5) use-sync-external-store: 1.6.0(react@19.2.5) optionalDependencies: - '@tiptap/extension-bubble-menu': 3.22.4(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4) - '@tiptap/extension-floating-menu': 3.22.4(@floating-ui/dom@1.7.6)(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4) + '@tiptap/extension-bubble-menu': 3.29.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2) + '@tiptap/extension-floating-menu': 3.29.2(@floating-ui/dom@1.7.6)(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2) transitivePeerDependencies: - '@floating-ui/dom' - '@tiptap/suggestion@2.27.2(@tiptap/core@3.22.4(@tiptap/pm@3.22.4))(@tiptap/pm@3.22.4)': + '@tiptap/suggestion@2.27.2(@tiptap/core@3.29.2(@tiptap/pm@3.29.2))(@tiptap/pm@3.29.2)': dependencies: - '@tiptap/core': 3.22.4(@tiptap/pm@3.22.4) - '@tiptap/pm': 3.22.4 + '@tiptap/core': 3.29.2(@tiptap/pm@3.29.2) + '@tiptap/pm': 3.29.2 '@transloadit/prettier-bytes@0.3.5': {} @@ -21236,14 +21240,14 @@ snapshots: dependencies: '@types/node': 20.19.39 - '@y/prosemirror@2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)': + '@y/prosemirror@2.0.0-6(patch_hash=e49b17b47e301dd138d7e383a779a0e2125bf7f038e10e3c740e26b43d988776)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23))(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)': dependencies: '@y/protocols': 1.0.6-rc.1(@y/y@14.0.0-rc.23) '@y/y': 14.0.0-rc.23 lib0: 1.0.0-rc.22 - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-state: 1.4.4 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 '@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.23)': dependencies: @@ -25255,7 +25259,7 @@ snapshots: prosemirror-commands@1.7.1: dependencies: - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 @@ -25263,67 +25267,72 @@ snapshots: dependencies: prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 prosemirror-gapcursor@1.4.1: dependencies: prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-state: 1.4.4 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 - prosemirror-highlight@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): + prosemirror-highlight@0.15.1(@shikijs/types@4.0.2)(@types/hast@3.0.4)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-transform@1.12.0)(prosemirror-view@1.42.2): optionalDependencies: '@shikijs/types': 4.0.2 '@types/hast': 3.0.4 - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 prosemirror-history@1.5.0: dependencies: prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 rope-sequence: 1.3.4 + prosemirror-inputrules@1.5.1: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + prosemirror-keymap@1.2.3: dependencies: prosemirror-state: 1.4.4 w3c-keyname: 2.2.8 - prosemirror-model@1.25.4: + prosemirror-model@1.25.11: dependencies: orderedmap: 2.1.1 prosemirror-schema-list@1.5.1: dependencies: - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 prosemirror-state@1.4.4: dependencies: - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 prosemirror-tables@1.8.5: dependencies: prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 prosemirror-transform@1.12.0: dependencies: - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 - prosemirror-view@1.41.8: + prosemirror-view@1.42.2: dependencies: - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 @@ -27212,7 +27221,7 @@ snapshots: picomatch: 4.0.4 std-env: 4.0.0 tinybench: 2.9.0 - tinyexec: 1.0.4 + tinyexec: 1.2.4 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 vite: 8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0) @@ -27242,7 +27251,7 @@ snapshots: picomatch: 4.0.4 std-env: 4.0.0 tinybench: 2.9.0 - tinyexec: 1.0.4 + tinyexec: 1.2.4 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 vite: 8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0) @@ -27485,12 +27494,12 @@ snapshots: y-protocols: 1.0.7(yjs@13.6.30) yjs: 13.6.30 - y-prosemirror@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-prosemirror@1.3.7(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.2)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30): dependencies: lib0: 1.0.0-rc.22 - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.11 prosemirror-state: 1.4.4 - prosemirror-view: 1.41.8 + prosemirror-view: 1.42.2 y-protocols: 1.0.7(yjs@13.6.30) yjs: 13.6.30 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 11b8e3c0b1..284861edef 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -15,8 +15,8 @@ publicHoistPattern: - "prosemirror-*" overrides: "@headlessui/react": "^2.2.4" - "@tiptap/core": "^3.0.0" - "@tiptap/pm": "^3.0.0" + "@tiptap/core": "^3.29.2" + "@tiptap/pm": "^3.29.2" "vitest": "4.1.7" "@vitest/runner": "4.1.7" "@y/y": "14.0.0-rc.23" diff --git a/tests/package.json b/tests/package.json index 8a45c0c53b..3ec4b42e3a 100644 --- a/tests/package.json +++ b/tests/package.json @@ -16,7 +16,7 @@ "@blocknote/shadcn": "workspace:^", "@playwright/test": "1.60.0", "@tailwindcss/vite": "^4.1.14", - "@tiptap/pm": "^3.13.0", + "@tiptap/pm": "^3.29.2", "@types/node": "^20.19.22", "@types/react": "^19.2.3", "@types/react-dom": "^19.2.3", From e8c08313cc3026b3eee468d5ed56f86509dc5be8 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Mon, 3 Aug 2026 18:40:49 +0200 Subject: [PATCH 2/4] fix: don't crash when a node view's `getPos()` is stale `getPos()` is derived from ProseMirror's view-desc tree, but `updateStateInner` assigns the new state before it reconciles that tree. Anything rendering part-way through reconciliation - a re-entrant dispatch from a node view effect, TipTap's `flushSync` while mounting a node view - therefore reads a position that no longer lines up with `view.state.doc`. Resolving it threw `RangeError: Position N out of range`, or `Node should be a bnBlock, but is instead: doc` when the position was in range but pointed at the wrong node. Under React 19 that tears down the consumer's tree rather than being rethrown. Upstream considers this TipTap's problem (ProseMirror/prosemirror#1532) and TipTap considers `flushSync` unavoidable, so recover on our side: - core `getBlockFromNodeView`: falls back to building the block from the node alone. Reached only when a re-entrant dispatch superseded the document, so the node is gone from it and there is no container to read an id from - `type`, `props` and `content` are correct, `id` is freshly generated and belongs to no block. - react `useNodeViewBlock`: falls back to the last block it resolved, seeded from the one core resolved at construction. Both are silent and transient; ProseMirror rebuilds the node view against the current document immediately after, so a stale frame is invisible where a throw is not. --- packages/core/src/schema/blocks/createSpec.ts | 13 +- .../core/src/schema/blocks/internal.test.ts | 77 ++++++ packages/core/src/schema/blocks/internal.ts | 68 +++++ packages/react/src/index.ts | 1 + packages/react/src/schema/ReactBlockSpec.tsx | 15 +- packages/react/src/schema/useNodeViewBlock.ts | 57 ++++ .../src/unit/react/staleNodeViewPos.test.tsx | 261 ++++++++++++++++++ .../src/unit/react/useNodeViewBlock.test.tsx | 173 ++++++++++++ 8 files changed, 656 insertions(+), 9 deletions(-) create mode 100644 packages/core/src/schema/blocks/internal.test.ts create mode 100644 packages/react/src/schema/useNodeViewBlock.ts create mode 100644 tests/src/unit/react/staleNodeViewPos.test.tsx create mode 100644 tests/src/unit/react/useNodeViewBlock.test.tsx diff --git a/packages/core/src/schema/blocks/createSpec.ts b/packages/core/src/schema/blocks/createSpec.ts index faf0d35292..5db7ff48eb 100644 --- a/packages/core/src/schema/blocks/createSpec.ts +++ b/packages/core/src/schema/blocks/createSpec.ts @@ -15,7 +15,7 @@ import { import { nonFormattingMarks } from "../markGroups.js"; import { PropSchema } from "../propTypes.js"; import { - getBlockFromPos, + getBlockFromNodeView, propsToAttributes, wrapInBlockStructure, } from "./internal.js"; @@ -247,8 +247,15 @@ export function addNodeAndExtensionsToSpec< return (props) => { // Gets the BlockNote editor instance const editor = this.options.editor; - // Gets the block - const block = getBlockFromPos(props.getPos, props.view.state.doc); + // Gets the block. Resolving this can't rely on `getPos()` alone — + // node views are constructed part-way through ProseMirror's + // reconciliation, where positions don't always line up with + // `view.state.doc` yet (see `getBlockFromNodeView`). + const block = getBlockFromNodeView( + props.getPos, + props.node, + props.view.state.doc, + ); // Gets the custom HTML attributes for `blockContent` nodes const blockContentDOMAttributes = this.options.domAttributes?.blockContent || {}; diff --git a/packages/core/src/schema/blocks/internal.test.ts b/packages/core/src/schema/blocks/internal.test.ts new file mode 100644 index 0000000000..b6029c2efa --- /dev/null +++ b/packages/core/src/schema/blocks/internal.test.ts @@ -0,0 +1,77 @@ +import { beforeEach, describe, expect, it } from "vite-plus/test"; + +import { getNodeById } from "../../api/nodeUtil.js"; +import { BlockNoteEditor } from "../../editor/BlockNoteEditor.js"; +import { getBlockFromNodeView } from "./internal.js"; + +describe("getBlockFromNodeView", () => { + let editor: BlockNoteEditor; + + beforeEach(() => { + editor = BlockNoteEditor.create({ + trailingBlock: false, + initialContent: [ + { type: "paragraph", content: "first" }, + { type: "paragraph", content: "second" }, + ], + }); + }); + + it("resolves from the position when it is valid", () => { + const doc = editor.prosemirrorState.doc; + const target = editor.document[1]; + // `getBlockFromPos` resolves the *parent* of the position, so the position + // sits just inside the block container — which is what ProseMirror hands a + // node view. + const pos = getNodeById(target.id, doc)!.posBeforeNode + 1; + const block = getBlockFromNodeView(() => pos, doc.nodeAt(pos)!, doc) as any; + + expect(block.id).toBe(target.id); + }); + + it("builds a standalone block when the node is no longer in the document", () => { + // The only way `getPos()` fails at node view construction is a re-entrant + // dispatch superseding `view.state.doc`, which takes the node with it — so + // the node genuinely isn't in the document any more. See #2937. + const doc = editor.prosemirrorState.doc; + const orphan = editor.pmSchema.nodes.paragraph.create( + { textAlignment: "right" }, + editor.pmSchema.text("orphaned content"), + ); + const block = getBlockFromNodeView( + () => doc.content.size + 1000, + orphan, + doc, + ) as any; + + // Everything readable off the node is correct... + expect(block.type).toBe("paragraph"); + expect(block.props.textAlignment).toBe("right"); + expect(block.content[0].text).toBe("orphaned content"); + // ...but the id belongs to no block in the document, so it must not + // collide with a real one. + expect(editor.document.map((b) => b.id)).not.toContain(block.id); + }); + + it("recovers from an in-range position that resolves to the wrong node", () => { + // Position 0 resolves to the doc rather than a block container — the shape + // a bounds check alone would not catch. + const doc = editor.prosemirrorState.doc; + const orphan = editor.pmSchema.nodes.paragraph.create( + null, + editor.pmSchema.text("orphaned content"), + ); + expect(() => getBlockFromNodeView(() => 0, orphan, doc)).not.toThrow(); + }); + + it("recovers when the position is undefined", () => { + const doc = editor.prosemirrorState.doc; + const orphan = editor.pmSchema.nodes.paragraph.create( + null, + editor.pmSchema.text("orphaned content"), + ); + expect(() => + getBlockFromNodeView(() => undefined, orphan, doc), + ).not.toThrow(); + }); +}); diff --git a/packages/core/src/schema/blocks/internal.ts b/packages/core/src/schema/blocks/internal.ts index 4f5a7941a9..f1073eda52 100644 --- a/packages/core/src/schema/blocks/internal.ts +++ b/packages/core/src/schema/blocks/internal.ts @@ -93,6 +93,74 @@ export function getBlockFromPos(getPos: () => number | undefined, doc: PMNode) { return block; } +/** + * Resolves the block a node view should render, tolerating a `getPos()` that + * can't be trusted. + * + * ProseMirror derives `getPos()` from its view-desc tree, but + * `EditorView.updateStateInner` assigns the new state *before* it reconciles + * that tree. Anything that runs partway through reconciliation - a re-entrant + * dispatch from a node view's effect, TipTap's `flushSync` while mounting a + * node view - therefore sees positions that no longer line up with + * `view.state.doc`. The position then either lands out of range or, just as + * bad, in range but pointing at the wrong node. + * + * Node views are constructed inside that same window, so this applies at + * construction just as much as on re-render. The state is always transient: + * ProseMirror finishes reconciling and rebuilds the node view against the + * current document immediately after. So we degrade instead of throwing, + * because a stale frame is invisible where a throw is not. + * + * See issues #2937, #2682 and #2621. + */ +export function getBlockFromNodeView( + getPos: () => number | undefined, + node: PMNode, + doc: PMNode, +) { + let positionError: unknown; + + try { + return getBlockFromPos(getPos, doc); + } catch (e) { + // Kept only to rethrow below if there turns out to be nothing to render. + // Otherwise deliberately silent: this is expected and self-correcting, and + // there is nothing a consumer could do about it in the meantime. + positionError = e; + } + + // Whenever this is reached, the node is not in `doc` — a re-entrant dispatch + // superseded the document ProseMirror is building node views for, and the + // node went with it. So there is no container to read an id from, and the + // block has to be built from the node alone. + // + // `type`, `props` and `content` are read off the node and are correct. + // `children` is empty and `id` is freshly generated, i.e. it belongs to no + // block in the document — callers must not treat it as addressable. (It can't + // collide with a real block: ids are uuids, and the deterministic test-mode + // generator shares one monotonic counter with real ids.) This is short-lived; + // ProseMirror rebuilds the node view against the real document right after. + // + // The alternatives are worse. Throwing is the crash this exists to prevent. + // Returning an empty placeholder node view can leave the block *permanently* + // blank, since vanilla node views don't implement `update()` and so are only + // rebuilt when something else changes the document. + // + // `createAndFill` rather than `create` so an unexpected node shape yields + // `null` instead of throwing over the top of the original failure. + const standalone = doc.type.schema.nodes["blockContainer"]?.createAndFill( + null, + node, + ); + if (standalone) { + return nodeToBlock(standalone, doc); + } + + // Nothing left to render from. Surface the original failure rather than + // inventing a block that isn't grounded in anything. + throw positionError; +} + // Function that wraps the `dom` element returned from 'blockConfig.render' in a // `blockContent` div, which contains the block type and props as HTML // attributes. If `blockConfig.render` also returns a `contentDOM`, it also adds diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index bae514dc94..2259babd84 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -139,6 +139,7 @@ export * from "./hooks/useEditorState.js"; export * from "./schema/ReactBlockSpec.js"; export * from "./schema/ReactInlineContentSpec.js"; export * from "./schema/ReactStyleSpec.js"; +export * from "./schema/useNodeViewBlock.js"; export * from "./icons.js"; diff --git a/packages/react/src/schema/ReactBlockSpec.tsx b/packages/react/src/schema/ReactBlockSpec.tsx index fb0e767d8f..4bd1649292 100644 --- a/packages/react/src/schema/ReactBlockSpec.tsx +++ b/packages/react/src/schema/ReactBlockSpec.tsx @@ -10,7 +10,6 @@ import { Extension, ExtensionFactoryInstance, ExtractBlockConfigFromConfigOrCreator, - getBlockFromPos, mergeCSSClasses, Props, PropSchema, @@ -23,6 +22,7 @@ import { } from "@tiptap/react"; import { FC, ReactNode } from "react"; import { renderToDOMSpec } from "./@util/ReactRenderUtil.js"; +import { useNodeViewBlock } from "./useNodeViewBlock.js"; // this file is mostly analogoues to `customBlocks.ts`, but for React blocks @@ -267,17 +267,20 @@ export function createReactBlockSpec< }, render(block, editor) { if (this.renderType === "nodeView") { + // The block core's `addNodeView` resolved when this node view was + // constructed (itself guarded, via `getBlockFromNodeView`). Seeds + // the fallback below so there is always something to render. + const initialBlock = block; + return ReactNodeViewRenderer( (props: NodeViewProps) => { // Vanilla JS node views are recreated on each update. However, // using `ReactNodeViewRenderer` makes it so the node view is // only created once, so the block we get in the node view will // be outdated. Therefore, we have to get the block in the - // `ReactNodeViewRenderer` instead. - const block = getBlockFromPos( - props.getPos, - props.view.state.doc, - ); + // `ReactNodeViewRenderer` instead. That position can be stale, + // so resolving it is guarded (see `useNodeViewBlock`). + const block = useNodeViewBlock(props, initialBlock); const ref = useReactNodeView().nodeViewContentRef; diff --git a/packages/react/src/schema/useNodeViewBlock.ts b/packages/react/src/schema/useNodeViewBlock.ts new file mode 100644 index 0000000000..02393a2fd0 --- /dev/null +++ b/packages/react/src/schema/useNodeViewBlock.ts @@ -0,0 +1,57 @@ +import { Block, getBlockFromPos } from "@blocknote/core"; +import type { NodeViewProps } from "@tiptap/react"; +import { useRef } from "react"; + +/** + * Resolves the `Block` that a React node view should render. + * + * A node view's `getPos()` is not always usable. ProseMirror computes it by + * walking the view-desc tree, but `EditorView.updateStateInner` assigns the new + * state *before* it reconciles that tree, so any render that happens partway + * through reconciliation sees positions computed against a half-updated tree + * while `view.state.doc` is already the new document. React node views get + * rendered in exactly that window: TipTap's `ReactRenderer` calls `flushSync` + * while mounting a node view, and anything that runs from the resulting commit + * (a layout effect, a re-entrant dispatch, another node view's pending update) + * renders with a position that no longer matches the document. `getPos()` can + * also return `undefined` outright once a desc has been detached. + * + * The resulting position is either out of range (`RangeError: Position N out of + * range`) or in range but pointing at the wrong node (`Node should be a + * bnBlock, but is instead: doc`) — both thrown out of the render path, which + * under React 19 tears down the consumer's tree rather than being rethrown. + * + * Upstream considers this TipTap's problem (ProseMirror/prosemirror#1532) and + * TipTap considers `flushSync` unavoidable, so we recover here instead, by + * reusing the last block we rendered. The bad position is always transient — + * ProseMirror finishes reconciling and re-renders the node view with a valid + * one immediately after — so a stale frame is invisible, whereas a throw is + * not. + * + * See BlockNote issues #2937, #2682 and #2621. + */ +export function useNodeViewBlock( + props: NodeViewProps, + /** + * The block core's `addNodeView` resolved when the node view was constructed + * — via `getBlockFromNodeView`, so it is already guarded against the same + * problem. Seeds the fallback so there is always a block to render. + */ + initialBlock: Block, +): Block { + const lastBlockRef = useRef(initialBlock); + const doc = props.view.state.doc; + + try { + // Deliberate render-phase write: a monotonic "last good value" cache, so a + // repeated render (e.g. StrictMode's double invoke) recomputes the same + // thing. + lastBlockRef.current = getBlockFromPos(props.getPos, doc); + } catch { + // Expected and self-correcting, so deliberately silent: ProseMirror + // re-renders the node view with a usable position immediately after, and + // there is nothing a consumer could do about it in the meantime. + } + + return lastBlockRef.current; +} diff --git a/tests/src/unit/react/staleNodeViewPos.test.tsx b/tests/src/unit/react/staleNodeViewPos.test.tsx new file mode 100644 index 0000000000..2328f09ae0 --- /dev/null +++ b/tests/src/unit/react/staleNodeViewPos.test.tsx @@ -0,0 +1,261 @@ +import { + BlockNoteEditor, + BlockNoteSchema, + createBlockSpec, + defaultProps, +} from "@blocknote/core"; +import { BlockNoteViewRaw, createReactBlockSpec } from "@blocknote/react"; +import { useLayoutEffect } from "react"; +import { flushSync } from "react-dom"; +import { createRoot, type Root } from "react-dom/client"; +import { afterEach, describe, expect, it, vi } from "vite-plus/test"; + +/** + * Regression tests for #2937 (and the same family: #2682, #2621). + * + * A React node view resolves its block from `getPos()`, which ProseMirror + * derives from its view-desc tree. `EditorView.updateStateInner` assigns the + * new state *before* it reconciles that tree, so anything rendering part-way + * through reconciliation reads a position that doesn't line up with + * `view.state.doc`. Resolving it then threw out of the render path, which under + * React 19 tears down the consumer's tree rather than being rethrown. + */ + +// Set by a test to make a newly mounted node view dispatch a transaction from +// its layout effect, i.e. re-entrantly during ProseMirror's reconciliation. +let onMount: ((blockId: string, text: string) => void) | undefined; + +// Whether each node view render resolved to a block that was actually in the +// document *at the time it rendered*. Proves the recovery path ran without +// relying on a log line: a successful resolve always yields a block from the +// current document, whereas core's fallback builds one from the node alone +// under a freshly generated id that belongs to no block at all. +let renderedFromFallbackCount = 0; + +function noteRender(id: string, ed: BlockNoteEditor) { + let found = false; + ed.prosemirrorState.doc.descendants((node) => { + found ||= node.attrs.id === id; + return !found; + }); + if (!found) { + renderedFromFallbackCount++; + } +} + +// Typed structurally rather than with `ReactCustomBlockRenderProps`, whose +// `contentRef` is conditional on the block config's `content` type and so +// doesn't resolve through `any`. +function ReproComponent(props: { + block: { id: string; content?: unknown }; + editor: BlockNoteEditor; + contentRef: (element: HTMLElement | null) => void; +}) { + const { id, content } = props.block; + const text = + Array.isArray(content) && content[0]?.type === "text" + ? content[0].text + : ""; + + noteRender(id, props.editor); + + useLayoutEffect(() => { + onMount?.(id, text); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [id]); + + return

; +} + +const createFillerBlock = createBlockSpec( + { type: "filler", propSchema: defaultProps, content: "inline" }, + { + render(block, editor) { + noteRender(block.id, editor as BlockNoteEditor); + const dom = document.createElement("p"); + return { dom, contentDOM: dom }; + }, + }, +); + +const createReproBlock = createReactBlockSpec( + { + type: "repro", + propSchema: defaultProps, + content: "inline", + }, + { render: ReproComponent }, +); + +const schema = BlockNoteSchema.create().extend({ + blockSpecs: { repro: createReproBlock(), filler: createFillerBlock() }, +}); + +type ReproEditor = BlockNoteEditor< + typeof schema.blockSchema, + typeof schema.inlineContentSchema, + typeof schema.styleSchema +>; + +let root: Root | undefined; +let div: HTMLDivElement | undefined; +let editor: ReproEditor | undefined; +/** Render-phase errors. React 19 reports rather than rethrows these. */ +let uncaught: unknown[] = []; + +function paragraphs(count: number, prefix: string) { + return Array.from({ length: count }, (_, i) => ({ + type: "filler" as const, + content: `${prefix} ${i} — filler text so the document has real size`, + })); +} + +function mountEditor(initialContent: any[]): ReproEditor { + div = document.createElement("div"); + document.body.appendChild(div); + + editor = BlockNoteEditor.create({ + schema, + trailingBlock: false, + initialContent, + }) as ReproEditor; + + uncaught = []; + renderedFromFallbackCount = 0; + root = createRoot(div, { + onUncaughtError: (error) => uncaught.push(error), + onCaughtError: (error) => uncaught.push(error), + }); + + flushSync(() => { + root!.render(); + }); + + // TipTap's `ReactRenderer` only renders a node view synchronously (via + // `flushSync`) when `isEditorContentInitialized` is set; otherwise it defers + // to a microtask. TipTap's own `PureEditorContent` sets it, but BlockNote + // replaces that component with its own mounting (`BlockNoteView.tsx`) and + // never does, so BlockNote currently gets the deferred path by accident. + // Set it here so node views mount the way they do for every other TipTap + // React user — and the way they do for anyone resolving `@tiptap/react` + // below 3.22, where this flag was still the always-true `isInitialized`. + // That is the configuration #2937 was reported against. + (editor as any)._tiptapEditor.isEditorContentInitialized = true; + + return editor; +} + +afterEach(() => { + onMount = undefined; + root?.unmount(); + root = undefined; + if (div) { + document.body.removeChild(div); + div = undefined; + } + editor?._tiptapEditor.destroy(); + editor = undefined; + vi.restoreAllMocks(); +}); + +/** Collects everything that went wrong during an action, however it surfaced. */ +function runCapturingErrors(action: () => void): string[] { + const errors: unknown[] = []; + const onWindowError = (e: ErrorEvent) => errors.push(e.error ?? e.message); + window.addEventListener("error", onWindowError); + try { + action(); + } catch (e) { + errors.push(e); + } finally { + window.removeEventListener("error", onWindowError); + } + errors.push(...uncaught); + uncaught = []; + return errors.map(String); +} + +const MARKER = "newly mounted repro block"; + +describe("stale node view getPos (#2937)", () => { + it("shrinking the doc while mounting a node view resolves normally", () => { + const ed = mountEditor([ + ...paragraphs(30, "head"), + { type: "repro", content: "existing repro block" }, + ...paragraphs(10, "tail"), + ]); + const errors = runCapturingErrors(() => { + ed.replaceBlocks(ed.document.slice(0, 28), [ + { type: "repro", content: MARKER } as any, + ]); + }); + + expect(errors).toEqual([]); + // The straightforward case must not go anywhere near the fallback. + expect(renderedFromFallbackCount).toBe(0); + }); + + it("recovers when a node view dispatches re-entrantly from its mount effect", () => { + const ed = mountEditor([ + ...paragraphs(30, "head"), + { type: "repro", content: "existing repro block" }, + ...paragraphs(10, "tail"), + ]); + let fired = false; + onMount = (_id, text) => { + if (fired || text !== MARKER) { + return; + } + fired = true; + // Runs inside React's commit phase, which is inside the `flushSync` in + // TipTap's `ReactRenderer` constructor, which is inside ProseMirror's + // `updateChildren`. Node views built or rendered from here see a + // `getPos()` computed against a half-updated view-desc tree. + ed.removeBlocks(ed.document.slice(-8)); + }; + + const errors = runCapturingErrors(() => { + ed.replaceBlocks(ed.document.slice(0, 28), [ + { type: "repro", content: MARKER } as any, + ]); + }); + + expect(fired).toBe(true); + // Before the fix this threw "Node should be a bnBlock, but is instead: doc" + // out of the render path. + expect(errors).toEqual([]); + // Guards against this silently ceasing to exercise the recovery path: a + // node view rendered the new block's content under an id that no block in + // the document has, which only core's fallback produces. + expect(renderedFromFallbackCount).toBeGreaterThan(0); + // The editor is still usable and shows the document it should. + expect(ed.document.some((b) => b.type === "repro")).toBe(true); + }); + + it("recovers when a re-entrant dispatch empties most of the document", () => { + const ed = mountEditor([ + ...paragraphs(40, "head"), + { type: "repro", content: "existing repro block" }, + ...paragraphs(20, "tail"), + ]); + let fired = false; + onMount = (_id, text) => { + if (fired || text !== MARKER) { + return; + } + fired = true; + ed.removeBlocks(ed.document.slice(1)); + }; + + const errors = runCapturingErrors(() => { + ed.replaceBlocks(ed.document.slice(0, 35), [ + { type: "repro", content: MARKER } as any, + ]); + }); + + expect(fired).toBe(true); + expect(errors).toEqual([]); + expect(renderedFromFallbackCount).toBeGreaterThan(0); + expect(ed.document.length).toBe(1); + }); +}); diff --git a/tests/src/unit/react/useNodeViewBlock.test.tsx b/tests/src/unit/react/useNodeViewBlock.test.tsx new file mode 100644 index 0000000000..71101c7fa7 --- /dev/null +++ b/tests/src/unit/react/useNodeViewBlock.test.tsx @@ -0,0 +1,173 @@ +import { + BlockNoteEditor, + BlockNoteSchema, + defaultProps, + getNodeById, +} from "@blocknote/core"; +import { createReactBlockSpec, useNodeViewBlock } from "@blocknote/react"; +import { flushSync } from "react-dom"; +import { createRoot, type Root } from "react-dom/client"; +import { + afterEach, + beforeEach, + describe, + expect, + it, + vi, +} from "vite-plus/test"; + +/** + * Branch-level coverage of the fallback `useNodeViewBlock` uses when a node + * view's `getPos()` can't be trusted. See `staleNodeViewPos.test.tsx` for the + * end-to-end reproduction of #2937. + */ + +const createReproBlock = createReactBlockSpec( + { type: "repro", propSchema: defaultProps, content: "inline" }, + { render: (props) =>

}, +); + +const schema = BlockNoteSchema.create().extend({ + blockSpecs: { repro: createReproBlock() }, +}); + +let editor: BlockNoteEditor; +let root: Root | undefined; +let div: HTMLDivElement; + +beforeEach(() => { + editor = BlockNoteEditor.create({ + schema, + trailingBlock: false, + initialContent: [ + { type: "paragraph", content: "first" }, + { type: "repro", content: "target block" }, + { type: "paragraph", content: "last" }, + ], + }) as BlockNoteEditor; + + div = document.createElement("div"); + document.body.appendChild(div); +}); + +afterEach(() => { + root?.unmount(); + root = undefined; + document.body.removeChild(div); + editor._tiptapEditor.destroy(); + vi.restoreAllMocks(); +}); + +/** Renders the hook once and returns what it resolved to. */ +function renderHook( + props: Parameters[0], + initialBlock: any, +) { + let resolved: any; + + function Probe() { + resolved = useNodeViewBlock(props, initialBlock); + return null; + } + + root = createRoot(div); + flushSync(() => { + root!.render(); + }); + + return resolved; +} + +// Only the two fields `useNodeViewBlock` reads. Built structurally so `tests` +// doesn't need a dependency on `@tiptap/react` just for its prop types. +function makeProps(getPos: () => number | undefined) { + return { + getPos, + view: { state: { doc: editor.prosemirrorState.doc } }, + } as unknown as Parameters[0]; +} + +describe("useNodeViewBlock", () => { + it("resolves from the position when it is valid", () => { + const doc = editor.prosemirrorState.doc; + const target = editor.document[1]; + // `getBlockFromPos` resolves the *parent* of the position, so the position + // has to sit just inside the block container. + const pos = getNodeById(target.id, doc)!.posBeforeNode + 1; + const stale = { ...target, id: "some-other-id" }; + const resolved = renderHook( + makeProps(() => pos), + stale, + ); + + expect(resolved.id).toBe(target.id); + expect(resolved.type).toBe("repro"); + }); + + it("falls back to the last known block when the position is out of range", () => { + const doc = editor.prosemirrorState.doc; + const lastKnown = editor.document[1]; + const resolved = renderHook( + makeProps(() => doc.content.size + 1000), + lastKnown, + ); + + // Returned as-is rather than throwing. + expect(resolved).toBe(lastKnown); + }); + + it("falls back to the last known block when the position is undefined", () => { + const lastKnown = editor.document[1]; + const resolved = renderHook( + makeProps(() => undefined), + lastKnown, + ); + + expect(resolved).toBe(lastKnown); + }); + + it("falls back to the last known block when the position resolves to the wrong node", () => { + const lastKnown = editor.document[1]; + // In range, but resolves to the doc rather than a block container — the + // shape that a bounds check alone would not have caught. + const resolved = renderHook( + makeProps(() => 0), + lastKnown, + ); + + expect(resolved).toBe(lastKnown); + }); + + it("keeps the last successfully resolved block, not the seed", () => { + const doc = editor.prosemirrorState.doc; + const target = editor.document[1]; + const pos = getNodeById(target.id, doc)!.posBeforeNode + 1; + const seed = { ...target, id: "stale-seed" }; + let positions = [pos, doc.content.size + 1000]; + let resolved: any; + + function Probe() { + resolved = useNodeViewBlock( + makeProps(() => positions[0]), + seed, + ); + return null; + } + + root = createRoot(div); + flushSync(() => { + root!.render(); + }); + expect(resolved.id).toBe(target.id); + + // Re-render with a position that no longer resolves: it must fall back to + // what it resolved last time, not to the seed it started with. + positions = positions.slice(1); + flushSync(() => { + root!.render(); + }); + + expect(resolved.id).toBe(target.id); + expect(resolved).not.toBe(seed); + }); +}); From 6e0e136937e66e6c783ad482bf101ce1bee8c4f6 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 4 Aug 2026 09:41:46 +0200 Subject: [PATCH 3/4] fix(test): destroy the editor in `getBlockFromNodeView` tests Each test created a `BlockNoteEditor` and never destroyed it, leaking a ProseMirror `DOMObserver` per test. Its `stop()` schedules a `flush()` 20ms later, which could outlive the test environment and fail the run with `ReferenceError: document is not defined` - reported against whichever test file happened to be running at the time. Destroying the editor nulls `view.docView`, so the late `flush()` hits its early-return guard. --- packages/core/src/schema/blocks/internal.test.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/core/src/schema/blocks/internal.test.ts b/packages/core/src/schema/blocks/internal.test.ts index b6029c2efa..809a314ed7 100644 --- a/packages/core/src/schema/blocks/internal.test.ts +++ b/packages/core/src/schema/blocks/internal.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it } from "vite-plus/test"; +import { afterEach, beforeEach, describe, expect, it } from "vite-plus/test"; import { getNodeById } from "../../api/nodeUtil.js"; import { BlockNoteEditor } from "../../editor/BlockNoteEditor.js"; @@ -17,6 +17,15 @@ describe("getBlockFromNodeView", () => { }); }); + afterEach(() => { + // Leaving the editor alive leaks a ProseMirror `DOMObserver`, whose + // `stop()` schedules a `flush()` 20ms later. That can outlive the test + // environment and then fail the run with `ReferenceError: document is not + // defined`, attributed to whichever test file happens to be running. + editor._tiptapEditor.destroy(); + editor = undefined as any; + }); + it("resolves from the position when it is valid", () => { const doc = editor.prosemirrorState.doc; const target = editor.document[1]; From 1504161bd766d680bda48664d04900e7f5468ed9 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 4 Aug 2026 10:04:58 +0200 Subject: [PATCH 4/4] refactor: collapse `getBlockFromNodeView` into a single try/catch Building the standalone block inside the `catch` lets it rethrow the original error directly, dropping the `positionError` local. Behaviour is unchanged - a `throw` inside a `catch` is not caught by its own `try`, so an error from `createAndFill`/`nodeToBlock` still propagates as before. --- packages/core/src/schema/blocks/internal.ts | 68 ++++++++++----------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/packages/core/src/schema/blocks/internal.ts b/packages/core/src/schema/blocks/internal.ts index f1073eda52..cfd17b9d11 100644 --- a/packages/core/src/schema/blocks/internal.ts +++ b/packages/core/src/schema/blocks/internal.ts @@ -118,47 +118,43 @@ export function getBlockFromNodeView( node: PMNode, doc: PMNode, ) { - let positionError: unknown; - try { return getBlockFromPos(getPos, doc); } catch (e) { - // Kept only to rethrow below if there turns out to be nothing to render. - // Otherwise deliberately silent: this is expected and self-correcting, and - // there is nothing a consumer could do about it in the meantime. - positionError = e; - } + // Failing here means the node is not in `doc` — a re-entrant dispatch + // superseded the document ProseMirror is building node views for, and the + // node went with it. So there is no container to read an id from, and the + // block has to be built from the node alone. Deliberately silent: this is + // expected and self-correcting, and there is nothing a consumer could do + // about it in the meantime. + // + // `type`, `props` and `content` are read off the node and are correct. + // `children` is empty and `id` is freshly generated, i.e. it belongs to no + // block in the document — callers must not treat it as addressable. (It + // can't collide with a real block: ids are uuids, and the deterministic + // test-mode generator shares one monotonic counter with real ids.) This is + // short-lived; ProseMirror rebuilds the node view against the real document + // right after. + // + // The alternatives are worse. Throwing is the crash this exists to prevent. + // Returning an empty placeholder node view can leave the block + // *permanently* blank, since vanilla node views don't implement `update()` + // and so are only rebuilt when something else changes the document. + // + // `createAndFill` rather than `create` so an unexpected node shape yields + // `null` instead of throwing over the top of the original failure. + const standalone = doc.type.schema.nodes["blockContainer"]?.createAndFill( + null, + node, + ); + if (standalone) { + return nodeToBlock(standalone, doc); + } - // Whenever this is reached, the node is not in `doc` — a re-entrant dispatch - // superseded the document ProseMirror is building node views for, and the - // node went with it. So there is no container to read an id from, and the - // block has to be built from the node alone. - // - // `type`, `props` and `content` are read off the node and are correct. - // `children` is empty and `id` is freshly generated, i.e. it belongs to no - // block in the document — callers must not treat it as addressable. (It can't - // collide with a real block: ids are uuids, and the deterministic test-mode - // generator shares one monotonic counter with real ids.) This is short-lived; - // ProseMirror rebuilds the node view against the real document right after. - // - // The alternatives are worse. Throwing is the crash this exists to prevent. - // Returning an empty placeholder node view can leave the block *permanently* - // blank, since vanilla node views don't implement `update()` and so are only - // rebuilt when something else changes the document. - // - // `createAndFill` rather than `create` so an unexpected node shape yields - // `null` instead of throwing over the top of the original failure. - const standalone = doc.type.schema.nodes["blockContainer"]?.createAndFill( - null, - node, - ); - if (standalone) { - return nodeToBlock(standalone, doc); + // Nothing left to render from. Surface the original failure rather than + // inventing a block that isn't grounded in anything. + throw e; } - - // Nothing left to render from. Surface the original failure rather than - // inventing a block that isn't grounded in anything. - throw positionError; } // Function that wraps the `dom` element returned from 'blockConfig.render' in a