Skip to content

Commit bb31026

Browse files
authored
Merge branch 'main' into rezrah/backfill-esm-tokens-control
2 parents cf3aa21 + 414e53f commit bb31026

5 files changed

Lines changed: 160 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/brand-primitives': patch
3+
---
4+
5+
Added JSON-based typography and size map exports at `@primer/brand-primitives/lib/design-tokens/json/typography.json` and `@primer/brand-primitives/lib/design-tokens/json/size.json`.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react-brand': patch
3+
---
4+
5+
Added JSON-based typography and size map exports at `@primer/react-brand/lib/design-tokens/json/typography.json` and `@primer/react-brand/lib/design-tokens/json/size.json`.

packages/design-tokens/scripts/build-tokens.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const mediaQueryFormat = require('../src/formats/responsive-media-query')
66
const colorModeFormat = require('../src/formats/color-mode-attributes')
77
const oneDimensionalFormat = require('../src/formats/json-one-dimensional')
88
const isColorValue = require('../src/filters/isColorValue')
9+
const isSizeValue = require('../src/filters/isSizeValue')
910

1011
const lightJson = require('../src/tokens/base/colors/light')
1112
const darkJson = require('../src/tokens/base/colors/dark')
@@ -339,6 +340,57 @@ const darkJson = require('../src/tokens/base/colors/dark')
339340
},
340341
})
341342

343+
/**
344+
* Build a flat JSON map of global typography tokens.
345+
*/
346+
buildPrimitives({
347+
source: [`tokens/base/typography/typography.json`, `tokens/functional/typography/typography-responsive.json`],
348+
namespace,
349+
platforms: {
350+
jsonTypography: {
351+
prefix: namespace,
352+
addPrefix: token => token.isSource && !token.filePath.replace(/\\/g, '/').includes('/base/typography/'),
353+
buildPath: `${outputPath}/json/`,
354+
transformGroup: 'css',
355+
files: [
356+
{
357+
destination: `typography.json`,
358+
format: `json/one-dimensional`,
359+
filter: token => token.isSource,
360+
},
361+
],
362+
},
363+
},
364+
})
365+
366+
/**
367+
* Build a flat JSON map of global size tokens.
368+
*/
369+
buildPrimitives({
370+
source: [
371+
`tokens/base/size/size.json`,
372+
`tokens/functional/size/size.json`,
373+
`tokens/functional/size/breakpoints.json`,
374+
`tokens/functional/size/border.json`,
375+
],
376+
namespace,
377+
platforms: {
378+
jsonSize: {
379+
prefix: namespace,
380+
addPrefix: token => token.isSource && !token.filePath.replace(/\\/g, '/').includes('/base/size/'),
381+
buildPath: `${outputPath}/json/`,
382+
transformGroup: 'css',
383+
files: [
384+
{
385+
destination: `size.json`,
386+
format: `json/one-dimensional`,
387+
filter: token => token.isSource && isSizeValue(token.value),
388+
},
389+
],
390+
},
391+
},
392+
})
393+
342394
/**
343395
* Step 4:
344396
* Clean up the temporary directory
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* @description Check whether a token value can be used as a CSS size.
3+
*
4+
* @param {string} value the token's resolved value
5+
* @returns {boolean} `true` when the value is size-shaped
6+
*/
7+
const SIZE_FUNCTION_PREFIXES = ['max(', 'min(', 'clamp(', 'calc(']
8+
const LENGTH_VALUE = /^-?(\d+\.?\d*|\.\d+)(px|rem|em|vh|vw|vmin|vmax|ch)$/
9+
10+
// TODO: Use isDimension from @primer/primitives once all size tokens include $type metadata.
11+
const isSizeValue = value => {
12+
if (typeof value !== 'string') return false
13+
14+
const normalized = value.trim().toLowerCase()
15+
16+
if (normalized === '') return false
17+
18+
if (normalized.startsWith('(')) return false
19+
if (normalized.startsWith('inset')) return false
20+
if (normalized.includes('cubic-bezier')) return false
21+
if (/^-?(\d+\.?\d*|\.\d+)(ms|s)$/.test(normalized)) return false
22+
23+
if (normalized.startsWith('var(')) return false
24+
25+
if (SIZE_FUNCTION_PREFIXES.some(prefix => normalized.startsWith(prefix))) return true
26+
27+
return LENGTH_VALUE.test(normalized)
28+
}
29+
30+
module.exports = isSizeValue
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
const {describe, it, expect} = require('@jest/globals')
2+
const isSizeValue = require('./isSizeValue')
3+
4+
describe('isSizeValue', () => {
5+
it('keeps bare length values', () => {
6+
expect(isSizeValue('2px')).toBe(true)
7+
expect(isSizeValue('0.125rem')).toBe(true)
8+
expect(isSizeValue('624.9375rem')).toBe(true)
9+
expect(isSizeValue('-0.035em')).toBe(true)
10+
expect(isSizeValue('20rem')).toBe(true)
11+
})
12+
13+
it('keeps viewport length units', () => {
14+
expect(isSizeValue('100vh')).toBe(true)
15+
expect(isSizeValue('50vw')).toBe(true)
16+
expect(isSizeValue('2ch')).toBe(true)
17+
})
18+
19+
it('keeps math functions', () => {
20+
expect(isSizeValue('max(1px, 0.0625rem)')).toBe(true)
21+
expect(isSizeValue('min(2px, 0.125rem)')).toBe(true)
22+
expect(isSizeValue('clamp(1rem, 2vw, 3rem)')).toBe(true)
23+
expect(isSizeValue('calc(48rem - 0.02px)')).toBe(true)
24+
})
25+
26+
it('excludes unresolved var() references', () => {
27+
expect(isSizeValue('var(--base-size-16)')).toBe(false)
28+
expect(isSizeValue('var(--brand-borderWidth-thin)')).toBe(false)
29+
expect(isSizeValue('var(--brand-animation-easing-glide)')).toBe(false)
30+
expect(isSizeValue('var(--brand-animation-duration-default)')).toBe(false)
31+
})
32+
33+
it('excludes color values', () => {
34+
expect(isSizeValue('#000000')).toBe(false)
35+
expect(isSizeValue('rgb(0, 0, 0)')).toBe(false)
36+
expect(isSizeValue('var(--brand-color-text-default)')).toBe(false)
37+
})
38+
39+
it('excludes time values', () => {
40+
expect(isSizeValue('80ms')).toBe(false)
41+
expect(isSizeValue('0.6s')).toBe(false)
42+
})
43+
44+
it('excludes easing functions', () => {
45+
expect(isSizeValue('cubic-bezier(0.16, 1, 0.3, 1)')).toBe(false)
46+
})
47+
48+
it('excludes inset composites', () => {
49+
expect(isSizeValue('inset 0 0 0 var(--brand-borderWidth-thin)')).toBe(false)
50+
})
51+
52+
it('excludes media-query ranges', () => {
53+
expect(isSizeValue('(max-width: calc(48rem - 0.02px))')).toBe(false)
54+
expect(isSizeValue('(orientation: portrait)')).toBe(false)
55+
})
56+
57+
it('excludes unitless and keyword values', () => {
58+
expect(isSizeValue('0')).toBe(false)
59+
expect(isSizeValue('1.5')).toBe(false)
60+
expect(isSizeValue('none')).toBe(false)
61+
})
62+
63+
it('excludes non-string values', () => {
64+
expect(isSizeValue(undefined)).toBe(false)
65+
expect(isSizeValue(null)).toBe(false)
66+
expect(isSizeValue(4)).toBe(false)
67+
})
68+
})

0 commit comments

Comments
 (0)