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.
npm install @projectwallace/css-design-tokens
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)
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',
// ...
// }
// }
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'],
}
}
}
'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,
}
},
}
'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': {
$value: ['Arial Black', 'sans-serif'],
$extensions: {
'com.projectwallace.css-authored-as': 'Arial Black, sans-serif',
'com.projectwallace.usage-count': 1,
}
},
}
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,
}
}
}
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,
}
}
}
- 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 abox-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,
}
}
}
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,
}
}
}
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,
}
}
}
'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,
}
}
}
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.
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'
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
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']
- 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
- Design Tokens analyzer - Online CSS to Design Tokens convernter, uses this package
- CSS Analyzer - The best CSS analyzer that powers all analysis on projectwallace.com
- Color Sorter - Sort CSS colors by hue, saturation, lightness and opacity
- CSS Time Sort - Sort an array of
<time>
values