tokens-studio / sd-transforms

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

Math resolve not done on expressions with inconsistent spacing #251

Open a-petrukhnov opened 6 months ago

a-petrukhnov commented 6 months ago

Hello Here is my tokens example https://codesandbox.io/p/devbox/figma-tokens-8p8ycw

I have few challanges from designers:

  1. They use code like this {borderRadiusDefault} * {badge.sizeSM} / {controlSizeMD} for border-radiuses, which compiles to something like this 48px /2 * 64px / 48px. So I nee to wrap some tokens values in to calc()
  2. They use some number variables that can not be transformed to pixels by default, for example --sdShadowXSm: 0;. So I have to use transformDimension for that tokens.

Default build script works fine, but can not solve my problems. When I tried to write custom transformers (build-tokens.mjs:10), like in commented code in my sandbox, variables naming brokes

For example: --sdShadowXSm: 0; - before transformation --xs: 2px; - after transformation

Can`t understand what I am doing wrong. And how can I do custom transformations and keep variables names safe. Appreciate your help!

jorenbroekema commented 6 months ago

Confirmed bug, minimal reproduction here.

To work around this issue, place ensure that your math operations either don't contain any spaces, or consistently have 1 space before and after operators (like /, * etc). In your case, 48px /2 * 64px / 48px should become 48px / 2 * 64px / 48px by ensuring that your borderRadiusDefault token is 48px / 2 instead of 48px /2

I'll try to fix this but our resolve math utility is a little bit fragile given that we also need to support multi-value tokens, which also happen to use space as separator, this makes the string interpolation we have to do to support both of these features really complicated. I can't guarantee that I'll find a fix 😓

a-petrukhnov commented 6 months ago

Oh, I see it. It works with fixed spaces!

But the main question was about "Custom transforms leads to incorrect variables names" Here is the example https://codesandbox.io/p/sandbox/figma-tokens-transforms-3qktlq

tokens JSON

{
  "shadow": {
    "blur": {
      "xs": {
        "value": "2",
        "type": "number"
      },
      "sm": {
        "value": "{shadow.blur.xs} * 2",
        "type": "number"
      }
    }
  }
}

Builder script

import StyleDictionary from "style-dictionary";
import {
  registerTransforms,
  permutateThemes,
  transforms,
  transformDimension,
} from "@tokens-studio/sd-transforms";

registerTransforms(StyleDictionary);

const config = {
  source: ["./tokens.json"],
  platforms: {
    css: {
      transformGroup: "tokens-studio",
      prefix: "sd",
      buildPath: "./",
      files: [
        {
          destination: "_vars.css",
          format: "css/variables",
        },
      ],
    },
  },
};

const sd = new StyleDictionary(config);
await sd.cleanAllPlatforms();
await sd.buildAllPlatforms();

Compiles to:

:root {
  --sdShadowBlurXs: 2;
  --sdShadowBlurSm: 4;
}

I want to transform these numbers to pixels, so change code of my builder to

import StyleDictionary from "style-dictionary";
import {
  registerTransforms,
  transforms,
  transformDimension,
} from "@tokens-studio/sd-transforms";

StyleDictionary.registerTransform({
  type: "value",
  name: "numbersToPx",
  transitive: true,
  matcher: (token) => token.type === "number",
  transformer: (token) => {
    return transformDimension(token.value);
  },
});

registerTransforms(StyleDictionary);

StyleDictionary.registerTransformGroup({
  name: "custom/tokens-studio",
  transforms: [...transforms, "numbersToPx"],
});

const config = {
  source: ["./tokens.json"],
  platforms: {
    css: {
      transformGroup: "custom/tokens-studio",
      prefix: "sd",
      buildPath: "./",
      files: [
        {
          destination: "_vars.css",
          format: "css/variables",
        },
      ],
    },
  },
};

const sd = new StyleDictionary(config);
await sd.cleanAllPlatforms();
await sd.buildAllPlatforms();

And the output is:

:root {
  --xs: 2px;
  --sm: 4px;
}

So, the name-folding is lost. What I am doing wrong?

jorenbroekema commented 6 months ago

If you use a custom transform group, you'll also need to add a custom name transform e.g. name/cti/kebab:

StyleDictionary.registerTransformGroup({
  name: "custom/tokens-studio",
  transforms: [...transforms, "name/cti/kebab", "numbersToPx"],
});