Need help with design-system-utils?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

mrmartineau
453 Stars 12 Forks MIT License 167 Commits 12 Opened issues

Description

👩‍🎨 Access your design tokens with ease

Services available

!
?

Need anything else?

Contributors list

No Data

👩‍🎨
Design System Utils

npm npm bundle size (minified + gzip) Travis CI Build PRs Welcome

Design System Utils is a micro framework that standardises your design-system tokens & provides helpful utility functions to access the information. It can be used with styled-components, emotion, glamorous or any other CSS-in-JS framework.

Install

yarn add design-system-utils

or

npm install --save design-system-utils

Size

$ size-limit

build/cjs.js Package size: 814 B Size limit: 1 KB

es/index.js Package size: 806 B Size limit: 1 KB

With all dependencies, minified and gzipped

🤓 Table of contents

Usage

First create your design system file, this contains all your design tokens that your app or site will use; things like font-sizes, color palette, spacing etc (kind of like a Sass/Less variables file).

For example you can create a top-level directory named

tokens
,
theme
or
designsystem
, and add an index.js inside, like so:
./tokens
└── index.js

A simple version of a tokens file with Design System Utils:

// ./tokens/index.js
import DesignSystem from 'design-system-utils'

// your design tokens object goes here, see below for further details const designTokens = {...}

export default new DesignSystem(designTokens)

Setup

The "shape" and structure of your design tokens object can actually be anything you want, however, if you want to make use of the shortcut/helper methods like

tokens.fontSize|bp|z|color|brand|spacing
etc, there is a particular shape that your data will need to follow, see below:

(🤔 the below code snippet includes some psuedo types for the values that occur in the different parts of the tokens object)

{
  type: {
    // this should be set as a px value if you have `options.fontSizeUnit` set
    // to 'rem' or 'em' so that the lib can convert the values properly
    baseFontSize: '' // string,

// used with `tokens.fs('size')` or `tokens.fontSize('size')`
sizes: {
  key: '' // <number string>,
},

},

// Color palette // Each object needs to have the same shape // Each color object needs a base value to be the default // Have as many color objects as you like colors: { // Used with ds.color('colorName') colorPalette: { colorName: { base: '' // , // base is the default }, },

// Used with `ds.brand('colorName)`
brand: {
  colorName: '' // <string>, base is the default
}

},

// Breakpoints // Used with ds.bp() // Keys can be anything you like // Have as many breakpoints as you like // Values can be use any unit you like breakpoints: { key: '' // , },

// Z-index // Used with ds.z() zIndex: { key: 10 // },

// Spacing // Used with ds.spacing() or ds.space() spacing: { scale: [] // [, ...], }, }

Below is an excerpt from the example design-system. See a more complete version in the

/example
directory or some that are used in the design-system-utils tests: 1 & 2.

const designTokens = {
  type: {
    baseFontSize: '20px',

sizes: {
  xs: '16px',
  s: '20px',
  base: '30px',
  m: '36px',
  l: '42px',
  xl: '50px',
  xxl: '58px',
},

fontFamily: {
  system:
    '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans"',
  sans: '"Helvetica Neue", Helvetica, Arial, sans-serif',
  serif: 'Georgia, "Times New Roman", Times, serif',
  mono: 'Menlo, Monaco, "Courier New", monospace',
},

lineHeight: {
  headings: 1.1,
},

fontWeight: {
  normal: 300, // Useful to set here if using anything other than `normal`
  bold: 'bold', // Useful to set here when bold webfonts come as 400 font-weight.
  headings: 'bold', // instead of browser default, bold
},

}, }

Initialise the design system framework

// myDesignSystem.js
import DesignSystem from 'design-system'
const designTokens = {...}
export default new DesignSystem(designTokens)

Accessing the design system data in your app

To access your design system, you just need to

import
it to the current file, like so:
import tokens from './tokens' // assuming you exported `default` from your design system file

Here is a very simple component using styled-components and some values from the tokens, you should be able to see how easy it is to pull information from the design system.

// Example using styled-components
import styled from 'styled-component'
import tokens from './tokens'

export const Box = styled.div font-family: ${tokens.get('type.fontFamilyBase')}; background-color: ${tokens.brand('primary')}; margin: ${tokens.space(2)} 0;

Options

There is only one option that can be passed to your design system class, it relates to font-sizing:

// Use default options. do not convert the font-sizes to rems or ems
export default new DesignSystem(myDesignSystem)

// OR: with custom options export default new DesignSystem(myDesignSystem, { // this is used to convert your type.sizes values from one unit to another // e.g. to convert all px sizes to rem, set this option: fontSizeUnit: 'rem', // this means you can define values using px and use rems in your app })

Basic API methods

tokens.get()
- Get a token value

The

tokens.get()
function can be used to get any value from the design-system. Use object dot notation to find the value you need from your design system object.
// with the system setup, as above
tokens.get('lineHeight.headings') // 1.1
tokens.get('a.really.deeply.nested.value')

tokens.set()
- Set a token value

The

tokens.set()
function can be used to set tokens values. This means you can overwrite existing items, or create new items that are specific to your application.

Like the

.get()
method, use object dot notation to find the value you need from your design system object.

This method uses dset under the hood, so please read the docs there for more info.

// with the system setup, as above
tokens.set('forms.inputBackground', '#fff')

// then use it later like so: tokens.get('forms.inputBackground')

API helper methods

The helper methods make getting values much more simple.

tokens.fontSize()
or
tokens.fs()
- Get font-size values

The

tokens.fontSize()
method is a short-hand for the
tokens.get()
method. It can be used to get a value from the
type.sizes
object.

The

type.sizes
object’s values can be formatted in a few ways:
  • as a string with any unit of measurement, e.g.
    s: '13px'
    /
    px
    ,
    rem
    or
    em
  • as a template string using another function to calculate font-sizes, for example a modular-scale, e.g.
    ${ms(0, modularscale)}px
    . Note: this uses an external package, modularscale-js
// define some values// type.sizes object
sizes: {
  xs: '16px',
  s: '20px',
  base: '30px',
  m: '36px',
  l: '42px',
  xl: '50px',
  xxl: '58px',
},

// retrieve some values tokens.fontSize('xl') tokens.fs('xl') // tokens.fs() is a short-hand alias for tokens.fontSize() tokens.fs('xl', true) // return font-size in px regardless of option.fontSizeUnit value

Modular scale

Note: v0.x.x had modular scale functionality built-in, in v1.x.x, this has been removed to reduce file-size for those that don't need a modular scale.

To make use of a modular scale, there are a few things that need to be done:

  • install a modular scale converter package, like modularscale-js
  • define your modular scale options outside of your design-system object
  • add the modular scale values to the
    type.sizes
    object
const modularscale = {
  base: [30],
  ratio: 1.5,
}

// design system ... sizes: { xs: ${ms(-2, modularscale)}px, s: ${ms(-1, modularscale)}px, } ...

Testing and remembering the values from your modular scale can be tricky, there are two options that can be used, either:

  • visit modularscale.com and enter your settings, you can then view all the type sizes on the scale you specified
  • or, add the below snippet to your code to print out the values of your scale:
const sizes = tokens.get('type.sizes')
Object.keys(sizes).forEach(item => {
  console.log(item, ':', sizes[item]) // e.g. `base : 20px`
})

Color palette

There are two possible ways to access color information: the color palette and the brand colors.

The color palette is intended to contain all the colors (and their shades) that your app will use, and the brand palette should contain the specific colors that your brand uses.

Two methods can be used to retrieve the values, these are:

tokens.color()
and
tokens.brand()
, below is what the data looks like for them:
colors: {
  // With a color palette like this:
  colorPalette: {
    bright: {
      base: '#F9FAFB',
      dark: '#F4F6F8',
      darker: '#DFE4E8',
    },

dark: {
  base: '#212B35',
  light: '#454F5B',
  lighter: '#637381',
},

},

// With a brand palette like this: brand: { red: '#e82219', deeporange: '#ff7200', orange: '#ff9500', green: '#c4d000', teal: '#1aa5c8', navy: '#0052da', } },

tokens.color()
- Get color palette values

The

tokens.color()
function gets values from the
colorPalette
object. It assumes every color has a
base
property and other properties for different shades of the same color. This is a short-hand for the
tokens.get()
function.
// Get values like this:
tokens.color('bright') // #F9FAFB - the `base` key is the default, so it is not needed
tokens.color('bright', 'dark')
tokens.color('background.extra.dark') // Accepts a path (in this case the second `variant` argument is ignored)

tokens.brand()
- Get brand palette values

The

tokens.brand()
function gets values from the
colors.brand
object. This is a short-hand for the
tokens.get()
function.
// Get brand values like this:
tokens.brand('orange')
tokens.brand('pink')
tokens.brand('primary.blue') // it is possible to nest this object as much as you like

tokens.bp()
- Get responsive breakpoint values

The

tokens.bp()
method is a short-hand for the
tokens.get()
method. It can be used to get a breakpoint from the
breakpoints
object.
tokens.bp('m')

tokens.z()
- Get
z-index
values

The

tokens.z()
method is a short-hand for the
tokens.get()
method. It can be used to get a breakpoint from the
zIndex
object.
tokens.z('low')

tokens.spacing()
or
tokens.space()
- Get spacing values

The

tokens.spacing()
method returns a value from your
spacing.scale
definition. The spacing data could either be an array, or an object.
  • If an array, it takes an
    index
    (number) for that array e.g.
    tokens.space(2)
    . This variant adds
    px
    to the end of the string, this will be deprecated in v2.0.0.
  • If an object, it takes a
    key
    (string) for the item in that object e.g.
    tokens.space('m')

Array example:

scale: [0, 8, 16, 24, 32, 40]

tokens.spacing(2) // '16px' // Note: tokens.space(2) can also be used

Object example:

scale: {
  s: '10rem',
  m: '100rem',
  l: '1000rem',
}

tokens.spacing('m') // '100rem' // Note: tokens.space('m') can also be used

Calculations

The framework currently provides a few calculation functions,

multiply
,
toPx
and
pxTo
:

tokens.multiply()

tokens.multiply(10, 2) // 20

// you can pass in another value from the system tokens.multiply(tokens.get('spacing.baseline'), 2)

// or just use the key from the system // the initial value will always be run through parseFloat() tokens.multiply('spacing.baseline', 2)

pxTo()

Converts

px
to
rem
or
em
import { pxTo } from 'design-system-utils'
// pxTo(fontSize, baseFontSize, unit - 'rem'/'em')
pxTo(12, 20, 'rem') // 0.6rem
pxTo(12, 20, 'em') // 0.6em

toPx()

Converts

rem
or
em
value to
px
import { toPx } from 'design-system-utils'
// toPx(fontSize, baseFontSize)
toPx('1.875rem', 16) // 30px
toPx('1.875em', 16) // 30px

parseUnit()

Parses a number and unit string, and returns the unit used

import { parseUnit } from 'design-system-utils'
parseUnit('1.875rem') // 'rem'
parseUnit('18px') // 'px'

Usage with Typescript

Typescript types and interfaces should be imported as named imports.

See all the type definitions in the types.ts file. Here are all the exported types that can be extended:

{
  System,
  SystemOptions,
  SystemBreakpoints,
  SystemZIndex,
  SystemFontSizes,
  SystemSpacing,
  SystemScale,
  SystemColorPalette,
  SystemBrandPalette,
  SystemType,
  SystemOptionalKey,
}

Below is an example where a new item (

baseline
) is added to the
spacing
object.
import DesignSystem, { System, SystemOptions, SystemSpacing } from '../index'

interface MySystemSpacing extends SystemSpacing { baseline: number }

interface MySystem extends System { spacing: MySystemSpacing }

const Tokens: MySystem = { ... ...

spacing: { scale: [0, 8, 16, 24, 32, 40], baseline: 20, }, }

export default new DesignSystem(Tokens)

Aliases

If you'd prefer to rename the above methods, or even add your own getter methods, to access your design tokens, it is very simple. See below for an example:

export tokens from './tokens' // import your design tokens

// create new alias functions

// this renames .bp() export const breakpoints = bp => tokens.bp(bp)

// this adds a new alias that doesn't already exist in Design System Utils export const fontWeights = weight => tokens.get('type.fontWeights')

// the aliases can also be for specific values export const baseFontSize = ds1.get('type.baseFontSize') export const brandPrimary = ds1.brand('red')

Then use them like so:

import { breakpoints, fontWeights, baseFontSize, brandPrimary } from './tokens'

breakpoints('m') fontWeights('normal')

Take a look at

alias.ts
and
alias.test.ts
to see working examples and their usage.

Demo & examples

I created a demo on codesandbox.io, it includes examples of using the design-system utils with emotion, styled-components and glamorous. There is also a basic example here.

Licence

MIT © Zander Martineau

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.