fix(collaboration): render cross-references for late-joining clients (SD-2975)#3211
Conversation
Adds an Editor.collaboration-seed regression test that seeds a doc with a crossReference node, syncs it to a Yjs fragment (including a cached-result run), and verifies a second client hydrating from the room preserves the node's instruction, target, and resolvedText attrs.
…gment Imported Word cross references can carry cached result runs in the shared Yjs XML, but the ProseMirror crossReference node is a leaf atom. When y-prosemirror hydrated the fragment, those extra children caused the node to fail schema validation and not render in collaboration mode. Add normalizeYjsFragmentForSchema to clear children of any crossReference elements before hydration, and invoke it both when creating the sync plugin and when seeding the doc from a fragment in Editor.init.
|
I wasn't granted permission to call the ecma-spec MCP tools, so I'm reviewing against ECMA-376 from working knowledge. The code changes are small enough to assess directly. Status: PASS The new
The two translator changes ( |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2a51835562
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Summary
Fixes SD-2975: cross-references (and citations) not rendering for collaborators who join an active room. Word-imported
crossReference/citationfield nodes carry cached result runs in their inline content, but the ProseMirror schema declares them as leaf atoms — so when y-prosemirror hydrated the shared Yjs XML for a late joiner, the cached children violated the schema and the node failed to materialize.normalize-yjs-fragment.jswalks thesupereditorXML fragment and clears children ofcrossReference/citationXmlElements. Runs beforeyXmlFragmentToProseMirrorRootNodeand viaobserveDeepfor incoming remote events. Runs inside a Yjs transaction with a private origin symbol so the normalizer ignores its own events.resolvedTexton export. Once cached content is stripped, the editor still needs to round-trip something to DOCX. NewbuildFieldResultRunsshared helper rebuilds aw:rwith the node'sresolvedTextattr whennode.contentis empty, applyingxml:space="preserve"for boundary whitespace. BothcrossReference-translator.jsandcitation-translator.jsnow route through it.OpenOptionsaccepts afragment(Y.jsXmlFragment) so callers can hydrate directly from a seeded room; the option is cleared on close to prevent stale fragments leaking across reopens. Pre-hydration normalization is also called inEditor.ts.crossReferencefrom a Yjs room, normalizer cleanup on extension teardown, scoping of the normalizer's own transactions, citation atom-content normalization, and export fallback when cached content has been stripped.