Awesome
rei-cedar-tokens
tokens for cedar design system
Consuming
-
Install the package
npm i -D @rei/cdr-tokens
(may need to remove the '-D' depending on your use case). -
Import/require the tokens in your needed format. Platforms specific formats are available in each directory with the same name -- i.e.
dist/scss/cdr-tokens.scss
.- JS: commonjs (default) and es module
- SCSS: variable and mixins
- LESS: variable and mixins
- Android: XML style sheets for Colors and Dimensions
- iOS: Objective C classes for Color and Size
** REI Internal teams should use the internal iOS and Android packages.
Updating
If you are consuming tokens in SCSS, there are deprecation warnings for variables, mixins, etc. that will appear in the console during your build. These can be silenced by adding a variable to your code called cdr-warn
and setting it to false like this: $cdr-warn: false;
All other formats should consult the changelog for a migration path.
Contributing
Initial set up
- Clone repo
npm install
npm run build
(output tokens)
Tokens are generated using Style Dictionary v4.
Project structure
The project is made of these files and folders:
tokens/
contains the design tokens input files (in JSON5 format)tokens/_options/
contains "option" tokens see belowtokens/global/
contains design tokens that are output for all platformstokens/<platform>/
contains design tokens specific to a platform (like mixins for scss/less that others can't use)
style-dictionary/
contains the build script, configs, transforms,actions, and formats used to generate the output filesdist/
contains the generated output files (in different formats)docs/
contains app that is generated for gh-pages examples
Tokens
In the
tokens/
directory. Files are in JSON5.
Token Structure
See style-dictionary properties docs.
We follow the basic structure of style-dictionary with the exception being that our tokens don't follow the implicit CTI structure and we abstract that into a separate "category" key (see Categories below).
Token Properties
The following properties can be added to tokens to support different options
$value # *required* The token value (most token values should be referenced from options)
$type # *required* The tokens type (used to transform values for their specific platform)
docs # Object to define meta data for docs
category # The category tokens are grouped in on the examples page
type # The sub category tokens are grouped in on the examples page
example # Defines how the token should be presented on the examples page -- Current example types are: color, spacing, sizing, radius, prominence, text, inset, and breakpoint
mixin # The name of the generated SCSS/LESS mixin (must be used with property)
property # Used with mixin -- the css property the value is applied to within the mixin
'utility-class' # Boolean -- Used to create scss maps of properties to more easily generate utility classes in cedar
Options
Found in tokens/_options/
Options are skipped and do not get exported for consumers. However they can be referenced in creating tokens that will be exported.
NOTE: "options" needs to be the root key in the file.
{
options: { // <-- anything beneath this will be ignored in output
color: {
'easily-excited': {
'$value': '#3278ae',
'$type': 'color',
},
'heart-of-darkness': {
'$value': '#292929',
'$type': 'color',
},
// ...
},
}
}
Output won't have a token named options-color-easily-excited
.
Naming
Token names are defined by the hierarchy of the object:
{
text: {
body: {
default: {
size: {
'$value': '23px',
'$type': 'fontSize',
},
height: {
'$value': '25px',
'$type': 'size',
},
},
},
}
}
Token output of above:
text-body-default-size: 23px;
text-body-default-height: 25px;
Types
Types need to be attached to both options and tokens (due to limitations of style-dictionary resolve order. This may change in the future)
Types define how style-dictionary should transform values between platforms.
For example, a type of "dimension" will transform to 'rem' for SCSS/LESS but 'dp' for Android. A type of "fontSize" will still transform values to 'rem' for SCSS/LESS but 'sp' for Android.
Categories are one of the following:
dimension
: Anything that would have a value in px. With the exception of fontSizefontSize
: Anything that defines a text sizeletterSpacing
: Anything that defined a letter spacingcolor
: Anything that defines a colortime
: Anything the defines a timing- Values without a category will not be transformed: Anything that is a string like
'normal'
or'italic'
Referencing Options (or other values)
{
color: {
text: {
primary: {
'on-dark': {
'$value': '{options.color.heart-of-darkness}',
'$type': 'color',
docs: {
category: 'colors',
type: 'text',
example: 'color'
}
}
}
}
}
}
Documentation within tokens
Tokens also have data that can be added to them to help generate documentation & examples. To get an idea of how this data is used see the tokens example page. This data is mostly used to create groupings of tokens and is not used to do transforms on token values, only for display in docs.
The docs object looks like this:
docs: {
category: String, // Large, broad groupings of things (i.e. color, spacing)
type: String, // Sub category (i.e. background (color) or inset (spacing))
example: String, // Used to determine how to display a visual representation of a token
// Current options (see docs/src/components/PropSorter.vue): color, spacing, sizing, radius, prominence, text, inset, breakpoint, timing, duration, an empty example defaults to 'token' which is just a string representation of the value.
description: String, // Short description of the token and/or suggested usage (displayed on the cedar docs site)
}
Deprecating tokens
Deprecated tokens should be moved to a seprate file (or into the existing file) which corresponds to the release cycle in which they will be deprecated.
For example, if tokens will be considered deprecated in the "Winter 2019" release they would be moved into a file called deprecated-2024-summer.json5
in whichever directory they currently reside. Structure for naming the file is : deprecated-<year>-<release>
Additionally, the contents will be wrapped inside an object with a key that corresponds to the release as well (so we can auto generate some deprecation warnings with the correct release). The key matches the naming of the file. See below for an example.
{
'deprecated-2024-q4': { // <-------- `deprecated-<year>-<release>`
color: {
text: {
primary: {
'on-dark': {
'$value': '{options.color.heart-of-darkness}',
'$type': 'color',
docs: {
category: 'colors',
type: 'text',
example: 'color'
}
}
}
}
}
// ...
}
}
Providing a migration path
When tokens are deprecated they can also be provided a new token name or new mixin name to use instead which will be provided in the SASS deprecation warning:
{
'deprecated-2024-q4': {
text: {
header: {
'1': {
family: {
'$value': '{options.font.family.serif.$value}',
mixin: 'textHeader1',
property: 'font-family',
newMixin: 'new-mixin-name', //<--- a new mixin name to use instead of the deprecated one
newToken: 'new-token-name', //<--- a new token name to use instead of the deprecated one
docs: {
category: '{text.docCategory}',
type: 'header',
example: '{text.docExample}',
},
},
}
}
}
}
}
Style Dictionary
Build
Main build script that is executed with npm run build
is at style-dictionary/build.js
. Logic to only build certain platforms or extending brands/themes will likely be done here.
All actions, configs, formats, etc are imported in this file and it extends the base style-dictionary functionality.
Actions
Found in style-dictionary/actions
See API for creating an action
Configs
Found in style-dictionary/configs
See config docs.
Configs follow standard config options. They are organized separately by platform and are required into the _index.js
file where they all have a filter for options applied.
Formats
Found in style-dictionary/formats
See API for creating a format
Transform Groups
See API for creating a transform group
Transforms
Found in style-dictionary/transforms
See API for creating a transform
See transform docs.
Validation
Because this library has many dependencies, there is a validation script that performs some checks. One of the tests is verifying the file structure has not changed. If a change is intentional, you may execute npm run validate -- --update
or delete the validate-structure.json
file and then execute npm run validate
. The validate-structure.json
file should be commited.