style-dictionary icon indicating copy to clipboard operation
style-dictionary copied to clipboard

Unable to use multiple transformers with the same token type

Open equinusocio opened this issue 1 year ago • 1 comments

The issue

Hello, in our design system we have some tokens that must be converted to px and other to rem. Since both size/pxToRem and size/px, check on the token.type === 'dimension' we can't use the built-in transformers because the output would be all px or all rem. We are forced to create custom transformers only to change the filter function and check on different type. Doing so makes the built-in transformers concept a bit useless.

Possible solution

In our opinion, transformers should have unique filter check to being able to combine them on the same platform. For instance size/pxToRem could match type === 'dimension-px-to-rem' and size/px could match type === 'dimension-px'. This way we can convert some tokens to px, and some to rem

equinusocio avatar Aug 22 '24 06:08 equinusocio

Transforms can be chained on the same type, but yes for size/pxToRem and size/px they both expect the input to be unitless, so in that particular case chaining them won't do much since only the first transform will actually take effect.

If you're only interested in changing the filter of a transform for a particular built-in transform, consider trying this:

Example from https://github.com/amzn/style-dictionary/discussions/1292

const colorHslBuiltin = StyleDictionary.hooks.transforms['color/hsl'];
StyleDictionary.registerTransform({
  ...colorHslBuiltin,
  filter: (token) => token.type === 'colors',
  name: 'colors/hsl', // if you don't override the name it will register on the original name and override the built-in one, which might be nice
});

jorenbroekema avatar Aug 28 '24 10:08 jorenbroekema

Thank you, my input is unitless, but when the token type is dimension only the latest transform with filter dimension defined in the custom group is used (or replace the previous ones with the same filter)

Giving this custom transform group:

[
  'size/rem',
  'size/px'
]

and the following tokens:

{
  "font": {
    "size-px": {
      "$type": "dimension",
      "100": {
        "$value": 100
      }
    },
    "size-rem": {
      "$type": "dimension",
      "100": {
        "$value": 100
      }
    }    
  }
}

both final tokens are in px because the size/px transform comes after in the custom group.


Is there any possibility of seeing the proposed change and avoiding writing "fake" custom transform to change the filter? Does it make sense to have non-exclusive transforms?

equinusocio avatar Aug 29 '24 07:08 equinusocio

So your proposal is to somehow make size/rem and size/px mutually exclusive from being used within the same platform?

The issue is that just because their filter methods overlap, it doesn't mean they can't work in conjunction with one another. E.g. ['color/rgb', 'color/lab'] (these are hypothetical transforms), you may need to first transform a color from hex to rgb before the color/lab can transform it to oklab, because maybe that transform happens to not support hex as input. Maybe not the greatest example but "daisy chaining" transforms on the same token type definitely has its use cases

jorenbroekema avatar Aug 29 '24 15:08 jorenbroekema

In your chain example, you have one token input, converted to RGB, then converted to LAB, a sigle output. Yes, this chain may be useful, but honestly, we find it more common in design systems to have tokens with the same type that need different output. Platforms support many “types”, in our case, the web platform supports line height in px, em, rem, etc… both are “dimension” types with different use cases and one doesn’t exclude the others. In the example above, if we want to convert the same token to multiple units we are forced to create a custom transform.

If there is a way to make chaining and this change work together is even better. Maybe an extra config to explicitly define transforms to be chained?

equinusocio avatar Aug 29 '24 16:08 equinusocio

I think if you want to transform two tokens differently yet they share the same type, you'll have to add some metadata to the token to be able to distinguish between these tokens if the type is the same. I'm not convinced currently about your proposed changes to complicate the transforms API to be able to do this when there's an easier way to do it already

jorenbroekema avatar Aug 30 '24 11:08 jorenbroekema

What easier way? Defining custom fake transforms?

equinusocio avatar Aug 31 '24 14:08 equinusocio

Yes overriding the built-in transforms either partially or entirely, or creating a custom transform and using that instead. The built-ins aren't meant to be perfect for everyone - custom transforms is already how people get around it, overriding the built-ins is often more convenient but just needs more documentation

jorenbroekema avatar Aug 31 '24 20:08 jorenbroekema

ok. It's worth taking into consideration that the software's assumption of only one output for token type may not align conceptually with the diverse needs of different platforms or design systems. For instance, using the type "dimension/rem" could potentially lead to the software enforcing the use of only rem throughout the platform. It's definitely a point worth considering.

equinusocio avatar Sep 01 '24 05:09 equinusocio