[community-group] Pre-defined composite type for refering color modifications (e.g. rgba) (#88)

markuslangl has just created a new issue for https://github.com/design-tokens/community-group:

== Pre-defined composite type for refering color modifications (e.g. rgba) ==
Hi,

Our Design and Development teams are currently trying to implement a new Design system based on the specified document as of 2021-12-13 (with the current proposal of limiting composite types (#86) in mind). The whole standard is awesome, and we'd like to thank everyone involved for all the great work done!

## Problem definition

We're currently struggling to create a correct `colors.tokens.json` with colors that use references parts of other colors, e.g. the RGB value or the opacity.
Our Design system consists of multiple levels of color definitions which reference to each other to provide consistency, but also long-term flexibility.

For example:

```json
{
  "base": {
    "red": {
      "type": "color",
      "value": "#ff0000"
    },
    "green": {
      "type": "color",
      "value": "#00ff00"
    },
    "blue": {
      "type": "color",
      "value": "#0000ff"
    },
    "yellow": {
      "type": "color",
      "value": "#ffff00"
    },
    "background": {
      "type": "color",
      "value": "#ffffff"
    },
    "foreground": {
      "type": "color",
      "value": "#000000"
    }
  },
  // ...
}
```

Now, in order to define a component which is based on these variables, would use references to these values:

```json
{
  // ...
  "components": {
    "alert": {
      "error": {
        "background": {
          "type": "color",
          "value": "{base.red}"
        },
        "foreground": {
          "type": "color",
          "value": "{base.foreground}"
        }
      },
      // ...
    },
  },
  // ...
}
```

But in our Design system, we'd like to reference the base color and modify it (e.g. add adding opacity to the value):

```json
{
  // ...
    "alert": {
      "modify": {
        "background": {
          "opacity": {
            "value": 0.1
          }
        },
        "border": {
          "opacity": {
            "value": 0.3
          },
        }
      },
      "error": {
        "background": {
          "type": "color",
          // Invalid value
          "value": "rgba({base.red}, {components.alert.modify.background.opacity})"
        },
        "border": {
          "type": "border",
          "value": {
            // Invalid value
            "color": "rgba({base.red}, {components.alert.modify.border.opacity})",
            "width": "{border.base.m}",
            "style": "{border.base.style}"
          },
        }
      }
    }
  // ...
}
```

Unfortunately, this would result in an invalid tokens file: Currently only colors in the formats `#RRGGBB` and `#RRGGBBAA` are allowed at a value field when it has been defined as type `color`.

A potential workaround would be to use the calculated `#RGBA` value and add the reference to the `extensions` field.

For us, keeping the references in a standardised way which will be supported throughout code and design is important. A custom composite type would cover this use case as well, but this part will not be part of the specification MVP.

## Concerns

We're concerned that not covering this use-case early would cause fragmentation in the ecosystem over time. If there's no common style for modifying the alpha value (or maybe even hue, saturation or lightness as example), there might be plugins and converters requiring different formats, which make it hard to create an easy-to-write file that works everywhere.

### Example: Fictional workflow with Figma, Style Dictionary and Storybook

The designers are creating their designs with [Figma tokens](https://github.com/six7/figma-tokens/), which might in a future version for example use their own extension `com.figma.tokens`:

```json
{
  "background": {
    "type": "color",
    "value": "{color.base.red}",
    "extensions": {
      "com.figma.tokens": {
        // Note the opacity written as percentage (10% = "10") in this example
        "opacity": 10
      }
    }
  }
}
```

Another tool might use it's own extension or format to store the modification. For example, the documentation of [style-dictionary's transitive transforms](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/transitive-transforms) lists the following format in the [examples](https://github.com/amzn/style-dictionary/blob/main/examples/advanced/transitive-transforms/tokens/color/overlay.json5) (to provide compability with [chroma-js](https://www.npmjs.com/package/chroma-js)):

```json
{
  "background": {
    "type": "color",
    "value": "{color.base.red}",
    "modify": [{
      "type": "alpha",
      "amount": 0.1
    }]
  }
}
```

Generating the documentation from the tokens file in a tool like Storybook might get hard at this point, because there could be multiple sources of truth for opacities. If there was for example a generic `<DesignTokens>` renderer, how could it know how to correctly display the defined color?

As a workaround, it would always be possible to write converters between these tools, formats, and extensions. Having the format for these standardised would greatly benefit interoperability for users.

## Benefits of referenced opacity values in tokens files

Our main motivation for referencing colors or modifications is to retain the references in CSS variables. We'd like to use the design tokens to create CSS variables directly from the token files, for example with this result:

```css
/* base.css */
:root {
  --color-base-red: #f00;
  --color-base-green: #0f0;
  --color-base-blue: #00f;
  --color-base-yellow: #ff0;
  --color-base-background: #fff;
  --color-base-foreground: #000;

  /* Additional RGB values could be added by the CSS generator to support usage in rgba() */
  --color-base-red-rgb: 255, 0, 0;
  /* ... */

  --color-alert-background-opacity: 0.1;
  --color-alert-border-opacity: 0.3;
  --color-alert-error-background:
    rgba(var(--color-base-red-rgb), var(--color-alert-background-opacity));
  --color-alert-error-border:
    var(--border-base-m) var(--border-base-style) rgba(var(--color-base-red-rgb), var(--color-alert-border-opacity));
}

/* components/alert.css */
.alert-component--error {
  background: var(--color-alert-error-background);
  border: var(--color-alert-error-border);
}
```

We would benefit from using CSS variables instead of using the direct values once we enable other themes (e.g. a "dark" or "high contrast" version). It wouldn't be required to re-generate the whole file, but just to replace the some of the base variables in e.g. another `dark.tokens.json` file:

```json
{
  "base": {
    "red": {
      "type": "color",
      "value": "#200000"
    },
    "green": {
      "type": "color",
      "value": "#002000"
    }
    // ...
  },
  "components": {
    "alert": {
      "modify": {
        "background": {
          "opacity": {
            "value": 0.2
          }
        },
        "border": {
          "opacity": {
            "value": 0.4
          }
        }
      }
    }
  }
}
```

Since the references in the second file would still be intact, it could generate a second file for `(prefers-color-scheme: dark)`, which could only overwrite the new values and still work:

```css
/* dark.css */
:root {
  --color-base-red: #200000;
  --color-base-green: #002000;

  --color-alert-background-opacity: 0.2;
  --color-alert-border-opacity: 0.4;
}
```

## Proposal: Additional pre-defined composite type

We would like to propose adding basic color modifications to the MVP. This could help avoiding the need for parsing different color syntaxes (#79) and prepare for a future implementation of computed token values (#81).

We have no preferred syntax for this, but assume that an additional pre-defined composite type for "modified colors" would fit in best with the current state of the specification. This could also enable other composite types to use `color` or `computed-color` as values.

One potential format could be for example:

```json
{
  "background": {
    "type": "modified-color",
    "value": {
      "color": "{color.base.red}",
      "modify": {
        "opacity": 0.1,
      }
    }
  }
}
```

This might eventually also enable further modifications to the color, like e.g.:

* Hue
* Saturation
* Lightness
* Red
* Green
* Blue
* Tint
* Shade

Please view or discuss this issue at https://github.com/design-tokens/community-group/issues/88 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Friday, 17 December 2021 12:30:00 UTC