Skip to content

Commit

Permalink
Merge pull request #96 from tokens-studio/opacity
Browse files Browse the repository at this point in the history
fix: add opacity percentage handling
  • Loading branch information
jorenbroekema authored Apr 14, 2023
2 parents b13f347 + e0893cc commit 04860d3
Show file tree
Hide file tree
Showing 15 changed files with 104 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/nasty-emus-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tokens-studio/sd-transforms': minor
---

BREAKING: Register ts/opacity transform, to transform opacity to number between 0 and 1, which is more multi-platform than percentages%. Breaking because people might not expect to have their opacity tokens suddenly as decimal numbers.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Generic:
- Maps token descriptions to comments -> `ts/descriptionToComment`
- Check and evaluate Math expressions (transitive) -> `ts/resolveMath`
- Transform dimensions tokens to have `px` as a unit when missing (transitive) -> `ts/size/px`
- Transform opacity from `%` to number between `0` and `1` -> `ts/opacity`
- Transform lineheight from `%` to unitless (150% -> 1.5) -> `ts/size/lineheight`
- Transform fontweight from keynames to fontweight numbers (100, 200, 300 ... 900) -> `ts/type/fontWeight`
- Transform color modifiers from Tokens Studio to color values -> `ts/color/modifiers`
Expand Down Expand Up @@ -151,6 +152,7 @@ const sd = StyleDictionary.extend({
transforms: [
'ts/descriptionToComment',
'ts/size/px',
'ts/opacity',
'ts/size/css/letterspacing',
'ts/size/lineheight',
'ts/type/fontWeight',
Expand Down
13 changes: 7 additions & 6 deletions src/css/transformLetterSpacing.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { percentageToDecimal } from '../utils/percentageToDecimal.js';

/**
* Helper: Transforms letter spacing % to em
*/
export function transformLetterSpacingForCSS(value: string | undefined): string | undefined {
export function transformLetterSpacingForCSS(
value: string | number | undefined,
): string | undefined {
if (value === undefined) {
return value;
}
if (`${value}`.endsWith('%')) {
const percentValue = value.slice(0, -1);
return `${parseFloat(percentValue) / 100}em`;
}
return value;
const decimal = percentageToDecimal(value);
return typeof decimal === 'string' || isNaN(decimal) ? `${value}` : `${decimal}em`;
}
1 change: 0 additions & 1 deletion src/parsers/expand-composites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ function shouldExpand<T extends SingleToken>(
condition: boolean | ExpandFilter<T>,
filePath: string,
): boolean {
console.log(filePath);
if (typeof condition === 'function') {
return condition(token, filePath);
}
Expand Down
11 changes: 10 additions & 1 deletion src/registerTransforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { mapDescriptionToComment } from './mapDescriptionToComment.js';
import { transformColorModifiers } from './color-modifiers/transformColorModifiers.js';
import { TransformOptions } from './TransformOptions.js';
import { expandComposites } from './parsers/expand-composites.js';
import { transformOpacity } from './transformOpacity.js';

const isBrowser = typeof window === 'object';

Expand Down Expand Up @@ -63,6 +64,13 @@ export async function registerTransforms(sd: Core, transformOpts?: TransformOpti
transformer: token => transformDimension(token.value),
});

_sd.registerTransform({
name: 'ts/opacity',
type: 'value',
matcher: token => token.type === 'opacity',
transformer: token => transformOpacity(token.value),
});

_sd.registerTransform({
name: 'ts/size/css/letterspacing',
type: 'value',
Expand Down Expand Up @@ -161,10 +169,11 @@ export async function registerTransforms(sd: Core, transformOpts?: TransformOpti
transforms: [
'ts/descriptionToComment',
'ts/size/px',
'ts/size/css/letterspacing',
'ts/opacity',
'ts/size/lineheight',
'ts/type/fontWeight',
'ts/resolveMath',
'ts/size/css/letterspacing',
'ts/typography/css/shorthand',
'ts/border/css/shorthand',
'ts/shadow/css/shorthand',
Expand Down
13 changes: 5 additions & 8 deletions src/transformLineHeight.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { percentageToDecimal } from './utils/percentageToDecimal.js';

/**
* Helper: Transforms line-height % to unit-less decimal value
* @example
* 150% -> 1.5
*/
export function transformLineHeight(
value: string | number | undefined,
): string | number | undefined {
export function transformLineHeight(value: string | number | undefined): string | undefined {
if (value === undefined) {
return value;
}
if (`${value}`.endsWith('%')) {
const percentValue = `${value}`.slice(0, -1);
return parseFloat(percentValue) / 100;
}
return value;
const decimal = percentageToDecimal(value);
return typeof decimal === 'string' || isNaN(decimal) ? `${value}` : `${decimal}`;
}
14 changes: 14 additions & 0 deletions src/transformOpacity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { percentageToDecimal } from './utils/percentageToDecimal.js';

/**
* Helper: Transforms opacity % to a decimal point number
* @example
* 50% -> 0.5
*/
export function transformOpacity(value: string | number | undefined): string | number | undefined {
if (value === undefined) {
return value;
}
const decimal = percentageToDecimal(value);
return typeof decimal === 'string' || isNaN(decimal) ? `${value}` : `${decimal}`;
}
8 changes: 8 additions & 0 deletions src/utils/percentageToDecimal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function percentageToDecimal(value: string | number): string | number {
if (!`${value}`.endsWith('%')) {
return `${value}`;
}
const percentValue = `${value}`.slice(0, -1);
const numberValue = parseFloat(percentValue);
return numberValue / 100;
}
4 changes: 2 additions & 2 deletions test/integration/expand-composition.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ describe('expand composition tokens', () => {
expect(file).to.include(
`
--sdCompositionSize: 24px;
--sdCompositionOpacity: 50%;
--sdCompositionOpacity: 0.5;
--sdCompositionFontSize: 96px;
--sdCompositionFontFamily: Roboto;
--sdCompositionFontWeight: 700;
Expand Down Expand Up @@ -82,7 +82,7 @@ describe('expand composition tokens', () => {
expect(file).to.include(
`
--sdCompositionSize: 24px;
--sdCompositionOpacity: 50%;
--sdCompositionOpacity: 0.5;
--sdCompositionFontSize: 96px;
--sdCompositionFontFamily: Roboto;
--sdCompositionFontWeight: 700;
Expand Down
1 change: 1 addition & 0 deletions test/integration/sd-transforms.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ describe('sd-transforms smoke tests', () => {
--sdDimensionMd: 16px;
--sdDimensionLg: 32px;
--sdDimensionXl: 64px;
--sdOpacity: 0.25;
--sdSpacingSm: 8px;
--sdSpacingXl: 64px;
--sdSpacingMultiValue: 8px 64px; /* You can have multiple values in a single spacing token. Read more on these: https://docs.tokens.studio/available-tokens/spacing-tokens#multi-value-spacing-tokens */
Expand Down
4 changes: 4 additions & 0 deletions test/integration/tokens/sd-transforms.tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
"type": "dimension"
}
},
"opacity": {
"value": "25%",
"type": "opacity"
},
"spacing": {
"sm": {
"value": "{dimension.sm}",
Expand Down
4 changes: 4 additions & 0 deletions test/spec/css/transformLetterSpacing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ describe('transform letter spacing', () => {
it("does not transform letter spacing if it doesn't end with %", () => {
expect(transformLetterSpacingForCSS('100')).to.equal('100');
});

it('does not transform letter spacing if it cannot be parsed as float', () => {
expect(transformLetterSpacingForCSS('not-a-float%')).to.equal('not-a-float%');
});
});
6 changes: 5 additions & 1 deletion test/spec/transformLineHeight.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ runTransformSuite(transformLineHeight as (value: unknown) => unknown);

describe('transform line height', () => {
it('transforms line-height % to unit-less decimal value', () => {
expect(transformLineHeight('50%')).to.equal(0.5);
expect(transformLineHeight('50%')).to.equal('0.5');
});

it("does not transform line-height if it doesn't end with %", () => {
expect(transformLineHeight('100')).to.equal('100');
});

it('does not transform line-height if it cannot be parsed as float', () => {
expect(transformLineHeight('not-a-float%')).to.equal('not-a-float%');
});
});
19 changes: 19 additions & 0 deletions test/spec/transformOpacity.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expect } from '@esm-bundle/chai';
import { transformOpacity } from '../../src/transformOpacity.js';
import { runTransformSuite } from '../suites/transform-suite.spec.js';

runTransformSuite(transformOpacity as (value: unknown) => unknown);

describe('transform opacity', () => {
it('transforms opacity % to unit-less decimal value', () => {
expect(transformOpacity('50%')).to.equal('0.5');
});

it("does not transform opacity if it doesn't end with %", () => {
expect(transformOpacity('100')).to.equal('100');
});

it('does not transform opacity if it cannot be parsed as float', () => {
expect(transformOpacity('not-a-float%')).to.equal('not-a-float%');
});
});
18 changes: 18 additions & 0 deletions test/spec/utils/percentageToDecimal.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { expect } from '@esm-bundle/chai';
import { percentageToDecimal } from '../../../src/utils/percentageToDecimal.js';

describe('percentage to decimal', () => {
it('converts percentage strings to decimal numbers', () => {
expect(percentageToDecimal('100%')).to.equal(1);
expect(percentageToDecimal('50%')).to.equal(0.5);
});

it('ignores values that do not end with a percentage character', () => {
expect(percentageToDecimal('100')).to.equal('100');
expect(percentageToDecimal('foo')).to.equal('foo');
});

it('returns NaN if percentage cannot be parsed as a float', () => {
expect(percentageToDecimal('foo%')).to.be.NaN;
});
});

0 comments on commit 04860d3

Please sign in to comment.