Skip to content

⚠️ [WB-2327] Phase 3 — Port wonder-blocks-styles action styles to a CSS mixin#3100

Draft
jandrade wants to merge 1 commit into
deploy/css-modulesfrom
WB-2327
Draft

⚠️ [WB-2327] Phase 3 — Port wonder-blocks-styles action styles to a CSS mixin#3100
jandrade wants to merge 1 commit into
deploy/css-modulesfrom
WB-2327

Conversation

@jandrade
Copy link
Copy Markdown
Member

@jandrade jandrade commented Jun 3, 2026

Adds a CSS-mixin counterpart to the actionStyles JS export so CSS
Modules authors can opt into the same interactive-control styling
without Aphrodite (Phase 3 of the CSS Modules migration). The change is
purely additive — the existing Aphrodite-shaped actionStyles /
focusStyles JS exports are unchanged and remain available for packages
that have not migrated, so no consumer is affected.

Issue: WB-2327

Test plan:

Automatically verified:

  • pnpm build succeeds end-to-end (tokens CSS regenerated).
  • pnpm typecheck clean.
  • pnpm lint:css / stylelint clean on the new CSS.
  • pnpm jest __docs__/css-modules-spike passes (incl. the new inverse
    assertion).
  • Storybook story tests for Default and WithBadge pass. These render
    the same spike.module.css that now imports action-styles.css and
    applies @apply --wb-action-inverse, so their passing proves the
    mixin (including the nested @apply --wb-focus-visible) resolves and
    expands end-to-end through Vite/PostCSS.

Manual (one item):

  • Open Storybook and view the new Inverse spike story
    (tools-css-modules-spike--inverse) at http://localhost:6061/. Tab to
    the button and confirm the focus ring shows under :focus-visible, and
    that hover/active states render on the dark backdrop. This story's own
    runner pass could not be captured because the running Storybook had not
    re-indexed the new export and a restart hit an environment file-handle
    limit (EMFILE) unrelated to the change.

Review plan:

Please review these risky changes

  1. ⚠️ action-styles.css

Common patterns:

1 File: Mirror an Aphrodite-shaped JS style export as a source-distributed CSS mixin, following the focus-styles.css precedent — the JS object's pseudo-state keys become nested & selectors and token references become --wb-* CSS variables.

  // action-styles.ts (kept, unchanged)
  export const inverse = {
      ":hover:not([aria-disabled=true])": {
          color: semanticColor.core.foreground.knockout.default,
      },
      ...focus,
  };

+ /* action-styles.css (new) */
+ @mixin --wb-action-inverse() {
+     &:hover:not([aria-disabled="true"]) {
+         color: var(--wb-semanticColor-core-foreground-knockout-default);
+     }
+     &:focus-visible {
+         @apply --wb-focus-visible;
+     }
+ }

1 File (consumer integration): Import a cross-package mixin into a *.module.css and apply it with @apply, proving end-to-end expansion.

+ @import "@khanacademy/wonder-blocks-styles/action-styles.css";
+
+ .inverse {
+     @apply --wb-action-inverse;
+ }

🤖 Built using Claude Code #ai-generated

…SS mixin

Adds a CSS-mixin counterpart to the `actionStyles` JS export so CSS
Modules authors can opt into the same interactive-control styling
without Aphrodite (Phase 3 of the CSS Modules migration). The change is
purely additive — the existing Aphrodite-shaped `actionStyles` /
`focusStyles` JS exports are unchanged and remain available for packages
that have not migrated, so no consumer is affected.

Issue: WB-2327

## Test plan:

Automatically verified:
- `pnpm build` succeeds end-to-end (tokens CSS regenerated).
- `pnpm typecheck` clean.
- `pnpm lint:css` / stylelint clean on the new CSS.
- `pnpm jest __docs__/css-modules-spike` passes (incl. the new inverse
  assertion).
- Storybook story tests for `Default` and `WithBadge` pass. These render
  the same `spike.module.css` that now imports `action-styles.css` and
  applies `@apply --wb-action-inverse`, so their passing proves the
  mixin (including the nested `@apply --wb-focus-visible`) resolves and
  expands end-to-end through Vite/PostCSS.

Manual (one item):
- Open Storybook and view the new `Inverse` spike story
  (`tools-css-modules-spike--inverse`) at http://localhost:6061/. Tab to
  the button and confirm the focus ring shows under `:focus-visible`, and
  that hover/active states render on the dark backdrop. This story's own
  runner pass could not be captured because the running Storybook had not
  re-indexed the new export and a restart hit an environment file-handle
  limit (EMFILE) unrelated to the change.

## Review plan:

Please review these risky changes

1. ⚠️ `packages/wonder-blocks-styles/src/styles/action-styles.css`: New `@mixin --wb-action-inverse()` in a published shared library, mirroring `actionStyles.inverse`. It expands into nested `:hover` / `:focus-visible` / `:active` rules and reuses `--wb-focus-visible`. Source-distributed (raw, like `focus-styles.css`) so the mixin survives un-expanded until the consumer build. Additive only; JS exports unchanged.

### Common patterns:

**1 File:** Mirror an Aphrodite-shaped JS style export as a source-distributed CSS mixin, following the `focus-styles.css` precedent — the JS object's pseudo-state keys become nested `&` selectors and token references become `--wb-*` CSS variables.

```diff
  // action-styles.ts (kept, unchanged)
  export const inverse = {
      ":hover:not([aria-disabled=true])": {
          color: semanticColor.core.foreground.knockout.default,
      },
      ...focus,
  };

+ /* action-styles.css (new) */
+ @mixin --wb-action-inverse() {
+     &:hover:not([aria-disabled="true"]) {
+         color: var(--wb-semanticColor-core-foreground-knockout-default);
+     }
+     &:focus-visible {
+         @apply --wb-focus-visible;
+     }
+ }
```

**1 File (consumer integration):** Import a cross-package mixin into a `*.module.css` and apply it with `@apply`, proving end-to-end expansion.

```diff
+ @import "@khanacademy/wonder-blocks-styles/action-styles.css";
+
+ .inverse {
+     @apply --wb-action-inverse;
+ }
```
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 3, 2026

🦋 Changeset detected

Latest commit: e45aa52

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

This PR includes changesets to release 20 packages
Name Type
@khanacademy/wonder-blocks-styles Minor
@khanacademy/wonder-blocks-badge Patch
@khanacademy/wonder-blocks-button Patch
@khanacademy/wonder-blocks-card Patch
@khanacademy/wonder-blocks-cell Patch
@khanacademy/wonder-blocks-date-picker Patch
@khanacademy/wonder-blocks-dropdown Patch
@khanacademy/wonder-blocks-form Patch
@khanacademy/wonder-blocks-icon-button Patch
@khanacademy/wonder-blocks-link Patch
@khanacademy/wonder-blocks-modal Patch
@khanacademy/wonder-blocks-pill Patch
@khanacademy/wonder-blocks-popover Patch
@khanacademy/wonder-blocks-switch Patch
@khanacademy/wonder-blocks-tabs Patch
@khanacademy/wonder-blocks-banner Patch
eslint-plugin-wonder-blocks-demo Patch
@khanacademy/wonder-blocks-birthday-picker Patch
@khanacademy/wonder-blocks-search-field Patch
@khanacademy/wonder-blocks-tooltip 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

@@ -0,0 +1,85 @@
/*
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

⚠️ 1 of 1: New @mixin --wb-action-inverse() in the published wonder-blocks-styles shared library, mirroring actionStyles.inverse. It expands into nested :hover / :focus-visible / :active rules and reuses --wb-focus-visible. Source-distributed (raw, like focus-styles.css) so the @mixin survives un-expanded until the consumer build runs its own postcss-import → postcss-mixins chain. Additive only — the existing Aphrodite-shaped JS exports are untouched, so no consumer is affected.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

Size Change: 0 B

Total Size: 129 kB

ℹ️ View Unchanged
Filename Size
packages/eslint-plugin-wonder-blocks/dist/es/index.js 7.18 kB
packages/wonder-blocks-accordion/dist/es/index.js 3.02 kB
packages/wonder-blocks-announcer/dist/es/index.js 2.43 kB
packages/wonder-blocks-badge/dist/es/index.js 2.03 kB
packages/wonder-blocks-banner/dist/es/index.js 2.01 kB
packages/wonder-blocks-birthday-picker/dist/es/index.js 1.93 kB
packages/wonder-blocks-breadcrumbs/dist/es/index.js 761 B
packages/wonder-blocks-button/dist/es/index.js 4.28 kB
packages/wonder-blocks-card/dist/es/index.js 1.09 kB
packages/wonder-blocks-cell/dist/es/index.js 2.19 kB
packages/wonder-blocks-clickable/dist/es/index.js 2.61 kB
packages/wonder-blocks-core/dist/es/index.js 2.6 kB
packages/wonder-blocks-data/dist/es/index.js 5.48 kB
packages/wonder-blocks-date-picker/dist/es/index.js 8.06 kB
packages/wonder-blocks-dropdown/dist/es/index.js 19.7 kB
packages/wonder-blocks-form/dist/es/index.js 6.32 kB
packages/wonder-blocks-grid/dist/es/index.js 1.25 kB
packages/wonder-blocks-icon-button/dist/es/index.js 4.01 kB
packages/wonder-blocks-icon/dist/es/index.js 1.95 kB
packages/wonder-blocks-labeled-field/dist/es/index.js 3.48 kB
packages/wonder-blocks-layout/dist/es/index.js 1.69 kB
packages/wonder-blocks-link/dist/es/index.js 1.54 kB
packages/wonder-blocks-modal/dist/es/index.js 7.36 kB
packages/wonder-blocks-pill/dist/es/index.js 1.31 kB
packages/wonder-blocks-popover/dist/es/index.js 4.41 kB
packages/wonder-blocks-progress-spinner/dist/es/index.js 1.48 kB
packages/wonder-blocks-search-field/dist/es/index.js 1.1 kB
packages/wonder-blocks-styles/dist/es/index.js 464 B
packages/wonder-blocks-switch/dist/es/index.js 1.55 kB
packages/wonder-blocks-tabs/dist/es/index.js 5.46 kB
packages/wonder-blocks-testing-core/dist/es/index.js 3.25 kB
packages/wonder-blocks-testing/dist/es/index.js 978 B
packages/wonder-blocks-theming/dist/es/index.js 384 B
packages/wonder-blocks-timing/dist/es/index.js 1.53 kB
packages/wonder-blocks-tokens/dist/es/index.js 5.4 kB
packages/wonder-blocks-toolbar/dist/es/index.js 921 B
packages/wonder-blocks-tooltip/dist/es/index.js 6.06 kB
packages/wonder-blocks-typography/dist/es/index.js 1.58 kB

compressed-size-action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

npm Snapshot: Published

🎉 Good news!! We've packaged up the latest commit from this PR (f7c4143) and published all packages with changesets to npm.

You can install the packages in frontend by running:

./dev/tools/deploy_wonder_blocks.js --tag="PR3100"

Packages can also be installed manually by running:

pnpm add @khanacademy/wonder-blocks-<package-name>@PR3100

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

A new build was pushed to Chromatic! 🚀

https://5e1bf4b385e3fb0020b7073c-lyphbtfmai.chromatic.com/

Chromatic results:

Metric Total
Captured snapshots 0
Tests with visual changes 0
Total stories 849
Inherited (not captured) snapshots [TurboSnap] 479
Tests on the build 479

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