Skip to content

Commit 3d5024b

Browse files
fix: correct drop-shadow output format and filter function bugs
1 parent 786f305 commit 3d5024b

File tree

3 files changed

+282
-101
lines changed

3 files changed

+282
-101
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import { render, screen } from "@testing-library/react-native";
2+
import { View } from "react-native-css/components/View";
3+
import { registerCSS, testID } from "react-native-css/jest";
4+
5+
describe("filter: drop-shadow()", () => {
6+
test("basic drop-shadow", () => {
7+
registerCSS(`
8+
.test { filter: drop-shadow(0 4px 6px #000); }
9+
`);
10+
11+
render(<View testID={testID} className="test" />);
12+
const component = screen.getByTestId(testID);
13+
14+
// drop-shadow uses standardDeviation (not blurRadius) to match
15+
// React Native's DropShadowValue type
16+
expect(component.props.style.filter).toStrictEqual([
17+
{
18+
dropShadow: {
19+
offsetX: 0,
20+
offsetY: 4,
21+
standardDeviation: 6,
22+
color: "#000",
23+
},
24+
},
25+
]);
26+
});
27+
28+
test("drop-shadow with color first", () => {
29+
registerCSS(`
30+
.test { filter: drop-shadow(#fb2c36 0 0 24px); }
31+
`);
32+
33+
render(<View testID={testID} className="test" />);
34+
const component = screen.getByTestId(testID);
35+
36+
expect(component.props.style.filter).toStrictEqual([
37+
{
38+
dropShadow: {
39+
color: "#fb2c36",
40+
offsetX: 0,
41+
offsetY: 0,
42+
standardDeviation: 24,
43+
},
44+
},
45+
]);
46+
});
47+
48+
test("drop-shadow without blur", () => {
49+
registerCSS(`
50+
.test { filter: drop-shadow(2px 4px #000); }
51+
`);
52+
53+
render(<View testID={testID} className="test" />);
54+
const component = screen.getByTestId(testID);
55+
56+
expect(component.props.style.filter).toStrictEqual([
57+
{
58+
dropShadow: {
59+
offsetX: 2,
60+
offsetY: 4,
61+
standardDeviation: 0,
62+
color: "#000",
63+
},
64+
},
65+
]);
66+
});
67+
68+
test("drop-shadow from CSS variable", () => {
69+
registerCSS(`
70+
:root { --my-shadow: 0 4px 6px #000; }
71+
.test { filter: drop-shadow(var(--my-shadow)); }
72+
`);
73+
74+
render(<View testID={testID} className="test" />);
75+
const component = screen.getByTestId(testID);
76+
77+
expect(component.props.style.filter).toStrictEqual([
78+
{
79+
dropShadow: {
80+
offsetX: 0,
81+
offsetY: 4,
82+
standardDeviation: 6,
83+
color: "#000",
84+
},
85+
},
86+
]);
87+
});
88+
89+
test("drop-shadow from runtime variable", () => {
90+
registerCSS(
91+
`.test {
92+
--my-shadow: 0 4px 6px #000;
93+
filter: drop-shadow(var(--my-shadow));
94+
}`,
95+
{ inlineVariables: false },
96+
);
97+
98+
render(<View testID={testID} className="test" />);
99+
const component = screen.getByTestId(testID);
100+
101+
expect(component.props.style.filter).toStrictEqual([
102+
{
103+
dropShadow: {
104+
offsetX: 0,
105+
offsetY: 4,
106+
standardDeviation: 6,
107+
color: "#000",
108+
},
109+
},
110+
]);
111+
});
112+
113+
test("drop-shadow with currentcolor resolves to PlatformColor", () => {
114+
registerCSS(
115+
`.test {
116+
--my-shadow: 0 4px 6px currentcolor;
117+
filter: drop-shadow(var(--my-shadow));
118+
}`,
119+
{ inlineVariables: false },
120+
);
121+
122+
render(<View testID={testID} className="test" />);
123+
const component = screen.getByTestId(testID);
124+
125+
// currentcolor resolves to a PlatformColor object — requires
126+
// "color" type (not "string") in the shorthand handler pattern
127+
expect(component.props.style.filter).toStrictEqual([
128+
{
129+
dropShadow: {
130+
offsetX: 0,
131+
offsetY: 4,
132+
standardDeviation: 6,
133+
color: { semantic: ["label", "labelColor"] },
134+
},
135+
},
136+
]);
137+
});
138+
139+
test("Tailwind v4 drop-shadow pattern with @property", () => {
140+
registerCSS(`
141+
@property --tw-drop-shadow { syntax: "*"; inherits: false; }
142+
:root { --drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12); }
143+
.test {
144+
--tw-drop-shadow: drop-shadow(var(--drop-shadow-md));
145+
filter: var(--tw-drop-shadow);
146+
}
147+
`);
148+
149+
render(<View testID={testID} className="test" />);
150+
const component = screen.getByTestId(testID);
151+
152+
expect(component.props.style.filter).toStrictEqual([
153+
{
154+
dropShadow: {
155+
offsetX: 0,
156+
offsetY: 3,
157+
standardDeviation: 3,
158+
color: "#0000001f",
159+
},
160+
},
161+
]);
162+
});
163+
});
164+
165+
describe("filter: opacity()", () => {
166+
test("opacity function produces correct key", () => {
167+
registerCSS(`
168+
@property --tw-opacity { syntax: "*"; inherits: false; }
169+
.test {
170+
--tw-opacity: opacity(0.5);
171+
filter: var(--tw-opacity);
172+
}
173+
`);
174+
175+
render(<View testID={testID} className="test" />);
176+
const component = screen.getByTestId(testID);
177+
178+
// Must produce { opacity: 0.5 }, not { hueRotate: 0.5 }
179+
expect(component.props.style.filter).toStrictEqual([{ opacity: 0.5 }]);
180+
});
181+
});

src/__tests__/vendor/tailwind/filters.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ describe("Filters - Drop Shadow", () => {
6363
[
6464
{
6565
dropShadow: {
66-
blurRadius: 2,
66+
standardDeviation: 2,
6767
color: "#0000001a",
6868
offsetX: 0,
6969
offsetY: 1,
7070
},
7171
},
7272
{
7373
dropShadow: {
74-
blurRadius: 1,
74+
standardDeviation: 1,
7575
color: "#0000000f",
7676
offsetX: 0,
7777
offsetY: 1,
Lines changed: 99 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,99 @@
1-
import { isStyleDescriptorArray } from "react-native-css/utilities";
2-
3-
import type { StyleFunctionResolver } from "../resolve";
4-
import { shorthandHandler } from "../shorthands/_handler";
5-
6-
export const blur: StyleFunctionResolver = (resolveValue, value) => {
7-
const args = resolveValue(value[2]);
8-
return {
9-
blur: (Array.isArray(args) ? args[0] : args) as unknown,
10-
};
11-
};
12-
13-
export const brightness: StyleFunctionResolver = (resolveValue, value) => {
14-
const args = resolveValue(value[2]);
15-
return {
16-
brightness: (Array.isArray(args) ? args[0] : args) as unknown,
17-
};
18-
};
19-
20-
export const contrast: StyleFunctionResolver = (resolveValue, value) => {
21-
const args = resolveValue(value[2]);
22-
return {
23-
contrast: (Array.isArray(args) ? args[0] : args) as unknown,
24-
};
25-
};
26-
27-
export const grayscale: StyleFunctionResolver = (resolveValue, value) => {
28-
const args = resolveValue(value[2]);
29-
return {
30-
grayscale: (Array.isArray(args) ? args[0] : args) as unknown,
31-
};
32-
};
33-
34-
export const hueRotate: StyleFunctionResolver = (resolveValue, value) => {
35-
const args = resolveValue(value[2]);
36-
return {
37-
hueRotate: (Array.isArray(args) ? args[0] : args) as unknown,
38-
};
39-
};
40-
41-
export const invert: StyleFunctionResolver = (resolveValue, value) => {
42-
const args = resolveValue(value[2]);
43-
return {
44-
invert: (Array.isArray(args) ? args[0] : args) as unknown,
45-
};
46-
};
47-
48-
export const sepia: StyleFunctionResolver = (resolveValue, value) => {
49-
const args = resolveValue(value[2]);
50-
return {
51-
sepia: (Array.isArray(args) ? args[0] : args) as unknown,
52-
};
53-
};
54-
55-
export const saturate: StyleFunctionResolver = (resolveValue, value) => {
56-
const args = resolveValue(value[2]);
57-
return {
58-
saturate: (Array.isArray(args) ? args[0] : args) as unknown,
59-
};
60-
};
61-
62-
export const opacity: StyleFunctionResolver = (resolveValue, value) => {
63-
const args = resolveValue(value[2]);
64-
return {
65-
hueRotate: (Array.isArray(args) ? args[0] : args) as unknown,
66-
};
67-
};
68-
69-
const color = ["color", "string"] as const;
70-
const offsetX = ["offsetX", "number"] as const;
71-
const offsetY = ["offsetY", "number"] as const;
72-
const blurRadius = ["blurRadius", "number"] as const;
73-
74-
const handler = shorthandHandler(
75-
[
76-
[offsetX, offsetY, blurRadius, color],
77-
[color, offsetX, offsetY],
78-
[color, offsetX, offsetY, blurRadius],
79-
[offsetX, offsetY, color],
80-
[offsetX, offsetY, blurRadius, color],
81-
],
82-
[],
83-
"object",
84-
);
85-
86-
export const dropShadow: StyleFunctionResolver = (
87-
resolveValue,
88-
func,
89-
get,
90-
options,
91-
) => {
92-
const args = resolveValue(func[2]);
93-
94-
return isStyleDescriptorArray(args)
95-
? {
96-
dropShadow: handler(resolveValue, args, get, options),
97-
}
98-
: undefined;
99-
};
1+
import { isStyleDescriptorArray } from "react-native-css/utilities";
2+
3+
import type { StyleFunctionResolver } from "../resolve";
4+
import { shorthandHandler } from "../shorthands/_handler";
5+
6+
export const blur: StyleFunctionResolver = (resolveValue, value) => {
7+
const args = resolveValue(value[2]);
8+
return {
9+
blur: (Array.isArray(args) ? args[0] : args) as unknown,
10+
};
11+
};
12+
13+
export const brightness: StyleFunctionResolver = (resolveValue, value) => {
14+
const args = resolveValue(value[2]);
15+
return {
16+
brightness: (Array.isArray(args) ? args[0] : args) as unknown,
17+
};
18+
};
19+
20+
export const contrast: StyleFunctionResolver = (resolveValue, value) => {
21+
const args = resolveValue(value[2]);
22+
return {
23+
contrast: (Array.isArray(args) ? args[0] : args) as unknown,
24+
};
25+
};
26+
27+
export const grayscale: StyleFunctionResolver = (resolveValue, value) => {
28+
const args = resolveValue(value[2]);
29+
return {
30+
grayscale: (Array.isArray(args) ? args[0] : args) as unknown,
31+
};
32+
};
33+
34+
export const hueRotate: StyleFunctionResolver = (resolveValue, value) => {
35+
const args = resolveValue(value[2]);
36+
return {
37+
hueRotate: (Array.isArray(args) ? args[0] : args) as unknown,
38+
};
39+
};
40+
41+
export const invert: StyleFunctionResolver = (resolveValue, value) => {
42+
const args = resolveValue(value[2]);
43+
return {
44+
invert: (Array.isArray(args) ? args[0] : args) as unknown,
45+
};
46+
};
47+
48+
export const sepia: StyleFunctionResolver = (resolveValue, value) => {
49+
const args = resolveValue(value[2]);
50+
return {
51+
sepia: (Array.isArray(args) ? args[0] : args) as unknown,
52+
};
53+
};
54+
55+
export const saturate: StyleFunctionResolver = (resolveValue, value) => {
56+
const args = resolveValue(value[2]);
57+
return {
58+
saturate: (Array.isArray(args) ? args[0] : args) as unknown,
59+
};
60+
};
61+
62+
export const opacity: StyleFunctionResolver = (resolveValue, value) => {
63+
const args = resolveValue(value[2]);
64+
return {
65+
opacity: (Array.isArray(args) ? args[0] : args) as unknown,
66+
};
67+
};
68+
69+
const color = ["color", "color"] as const;
70+
const offsetX = ["offsetX", "number"] as const;
71+
const offsetY = ["offsetY", "number"] as const;
72+
const standardDeviation = ["standardDeviation", "number"] as const;
73+
74+
const handler = shorthandHandler(
75+
[
76+
[offsetX, offsetY, standardDeviation, color],
77+
[color, offsetX, offsetY],
78+
[color, offsetX, offsetY, standardDeviation],
79+
[offsetX, offsetY, color],
80+
[offsetX, offsetY, standardDeviation, color],
81+
],
82+
[],
83+
"object",
84+
);
85+
86+
export const dropShadow: StyleFunctionResolver = (
87+
resolveValue,
88+
func,
89+
get,
90+
options,
91+
) => {
92+
const args = resolveValue(func[2]);
93+
94+
return isStyleDescriptorArray(args)
95+
? {
96+
dropShadow: handler(resolveValue, args, get, options),
97+
}
98+
: undefined;
99+
};

0 commit comments

Comments
 (0)