tokens-studio / sd-transforms

Custom transforms for Style-Dictionary, to work with Design Tokens that are exported from Tokens Studio
MIT License
185 stars 28 forks source link

Use of period or underscore in tokens #226

Closed nareshbhatia closed 9 months ago

nareshbhatia commented 9 months ago

What feature would you like?

I am trying to create Tailwind compatible spacing tokens using token names like 1, 1_5 etc.:

{
  spacing: {
    ...
    1: {
      value: '0.25rem',
      type: 'dimension',
      description: '4px',
    },
    '1_5': {
      value: '0.375rem',
      type: 'dimension',
      description: '6px',
    },
    ...
    15: {
      value: '3.75rem',
      type: 'dimension',
      description: '60px',
    },
}

However somewhere in the transformation, spacing.1_5 becomes spacing.15 and I get the following error:

While building vars-always-on-alway-on-tools-standard-dark.css, token collisions were found; output may be unexpected.
    Output name spacing15 was generated by:
        spacing.15   3.75rem
        spacing.1_5   0.375rem

Is there a better way to do this? I am open to using something other than underscore as the separator. The final goal is to produce a tailwind config like this:

module.exports = {
  theme: {
    spacing: {
      '1': '0.25rem',
      '1.5': '0.375rem',
      ...
      '15': '3.75rem',
    }
  }
}

Would you be available to contribute this feature?

nareshbhatia commented 9 months ago

Interesting that the problem goes away when I set casing: 'kebab'.

Now I am getting this output:

--spacing-0: 0px;
--spacing-1: 0.25rem; /* 4px */
--spacing-0-5: 0.125rem; /* 2px */
--spacing-1-5: 0.375rem; /* 6px */

So the only remaining issue is that output is --spacing-0-5 instead of --spacing-0.5. What's the best way to fix this? Token studio does not accept a token name with a period such as 0.5. That's why we chose to enter it as 0_5.

jorenbroekema commented 9 months ago

Style-Dictionary uses a library called change-case to take a token name (established from the token path) and create a string out of it with a specific casing, depending on what you configured -> which name transform you use.

The problem when you have two tokens:

Is that when you convert that to camelCase or PascalCase, it will remove the delimiter character and not give you a new delimiter character in return, and by default that delimiter character is actually _. If you use kebab-case, it gives a new delimiter so it becomes 1-5 and 15 respectively. For snake_case it gives back the delimiter so it remains 1_5 and 15 respectively. This explains why kebab-case and snake_case fixes your issue.

So in conclusion, be careful with using _ characters in your token names if you plan to convert to PascalCase or camelCase, as _ is the delimiter character for parsing strings by change-case library, by default.

If the Studio Tokens plugin doesn't allow using . (probably due to that being a special character for token aliases), maybe file an issue on the plugin https://github.com/tokens-studio/figma-plugin about this.

In the short term you can fix it by creating a custom transform with a custom camelCase transformer:

StyleDictionary.registerTransform({
  name: 'my-custom-cti-camel-case',
  type: 'name',
  transformer: (token, options) => {
    const tokenPathReplace_ = token.path.map(part => part.replace('_', '.'));
    const tokenPath = [options.prefix, ...tokenPathReplace_].map((part, index) => {
      return index < 1 ? part : part.slice(0, 1).toUpperCase() + part.slice(1);
    }).join('');
    return tokenPath;
  }
});

See configurator example

However, note that a . in the variable name in most languages is an illegal character. In your tailwind config you will likely not be using the token name property to construct the final tailwind config file, but rather put the transformed dictionary content inside an object directly. This means a name transform is not useful for you. In this case I would fall back to raising an issue with the plugin to allow . in token names.

nareshbhatia commented 9 months ago

Thank you for the clarification, @jorenbroekema. Given that change-case uses underscore as the default delimiter, we will change the delimiter to a dash, so 0-5, 1-5 etc. I am using the kebab case option, so this will become --spacing-0-5 anyway, which I can live with. I can map it to spacing-0.5 at the tailwind.config.js level.