Skip to content

Commit

Permalink
Fix figma color transform (#722)
Browse files Browse the repository at this point in the history
* adding a fix for mix

* added changeset

* fix for alpha in mix

* fixes

* github-actions[bot] Regenerated snapshots

---------

Co-authored-by: lukasoppermann <lukasoppermann@users.noreply.github.com>
  • Loading branch information
lukasoppermann and lukasoppermann authored Aug 31, 2023
1 parent 01aae86 commit 5394816
Show file tree
Hide file tree
Showing 32 changed files with 87 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/clever-zebras-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/primitives': patch
---

Fioxed RGBAfloatconversion
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/formats/jsonFigma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const jsonFigma: StyleDictionary.Formatter = ({dictionary, file: _file, p
const tokens = dictionary.allTokens.sort(sortByReference(dictionary)).map(token => {
const {attributes, value, $type, comment: description, original, alpha, mix} = token
const {mode, collection, scopes} = attributes || {}

return {
name: token.name,
value,
Expand Down
2 changes: 1 addition & 1 deletion src/transformers/colorToHexMix.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('Transformer: colorToHexMix', () => {
},
}),
]
const expectedOutput = ['#15191d77', '#4c5b6a4b']
const expectedOutput = ['#51617177', '#3e4a574b']
expect(input.map(item => colorToHexMix.transformer(item, {}))).toStrictEqual(expectedOutput)
})

Expand Down
8 changes: 5 additions & 3 deletions src/transformers/colorToHexMix.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {toHex, mix} from 'color2k'
import {toHex} from 'color2k'
import {isColorWithMix} from '~/src/filters'
import type StyleDictionary from 'style-dictionary'
import {getTokenValue} from './utilities/getTokenValue'
import mix from './utilities/mix'
/**
* @description replaces tokens value with `hex8` color using the tokens `alpha` property to specify the value used for alpha
* @type value transformer — [StyleDictionary.ValueTransform](https://github.com/amzn/style-dictionary/blob/main/types/Transform.d.ts)
Expand All @@ -12,6 +13,7 @@ export const colorToHexMix: StyleDictionary.Transform = {
type: `value`,
transitive: true,
matcher: isColorWithMix,
transformer: (token: StyleDictionary.TransformedToken) =>
toHex(mix(getTokenValue(token), token.mix?.color || getTokenValue(token), token.mix?.weight || 0)),
transformer: (token: StyleDictionary.TransformedToken) => {
return toHex(mix(getTokenValue(token), token.mix?.color || getTokenValue(token), token.mix?.weight || 0))
},
}
26 changes: 19 additions & 7 deletions src/transformers/colorToRgbaFloat.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {getMockToken} from '~/src/test-utilities'
import {colorToRgbaFloat} from './colorToRgbaFloat'
import {rgbaFloatToHex} from './utilities/rgbaFloatToHex'

describe('Transformer: colorToRgbaFloat', () => {
it('transforms `hex3`, `hex6`, and `hex8` tokens to rgb float value', () => {
Expand Down Expand Up @@ -85,22 +86,22 @@ describe('Transformer: colorToRgbaFloat', () => {
it('transforms `color` tokens including mix', () => {
expect(
[
getMockToken({value: '#343434', mix: {color: '#000000', weight: 0.5}}),
getMockToken({name: 'Mix of reds', value: '#a40e26', mix: {color: '#660018', weight: 0.4}}),
getMockToken({value: '#34343466', mix: {color: '#000000'}}),
getMockToken({value: 'rgb(100,200,255)', mix: {weight: 0.5}}),
getMockToken({value: 'rgba(100,200,255,0.8)', mix: {color: undefined, weight: undefined}}),
].map(item => colorToRgbaFloat.transformer(item, {})),
).toStrictEqual([
{
b: 0.10196078431372549,
g: 0.10196078431372549,
r: 0.10196078431372549,
b: 0.12549019607843137,
g: 0.03137254901960784,
r: 0.5450980392156862,
a: 1,
},
{
b: 0.050980392156862744,
g: 0.050980392156862744,
r: 0.050980392156862744,
r: 0.20392156862745098,
g: 0.20392156862745098,
b: 0.20392156862745098,
a: 0.4,
},
{
Expand All @@ -116,6 +117,17 @@ describe('Transformer: colorToRgbaFloat', () => {
a: 0.8,
},
])

expect(
[
getMockToken({name: 'Mix of reds', value: '#a40e26', mix: {color: '#660018', weight: 0.4}}),
getMockToken({value: '#34343466', mix: {color: '#000000'}}),
getMockToken({value: 'rgb(100,200,255)', mix: {weight: 0.5}}),
getMockToken({value: 'rgba(100,200,255,0.8)', mix: {color: undefined, weight: undefined}}),
]
.map(item => colorToRgbaFloat.transformer(item, {}))
.map(item => rgbaFloatToHex(item)),
).toStrictEqual(['#8b0820', '#34343466', '#64c8ff', '#64c8ffcc'])
})

it('it forwards `rgb float` values', () => {
Expand Down
11 changes: 8 additions & 3 deletions src/transformers/colorToRgbaFloat.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {mix, toHex} from 'color2k'
import {toHex} from 'color2k'
import {isColor} from '~/src/filters'
import type StyleDictionary from 'style-dictionary'
import {getTokenValue} from './utilities/getTokenValue'
import {rgbaFloatToHex} from './utilities/rgbaFloatToHex'
import mix from './utilities/mix'

const toRgbaFloat = (token: StyleDictionary.TransformedToken, alpha?: number) => {
let tokenValue = getTokenValue(token)
Expand All @@ -14,18 +15,22 @@ const toRgbaFloat = (token: StyleDictionary.TransformedToken, alpha?: number) =>
if (tokenMixColor && isRgbaFloat(tokenMixColor)) {
tokenMixColor = rgbaFloatToHex(tokenMixColor, false)
}
let hex = toHex(tokenValue)
// mix color with mix color and weight
const hex = toHex(mix(tokenValue, tokenMixColor || tokenValue, token.mix?.weight || 0))
if (token.mix && token.mix.color && token.mix.weight) {
hex = toHex(mix(tokenValue, tokenMixColor, token.mix.weight))
}
// retrieve spots from hex value (hex 3, hex 6 or hex 8)
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex) ?? ['00', '00', '00']
// return parsed rgba float object using alpha value from token, from hex code or defaults to 1
return {
r: parseInt(result[1], 16) / 255,
g: parseInt(result[2], 16) / 255,
b: parseInt(result[3], 16) / 255,
a: alpha !== undefined ? alpha : parseInt(result[4], 16) / 255 || 1,
a: alpha !== undefined ? alpha : result[4] ? parseInt(result[4], 16) / 255 : 1,
}
}

// sum up the values of all values in an array
const sum = (array: unknown[]): number => array.reduce((acc: number, v: unknown) => acc + parseInt(`${v}`), 0)

Expand Down
46 changes: 46 additions & 0 deletions src/transformers/utilities/mix.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {rgba, parseToRgba} from 'color2k'

/**
* Mixes two colors together. Taken from sass's implementation.
*/
function mix(color1: string, color2: string, weight: number): string {
const normalize = (n: number, index: number) =>
// 3rd index is alpha channel which is already normalized
index === 3 ? n : n / 255

const [r1, g1, b1, a1] = parseToRgba(color1).map(normalize)
const [r2, g2, b2, a2] = parseToRgba(color2).map(normalize)

// The formula is copied from the original Sass implementation:
// http://sass-lang.com/documentation/Sass/Script/Functions.html#mix-instance_method
const normalizedWeight = 2 * weight - 1
const alphaDelta = a1 - a2

const combinedWeight =
normalizedWeight * alphaDelta === -1
? normalizedWeight
: (normalizedWeight + alphaDelta) / (1 + normalizedWeight * alphaDelta)

const weight2 = (combinedWeight + 1) / 2
const weight1 = 1 - weight2
const r = Math.round((r1 * weight1 + r2 * weight2) * 255)
const g = Math.round((g1 * weight1 + g2 * weight2) * 255)
const b = Math.round((b1 * weight1 + b2 * weight2) * 255)
const a = a2 * weight + a1 * (1 - weight)
return rgba(r, g, b, a)
}

export default mix
// Number* weight = ARGR("$weight", Number, 0, 100);
// double p = weight->value()/100;
// double w = 2*p - 1;
// double a = color1->a() - color2->a();
// double nW = ((w * a == -1) ? w : (w + a)/(1 + w*a))
// double w1 = (nW + 1)/2.0;
// double w2 = 1 - w1;

// return new (ctx.mem) Color(pstate,
// std::round(w1*color1->r() + w2*color2->r()),
// std::round(w1*color1->g() + w2*color2->g()),
// std::round(w1*color1->b() + w2*color2->b()),
// color1->a()*p + color2->a()*(1-p));
4 changes: 2 additions & 2 deletions src/transformers/utilities/rgbaFloatToHex.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const rgbaFloatToHex = ({r, g, b, a}: {r: number; g: number; b: number; a?: number}, alpha = true): string => {
const values = [r, g, b, alpha === true && a ? a : undefined].filter(Boolean) as number[]
const values = [r, g, b, alpha === true && a && a < 1 ? a : undefined].filter(item => item !== undefined) as number[]

return `#${values.map(v => `${(v * 255).toString(16)}`.padEnd(2, '0')).join('')}`
return `#${values.map(v => `${(v * 255).toString(16)}`.padStart(2, '0')).join('')}`
}

0 comments on commit 5394816

Please sign in to comment.