amzn / style-dictionary

A build system for creating cross-platform styles.
https://styledictionary.com
Apache License 2.0
3.93k stars 557 forks source link

Missing "local" token attributes while using alias #1006

Closed equinusocio closed 1 year ago

equinusocio commented 1 year ago

Hello, i'm digging the doc (this and this) and the examples but I can't find a way to do what I need for our use case.

I have a collection of raw design tokens, which are transformed for different platforms. Now, I also have a collection of themes (semantic tokens) that use the raw tokens as an alias living in different files, plus add custom transparency. Themes also are then transformed for different platforms.

Issue

I have theme tokens like the following, and a custom transform to compile hex colors into different formats, but I'll use oklch as an example for web. As you can see I added a custom transparency attribute to use while generating the theme keys.

// light-theme.json
{
  "vibrancy": {
    "background": {
      // color.primary.100 comes from different file
      "value": "{color.primary.100}",
      "attributes": {
        "transparency": "60%",
        "category": "color"
      }
    },
  }
}

The issue is that inside the custom transform, when I access token.attributes, I get the attributes of the aliased token (color.primary.100) and not the attributes from vibrancy.background. I'm going mad about this.

Custom transform

import Color from 'colorjs.io';
import * as StyleDictionary from 'style-dictionary';

const OkLCH: StyleDictionary.Named<StyleDictionary.Transform> = {
  name: 'color/oklch',
  type: 'value',
  matcher: prop => prop.attributes?.category === 'color',
  transformer: (token) => {
    // token.attributes.transparency is undefined
    // and token object is color.primary.100 instead of vibrancy.background
    console.log(token.attributes?.transparency)

    // Do stuff
  },
};

export default OkLCH;

Config

const { hideBin } = require('yargs/helpers');

const yargs = require('yargs/yargs');

// Here import color tokens from another file.
const ColorTokens = require('../../tokens/src/configs/colors');

const { argv } = yargs(hideBin(process.argv));

module.exports = {
  source: [`./src/templates/${argv.name}/*.json`],
  tokens: {
    ...ColorTokens,
  },
  platforms: {
    web: {
      buildPath: 'dist/themes/',
      transformGroup: 'custom-web',
      files: [
        {
          format: 'css/variables',
          destination: `${argv.name}.css`,
        },
        {
          format: 'json/flat',
          destination: `${argv.name}.json`,
        },
      ],
      options: {
        showFileHeader: true,
      },
    },
  },
};

SD script

/* eslint-disable no-console */
import StyleDictionary from 'style-dictionary';

import OkLCH from './transformers/oklch';

const SDWithConfig = StyleDictionary.extend('src/themes.config');

/**
 * Register custom transformers to process token values for
 * the web platform
 */
SDWithConfig.registerTransform(OkLCH);

/**
 * Add the custom transformers to a new transformGroup `custom-web`
 * used inside tokens.config.json
 */
SDWithConfig.registerTransformGroup({
  name: 'custom-web',
  transforms: [
    'attribute/cti',
    'name/cti/kebab',
    'time/seconds',
    'content/icon',
    'size/rem',
    'color/oklch',
  ],
});

/**
 * Manually run StyleDictionary for all the configured platforms
 */
console.clear();
SDWithConfig.buildAllPlatforms();

Any idea how to do this? I'm doing it wrong or missing something? Since design tokens are raw values and both tokens and themes are transformed for multiple platforms, I need the themes to use raw tokens, and not compiled ones.

equinusocio commented 1 year ago

Who don't want to waste time, the fix is to transitive: true on the custom transform. This flag is hidden in the documentation. https://amzn.github.io/style-dictionary/#/transforms?id=transitive-transforms