[community-group] Composite Token Composition (#179)

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

== Composite Token Composition ==

## Context
I'm in the process of defining some rather complex typography tokens that define responsive parameters (i.e., values may range from a min to a max, based on viewport/window width).  Additionally, the min/max styles have to be defined for (currently) 10 text styles (heading1, headingN, subheadingLg, bodySm, etc.).  To make things even more complex, there are three different font families that may be applied to each text style.  And to top it all off, we need to be able to mix and match some of these combinations at will.

## The issue
The problem I've run into is that I have to duplicate a LOT of composite properties in order to account for every possible combination of font + style + min/max.  There are two things that would help with this.

1. defining partial composite token values (i.e., not having to define all 5 `typography` token properties), such that I can compose a complete token/style later
2. being able to extend an existing composite token value, in order to override one or two properties


```json5
{
  type: {
    base: {
      $description: 'base typography styles',
      $type: 'typography',
      $value: { // [1] partial composite token definition
        fontFamily: [ "Arial", "sans-serif" ],
        fontWeight: 400,
      },
    },
    heading1-base: {
      $description: 'Heading 1 base styles',
      $value: { // [1] partial composite token definition
        fontSize: "48px",
        lineHeight: "1.25",
        letterSpacing: "0px",
      }
    },
    heading2: {
      $description: 'Heading 2 styles',
      $value: {
        // base props
        $extends: "{type.base}",  // [2] composite extension
        // additional props
        fontSize: "40px",
        lineHeight: "1.2",
        letterSpacing: "-0.5px",
      }
    },
    heading2-alt: {
      $description: 'Heading 2 (alternate) styles',
      $value: {
        // "inherited" parent token props
        $extends: "{type.heading2}", // [2] composite extension
        // child token prop overrides
        $fontFamily: ['Georgia', 'Times', 'serif'], // single prop override
      }
    }
  }
}
```

This could generate the following Sass code after transformation:

```scss
/// base typography styles
$type-base: (
  "fontFamily": (Arial, sans-serif),
  "fontWeight": 400
);
/// Heading 1 base styles
$type-heading1-base: (
  "fontSize": 48px,
  "lineHeight": 1.25,
  "letterSpacing": 0px
);
/// Heading 2 styles
$type-heading2: (
  "fontFamily": (Arial, sans-serif),
  "fontWeight": 400,
  "fontSize": 40px,
  "lineHeight": 1.2,
  "letterSpacing": -0.5px
);
/// Heading 2 (alternate) styles
$type-heading2-alt: (
  "fontFamily": (Georgia, Times, serif),
  "fontWeight": 400,
  "fontSize": 40px,
  "lineHeight": 1.2,
  "letterSpacing": -0.5px
);
```
* For times when you need to let consumers control how styles are composed, defining partial tokens would be best.
    * e.g., to get full Heading 1 styles requires `$heading1: map.merge($type-base, $type-heading1-base)`
* For times when you want to compose the styles for your consumers, composite token extension is best.
    * e.g., `$type-heading2` and `$type-heading2-alt`


### Questions
1. Does `#/type/base` qualify as a `$type: "typography"` or would we need a different `$type`?
    - possibly just use `$type: 'object'` for the partial defs? (not sure how this would affect environment-specific transforms)
2. Would `$type: 'object'` essentially be a _custom_ generic composite token?
3. 



### Ideal Configuration: $value.$extends
An idea I had would be to add support for as special `$extends` property within a composite token definition, such that a sub-token could extend the properties of a parent token.  Theoretically, this would work with any object-like `$type` (i.e., composite tokens and `$type: 'object'`).


This would extend `#/type/base/$value` with additional properties defined in `#/type/heading1/$value`.  
If a property exists in both `#/type/base/$value` AND `#/type/heading1/$value`, then the latter takes precedence.



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


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

Received on Monday, 7 November 2022 20:18:52 UTC