chore(CardHorizontal): migrate to CSS Modules with visual regression baseline#1039
Conversation
…es migration Captures the current styled-components rendering for color variants (default, muted), size (md, sm), alignment (top), selectable/selected, disabled (with and without isSelected), badge, button, and the hover and focus interactive states (on both selectable and non-selectable cards) under both light and dark themes. These snapshots will be re-asserted byte-for-byte after the CSS Modules migration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Modules Replaces six styled.div templates (Header, Description, Wrapper, CardIcon, ContentWrapper, IconTextContentWrapper) with a single CardHorizontal.module.css + cva/cn. Per-color tokens are exposed as local CSS variables so the state rules (default, hover, active/focus/focus-within, disabled) are written once and consumed by both the default and muted color variants. The DOM tree and every visual state are preserved byte-for-byte against the snapshots captured in the baseline commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: a81f62c The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
These rules feel like they conflict with one another. I don't think we should use the |
| $color={color} | ||
| $size={size} | ||
| $alignment={alignment} | ||
| <div |
There was a problem hiding this comment.
Same question about replacing Wrapper with a div
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…x and aria-disabled
Move {...props} after the hardcoded tabIndex, aria-disabled, and onClick
so consumer-provided values can override them, matching the pre-migration
behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Storybook Preview Deployed✅ Preview URL: https://click-9ikdbhhht-clickhouse.vercel.app Built from commit: |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a81f62c. Configure here.
* docs(skill): codify prop spread order rule for CSS Modules migrations
Spreading {...props} before hardcoded attributes (aria-disabled,
tabIndex, onClick) silently overrides consumer-passed values. The
styled-components version of these components put {...props} last,
so the migration must preserve that order. TypeScript doesn't catch
the regression because HTMLAttributes<...> admits those props.
Caught post-merge on CardPrimary (#1038) and CardHorizontal (#1039).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(skill): codify local CSS variable aliasing for multi-state variants
When a component has color/theme variants that cross many states
(default, hover, active, disabled) and many properties (background,
title, stroke, description), writing one state rule per variant blows
up the file. The pattern adopted in CardHorizontal (#1039) aliases the
long global tokens to short local custom properties inside each color
modifier block, then writes the state rules once on the base class
referencing the short names — the cascade resolves the right value.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Summary
Migrates
CardHorizontalfromstyled-componentsto CSS Modules (cva+cn), following the procedure established by ButtonGroup (PR #1034), IconButton (PR #1036), and CardPrimary (PR #1038) and codified in the `component-css-modules-migration` skill.Two commits, each green on its own:
The migration is a pure styling refactor — no a11y refinements, no type changes, no consumer updates.
Judgment calls to flag
Local CSS variables for color variants. `CardHorizontal` has two color variants (`default`, `muted`) and each appears in four states (default, hover, active/focus, disabled) across four token families (background, title, stroke, description). Instead of emitting a full state matrix per color (≈80 rules), I exposed the per-color tokens as locally-scoped CSS custom properties (`--card-bg-default`, `--card-stroke-active`, etc.) on `.wrapper_color_default` and `.wrapper_color_muted`, then write the state rules once against `var(--card--)`. This kept the stylesheet compact without changing any rendered behavior — confirmed by zero snapshot regeneration.
Scoped `stylelint-disable no-descending-specificity` around the disabled-state block. The disabled rules intentionally come after hover/active rules to mirror the source cascade order. `pointer-events: none` plus `tabIndex=-1` on disabled cards prevent the hover/active rules from ever firing, so the lint complaint is structural rather than behavioral. Scoped narrowly to that block.
Scoped `stylelint-disable-next-line media-feature-range-notation` on the responsive `@media`. The repo's stylelint-config-standard expects modern range notation (`(width <= 768px)`), but `plugin/no-unsupported-browser-features` flags that syntax as unsupported in Edge 102–103, Chrome 102–103, Safari 15.6, etc. The two rules conflict; the prefix notation (`(max-width: 768px)`) is required for browser compatibility per `.browserslistrc`. Single-line disable.
Test plan
🤖 Generated with Claude Code
Note
Low Risk
Styling-only refactor in a single component, guarded by extensive visual snapshots and unchanged public props/types.
Overview
CardHorizontal moves from
styled-componentsto CSS Modules withcva/cnfor variant classes, a newCardHorizontal.module.css(including scoped CSS variables per color and preserved hover/selectable/disabled cascade), and optionalclassNameon the root. Storybook gains dedicated variant stories and dropsstyled-componentsfrom the decorator; a changeset records a patch with no intended behavior change.Tests: Playwright visual regression (
tests/cards/cardhorizontal.spec.ts) covers light/dark variants, hover/focus, and basic a11y (focus +aria-disabled/tabIndex).Reviewed by Cursor Bugbot for commit a81f62c. Bugbot is set up for automated code reviews on this repo. Configure here.