npx create-next-app --typescript
npm install @mui/material @emotion/react @emotion/styled
npm install @mui/icons-material
`npm install @date-io/date-fns` or `npm install date-fns @types/date-fns`
npm install @mui/x-date-pickers
npx sb init
npm run storybook
npm install -D style-dictionary
mkdir style-dictionary
cd style-dictionary
style-dictionary init basic (create starter code)
style-dictionary build
npm install -D token-transformer
Add the following script commands to package.json
.
"generate-tokens": "yarn run generate-tokens:transform-figma-tokens && yarn run generate-tokens:style-dictionary",
"generate-tokens:transform-figma-tokens": "yarn token-transformer ./style-dictionary/source/figma-tokens.json ./style-dictionary/build/sd-tokens.json --resolveReferences true --preserveRawValue true --expandTypography true --expandShadow true",
"generate-tokens:style-dictionary": "node ./style-dictionary/sd.build.js"
Remove the starter code from the style-dictionary
folder and add the folowing files structure:
style-dictionary
- build/sd-tokens.json
- source/figma-tokens.json
- sd.build.js
- sd.config.json
In the sd.build.js
file paste the following code:
const styleDictionary = require('../node_modules/style-dictionary').extend('./style-dictionary/sd.config.json');
// Do custome stuff here
// https://amzn.github.io/style-dictionary/#/api
// Add a group name to the attribute hierarchy one level above the category. This make a lot of Style dictionary's built-in functions and filters work out of the box as they assume the tokens follow the "cti" structure.
styleDictionary.registerTransform({
name: 'attribute/gcti',
type: 'attribute',
transformer: function(token) {
const attrNames = ['group', 'category', 'type', 'item', 'subitem', 'state'];
const originalAttrs = token.attributes || {};
const generatedAttrs = {}
for(let i=0; i<token.path.length && i<attrNames.length; i++) {
generatedAttrs[attrNames[i]] = token.path[i];
}
return Object.assign(generatedAttrs, originalAttrs);
}
});
// Convert unit less sizes to rem but NOT if they are defined as px. IF the value is in px we will keep them as px for better accessibility (https://www.joshwcomeau.com/css/surprising-truth-about-pixels-and-accessibility/)
styleDictionary.registerTransform({
name: 'sizeToRem',
type: 'value',
matcher: function(token) {
return token.type === 'fontSize' || token.type === 'fontSizes' || token.type === 'borderRadius' || token.type === 'sizing' || token.type === 'spacing';
},
transformer: (token) => {
if(!token.value.toString().includes('px')) {
const baseFont = 16;
const floatVal = parseFloat(token.value);
if (isNaN(floatVal)) {
throwSizeError(token.name, token.value, 'rem');
}
if (floatVal === 0) {
return '0';
}
return `${floatVal / baseFont}rem`;
}
return token.value;
}
});
// Convert line height in percents to decimal for better accessibility
styleDictionary.registerTransform({
name: 'lineHeightToDecimal',
type: 'value',
matcher: function(token) {
return token.type === 'lineHeight';
},
transformer: (token) => {
if(token.value.toString().includes('%')) {
const dec = parseInt(token.value.replace('%', '')) / 100;
return dec;
}
return token.value;
}
});
// Remove TextCase. from value TextCase.uppercase
styleDictionary.registerTransform({
name: 'textCase',
type: 'value',
matcher: function(token) {
return token.type === 'textCase';
},
transformer: (token) => {
if(token.value.toString().includes('TextCase.')) {
return token.value.replace('TextCase.', '');
}
return token.value;
}
});
// Create custome token name
styleDictionary.registerTransform({
name: 'name/gcti/snakeKebab',
type: 'name',
transformer: (token, options) => {
const snakeCamel = [options.prefix].concat(token.path).join('_');
const snakeKebab = snakeCamel.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
return snakeKebab;
}
});
styleDictionary.buildAllPlatforms();
In the sd.config.json
file paste the following code:
{
"source": ["./style-dictionary/build/sd-tokens.json"],
"platforms": {
"css": {
"transformGroup": "css",
"transforms": [
"attribute/gcti",
"name/gcti/snakeKebab",
"sizeToRem",
"lineHeightToDecimal",
"textCase"
],
"prefix": "token",
"buildPath": "./styles/",
"files": [
{
"destination": "design-tokens.css",
"format": "css/variables",
"options": {
"outputReferences": true
}
}
]
},
"js": {
"transformGroup": "js",
"transforms": [
"attribute/gcti",
"name/cti/camel",
"sizeToRem",
"lineHeightToDecimal",
"textCase"
],
"prefix": "token",
"buildPath": "./styles/",
"files": [
{
"destination": "design-tokens.js",
"format": "javascript/es6",
"options": {
"outputReferences": true
}
}
]
}
}
}
-
Setup a new project in chromatic and copy the
chromatic_project_token
. -
Install Chromatic.
npm install --save-dev chromatic
npx chromatic --project-token= chromatic_project_token
npx chromatic --project-token= chromatic_project_token --force-rebuild
- Create GitHub token
- Add the new created GitHub token to Figma tokens plugin
- Change or create a token in Figma and push to your GitHub repo
-
Create a
.github/workflows
folder in the root of the project. -
Create a
transform-tokens.yml
file and add the following code:
//.github/workflows/transform-tokens.yml
name: Transform Figma Tokens
on:
push:
paths:
- "style-dictionary/source/figma-tokens.json"
jobs:
transform_figma_tokens:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: "12"
- name: Install Node Dependencies
run: npm install
- name: Build Style Dictionary
run: yarn run generate-tokens
- name: Commit Generated Platform Deliverables
id: "auto-commit-action"
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Update platform deliverables
- Create a new repository secret
- In the
.github/workflows
folder create achromatic.yml
file and add the following code:
//.github/workflows/chromatic.yml
name: Chromatic deploy
on:
workflow_run:
workflows: [Transform Figma Tokens]
types:
- completed
jobs:
chromatic-deployment:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v1
- name: Install dependencies
run: yarn
- name: Publish to Chromatic
uses: chromaui/action@v1
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}