Skip to content

Create Design Tokens by going through CSS to find colors, font-sizes, gradients etcetera and turn them into a Design Tokens spec-compliant token format.

License

Notifications You must be signed in to change notification settings

projectwallace/css-design-tokens

Repository files navigation

css-design-tokens

Create Design Tokens by going through CSS to find colors, font-sizes, gradients etcetera and turn them into a Design Tokens spec-compliant token format.

Table of contents

Installation

npm install @projectwallace/css-design-tokens

Usage

import { css_to_tokens } from '@projectwallace/css-design-tokens'

let {
  color,
  font_size,
  font_family,
  line_height,
  gradient,
  box_shadow,
  radius,
  duration,
  easing,
} = css_to_tokens(`.my-design-system { color: green; }`)

// Or if you already have done CSS analysis with @projectwallace/css-analyzer
import { analyze } from '@projectwallace/css-analyzer'
import { analysis_to_tokens } from '@projectwallace/css-design-tokens'

let analysis = analyze(`.my-design-system { color: green; }`, {
  useLocations: true // may be `true` or `false`, it works either way
})
let tokens = analysis_to_tokens(analysis)

Stable unique token ID's

All tokens have a stabe unique ID using a very simple hashing algorithm. This is helpful when you run analysis multiple times over your project and lets you identify removed or added tokens easily.

let { color } = css_to_tokens(
  `.my-design-system {
    color: green;
    color: rgb(100 100 100 / 20%);
  }`
)

// {
//   'green-5e0cf03': {
//     $type: 'color',
//     ...
//   },
//   'grey-8139d9b': {
//     $type: 'color',
//     ...
//   }
// }

Token types

Color

'Color' Design Token format

Only fully compliant colors are listed. Colors that can't be parsed by colorjs.io are ignored, like rgb(var(--red) var(--green) var(--blue)) or CSS system colors like ButtonText.

  • The optional alpha property is always present.
  • The optional hex fallback property is never present.
  • In addition to other tokens all colors have a com.projectwallace.css-properties extension that contains all the CSS properties that a specific color was used for.
let { color } = css_to_tokens(`.my-design-system { color: green; }`)

let color = {
  'green-5e0cf03': {
    $type: 'color',
    $value: {
      colorSpace: 'srgb',
      components: [0, 0.5019607843137255, 0],
      alpha: 1,
    },
    $extensions: {
      'com.projectwallace.css-authored-as': 'green',
      'com.projectwallace.usage-count': 2,
      'com.projectwallace.css-properties': ['color', 'border-color'],
    }
  }
}

Font-size

'Dimension' Design Token format

Font-sizes are listed as $type: 'dimension' types if the font-size is declared with either px or rem or as plain type-less tokens otherwise.

let { font_size } = css_to_tokens(`.my-design-system {
  .my-design-system {
    font-size: 16px;
    font-size: 1rem;
    font-size: 20vmin;
  }
}`)

let font_size = {
  'fontSize-171eed': {
    $type: 'dimension',
    $value: {
      value: 16,
      unit: 'px'
    },
    $extensions: {
      'com.projectwallace.css-authored-as': '16px',
      'com.projectwallace.usage-count': 1,
    }
  },
  'fontSize-582e015a': {
    $value: '20vmin',
    $extensions: {
      'com.projectwallace.css-authored-as': '20vmin',
      'com.projectwallace.usage-count': 1,
    }
  },
}

Font-family

'fontFamily' Design Token format

Font-families are always listed as $type: 'fontFamily'.

let { font_family } = css_to_tokens(`.my-design-system {
  .my-design-system {
    font-family: 'Inter';
    font-family: Arial Black, sans-serif;
  }
}`)

let font_family = {
  'fontFamily-3375cf09': {
    $type: 'fontFamily',
    $value: ['\'Inter\''],
    $extensions: {
      'com.projectwallace.css-authored-as': '\'Inter\'',
      'com.projectwallace.usage-count': 1,
    }
  },
  'fontFamily-582e015a': {
    $type: 'fontFamily',
    $value: ['Arial Black', 'sans-serif'],
    $extensions: {
      'com.projectwallace.css-authored-as': 'Arial Black, sans-serif',
      'com.projectwallace.usage-count': 1,
    }
  },
}

Line-height

Line heights can either be dimension or number types, or a plain type-less token. This depends on how well the value can be mapped to a valid token.

let { line_height } = css_to_tokens(`
  .my-design-system {
    line-height: 1.5rem; /* rem -> type=dimension */
    line-height: 1.5; /* no unit -> type=number */
    line-height: 20vmin; /* can not be mapped to valid token type */
  }
`)

let line_height = {
  'lineHeight-563f7fe2': {
    $type: 'dimension',
    $value: {
      value: 1.5,
      unit: 'rem'
    },
    $extensions: {
      'com.projectwallace.css-authored-as': '1.5rem',
      'com.projectwallace.usage-count': 1,
    }
  },
  'lineHeight-bdb8': {
    $type: 'number',
    $value: 1.5,
    $extensions: {
      'com.projectwallace.css-authored-as': '1.5',
      'com.projectwallace.usage-count': 1,
    }
  },
  'lineHeight-582e015a': {
    $value: '20vmin',
    $extensions: {
      'com.projectwallace.css-authored-as': '20vmin',
      'com.projectwallace.usage-count': 1,
    }
  }
}

Gradient

Gradients are passed as-is, no mapping is done. This is because the spec is currently too limited in expressing a CSS gradient.

let { gradient } = css_to_tokens(`
  .my-design-system {
    background: linear-gradient(to right, red, blue);
  }
`)

let gradient = {
  'gradient-2aec04e5': {
    $value: 'linear-gradient(to right, red, blue)',
    $extensions: {
      'com.projectwallace.css-authored-as': 'linear-gradient(to right, red, blue)',
      'com.projectwallace.usage-count': 1,
    }
  }
}

Box-shadow

'Shadow' Design Token type

  • Multiple shadows can be mapped, so beware that $value van either be a single object or an array.
  • Only if a box-shadow has a valid color type it will be mapped as a box-shadow type
let { box_shadow } = css_to_tokens(`
  .my-design-system {
    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.5);
    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.5), 0 0 10px 0 rgba(0, 0, 0, 0.5);
    box-shadow: 0 0 0 0 var(--red);
  }
`)

let box_shadow = {
  'boxShadow-6f90da6b': {
    $type: 'shadow',
    $value: {
      offsetX: {
        value: 0,
        unit: 'px'
      },
      offsetY: {
        value: 0,
        unit: 'px'
      },
      blur: {
        value: 10,
        unit: 'px'
      },
      spread: {
        value: 0,
        unit: 'px'
      },
      inset: false,
      color: {
        colorSpace: 'srgb',
        components: [0, 0, 0],
        alpha: 0.5,
      },
    },
    $extensions: {
      'com.projectwallace.css-authored-as': '0 0 10px 0 rgba(0, 0, 0, 0.5)',
      'com.projectwwallace.usage-count': 1,
    }
  },
  'boxShadow-be2751ac': {
    $type: 'shadow',
    $value: [
      {
        offsetX: {
          value: 0,
          unit: 'px'
        },
        offsetY: {
          value: 0,
          unit: 'px'
        },
        blur: {
          value: 10,
          unit: 'px'
        },
        spread: {
          value: 0,
          unit: 'px'
        },
        inset: false,
        color: {
          colorSpace: 'srgb',
          components: [0, 0, 0],
          alpha: 0.5,
        },
      },
      {
        offsetX: {
          value: 0,
          unit: 'px'
        },
        offsetY: {
          value: 0,
          unit: 'px'
        },
        blur: {
          value: 10,
          unit: 'px'
        },
        spread: {
          value: 0,
          unit: 'px'
        },
        inset: false,
        color: {
          colorSpace: 'srgb',
          components: [0, 0, 0],
          alpha: 0.5,
        },
      }
    ],
    $extensions: {
      'com.projectwwallace.css-authored-as': '0 0 10px 0 rgba(0, 0, 0, 0.5), 0 0 10px 0 rgba(0, 0, 0, 0.5)',
      'com.projectwwallace.usage-count': 1,
    }
  },
  'boxShadow-j4h5gas5h': {
    $value: '0 0 0 0 var(--red)',
    $extensions: {
      'com.projectwwallace.css-authored-as': '0 0 0 0 var(--red)',
      'com.projectwwallace.usage-count': 1,
    }
  }
}

Radius

Radii are passed as-is, no mapping is done.

let { radius } = css_to_tokens(`
  .my-design-system {
    border-radius: 10px;
  }
`)

let radius = {
  'radius-170867': {
    $value: '10px',
    $extensions: {
      'com.projectwwallace.css-authored-as': '10px',
      'com.projectwwallace.usage-count': 1,
    }
  }
}

Duration

'Duration' Design Token type

Durations can either be animation- or transition-durations or -delays. Even though s is a valid unit we always map to ms.

let { duration } = css_to_tokens(`
  .my-design-system {
    animation-duration: 1s;
  }
`)

let duration = {
  'duration-17005f': {
    $type: 'duration',
    $value: {
      value: 1000,
      unit: 'ms'
    },
    $extensions: {
      'com.projectwwallace.css-authored-as': '1s',
      'com.projectwwallace.usage-count': 1,
    }
  }
}

Easing

'Cubic Bézier' Design Token type

Easings are mapped to cubic béziers when possible or represented as plain type-less tokens otherwise. CSS Easing keywords are also converted to cubic béziers.

let actual = css_to_tokens(`
  .my-design-system {
    animation-timing-function: ease-in-out;
    animation-timing-function: cubic-bezier(0, 0, 0.5, .8);
    animation-timing-function: var(--test);
  }
`)

let easing = {
  'easing-ea6c7565': {
    $type: 'cubicBezier',
    $value: [
      0.42,
      0,
      0.58,
      1
    ],
    $extensions: {
      'com.projectwwallace.css-authored-as': 'ease-in-out',
      'com.projectwwallace.usage-count': 1,
    }
  },
  'easing-90111eba': {
    $type: 'cubicBezier',
    $value: [
      0,
      0,
      0.5,
      0.8
    ],
    $extensions: {
      'com.projectwwallace.css-authored-as': 'cubic-bezier(0, 0, 0.5, .8)',
      'com.projectwwallace.usage-count': 1,
    }
  },
  'easing-12bb7f36': {
    $value: 'var(--test)',
    $extensions: {
      'com.projectwwallace.css-authored-as': 'var(--test)',
      'com.projectwwallace.usage-count': 1,
    }
  }
}

Extensions

This library adds a couple of potentially extensions to the design token values via the com.projectwallace namespace on the $extensions property of all generated design tokens.

Authored CSS values

This package parses CSS into Design Tokens but also provides a way to get the authored CSS via the $extensions['com.projectwallace.css-authored-as'] property on any of the tokens:

let { color } = css_to_tokens(`.my-design-system { color: green; }`)

// {
//   'green-5e0cf03': {
//     ...
//     $extensions: {
//       'com.projectwallace.css-authored-as': 'green'
//     }
//   },
// }

let authored_green = color['green-5e0cf03']['$extensions']['com.projectwallace.css-authored-as']

// 'green'

Usage count

If you need to know how often a particalur design token was found in the CSS you can use the $extensions['com.projectwallace.usage-count'] property on any of the tokens:

let { color } = css_to_tokens(`.my-design-system { color: green; }`)

// {
//   'green-5e0cf03': {
//     ...
//     $extensions: {
//       'com.projectwallace.usage-count': 1
//     }
//   },
// }

let green_count = color['green-5e0cf03']['$extensions']['com.projectwallace.usage-count']

// 1

CSS property usage

For color tokens only

You can read the $extensions['com.projectwallace.css-properties'] property to see for which CSS properties a color was used:

let { color } = css_to_tokens(`.my-design-system { color: green; }`)

// {
//   'green-5e0cf03': {
//     ...
//     $extensions: {
//       'com.projectwallace.css-properties': ['color']
//     }
//   },
// }

let properties = color['green-5e0cf03']['$extensions']['com.projectwallace.css-properties']

// ['color']

Acknowledgements

  • CSSTree does all the heavy lifting of parsing CSS
  • ColorJS.io powers all color conversions necessary for grouping and sorting and converting into Color tokens

Related projects

About

Create Design Tokens by going through CSS to find colors, font-sizes, gradients etcetera and turn them into a Design Tokens spec-compliant token format.

Resources

License

Stars

Watchers

Forks

Packages

No packages published