Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Add atomic font tokens #540

Merged
merged 11 commits into from
Oct 21, 2024
217 changes: 154 additions & 63 deletions packages/tokens/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ const stripModeReducer = (result, token) => {
return result
}

/** Filter function to return tokens of category 'font', type from filter, and npm true */
const fontFilter = (token, fontType) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, but suggest we follow the filterX naming pattern and group with the other filters above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

const { category, type, npm } = token.attributes

return category === 'font' && type === fontType && npm === true
}

/**
* Filters
*/
Expand All @@ -53,6 +60,37 @@ StyleDictionary.registerFilter({
matcher: (token) => token.attributes.category.includes('color'),
})

/** Filter to tokens of category 'font', type 'family', and npm true */
StyleDictionary.registerFilter({
name: 'filter/font/family-npm',
matcher: (token) => fontFilter(token, 'family'),
})

/** Filter to tokens of category 'font', type 'letterSpacing', and npm true */
StyleDictionary.registerFilter({
name: 'filter/font/letterSpacing-npm',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest we stick to kebab case instead of mixing camel and kebab

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Was naming it this way for the source file name, but looking at it holistically using the type name (kebab to follow the raw token name) probably makes more sense.

matcher: (token) => fontFilter(token, 'letter-spacing'),
})

/** Filter to tokens of category 'font', type 'size', and npm true */
StyleDictionary.registerFilter({
name: 'filter/font/size-npm',
matcher: (token) => fontFilter(token, 'size'),
})

/** Filter to tokens of category 'font', type 'line-height', and npm true */
StyleDictionary.registerFilter({
name: 'filter/font/lineHeight-npm',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

matcher: (token) => fontFilter(token, 'line-height'),
})

/** Remove tokens that do not have 'font' in the category and have figma attribute */
StyleDictionary.registerFilter({
name: 'filter/font-figma',
matcher: (token) =>
token.attributes.category === 'font' && token.attributes.figma === true,
})

/** Remove tokens that have the dark mode (OnDark/-on-dark) suffix */
StyleDictionary.registerFilter({
name: 'filter/color/light-mode',
Expand All @@ -75,16 +113,22 @@ StyleDictionary.registerFilter({
* Formats
*/

/** Custom format for colors. Exports all color tokens as single object */
/** Custom format for basic named export of simple key:value token pairs */
StyleDictionary.registerFormat({
name: 'javascript/es6/vads-colors',
formatter: function (dictionary) {
const colorTokens = dictionary.allProperties.reduce((result, token) => {
name: 'javascript/es6/simple-key-value',
formatter: function ({ dictionary, options }) {
const tokens = dictionary.allProperties.reduce((result, token) => {
result[token.name] = token.value
return result
}, {})

return `export const colors = ${JSON.stringify(sortTokensByKey(colorTokens), null, 2)};`
const exportName = options.exportName

if (options.noSort) {
return `export const ${exportName} = ${JSON.stringify(tokens, null, 2)};`
}

return `export const ${exportName} = ${JSON.stringify(sortTokensByKey(tokens), null, 2)};`
},
})

Expand Down Expand Up @@ -114,43 +158,94 @@ StyleDictionary.registerFormat({
StyleDictionary.registerFormat({
name: 'javascript/es6/vads-module-export',
formatter: function () {
return (
"export { colors } from './colors'\n" +
"export { themes } from './themes'\n" +
"export { spacing } from './spacing'"
)
const files = ['colors', 'font', 'spacing', 'themes']
let exports = ''
for (const file of files) exports += `export { ${file} } from './${file}'\n`

return exports
},
})

/** Creates named type declaration for colors. Allows for TypeScript autocomplete */
/** Custom format to generate font/index.js with exports */
StyleDictionary.registerFormat({
name: 'typescript/es6-declarations/colors',
formatter: function (dictionary) {
const sortedTokens = sortTokensByName(dictionary.allTokens)
let declaration = 'export declare const colors: {\n'
sortedTokens.forEach((token) => {
declaration += ` /** ${token.value} */\n`
declaration += ` ${token.name}: string;\n`
})
declaration += '}'
return declaration
name: 'javascript/es6/fontIndex',
formatter: function () {
const files = ['family', 'letterSpacing', 'lineHeight', 'size']
let imports = '',
exports = ''

for (const file of files) imports += `import { ${file} } from './${file}'\n`
exports += 'export const font = {\n'
for (const file of files) exports += `${file},\n`

return `${imports}\n${exports}}`
},
})

/** Creates named type declaration for spacing. Allows for TypeScript autocomplete */
/** Custom format to generate font/index.d.ts with exports */
StyleDictionary.registerFormat({
name: 'typescript/es6-declarations/spacing',
formatter: function (dictionary) {
let declaration = 'export declare const spacing: {\n'
let allValuesComment = '/**\n * '
dictionary.allProperties.forEach((token, index) => {
declaration += ` /** Value: ${token.value} */\n`
declaration += ` ${token.name}: number;\n`
allValuesComment += `${index !== 0 ? ' | ' : ''}${token.name.replace('vadsSpace', '')}: ${token.value}`
})
name: 'typescript/es6-declarations/fontIndex',
formatter: function () {
const files = ['family', 'letterSpacing', 'lineHeight', 'size']
let imports = '',
exports = ''

for (const file of files) imports += `import { ${file} } from './${file}'\n`
exports += 'export declare const font: {\n'
for (const file of files) exports += `${file}: typeof ${file},\n`

return `${imports}\n${exports}}`
},
})

/** Formats basic key-value type declarations exports */
StyleDictionary.registerFormat({
name: 'typescript/es6-declarations/simple-key-value',
formatter: function ({ dictionary, options }) {
const tokenTyping = options.tokenTyping || 'number'
let tokens = dictionary.allTokens,
declaration = '',
globalValuesDoc = '/**\n',
docLine = ' * '

if (!options.noSort) {
tokens = sortTokensByName(tokens)
}

if (options.noGlobalDoc) {
globalValuesDoc = ''
} else {
// Add global values doc to the top of the file
for (const token of tokens) {
let tokenDoc = ''
// Shorten token names:
const shortName = token.name
.replace('vads', '')
.replace('FontFamily', '')
.replace('FontLetterSpacing', '')
.replace('FontLineHeight', '')
.replace('FontSize', '')
.replace('Space', '')

tokenDoc = `${shortName}: \`${token.value}\``
tokenDoc += token === tokens[tokens.length - 1] ? '' : ' | ' // Add | if not last token

if (docLine.length + tokenDoc.length > 120) {
globalValuesDoc += docLine + '\n'
docLine = ' * '
}
docLine += tokenDoc
}
globalValuesDoc += docLine + '\n */\n'
}

declaration += `export declare const ${options.exportName}: {\n`
for (const token of dictionary.allTokens) {
declaration += ` /** Value: \`${token.value}\` */\n`
declaration += ` ${token.name}: ${tokenTyping};\n`
}
declaration += '}'
allValuesComment += '\n */\n'
return allValuesComment + declaration
return globalValuesDoc + declaration
},
})

Expand Down Expand Up @@ -179,11 +274,11 @@ StyleDictionary.registerFormat({
StyleDictionary.registerFormat({
name: 'typescript/es6-declarations/module',
formatter: function () {
let declaration = "export * from './types/theme'\n"
declaration += "export * from './types/colors'\n"
declaration += "export * from './types/spacing'"
const files = ['colors', 'font', 'spacing', 'themes']
let exports = ''
for (const file of files) exports += `export * from './types/${file}'\n`

return declaration
return exports
},
})

Expand All @@ -210,19 +305,27 @@ StyleDictionary.registerFormat({

if (category.includes('color')) {
return 'color'
} else if (category === 'units') {
return 'dimension'
} else if (category === 'font' && type === 'family') {
return 'fontFamily'
} else if (category === 'font' && type === 'weight') {
return 'fontWeight'
} else if (category === 'font' && type === 'size') {
return 'dimension'
} else if (category === 'spacing') {
return 'number'
}

return ''
switch (category) {
case 'font':
switch (type) {
case 'family':
case 'style':
return 'string'
case 'letter-spacing':
case 'size':
case 'line-height':
case 'paragraph-spacing':
return 'number'
default:
return ''
}
case 'spacing':
return 'number'
default:
return ''
}
}

// Format tokens for dtcg
Expand All @@ -237,28 +340,16 @@ StyleDictionary.registerFormat({
{},
)

// Leave spacing tokens sorted by size
if (dictionary.allTokens?.[0].attributes?.category === 'spacing') {
const category = dictionary.allTokens?.[0].attributes?.category
// Leave spacing and font tokens sorted by source (size)
if (category === 'spacing' || category === 'font') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth adding a noSort option here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, did Figma first and didn't figure out the options stuff until later. Updated.

return JSON.stringify(tokens, undefined, 2) + `\n`
}

return JSON.stringify(sortTokensByKey(tokens), undefined, 2) + `\n`
},
})

/** Custom format for spacing. Exports all spacing tokens as single object */
StyleDictionary.registerFormat({
name: 'javascript/es6/vads-spacing',
formatter: function (dictionary) {
const tokens = dictionary.allProperties.reduce((result, token) => {
result[token.name] = token.value
return result
}, {})

return `export const spacing = ${JSON.stringify(tokens, null, 2)};`
},
})

/**
* Transform Groups
*/
Expand Down
Loading
Loading