Skip to content

Commit f4386a1

Browse files
committed
generate css for modular size scale
1 parent ac01b24 commit f4386a1

File tree

9 files changed

+127
-46
lines changed

9 files changed

+127
-46
lines changed

apps/www/app/_components/tokens/design-tokens/size-mode.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
{
22
"medium": [
3+
{
4+
"path": [
5+
"font-scale",
6+
"_base"
7+
],
8+
"variable": "--ds-font-scale-base",
9+
"value": "1.125"
10+
},
11+
{
12+
"path": [
13+
"font-scale",
14+
"_ratio"
15+
],
16+
"variable": "--ds-font-scale-ratio",
17+
"value": "1.143"
18+
},
319
{
420
"path": [
521
"_size",
@@ -10,6 +26,22 @@
1026
}
1127
],
1228
"large": [
29+
{
30+
"path": [
31+
"font-scale",
32+
"_base"
33+
],
34+
"variable": "--ds-font-scale-base",
35+
"value": "1.3125"
36+
},
37+
{
38+
"path": [
39+
"font-scale",
40+
"_ratio"
41+
],
42+
"variable": "--ds-font-scale-ratio",
43+
"value": "1.146"
44+
},
1345
{
1446
"path": [
1547
"_size",
@@ -20,6 +52,22 @@
2052
}
2153
],
2254
"small": [
55+
{
56+
"path": [
57+
"font-scale",
58+
"_base"
59+
],
60+
"variable": "--ds-font-scale-base",
61+
"value": "1"
62+
},
63+
{
64+
"path": [
65+
"font-scale",
66+
"_ratio"
67+
],
68+
"variable": "--ds-font-scale-ratio",
69+
"value": "1.131"
70+
},
2371
{
2472
"path": [
2573
"_size",

apps/www/app/_components/tokens/design-tokens/type-scale.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,79 +5,79 @@
55
"1"
66
],
77
"variable": "--ds-font-size-1",
8-
"value": "round(calc(0.75rem * var(--_ds-font-size-factor)), 1px)"
8+
"value": "round(calc(1rem * var(--ds-font-scale-base) / pow(var(--ds-font-scale-ratio), 3)), 1px)"
99
},
1010
{
1111
"path": [
1212
"font-size",
1313
"2"
1414
],
1515
"variable": "--ds-font-size-2",
16-
"value": "round(calc(0.875rem * var(--_ds-font-size-factor)), 1px)"
16+
"value": "round(calc(1rem * var(--ds-font-scale-base) / pow(var(--ds-font-scale-ratio), 2)), 1px)"
1717
},
1818
{
1919
"path": [
2020
"font-size",
2121
"3"
2222
],
2323
"variable": "--ds-font-size-3",
24-
"value": "round(calc(1rem * var(--_ds-font-size-factor)), 1px)"
24+
"value": "round(calc(1rem * var(--ds-font-scale-base) / pow(var(--ds-font-scale-ratio), 1)), 1px)"
2525
},
2626
{
2727
"path": [
2828
"font-size",
2929
"4"
3030
],
3131
"variable": "--ds-font-size-4",
32-
"value": "round(calc(1.125rem * var(--_ds-font-size-factor)), 1px)"
32+
"value": "round(calc(1rem * var(--ds-font-scale-base) * pow(var(--ds-font-scale-ratio), 0)), 1px)"
3333
},
3434
{
3535
"path": [
3636
"font-size",
3737
"5"
3838
],
3939
"variable": "--ds-font-size-5",
40-
"value": "round(calc(1.3125rem * var(--_ds-font-size-factor)), 1px)"
40+
"value": "round(calc(1rem * var(--ds-font-scale-base) * pow(var(--ds-font-scale-ratio), 1)), 1px)"
4141
},
4242
{
4343
"path": [
4444
"font-size",
4545
"6"
4646
],
4747
"variable": "--ds-font-size-6",
48-
"value": "round(calc(1.5rem * var(--_ds-font-size-factor)), 1px)"
48+
"value": "round(calc(1rem * var(--ds-font-scale-base) * pow(var(--ds-font-scale-ratio), 2)), 1px)"
4949
},
5050
{
5151
"path": [
5252
"font-size",
5353
"7"
5454
],
5555
"variable": "--ds-font-size-7",
56-
"value": "round(calc(1.875rem * var(--_ds-font-size-factor)), 1px)"
56+
"value": "round(calc(1rem * var(--ds-font-scale-base) * pow(var(--ds-font-scale-ratio), 3)), 1px)"
5757
},
5858
{
5959
"path": [
6060
"font-size",
6161
"8"
6262
],
6363
"variable": "--ds-font-size-8",
64-
"value": "round(calc(2.25rem * var(--_ds-font-size-factor)), 1px)"
64+
"value": "round(calc(1rem * var(--ds-font-scale-base) * pow(var(--ds-font-scale-ratio), 5)), 1px)"
6565
},
6666
{
6767
"path": [
6868
"font-size",
6969
"9"
7070
],
7171
"variable": "--ds-font-size-9",
72-
"value": "round(calc(3rem * var(--_ds-font-size-factor)), 1px)"
72+
"value": "round(calc(1rem * var(--ds-font-scale-base) * pow(var(--ds-font-scale-ratio), 7)), 1px)"
7373
},
7474
{
7575
"path": [
7676
"font-size",
7777
"10"
7878
],
7979
"variable": "--ds-font-size-10",
80-
"value": "round(calc(3.75rem * var(--_ds-font-size-factor)), 1px)"
80+
"value": "round(calc(1rem * var(--ds-font-scale-base) * pow(var(--ds-font-scale-ratio), 9)), 1px)"
8181
},
8282
{
8383
"path": [

packages/cli/src/tokens/process/configs/semantic.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const semanticVariables: GetStyleDictionaryConfig = ({ theme }) => {
3030
const isUwantedToken = R.anyPass([R.includes('primitives/global')])(token.filePath);
3131
const isPrivateToken = R.includes('_', token.path);
3232
const unwantedPaths = pathStartsWithOneOf(
33-
['size', '_size', 'font-size', 'line-height', 'letter-spacing'],
33+
['size', '_size', 'font-scale', 'font-size', 'line-height', 'letter-spacing'],
3434
token,
3535
);
3636
const unwantedTypes = typeEquals(['color', 'fontWeight', 'fontFamily', 'typography'], token);

packages/cli/src/tokens/process/configs/size-mode.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as R from 'ramda';
2+
import { pathStartsWithOneOf } from '../../utils.js';
23
import { formats } from '../formats/css.js';
3-
44
import { basePxFontSize, dsTransformers, type GetStyleDictionaryConfig, prefix } from './shared.js';
55

66
export const sizeModeVariables: GetStyleDictionaryConfig = ({ theme, size }) => {
@@ -26,7 +26,7 @@ export const sizeModeVariables: GetStyleDictionaryConfig = ({ theme, size }) =>
2626
destination: `size-mode/${size}.css`,
2727
format: formats.sizeMode.name,
2828
filter: (token) => {
29-
return R.equals(['_size', 'mode-font-size'], token.path);
29+
return R.equals(['_size', 'mode-font-size'], token.path) || pathStartsWithOneOf(['font-scale'], token);
3030
},
3131
},
3232
],

packages/cli/src/tokens/process/configs/type-scale.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ export const typeScaleVariables: GetStyleDictionaryConfig = ({ theme }) => {
3333
destination: `type-scale.css`,
3434
format: formats.typeScale.name,
3535
filter: (token) => {
36-
const included = typeEquals(['typography', 'dimension', 'fontsize'], token);
36+
const included = typeEquals(['typography', 'dimension', 'fontsize', 'number'], token);
3737

3838
// Remove primitive typgography tokens
3939
if (/primitives\/modes\/typography\/(primary|secondary)/.test(token.filePath)) return false;
4040

4141
return (
4242
included &&
4343
!pathStartsWithOneOf(['spacing', 'sizing', 'size', 'border-width', 'border-radius'], token) &&
44-
(pathStartsWithOneOf(['font-size'], token) || token.path.includes('fontSize'))
44+
(pathStartsWithOneOf(['font-size', 'font-scale'], token) || token.path.includes('fontSize'))
4545
);
4646
},
4747
},

packages/cli/src/tokens/process/formats/css/size-mode.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ const formatBaseSizeToken =
1212
...token,
1313
originalName: token.name,
1414
name: `${token.name}--${shortSizeName(size)}`,
15-
$value: token.$value / basePxFontSize,
15+
$value: token.path.includes('_ratio') ? token.$value : token.$value / basePxFontSize,
16+
$description: undefined, // removes comment from output
1617
});
1718

1819
export const sizeMode: Format = {
@@ -57,6 +58,10 @@ export const sizeMode: Format = {
5758
${sizes.map((size) => ` --ds-size--${size}: var(--ds-size,);`).join('\n')}
5859
--ds-size-mode-font-size:
5960
${sizes.map((size) => ` var(--ds-size--${size}, var(--ds-size-mode-font-size--${size}))`).join('\n')};
61+
--ds-font-scale-base:
62+
${sizes.map((size) => ` var(--ds-size--${size}, var(--ds-font-scale-base--${size}))`).join('\n')};
63+
--ds-font-scale-ratio:
64+
${sizes.map((size) => ` var(--ds-size--${size}, var(--ds-font-scale-ratio--${size}))`).join('\n')};
6065
}`;
6166
const sizingHelpers = sizes
6267
.map((size) => `[data-size='${size}'] { --ds-size: var(--ds-size--${size}); }`)

packages/cli/src/tokens/process/formats/css/type-scale.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as R from 'ramda';
2-
import type { Format, TransformedToken } from 'style-dictionary/types';
2+
import type { Dictionary, Format, TransformedToken } from 'style-dictionary/types';
33
import { createPropertyFormatter } from 'style-dictionary/utils';
4-
import { basePxFontSize } from '../../configs/shared.js';
54
import { buildOptions } from '../../platform.js';
65
import { sizingTemplate } from './size.js';
76

@@ -10,29 +9,42 @@ const isTypographyFontFamilyToken = R.allPass([
109
R.pathSatisfies(R.includes('typography'), ['path']),
1110
R.pathSatisfies(R.includes('fontFamily'), ['path']),
1211
]);
12+
// Predicate to filter font-scale tokens
13+
const isFontScaleToken = R.pathSatisfies(R.includes('font-scale'), ['path']);
1314

1415
type TokensWithCalcAndRoundFormatting = { tokens: TransformedToken[]; calc: string[]; round: string[] };
1516

1617
const formatTypographySizeToken = (
18+
dictionary: Dictionary,
1719
format: (t: TransformedToken) => string,
1820
token: TransformedToken,
1921
): { name: string; calc: string; round: string } => {
2022
const [name, value] = format(token).replace(/;$/, '').split(': ');
23+
2124
let calc: string;
2225
let round: string | undefined;
2326
if (R.startsWith(['font-size'], token.path)) {
24-
calc = `calc(${value} * var(--_ds-font-size-factor))`;
27+
const originalWithCssReference = (token.original.$value as string).replaceAll(/\{font-scale\.[^}]+\}/g, (match) => {
28+
const t = dictionary.unfilteredTokenMap?.get(match);
29+
return `var(--${t?.name as string})`;
30+
});
31+
const cssCalcValue = originalWithCssReference.replace(/^roundTo\((.*), 0\)$/, '$1');
32+
calc = `calc(1rem * ${cssCalcValue})`;
2533
round = `round(${calc}, 1px)`;
2634
} else {
2735
calc = value;
2836
}
2937
return { name, calc, round: round ?? calc };
3038
};
3139

32-
const formatTypographySizeTokens = (format: (t: TransformedToken) => string, tokens: TransformedToken[]) =>
40+
const formatTypographySizeTokens = (
41+
dictionary: Dictionary,
42+
format: (t: TransformedToken) => string,
43+
tokens: TransformedToken[],
44+
) =>
3345
R.reduce<TransformedToken, TokensWithCalcAndRoundFormatting>(
3446
(acc, token) => {
35-
const { name, calc, round } = formatTypographySizeToken(format, token);
47+
const { name, calc, round } = formatTypographySizeToken(dictionary, format, token);
3648
acc.tokens.push(token);
3749
acc.calc.push(`${name}: ${calc};`);
3850
acc.round.push(`${name}: ${round};`);
@@ -56,8 +68,8 @@ export const typeScale: Format = {
5668
usesDtcg,
5769
});
5870

59-
const filteredTokens = R.reject(R.anyPass([isTypographyFontFamilyToken]), dictionary.allTokens);
60-
const formattedTokens = formatTypographySizeTokens(format, filteredTokens);
71+
const filteredTokens = R.reject(R.anyPass([isTypographyFontFamilyToken, isFontScaleToken]), dictionary.allTokens);
72+
const formattedTokens = formatTypographySizeTokens(dictionary, format, filteredTokens);
6173

6274
const formattedMap = formattedTokens.round.map((t, i) => ({
6375
token: formattedTokens.tokens[i],
@@ -66,8 +78,7 @@ export const typeScale: Format = {
6678

6779
buildOptions.buildTokenFormats[destination] = formattedMap;
6880

69-
const sizeFactor = ` --_ds-font-size-factor: calc(var(--ds-size-mode-font-size) / (var(--ds-size-base) / ${basePxFontSize}));`;
70-
const content = `${selector} {\n${sizeFactor}${sizingTemplate(formattedTokens)}\n}`;
81+
const content = `${selector} {${sizingTemplate(formattedTokens)}\n}`;
7182
const body = R.isNotNil(layer) ? `@layer ${layer} {\n${content}\n}` : content;
7283

7384
return body;

packages/css/src/data-size-workaround.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ the component to scale based on the surrounding data-size.
1010
/* Hack: Preserve --ds-size-mode-font-size on ancestor so we can look it up at the descendant */
1111
[data-size]:not(.ds-avatar, .ds-heading, .ds-paragraph, .ds-spinner) {
1212
--_ds-size-mode__hack: var(--ds-size-mode-font-size);
13+
--_ds-font-scale-base__hack: var(--ds-font-scale-base);
14+
--_ds-font-scale-ratio__hack: var(--ds-font-scale-ratio);
1315
}
1416
/* Hack: use the nearest ancestor size mode */
1517
[data-size] :is(.ds-avatar, .ds-heading, .ds-paragraph, .ds-spinner) {
1618
--ds-size-mode-font-size: var(--_ds-size-mode__hack);
19+
--ds-font-scale-base: var(--_ds-font-scale-base__hack);
20+
--ds-font-scale-ratio: var(--_ds-font-scale-ratio__hack);
1721
}

0 commit comments

Comments
 (0)