Closed KenjiCrosland closed 4 months ago
We're having the same situation. In our case, we define the base colors in one file, and then define one additional color file for each theme. The theme color files reference the base colors, and the base color file is filtered out from the final output.
The ideal behavior for this situation would be:
Very much doable! On our end, we have a custom CTI that has a layer field which could be base
, semantic
, or component
. In our build config we then have a filter that essentially makes sure token.attributes.layer != base
.
Very much doable! On our end, we have a custom CTI that has a layer field which could be
base
,semantic
, orcomponent
. In our build config we then have a filter that essentially makes suretoken.attributes.layer != base
.
That's not the issue, we're doing that as well. The issue is that references to the filtered tokens are still included in the output.
For example:
base.json
{
"color": {
"base": {
"white": { "value": "#ffffff" }
}
}
}
some.theme.json
{
"color": {
"background": { "value": "{color.base.white}" },
"button": {
"background": { "value": "{color.background.white}" }
}
}
}
Now if you filter base.json
from the output and set outputReferences
to true
:
{
platforms: {
css: {
transformGroup: "css",
files: [{
destination: "variables.css",
format: "css/variables",
filter: "baseColorFilter",
options: {
outputReferences: true
}
}]
}
}
}
The desired output would be:
--color-background: #ffffff;
--color-button-background: --color-background;
So references would only be used if the referenced value is part of the output. Right now, this doesn't work, though, because Styledict tries to use references even if the referenced value is not included in the final output, and since it cannot resolve the references, the build will fail.
@woylie You are right, I misinterpreted the problem. My bad! I appreciate your example. I get the issue now. Just thought more about it and have a likely solution.
The gist is, outputReferences
(and the subsequent functions usesReference
and formattedVariables
) doesn't take into account if a referenced token is filtered out to your point. But we can bypass that quirk by defining a customFormat where we pre-process the dictionary object to remove references (and keep the literal value intact) to filtered tokens.
My example is specific to css/variables
and tokens that are base
but I think we can make that smarter to sync up with whatever we are filtering on.
Key part:
const resolveBaseReferences = (dictionary) => {
dictionary.allTokens.map(token => {
if (token.original.value.includes('color.base.')) {
token.original.value = token.value
}
return token
})
return dictionary
}
StyleDictionary.registerFormat({
name: 'custom/css/variables',
formatter: function({dictionary, file, options}) {
const selector = options.selector ? options.selector : `:root`;
const { outputReferences } = options;
dictionary = resolveBaseReferences(dictionary)
return fileHeader({file}) +
`${selector} {\n` +
formattedVariables({format: 'css', dictionary, outputReferences}) +
'\n}\n';
}
})
This does give the desired output:
--color-background: #ffffff;
--color-button-background: --color-background;
Even though I have a base.json
with color.base.white
in it thats referenced by color.background
Example repo - style-dictionary-output-references-demo
I would classify it as a bug that outputReferences on a format-level does not take into account filters (also on format-level). It definitely should imo, and perhaps outputReferences besides just "true" or "false" should also accept a Function where you can selectively decide to output references or not, per token basis.
We are running into the same issue.
We have base tokens for colors and those are referenced in semantic tokens. We don't want the base tokens to be used, so neither the tokens nor references to base tokens should be in the output.
However, component tokens reference semantic tokens. We want those to use css variables and keep the references as this allows us to overwrite semantic tokens and those changes would propagate to component tokens.
Ah yeah we can use this issue for what we started talking about on here https://github.com/amzn/style-dictionary/issues/1021#issuecomment-2031769455
My comment in October wasn't entirely correct because filtering tokens that are relied upon through references when using outputReferences 'true' do give a warning in the console so that's decent, but it doesn't exactly help you fix the problem, selectively not outputting refs for tokens that rely on tokens that are filtered out would be a good fix. So that gives us a pretty good use case for justifying the feature I suggested in that other issue: disabling outputting refs for specific tokens, in this case any token that contains references that would be filtered out.
I'll add this issue to the v4 board
So @jorenbroekema this would still mean changing outputReferencea to accept a function or Boolean right?
Yup! should come with a little demo on how you can use that to not output refs for tokens that contain refs that are filtered out, the getReferences()
util will come in handy for that I think, or marking the token somehow as "contains refs that are filtered out"
I'm looking to use 3.0 outputReferences but there are several tokens we filter out of our main output file. Is it possible to only output the references for non-filtered tokens?
For example, lets say we have an
_options
folder whose values get used in our final output file but the values of those options are not in the output file. When I use outputReferences these option token names get referenced even though they aren't in the final outputted file. Could we have the values of these instead?