Skip to content

Commit ffd33dd

Browse files
fix: resolve single box-shadow from runtime CSS variables
When a CSS variable holding a single box-shadow value is resolved at runtime, the shorthand handler receives a flat array of tokens like [0, 4, 6, -1, "#000"]. The handler incorrectly iterates each primitive individually, none match any shadow pattern, and the result is an empty array. Detect flat vs nested arrays before entering the multi-shadow handler. A flat array is a single shadow's tokens that should be passed directly to the pattern handler. A nested array contains multiple shadows for the existing flatMap logic.
1 parent 251cdfc commit ffd33dd

File tree

2 files changed

+115
-13
lines changed

2 files changed

+115
-13
lines changed

src/__tests__/native/box-shadow.test.tsx

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,96 @@ test("shadow values - single nested variables", () => {
2828
});
2929
});
3030

31+
test("single shadow via runtime variable", () => {
32+
registerCSS(
33+
`.test {
34+
--my-shadow: 0 4px 6px -1px #000;
35+
box-shadow: var(--my-shadow);
36+
}`,
37+
{ inlineVariables: false },
38+
);
39+
40+
render(<View testID={testID} className="test" />);
41+
const component = screen.getByTestId(testID);
42+
43+
expect(component.props.style.boxShadow).toStrictEqual([
44+
{
45+
offsetX: 0,
46+
offsetY: 4,
47+
blurRadius: 6,
48+
spreadDistance: -1,
49+
color: "#000",
50+
},
51+
]);
52+
});
53+
54+
test("single shadow via multi-definition variable (theme switching)", () => {
55+
registerCSS(`
56+
:root { --themed-shadow: 0 4px 6px -1px #000; }
57+
.dark { --themed-shadow: 0 4px 6px -1px #fff; }
58+
.test { box-shadow: var(--themed-shadow); }
59+
`);
60+
61+
render(<View testID={testID} className="test" />);
62+
const component = screen.getByTestId(testID);
63+
64+
expect(component.props.style.boxShadow).toStrictEqual([
65+
{
66+
offsetX: 0,
67+
offsetY: 4,
68+
blurRadius: 6,
69+
spreadDistance: -1,
70+
color: "#000",
71+
},
72+
]);
73+
});
74+
75+
test("transparent shadow via runtime variable is filtered", () => {
76+
registerCSS(
77+
`.test {
78+
--my-shadow: 0 0 0 0 #0000;
79+
box-shadow: var(--my-shadow);
80+
}`,
81+
{ inlineVariables: false },
82+
);
83+
84+
render(<View testID={testID} className="test" />);
85+
const component = screen.getByTestId(testID);
86+
87+
expect(component.props.style.boxShadow).toStrictEqual([]);
88+
});
89+
90+
test("multi-shadow via runtime variables (comma-separated)", () => {
91+
registerCSS(
92+
`.test {
93+
--shadow-a: 0 4px 6px -1px #000;
94+
--shadow-b: 0 1px 2px 0 #333;
95+
box-shadow: var(--shadow-a), var(--shadow-b);
96+
}`,
97+
{ inlineVariables: false },
98+
);
99+
100+
render(<View testID={testID} className="test" />);
101+
const component = screen.getByTestId(testID);
102+
103+
expect(component.props.style.boxShadow).toStrictEqual([
104+
{
105+
offsetX: 0,
106+
offsetY: 4,
107+
blurRadius: 6,
108+
spreadDistance: -1,
109+
color: "#000",
110+
},
111+
{
112+
offsetX: 0,
113+
offsetY: 1,
114+
blurRadius: 2,
115+
spreadDistance: 0,
116+
color: "#333",
117+
},
118+
]);
119+
});
120+
31121
test("shadow values - multiple nested variables", () => {
32122
registerCSS(`
33123
:root {

src/native/styles/shorthands/box-shadow.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,32 @@ export const boxShadow: StyleFunctionResolver = (
3434

3535
if (!isStyleDescriptorArray(args)) {
3636
return args;
37-
} else {
38-
return args
39-
.flatMap(flattenShadowDescriptor)
40-
.map((shadows) => {
41-
if (shadows === undefined) {
42-
return;
43-
} else {
44-
return omitTransparentShadows(
45-
handler(resolveValue, shadows, get, options),
46-
);
47-
}
48-
})
49-
.filter((v) => v !== undefined);
5037
}
38+
39+
// A flat array of primitives (e.g. [0, 4, 6, -1, "#000"]) is a single shadow
40+
// resolved from a runtime variable. Pass it directly to the pattern handler.
41+
// A nested array (e.g. [[0, 4, 6, -1, "#000"], [...]]) is multiple shadows.
42+
if (args.length > 0 && !Array.isArray(args[0])) {
43+
const result = handler(resolveValue, args, get, options);
44+
if (result === undefined) {
45+
return [];
46+
}
47+
const filtered = omitTransparentShadows(result);
48+
return filtered !== undefined ? [filtered] : [];
49+
}
50+
51+
return args
52+
.flatMap(flattenShadowDescriptor)
53+
.map((shadows) => {
54+
if (shadows === undefined) {
55+
return;
56+
} else {
57+
return omitTransparentShadows(
58+
handler(resolveValue, shadows, get, options),
59+
);
60+
}
61+
})
62+
.filter((v) => v !== undefined);
5163
};
5264

5365
function flattenShadowDescriptor(arg: StyleDescriptor): StyleDescriptor[] {

0 commit comments

Comments
 (0)