kristerkari / react-native-svg-transformer

Import SVG files in your React Native project the same way that you would in a Web application.
MIT License
1.58k stars 116 forks source link

Warning while Interpolating animated SVG: '"###.###" is not a valid color or brush' #50

Open andrewtremblay-pear opened 4 years ago

andrewtremblay-pear commented 4 years ago

I am attempting to import svgs from a class template and animating their colors:

My .svgrrc.js:

/* eslint-disable no-shadow */
module.exports = {
  native: true,
  template(
    { template },
    opts,
    {
      imports, componentName, props, jsx, exports,
    },
  ) {
    const flowTpl = template.smart({ plugins: ['flow'] })
    return flowTpl.ast`
      ${imports}
      class ${componentName} extends React.Component<any, any> {
        render () {
          const ${props} = this.props;
          return ${jsx}
        }

      }
      ${exports}
    `;
  },
  dimensions: false,
  replaceAttrValues: {
    color: "{props.color}",
    color1: "{props.color1}",
    color2: "{props.color2}",
    color3: "{props.color3}",
    color4: "{props.color4}",
    color5: "{props.color5}",
    opacity: "{props.opacity}",
    opacity1: "{props.opacity1}",
    opacity2: "{props.opacity2}",
    opacity3: "{props.opacity3}",
    opacity4: "{props.opacity4}",
    opacity5: "{props.opacity5}",
    opt: "{props.opt}",
    opt1: "{props.opt1}",
    opt2: "{props.opt2}",
    opt3: "{props.opt3}",
    opt4: "{props.opt4}",
    opt5: "{props.opt5}"
  }
}

I can then animate the imported svgs like so:

import SmileSvg from './SmileSvg.svg';
const AnimatedSmileSvg = Animated.createAnimatedComponent(SmileSvg);

SmileSvg.svg replaces the named attributes (color, color1, opacity1):

<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect opacity="opacity1" width="80" height="80" rx="40" fill="color1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="..." fill="color"/>
</svg>

However, when I interpolate I get warnings that appear like the following:

"42853378097.68554577" is not a valid number or brush. The color then does not interpolate.

This occurs only on iOS where I have to process the color,

const colorMap = Platform.select({
  ios: {
    enabled: [processColor(COLORS.WHITE), processColor(COLORS.WHITE), 0.2],
    selected: [processColor(COLORS.PRIMARY_TEAL), processColor(COLORS.WHITE), 1],
  }, 
  android: {
    enabled: [COLORS.WHITE, COLORS.WHITE, 0.2],
    selected: [COLORS.WHITE, COLORS.PRIMARY_TEAL, 1],
  },
});
...
export default class GridIcon extends Component<GridIconProps, GridIconState> {
... // GridIcon constructor
this.state = {
      pressAnim: new Animated.Value(0),
};
...
// GridIcon onPress
Animated.timing(
  this.state.pressAnim,
  { toValue, duration: 200 },
);
...
<AnimatedSmileSvg
      color1={this.state.pressAnim.interpolate({
        inputRange: [0, 1],
        outputRange: [colorMap.enabled[0], colorMap.selected[0]],
      }},
      color={this.state.pressAnim.interpolate({
        inputRange: [0, 1],
        outputRange: [colorMap.enabled[1], colorMap.selected[1]],
      }},
      opacity1={this.state.pressAnim.interpolate({
        inputRange: [0, 1],
        outputRange: [colorMap.enabled[2], colorMap.selected[2]],
      })}
/>

Does anyone have a similar issue?

Notes:

Calling useNativeDriver = true on the Animated.timing function causes an invariant violation:

"Attempt to get native tag from node not marked as 'native'"

kristerkari commented 4 years ago

@msand do you have any idea about this one?

msand commented 4 years ago

What versions of react-native and react-native-svg is this? Can you try v9.10.0?

msand commented 4 years ago

The useNativeDriver issue should by fixed by a pr i made which is included in v0.60.0 and later

andrewtremblay-pear commented 4 years ago

Currently on "react-native": "0.59.10" and "react-native-svg": "9.8.3", will try to repro in more recent versions.

Still no clear idea as to the cause but there might be an issue with animating rgba colors against hexadecimal values.

msand commented 4 years ago

I mean v0.61.0

andrewtremblay-pear commented 4 years ago

Still seeing the warning in RN 0.61.5 Listing relevant versions:

    "react": "^16.9.0",
    "react-native": "0.61.5",
    "react-native-svg": "10.1.0",
    "@svgr/plugin-svgo": "^4.3.1",
    "react-native-svg-transformer": "^0.14.3",
sypl commented 3 years ago

I was getting this error, trying to replace "@fill". For some reason the space before the closing tag is important.

This works:

<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.4853 12C21.4853 12.5523 21.0376 13 20.4853 13H3.51472C2.96243 13 2.51472 12.5523 2.51472 12C2.51472 11.4477 2.96243 11 3.51472 11H20.4853C21.0376 11 21.4853 11.4477 21.4853 12Z" fill="@fill" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2.51471C12.5523 2.51471 13 2.96242 13 3.51471L13 20.4853C13 21.0376 12.5523 21.4853 12 21.4853C11.4477 21.4853 11 21.0376 11 20.4853L11 3.51471C11 2.96242 11.4477 2.51471 12 2.51471Z" fill="@fill"/>
</svg>

This doesn't (throws warning "@fill" is not a valid color or brush:

<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.4853 12C21.4853 12.5523 21.0376 13 20.4853 13H3.51472C2.96243 13 2.51472 12.5523 2.51472 12C2.51472 11.4477 2.96243 11 3.51472 11H20.4853C21.0376 11 21.4853 11.4477 21.4853 12Z" fill="@fill" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2.51471C12.5523 2.51471 13 2.96242 13 3.51471L13 20.4853C13 21.0376 12.5523 21.4853 12 21.4853C11.4477 21.4853 11 21.0376 11 20.4853L11 3.51471C11 2.96242 11.4477 2.51471 12 2.51471Z" fill="@fill"/>
</svg>

Can you spot the difference? It's the end of line 2:

Good:

fill="@fill" />

Bad:

fill="@fill"/>

Even weirder is that it doesn't cause a problem on line three, which ends:

fill="@fill"/>