I'm working on a refactor of our style-dictionary implementation. I'm working on applying alpha values through a transform rather than predefining values with alpha values.
It looks something like this:
In color.json
{
color: {
text: {
primary: {
value: '{options.color.warm-grey-1150.value}',
alpha: .75,
category: 'color',
docs: {
category: 'colors',
type: 'text',
example: 'color',
description: 'The default, primary text color',
},
}
}
}
The value for warm-grey-1150
is #0C0B08
and is in another file.
I have already successfully created a simple alpha transform for scss, less, and js and it works just fine:
const tinycolor = require('tinycolor2');
module.exports = (StyleDictionary) => {
StyleDictionary.registerTransform({
name: 'color/alpha',
type: 'value',
transitive: true,
matcher(prop) {
return (prop.attributes.category === 'color') && prop.alpha;
},
transformer(prop) {
const { value, alpha } = prop;
let color = tinycolor(value);
color.setAlpha(alpha)
return color.toRgbString();
},
});
};
However, I'm stuck on the IOS UIColor transform. My initial approach was to convert the colors to a hex8 value, as those were the original values that we were converting. (We had a value already created which mapped to #0C0B08BF
and just plugged that into UIColor).
So I created a separate transform for IOS to set the alpha value and then extended the UI-color transform to make it transitive.
const tinycolor = require('tinycolor2');
module.exports = (StyleDictionary) => {
StyleDictionary.registerTransform({
name: 'color/alpha-hex',
type: 'value',
transitive: true,
matcher(prop) {
return (prop.attributes.category === 'color') && prop.alpha;
},
transformer(prop) {
let { value, alpha } = prop;
let color = tinycolor(value);
color.setAlpha(alpha);
return color.toHex8String();
},
});
};
In the transform group I made sure that the alpha-hex
transform happened before UIColor:
module.exports = (StyleDictionary) => {
StyleDictionary.registerTransformGroup({
name: 'custom/ios',
transforms: [
//Other non-color related transforms
'color/alpha-hex',
'color/UIColor-transitive',
//Other non-color related transforms
],
});
};
The results were strange, as all the UIColor values that happened to undergo the alpha transform had a red, green and blue value of zero, but the alpha value was set:
[UIColor colorWithRed:0.000f green:0.000f blue:0.000f alpha:0.749f]
I decided to experiment and tried using chroma-js instead of tinycolor2 and chroma threw up an error:
Error: unknown format: [UIColor colorWithRed:0.047f green:0.043f blue:0.031f alpha:1.000f]
(Apparently, tinycolor doesn't throw up an error when passed an invalid format and instead creates an instance of tinycolor with #000000
as its value.)
For some reason, the UIColor formatted values are already being piped to the alpha-hex transform, even though I specified that I wanted the alpha-hex transform to run before. I've tried several things like not running the transform if value.indexOf('UIColor') !== -1)
and that didn't seem to work. I also copied/pasted the UIColor transform and tried to run my hex transform in the same transform function but that didn't seem to work either.
Any ideas on what I'm missing here?
I figured out the issue for me. We had a whole bunch of options structure like this:
These are one of our color options tokens that get filtered out of the final result. These options get used for tokens like
color-text-primary
When we use a transitive transform we are going through every single transform in a transform group for each of the options. With ios UIColor the problem is the final result of the transform can't get transformed again because it's a different format.
So this is what solved it for us. We changed the options to bare values like so:
we removed the "value" keyword as well as the category. However, this meant that now we had to make all of our transforms transitive (at least those dealing with color) and this meant extending some of the existing predefined transforms so they were transitive like so:
This worked great for us. To sum up the two steps we needed to make were: