cobalt-ui
cobalt-ui copied to clipboard
[question] Token referencing an alias gets raw value?
Setup:
palette.json
-> collection of colors, some containing a custom extension that adjusts the raw value
colors.json
-> collection of color tokens, each referencing a palette color
For example's sake, let's say my custom extension sets the opacity of an rgba color value.
// palette.json
{
"palette": {
"$type": "color",
"black": {
"$value": "rgba(0,0,0,100)",
"$extensions": { "set-opacity": { "opacity": "0.25" } }
}
}
}
// colors.json
{
"colors": {
"$type": "color",
"primary": {
"$value": "{palette.black}"
}
}
}
When a plugin is run, such as @cobalt-ui/plugin-js
, the value of token
in the transform
function references the value of the alias before the extensions are run, instead of the computed value. For example:
// tokens.config.mjs
import pluginCustom from './pluginCustom.mjs'
export default {
tokens: [
"./src/palette.json",
"./src/color.json"
],
plugins: [
pluginJS({
transform: (token) => {
console.log(token.$value); // 'rgba(0,0,0,100)'
console.log(token._original); // { '$value': '{palette.black}' }
return token.$value;
},
})
}
Is this intended? If so, is there a way to either:
- Provide an option to have the plugins transform computed tokens (post-extension)
- Expose all properties of
__original
to include extensions
Thanks for raising! $extensions
in the spec is basically arbitrary metadata meant for tools to interpret how they will. There is no standard inside $extensions
, so every tool will interpret it differently.
So there is no way for Cobalt to know how to execute set-opacity
; it’s merely ignored. And as plugins are concerned with build targets, even if a plugin provided instructions with how to apply $extensions['set-opacity']
, that would only apply to that plugin run and no other (i.e. plugin-js wouldn’t affect plugin-css).
So I think of the 2 proposals, #2 is the only one that’s possible—we do need to keep $extensions
in the transformer for consumers to control how to execute that code.
I don’t think it’s intentional that’s omitted; it’s probably just a byproduct of how $extensions.mode
works in Cobalt currently. We probably need to have better, clearer ways to provide multi-modal transforms in plugins, which means handling $extensions
better in general.
A related issue popped up this week with #192. I’ve realized that plugins need 3 things:
- The final / resolved value (exists currently)
- The original as-authored raw value (exists currently)
- (If aliased) The resolved original raw value, including extensions and modes (currently missing)
I think there’s a way to provide the third without a breaking change to the API. But things like these will inform the 2.0 API revision that will likely happen later this year.
On another note, this issue is related to #179
Style Dictionary added this concept in v3. They call it "transitive transforms". Just wanted to note it as potential inspiration.
@jbarreiros ah that’s very helpful, thank you! I am currently exploring something like that as part of the 2.0 plugin API. That will be a good reference point though