Skip to content

feat(ui): interactive kit charts — hover, highlight, context menu (DASH-2)#146

Merged
eliotlim merged 2 commits into
mainfrom
feat/dash-2-chart-interactivity
Jul 13, 2026
Merged

feat(ui): interactive kit charts — hover, highlight, context menu (DASH-2)#146
eliotlim merged 2 commits into
mainfrom
feat/dash-2-chart-interactivity

Conversation

@eliotlim

Copy link
Copy Markdown
Owner

What

Adds interactivity to the kit chart SVG renderer across all 7 kinds. Board: DASH-2 (Epic: Dashboards). Builds on the DASH-1 registry + DASH-3 data source.

How (shared scaffold, not per-kind)

A ChartInteractionContext + a <Mark datum={{key,label,value}} at={{x,y}}> wrapper carry all behavior; each kind's only change is tagging its datum SVG with <Mark>. All tooltip/highlight/menu logic lives once in ChartBlock. With no live context (static export, provider-less viewer, unit tests) Mark returns children unchanged → byte-identical SVG.

  • Tooltip: HTML overlay in a .obe-chart-plot wrapper, positioned by SVG-coord→percentage, showing label + formatted value. aria-hidden (the focused mark's aria-label announces it).
  • Highlight: hovered/focused mark gets is-active (brightness + stroke ring; line/scatter surface a dot); others is-dim (0.32 opacity). Shared CSS, every kind benefits.
  • Context menu: controlled Radix DropdownMenu anchored at the datum — same menu for right-click and keyboard. Copy value (everywhere, incl. read-only/present) + Change chart kind (radio over chartKinds(), writes the kind prop) gated on !readOnly && !pageLocked && !groupLocked (hidden in viewer/exports/locked groups).

ChartRenderArgs additions (all optional, additive)

interactions? ({markProps}), block?, editor?, width?, height?. The 7 built-ins never read these directly (they use <Mark>); they exist so a future custom kind drawing outside <Mark> can wire its own handlers. Existing kinds + serialized charts render byte-identically.

Accessibility

Each mark is tabIndex=0, role="button", aria-haspopup="menu", aria-label="{label}: {value}"; focus (not just mouse) drives tooltip+highlight; menu via Enter/Space/ContextMenu key + right-click; focus returns to the datum on close.

Scope note

DB-drill ("filter source DB to this group") skipped — the seam is unclean (aggregateDbSeries returns only {value,labels} so the raw group key is lost; useNavigation throws provider-less; view filters are persistent updateView mutations with no navigation-time injection). Reported rather than half-implemented; candidate follow-up. No new chart KINDS (that's DASH-5).

Tests / verify

New chartsInteractive.test.tsx (20): focusable labelled marks + tooltip/highlight + menu (Enter + right-click) + Copy + read-only-gated Change-kind + the additive-contract test (a kind rendered with only {value,labels,palette} produces no .obe-chart-mark). pnpm verify exit 0; @book.dev/ui 111 files / 1015 tests pass.

For the design reviewer (no screenshot — app stand-up is disproportionate)

At rest: identical to before. On hover/focus: a popover-styled tooltip (bordered, --popover bg, soft shadow, muted label + bold tabular value) above the datum; the mark brightens with a thin foreground stroke ring (line/scatter gain a filled dot); other marks fade to ~32%. Right-click/Enter opens a dropdown at the datum: header "label: value", separator, "Copy value", and (when editable) a "Change chart kind" submenu of the registered kinds.

Adds a shared interaction scaffold to the kit chart SVG renderer (DASH-2)
so every registered kind (line/area/bar/pie/donut/scatter/funnel) gets:

- Hover/focus tooltip showing the datum's label + formatted value.
- Highlight: the active mark emphasises, the rest de-emphasise — driven
  by a single `.obe-chart-mark` scaffold, not per-kind duplication.
- A context menu (right-click AND keyboard) with Copy value + Change
  chart kind (via the registry). Change-kind is hidden when the chart is
  read-only / page-locked / group-locked; Copy value stays everywhere.
- Keyboard access: data marks are focusable, focus drives the tooltip,
  and Enter / Space / Menu open the context menu at the datum.

`ChartRenderArgs` grows additively with OPTIONAL `interactions`, `block`,
`editor`, `width`, `height`; a kind wraps each datum in the new `<Mark>`,
which no-ops without a live interaction context — so the static export,
provider-less viewer, and existing/serialized charts render unchanged.

DB drill (filter source DB to hovered group) is intentionally skipped:
the seam isn't clean — `aggregateDbSeries` drops the raw group key,
NavigationContext isn't reachable provider-safely, and view filters are
persistent mutations with no navigation-time injection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFk2T9k3p7ghCjdzMfkA5w
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
app.book.pub Ready Ready Preview, Comment Jul 13, 2026 5:15am

Request Review

- Tooltip no longer escapes the plot at the top edge: it flips below the
  mark (`.obe-chart-tooltip-below`) when the datum is within ~1 row of the
  top (max bar / top scatter point / funnel row 1).
- a11y: the chart svg is `role="group"` (was `role="img"`) so the now
  interactive `role="button"` marks and their `label: value` names stay
  exposed to assistive tech, while the aria-label keeps the accessible name.
- Test: the additive-contract test now covers line/area, asserting the
  true invariant — zero `.obe-chart-mark` wrappers in the no-context path
  while the always-shipped invisible `.obe-chart-dot` hit circles remain.
- Polish: menu icons h-3.5→h-4 (product idiom), menu-anchor left clamped
  with pctIn like the tooltip, and a forced-colors focus outline on
  `.obe-chart-mark:focus-visible`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFk2T9k3p7ghCjdzMfkA5w
@eliotlim eliotlim merged commit e2a4d7a into main Jul 13, 2026
10 checks passed
@eliotlim eliotlim deleted the feat/dash-2-chart-interactivity branch July 13, 2026 05:30
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.

1 participant