Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove color from SVG file to be able to customize it #4

Closed

Conversation

VincentCATILLON
Copy link

This PR adds ability to remove colors from SVG files to be able to define it in React components like this:

Usage

<Bulb width={32} height={32} fill="#00ff00" />

With default transformer

capture d ecran 2018-12-12 a 16 22 54

With color removal

capture d ecran 2018-12-12 a 16 24 56

@VincentCATILLON
Copy link
Author

@kristerkari

I'd like to use a custom transform option in Metro config, but i didn't found how to do it.
If you have any idea, feel free to tell me :)

@kristerkari
Copy link
Owner

thanks @VincentCATILLON! I really like the feature of making it possible to override the color, but I wonder if there is a cleaner way of doing it.

I have also myself tried to get the custom options for Metro to work in React Native, but so far I haven't had any success, so it might not be supported.

SVGR, which is transforming the svg to a React component, has the feature of replacing svg attributes, but it does not seem to do exactly what is needed for this feature because you have to know the color that gets replaced.

I will spend some time thinking of alternative ways of implementing this feature and I will get back to you. In the mean time if you have any ideas of a simpler way of doing it, please let me know! 👍

@VincentCATILLON
Copy link
Author

VincentCATILLON commented Dec 13, 2018

@kristerkari
You're welcome, and thanks for the interest of my incoming PR.

Indeed, we could use the equivalent of remove-attr-values used with @svgr/cli, but with @svgr/core in JS side.
I wonder there is a cleaner way to do this too, my ideas:

  • add to sync() method options the following arg: removeAttrValues instead of doing it by our own way with a regex
  • use a .svgrrc config file, as it's supported by the @svgr/cli package (but don't know about @svgr/core)

@Bill-Niz
Copy link

Bill-Niz commented Apr 18, 2019

@kristerkari Please merge :-)

@mAiNiNfEcTiOn
Copy link

mAiNiNfEcTiOn commented Apr 18, 2019

@VincentCATILLON first of all, thank you for this PR. If it is merged as is, already solves (a part?) of my problem.

However, for the sake of extensibility, I would argue that it would be better to:

  1. Support a new svgrConfig property on the options object
  2. Which would be fully compliant with svgo's configuration object.

I did something locally (which I'd be glad to either see implemented or I can create a PR myself, let me know if you guys are interested) which basically changes the transform to do the following:

index.js

  // in your transform() function in the index.js
  if (filename.endsWith(".svg") || filename.endsWith(".svgx")) {
    const { svgrConfig } = options;
    var jsCode = svgr.sync(src, { ...svgrConfig, native: true });
    return upstreamTransformer.transform({
      src: fixRenderingBugs(jsCode),
      filename,
      options
    });
  }

rn-cli.transformers.js

var upstreamTransformer = require('metro-react-native-babel-transformer');

var cssTransformer = require('react-native-css-transformer');
var svgTransformer = require('react-native-svg-transformer');

module.exports.transform = function({ src, filename, options }) {
  if (filename.endsWith('.css')) {
    return cssTransformer.transform({ src, filename, options });
  } else if (filename.endsWith('.svg')) {
    return svgTransformer.transform({
      src,
      filename,
      options: {
        ...options,
        svgrConfig: {
          plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx'],
          svgAttributes: {
            removeAttrs: { attrs: 'fill' },
            fill: 'currentColor',
          },
          svgoConfig: {
            plugins: { convertColors: { currentColor: true } },
          },
        }
      },
    });
  }
  return upstreamTransformer.transform({ src, filename, options });
};

metro.config.js

const { getDefaultConfig } = require("metro-config");

module.exports = (async () => {
  const {
    resolver: { assetExts, sourceExts }
  } = await getDefaultConfig();

  return {
    transformer: {
      babelTransformerPath: require.resolve("./rn-cli.transformers.js"),
      experimentalImportSupport: false,
      inlineRequires: false,
    },
    resolver: {
      assetExts: assetExts.filter(ext => ext !== "svg"),
      sourceExts: [...sourceExts, "css", "svg"]
    }
  };
})();

So you can see that in the svgTransformer.transform() call I'm passing an extra property called svgrConfig which is then used inside the actual react-native-svg-transformer.

Note: The plugin @svgr/plugin-svgo needs to be installed as well, in order for this to work.

@kristerkari
Copy link
Owner

@mAiNiNfEcTiOn Thanks for the examples of implementing support for the SVGR config.

I had a look at the SVGR source code and it seems that SVGR exposes methods to read the config from any of the supported config formats.

I think that I will look into doing that instead of doing the options passing from the transformer files because that way configuring the SVGR options is way cleaner for the user.

@kristerkari
Copy link
Owner

I opened a Pull Request that adds support for reading SVGR config:
#19

@kristerkari
Copy link
Owner

There's a new version out that supports defining SVGR options in a config file. It does not allow you to do exactly the same thing for the color manipulation as in this PR, but it will be good enough for now.

https://github.com/kristerkari/react-native-svg-transformer/releases/tag/0.13.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants