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

[Feature] (Transformer to) allow splitting tokens #695

Open
lukasoppermann opened this issue Sep 14, 2021 · 9 comments
Open

[Feature] (Transformer to) allow splitting tokens #695

lukasoppermann opened this issue Sep 14, 2021 · 9 comments

Comments

@lukasoppermann
Copy link
Contributor

Hey @dbanksdesign and @chazzmoney I think especially considering the upcoming composite tokens this could be very helpful.

I am running into this problem currently with font styles. My font styles (exported from figma) has letter-spacing. Sadly in css letter-spacing is not part of the font property but a separate attribute.

My need is to transform this input:

'font': {
  type: 'font-style',
  value: {
    fontSize: 16,
    fontWeight: 700,
    //...
    letterSpacing: 0.136
  }
}

Into this css:

font: 700 16px /*...*/;
letter-spacing: 0.136px;

While this is technically possible in a format I feel that is not the correct place for it, as it has not so much to do with the formatting.

@dbanksdesign
Copy link
Member

This would be a bit more difficult, but nothing is impossible. The difficulty in this approach is the end result for the generated code for each platform would mean splitting up a single token in different ways. Style Dictionary has the assumption that a design token is a name and a value and like you pointed out, the format should just format how a given language like CSS writes that declaration, [name] : [value] ; for example. This works fine in cases where a composite token can still be represented as a single declaration, for example having a border token that can be represented like [border width] [border style] [border color] in CSS because a transform can take an object and turn it into that string. While it doesn't fit with the spirit of what the format is supposed to do, that is the only way I can think of to split a single token into multiple tokens in an output. A better place would be if Style Dictionary had a pre-format step where you could mutate the dictionary object, but that sounds a bit weird too.

Another option would be to have a token group rather than a composite token and then split each font property into its own token inside the group. This might be a bit cleaner to implement a format for since it wouldn't involve splitting a token.

Can you zoom out a bit, what is the full output you want to have? A single text style in figma outputs to a helper class in CSS?

@lukasoppermann
Copy link
Contributor Author

lukasoppermann commented Sep 15, 2021

Hey @dbanksdesign,

I totally understand this. Actually I find a pre-format step very good, I just thought it was more complicated.
This pre-format step would have to be run on a per platform or per file basis (better would be to allow both).

In the w3c specs it is stated that groups are not supposed to have any meaning, it's just an ordering system, however a font-style needs to be grouped. It is actually part of the same token. This is why I think a composite token is better.

Zooming out

I actually translate the tokens into css variables:

 --background: #ffffffff;
 --breakpoints-xl: 1792px;
 --radius-round: 5px 10px 5px 5px;
 --typography-title1: 700 114/131.1 "RTL United Text", sans-serif;
 --typography-title1-letter-spacing: 0.135px; /* <-- this does not work yet */
 --gradients-image-overlay: linear-gradient(180deg, rgb(0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 100%);
 --elevation-small: 0px 1px 0px 0px rgba(23, 24, 26, 0.1);

The composite token for fonts looks like this (plugin output):

{
      name: 'title 1',
      description: 'a font token',
      type: 'custom-fontStyle',
      value: {
        fontSize: 114,
        textDecoration: 'underline',
        fontFamily: 'Helvetica',
        fontWeight: 700,
        fontStyle: 'italic',
        fontStretch: 'normal',
        letterSpacing: 1.2,
        lineHeight: 131.1,
        paragraphIndent: 0,
        paragraphSpacing: 12,
        textCase: 'none'
      }
}

@BrettJephson
Copy link

I'm bumping up against the same problem with JSON exported from Figma (via Figma-tokens plugin). Is there a workaround that others have used? Or is this feature in consideration?

@juwain
Copy link

juwain commented Mar 11, 2022

BTW, Figma tokens plugin supports splitting typography tokens into separate ones during export. You should check "Expand Typography" field in plugin UI.

Screenshot 2022-03-11 at 10 47 43

So the result will be:

"fontFamily": {
  "value": "{typography.font-family.sans-serif}",
  "type": "fontFamily"
},
"fontWeight": {
  "value": "{typography.font-weight.normal}",
  "type": "fontWeight"
},
"lineHeight": {
  "value": "{typography.line-height.32px}",
  "type": "lineHeight"
},
"fontSize": {
  "value": "{typography.font-size.24px}",
  "type": "fontSize"
},
"letterSpacing": {
  "value": "{typography.letter-spacing.02%}",
  "type": "letterSpacing"
}

@jakobe
Copy link
Contributor

jakobe commented Sep 9, 2022

This would be a bit more difficult, but nothing is impossible. The difficulty in this approach is the end result for the generated code for each platform would mean splitting up a single token in different ways. Style Dictionary has the assumption that a design token is a name and a value and like you pointed out, the format should just format how a given language like CSS writes that declaration, [name] : [value] ; for example. This works fine in cases where a composite token can still be represented as a single declaration, for example having a border token that can be represented like [border width] [border style] [border color] in CSS because a transform can take an object and turn it into that string. While it doesn't fit with the spirit of what the format is supposed to do, that is the only way I can think of to split a single token into multiple tokens in an output. A better place would be if Style Dictionary had a pre-format step where you could mutate the dictionary object, but that sounds a bit weird too.

Another option would be to have a token group rather than a composite token and then split each font property into its own token inside the group. This might be a bit cleaner to implement a format for since it wouldn't involve splitting a token.

Can you zoom out a bit, what is the full output you want to have? A single text style in figma outputs to a helper class in CSS?

Hey @dbanksdesign, just stumbled upon this issue. I actually chimed in on #848 with a similar idea (mutating the dictionary object by expanding composite tokens into separate tokens). While this might seem a bit weird it has the benefit of making a lot of formats just work out of the box (e.g. css/variables, scss/map-flat, scss/variables).

I also vented the idea of a pre-format step - and if run per platform and/or file as suggested, that would not tie it directly with the format and could be reused for different files and formats within that platform.
Maybe 2 brains having the same thought is hinting at something? 🤔 😅

@bennypowers
Copy link

This would be very helpful for colours, as well:

ideally, style-dictionary would let us write a transform to automatically split single colour inputs to multiple values, for example hex to rgb, hsl:

IN:

color:
  blue:
    500:
      $value: '#0066cc'

OUT:

:root {
  --rh-color-blue-500: #0066cc;
  --rh-color-blue-500-rgb: 0, 102, 204;
  --rh-color-blue-500-hsl: 210 100% 40%;
}

USAGE:

#play-button {
  background-color: hsl(var(--rh-color-blue-500-hsl) / var(--rh-opacity-50));
}

@yringler
Copy link

Here's a gist. It has a self contained class, which can be used with a formatter to expand a token.

@jossmac
Copy link

jossmac commented Aug 3, 2023

Adding a case for things like https://seek-oss.github.io/capsize/

Input:

text: {
  regular: {
    size: { $value: '14px', $type: 'dimension' },
    lineheight: { $value: 1.4, $type: 'number' },
  }
}

Output:

text: {
  regular: {
    size: { $value: '14px', $type: 'dimension' },
    lineheight: { $value: 1.4, $type: 'number' },
    baselineTrim: { $value: '-0.3364em', $type: 'dimension' },
    capHeightTrim: { $value: '-0.3364em', $type: 'dimension' },
    capHeight: { $value: '10.1818px', $type: 'dimension' },
  }
}

@jorenbroekema
Copy link
Collaborator

jorenbroekema commented Apr 23, 2024

Technically you can now do this in V4 with the Preprocessor hook.

It does require you to create your own function that recursively goes through the tokens and mutates the object to your liking.

I'm also adding a feature to expand composite type tokens (object values) either globally, per platform, or conditionally per token, but this feature is slightly limited in that it's either "expand" or "don't expand" and it doesn't allow:

  • specifying which props within an object to expand to separate tokens, and which ones to leave as is
  • expanding the token while also keeping the original, the practical issue with that is that it would make the token both a token and a token group at the same time which is not in compliance with the spec, and we wouldn't know how to handle that
    PR is work in progress but: Expand composites #1169

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

No branches or pull requests

9 participants