figma-plugin
figma-plugin copied to clipboard
Update documentation to explain how to transform shadow tokens
Describe the bug When trying to use a box shadow token, the child properties are not being parsed in CSS or SCSS (or any flat format) on Style Dictionary.
To Reproduce Steps to reproduce the behavior:
"set": {
"radio": {
"unchecked": {
"focus": {
"box-shadow": {
"value": {
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "rgba({cta.color.primary}, 0.3)",
"type": "dropShadow"
},
"description": "Focus ring for radio button",
"type": "boxShadow"
}
}
}
I have passed this token through the token-transformer package. This token is returning as follows:
--radio-unchecked-focus-box-shadow: [object Object];
$radio-unchecked-focus-box-shadow: [object Object];
export const RadioFocusBoxShadow = {"x":0,"y":0,"blur":0,"spread":3,"color":"#3d4cbf4d","type":"dropShadow"};
Expected behavior I would expect the Box Shadow properties to be spread as separate tokens, similar to how typography is handled.
@dermyhughes I ran into the same problem, did you solve it
I'm wondering how array shadow tokens should be transformed, having keys with "0", "1", "2" etc would probably not be ideal. Instead the current array we output would still allow you to write your own transform and convert that to a valid css shadow syntax.
I've written a simple transformer to handle this for CSS/SCSS, but haven't given much thought as to how it would work for other formats. Maybe this is more a Style Dictionary issue than Figma Tokens.
function isShadow(token) {
return token.type === 'boxShadow';
}
StyleDictionary.registerTransform({
name: 'shadow/spreadShadow',
type: 'value',
matcher: isShadow,
transformer: (token) => {
const shadow = Object.values(token.value);
const [x, y, blur, spread, color] = shadow.map((s) => s.toString());
return `${x}px ${y}px ${blur}px ${spread}px ${color}`;
}
});
That's awesome. I think a lot depends on the W3C standard to define a common format. Every tool will write it their own style until then, so I doubt that SD will write something specific for Figma Tokens.
We also had a use case needing a single string for both es6 and css variables, figured I'd share here:
Thanks @dermyhughes for pointing us in the right direction!
StyleDictionary.registerTransform({
name: 'shadow/spreadShadow',
type: 'value',
matcher: function(token) {
return token.type === 'boxShadow';
},
transformer: (token) => {
const shadows = Object.values(token.value);
const result = shadows.map(shadow => `${shadow.x} ${shadow.y} ${shadow.blur} ${shadow.spread} ${shadow.color}`);
return result.join(',');
}
});
I think we want to solve this on a transformation level (style dictionary). The current way of giving the whole shadow object is fine IMO, as users can then transform these to whatever they'd want.
However, we should update docs to include something to point users in the right direction, and using the transforms mentioned above would be a great start.
Sharing my CSS transform as well - this supports stacked shadow tokens, as well as aliased color references, and inset shadows:
StyleDictionaryPackage.registerTransform({
name: 'shadow/css',
type: 'value',
// necessary in case the color is an alias reference, or the shadows themselves are aliased
transitive: true,
matcher: (token) => token.type === 'boxShadow',
transformer: (token) => {
// allow both single and multi shadow tokens
const shadow = Array.isArray(token.value) ? token.value : [token.value];
const value = shadow.map((s) => {
const { x, y, blur, color, type } = s;
// support inset shadows as well
return `${type === 'innerShadow' ? 'inset ' : ''}${x}px ${y}px ${blur}px ${color}`;
});
return value.join(', ');
},
});
Hey @mihkeleidast , thx for sharing your solution 👍🏻
I agree with @six7 that this should be tackled at the transformation level, instead of expanding the shadow token. There will be different ways of outputting shadows on different platforms and that's what SD and platform specific transforms do best. See a similar discussion around Support Composite Token in the SD repo.
For anyone wanting to create a custom transform here's a slightly modified version of @mihkeleidast 's code, that also includes the spread:
/**
* Based on: https://github.com/six7/figma-tokens/issues/379#issuecomment-1116953915
*/
StyleDictionaryPackage.registerTransform({
name: "shadow/css",
type: "value",
transitive: true, // Necessary when the color is an alias reference, or the shadows themselves are aliased
matcher: (token) => token.type === "boxShadow",
transformer: (token) => {
// Allow both single and multi shadow tokens:
const shadows = Array.isArray(token.value) ? token.value : [token.value];
const transformedShadows = shadows.map((shadow) => {
const { x, y, blur, spread, color, type } = shadow;
const inset = type === "innerShadow" ? "inset " : "";
return `${inset}${x}px ${y}px ${blur}px ${spread}px ${color}`;
});
return transformedShadows.join(", ");
},
});
Closing this as sd-transforms now supports most features token-transformer has supported. Added a page to our docs.
- https://docs.tokens.studio/transforming/style-dictionary
- https://www.npmjs.com/package/@tokens-studio/sd-transforms
- https://configurator.tokens.studio/