amzn / style-dictionary

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

Transform tokens into data set referecing other root variables #1142

Open lwnoble opened 5 months ago

lwnoble commented 5 months ago

I need to transform tokes into data sets referencing other root variables.

I want to transform these tokens:

{
 "backgrounds": {
  "pink": {
    "background-color": {
      "value": "{mode-colors.magenta-10.background-color}",
      "type": "color"
    },
    "alt-background-color": {
      "value": "{mode-colors.magenta-10.alt-background-color}",
      "type": "color"
    },
    "background-on-color": {
      "value": "{mode-colors.magenta-10.background-on-color}",
      "type": "color"
    },
    "background-on-on-color": {
      "value": "{mode-colors.magenta-10.background-on-on-color}",
      "type": "color"
    },
    "background-on-color-quiet": {
      "value": "{mode-colors.magenta-10.background-on-quiet}",
      "type": "color"
    },
    "background-button": {
      "value": "{mode-colors.magenta-10.background-button}",
      "type": "color"
    },
    "background-button-half": {
      "value": "{mode-colors.magenta-10.background-button-half}",
      "type": "color"
    },
    "background-on-button": {
      "value": "{mode-colors.magenta-10.background-on-button}",
      "type": "color"
    },
    "background-hotlink": {
      "value": "{mode-colors.magenta-10.background-hotlink}",
      "type": "other"
    }
  }
}  

Into this css:

[data-background="pink"] {
  --background: var(--mode-colors.magenta-10.background-color);
  --background-alt:  var(--mode-colors.magenta-10.alt-background-color);
  --on-background: var(--mode-colors.magenta-10.background-on-color);
  --on-background-quiet: var(--mode-colors.magenta-10.background-on-quiet);;
  --hotlink: var(--mode-colors.magenta-10.background-hotlink);;
  --border: var(--mode-colors.magenta-10.background-border)
  --button: var(--mode-colors.magenta-10.background-button);
  --on-button: var(--mode-colors.magenta-10.background-on-button);
  --button-half: var(--mode-colors.magenta-10.background-button-half);
  }

I know I need to apply, format, and filter, but I don't know where to get started.

jorenbroekema commented 5 months ago

https://amzn.github.io/style-dictionary/#/formats?id=cssvariables you'll probably want to use options.outputReferences set to true

lwnoble commented 4 months ago

@jorenbroekema I tried following @dbanksdesign guidance for issue #261 to convert this

{
  "data-background": {
    "voilet-50": {
      "type": "group";
      "background-color": {
        "value": "{mode-colors.default.background-color}",
        "type": "color",
        "$extensions": {
          "studio.tokens": {
            "modify": {
              "type": "mix",
              "value": "{mix-in}",
              "space": "lch",
              "color": "#ffffff"
            }
          }
        }
      },
      "alt-background-color": {
        "value": "{mode-colors.default.alt-background-color}",
        "type": "color"
      },
      "background-on-color": {
        "value": "{text-dark}",
        "type": "color",     
      }
    }
  }
}

to the following css:

[data-background=“violet-50”] { --background: var(—mode-colors.violet-50.background-color); --background-alt: var(—mode-colors.violet-50.alt-background-color); --background-on-color: var(—text-dark); }

I know there is more formatting to do to get my desired results, but I am getting the folllowing error: "Build error: Cannot read properties of undefined (reading 'reduce')." See console logs for more info."

when using the following code in the Style-Dictionary Configurator:


import StyleDictionary from 'style-dictionary';
import { formattedVariables } from 'style-dictionary/utils';
import { fileHeader } from 'style-dictionary/utils';
import { registerTransforms } from '@tokens-studio/sd-transforms';

// sd-transforms, 2nd parameter for options can be added
// See docs: https://github.com/tokens-studio/sd-transforms
registerTransforms(StyleDictionary);

const groups = ["font-style", "color-theme", "data-background"];

StyleDictionary.registerTransform({
  name: "attribute/group",
  type: 'attribute',
  matcher: function(prop) {
    return groups.includes(prop.path.slice(0,2).join('-'));
  },
  transformer: function(prop) {
    return {
      // Brittle logic, the group is the 3rd level of the object path
      group: true,
      groupName: prop.path.slice(0,3).join('-')
    }
  }
});

StyleDictionary.registerFilter({
  name: 'core-filter',
  matcher: (token) => token.filePath.endsWith('core.json')
});

StyleDictionary.registerFilter({
  name: 'base-filter',
  matcher: (token) => token.filePath.endsWith('base.json')
});

StyleDictionary.registerFilter({
  name: 'background-filter',
  matcher: (token) => token.filePath.endsWith('base.json')
});

StyleDictionary.registerTransform({
  name: 'css/boolean-to-display',
  type: 'value',
  transformer: (token, _, options) => {
    const tokenType = options.usesDtcg ? token.$type : token.type;
    const tokenValue = options.usesDtcg ? token.$value : token.value;
    if (tokenType === 'boolean') {
      return tokenValue === 'true' ? 'block' : 'hidden';
    }
    return tokenValue;
  }
});

// Custom CSS format that is basically a copy of the built-in,
// except for the fact that we pass formatting options -> commentPosition
StyleDictionary.registerFormat({
  name: 'custom/css/variables',
  formatter: async function ({ dictionary, options = {}, file }) {
    const selector = options.selector ? options.selector : `:root`;
    const { outputReferences, outputReferenceFallbacks, usesDtcg } = options;
    const header = await fileHeader({ file });
    return (
      header +
      `${selector} {\n` +
      formattedVariables({
        format: 'css',
        dictionary,
        outputReferences,
        outputReferenceFallbacks,
        usesDtcg,
        formatting: {
          commentPosition: 'above'
        }
      }) +
      `\n}\n`
    );
  },
});

StyleDictionary.registerFormat({
  name: 'css/group',
  formatter: function(dictionary, config) {
    const groupMap = dictionary.allProperties.reduce(function(prev,curr) {
      if (!prev[curr.attributes.groupName]) {
        prev[curr.attributes.groupName] = [];
      }
      prev[curr.attributes.groupName].push(curr);
      return prev;
    },{});

    return Object.keys(groupMap).map(function(key) {
      let props = groupMap[key];
      return `.${key} {
${props.map(function(prop) {
  return `  ${prop.name}: ${prop.value};`
}).join('\n')}
}`
    }).join('\n\n');
  }
});

Any ideas how to get the results I am looking for or how to solve the error?

jorenbroekema commented 4 months ago

The dictionary.allProperties and dictionary.properties were deprecated in v3, and removed in v4 in favor of dictionary.allTokens and dictionary.tokens https://style-dictionary-v4.netlify.app/version-4/migration/#removed-deprecated-features