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

cross-file token/token-group collision #275

Open dick-jo opened 3 months ago

dick-jo commented 3 months ago

What happened?

My design system derives the majority of it's colours from a single primary hue and generates a theme around that using lch colour space. All luminosity, chroma, and hue values are split up atomically like so:

    "secondary": {
      "luminosity": {
        "value": "{clr.luminosity.schedule.3}",
        "type": "other",
        "description": "{clr.luminosity.schedule.2}"
      },
      "chroma": {
        "value": "{clr.primary.chroma}",
        "type": "other"
      },
      "hue": {
        "value": "{clr.primary.hue} + {clr.secondary.mix}",
        "type": "other"
      },
      "mix": {
        "value": "{clr.mixer} * -1",
        "type": "other"
      }
    },

...the arithmetic in hue uses a mix property for users to adjust how distinct or similar the derived colours are from the seed colour.

They are then combined into actual colours like:

    "secondary": {
      "value": "lch({clr.secondary.luminosity}, {clr.secondary.chroma}, {clr.secondary.hue})",
      "type": "color",
      "$extensions": {
        "studio.tokens": {
          "modify": {
            "type": "alpha",
            "value": "1",
            "space": "lch"
          }
        }
      }
    },

..however when I build with ts/resolveMath, whilst math is resolved as expected in other tokens, these lch colour tokens are output as ie --clr-secondary: lch(72%, 14, 298 + 120 * -1);

Reproduction

    source: ['./theme/*.json'],
    platforms: {
        css: {
            transformGroup: 'tokens-studio',
            transforms: ['name/kebab', 'ts/resolveMath', 'ts/color/modifiers'], 
            buildPath: 'build/css/',
            files: [
                {
                    destination: 'variables.css',
                    format: 'css/variables'
                }
            ]
        }
    }

Expected output

--clr-secondary: lch(72%, 14, 298 + 120 * -1); should be -> --clr-secondary: lch(72%, 14, 178);

...this is rendered correctly in figma, but doesn't seem to be able to transform correctly for style-dictionary.

Version

0.15.2

jorenbroekema commented 3 months ago

Could you try to reproduce it in the configurator? My reproduction seems to create the desired output: lch(72 14 178).

I also tried to reproduce it in an integration test in sd-transforms itself and there I also get the desired output

dick-jo commented 3 months ago

Thanks kindly for your diligence @jorenbroekema

I tested based on your reproduction a bit and was scratching my head trying to replicate the issue for a minute there, however I have successfully reproduced the issue

It appears everything resolves correctly until I split the resolved colours off into a seperate .json, which then causes the math resolve to fail.

The logic here is that in this design system, resolved colours (represented in resolved-color.json here) as well as other similarly resolved design tokens live in a dictionary.json which the user doesn't need to touch, I merely expose minimal relevant customisable tokens in other discrete files such as color.json, text.json etc.

Is there some additional handling I'm neglecting to achieve this pattern?

jorenbroekema commented 2 months ago

I think I know what the problem is, loading all the input files for style-dictionary, it merges everything into a single dictionary structure.

{
  foo: {
    bar: {
      value: ...
    }
  }
}

merged with:

{
  foo: {
    value: ...
  }
}

Is essentially what you're doing in that reproduction, merging a token with a token group on the same name. I think this issue can be worked around by simply changing your token structures a bit to not cause cross-file collisions like that?

jorenbroekema commented 2 months ago

Might be good for style-dictionary to warn about these kinds of collisions, or even throw an error, because this seems to me to be always fatal and a user error