[community-group] Native modes and theming support (#210)

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

== Native modes and theming support ==
We're currently working on native support for tokens internally here at Figma. In our eyes there are two core use cases that stem from customer requests for design tokens:

1. Token aliasing (i.e. `danger-bg` -> `red-300`)
2. **Theming**

Currently the spec does not support theming, which at the moment is a blocker for us for full adoption. I'd like to start a thread here on what native mode support would look like for this format. Major shout out to @drwpow for trailblazing some of this with Cobalt-UI, to @jkeiser for turning this into a proper proposal, and to @connorjsmith for comments and critiques.

Here's the proposal we ended up with:


### Overview

Modes represent alternative sets of values for a collection of design tokens. For example, one might wish to have a different value for the “background” and “foreground” tokens depending on whether they are in “light” mode or “dark” mode.

This proposal allows the user to define a set of modes that apply to all tokens in the design tokens file, allowing them to have distinct values for each mode.

Herein we’ll use this example:

```json
{
  "$name": "Figma UI Colors",
  "$modes": {
    "light":      {}, // no fallback
    "dark":       {}, // no fallback
    "super-dark": { "$fallback": "dark" }
  },
  "bg": {
    "$type": "color",
    "brand": {
      "$value": "{colors.blue.300}", // light mode falls back to this
      "$modes": {
        "dark": "{colors.blue.500}" // super-dark mode falls back to this
      }
    }
  },
  "fg": {
    "$type": "color",
    "brand": {
      "$modes": {
        "light": "{colors.black}",
        "dark": "{colors.white}",
        "super-dark": "{colors.gray}"
      }
    }
  }
}
```

In this example, the values for bg and fg for each mode would be:

  | light | dark | super-dark
-- | -- | -- | --
bg | {colors.blue.300} | {colors.blue.500} | {colors.blue.700}
fg | {colors.black} | {colors.white} | {colors.white}


### Defining Modes

A design tokens file may optionally define a set of named modes at the top of the file.

```json
{
  "$name": "Figma UI Colors",
  "$modes": {
    "light": {},
    "dark": {},
    "super-dark": { "$fallback": "dark" }
  },
  // tokens ...
}
```

The `$modes` definition is an object at the top level of the design tokens file.


- `$modes` should be placed before the first token or token group, to make efficient file import possible.
- Mode names are case sensitive: `"``light``"` and `"``LIGHT``"` are different modes.
- Mode names have the same restrictions as token and group names: they must not start with `$`, and must not contain `{`, `.` or `}` characters.
- If `$modes` is empty `{}`, it is treated the same as if it were not specified (namely, that no modes are defined).

### Fallbacks

Each mode may optionally define a `$fallback` mode, which will be used to determine the value of tokens which do not define a value for the given mode.


- The lack of a `$fallback` value implies that mode will fall back to a token’s default `$value`.
```json
        "dark":       {}, // no fallback
```

- `$fallback` value must be the name of another mode in the same file.
```json
        "super-dark": { "$fallback": "dark" }
```

- Fallbacks must not form a cycle.
```json
        "dark": { "$fallback": "super-dark" },
        "super-dark": { "$fallback": "dark" } // ERROR: cycle
```

### Token Values

Design token files may specify different values for each mode, for each token.

```json
    "brand": {
      "$value": "{colors.blue.300}", // light mode falls back to this
      "$modes": {
        "dark": "{colors.blue.500}" // super-dark mode falls back to this
      }
    }
```


- A token may optionally define `$value`, which determines its default value.
- If no modes are defined, `$value` must be defined and represents the token’s value.
- A token may optionally define `$modes`, which is an object defining its value for specific modes.
- A token’s `$modes`  may only define values for modes defined in the same file. `"$modes": {"daaaaark":"#000000"}` is an error if there is no `"daaaaark"` mode.
- `"$modes": {}` is equivalent to not specifying `$modes` at all.

_NOTE: this relaxes the requirement that `$value` is required when modes exist._

### Value Resolution

If modes are defined, all tokens must have values for all modes, taking into account fallback and default rules. This means that either `$value` or `$modes` (or both) must be defined for all tokens.

The value of a token for mode `"m"` is as follows:

1. If the token defines a value for `"m"` , that value is used for the mode.
2. Otherwise, if the mode defines a `$fallback`, the token’s value for the fallback mode is used. The same rules are applied for the fallback mode, so if an explicit value is not defined for the fallback mode, its fallback is used, and so on.
3. Otherwise, if `$value` is defined, then that value is used for the mode.
4. Otherwise, the token is undefined for the mode, which is an error.


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


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

Received on Wednesday, 22 March 2023 23:03:04 UTC