Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@tokens-studio/sd-transforms

tokens-studio371.9kMIT1.3.0TypeScript support: included

Custom transforms for Style-Dictionary, to work with Design Tokens that are exported from Tokens Studio

design tokens, figma, style-dictionary

readme

Style Dictionary Transforms for Tokens Studio

NPM version badge License badge

Note: this README contains examples that assume latest version of this package & v4 style-dictionary latest prerelease.

Table of contents

This package contains custom transforms for Style-Dictionary, to work with Design Tokens that are exported from Tokens Studio:

Generic:

  • Optionally excludes parent keys from your tokens file, e.g. when using single-file export from Tokens Studio Figma plugin -> preprocessor
  • Maps token descriptions to comments -> ts/descriptionToComment
  • Check and evaluate Math expressions (transitive) -> ts/resolveMath
  • Transform dimensions tokens to have px as a unit when missing (transitive) -> ts/size/px
  • Transform opacity from % to number between 0 and 1 -> ts/opacity
  • Transform lineheight from % to unitless (150% -> 1.5) -> ts/size/lineheight
  • Transform fontweight from keynames to fontweight numbers (100, 200, 300 ... 900) -> ts/typography/fontWeight
  • Transform color modifiers from Tokens Studio to color values -> ts/color/modifiers

CSS:

  • Transform letterspacing from % to em -> ts/size/css/letterspacing
  • Transform colors to rgba() format -> ts/color/css/hexrgba
  • Transform shadow "type" property "innerShadow" to "inset" -> ts/shadow/innerShadow

Android:

  • Transform typography objects to Android Compose shorthand -> ts/typography/compose/shorthand

Registers the generic and CSS transforms as a transform group called tokens-studio.

Installation

With NPM:

npm install @tokens-studio/sd-transforms

Compatibility

This package is to be used in combination with Style Dictionary.

There are some caveats however, with regards to which versions of Style Dictionary are compatible with which versions of this package:

Style Dictionary sd-transforms
3.0.0 - 4.0.0-prerelease.1 <= 0.12.2
4.0.0-prerelease.2** - **4.0.0-prerelease.18 0.13.0 - 0.14.4
4.0.0-prerelease.18 - 4.0.0-prerelease.26 0.15.0 - 0.15.2
>= 4.0.0-prerelease.27 >= 0.16.0
>= 4.0.0 >= 1.0.0

Now that Style Dictionary v4 is released, and sd-transforms v1 is released and out of alpha state,both APIs are stable and the recommendation is to use these.

Usage

[!NOTE] This library is only available in ESM

import { register } from '@tokens-studio/sd-transforms';
import StyleDictionary from 'style-dictionary';

// will register them on StyleDictionary object
// that is installed as a dependency of this package.
register(StyleDictionary);

const sd = new StyleDictionary({
  // make sure to have source match your token files!
  // be careful about accidentally matching your package.json or similar files that are not tokens
  source: ['tokens/**/*.json'],
  preprocessors: ['tokens-studio'], // <-- since 0.16.0 this must be explicit
  platforms: {
    css: {
      transformGroup: 'tokens-studio', // <-- apply the tokens-studio transformGroup to apply all transforms
      transforms: ['name/kebab'], // <-- add a token name transform for generating token names, default is camel
      buildPath: 'build/css/',
      files: [
        {
          destination: 'variables.css',
          format: 'css/variables',
        },
      ],
    },
  },
});

await sd.cleanAllPlatforms();
await sd.buildAllPlatforms();

To run it use the following command

node build-output.js

Using the preprocessor

You must add the 'tokens-studio' preprocessor explicitly in the configuration:

{
  "source": ["tokens/**/*.json"],
  "preprocessors": ["tokens-studio"],
  "platforms": {}
}

This allows fontStyles to be extracted when they are embedded in fontWeights, aligns Tokens Studio token types with DTCG token types, and allows excluding parent keys for single-file Tokens Studio exports.

[!TIP] The align types part of the preprocessor aligns Tokens Studio token types to DTCG token types. The original Tokens Studio type in this scenario will be stored at $extensions['studio.tokens'].originalType if this happens. This allows you to use the original type e.g. for token filtering/matching for your custom transforms.

Using "Expand"

Expand used to be an sd-transforms exclusive feature but has moved to Style Dictionary itself under a slightly different API. This made sense due to object-value tokens being part of the DTCG spec and no longer a Tokens Studio specific feature.

When using the expand feature of Style Dictionary to expand object-value (composite) tokens, you should pass our additional expandTypesMap for Tokens Studio tokens, because these are slightly different from the DTCG tokens:

  • shadow tokens are called boxShadow and their offsetX and offsetY props are called x and y respectively.
  • typography tokens have some additional properties in Tokens Studio:
    • paragraphSpacing -> dimension
    • paragraphIndent -> dimension
    • textDecoration -> other
    • textCase -> other

Due to the Style Dictionary object-value tokens expansion happening before custom preprocessors such as the sd-transforms preprocessor, which aligns Tokens Studio token types with DTCG token types, this has to be configured like so:

import StyleDictionary from 'style-dictionary';
import { expandTypesMap } from '@tokens-studio/sd-transforms';

const sd = new StyleDictionary({
  source: ['tokens/**/*.json'],
  preprocessors: ['tokens-studio'],
  expand: {
    typesMap: expandTypesMap,
  },
  platforms: {},
});

Using the transforms

{
  "source": ["tokens/**/*.json"],
  "preprocessors": ["tokens-studio"],
  "platforms": {
    "css": {
      "transformGroup": "tokens-studio",
      "transforms": ["name/kebab"],
      "buildPath": "build/css/",
      "files": [
        {
          "destination": "variables.css",
          "format": "css/variables"
        }
      ]
    },
    "scss": {
      "transforms": ["ts/size/px", "ts/opacity", "name/kebab"],
      "buildPath": "build/scss/",
      "files": [
        {
          "destination": "variables.scss",
          "format": "scss/variables"
        }
      ]
    }
  }
}

More fine-grained control is possible, every transformation is available as a raw JavaScript function for you to create your own Style-Dictionary transform out of.

import { transformDimension } from '@tokens-studio/sd-transforms';
import StyleDictionary from 'style-dictionary';

StyleDictionary.registerTransform({
  name: 'my/size/px',
  type: 'value',
  transitive: true,
  filter: token => ['fontSizes', 'dimension', 'borderRadius', 'spacing'].includes(token.type),
  transform: token => transformDimension(token.value),
});

Custom Transform Group

[!NOTE] From Style-Dictionary 4.0.0-prerelease.18, transformGroup and transforms can now be combined in a platform inside your config.

You can create a custom transformGroup that includes the individual transforms from this package. If you wish to use the transformGroup, but adjust or remove a few transforms, your best option is to create a custom transform group:

import { getTransforms } from '@tokens-studio/sd-transforms';
import StyleDictionary from 'style-dictionary';

// Register custom tokens-studio transform group
// without 'px' being added to numbers without a unit
// and also adding 'name/constant' for the token names
StyleDictionary.registerTransformGroup({
  name: 'custom/tokens-studio',
  // default value for platform is css, specifies which Tokens Studio transforms for which platform to grab
  transforms: [...getTransforms({ platform: 'css' }), 'name/constant'].filter(
    transform => transform !== 'ts/size/px',
  ),
});

Note that you can also manually grab some of the SD built-in transforms by using StyleDictionary.hooks.transformGroups or StyleDictionary.hooks.transforms

Options

You can pass options to the register function.

register(StyleDictionary, {
  excludeParentKeys: true,
  platform: 'css',
  name: 'tokens-studio',
  'ts/color/modifiers': {
    format: 'hex',
  },
});

Options:

name type required default description
excludeParentKeys boolean false Whether or not to exclude parent keys from your token files
platform 'css'|'compose' css Which platform to use the transforms for.
name string tokens-studio Under which name to register the transformGroup
withSDBuiltins boolean true Whether to append the Style Dictionary built-in transformGroup transforms for the configured platform into the tokens-studio transformGroup.
alwaysAddFontStyle boolean false Whether or not to always add a 'normal' fontStyle property to typography tokens which do not have explicit fontStyle
['ts/color/modifiers'] ColorModifierOptions See props below Color modifier options
['ts/color/modifiers'].format ColorModifierFormat undefined Color modifier output format override ('hex' | 'hsl' | 'lch' | 'p3' | 'srgb'), uses local format or modifier space as default

[!NOTE] You can also import and use the parseTokens function to run the parsing steps on your tokens object manually. Handy if you have your own preprocessors set up (e.g. for JS files), and you want the preprocessor-based features like composites-expansion to work there too.

Theming

Themes: complete example

You might be using Themes in the PRO version of Tokens Studio.

Here's a full example of how you can use this in conjunction with Style Dictionary and sd-transforms:

Run this script:

import { register } from '@tokens-studio/sd-transforms';
import StyleDictionary from 'style-dictionary';
import { promises } from 'fs';

register(StyleDictionary, {
  /* options here if needed */
});

async function run() {
  const $themes = JSON.parse(await promises.readFile('$themes.json', 'utf-8'));
  const configs = $themes.map(theme => ({
    source: Object.entries(theme.selectedTokenSets)
      .filter(([, val]) => val !== 'disabled')
      .map(([tokenset]) => `${tokenset}.json`),
    preprocessors: ['tokens-studio'], // <-- since 0.16.0 this must be explicit
    platforms: {
      css: {
        transformGroup: 'tokens-studio',
        transforms: ['name/kebab'],
        files: [
          {
            destination: `vars-${theme.name}.css`,
            format: 'css/variables',
          },
        ],
      },
    },
  }));

  async function cleanAndBuild(cfg) {
    const sd = new StyleDictionary(cfg);
    await sd.cleanAllPlatforms(); // optionally, cleanup files first..
    await sd.buildAllPlatforms();
  }
  await Promise.all(configs.map(cleanAndBuild));
}

run();

Multi-dimensional Theming

If you're using Tokens Studio multi-dimensional theming, you'll have to run some logic to create permutations of those multiple dimensions of themes. We export a function called permutateThemes that allows passing the data from your $themes.json, and will give back an object with all the different permutations.

For example, consider the following multi-dimensional theme hierarchy (Group > Theme > TokenSet):

mode
  |-- light
  |     `-- core, light, theme
  `-- dark
        `-- core, dark, theme

brand
  |-- casual
  |     `-- core, casual
  `-- business
        `-- core, business

Here we have two groups:

  1. mode: has two themes light & dark
  2. brand: has two themes casual & business

Running permutateThemes on these themes will generate 4 theme combinations:

  1. light_casual
  2. dark_casual
  3. light_business
  4. dark_business

See details below:

import { permutateThemes } from '@tokens-studio/sd-transforms';
import fs from 'fs';

/**
 * Input:
 * [
 *  {
 *    name: 'light'
 *    group: 'mode',
 *    selectedTokensets: {
 *      'core': 'source',
 *      'light': 'enabled',
 *      'theme': 'enabled'
 *    }
 *  },
 *  {
 *    name: 'dark'
 *    group: 'mode',
 *    selectedTokensets: {
 *      'core': 'source',
 *      'dark': 'enabled',
 *      'theme': 'enabled'
 *    }
 *  },
 *  {
 *    name: 'casual'
 *    group: 'brand',
 *    selectedTokensets: {
 *      'core': 'source',
 *      'casual': 'enabled'
 *    }
 *  },
 *  {
 *    name: 'business'
 *    group: 'brand',
 *    selectedTokensets: {
 *      'core': 'source',
 *      'business': 'enabled'
 *    }
 *  }
 * ]
 *
 * Output:
 * {
 *   light_casual: ['core', 'light', 'theme', 'casual'],
 *   dark_casual: ['core', 'dark', 'theme', 'casual'],
 *   light_business: ['core', 'light', 'theme', 'business'],
 *   dark_business: ['core', 'dark', 'theme', 'business'],
 * }
 */
permutateThemes(JSON.parse(fs.readFileSync('$themes.json', 'utf-8')), { separator: '_' });

Note that it is a best practice to generate standalone output files for each theme combination. In the example above, we should generate 4 standalone CSS file light_casual.css, dark_casual.css, light_business.css and dark_business.css. We can then switch between them to change themes. Avoid generating all this output in a single file and trying to select different sections of the file. This will increase the file size as the number of theme combinations grows resulting in increased load times.

Full example with multi-dimensional themes:

import { register, permutateThemes } from '@tokens-studio/sd-transforms';
import StyleDictionary from 'style-dictionary';
import { promises } from 'fs';

register(StyleDictionary, {
  /* options here if needed */
});

async function run() {
  const $themes = JSON.parse(await promises.readFile('$themes.json', 'utf-8'));
  const themes = permutateThemes($themes, { separator: '_' });
  const configs = Object.entries(themes).map(([name, tokensets]) => ({
    source: tokensets.map(tokenset => `${tokenset}.json`),
    preprocessors: ['tokens-studio'], // <-- since 0.16.0 this must be explicit
    platforms: {
      css: {
        transformGroup: 'tokens-studio',
        transforms: ['name/kebab'],
        files: [
          {
            destination: `vars-${name}.css`,
            format: 'css/variables',
          },
        ],
      },
    },
  }));

  async function cleanAndBuild(cfg) {
    const sd = new StyleDictionary(cfg);
    await sd.cleanAllPlatforms(); // optionally, cleanup files first..
    await sd.buildAllPlatforms();
  }
  await Promise.all(configs.map(cleanAndBuild));
}

run();

You can find a variation of this example here. It outputs a CSS file for every theme combination for every component, e.g. button-business-blue.css, date-picker-business-blue.css and so on. This caters to use cases where component-level tokens as required, e.g. when implementing Web Components.

Single-file tokens example

This is not recommended because it's a pretty complex workaround. The best method is to just migrate to multi-file tokens export.

The same full example as above but assuming single token-file export.

What it does is, take your single "tokens.json" file and turn it into multi-file by persisting the sets as separate files in a "tokens" folder and then creating the SD config accordingly.

import { register, permutateThemes } from '@tokens-studio/sd-transforms';
import StyleDictionary from 'style-dictionary';
import { readFile, writeFile, mkdir } from 'fs/promises';
import { dirname } from 'node:path/posix';

register(StyleDictionary, {
  /* options here if needed */
});

async function run() {
  const tokens = JSON.parse(await readFile('tokens.json', 'utf-8'));
  const { $themes, ...sets } = tokens;

  const persistSet = async ([setName, setTokens]) => {
    const fileName = `tokens/${setName}.json`;
    const dirName = dirname(fileName);
    try {
      await mkdir(dirName, { recursive: true });
    } catch (e) {
      // do nothing, dir already exists
    }
    await writeFile(fileName, JSON.stringify(setTokens, null, 2), 'utf-8');
  };

  // persist sets as multi file in tokens folder
  await Promise.all(Object.entries(sets).map(persistSet));

  const themes = permutateThemes($themes, { separator: '_' });
  const configs = Object.entries(themes).map(([name, tokensets]) => ({
    source: Object.keys(sets)
      .filter(setName => tokensets.includes(setName))
      .map(setName => `tokens/${setName}.json`),
    preprocessors: ['tokens-studio'], // <-- since 0.16.0 this must be explicit
    platforms: {
      css: {
        transformGroup: 'tokens-studio',
        transforms: ['name/kebab'],
        files: [
          {
            destination: `vars-${name}.css`,
            format: 'css/variables',
          },
        ],
      },
    },
  }));

  async function cleanAndBuild(cfg) {
    const sd = new StyleDictionary(cfg);
    await sd.cleanAllPlatforms(); // optionally, cleanup files first..
    await sd.buildAllPlatforms();
  }
  await Promise.all(configs.map(cleanAndBuild));
}

run();

Transforms

ts/descriptionToComment

This transform maps token descriptions into comments.

Also converts carriage return \r into \n and \r\n into just \n.

matches: All tokens that have a description property.

before

{
  "token": {
    ...
    "description": "Some description about the token",
  }
}

after

{
  "token": {
    ...
    "description": "Some description about the token",
    "comment": "Some description about the token",
  }
}

ts/resolveMath

This transform checks and evaluates math expressions

matches: All tokens that have string values.

You can adjust to how many decimals the result should be rounded using PlatformConfig.mathFractionDigits:

{
  "source": ["tokens.json"],
  "platforms": {
    "css": {
      "mathFractionDigits": 3,
      "transformGroup": "tokens-studio",
      "files": [
        {
          "format": "css/variables",
          "destination": "output.css"
        }
      ]
    }
  }
}

before

{
  "token-one": {
    ...
    "value": "4*1.5px 4*1.5px 4*1.5px"
  },
  "token-two": {
    ...
    "value": "4 * 7"
  }
}

after

{
  "token-one": {
    ...
    "value": "6px 6px 6px"
  },
  "token-two": {
    ...
    "value": "28"
  }
}

ts/size/px

This transform adds px as a unit when dimension-like tokens do not have a unit.

matches: token.type is one of ['fontSize', 'dimension', 'border', 'typography', 'shadow']

before

{
  "token": {
    "type": "dimension",
    "value": 4
  }
}

after

{
  "token": {
    "type": "dimension",
    "value": "4px"
  }
}

ts/opacity

This transforms opacity token values declared with % into a number between 0 and 1.

matches: token.type is 'opacity'

before

{
  "token": {
    "type": "opacity",
    "value": "50%"
  }
}

after

{
  "token": {
    "type": "opacity",
    "value": 0.5
  }
}

ts/size/lineheight

This transforms line-height token values declared with % into a unitless value.

matches: token.type is 'lineHeight' or token.type is 'typography'

before

{
  "token": {
    "type": "lineHeights",
    "value": "50%"
  }
}

after

{
  "token": {
    "type": "lineHeights",
    "value": 0.5
  }
}

ts/typography/fontWeight

This transforms fontweight from keynames to fontweight numbers.

matches: token.type is 'fontWeight' or token.type is 'typography'

before

{
  "token-one": {
    "type": "fontWeights",
    "value": "Bold"
  },
  "token-two": {
    "type": "fontWeights",
    "value": "Light"
  }
}

after

{
  "token-one": {
    "type": "fontWeights",
    "value": "700"
  },
  "token-two": {
    "type": "fontWeights",
    "value": "300"
  }
}

ts/color/modifiers

This transforms color modifiers from Tokens Studio to color values.

matches: token.type is 'color' and has token.$extensions['studio.tokens'].modify

before

{
  "token-one": {
    "value": "#C14242",
    "type": "color",
    "$extensions": {
      "studio.tokens": {
        "modify": {
          "type": "lighten",
          "value": "0.2",
          "space": "srgb"
        }
      }
    }
  },
  "token-two": {
    "value": "#C14242",
    "type": "color",
    "$extensions": {
      "studio.tokens": {
        "modify": {
          "type": "darken",
          "value": "0.2",
          "space": "hsl"
        }
      }
    }
  }
}

after

{
  "token-one": {
    "value": "rgb(80.5% 40.7% 40.7%)",
    "type": "color"
  },
  "token-two": {
    "value": "hsl(0 50.6% 40.6%)",
    "type": "color"
  }
}

ts/size/css/letterspacing

This transforms letter-spacing token values declared with % to a value with em.

matches: token.$extensions['studio.tokens'].originalType is 'letterSpacing' or token.type is 'typography'

before

{
  "token": {
    "type": "letterSpacing",
    "value": "50%"
  }
}

after

{
  "token": {
    "type": "letterSpacing",
    "value": "0.5em"
  }
}

ts/color/css/hexrgba

This transforms color token values with Figma's "hex code RGBA" into actual rgba() format

matches: token.type is 'color'

before

{
  "token": {
    "type": "color",
    "value": "rgba(#ABC123, 0.5)"
  }
}

after

{
  "token": {
    "type": "color",
    "value": "rgba(171, 193, 35, 0.5)"
  }
}

ts/shadow/innerShadow

This transforms shadow tokens to ensure that the type property gets converted from innerShadow to inset (CSS compatible).

matches: token.type is 'shadow'

before

{
  "token": {
    "type": "color",
    "value": {
      "offsetX": "0",
      "offsetY": "4px",
      "blur": "10px",
      "color": "#000",
      "type": "innerShadow"
    }
  }
}

after

{
  "token": {
    "type": "color",
    "value": {
      "offsetX": "0",
      "offsetY": "4px",
      "blur": "10px",
      "color": "#000",
      "type": "inset"
    }
  }
}

Not sure how to fix your issue?

Create a reproduction by:-

  1. Open the configurator tool link
  2. Upload your tokens and add your style dictionary config and transforms
  3. Copy the URL as it will include your settings
  4. Join our Slack link
  5. Open style-dictionary-configurator channel
  6. Create a thread about your issue and paste your reproduction link inside it

changelog

@tokens-studio/sd-transforms

1.3.0

Minor Changes

  • a8f4c73: - Supporting color modifier value calculations
    • Changing the default color precision to the ColorJS default of 5
    • Updating the integration tests to use vitest instead of mocha chai

1.2.12

Patch Changes

  • 9801a8f: Specify version range for SD peer dep to specifically support the 5.0.0 release candidates.

1.2.11

Patch Changes

  • 59d9d7f: Migrate to latest Style Dictionary v4 and allow v5 in peerDependencies for now, as v5 doesn't plan to be a breaking change for packages like this one.

1.2.10

Patch Changes

  • ab40f11: avoid checkAndEvaluateMath returning NaN

1.2.9

Patch Changes

  • e0aab62: Fix ts/size/px transform to handle multi-value token values such as 'button.padding': { value: '4 8' }.

1.2.8

Patch Changes

  • 5de4025: Addressed issue #316 about letterSpacing. LetterSpacing is no longer a dimension token. Also, the expand composition test token has been modify to test if the letterSpacing still works properly.

1.2.7

Patch Changes

  • fb3c7d3: Export TransformOption type to be publicly available (#319)
  • 26cf7f9: -Made the font weight case insensitive; Extra checks for style and weight values, confusions cleared up in the code; Font style and value are not both mandatory, it is fine if only one is specified; If font style is not provided, the style field will take the weight value; The bug from issue #267 is fixed.

1.2.6

Patch Changes

  • b4461f4: Ensure that shadow value is still of type object (either Object or Array) before attempting to resolve math for each property/item.

1.2.5

Patch Changes

  • 61af02f: Check for color transforms that the value is of type string, since other color object types could occur from previously ran transforms.

1.2.4

Patch Changes

  • b9aee1e: Fix lineHeight transform to keep numbers as numbers, and not stringify them.

1.2.3

Patch Changes

  • 1085fe8: Improve math compute utility to better deal with mixed units computations. Expand on tests.

1.2.2

Patch Changes

  • 0dea2af: fix: evaluate math expressions with units
  • 4fe336f: Override lineHeight expandTypesMap from SD. Add letterSpacing override. This is needed for our lineHeight and letterSpacing transforms to apply.

1.2.1

Patch Changes

  • c6c9223: Add composition to expandTypesMap.
  • 19f4530: Fix alwaysAddFontStyle option to not apply to tokens of type fontWeight(s), only meant for typography tokens.
  • 32c2d13: textCase and textDecoration types should be kept, instead of changing to "other". This should help with transforms targeting those tokens, whereas "other" is not a useful type conversion whatsoever.
  • 3a044ed: Remove the boxShadow expandTypesMap, this is no longer needed since SD 4.0.1 as it runs user defined preprocessors before expanding tokens.

1.2.0

Minor Changes

  • ff31df8: Add lineHeight and fontWeight types to the expandTypesMap. Even though DTCG spec does not yet recognize them, they really are special types and marking them as such enables transforms to target them specifically.
  • ff31df8: Properly split fontWeight tokens that contain fontStyle into the parent group. For typography tokens this was correct but for fontWeight tokens, collision could occur between the token and its sibling tokens.

1.1.0

Minor Changes

  • c687817: Add the originalType property to $extensions.['studio.tokens'] to store the original Tokens Studio token type, when the type is aligned to DTCG types. LetterSpacing transform is the transform in this package that actually needs to use this, because it doesn't want to match all dimension tokens, but it does want to match letterSpacing tokens.
  • ed10715: Allow changing the resolve math transform amount of decimals to round for using platform options mathFractionDigits, change default value from 3 to 4.

Patch Changes

  • c687817: Fix alignTypes to also include borderWidth, letterSpacing, paragraphSpacing and paragraphIndent and align them to dimension.
  • 9c02741: Fix bug where usesDtcg flag was not passed to resolveReference utility.

1.0.1

Patch Changes

  • 6c7b2ff: Fix tsconfig to exclude test files and ensure dist folder structure is correct.

1.0.0

Major Changes

  • 67edf4b: BREAKING: descriptionToComment transform no longer removes newlines, just turns carriage returns into newlines. Style Dictionary now handles comments with newlines properly in its createPropertyFormatter utility.
  • 67edf4b: BREAKING: Remove expand option, composite/object-value tokens must be expanded by using Style Dictionary Expand.
  • 67edf4b: BREAKING: remove CommonJS entrypoint and tools/scripts required to dual publish. Now that Style Dictionary v4 is ESM-only, this library will follow suit.
  • 67edf4b: BREAKING: transformFontWeights has been renamed to transformFontWeight for consistency.

    Apply transforms to object-value (composite) token types:

    • HEXRGBa transform applies to border and shadow colors
    • Px dimension transform applies to border, typography and shadow dimensions
    • Letterspacing, lineheights and fontweights transforms apply to these respective typography properties
    • Resolve math transform applies to all properties of border, typography and shadow tokens

    This also means that all transforms except for description to comment mapping are now transitive transforms, since the math resolve transform must be transitive and all other transforms must apply after the math one.

  • 67edf4b: BREAKING: remove CSS shorthand transforms for border, typography and shadow. Use the Style Dictionary transforms instead: https://styledictionary.com/reference/hooks/transforms/predefined/#bordercssshorthand.

    Note that if you're not disabling the withSDBuiltins option, the tokens-studio transformGroup will include the ones in the css built-in transformGroup, so you might not notice the fact that they are moved.

  • 67edf4b: - BREAKING: Compatible with Style Dictionary >= v4.0.0. Not compatible with anything below that SD version.

    • BREAKING: registerTransforms function has been renamed to register.
    • BREAKING: transforms array has been refactored to getTransforms(), which is a function you should call. Optionally pass in the new platform option as parameter { platform: 'css' /* or 'compose' */}
    • BREAKING: By default, registered tokens-studio transformGroup will include the platform's Style Dictionary built-in transforms. E.g. if you're registering for platform css it will include the css transformGroup transforms from Style Dictionary, appended to the Tokens Studio specific transforms. This behavior can be disabled by passing { withSDBuiltins: false }.
    • Allow passing platform to the register() call: register(SD, { platform: 'compose' }). Default value is 'css'. This means your tokens-studio group will be registered for that specific platform.
    • Allow passing name to the register() call to configure the transformGroup name: register(SD, { name: 'tokens-studio-css' }). Default value is tokens-studio.

Minor Changes

  • 67edf4b: Adjust add-font-styles parser to also run on tokens of type fontWeight, to create a sibling token for the fontStyle if it is included in the fontWeight token.
  • 67edf4b: Add an adjust-types preprocessor utility that aligns the Tokens Studio types / object-value props with the DTCG ones.

0.16.1

Patch Changes

  • 3ab8d64: Restructure evaluate math util to support expr eval expressions in combination with regular math.
  • 3ab8d64: Allow math expressions where multiple components contain units, as long as they are still computable.

0.16.0

Minor Changes

  • 5856621: BREAKING: update to Style Dictionary v4.0.0-prerelease.27, set preprocessor name to 'tokens-studio', which now has to be applied if you want to exclude parent keys, expand composite types or add font style properties to typography values.

0.15.2

Patch Changes

  • 7617f9d: Pass colorspace to mix modifier, to use the correct color space to mix in.

0.15.1

Patch Changes

  • 000b202: Update to latest style-dictionary pre.22

0.15.0

Minor Changes

  • 09b1fc0: BREAKING: remove options addAttributeCTI & casing. Since transformGroup can now be combined with transforms, this is now much easier to accomplish in Style-Dictionary without additional sd-transforms options.

    Before:

    registerTransforms(StyleDictionary, { addAttributeCTI: true, casing: 'kebab' });

    After:

    {
      "platforms": {
        "css": {
          "transformGroup": "tokens-studio",
          "transforms": ["attribute/cti", "name/kebab"]
        }
      }
    }

    From this version onwards, Style-Dictionary v4.0.0-prerelease.19 minimum is required.

0.14.4

Patch Changes

  • 41d83fa: Add "book" to named font weights, converted to 400

0.14.3

Patch Changes

  • 9351782: Fix expand utility with latest style-dictionary prerelease.16, values would end up undefined due to bad reference resolve.

0.14.2

Patch Changes

0.14.1

Patch Changes

  • f5a8b12: Copy metadata from composite type tokens when expanding.

0.14.0

Minor Changes

0.13.4

Patch Changes

  • 8bde22d: Support references in color modifiers now that style-dictionary transformers can defer themselves.
  • 771428a: Fix expanding composition tokens flattening to not occur for certain object values and resulting in [object Object].

0.13.3

Patch Changes

  • cfc0c3d: Fix rgba(hex, alpha) regex to allow percentages, add more tests for different types of alpha values.

0.13.2

Patch Changes

  • 3f97dc2: Remove trailing console logs from previous update.

0.13.1

Patch Changes

  • 7409419: Use expr-eval-fork to work around a prototype pollution vulnerability in the original package.

0.13.0

Minor Changes

  • 6c95fe4: BREAKING: remove code that allowed user to not pass StyleDictionary instance to registerTransforms, and grabbed the locally installed StyleDictionary automatically. This seemed like a cool feature at first, but can cause hard to trace bugs if there are multiple installations of style-dictionary (due to incompatible semver).
  • 6c95fe4: Will now use preprocessors instead of parsers when user Style-Dictionary is v4.0.0-prerelease.2 or higher. Fixes an issue with multi-file references not being resolvable when running composite token expansion or add font style utilities.

0.12.2

Patch Changes

0.12.1

Patch Changes

  • e7ecf43: Fixes transform HEXRGBa format when this format is contained within a value, e.g. linear-gradient() or multi-value.

0.12.0

Minor Changes

  • 6f4b5ed: BREAKING: swap expandComposites 2nd argument and 3rd argument. 2nd argument is now TransformOptions and 3rd argument the filePath (string). This used to be vice versa and was inconsistent with the other parser functions.
  • 6f4b5ed: Add and expose a parseTokens function to make it more developer friendly to add the sd-transforms parsing step to your own custom parser.
  • f7e88b6: BREAKNG: Use structuredClone instead of shallow Object.assign copy in parsers. Must use NodeJS v17 at minimum now, as opposed to v15.14.0 before this update.
  • 6f4b5ed: Add the addAttributeCTI option to registerTransforms function, to automatically add attribute/cti predefined transform to the tokens-studio transformGroup.

Patch Changes

  • 2307b9d: Refined CSS font name processing: Enhanced escapeApostrophes for accurate apostrophe handling in font names. Updated quoteWrapWhitespacedFont for smart quoting and escaping in multi-word fonts. Ensures better CSS font family compatibility.

0.11.10

Patch Changes

  • 8c2e03f: Fix types for expandComposites functions, no longer trips up on key value pairs with primitive values during parsing process.

0.11.9

Patch Changes

  • a3ad58b: Fix the webpackIgnore statement to use single *. For NextJS integration (webpack).

0.11.8

Patch Changes

  • dd58528: Remove reliance on browser-style-dictionary. This created problems with CJS style-dictionary config files (default export).

0.11.7

Patch Changes

  • 72b828d: Fix permutateThemes to order "enabled" sets below "source" sets so enabled sets overrides are prioritized in Style-Dictionary.

0.11.6

Patch Changes

  • 2e8576e: resolveMath no longer unnecessarily changes the token type to number if the token value is a string without any expressions to resolve.

0.11.5

Patch Changes

  • Fix resolve reference for multi-value shadow tokens when expanding shadow tokens.

0.11.4

Patch Changes

  • 77b4f04: Add a webpack ignore statement to dynamic import of node builtin in node env. Should be ignored at compile-time, done at run-time.

0.11.3

Patch Changes

  • 333355b: Specify import to "module" as "node:module" for build tools to better understand it as a built-in.

0.11.2

Patch Changes

  • 3f37446: Fix for add-font-styles parser to deal with value props not being objects (e.g. null).

0.11.1

Patch Changes

  • 597ddcd: Slightly adjust how math evaluation is done on non-numeric string and boolean values, so as to not remove quotes inside strings.
  • e486d94: Handle fonts that put only fontStyle inside fontWeight properly e.g. "Italic", which should resolve to weight "Regular" and style "Italic".
  • 40e1b27: Add alwaysAddFontStyle to recursive function parameters.

0.11.0

Minor Changes

  • 96a66a9: checkAndEvaluateMath to not stringify if not needed:

    • for single math expressions resolving to a floating number without unit, we can keep it as a Number
    • for expressions such as false or true (Boolean), keep as Boolean type

0.10.5

Patch Changes

  • 0032d8d: Hotfix for evaluate math of values that have non-numericals wrapped in spaces.

0.10.4

Patch Changes

  • 894efe4: Add option to always add font style when expanding typography objects.
  • d76b5cc: Add export for addFontStyles parser.

0.10.3

Patch Changes

  • eff2f93: Fix resolve math transform multi-value splitter function to properly split more than 2 values where each value does itself not contain any spaces.

0.10.2

Patch Changes

  • 1327559: Add 'ts/color/modifiers' option: format, to globally set the output format for color modifiers.
  • 29ac771: Add hairline and ultra to fontWeightsMap, reflect to 1 and 1000 respectively.
  • c59df89: Add option to easily change the casing of the output token names, without requiring to create a custom transform group.

0.10.1

Patch Changes

  • 6a6a5d2: ts/color/css/hexrgba to correctly apply on all color typed tokens, including those containing references.

0.10.0

Minor Changes

  • 3425572: BREAKING: permutateThemes to return the same format regardless of whether multi-dimensional themes are used or not. Format: { themeName: [sets] }.
  • 2731a5e: BREAKING: change name of ts/type/fontWeight transform to -> ts/typography/fontWeight, for consistency's sake.
  • 0363efc: BREAKING: add parser that extracts fontStyle from fontWeight and adds it as a separate property on Typography tokens object values.

Patch Changes

  • 2731a5e: Add value transform ts/typography/css/fontFamily to font-families which adds quotes if it has white space. The source value will then match with how it's rendered in the composite typography token value. outputReferences: true will now replace the quoted value with the reference. Previously, the reference was wrapped in quotes.
  • acb344c: Properly take into account fontStyle inside fontWeights values, in both the fontWeights and CSS typography shorthand transforms.

0.9.10

Patch Changes

  • c4bb776: Allow color modifications to format to hex when the color space is not sRGB. It will do a conversion step to sRGB space before formatting to hex.

0.9.9

Patch Changes

  • 4a8a44f: Fix path to the typescript types

0.9.8

Patch Changes

  • d8eabab: Fix font-families with spaces in between them for multiple comma separated font fallbacks.

0.9.7

Patch Changes

  • a18c91f: Export permutateThemes utility function, allowing you to input your multi-dimensional $themes.json data, and receive the permutations (single dimensional outputs) as a result. See docs.

0.9.6

Patch Changes

  • 21608ff: Patches the transformHEXRGBa function to allow for whitespaces surrounding the HEX code. The Tokens Studio plugin automatically adds these whitespaces when working with aliases so this patch removes the need for manually having to remove those whitespaces.

0.9.5

Patch Changes

  • 0e493a1: Fixes comment transformer for descriptions with line breaks

0.9.4

Patch Changes

  • de971fe: Fixed the return types of lineHeight, opacity and fontWeight to be number instead of string

0.9.3

Patch Changes

  • bd7fe6e: Handle references and deep references for tokens that can be expanded, like typography, border, shadow and composition.
  • b69b05b: set font family name in quotes if its name has whitespaces
  • 4a3d5f9: Error handle if SD cannot resolve reference.

0.9.2

Patch Changes

  • 01d45fd: Fix hex rgba regex matcher to be lazier about some character matching, warn for errors from colorjs.io hex parsing.

0.9.1

Patch Changes

  • ce69ada: Consider that properties can also be empty string, which is especially common if the typography/border/shadow tokens are coming from Tokens Studio.

0.9.0

Minor Changes

  • 24a20df: BREAKING: when missing properties inside typography, border or shadow objects, we prefill them with empty string, 0, or some default value.

0.8.7

Patch Changes

  • 3f12797: Exclude parent keys can lead to duplicate property keys. Ensure they are deepmerged instead of overwritten.

0.8.6

Patch Changes

  • 345e03e: Expose transforms names, so it's easy to create a custom transformGroup and adjust, add or remove transforms in it.

0.8.5

Patch Changes

  • d637cec: Use Rollup output.interop for CJS output, to properly handle default exports in our CJS external dependencies.

0.8.4

Patch Changes

  • d37eebc: Support values of type number for checkAndEvaluateMath utility.

0.8.3

Patch Changes

  • acd3ddb: Evaluate math expressions within complex value types like border, typography, shadow.

0.8.2

Patch Changes

  • a25a1ff: Add excludeParentKeys option to the transform options, in order to exclude parent keys from your token files. This is useful if you use a single-file export from Tokens Studio Figma Plugin.

0.8.1

Patch Changes

  • 4d3b98b: Fix package exports paths.

0.8.0

Minor Changes

  • 3728d90: BREAKING: remove modifier type files, use @tokens-studio/types instead for it.

0.7.0

Minor Changes

  • 2f2cd8c: BREAKING: Register parser that expands composition tokens by default, and optionally typography, border and shadow tokens as well.
  • e23ec38: BREAKING: Register ts/opacity transform, to transform opacity to number between 0 and 1, which is more multi-platform than percentages%. Breaking because people might not expect to have their opacity tokens suddenly as decimal numbers.

0.6.0

Minor Changes

  • cc7d86b: BREAKING: move the following transforms to CSS namespace, since they are CSS-specific transforms:

    • ts/size/letterspacing -> ts/size/css/letterspacing
    • ts/color/hexrgba -> ts/color/css/hexrgba
    • ts/shadow/shorthand -> ts/shadow/css/shorthand
  • cc7d86b: New transform: ts/border/css/shorthand -> transform border objects to CSS shorthand.

  • cc7d86b: BREAKING: turn a few of our transforms from transitive to default transforms, if transitive was not necessary:

    • ts/descriptionToComment
    • ts/size/px
    • ts/size/css/letterspacing
    • ts/size/lineheight
    • ts/type/fontWeight

Patch Changes

  • f320d4a: Keep shadow shorthands as is instead of attempting to transform them again.

0.5.7

Patch Changes

  • 3d73476: Add inset to shadow CSS shorthand if the type is innerShadow.

0.5.6

Patch Changes

  • a824884: Do not use original value for transforms, use transformed value instead.

0.5.5

Patch Changes

  • df20034: Allow letter spacing to be a number value, since 0 is a legitimate value for letter spacing.

0.5.4

Patch Changes

  • 2869382: Use expr-eval to evaluate math functions like roundTo().

0.5.3

Patch Changes

  • a75c420: Add engines property to pkg.json, NodeJS 15.14.0 and higher supported.

0.5.2

Patch Changes

  • a94d137: Transform typography to make use of transform fontweights map for the fontWeight property.
  • 81362be: Account for token values being of type number in certain transformers.

0.5.1

Patch Changes

  • 48846b3: Fix checkAndEvaluateMath to deal with regular values with spaces in them like linear-gradient(a, b1 b2, c1 c2).
  • 4f6da6c: Return original value if mapped fontweight is undefined.

0.5.0

Minor Changes

  • 2ad1630: BREAKING: remove attribute/cti transform from tokens-studio transform group, this is redundant. However, users might rely on it, therefore it is a breaking change.

0.4.6

Patch Changes

  • 71d12d2: Improve checkAndEvaluateMath for expressions with more than one unit.

0.4.5

Patch Changes

  • a2b2a22: Account for undefined as a token value in transformers. This may happen if a token value is a reference, but the reference is broken. A fatal error in the transform makes it more difficult for the user to find out that they have broken references and to debug it, therefore we guard against it in our transformers.

0.4.4

Patch Changes

  • e366ac0: Export transformColorModifiers function inside the main entrypoint.
  • b9f179a: Allow passing an output format to the color modify props of Tokens Studio.

0.4.3

Patch Changes

  • 31c81b4: Fix property name modifier -> modify.

0.4.2

Patch Changes

  • 2cff78f: Fix check and evaluate math, don't run it on non-string token values, no longer fails on simple expressions.

0.4.1

Patch Changes

  • 5718a7b: Fix small bug in transform typography for compose, passes token value instead of full token.
  • 2d4ce90: Change regex for HEXRGBa detection space character from lazy to greedy, to more tightly match the "alpha" number without leading spaces.
  • 22f9859: Add color modifiers transform, see more info.
  • 2d4ce90: Add multi-value support for evaluating math expressions in token values.

0.4.0

Minor Changes

  • d4d2bc2: BREAKING: Renames typography transform to clarify it's transformed to CSS-based format. Previously transformTypography, now transformTypographyForCSS.

Patch Changes

  • d4d2bc2: Adds a transformer for typography tokens on Jetpack Compose

0.3.3

Patch Changes

  • 0288c1f: Include missing token types (sizing, borderWidth) in ts/size/px transform matcher.

0.3.2

Patch Changes

  • 5826117: Add lineheight tranform for aligning Figma and CSS behaviour. Add transform to assign Tokens Studio description to Style Dictionary comment.

0.3.1

Patch Changes

  • 631424d: No longer need to commit to using @rollup/plugin-commonjs. We prebundle the dependency that is CJS-only so users don't need to worry about it.

0.3.0

Minor Changes

  • 6c35e0e: Add 4 more transforms necessary for dealing with Tokens Studio syntax.

0.2.0

Minor Changes

  • cfa044f: Take into account that env might be browser. Only attempt to import module and use createRequire in NodeJS env.

0.1.0

Minor Changes

  • 6e3bd89: Initial release of sd-transforms, a library to easily register transforms related to Tokens Studio