Skip to content

fix(styled-jsx): handle top-level & nesting selector correctly in scopeSelector#95

Open
Copilot wants to merge 4 commits into
mainfrom
copilot/investigate-issue-94
Open

fix(styled-jsx): handle top-level & nesting selector correctly in scopeSelector#95
Copilot wants to merge 4 commits into
mainfrom
copilot/investigate-issue-94

Conversation

Copilot AI commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the handling of top-level & (CSS nesting) in scopeSelector. Previously the function had no awareness of :scope pseudo-classes (which lightningcss emits when it flattens a top-level &), so patterns like &:global(.foo) and & .bar produced incorrect or missing scoped selectors.

Changes

src/css.ts

  • Add isScopePseudo helper to detect :scope pseudo-classes emitted by lightningcss when expanding a top-level &
  • Fix &:global() handling: strip any leading :scope (from &) before unwrapping :global(), so &:global(.theme-dark) correctly emits .theme-dark instead of leaving .jsx-HASH:scope
  • Simplify non-global compound handling: instead of a two-step strip-then-insert, replace :scope in-place with the scope class. This means & is substituted directly rather than removed and re-added at a different position
    • &.active.jsx-HASH.active (was .active.jsx-HASH)
    • &.active:hover.jsx-HASH.active:hover (was .active.jsx-HASH:hover)
    • All other & patterns are unaffected: &:hover, &::before, &:not(...), bare &, & .child
  • Update JSDoc comments to describe the new behaviour

Test fixtures

Behaviour notes

The CSS semantics are equivalent in all cases — both .active.jsx-HASH and .jsx-HASH.active require both classes to be present on the element. The change is purely in which position the scope class occupies in the compound selector.

Copilot AI changed the title fix(styled-jsx): replace lone :scope with scope class to fix & :global(...) selectors fix(styled-jsx): & :global(...) selectors compile to dead .jsx-HASH:scope selector Jun 24, 2026
Copilot AI requested a review from sapphi-red June 24, 2026 10:44
Copilot AI changed the title fix(styled-jsx): & :global(...) selectors compile to dead .jsx-HASH:scope selector fix(styled-jsx): strip :scope from all & compound selectors, not just lone :scope Jun 24, 2026
Copilot AI changed the title fix(styled-jsx): strip :scope from all & compound selectors, not just lone :scope Replace two-step &/:scope removal+insertion with single in-place replacement Jun 24, 2026
@sapphi-red sapphi-red changed the title Replace two-step &/:scope removal+insertion with single in-place replacement fix(styled-jsx): handle top-level & nesting selector correctly in scopeSelector Jun 24, 2026
if (globalIdx >= 0) {
// Emit any components before :global() in this compound
// Emit any components before :global() in this compound, skipping any
// leading :scope (originated from `&` — e.g. `&:global(.foo)` → `:scope:global(.foo)`)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's arguable that &:global(.foo) should be .jsx-hash.foo, but I think either is fine as &:global(.foo) is contradictory.

@sapphi-red sapphi-red marked this pull request as ready for review June 24, 2026 12:32
@pkg-pr-new

pkg-pr-new Bot commented Jun 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

@rolldown/plugin-babel

pnpm add https://pkg.pr.new/@rolldown/plugin-babel@95 -D
npm i https://pkg.pr.new/@rolldown/plugin-babel@95 -D
yarn add https://pkg.pr.new/@rolldown/plugin-babel@95.tgz -D

@rolldown/plugin-emotion

pnpm add https://pkg.pr.new/@rolldown/plugin-emotion@95 -D
npm i https://pkg.pr.new/@rolldown/plugin-emotion@95 -D
yarn add https://pkg.pr.new/@rolldown/plugin-emotion@95.tgz -D

@rolldown/plugin-jsx-remove-attributes

pnpm add https://pkg.pr.new/@rolldown/plugin-jsx-remove-attributes@95 -D
npm i https://pkg.pr.new/@rolldown/plugin-jsx-remove-attributes@95 -D
yarn add https://pkg.pr.new/@rolldown/plugin-jsx-remove-attributes@95.tgz -D

oxc-unshadowed-visitor

pnpm add https://pkg.pr.new/oxc-unshadowed-visitor@95 -D
npm i https://pkg.pr.new/oxc-unshadowed-visitor@95 -D
yarn add https://pkg.pr.new/oxc-unshadowed-visitor@95.tgz -D

@rolldown/pluginutils

pnpm add https://pkg.pr.new/@rolldown/pluginutils@95 -D
npm i https://pkg.pr.new/@rolldown/pluginutils@95 -D
yarn add https://pkg.pr.new/@rolldown/pluginutils@95.tgz -D

@rolldown/plugin-styled-jsx

pnpm add https://pkg.pr.new/@rolldown/plugin-styled-jsx@95 -D
npm i https://pkg.pr.new/@rolldown/plugin-styled-jsx@95 -D
yarn add https://pkg.pr.new/@rolldown/plugin-styled-jsx@95.tgz -D

@rolldown/plugin-transform-imports

pnpm add https://pkg.pr.new/@rolldown/plugin-transform-imports@95 -D
npm i https://pkg.pr.new/@rolldown/plugin-transform-imports@95 -D
yarn add https://pkg.pr.new/@rolldown/plugin-transform-imports@95.tgz -D

commit: b9150ba

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants