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

How do I transform the convention of my Style Dictionary variables.js after being compiled. To ignore they parent style folder #907

Closed tonyblu331 closed 1 year ago

tonyblu331 commented 1 year ago

This is my transform-token.js file:

const baseConfig = require('./style-dictionary.config.json');

StyleDictionary.registerTransform({
  name: 'size/px',
  type: 'value',
  matcher: token => {
    return (token.unit === 'pixel' || token.type === 'dimension') && token.value !== 0;
  },
  transformer: token => {
    return `${token.value}px`;
  },
});

StyleDictionary.registerTransform({
  name: 'size/percent',
  type: 'value',
  matcher: token => {
    return token.unit === 'percent' && token.value !== 0;
  },
  transformer: token => {
    return `${token.value}%`;
  },
});

StyleDictionary.registerTransformGroup({
  name: 'custom/css',
  transforms: StyleDictionary.transformGroup['css'].concat([
    'size/px',
    'size/percent',
  ]),
});

// StyleDictionary.registerFilter({
//   name: 'validToken',
//   matcher: function(token) {
//     return ['dimension', 'string', 'number', 'color'].includes(token.type)
//   }
// });

StyleDictionary
  .extend(baseConfig)
  .buildAllPlatforms();

And when we build we get this: TypographyTypographyHeadersSubheadersSubheading1400 instead of getting something like: "Subheading1400"

This how tokens are getting exported to their typography.json

  "typography": {
    "typography": {
      "headers": {
        "subheaders": {
          "subheading1-400": {
            "value": {
              "font": {
                "type": "font",
                "value": {
                  "family": {
                    "type": "string",
                    "value": "Plus Jakarta Sans"
                  },
                  "subfamily": {
                    "type": "string",
                    "value": "Regular"
                  }
                }
              },

It seems it is taking all the parent folders from this style inside Figma and putting it into the variable name.

nahiyankhan commented 1 year ago

Based on what's shared - you likely need a custom name transform. By default, it is taking the whole path and using that for the name. You could instead tell it only use the last item in the path (or some other predictable format).

tonyblu331 commented 1 year ago

I am more on the design side of things, so how could I build this?

nahiyankhan commented 1 year ago

Nice! Appreciate a designer on the code side of things. So, a transform like this could work assuming you just want the last reference in the path, the example Subheading1400. Uses lodash for the case.

const _ = require('lodash');

SD.registerTransform({
    name: 'custom/name',
    type: 'name',
    transformer: token => {
      return _.upperFirst(_.camelCase(token.path.at(-1))
    }
  })

Your transform-token.js references CSS transforms but the output example is JSON. Would need to peek at your style-dictionary.config.json file to suggest where to apply it.

tonyblu331 commented 1 year ago

This is how my config file looks like

  "source": [
    "src/design-tokens/json/**/*.json"
  ],
  "platforms": {
    "css": {
      "transformGroup": "css",
      "prefix": "sr",
      "buildPath": "src/design-tokens/css/",
      "files": [
        {
          "destination": "_variables.css",
          "format": "css/variables"
        }
      ]
    },
    "js": {
      "transformGroup": "js",
      "buildPath": "src/design-tokens/js/",
      "files": [
        {
          "destination": "variables.js",
          "format": "javascript/es6"
        }
      ]
    }
  }
}

Thanks a lot for sharing. Yes, I do like coding and want to get more into it. I appreciate a lot to help.

nahiyankhan commented 1 year ago

Gotcha! So a few things then. Your original transform-token.js file would have something like my suggested added and then the custom/css transformGroup needs to be tweaked to reference it instead of the built in name transform.

const _ = require('lodash');

SD.registerTransform({
    name: 'custom/name',
    type: 'name',
    transformer: token => {
      return _.upperFirst(_.camelCase(token.path.at(-1))
    }
  })

StyleDictionary.registerTransformGroup({
  name: 'custom/css',
  transforms: [
    'attribute/cti',
    'custom/name',
    'time/seconds',
    'content/icon',
    'size/rem',
    'color/css'
  ]
});

After this, the config files need to reference the right transformGroup. In yours I am seeing its still referencing the built in css group.

  "source": [
    "src/design-tokens/json/**/*.json"
  ],
  "platforms": {
    "css": {
      "transformGroup": "custom/css",
      "prefix": "sr",
      "buildPath": "src/design-tokens/css/",
      "files": [
        {
          "destination": "_variables.css",
          "format": "css/variables"
        }
      ]
    },
    "js": {
      "transformGroup": "js",
      "buildPath": "src/design-tokens/js/",
      "files": [
        {
          "destination": "variables.js",
          "format": "javascript/es6"
        }
      ]
    }
  }
}

Let me know if its hard to follow. Another thing I noticed is that you have a token prefix "sr" and if you intend to keep it, then the custom/name transform would have to be tweaked to add it. Like so -

SD.registerTransform({
    name: 'custom/name',
    type: 'name',
    transformer: function(token, options) {
      return _.upperFirst(_.camelCase([options.prefix].concat(token.path.at(-1)))
    }
  })

(btw - am a designer turned engineer! I know the journey!)

tonyblu331 commented 1 year ago

It's been a while, thanks a lot for the help. We didn't manage to fix it, as it was probably something there, but I am still honing my coding skills. Regardless, here is the case study for this project if you want to take a look at it: https://abonet.me/re-play