Skip to content

fix(ui): fit the view after React Flow renders the new layout - #523

Merged
zaebee merged 1 commit into
mainfrom
claude/adoring-knuth-m6hrdb
Oct 1, 2026
Merged

zaebee merged 1 commit into
mainfrom
claude/adoring-knuth-m6hrdb

Conversation

@zaebee

@zaebee zaebee commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Found by gemini-code-assist on #522, where it was out of scope for a formatting-only PR.

Problem

useLayoutComputation and useFlowNavigation call fitView synchronously, right after the store update that replaces the nodes (setLayout / setFlow). React Flow has not yet rendered or measured the new nodes, so the fit is computed against the previous view.

The visible symptom: clicking a node to open its flow view leaves the viewport zoomed to the 2× cap on the clicked node, with almost everything else off-screen.

Fix

Both calls are deferred to the next animation frame:

requestAnimationFrame(() => void fitView({ padding: 0.15, duration: 250 }));

Measured in the browser

Chromium via Playwright, against vite dev serving the bundled public/graph.json at a 1280×800 viewport. The script counts the nodes whose bounding box lies fully inside the React Flow pane, 1.2 s after each step (fitView animates for 250 ms). Three runs each, and the results were identical across runs:

step main this PR
initial load 94 / 94 in view, scale 0.197 94 / 94 in view, scale 0.257 (tighter fit)
click node main → flow view 2 / 95 in view, scale 2 (max zoom) 95 / 95 in view, scale 0.257
console errors none none

The initial load was already fully visible on main, but the old fit was looser. It had been computed against stale bounds, too.

Test changed, deliberately

useFlowNavigation.test.ts pinned the synchronous call. It now asserts the fixed contract:

  • fitView is not called in the same tick as setFlow;
  • it is called with the same options once the frame runs.

The test fails against the old hook.

Test plan

  • Playwright before/after measurement above; screenshots were checked visually as well.
  • bun run format:check, lint, typecheck, test:run (119 passed), build all pass.
  • The updated test fails with the old hook restored.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Uv6LUrB5HCQcqBvmcixYn3


Generated by Claude Code

Both fitView calls ran synchronously after the store update that replaces
the nodes (setLayout / setFlow). React Flow had not rendered or measured the
new nodes yet, so the fit was computed against the previous view. Both are now
deferred to the next animation frame.

Measured in Chromium (Playwright) on the bundled graph.json, 3 runs each:
- clicking a node into flow view: main fits 2 of 95 nodes, zoomed to the 2x
  cap on the clicked node; with the fix all 95 are in view.
- initial load: all 94 nodes in view either way, but the fix fits them
  tighter (scale 0.197 -> 0.257), the old fit having included stale bounds.
No console errors in either.

useFlowNavigation.test.ts pinned the synchronous call; it now asserts that
fitView is not called in the same tick and is called, with the same options,
once the frame runs. It fails against the old hook.

Found by gemini-code-assist on #522, where it was out of scope for a
formatting-only change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uv6LUrB5HCQcqBvmcixYn3
@sonarqubecloud

sonarqubecloud Bot commented Oct 1, 2026

Copy link
Copy Markdown

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini is experiencing higher than usual traffic and was unable to create the review. Please try again in a few hours by commenting /gemini review.

@zaebee
zaebee merged commit 7be630f into main Oct 1, 2026
4 checks passed
@zaebee
zaebee deleted the claude/adoring-knuth-m6hrdb branch October 1, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants