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

I'm reading through this, but especially on @ddamato's post I came to realize we've been using very overloaded terms and everybody is defining them differently, which in turn makes it complicated for us to properly communicate (as I don't really know what Donnie means with theme or context). I consider myself part of this problem and started to define them for my blog series.

I start with definitions at first, then I have an excerpt for you, that is one of the articles of the series (which is about theming, which I actually started writing before I know about this issue) - but is exactly targeting this issue. And later I propose this into a something formalized that has draft spec character for us to discuss and invent further.

# 1. Definitions

**(Design Token) Feature**

> Features provide a customization option for users to modify their experience.

Features encode user preferences (e.g. color scheme or color contrast). Design tokens may or may not support a feature.

**Theme**

> Themes contain the design decisions of your brand with differing capabilities (features and scopes) and are exchangeable within your product.

A theme defines its capabilities and delegates implementation of these to its tokens.

**(Design) Token Designers**

A token designer develops designs tokens. The token design includes references, possible transforms, ambients and computed tokens (this can be done by designers _and/or_ developers !).

**(Design) Token Consumer**

A user applying a token - most likely designers and engineers, but also includes branding and marketeers or generally speaking people applying the brand by using design tokens.

**(Design) Token Users**

Token users include token designers and consumers, it's a way to refer to both parties. And includes the fact a token designer here, can be a token consumer there.

**Tooling Authors**

Folks to support design tokens in their tools and define the processes we use for crafting.

**(End)Users/Customers**

People like you and me visiting apps and sites and _experience_ products applying design tokens for their theme.

**Product**

The application, website or service an enduser is using. A product uses a design system.

# 2. Theming with Design Tokens (an Excerpt)

The definitions above seem a little exaggerated, but I use them in the article, which dives more into the term `Theme`.

[-> Theming with Design Tokens (Draft)](https://gist.github.com/gossi/1b83d6ec3740b00152fe3269a3b59dec)

I know people use theme to describe their light or dark color-scheme, which is still possible for them to do. I think, the key is to separate this into theme and features. As this group aims to land a spec that targets enterprise size solution, the more range the definitions cover, the better.

---

⬇️ ⚠️ **From here on, I expect you to have read the excerpt above**. 

# 3. Formalizing a Spec Draft

When formalizing this, it is critical to define goals and non-goals.

Goals:
- The spec is more like a schema to a database, as the token file is a storage of structured data
- The spec is to provide a structure to in which information can be stored
- The spec is providing all the information for tools to understand the data much like humans
- The spec is human friendly and allows manipulation in text-editors
- The spec allows for validating the data to ensure data integrity

Non-Goals:
- The spec is not based or constraint by implementation behavior
- The spec does not assume or prefer specific working mode (tool vs manual, context or global editing)

With that in mind, I worked on a draft. I'll have to make assumptions on the way (that also target @kevinmpowell's questions).

## 1. Define the Capabilities of a Theme

<details>
  <summary><b>Assumption 1:</b> One folder with multiple token files contain a theme.</summary>

  So far the spec defines the structure within one file. But I can't remember reading about multiple files (please send a link, if there is a mention). That is I assume it the way style-dictionary does: Multiple files in one directory, then all files are merged into one in-memory "database" which is then translated into desired formats.
</details>

For that a theme first must mention its capabilities in terms of features and scopes. I'm using typescript here to model this:

```ts
interface Theme {
  name: string;
  features?: Features;
  scopes?: string[];
}

interface Features {
  [feature: string]: {
    default: string; // must be available in options
    options: string[];
  }
}
```

... and an example to it:

```json
{
  "name": "ocean",
  "features": {
    "color-scheme": {
      "default": "light",
      "options": ["light", "dark", "midnight"]
    },
    "color-contrast": {
      "default": "low",
      "options": ["low", "high"]
    }
  },
  "scopes": ["invert"]
}
```

This information can be read, interpreted and understood by tools and humans. When authoring the theme, these are the constraints.

## 2. Multiple Token Values

I'd follow the approach for multiple token values, but take in the idea from @ddamato about context oriented editing and evolve from there.

```json5
// intents.tokens
{
  "intent-action-base-background": {
    "$type": "color",
    "$value": "darkblue"
  }
}
```

and another file for dark:

```json5
intents-dark.tokens
{
  "intent-action-base-background": {
    "$type": "color",
    "$value": {
      "$value": "lightblue",
      "color-scheme": "dark"
    }
  }
}
```

The `$value` definition gets more detailed by describing the constraints under which this value is valid.

Next up, bring in a scope:

```json5
// scope-invert.tokens
{
  "intent-action-base-background": {
    "$type": "color",
    "$value": {
      "$value": "lightblue",
      "$scope": "invert"
    }
  }
}
```

The same token defined three times, in three different files. They can be compiled into one file:

```json5
// compiled.tokens
{
  "intent-action-base-background": {
    "$type": "color",
    "$value": [
      {
        "$value": "darkblue"
      }, 
      {
        "$value": "lightblue",
        "color-scheme": "dark"
      }, 
      {
        "$value": "lightblue",
        "$scope": "invert"
      }
    ]
  }
}
```

... and both formats are valid and acceptable. Apparently, when all of the files above are merged, the compiled one is the output. 

Let's turn this into a formalized definition, using typescript again (simplified of course):

```ts
/* 
this is the way how a current value can be defined, depending on its type, etc. 
As this is not relevant here, I assigned it to a string - but give it a name to 
make the connection to the work that was already put into here
*/
type CurrentValue = string;

interface ConstrainedValue {
  $value: CurrentValue;
  $scope?: string; // must be the values defined in meta file
  [feature: string]: string; // must be the values defined in meta file
}

type SingleValue =
  | CurrentValue
  | ConstrainedValue;

type Value = 
  | SingleValue
  | SingleValue[];
```

This will continue to use _special fields_ prefixed with `$` and features use user-defined values. That rule makes it possible to validate the token files.

## Validating the Spec

Ok, so here is a good way to validate the spec against some test-cases and whether it confirms ot not.

1. Is the spec coherent?
yes, capabilities can be defined in the meta file

2. Does the spec allow people to define their situations?
yes, capabilities can take any user-defined values

3. Does the spec allow validation of token files?
yes, as token values are defined based on the user-defined values and the structure accounts for them. Validation routines can be written by tooling authors

4. Does the spec prefer or assume a specific working mode?
no, it can be used in a single file or multiple files and authors can define their own organization

5. Is the spec human friendly?
yes, especially as it allows authors to define their own organization of files with their prefered working mode.<br>
no, it may be cumbersome to always define the constraints when working in one file that always uses the same constraint (see open question below)

6. Is the spec tool friendly?
yes, thanks to the meta file. Which contains the information about the capabilities. That's the required information for tools to generate UIs based on these information.<br>
At the same time allows tooling authors to write theme-switchers.<br>
It also allows to take a collection of `*.token` files and wrap them in a custom build scripts for filtering or put a REST API around them as demonstrated in the article.

7. Is the spec coupled to a particular implementation?
no, the spec defines a structure to organize data into information.

8. Is the spec coupled to environment implementation details - such as media queries for color schemes?
no, that's up to authors to define their feature options and implementation to connect this with the given technical environment.

9. But there are given technical constraints for color-scheme and color-contrast, how does the spec connect here?
I see it similar to how the `$type` defines the structure of `$value`. It potentially started with only _primitive_ values (string, number, boolean) into what `border-radius` needs and by that enhancing the spec with more of such use-cases. I can see the same evolution happening here, in which the spec enhances such types. I would even want to see this, but at first is to create the boundaries and frame the picture in which this can happen.

10. You like that meta file very much, is that a solution to everything?
😎 haha, no. I'm also not working for meta. I needed a name to refer to that, can also be a theme config 😁 

## Open Questions

There are a couple of open questions

**Q: How to find the "meta" file?**

Is there a special name `meta.tokens` or does each file reference the meta file?

```json
{
  "$reference": "path/to/meta.tokens"
}
```

Probably, a question asked too early?

**Q: What's the conflict resolution algorithm when merging files?**

As the spec allows for validating the files against the capabilties set in the meta file, when merging files (especially through tooling) they can validate the files and log error messages, such as:

- `Found two values for the same token: xx-yy-zz`
- `Missing token value for dark color-scheme and low contrast for: another-token`
- ...

I think, that's already the case for style-dictionary. Tools can provide configuration for severity levels (warn vs error).

**Q: Do I always have to set the constraints on each token value? Can't I set it for the entire file?**

I can already hear the people scream about this 😇 That's a question for constraining an entire group and not part of this issue. I've seen other discussion around this, please link them.

**Q: Do features need to be `$features` in `ConstrainedValue`?**

With features being next to `$value` and `$scope` they eat up all space for future enhancements (unless they come `$`-prefixed). Which takes away real-estate within the object. Instead they can be fenced in its own object:

```json5
intents-dark.tokens
{
  "intent-action-base-background": {
    "$type": "color",
    "$value": {
      "$value": "lightblue",
      "$features": {
        "color-scheme": "dark"
      }
    }
  }
}
```

that is making it more explicit for sure, but also a bit more cluttering. Tools wouldn't care, but reduces the "human-friendly" part of it.

I don't have an answer but wanted to state I was discussing this situation.

---

My own opinions on this: I took the comments of this issue matched them with my own research and come up with this draft. I think, it answers a lot of questions. It is despite quite concise and I even managed to keep it human friendly (I hope). I'm somewhat surprise about the outcome here (now that I wrote up all this). Super interested in hearing your feedback.

-- 
GitHub Notification of comment by gossi
Please view or discuss this issue at https://github.com/design-tokens/community-group/issues/210#issuecomment-1508546324 using your GitHub account


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

Received on Friday, 14 April 2023 13:52:17 UTC