Skip to content

Commit

Permalink
add dimension to pixelUnitless transformer for figma
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasoppermann committed Jul 12, 2023
1 parent a274930 commit fedff7c
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/PrimerStyleDictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
typographyToCss,
colorToHexMix,
dimensionToRem,
dimensionToPixelUnitless,
colorToRgbaFloat,
} from './transformers'
import {
Expand Down Expand Up @@ -130,6 +131,11 @@ StyleDictionary.registerTransform({
...dimensionToRem,
})

StyleDictionary.registerTransform({
name: 'dimension/pixelUnitless',
...dimensionToPixelUnitless,
})

StyleDictionary.registerTransform({
name: 'json/deprecated',
...jsonDeprecated,
Expand Down
93 changes: 93 additions & 0 deletions src/transformers/dimensionToPixelUnitless.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import {getMockToken} from '~/src/test-utilities'
import {dimensionToPixelUnitless} from './dimensionToPixelUnitless'

describe('Transformer: dimensionToPixelUnitless', () => {
it('transforms pixel string tokens', () => {
const input = [
getMockToken({
value: '16px',
}),
]
const expectedOutput = [16]
expect(input.map(item => dimensionToPixelUnitless.transformer(item, {}))).toStrictEqual(expectedOutput)
})

it('does not transforms number or number string', () => {
const input = [
getMockToken({
value: '16',
}),
getMockToken({
value: 16,
}),
]
const expectedOutput = ['16', 16]
expect(input.map(item => dimensionToPixelUnitless.transformer(item, {}))).toStrictEqual(expectedOutput)
})

it('transforms rem', () => {
const input = [
getMockToken({
value: '1rem',
}),
]
const expectedOutput = [16]
expect(input.map(item => dimensionToPixelUnitless.transformer(item, {}))).toStrictEqual(expectedOutput)
})

it('transforms rem with custom basePxFontSize', () => {
const input = [
getMockToken({
value: '2rem',
}),
]
const expectedOutput = [20]
expect(input.map(item => dimensionToPixelUnitless.transformer(item, {basePxFontSize: 10}))).toStrictEqual(
expectedOutput,
)
})

it('does not transforms em', () => {
const input = [
getMockToken({
value: '1em',
}),
]
const expectedOutput = ['1em']
expect(input.map(item => dimensionToPixelUnitless.transformer(item, {}))).toStrictEqual(expectedOutput)
})

it('transforms 0 to 0', () => {
const input = [
getMockToken({
value: '0rem',
}),
getMockToken({
value: '0px',
}),
getMockToken({
value: '0',
}),
]
const expectedOutput = [0, 0, 0]
expect(input.map(item => dimensionToPixelUnitless.transformer(item, {}))).toStrictEqual(expectedOutput)
})

it('throws on invalid tokens', () => {
const input = [
getMockToken({
value: 'rem',
}),
getMockToken({
value: '',
}),
getMockToken({
value: undefined,
}),
getMockToken({
value: null,
}),
]
expect(() => input.map(item => dimensionToPixelUnitless.transformer(item, {}))).toThrow()
})
})
60 changes: 60 additions & 0 deletions src/transformers/dimensionToPixelUnitless.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {isDimension} from '~/src/filters'
import type StyleDictionary from 'style-dictionary'
import type {Platform} from 'style-dictionary'

/**
* @description base font size from options or 16
* @param options
* @returns number
*/
const getBasePxFontSize = (options?: Platform): number => (options && options.basePxFontSize) || 16

/**
* @description checks if token value has a specific unit
* @param value token value
* @param unit unit string like px or value
* @returns boolean
*/
const hasUnit = (value: string | number, unit: string): boolean => {
if (typeof value === 'number') {
return false
}

return value.indexOf(unit) > -1
}

/**
* @description converts dimension tokens value to pixel value without unit, ignores `em` as they are relative to the font size of the parent element
* @type value transformer — [StyleDictionary.ValueTransform](https://github.com/amzn/style-dictionary/blob/main/types/Transform.d.ts)
* @matcher matches all tokens of $type `dimension`
* @transformer returns a float number
*/
export const dimensionToPixelUnitless: StyleDictionary.Transform = {
type: `value`,
transitive: true,
matcher: isDimension,
transformer: (token: StyleDictionary.TransformedToken, options?: Platform) => {
const baseFont = getBasePxFontSize(options)
const floatVal = parseFloat(token.value)

if (isNaN(floatVal)) {
throw new Error(
`Invalid dimension token: '${token.name}: ${token.value}' is not valid and cannot be transform to 'float' \n`,
)
}

if (floatVal === 0) {
return 0
}

if (hasUnit(token.value, 'rem')) {
return floatVal * baseFont
}

if (hasUnit(token.value, 'px')) {
return floatVal
}

return token.value
},
}
1 change: 1 addition & 0 deletions src/transformers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export {colorToHexMix} from './colorToHexMix'
export {colorToRgbAlpha} from './colorToRgbAlpha'
export {colorToRgbaFloat} from './colorToRgbaFloat'
export {dimensionToRem} from './dimensionToRem'
export {dimensionToPixelUnitless} from './dimensionToPixelUnitless'
export {fontFamilyToCss} from './fontFamilyToCss'
export {fontWeightToNumber} from './fontWeightToNumber'
export {jsonDeprecated} from './jsonDeprecated'
Expand Down

0 comments on commit fedff7c

Please sign in to comment.