Skip to content

chore(CardPrimary): migrate to CSS Modules with visual regression baseline#1038

Open
DreaminDani wants to merge 2 commits into
mainfrom
chore/migrate-cardprimary-css-modules
Open

chore(CardPrimary): migrate to CSS Modules with visual regression baseline#1038
DreaminDani wants to merge 2 commits into
mainfrom
chore/migrate-cardprimary-css-modules

Conversation

@DreaminDani
Copy link
Copy Markdown
Contributor

Summary

Migrates CardPrimary from styled-components to CSS Modules (cva + cn), following the procedure established by ButtonGroup (PR #1034) and IconButton (PR #1036) and codified in the component-css-modules-migration skill.

Two commits, each green on its own:

  • test(CardPrimary): add visual regression baseline before CSS Modules migration — extends the stories with one named story per visual variant (size, alignContent, hasShadow, isSelected, disabled, top-badge, without-button) and adds tests/cards/cardprimary.spec.ts. 26 snapshots captured against the existing styled-components rendering, covering light + dark themes plus hover and focus interactive states.
  • chore(CardPrimary): migrate styling from styled-components to CSS Modules — adds CardPrimary.module.css, rewrites three styled-components in CardPrimary.tsx (Wrapper, Header, Content) and the two in CardPrimaryTopBadge.tsx (TopBadgeWrapper extending Container; CardPrimaryTopBadge extending Badge) with cva + cn. Re-asserts the baseline snapshots byte-for-byte with zero regenerations. withTopBadge.tsx is updated to pass isSelected instead of the former transient $isSelected prop.

The migration is a pure styling refactor — no a11y refinements, no type changes, no consumer updates.

Judgment calls to flag

  1. Specificity bump on icon and title selectors. The original styled-components Header rule & svg { width/height: ... } (specificity 0,1,1) and the Icon component's internal SvgWrapper & svg { width/height: ... } (also 0,1,1) had matching specificity. In the styled-components world the cascade order favored Header's rule; in the CSS Modules world the order shifts and the Icon's default size won, shrinking the rendered icon. I bumped specificity to 0,2,1 using compound selectors (.header.header_size_md svg, .header.header h3). This is the minimal change needed to restore the original rendered behavior — confirmed by zero snapshot regeneration.

  2. Scoped stylelint-disable no-descending-specificity around the disabled-state block. The disabled rules (.wrapper[aria-disabled='true'] button, specificity 0,2,1) are intentionally defined after the hover rules (.wrapper:hover button:active, specificity 0,2,2) to mirror the source styled-components cascade order. pointer-events: none on the disabled wrapper prevents the hover/active rules from ever applying when disabled, so there's no real cascade conflict — the lint complaint is structural, not behavioral. I scoped the disable narrowly to that block rather than touching the repo-wide stylelint config.

Test plan

  • yarn test:visual tests/cards/cardprimary.spec.ts — all 26 snapshots pass against the baseline with zero regenerations after the migration commit.
  • yarn test CardPrimary — unit tests (8) pass unchanged.
  • yarn lint:code src/components/CardPrimary/ — no new errors.
  • yarn lint:css — clean (with the scoped disable noted above).
  • yarn build — succeeds.
  • grep -r 'styled-components' src/components/CardPrimary/ — empty.

🤖 Generated with Claude Code

DreaminDani and others added 2 commits May 19, 2026 18:15
…migration

Captures the current styled-components rendering for size variants
(sm, md), content alignment (start, center, end), shadow, selected,
disabled, top-badge (plain + selected), without-button, and the hover
and focus interactive states 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>
…ules

Replaces the three inline styled.div templates (Wrapper, Header, Content)
in CardPrimary.tsx and the two styled wrappers in CardPrimaryTopBadge.tsx
(TopBadgeWrapper extending Container; CardPrimaryTopBadge extending Badge)
with a single CardPrimary.module.css + cva/cn. The DOM tree and every
visual state are preserved byte-for-byte against the snapshots captured
in the baseline commit.

withTopBadge.tsx is updated to pass isSelected (instead of the former
transient $isSelected prop) since the new CardPrimaryTopBadge no longer
uses styled-components.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 20, 2026

🦋 Changeset detected

Latest commit: 5b0334e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@clickhouse/click-ui Patch

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

@workflow-authentication-public
Copy link
Copy Markdown
Contributor

Storybook Preview Deployed

✅ Preview URL: https://click-ntghyilnv-clickhouse.vercel.app

Built from commit: e25019f9ad27728ead2db935539a171fae75dfab

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