Skip to content

fix: focus ring rendering + light theme regressions (v0.39.1)#4

Merged
mandarwagh9 merged 4 commits into
mainfrom
fix/v0.39.1-focus-ring-light-theme
May 28, 2026
Merged

fix: focus ring rendering + light theme regressions (v0.39.1)#4
mandarwagh9 merged 4 commits into
mainfrom
fix/v0.39.1-focus-ring-light-theme

Conversation

@mandarwagh9

Copy link
Copy Markdown
Owner

Summary

Hotfix on top of v0.39.0 — caught by post-merge headless UI testing in a Playwright Chromium with a Tauri shim.

What broke and how

Focus ring rendered as 1px UA default instead of 2px accent. The v0.39.0 :focus-visible rule used outline: 2px solid var(--accent). Chromium has a long-standing quirk where the UA :focus-visible outline-style: auto 1px ring can't be fully replaced by an author outline-style: solid — the rendered width stays at 1px regardless of !important or specificity. Confirmed via CDP getMatchedStylesForNode: my rule was in the cascade winning specificity, but the engine's computed outline-width stayed at the UA's 1px. Switched the focus indicator from outline to box-shadow. After the fix: every focused interactive element reports box-shadow: rgb(99, 102, 241) 0px 0px 0px 2px — clean 2px accent ring.

Light theme only flipped the outer chrome. The SetupWizard modal stayed dark in light theme because its CSS hardcoded a Catppuccin palette (#1e1e2e, #cdd6f4, #89b4fa, ...). Toast tints similarly used hardcoded RGBA literals. Rewrote both to use design tokens (SetupWizard) and color-mix(in srgb, var(--success) 15%, transparent) (Toast). Verified in both themes.

Test infrastructure added

  • scripts/test-ui-headless.py — Playwright walk through the dev server with a Tauri shim. Catches CSS regressions, focus-ring breakage, missing empty states. Required because TitleBar.tsx calls getCurrentWindow() at module-import — crashes the React tree outside a Tauri runtime; the shim fixes that for testing.
  • scripts/test-pure-logic.mjs — esbuild + Node 30-assertion suite for serial-parsing.ts + ai-pricing.ts.

Follow-up spec

docs/superpowers/specs/2026-05-28-theme-token-sweep.md classifies the remaining 17 component files with hardcoded colors. Category A (replace with tokens) is ~9 files, Category B (intentional palettes like MarkdownRenderer's syntax-highlighting colors) is correct as-is, Category C is TSX inline styles.

Verification

  • npm run check:versions → OK at v0.39.1
  • npm run build → clean
  • cargo clippy --all-targets -- -D warnings → clean
  • cargo test --all-targets → 16/16 passing
  • python scripts/test-ui-headless.py → focus ring 2px confirmed on every Tabbed element, SetupWizard renders correctly in dark + light, Plot view toggle reaches empty state
  • python scripts/test-pure-logic.mjs → 30/30

🤖 Generated with Claude Code

mandarwagh9 and others added 4 commits May 28, 2026 20:57
The v0.39.0 :focus-visible rule used outline-width: 2px solid var(--accent)
but Chromium has a long-standing quirk where the UA :focus-visible
outline-style: auto 1px ring isn't fully replaced by an author
outline-style: solid — the rendered width stays at 1px no matter what
the author specifies. Headless UI testing surfaced this: every focused
button showed a Chromium-default 1px ring instead of the designed 2px
accent ring.

Switch the focus indicator from `outline` to `box-shadow`. box-shadow has
no cascade quirk with the UA layer, is the modern recommendation for
keyboard focus rings, and benefits from the existing component-level
transition: all rules so the ring fades in smoothly on focus.

Verified via the new scripts/test-ui-headless.py: every focused
interactive element now reports box-shadow as exactly
"rgb(99, 102, 241) 0px 0px 0px 2px".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SetupWizard.css had a hardcoded Catppuccin palette (#1e1e2e, #cdd6f4,
#89b4fa, etc), so the first-launch modal stayed dark even when the user
flipped data-theme=light. Headless UI testing caught this: the screenshot
of the wizard in light mode showed it floating dark against a light app.

Rewrite the wizard entirely in --bg-*/--text-*/--accent tokens. Verified
in both themes. The "Skip for now" button (previously caught by my own
:focus-visible test as having a slightly-different focus color) is now
explicitly themed via .setup-btn.skip selector matching the existing
.setup-btn.secondary styling.

Toast.css used hardcoded RGBA values (rgba(52, 211, 153, ...)) for
success/error/warning/info tints. Replace with color-mix(in srgb,
var(--success) 15%, transparent) so the tint follows the status tokens
when the theme flips.

Status sweep: 17 component CSS files still hardcode colors; see
docs/superpowers/specs/2026-05-28-theme-token-sweep.md for the full
classification (Category A = bug, B = intentional like MarkdownRenderer
syntax highlighting, C = TSX inline styles).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scripts/test-ui-headless.py — boots the Vite dev server in headless
Chromium with a Tauri shim, walks through the default view, focus ring,
light theme, Serial sidebar, and Plot view toggle. Captures screenshots
under scripts/ui-screenshots/ (gitignored). Useful for catching CSS
regressions before release. Required the shim because TitleBar.tsx:6
calls getCurrentWindow() at module-import time which crashes the React
tree outside the Tauri runtime.

scripts/test-pure-logic.mjs — compiles serial-parsing.ts and
ai-pricing.ts via esbuild and runs 30 assertions covering CSV/JSON/
key-value parsing, pricing math, and formatter rounding. Catches the
edge cases that are easy to break and hard to spot in a smoke test.

.gitignore — exclude scripts/ui-screenshots/ since those are test
artifacts. The .py/.mjs scripts themselves are tracked.

docs/superpowers/specs/2026-05-28-theme-token-sweep.md — the rest of
the theme audit. 17 component files still have hardcoded hex values;
classifies them into Category A (replace with tokens), B (intentional
domain palettes), C (TSX inline styles) so a future PR can sweep them
mechanically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hotfix on top of v0.39.0 — caught by post-merge headless UI testing:
- fix(design): focus ring rendered as 1px Chromium-UA default instead
  of the designed 2px accent ring (CSS outline quirk; switched to
  box-shadow)
- fix(theme): SetupWizard and Toast had hardcoded color palettes so
  light theme only restyled the outer chrome

Plus tooling additions and the theme-token sweep spec for follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 28, 2026 15:28
@mandarwagh9 mandarwagh9 merged commit 53cef9a into main May 28, 2026
1 check failed
@mandarwagh9 mandarwagh9 deleted the fix/v0.39.1-focus-ring-light-theme branch May 28, 2026 15:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

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