Uh oh!
There was an error while loading. Please reload this page.
fix(charts,core,dashboard): resolve a cartesian drill from the clicked mark, and title it with the series label - #4694
Merged
Conversation
…d mark, and title it with the series label objectui#4672's ruled half and objectui#4682. A chart-level cartesian click is an AXIS interaction, and recharts 3 dispatches those with `activeDataKey` hard-coded undefined — the shared cursor spans every series at that tick. A pivoted chart's drill lookup requires the series, so every segment of every pivoted dashboard chart was a dead click. The mark knows. This renderer draws the Bar / Line / Area, so an item-level onClick closes over the dataKey it was rendered with. Both handlers fire for one gesture (item first, chart second, sharing one nativeEvent), so the item handler records its series stamped with that gesture and the chart-level handler emits the single event: one click, one drill event, and a click landing on no mark falls through to objectui#4680's axis contract byte for byte. The clicked key is forwarded exactly as rendered, '' included — the empty-string second-dimension group draws its own bar since objectui#4673 and '' is falsy. ChartSegmentClickEvent gains `seriesLabel`, and the drill drawer titles itself from `seriesLabel ?? series`. `ev.series` stays the LOOKUP key; only the title reads the label, so an identity-keyed group stops announcing `Backlog / [null]` over a segment the user saw labelled `(None)`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RnQd8iMMUwXQEV1crFmQiQ
The latest updates on your projects. Learn more about Vercel for GitHub. |
This was referenced Aug 15, 2026
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
yinlianghui
marked this pull request as ready for review
August 15, 2026 09:55
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 15, 2026
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.
Fixes#4672
Fixes#4682
Delivers the ruled Option A on #4672 (delegated ruling, comment 5301329590, veto window unvetoed) with its three sub-decisions bound, and folds in #4682 as the same PR's title half.
The dead pivoted drill (#4672)
PR #4680 fixed what a cartesian click can read out of recharts 3's
MouseHandlerDataParam, and measured the wall it could not get past: a chart-level cartesian click is an axis interaction, and recharts dispatches those withactiveDataKeyhard-codedundefined— the shared cursor spans every series at that tick, so the payload names no single one. A pivoted dataset chart (2 dimensions, 1 measure — the shape ADR-0021 introduced) needs the series to resolve its drill row, so every segment of every such dashboard chart stayed a dead click.The mark knows. This renderer draws the
Bar/Line/Area, so an item-levelonClickcloses over the verydataKeyit was rendered with — statically known, not inferred from tooltip state.Premises measured first (section 2 of the dispatch)
Bar's item handler is(item, index, event)and the item carries the row and value.Line/Areaare not typed foronClickat all, and measured they receive(curveProps, event)— two args, the first being the rendered curve's props, not a datum.nativeEventobject.dot={false}line renders.recharts-line-curveand nothing else, so the stroke is its only mark; the item handler fires on it.seriesat all — nothing to add. The pie path sends only the key, so it gainedseriesLabeltoo.What premise A forced
Because line and area item handlers get no datum, an item handler cannot compose the event on its own — it knows its series and nothing about which category. So the item handler does not emit. It records its series, stamped with the gesture, and the chart-level handler (which does know the category, the bucket identity and the row) composes the one event.
That single choice discharges all three bound sub-decisions:
onChartClickbecause there is exactly one emit site, rather than a second event suppressed after the fact. Pinned by a test that goes red against the naive design (item emits directly):expected [ ... ] to have a length of 1 but got 2.categoryId+ the series only where one series is plotted. A line'sdot={false}stroke simply gains the exact series where the stroke is hit; nothing that resolved before stops resolving.Pairing on the shared DOM event rather than on a flag-and-timeout also means a record left by one gesture can never be adopted by a later click — pinned directly.
The
''group (the #4681 tripwire)The clicked key is forwarded exactly as rendered,
''included. The empty-string second-dimension group draws its own bar since #4673 and''is falsy, so a truthiness test on the way out would send no series at all and leave that bar's drill standing on the reader'sString(seriesKey ?? '')coercion instead of on what was clicked. Satisfied by design, not by editing the core pin —chart-series.nullCategory.test.ts'sreads an absent series key as the empty-string group when one existsis untouched and green.The opaque drill title (#4682)
ChartSegmentClickEventgainsseriesLabel, written wherever a handler resolves a series (item-level always, axis-level when unambiguous, pie too), andDatasetWidget.handleChartDrilltitles the drawer fromseriesLabel ?? series.ev.seriesstays the lookup key —findChartSeriesRowresolves it through the same assignmentbuildChartSeriesmade — and only the title reads the label, exactly as the card requires.Neither string can do the other's job, which is why this is a second field rather than a change to the first: the label is not resolvable (it is precisely what the colliding groups share — pinned in core: resolving by the shared label returns
-1) and the key is not showable.The #4680 pin, flipped consciously
leaves the series unresolved when the shared cursor names nonewas written when no cartesian click could resolve a series, and it stood in for all of them. Re-measured rather than assumed: it drives the chart-level handler directly, which is exactly the shape of a click that reached no mark — so its assertion is unchanged and still green, and what it pins is now narrower and still load-bearing (sub-decision 3 verbatim). It is renamed and re-documented to say so, with the complementary mark-click case added in the new file. The pin was not deleted and its assertion did not need to move; the honest result is a scope change, not a red flip.Tests
New:
AdvancedChartImpl.itemSeriesClick.test.tsx(11 cases, real DOM clicks) — the headline case resolved end to end (a real click on a pivoted segment, throughfindChartSeriesRow, to that group's row); every segment to its own group; one-click-one-event; line stroke and area mark; the three additive pins; the''group; and #4682's key-vs-label split. Plus the #4682 consumer tests inDatasetWidget.drillTitleLabel.test.tsxand the field's own core tests.Reverse verification — four legs, each direction predicted before running, all observed as predicted:
Tests 8 failed | 9 passed (17)— exactly the 8 namedto have a length of 1 but got 2ev.seriesexpected 'Backlog / [null]' to be 'Backlog / (None)'seriesLabelfrom coreerror TS2353/TS2339at 5 sitesEach leg restored byte-identically from the commit (
git diff HEADempty).Gate union — all at
1b5365a9a, the final commit, tree cleanpnpm --filter '@object-ui/plugin-charts^...' buildand'@object-ui/plugin-dashboard^...' build— dependency closures, first in the fresh worktreetype-checkfor core / plugin-charts / plugin-dashboard —Scope: 3 of 47 workspace projects, allDone(filters matched; no silent zero-match)pnpm exec vitest run packages/core/ packages/plugin-charts/ packages/plugin-dashboard/—Test Files 174 passed (174)/Tests 2524 passed (2524)eslint --quieton all 7 changed files — cleannode scripts/check-changeset-presence.mjs—7 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)pnpm run check:control-bytes—OK (scanned 4215 tracked text file(s)), plus agrep -naPself-scan of the changed files (no hits)check:phantom-deps—Every in-scope import is declared. The remaining gates (i18n-*,spec-symbols,action-forward-parity,skills-paths) are not implicated by these paths.Scope
AdvancedChartImpl.tsx+ tests;chart-series.tsonly for theseriesLabelfield + its test;DatasetWidget.tsx's title read + tests; one changeset. The in-flight siblings' files (plugin-grid,packages/types/field-types.ts) are untouched. Combo charts were left alone deliberately —ComposedChartis the one cartesian branch that never receives the click props, which is declared behavior and a different defect class; recorded as #4692, unassigned.Generated by Claude Code