Skip to content

fix(ui): make the sparkline hover-tooltip keyboard-operable#4953

Closed
philluiz2323 wants to merge 1 commit into
JSONbored:mainfrom
philluiz2323:fix/sparkline-keyboard-tooltip
Closed

fix(ui): make the sparkline hover-tooltip keyboard-operable#4953
philluiz2323 wants to merge 1 commit into
JSONbored:mainfrom
philluiz2323:fix/sparkline-keyboard-tooltip

Conversation

@philluiz2323

Copy link
Copy Markdown
Contributor

Closes #3954

What

The shared Sparkline component (now packages/ui-kit/src/components/metagraphed/charts/sparkline.tsx, migrated there from apps/ui/src/components/metagraphed/charts/sparkline.tsx since this issue was filed) drove its per-point value/date tooltip purely from onPointerMove/onPointerLeave. There was no tabIndex, onFocus, or onKeyDown handling, so keyboard-only and screen-reader users got only the single static aria-label summary on the <svg> and never the point-by-point detail mouse users see on hover. This component is reused broadly (concentration-panel.tsx, subnet-history-chart.tsx, neuron-history-chart.tsx, and more).

Changes

  • packages/ui-kit/src/components/metagraphed/charts/sparkline.tsx:
    • The wrapping <div> now gets tabIndex={0} whenever canTooltip is true (same gate the pointer-hover path already uses: interactive && pts.length > 1).
    • onKeyDown handles ArrowRight/ArrowLeft to step the same hover index state the pointer path already drives — so the existing tooltip/dot/guide-line rendering just works for keyboard focus too, with zero duplicated rendering logic.
    • onFocus seeds hover to 0 (first point) so keyboard users get immediate feedback on focus, matching the "step through points" requirement; onBlur clears it, mirroring onPointerLeave.
    • Added an aria-live="polite" visually-hidden (sr-only) span mirroring the same tooltipText used by the visual tooltip, so screen readers announce each point's value/date as the user arrows through — the issue's suggested mechanism.
    • The wrapper's aria-label (only set when canTooltip) now reads "{ariaLabel ?? "Sparkline chart"}, use arrow keys to step through values" — falling back to a generic label for the several real consumers (e.g. subnet-history-chart.tsx) that don't pass an explicit ariaLabel prop, so the focusable element never ships without an accessible name.
    • packages/ui-kit/dist/index.js / dist/index.cjs are regenerated (npm run build --workspace=packages/ui-kit) and committed alongside, per this package's own .gitignore convention — apps/ui consumes it as a live workspace link, not a rebuilt-at-deploy artifact.

Verification across real consumers

Verified interactively (Playwright) against two independent real consumers, not just in isolation:

  • concentration-panel.tsx's reward-drift DriftRow chart (Rewards tab, /subnets/$netuid): focusing the chart announces the first point's value via the aria-live region; stepping ArrowRight through a real 32-point series correctly advances the announced/tooltip value once the underlying data changes (confirmed the value holds flat across a flat data segment, then updates exactly where the real series changes) — proving the index-stepping logic tracks real data, not just re-rendering a static string.
  • subnet-history-chart.tsx's per-metric trend rows (Overview tab): confirmed a second, independently-rendered Sparkline instance (different ariaLabel) is likewise focusable and keyboard-steppable.
  • Confirmed Tab from a focused sparkline moves to the next natural focusable element with no trapping, and mouse-hover behavior (onPointerMove/onPointerLeave) is untouched — same code paths, now also driven by keyboard.

On screenshots

This is a purely interaction-only fix — the sparkline's at-rest (unfocused, non-hovered) rendering is pixel-identical before and after; the only behavior change is what happens when a keyboard user focuses/steps through it, which a static image can't show. Per the repo's screenshot-contract guidance, skipping the static viewport×theme matrix for this reason and providing only the required animated evidence below.

Keyboard interaction (animated)

Target Before After
Reward-drift sparkline, /subnets/19?tab=metagraph (Rewards) before-sparkline-kbd.webm after-sparkline-kbd.webm

(GitHub doesn't inline-render .webm from a raw.githubusercontent.com link in a PR body — click through to view. Before: repeatedly pressing Tab near the chart never reaches or steps through it — only the static SVG summary exists. After: focusing the chart directly and pressing ArrowRight repeatedly visibly moves the guide-line/dot and updates the tooltip through the real series.)

Acceptance criteria

  • sparkline.tsx appears in the diff
  • A keyboard-only user can focus the sparkline and step through points via arrow keys, with each point's value/date exposed to assistive tech (aria-live) as they do
  • Mouse-hover behavior is completely unchanged
  • Verified across two real consumers (concentration-panel.tsx and subnet-history-chart.tsx), not just in isolation
  • Includes a before/after screen recording demonstrating keyboard-driven point stepping

Testing

  • npm run build --workspace=packages/ui-kit + npm run typecheck --workspace=packages/ui-kit: clean.
  • npx eslint on the changed source file: clean aside from pre-existing CRLF noise unrelated to this change.
  • Diff is 3 files (source + 2 regenerated dist bundles), no visual-rendering change at rest.

@philluiz2323 philluiz2323 requested a review from JSONbored as a code owner July 12, 2026 13:51
@superagent-security

Copy link
Copy Markdown

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.93%. Comparing base (7f90522) to head (1ee3151).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4953   +/-   ##
=======================================
  Coverage   97.93%   97.93%           
=======================================
  Files         163      163           
  Lines       19389    19389           
  Branches     7364     7364           
=======================================
  Hits        18989    18989           
  Misses         53       53           
  Partials      347      347           
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gittensory-orb gittensory-orb Bot added the gittensor:bug Gittensor-scored bug fix or unsolicited PR — scores a 0.05x multiplier. label Jul 12, 2026
@gittensory-orb

gittensory-orb Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Caution

🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥

🛑 Gittensory review result - fixes required

Review updated: 2026-07-12 14:01:31 UTC

3 files · no blockers · readiness 100/100 · CI failing · unstable

🛑 Suggested Action - Fix Blockers

  • AI review already in progress for this PR head: Another Gittensory pass is already running the AI review for this exact PR head. This pass is skipping to avoid a duplicate LLM call.

Review summary
AI review is already running for this PR head in another Gittensory pass. Gittensory is holding this PR for manual review until that pass completes.

Nits — 2 non-blocking
  • Code changes lack test evidence — Add focused regression tests or explain why existing coverage is sufficient.
  • AI review already in progress for this PR head — The gate is held for a human reviewer rather than passed automatically; it re-evaluates once the in-flight review completes or on the next update.

CI checks failing

  • checks
  • ui
Signal Result Evidence
Code review ✅ No blockers No AI review summary
Linked issue ✅ Linked #3954
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 1090 registered-repo PR(s), 663 merged, 127 issue(s).
Contributor context ✅ Confirmed Gittensor contributor philluiz2323; Gittensor profile; 1090 PR(s), 127 issue(s).
Gate result ⚠️ Not blocking Advisory; not blocking this PR.
Review context
  • Author: philluiz2323
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: not available
  • Official Gittensor activity: 1090 PR(s), 127 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
[BETA] Chat with Gittensory

Ask Gittensory a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @gittensory ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @gittensory chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @gittensory mention with a real question is routed to the closest matching read-only command automatically -- no exact syntax required.

Full command reference: https://gittensory.aethereal.dev/docs/gittensory-commands

Visual preview
Route Viewport Before (production) After (this PR's preview) Diff
/ desktop before / after /
/ mobile before / (mobile) after / (mobile)

Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.

  • Re-run Gittensory review

@gittensory-orb

Copy link
Copy Markdown
Contributor

Gittensory is closing this pull request on the maintainer's behalf (CI is failing (checks, ui)). This is an automated maintenance action — to pursue this change, please open a new pull request with the issues resolved. Closed PRs may be analyzed later to improve review accuracy, but they are not automatically reopened or re-reviewed.

@gittensory-orb gittensory-orb Bot closed this Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix or unsolicited PR — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sparkline hover-tooltip has no keyboard equivalent

1 participant