Skip to content

Commit 5cb4bbe

Browse files
claudeskovhus
authored andcommitted
fix: fall back to stylex.props() when sx has no local style refs
The StyleX compiler can only transform the sx prop when it contains at least one reference to a local stylex.create() result. When all styles come from external mixin maps (e.g. $colorMixins.backgroundColor[x]), emit {...stylex.props(...)} instead of sx={...} to ensure styles render. Fixes visual mismatch in theme-indexedLookup, theme-indexedPropClash, and import-react storybook rendering. https://claude.ai/code/session_01EhFJ4W5QixJn7ZLPzMbxPL
1 parent 0d705cd commit 5cb4bbe

File tree

5 files changed

+19
-6
lines changed

5 files changed

+19
-6
lines changed

src/internal/emit-wrappers/style-merger.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,12 @@ export function emitStyleMerging(args: {
174174
!staticClassNameExpr
175175
) {
176176
// When useSxProp is enabled, emit sx={expr} instead of {...stylex.props(expr)}
177-
// Only valid on intrinsic elements (the StyleX babel plugin only processes lowercase tags)
178-
if (emitter.useSxProp && isIntrinsicElement) {
177+
// Only valid on intrinsic elements (the StyleX babel plugin only processes lowercase tags).
178+
// sx requires at least one local styles.* reference for the compiler to recognize;
179+
// fall back to stylex.props() when all styles are external (e.g. mixin map lookups).
180+
const sid = emitter.stylesIdentifier;
181+
const hasLocalRef = styleArgs.some((a) => j([a]).find(j.Identifier, { name: sid }).size() > 0);
182+
if (emitter.useSxProp && isIntrinsicElement && hasLocalRef) {
179183
const sxExpr =
180184
styleArgs.length === 1 && styleArgs[0] ? styleArgs[0] : j.arrayExpression(styleArgs);
181185
return {

src/internal/transform-steps/rewrite-jsx.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,15 @@ export function rewriteJsxStep(ctx: TransformContext): StepResult {
783783
}
784784

785785
const needsMerge = effectiveClassNameAttr !== null || styleAttr !== null;
786-
const useSxProp = ctx.adapter.useSxProp && !needsMerge && isIntrinsicTag;
786+
// sx prop requires at least one local stylex.create() reference so the
787+
// StyleX compiler can verify and transform it. When all styles are external
788+
// (e.g. only extraStylexPropsArgs mixin lookups), fall back to stylex.props().
789+
const stylesId = ctx.stylesIdentifier ?? "styles";
790+
const hasLocalStyleRef = styleArgs.some(
791+
(arg) => j([arg]).find(j.Identifier, { name: stylesId }).size() > 0,
792+
);
793+
const useSxProp =
794+
ctx.adapter.useSxProp && !needsMerge && isIntrinsicTag && hasLocalStyleRef;
787795
const stylexAttr = useSxProp
788796
? (() => {
789797
const sxExpr =

test-cases/import-react.output.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function ThemeSpan(
3434
) {
3535
const { children, variant, ...rest } = props;
3636
return (
37-
<span {...rest} sx={$colorMixins.color[variant]}>
37+
<span {...rest} {...stylex.props($colorMixins.color[variant])}>
3838
{children}
3939
</span>
4040
);

test-cases/theme-indexedLookup.output.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export function TextColor(
4646
) {
4747
const { children, color, ...rest } = props;
4848
return (
49-
<span {...rest} sx={$colorMixins.color[color]}>
49+
<span {...rest} {...stylex.props($colorMixins.color[color])}>
5050
{children}
5151
</span>
5252
);

test-cases/theme-indexedPropClash.output.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from "react";
2+
import * as stylex from "@stylexjs/stylex";
23
import { $colorMixins } from "./lib/colorMixins.stylex";
34

45
type Colors = "labelBase" | "labelMuted";
@@ -9,7 +10,7 @@ type DotProps = React.PropsWithChildren<{
910

1011
function Dot(props: DotProps) {
1112
const { children, colors } = props;
12-
return <div sx={$colorMixins.backgroundColor[colors]}>{children}</div>;
13+
return <div {...stylex.props($colorMixins.backgroundColor[colors])}>{children}</div>;
1314
}
1415

1516
export const App = () => <Dot colors="labelBase">Hello</Dot>;

0 commit comments

Comments
 (0)