Skip to content

Fix: DocumentEditor open delay by deferring content load#477

Open
urjitc wants to merge 2 commits intomainfrom
capy/defer-editor-content-load
Open

Fix: DocumentEditor open delay by deferring content load#477
urjitc wants to merge 2 commits intomainfrom
capy/defer-editor-content-load

Conversation

@urjitc
Copy link
Copy Markdown
Member

@urjitc urjitc commented Apr 28, 2026

Defer initial content load in DocumentEditor to avoid blocking the modal's open animation with synchronous markdown parsing and KaTeX rendering.

  • Remove content / contentType from useEditor initial options so the editor mounts empty and paints immediately.
  • Use double requestAnimationFrame for the first content load to ensure it runs after the modal's open paint.
  • Subsequent prop changes (e.g., ZeroDB sync) apply synchronously for instant feedback.
  • Re-apply autofocus after deferred initial load to focus at end of content.

Open ENG-074 ENG-074

Summary by CodeRabbit

Release Notes

  • Performance
    • Optimized editor content loading by deferring initial synchronization until after modal rendering completes, improving visual performance and responsiveness.
    • Autofocus now correctly positions the cursor at the end following the initial content load.
    • Subsequent external content changes apply immediately without delay.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
thinkex Ready Ready Preview, Comment Apr 28, 2026 7:04am

Request Review

@urjitc urjitc added the capy Generated by capy.ai label Apr 28, 2026 — with Capy AI
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ca16fadd-2f21-4d16-8e02-57e6602a8c09

📥 Commits

Reviewing files that changed from the base of the PR and between ce9a891 and cca2117.

📒 Files selected for processing (1)
  • src/components/editor/DocumentEditor.tsx

📝 Walkthrough

Walkthrough

Initial editor content was removed from the useEditor hook initialization. Content synchronization now occurs in a dedicated effect that defers the first application until after the modal renders using two requestAnimationFrame calls, compares against live editor state to skip redundant updates, applies subsequent changes immediately, focuses at the end if autofocus is enabled, and cleans up scheduled frames.

Changes

Cohort / File(s) Summary
Editor Content Synchronization
src/components/editor/DocumentEditor.tsx
Refactored initial content loading from hook parameter to dedicated effect with deferred application timing via requestAnimationFrame, maintaining subsequent change reactivity and supporting autofocus positioning at load completion.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hops with glee at timing refined,
Two frames await, content aligned,
No more redundant updates to say,
Focus springs at the end of the day!
Animation deferred, but never in vain,

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: deferring content load to address DocumentEditor's open delay, which is the core change in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch capy/defer-editor-content-load

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Requires human review: Modifying the initialization lifecycle and content synchronization of the core DocumentEditor is a high-impact logic change that requires human review.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 28, 2026

Greptile Summary

This PR optimises DocumentEditor by deferring the initial content load (markdown parsing + KaTeX rendering) until after the modal's open animation by omitting content/contentType from useEditor and scheduling a double requestAnimationFrame in the sync effect. Subsequent prop updates (ZeroDB sync) are applied synchronously via a hasLoadedInitialContentRef flag, and autofocus is re-applied after the deferred load.

Confidence Score: 4/5

Safe to merge with minor style/robustness improvements

No P0/P1 bugs found. Two P2 findings: autofocus being unnecessarily included in the dependency array (causes spurious applyContent calls after initial load) and the hasLoadedInitialContentRef not being reset when the editor instance is recreated. Core animation-deferral logic and rAF cancellation are correct.

src/components/editor/DocumentEditor.tsx — review the effect dependency array and ref reset behaviour

Important Files Changed

Filename Overview
src/components/editor/DocumentEditor.tsx Defers initial content load via double rAF to avoid blocking modal-open animation; two P2 style/robustness issues found (unnecessary autofocus dependency and stale hasLoadedInitialContentRef on editor recreation).

Fix All in Cursor

Reviews (1): Last reviewed commit: "Defer DocumentEditor content load to fix..." | Re-trigger Greptile

if (rafA != null) cancelAnimationFrame(rafA);
if (rafB != null) cancelAnimationFrame(rafB);
};
}, [editor, content, contentType, autofocus]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 autofocus in deps triggers unnecessary applyContent after initial load

autofocus is only consumed in the initial-load rAF branch. Once hasLoadedInitialContentRef.current is true, any change to autofocus re-runs the effect and calls applyContent() — which, for large documents, runs a full JSON.stringify comparison — but never actually re-focuses the editor. Consider reading autofocus through a ref so it can be omitted from the dependency array:

const autofocusRef = useRef(autofocus);
useEffect(() => { autofocusRef.current = autofocus; }, [autofocus]);

// then in the rAF callback:
if (autofocusRef.current) { editor.commands.focus("end"); }

This eliminates spurious applyContent calls while keeping the focus behaviour correct.

Fix in Cursor

Comment on lines +957 to +961
if (hasLoadedInitialContentRef.current) {
// External update (e.g., ZeroDB sync from another tab). Apply immediately.
applyContent();
return;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 hasLoadedInitialContentRef not reset on editor recreation

hasLoadedInitialContentRef is a component-scoped useRef and persists for the lifetime of the component instance. If TipTap's useEditor ever recreates the editor object (e.g. because an extension config prop changes), the effect runs with hasLoadedInitialContentRef.current === true and applies content synchronously on the fresh editor. In most cases this is harmless, but it also means the deferred-paint optimisation is silently bypassed for any editor rebuild. Adding a reset when editor changes would make the behaviour explicit:

useEffect(() => {
  hasLoadedInitialContentRef.current = false;
}, [editor]);

Fix in Cursor

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Requires human review: Modifies the initialization and synchronization timing of a core UI component (DocumentEditor), which requires manual verification to ensure no UI flickering or race conditions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

capy Generated by capy.ai

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant