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

prefix the all id attributes with a string, random or customisable #731

Open
revelt opened this issue Jun 5, 2022 · 7 comments
Open

prefix the all id attributes with a string, random or customisable #731

revelt opened this issue Jun 5, 2022 · 7 comments

Comments

@revelt
Copy link

revelt commented Jun 5, 2022

🚀 Feature Proposal

Prepend random, set string to each id, so that they're unique per this SVG.

Motivation

When you export multiple SVG from let's say Illustrator, you get same id names, for example #b, #d and so on. They tend to clash, so I have to manually go to the output of svgr and prepend some string to each id value. Can this be automated somehow?

Example

Can we use maybe nanoid or let's say add an input to the GUI sidebar to prepend that string to each id?

Pitch

Because in real-life, more often than not, there will be multiple SVG's on a given page, which, in turn, will have to have unique ids because they're on the same page.

@AlfieJones
Copy link

I actually had a similar issue with one of my projects, and I created a plugin to solve it.

You can find my plugin here https://github.com/AlfieJones/theme-toggles/blob/main/packages/react/plugins/babel-plugin-update-id-attribute.js

@AlfieJones
Copy link

My plugin adds a prop to each component to allow for an id prefix

@revelt
Copy link
Author

revelt commented Jun 8, 2022

@AlfieJones Nice! How cool would it be if the GUI version had this functionality...

@gregberge
Copy link
Owner

I think it is a good addition, let's do it!

@matthew-dean
Copy link

@AlfieJones That's a good start but it only updates the ID for clipPath. URL references for masks, for example, would not work.

@stale
Copy link

stale bot commented Nov 13, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@G1itcher
Copy link

Anyone looking for a now solution for this:

I've taken the current version of @AlfieJones plugin, fixed a bug around Hex values:

const t = require("@babel/core").types;
const template = require("@babel/core").template;

const getValueWithProps = (value, { prefix, suffix }) =>
  `${prefix ? "${props.idPrefix || ''}" : ""}${value}${
    suffix ? "${props.idSuffix || ''}" : ""
  }`;

const isHexValue = (possibleHexValue) => {
  return (
    possibleHexValue[0] === "#" &&
    !isNaN(parseInt(possibleHexValue.slice(1), 16))
  );
};

const getAttributeValue = (value, opts) => {
  let id = "";
  let prefix = "";
  let suffix = "";
  if (value && !isHexValue(value) && value.charAt(0) === "#") {
    id = value.slice(1);
    prefix = "#";
  } else if (value && value.match(/^url\(#/)) {
    id = value.slice(5, -1);
    prefix = "url(#";
    suffix = ")";
  }
  if (id) {
    return t.jsxExpressionContainer(
      template.ast(`\`${prefix}${getValueWithProps(id, opts)}${suffix}\``)
        .expression,
    );
  }
};

const getIdValue = (value, opts) =>
  t.jsxExpressionContainer(
    template.ast(`\`${getValueWithProps(value, opts)}\``).expression,
  );

const plugin = (api, opts) => ({
  visitor: {
    JSXAttribute(path) {
      if (!opts.prefix && !opts.suffix) return;

      const valuePath = path.get("value");
      const namePath = path.get("name");

      const value = valuePath?.container?.value?.value;
      const name = namePath?.container?.name?.name;

      if (name === "id") {
        valuePath.replaceWith(getIdValue(value, opts));
      } else {
        const attr = getAttributeValue(value, opts);
        if (attr) {
          valuePath.replaceWith(attr);
        }
      }
    },
  },
});

module.exports = plugin;

stick it in your svgr config like so:

module.exports = {
  // the rest of your config
  jsx: {
    babelConfig: {
      plugins: [
        [
          path.resolve("./dynamic-ids.js"),
          {
            prefix: true,
          },
        ],
      ],
    },
  },
};

Then you can set a prefix for your IDs via the idPrefix prop on the generated SVG components

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

No branches or pull requests

5 participants