Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lazy-styled-specificity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linaria/react": patch
---

Increase selector specificity when styling React.lazy targets so wrapper styles can override lazy-loaded component CSS.
14 changes: 14 additions & 0 deletions packages/react/src/processors/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ type RawStringLiteral = StringLiteral & {

const staticClassSelector = (className: string): string => `.${className}`;

const isReactLazyValue = (value: unknown): boolean => {
if (typeof value !== 'object' || value === null) {
return false;
}

return (
(value as { $$typeof?: unknown }).$$typeof === Symbol.for('react.lazy')
);
};

const isStaticStyledValue = (value: unknown): value is StaticStyledValue => {
if (typeof value !== 'object' || value === null) {
return false;
Expand Down Expand Up @@ -376,6 +386,10 @@ export default class StyledProcessor extends TaggedTemplateProcessor {
value = value.__wyw_meta.extends;
}

if (isReactLazyValue(value)) {
selector += `.${this.className}`;
}

rules[selector] = {
cssText,
className: this.className,
Expand Down
32 changes: 32 additions & 0 deletions packages/testkit/src/babel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1859,6 +1859,38 @@ describe('strategy shaker', () => {
expect(metadata).toMatchSnapshot();
});

it('adds specificity when wrapping a lazy component', async () => {
const { metadata } = await transform(
dedent`
import { styled } from '@linaria/react';

const lazy = (ctor) => ({
$$typeof: Symbol.for('react.lazy'),
_ctor: ctor,
_status: -1,
_result: null,
});

const Title = styled.h1\`
color: red;
\`;

const LazyTitle = lazy(() => Promise.resolve({ default: Title }));

export const BlueTitle = styled(LazyTitle)\`
color: blue;
\`;
`,
[evaluator]
);

const selector = Object.keys(metadata.wywInJS.rules ?? {}).find((rule) =>
rule.startsWith('.BlueTitle_')
);

expect(selector).toMatch(/^(\.BlueTitle_[^.]+)\1$/);
});

it('handles indirect wrapping another styled component', async () => {
const { code, metadata } = await transform(
dedent`
Expand Down
Loading