Skip to content

Commit

Permalink
chore: 👷 Support for fluid typography in tokens (#357)
Browse files Browse the repository at this point in the history
  • Loading branch information
mimarz authored May 8, 2023
1 parent 78f1d35 commit 329d405
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 31 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Built files
dist
ignore

# Yarn stuff; we're not using PnP/Zero installs
.pnp.*
Expand Down
137 changes: 106 additions & 31 deletions packages/tokens/build.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { noCase } from 'change-case';
import StyleDictionary from 'style-dictionary';
import type { Config, TransformedToken } from 'style-dictionary';
import type {
Config,
TransformedToken,
TransformedTokens,
} from 'style-dictionary';
import { registerTransforms } from '@tokens-studio/sd-transforms';

void registerTransforms(StyleDictionary);
Expand All @@ -9,10 +13,8 @@ type Brands = 'Altinn' | 'Digdir' | 'Tilsynet';
const brands: Brands[] = ['Digdir', 'Tilsynet', 'Altinn'];
const prefix = 'fds';
const basePxFontSize = 16;
/**
* Transforms `level1.level2.another_level` to `level1-level2-another_level`
* This maintains hierarchy distinction (i.e. underscore is not a hierarchy level separator)
*/
let fontScale: TransformedTokens;

StyleDictionary.registerTransform({
name: 'name/cti/hierarchical-kebab',
type: 'name',
Expand All @@ -24,9 +26,20 @@ StyleDictionary.registerTransform({
},
});

StyleDictionary.registerTransform({
name: 'name/cti/camel_underscore',
type: 'name',
transformer: function (token, options) {
return noCase([options?.prefix].concat(token.path).join(' '), {
delimiter: '_',
stripRegexp: /[^A-Z0-9_]+/gi,
});
},
});

type Typgraphy = {
fontWeight: string;
fontSize: number;
fontSize: string;
lineHeight: number;
fontFamily: string;
};
Expand All @@ -37,10 +50,62 @@ StyleDictionary.registerTransform({
transitive: true,
matcher: (token) => token.type === 'typography',
transformer: (token, options) => {
const value = token.value as Typgraphy;
const divider = options?.basePxFontSize || 1;
const remValue = value.fontSize / divider;
return `${value.fontWeight} ${remValue}rem/${value.lineHeight} '${value.fontFamily}'`;
const typography = token.value as Typgraphy;
let fontSize = typography.fontSize;

if (!fontSize.startsWith('clamp')) {
const baseFontPx = options?.basePxFontSize || 1;
fontSize = `${parseFloat(fontSize) / baseFontPx}rem`;
}
return `${typography.fontWeight} ${fontSize}/${typography.lineHeight} '${typography.fontFamily}'`;
},
});

type FontScale = {
min: TransformedToken;
max: TransformedToken;
v: TransformedToken;
r: TransformedToken;
fluid: TransformedToken;
};

StyleDictionary.registerTransform({
name: 'fontSizes/fluid',
type: 'value',
transitive: true,
matcher: (token) =>
token.type === 'fontSizes' &&
token.path[0] === 'font-size' &&
token.path[1].startsWith('f'),
transformer: (token, options) => {
if (fontScale) {
const baseFontPx = options?.basePxFontSize || 1;

const scale = fontScale[token.path[1]] as unknown as FontScale;

const { min, max, v, r } = scale;
const minRem = (parseFloat(min.value as string) / baseFontPx).toFixed(2);
const maxRem = (parseFloat(max.value as string) / baseFontPx).toFixed(2);
const fontR = (parseFloat(r.value as string) / baseFontPx).toFixed(2);
const fontV = parseFloat(v.value as string).toFixed(2);

const fluid = `clamp(${minRem}rem, calc(${fontV}vw + ${fontR}rem), ${maxRem}rem)`;

return fluid;
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return token.value;
},
});

StyleDictionary.registerFormat({
name: 'global-values-hack',
formatter: ({ dictionary }) => {
console.info('\x1b[34m✔ Setting global values');
fontScale = dictionary.tokens['font-scale'];

return `/** Style Dictionary hack because it must write to file for some reason... */\n`;
},
});

Expand All @@ -54,63 +119,73 @@ const getStyleDictionaryConfig = (
const tokensPath = '../../design-tokens';
const destinationPath = `${targetFolder}/${brand.toLowerCase()}`;

return {
const config: Config = {
include: [
`${tokensPath}/Brand/${brand}.json`,
`${tokensPath}/Base/Semantic.json`,
],
source: [`${tokensPath}/Base/Core.json`],
platforms: {
js: {
css: {
prefix,
basePxFontSize,
transformGroup: 'css',
transforms: [
'ts/resolveMath',
'name/cti/camel',
'name/cti/hierarchical-kebab',
'fontSizes/fluid',
'typography/shorthand',
'ts/resolveMath',
'ts/size/lineheight',
'ts/shadow/css/shorthand',
],
transformGroup: 'js',
files: [
{
destination: `${destinationPath}/tokens.cjs.js`,
format: 'javascript/module-flat',
filter: excludeSource,
format: 'global-values-hack',
destination: 'ignore/hack',
},
{
destination: `${destinationPath}/tokens.esm.js`,
format: 'javascript/es6',
filter: excludeSource,
},
{
destination: `${destinationPath}/tokens.d.ts`,
format: 'typescript/es6-declarations',
destination: `${destinationPath}/tokens.css`,
format: 'css/variables',
filter: excludeSource,
},
],
options: {
// outputReferences: true,
},
},
css: {
prefix,
js: {
basePxFontSize,
transformGroup: 'js',
transforms: [
'ts/resolveMath',
'name/cti/hierarchical-kebab',
'name/cti/camel_underscore',
'fontSizes/fluid',
'typography/shorthand',
'ts/resolveMath',
'ts/size/lineheight',
'ts/shadow/css/shorthand',
],
files: [
{
destination: `${destinationPath}/tokens.css`,
format: 'css/variables',
destination: `${destinationPath}/tokens.cjs.js`,
format: 'javascript/module-flat',
filter: excludeSource,
},
{
destination: `${destinationPath}/tokens.esm.js`,
format: 'javascript/es6',
filter: excludeSource,
},
{
destination: `${destinationPath}/tokens.d.ts`,
format: 'typescript/es6-declarations',
filter: excludeSource,
},
],
},
},
};

return config;
};

console.log('Build started...');
Expand Down

0 comments on commit 329d405

Please sign in to comment.