@historylab/design-tokens
v0.3.0
Published
Design Tokens for the HistoryLab project
Readme
Design tokens
Design tokens are named entities that store visual design information. These are used in place of hard-coded values (such as hex values for color or pixels for spacing) in order to maintain a scalable, consistent system for UI development. They stand above all. They are the most fundamental level shared throughout the whole company.
Technically speaking, we store them as key/value pair in JSON files which can be used by anyone to generate variables for any language.
Structure, notation, naming
The structure of token notation in JSON and the resulted token name is constructed like this: category + sub-category + device + level. Use dash (-) as a separator.
Example: Token notation in JSON
{
"font-size": {
"sans-serif": {
"mobile": [
{
"0": "1.625rem"
}
]
}
}
}Example: Token name
font-size-sans-serif-mobile-0Values
From negative values to positive ones where level 0 is always meant as the default value, negative levels (-1) is used for darker or smaller values, positive levels (1) are used for lighter or bigger values. All levels are stored as objetcs in an array, in JSON.
{
"token": [
{
"-1": "smaller/darker token value"
},
{
"0": "default token value"
},
{
"1": "bigger/lighter token value"
}
]
}How to use them?
Use recursive function to loop through all nested objects until you reach a string which is the token value. Example of such function to create variable names:
/**
* Variable name is constructed from all keys parent to the actual value.
*
* @param {object} data Input data in the form of Object or JSON.
* @param {string} symbol Symbol used in styling languages for variable names.
* @param {string} prefix Operational variable to store the name of a token.
*
* @return {string} returnData Resulted string of variable name and value pairs.
*/
function createVariables(data, symbol, prefix) {
let returnData = '';
prefix = prefix ? `${prefix}-` : '';
for (let [key, value] of Object.entries(data)) {
// if string
if (typeof value === 'string') {
returnData += `${symbol}${prefix + key}: ${value};
`;
}
// if another nested object
else if (typeof value === 'object') {
// if the nested object is an array
// we need to use an array (of objects) to keep the order of items
if (value.constructor.name == 'Array') {
value.forEach(item => {
returnData += createVariables(item, symbol, (prefix + key));
});
} else {
returnData += createVariables(value, symbol, (prefix + key));
}
}
}
return returnData;
}Then, you can simply store the return data into file with npm scripts:
// create a LESS file
const less = () => {
const code = createVariables(tokenData, '@');
const lessFileName = tokenFileName.replace('.json', '.less');
fs.writeFile(lessFileName, code, (err) => err ? console.log(err));
}
// run the function
less();