Uh oh!
There was an error while loading. Please reload this page.
fix(plugin-charts): draw dashboard bars on first paint via one settle re-mount - #2727
Merged
Merged
Conversation
… re-mount Dashboard bar/area/line widgets rendered with axes + labels but NO bars on first mount, only appearing after an unrelated re-render (theme toggle / resize). Root cause is a Recharts entrance-animation race, not a container-size bug: the bar entrance is a requestAnimationFrame tween that starts at height 0 (JavascriptAnimate: `useState(isActive ? 0 : 1)`). Inside a react-grid-layout dashboard the widget's box settles over several frames right after mount, and the tween kicked off during that churn is interrupted before it advances past 0, so the bars stay at height 0. Any later re-render mints a fresh Recharts animationId that re-keys the tween and lets it replay — which is why bars "appear on resize". ChartContainer now watches its own box with a ResizeObserver and, once size changes stop at a positive box (80ms debounce), bumps a `settleNonce` used as the ResponsiveContainer `key` — performing exactly one clean re-mount in a quiet window so the entrance animation runs uninterrupted. One-shot (disconnects after firing), so later resizes stay in-place. The nonce only bumps under a real layout engine, so headless (0x0) test renders are unaffected. Covers every dashboard chart path (they all funnel through ChartContainer) and full-page chart views. Adds ChartContainerImpl.settleRemount.test.tsx. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This was referenced Jul 20, 2026
os-zhuang added a commit
that referenced
this pull request
Jul 20, 2026
…imationActive=false (#2756) (#2759) #2727's settle re-mount tried to *heal* a frozen Recharts entrance animation by re-mounting the ResponsiveContainer once the grid settled. Live (react-grid-layout) that bet doesn't hold: the re-mount can land back in mount-time measurement churn, so the rAF tween — which starts at height 0 — stays stuck there and bars never draw, though axes/labels and the data are present. Reproduced in a real browser on the showcase Chart Gallery dashboard: pre-fix, bars sit at ~0 for 8s+; identical to the reported magic-flow symptom. Fix: dashboard chart widgets render with isAnimationActive={false}, so there is no entrance-animation tween to freeze — bars render at final geometry on the first committed frame, deterministically. With the animation off there is nothing to heal, so ChartContainer skips its settle re-mount (new disableSettleRemount prop), avoiding a needless 1-frame ResponsiveContainer reflow on first paint. Every dashboard chart schema carries the flag (DatasetWidget + DashboardRenderer + DashboardGridLayout, both chart and object-chart); AdvancedChartImpl now honors isAnimationActive uniformly across bar/line/area/pie/funnel/treemap/radar/scatter (funnel/treemap/radar/ scatter previously hard-coded animation on). Standalone chart views keep their entrance animation. Verified end-to-end in a real browser (worktree console → live backend): before = frozen empty bars after 8s, after = bars drawn on first paint, zero console errors, deterministic across fresh navigations and a fresh tab. plugin-charts + plugin-dashboard: 156 tests pass; both type-check. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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 freeto 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.
Problem
Dashboard bar/area/line widgets rendered axes + labels but no bars on first mount, only drawing after an unrelated re-render (theme toggle / resize / re-nav). Reproduced 2026-07-20 on the magic-flow rig (AI CRM
customer_status_dashboard, datasetycde_customer_ds). The analytics query returns 200 with correct rows — it's a frontend mount-time race, not a data bug.Root cause (traced through recharts@3.9.2 source)
Not a container-size bug —
ResponsiveContaineralready null-renders until its RO reports a positive box, which is why the axes/scale paint. The stuck bars are a Recharts entrance-animation race:requestAnimationFrametween that starts at height 0 (JavascriptAnimate:useState(isActive ? 0 : 1)).Bara freshanimationInputref →useAnimationIdmints a new id →<JavascriptAnimate key={animationId}>remounts and replays the tween. That's why bars appear on resize/theme-toggle.Fix
ChartContainer(the single choke point every dashboard chart flows through) watches its own box with aResizeObserver; once size changes stop at a positive box (80 ms debounce), it bumps asettleNonceused askeyon<ResponsiveContainer>→ exactly one clean re-mount after the grid settles, so the entrance animation runs uninterrupted and bars draw on first paint.Tests
ChartContainerImpl.settleRemount.test.tsx: settle → exactly one re-mount; debounces mid-settle resizes into one; never re-mounts under 0×0.plugin-charts32/32 andplugin-dashboard89/89 pass; package builds clean.Verification note
Full live magic-flow visual repro wasn't possible locally — the run-stack rig serves framework's vendored objectui and ignores worktree edits, so browser confirmation needs an objectui SHA-pin bump. Mechanism is confirmed from source + unit tests.
🤖 Generated with Claude Code