tokens-studio / figma-plugin

Official repository of the plugin 'Tokens Studio for Figma' (Figma Tokens)
https://www.figma.com/community/plugin/843461159747178978
MIT License
1.35k stars 193 forks source link

Introduce color modifiers #1166

Closed six7 closed 1 year ago

six7 commented 2 years ago

Description

Users often need to manipulate colors to create slight color variations of a specific base color. An example would be a hover color that is just slightly brighter than the other one, or a pressed state which is usually a bit darker. Also users would want to create alpha variations of a color. This often depends on a few things:

Type of operation

We could introduce this by implementing a color library such as Chroma.js, which does have support for all of the manipulations we need to do:

Users would need to configure that in the UI, and we should make it as easy as possible. Let's start with these 4 modifiers and later on we'll see what else is required.

image

As we need to capture these decisions in JSON and these would not be matching the official W3C spec for color values, we need to define these in the $extensions property that we can introduce, which is part of the W3C spec and could be a good starting point to have this kind of modification in place.

The JSON could look like this:

{
  "blue": {
    "value": "#0f78dd",
    "type": "color"
  },
  "red": {
    "value": "#ff0000",
    "type": "color"
  },
  "primary": {
    "default": {
      "value": "{blue}",
      "type": "color"
    },
    "lighten": {
      "value": "{primary.default}",
      "type": "color",
      "$extensions": {
        "com.figmatokens": {
          "modify": {
            "type": "lighten",
            "amount": 1.5,
            "space": "LCH"
          }
        }
      }
    },
    "darken": {
      "value": "{primary.default}",
      "type": "color",
      "$extensions": {
        "com.figmatokens": {
          "modify": {
            "type": "darken",
            "amount": 1.5,
            "space": "LCH"
          }
        }
      }
    },
    "mix": {
      "value": "{primary.default}",
      "type": "color",
      "$extensions": {
        "com.figmatokens": {
          "modify": {
            "type": "mix",
            "color": "{red}",
            "amount": 0.5,
            "space": "LCH"
          }
        }
      }
    },
    "alpha": {
      "value": "{primary.default}",
      "type": "color",
      "$extensions": {
        "com.figmatokens": {
          "modify": {
            "type": "alpha",
            "amount": 0.25,
            "space": "LCH"
          }
        }
      }
    },
  }
}

Options on each modifier

Modifier Options
Lighten Amount (number field)
Darken Amount (number field)
Mix Color (color field with picker and token dropdown showing color tokens), Ratio (number field)
Alpha Opacity (number field between 0 and 1)

Available color spaces

c1rrus commented 2 years ago

Similar ideas have been discussed in this DTCG issue too: https://github.com/design-tokens/community-group/issues/88

Would be great to share your ideas there too. Perhaps the community can align on something together

bewarai commented 2 years ago

The problem I have with this is that the darken or lighten in chroma.js (and many programmers follow the same logic) is that the color system HSL used is not very designsystem friendly towards contrast usability and in line with perceptual color space. I use LCH to output my different variations. That way I can tokenize a color red 20 and align it with green 20 with the same contrast ratio. So I can interchange the color without having it an impact on my contrast. So at least let us choose which color-space the darken and light is applied to.

I hate it when front-end uses this function because we have to manually check every color combo against WCAG standards. While using it in combination with LCH I can make a system that always work and does not need to be checked each time.

Ideally I would want to have a choice what colors-pace is used. How many tokens between absolute white and absolute black I can set.

Picture 2 Picture 1
six7 commented 2 years ago

The problem I have with this is that the darken or lighten in chroma.js (and many programmers follow the same logic) is that the color system HSL used is not very designsystem friendly towards contrast usability and in line with perceptual color space. I use LCH to output my different variations. That way I can tokenize a color red 20 and align it with green 20 with the same contrast ratio. So I can interchange the color without having it an impact on my contrast. So at least let us choose which color-space the darken and light is applied to.

Chroma.js would allow us to choose a colorspace: https://gka.github.io/chroma.js/#chroma-mix so adding to these modifiers would definitely make sense šŸ‘

bewarai commented 2 years ago

Some links that can help: https://www.bugsnag.com/blog/chromatic-sass https://github.com/aotearoan/sass-farbig

AndySobol commented 2 years ago

Hurrah! I look forward to it! ā¤ļø

EloB commented 2 years ago

I'm not aware if you maybe already started implementing this but Colord looks like a really good alternative to Chroma.js.

Accoding to their docs they have better performance (300%). Also smaller in size and has plugin based approach if you need to extend it. Builtin Typescript support. MIT license...

https://github.com/omgovich/colord#benchmarks

Apart from this. I'm like shaking of excitement for one. You rock! Go go go! :D

yinonov commented 2 years ago

SD transitive-transforms example shares a similar approach at

https://github.com/amzn/style-dictionary/blob/28787befb1a2c7173c64a2a4bef5b029d0799cce/examples/advanced/transitive-transforms/tokens/color/overlay.json5#L13-L21

yinonov commented 2 years ago

how would this be interpreted by Figma in practice? say a rectangle, a 2 color mix would output a linear-gradient workaround

background: linear-gradient(0deg, #0D0D0D, #0D0D0D),
linear-gradient(0deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.12));
image

would this feature output a computed primitive value?

EloB commented 2 years ago

@six7 I'm not sure if this would be easy to implement but there are some working draft in CSS to include color manipulation. I read about it here: https://www.digitalocean.com/community/tutorials/css-color-function

In that blog post they said that cssnext, a postcss module, already built this. https://cssnext.github.io/features/#color-function

So you might be able to reuse that.

If this draft getting accepted you will have working "css" out of the box. Don't take my word on it because I only fast read everything.

yinonov commented 2 years ago

@EloB CSS Color Module Level 5 color-mix will enable run-time color manipulation.

scss and the other transpilers you mention can SSRly manipulate colors and output a primitive value to be used in run-time.

there are other workarounds but it's an author's choice on how to handle in development.

Figma is less flexible in that sense and it's more interesting if this can actually work in Figma?

six7 commented 2 years ago

Updated mocks to include color space as an option (please let me know if a color space is missing, we'll only ship a subset)

EloB commented 2 years ago

@yinonov I understand that but you might be able to use the some of code to achieve realtime. :)

The code might be crappy. I didn't look... :D

LiamMartens commented 1 year ago

@six7 does it make sense to make these add these as value functions instead? ie lighten({colors.red.500}, 50%) This way it could be caught by the CSS ast

six7 commented 1 year ago

No, as then those would not be valid color tokens as per the w3c draft.

LiamMartens commented 1 year ago

@six7 fair enough, my bad. One other thing is that we might want the modify key to be an array in case we support multiple modifiers at the same time in the future. It would be a good to have a consistent data type. Perhaps we should also consider having a generic modifier structure; so the base could be

interface Modifier <T extends string, V> {
  type: T
  value: V
}

And then for the color modifiers we could create an extended interface

interface ColorModifier<T extends string, V> extends Modifier<T, V> {
  space: 'LCH' | 'sRGB' | 'P3'
}

and lastly for a specific one such as lighten

interface LightenModifier extends ColorModifier<'lighten', number> {}

As for the Figma implementation I assume we will just have to process all modifiers for a token and use the resulting value. No way around that for now.

six7 commented 1 year ago

That would be awesome! And yeah, very good point on the array. I think storing it as an array to future-proof this makes lots of sense. I could see us combining these in the future, so let's do that!

One thing that might change is our $extensions id (com.figmatokens) in case there's going to be a name change in the future.

1pxone commented 1 year ago

Hey @six7

Any updates on this? Can I help with something to make it happen sooner?

AndySobol commented 1 year ago

Hi @six7 =)

Wanted to ask if this feature will be available in the near future or not to wait this year (2022) ? It is important to know for the project.

Thank you for your efforts!

six7 commented 1 year ago

@AndySobol we're focusing on this in the next iteration, after we released the current iteration (early December). The next one after that will likely land in January 2023.

EloB commented 1 year ago

@six7 This is me right now! excited

Sending some love your way. You are the man! love

yinonov commented 1 year ago

@six7 is it documented anywhere? curious to see your roadmap

AndySobol commented 1 year ago

@AndySobol we're focusing on this in the next iteration, after we released the current iteration (early December). The next one after that will likely land in January 2023.

@six7 Thank you, so much!!) Thanks for your work!

AndySobol commented 1 year ago

is it documented anywhere? curious to see your roadmap

@yinonov Everything is documented here https://github.com/users/six7/projects/4/views/17

AndySobol commented 1 year ago

Hi!

Are you planning to add the BlendMode type? Figma Api BlendMode

six7 commented 1 year ago

This was released in 1.35 šŸŽ‰

Read more here: https://docs.tokens.studio/tokens/color-modifiers and https://tokens.studio/changelog/release-1-35