Repository navigation
Match functional colors against the whole string in normalize-colors - #59103
YevheniiKotyrlo wants to merge 1 commit into
Conversation
normalize-colors anchors its hex matchers but not rgb, rgba, hsl, hsla and hwb, so a string that only contains one of those calls normalizes to that color. AnimatedInterpolation reads an output range that normalizes as a color, so a JS-driven interpolation of a box shadow such as `inset 0 0 0 1px rgba(124, 58, 237, 1)` returns the bare color, which processBoxShadow parses to no shadow at all. Anchor the five functional matchers, as the hex ones already are.
Device evidence — before / afterUNFIXED — the interpolated box shadow collapses to its bare FIXED — the views draw the ring at the interpolated alpha.
RNTester release builds for Device evidence — before / after, recordedUNFIXED — no frame draws the ring. FIXED — the ring follows the interpolation, from alpha 1 to 0.7 and back every second. Left: Scenefunction AnimatedInterpolatedBoxShadowExample() {
const progress = React.useRef(new Animated.Value(0)).current;
React.useEffect(() => {
const loop = Animated.loop(
Animated.timing(progress, {
toValue: 1,
duration: 1000,
easing: Easing.linear,
useNativeDriver: false,
}),
);
loop.start();
return () => loop.stop();
}, [progress]);
const boxShadow = progress.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [
'inset 0 0 0 3px rgba(124, 58, 237, 1)',
'inset 0 0 0 3px rgba(124, 58, 237, 0.7)',
'inset 0 0 0 3px rgba(124, 58, 237, 1)',
],
});
return (
<View style={{flexDirection: 'row', flexWrap: 'wrap', gap: 12, padding: 8}}>
{Array.from({length: 24}, (_, index) => (
<Animated.View
key={index}
style={{
width: 48,
height: 48,
borderRadius: 8,
backgroundColor: '#e5e7eb',
boxShadow,
}}
/>
))}
</View>
);
} |



Summary:
@react-native/normalize-colorsanchors its hex matchers but notrgb,rgba,hsl,hslaandhwb, so a string that only contains one of those calls normalizes to that color:normalizeColor('xxrgb(1, 2, 3)yy')is0x010203ff(#58495).Animated pays for it.
AnimatedInterpolationtreats an output range that normalizes as a color as a color, so a JS-driven interpolation of a box shadow such asinset 0 0 0 1px rgba(124, 58, 237, 1)returns the barergba(…), whichprocessBoxShadowparses to no shadow at all.This anchors the five functional matchers, as the hex ones already are. It is the change #58496 proposed before its author closed it.
Changelog:
[GENERAL] [FIXED] - An Animated interpolation of a string that contains an
rgb(),hsl()orhwb()color, such as a box shadow, interpolates the whole string instead of collapsing to the colorTest Plan:
normalizeColor-test.jsgains a case for strings that only contain a functional color, which returned16909311for'xxrgb(1, 2, 3)yy'before the change.Interpolation-itest.jsgains a box-shadow range, which returned'rgba(124, 58, 237, 1)'before the change and now answers'inset 0 0 0 2px rgba(124, 58, 237, 0.75)'halfway.yarn jest packages/normalize-color packages/react-native/Libraries/Animated packages/react-native/Libraries/StyleSheet: 80 passedyarn flow check: no errorseslintandprettier --checkon the three files: cleanUnder Fantom, this PR's CI run passes
Interpolation-itest.jsandnormalizeColor-itest.js.