feat: @y/prosemirror v2 + @y/y v14 integration#2739
Draft
nperez0111 wants to merge 89 commits into
Draft
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
776ca34 to
5fae30a
Compare
5fae30a to
d70df64
Compare
@blocknote/ariakit
@blocknote/code-block
@blocknote/core
@blocknote/mantine
@blocknote/react
@blocknote/server-util
@blocknote/shadcn
@blocknote/xl-ai
@blocknote/xl-docx-exporter
@blocknote/xl-email-exporter
@blocknote/xl-multi-column
@blocknote/xl-odt-exporter
@blocknote/xl-pdf-exporter
commit: |
00569fc to
38d3e13
Compare
38d3e13 to
a56bb0d
Compare
a9f7067 to
2ad90dc
Compare
a56bb0d to
6b9a6f6
Compare
e44394d to
17ab49f
Compare
6b9a6f6 to
d13fcac
Compare
… conditionally Keep the `y-attributed-*` (Yjs) and `insertion`/`deletion`/`modification` (AI) suggestion marks as completely separate instances, and out of the default schema. Each set is bundled into its own BlockNote extension and loaded only where needed (YSync for Yjs, AIExtension for AI). Block node specs (blockContainer, blockGroup, doc, table cells, columns) no longer hardcode the mark names — they use a `suggestionMarks(this.editor)` helper that returns the shared `blockLevelSuggestion` mark group when any such mark is registered, or "" otherwise (so a plain editor's schema still builds). Marks opt in by declaring `group: BLOCK_LEVEL_SUGGESTION_GROUP` in their spec; ProseMirror expands the group to the member marks. Point the AI agent apply flow at the AI marks instead of the Yjs marks, completing the separation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix lists and headings, disable "deleted" * viz fixes * improve table visualization and clean comments / re-add testcases * add support for attributions in test cases * extract scenarios to gallery, add feedback to scenarios * update screenshots * fix build * run gen * add enterPreview test * blockMatchNodes account for blockgroup (commented out) * fix e2e * fix nesting bugs
The user cache is no longer a BlockNote extension. It's now a plain `createUserStore(resolveUsers)` factory (moved out of `extensions/` to `src/user/`), and the extensions that need it build one and expose it on their instance instead of locating it through the extension registry. - comments & collaboration accept `resolveUsers: callback | UserStore`, normalized via a shared `normalizeToUserStore` helper, so one de-duped store can be shared across comments, suggestions and versioning - CollaborationExtension normalizes once and hands the same store down to YSync (suggestion tooltips + author colors), Suggestions and versioning - YSync suggestion colors now derive from the user store, falling back to the deterministic palette when a user isn't resolved - yhub versioning reads the store off the YSync extension instance - React drops the generic useUsers/useUser hook in favour of a comments-local helper that reads the comments extension's store Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrate the attribution tooltip from an imperative DOM implementation to
the standard BlockNote pattern: the core SuggestionMarksExtension now
drives state through a store and stays agnostic about rendering, while a
React controller subscribes to it and positions the tooltip with
floating-ui (GenericPopover), portaling through a themeable
SuggestionMarksTooltip component slot (mantine/ariakit/shadcn).
Also add an optional getSuggestionMarkClassName collaboration option to
color suggestion marks by change type (e.g. green insertions, red
deletions) instead of by author. It can return a single class (applied to
both the mark content and its tooltip) or { content, tooltip } to style
them independently; when set, the per-user color styling is dropped so the
class fully controls appearance. Default dark-mode suggestion text is now
white for better contrast.
SuggestionMarksExtension's userStore option is now optional
(normalized to an empty store), fixing no-arg call sites (xl-ai).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Yjs `mapAttributionToMark` baked each author's color into the `y-attributed-*` mark attributes, resolved through the user store at sync time. That made the mapper non-deterministic: once a user's real color resolved asynchronously the mapper's output changed for the same (format, attribution) input, so the @y/prosemirror reconcile diff was never empty and fired phantom reconcile dispatches in a loop. Marks now carry only stable identity (`userIds`, plus `format` for the modification mark). Author colors are applied as a reactive ProseMirror decoration layer in SuggestionMarksExtension, resolved from the user store and rebuilt when users/colors resolve (via a store subscription), so colors load independently of the deterministic mark representation. An inline decoration nests inside the mark's content span, so the `--user-color-*` custom properties would land below the paint element. The decoration span therefore carries the `.bn-suggestion-mark(--delete)` paint class itself (and the mark view keeps its own content span structural), so the existing Block.css rules resolve the colors on the element that actually has them. Block-level marks use a node decoration, which lands the properties directly on the painted `.bn-suggestion-node` child, so no CSS changes were needed. When `getSuggestionMarkClassName` supplies an override class, no per-user color decoration is emitted. The suggestion-mark tooltip now resolves its color from the user store (the same helper) instead of the removed `data-user-color-*` attribute. e2e inline snapshots updated to drop the color attrs from the serialized doc; screenshots are unchanged (visual parity confirmed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rename the suggestion-mark presentation/schema surface to a consistent "attribution" vocabulary, distinct from the attribution *managers* that produce the data: - SuggestionMarksExtension -> AttributionExtension (key: "attribution"); the color-decoration + hover-tooltip resolver. - YSuggestionMarksExtension -> YAttributionMarksExtension (key: "yAttributionMarks"), plus its styling API (get/GetSuggestionMarkClassName, resolveSuggestionMarkClassName, SuggestionMarkStyleInfo/ClassNames -> Attribution* equivalents). - SuggestionMarksTooltip component family -> AttributionTooltip across react/mantine/ariakit/shadcn (component, Props, Controller, the Components slot, the suggestionMarksTooltip prop/portal target, and the containing folders). - xl-ai SuggestionMarksExtension -> AttributionMarksExtension (key: "aiAttributionMarks"). No back-compat aliases. Types regenerate on build; all packages typecheck. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the reactive decoration layer that colored the y-attributed-* suggestion marks with per-user CSS custom properties, so coloring no longer depends on async user-store resolution driving a decoration rebuild. The mark wrapper now sets the generic `--user-color-*` properties the Block.css rules read, sourcing them from the author's per-user variable via `var(--user-color-<id>-*, <fallback>)`. AttributionExtension writes those `--user-color-<id>-*` variables on the editor root as users resolve, so the CSS cascade recolors marks from the deterministic palette fallback to the author's own color — no decoration, no doc transaction. This restores the pre-decoration mark-view structure (colors on the wrapper) while keeping the marks color-free in their attrs (the determinism the sync reconcile requires). No CSS changes. The per-user variable name is a fixed-width FNV-1a hash of the id (lib0/hash/fnv1a), safe to embed in a custom-property name. Authors are loaded incrementally: a small plugin scans each doc-changing transaction's changed span (via @tiptap/core `getChangedRanges`, which unlike `Transaction.changedRange()` also covers the mark-only steps suggestion mode adds over existing text). Adds a unit test covering that a change adding an attribution mark loads its author. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move formatChangeLabel out of the core AttributionExtension and into the React layer, where rendering the tooltip's text is a view concern. Core now emits the raw change context (parsed `format` keys) on AttributionTooltipState instead of a pre-baked label, mirroring how getAttributionMarkClassName receives structured info for categorization. The internal grouping key for nested marks becomes an i18n-free `attributionIdentity`. React composes the fully-localized tooltip text — "Inserted by: x", "Deleted by: x", "Formatting change (Bold, Italic) by: x" — via new function-valued `suggestion_changes` dictionary entries, translated across all locales, plus a configurable `formatChangeLabel` for the format list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sentinel
Rework the versioning contract for clarity and consistency:
- Rename endpoint + extension methods to a bare-verb scheme:
updateSnapshotName -> rename, deleteSnapshot -> remove; extension
methods/flags follow (canCreate, canRestore, canRename, canRemove,
canCompare, canPreviewCurrent).
- Rename the two "current" option callbacks to getCurrentDocument
(live handle, Input) and serializeCurrentContent (detached copy,
Output), and generics I/O/A -> Input/Output/Attributions.
- Collapse the current-version sentinel to a single exported
constant: CURRENT_VERSION_ID is now a `unique symbol` used as both
the store sentinel and the synthetic list-entry id (VersionSnapshot.id
widened to `string | typeof CURRENT_VERSION_ID`). Removes the former
CURRENT_VERSION_ENTRY_ID string twin. React derives a local string
key; YHub builds the current entry directly instead of via the
string-typed wire helper.
- Tighten JSDoc across the versioning files (inline-arg docs, less
prose, {@link} cross-references).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an opt-in DiffVersioningExtension (@blocknote/core/y) that renders a read-only diff between two Block[] states with y-attributed-insert/delete marks — the same visual result as the Yjs collaboration adapter, but driven from plain block arrays with no server. Changes are attributed to a static User A / User B via a serverless Y.Attributions store; colors and hover tooltips reuse the composed AttributionExtension. The core inMemoryVersioning preview controller discovers the extension by key (type-only import, so the base @blocknote/core bundle keeps zero runtime @y/* dependency) and delegates diff rendering to it, falling back to a static document swap when it isn't registered. supportsComparison / canCompare are lazy getters gated on the extension's presence, so comparison UI is only offered when a diff can actually be rendered — independent of extension registration order. Move the shared docDiffToDelta and getProseMirrorTrFromYFragment helpers into y/utils.ts and reuse them from the Yjs adapter and snapshot builder. Wire the extension into the 02-versioning example. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…xample snapshotBuilder.ts and seed.ts were only used by the versioning-yjs14 example but shipped in @blocknote/core's output. Move them into the example's src/, drop their exports from the y extension/versioning barrels, and delete their tests (demo-only, no coverage needed). Add @y/prosemirror to the example deps since buildSnapshots uses it directly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Show the version history sidebar by default (no click-to-open), match the wrapper/layout/editor-panel structure used by the collaboration versioning examples, and use the shared VersioningSidebar directly. Drop the Filter dropdown along with the now-unused SettingsSelect/VersionHistorySidebar components and the react-icons dependency. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…w context
A version diff has a single conceptual author — the version that introduced
the changes — not two collaborators. Replace the static User A / User B model
in DiffVersioningExtension with the previewed version's name: renderDiff takes
a version label and attributes the y-attributed-* marks to a synthetic id that
encodes it (`version:<label>`), so each version's tooltip resolves to its own
name (the encoded id also keeps the user-store cache from showing a stale name
when switching comparisons). Tooltips read "…by {versionName}".
Thread the version metadata through a new `context` argument on
PreviewController.enterPreview (the previewed + compared-against snapshots the
extension already has in hand) instead of smuggling a display label through the
getAttributions channel — which is meant for who/when authorship data. The
in-memory controller reads snapshot.name directly, so the synthetic
getAttributions and InMemoryDiffAttribution type are gone.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… into user/ Extract User/UserStore/createUserStore from user/index.ts into user/UserStore.ts, turning index.ts into a barrel. Move userColors.ts out of y/extensions/ (it has no Yjs coupling — it operates on the generic User/UserStore) into user/, alongside the identity types it extends. Repoint the two consumers (AttributionExtension, YAttributionMarks) at the new path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Version snapshots now carry raw author user-ids on a new `by` field instead of a pre-resolved `secondaryLabel` string, and resolving those ids to usernames becomes a view concern: - `VersioningExtension` accepts `resolveUsers` and exposes the normalized `userStore` on its instance (mirroring CommentsExtension); `CollaborationExtension` passes its shared store in. - The YHub endpoints just split the activity `by` field into ids — no more reaching into the attribution extension's user store. `create` stamps the optimistic snapshot with the cursor user's id. - New `useVersionUsers`/`useSnapshotLabel` React hooks (mirroring `useCommentUsers`) resolve `by` ids reactively, so author labels update as user info loads into the store — no re-list needed. - `UserStore` gains `setUser` and resolvers now receive the store, so a resolver can return partial info synchronously and fill in the rest later.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds support for the new
@y/prosemirrorv2 and@y/yv14 (Yjs 14) packages alongside the existing Yjs 13 (yjs,y-prosemirror) integration. This includes new collaboration bindings, versioning extensions, forked document support, and suggestion tracking built on the v14 APIs.Rationale
The
@y/yv14 ecosystem introduces significant improvements over Yjs 13, including better TypeScript support, a new protocol layer, and improved ProseMirror bindings. This PR adds first-class support for v14 while keeping full backward compatibility with Yjs 13.Changes
New
@blocknote/core/yentry point@y/prosemirrorv2 with TipTap/BlockNote@y/prosemirrorv2@y/yv14 APIsVersioning system (
@blocknote/coreextensions)yjspackageVersioningSidebar,Snapshot,CurrentSnapshotEditor improvements
y-attributed-deletemark) to avoid corrupting suggestionsgetBlockInfoFromPosnow handles nodes with marks (suggested changes)moveBlocks,replaceBlocks,splitBlock,nestBlock) to handle marked/attributed nodesPatches
@y/prosemirror@2.0.0-2— extensive patch for BlockNote compatibility@y/y@14.0.0-rc.16— minor patchlib0@1.0.0-rc.13— compatibility patchExamples
Tests
Impact
@y/packages are optional peer dependencies@blocknote/core/yexport for v14 users, parallel to existing@blocknote/core/yjsScreenshots/Video
Live examples:
Checklist