Hello!
We have opacity tokens in our Design System. To generate CSS and SCSS variables its's ok, but how can we deal with opacity tokens for iOS and Android?
Example JSON
{
"opacity": {
"8": { "value": ".8" },
"6": { "value": ".6" },
"4": { "value": ".4" },
"1": { "value": ".16" }
}
}
````
Generates
```scss
$opacity-1: .16;
$opacity-4: .4;
$opacity-6: .6;
$opacity-8: .8;
Or shadow tokens
{
"shadow": {
"level-1": { "value": "0 4px 8px 0 rgba (0, 0, 0, 0.10)" },
"level-2": { "value": "0 8px 16px 0 rgba (0, 0, 0, 0.10)" },
"level-3": { "value": "0 16px 32px 0 rgba (0, 0, 0, 0.10)" },
"level-4": { "value": "0 32px 64px 0 rgba (0, 0, 0, 0.10)" }
}
}
That generates
$shadow-level-1: 0 4px 8px 0 rgba (0, 0, 0, 0.10);
$shadow-level-2: 0 8px 16px 0 rgba (0, 0, 0, 0.10);
$shadow-level-3: 0 16px 32px 0 rgba (0, 0, 0, 0.10);
$shadow-level-4: 0 32px 64px 0 rgba (0, 0, 0, 0.10);
up 馃槉
For more complex token like shadows or gradients I typically store the tokens as an array or object and then write custom transforms depending on which platform you need to support.
To take your shadows for example you could store the tokens like so:
{
"shadow": {
"level-1": {
"value": {
"x": 0,
"y": 4,
"blur": 8,
"spread": 0,
"color": "#000000",
"opacity": 0.1
}
},
"level-2": "..."
}
}
And then your custom transforms can access the individual values as needed. For the web it would look something like this (haven't actually tested):
const tinycolor = require('tinycolor2')
StyleDictionary.registerTransform({
name: 'shadow/scss',
type: 'value',
matcher: function(prop) {
return prop.attributes.category === 'shadow';
},
transformer: function(prop) {
// destructure shadow values from original token value
const {
x,
y,
blur,
spread,
color,
alpha
} = prop.original.value
// convert hex code to rgba string
const shadowColor = tinycolor(color)
shadowColor.setAlpha(alpha)
shadowColor.toRgbString()
return `${x}px ${y}px ${blur}px ${spread}px ${shadowColor}`
}
});
For Android/iOS it would be a similar pattern though you may need to look into custom formats and templates for those depending on what the desired outcome looks like.
Here's the custom shadow transformer I wrote for our token project:
// configuration/shadowTransform.js
const styleDictionary = require("style-dictionary");
const tinycolor = require("tinycolor2");
const toPx = (value) =>
styleDictionary.transform["size/remToPx"].transformer({ value });
const shadowMatcher = (prop) => prop.attributes.category === "shadow";
const webShadowTransformer = (prop) => {
const {
blurRadius,
color,
offsetX,
offsetY,
spreadRadius,
} = prop.original.value;
return `${toPx(offsetX)} ${toPx(offsetY)} ${toPx(blurRadius)} ${toPx(
spreadRadius
)} ${tinycolor(color).toRgbString()}`;
};
module.exports.shadowCSSTransform = {
matcher: shadowMatcher,
name: "shadow/css",
transformer: webShadowTransformer,
type: "value",
};
module.exports.shadowSCSSTransform = {
matcher: shadowMatcher,
name: "shadow/scss",
transformer: webShadowTransformer,
type: "value",
};
These get plugged into the project's config, like so:
// configuration/index.js
module.exports = {
transform: {
"shadow/css": shadowCSSTransform,
"shadow/scss": shadowSCSSTransform,
},
// ...
}
鈥nd individual config.platforms use them. Seems to work pretty well (for web).
Thanks @davidyeiser your solition works fine to me!
@swashcap Does the webShadowTransformer you wrote work for referencing existing values?
Like this e.g.:
"value": {
"blurRadius": 4,
"color": "{color.base.gray.900}",
"offsetX": 1,
"offsetY": 4,
"spreadRadius": 0,
}
I tried it and get this error when I run it.
value.replace(regex, function(match, variable) {
^
TypeError: value.replace is not a function
at Object.getReferences (/Users/.../.../.../.../node_modules/style-dictionary/lib/utils/references/getReferences.js:45:9)
I'm just curious if the transform doesn't support it, or if I have made a mistake somewhere else 馃槉
Most helpful comment
Here's the custom shadow transformer I wrote for our token project:
These get plugged into the project's config, like so:
鈥nd individual
config.platforms use them. Seems to work pretty well (for web).