Skip to content

Commit 1fbb968

Browse files
mimarzCopilot
andauthored
chore: refactor tokenSets constants (#4752)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 05e842f commit 1fbb968

10 files changed

Lines changed: 118 additions & 72 deletions

File tree

.changeset/warm-streets-clap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

packages/cli/bin/designsystemet.ts

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import { convertToHex } from '../src/colors/index.js';
77
import type { CssColor } from '../src/colors/types.js';
88
import migrations from '../src/migrations/index.js';
99
import { buildTokens } from '../src/tokens/build.js';
10-
import { createTokenFiles } from '../src/tokens/create/files.js';
11-
import { cliOptions, createTokens } from '../src/tokens/create.js';
10+
import { createSystemTokenFiles, tokenSetsToFiles } from '../src/tokens/create/files.js';
11+
import { cliOptions, createTokens, tokenSetDimensions } from '../src/tokens/create.js';
1212
import { generateConfigFromTokens } from '../src/tokens/generate-config.js';
1313
import type { OutputFile, Theme } from '../src/tokens/types.js';
14+
import { colorNamesByCategory } from '../src/tokens/utils.js';
1415
import { dsfs } from '../src/utils/filesystem.js';
1516
import { parseCreateConfig, readConfigFile } from './config.js';
1617

@@ -124,21 +125,29 @@ function makeTokenCommands() {
124125

125126
const outDir = dsfs.outDir;
126127

127-
if (config.clean) {
128-
await dsfs.cleanDir(outDir);
128+
const files: OutputFile[] = [];
129+
130+
for (const [name, themeConfig] of Object.entries(config.themes)) {
131+
const { tokenSets } = await createTokens({ name, ...themeConfig } as Theme);
132+
files.push(...tokenSetsToFiles(tokenSets));
129133
}
130134

131-
let files: OutputFile[] = [];
132-
if (config.themes) {
133-
for (const [name, themeWithoutName] of Object.entries(config.themes)) {
134-
// Casting as missing properties should be validated by `getDefaultOrExplicitOption` to default values
135-
const theme = { name, ...themeWithoutName } as Theme;
135+
// Pick colors from first theme since we have a constraint they should be the same across themes.
136+
const colors = config.themes?.[themeNames[0]]?.colors ?? { main: {}, support: {} };
136137

137-
const { tokenSets } = await createTokens(theme);
138-
files = files.concat(await createTokenFiles({ outDir, theme, tokenSets, themeNames }));
139-
}
138+
files.push(
139+
...(await createSystemTokenFiles({
140+
tokenSetDimensions,
141+
themeNames,
142+
colors: colorNamesByCategory(colors),
143+
})),
144+
);
145+
146+
if (config.clean) {
147+
await dsfs.cleanDir(outDir);
140148
}
141149

150+
await dsfs.mkdir(outDir);
142151
await dsfs.writeFiles(files, outDir);
143152

144153
console.log(`\n✅ Finished creating tokens in ${pc.green(outDir)} for themes: ${pc.blue(themeNames.join(', '))}`);

packages/cli/src/scripts/update-preview-tokens.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import pc from 'picocolors';
22
import type { TransformedToken } from 'style-dictionary/types';
33
import config from './../../../../designsystemet.config.json' with { type: 'json' };
44
import { generate$Themes } from '../tokens/create/generators/$themes.js';
5-
import { createTokens } from '../tokens/create.js';
5+
import { createTokens, tokenSetDimensions } from '../tokens/create.js';
66
import { buildOptions, processPlatform } from '../tokens/process/platform.js';
77
import { processThemeObject } from '../tokens/process/utils/getMultidimensionalThemes.js';
8-
import type { SizeModes, Theme } from '../tokens/types.js';
8+
import type { Theme } from '../tokens/types.js';
9+
import { colorNamesByCategory } from '../tokens/utils.js';
910
import { dsfs } from '../utils/filesystem.js';
1011

1112
const OUTDIR = '../../internal/components/src/tokens/design-tokens';
@@ -26,9 +27,10 @@ type PreviewToken = { variable: string; value: string };
2627
export const formatTheme = async (themeConfig: Theme) => {
2728
const { tokenSets } = await createTokens(themeConfig);
2829

29-
const sizeModes: SizeModes[] = ['small', 'medium', 'large'];
30+
const themeNames = [themeConfig.name];
31+
const colors = colorNamesByCategory(themeConfig.colors);
32+
const $themes = await generate$Themes(tokenSetDimensions, themeNames, colors);
3033

31-
const $themes = await generate$Themes(['dark', 'light'], [themeConfig.name], themeConfig.colors, sizeModes);
3234
const processed$themes = $themes.map(processThemeObject);
3335

3436
// We run this to populate the `buildOptions.buildTokenFormats` with transformed tokens

packages/cli/src/tokens/create.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { ColorScheme } from '../colors/types.js';
21
import { generateColorScheme } from './create/generators/primitives/color-scheme.js';
32
import { generateGlobals } from './create/generators/primitives/globals.js';
43
import { generateSize, generateSizeGlobal } from './create/generators/primitives/size.js';
@@ -7,7 +6,12 @@ import { generateSemanticColors } from './create/generators/semantic/color.js';
76
import { generateColorModes } from './create/generators/semantic/color-modes.js';
87
import { generateSemanticStyle } from './create/generators/semantic/style.js';
98
import { generateTheme } from './create/generators/themes/theme.js';
10-
import type { SizeModes, Theme, TokenSet, TokenSets } from './types.js';
9+
import type { Theme, TokenSet, TokenSetDimensions, TokenSets } from './types.js';
10+
11+
export const tokenSetDimensions: TokenSetDimensions = {
12+
colorSchemes: ['dark', 'light'],
13+
sizeModes: ['small', 'medium', 'large'],
14+
};
1115

1216
export const cliOptions = {
1317
outDir: 'out-dir',
@@ -28,8 +32,7 @@ export const cliOptions = {
2832

2933
export const createTokens = async (theme: Theme) => {
3034
const { colors, typography, name, borderRadius, overrides } = theme;
31-
const colorSchemes: ColorScheme[] = ['light', 'dark'];
32-
const sizeModes: SizeModes[] = ['small', 'medium', 'large'];
35+
const { colorSchemes, sizeModes } = tokenSetDimensions;
3336

3437
const tokenSets: TokenSets = new Map([
3538
['primitives/globals', generateGlobals()],
Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,46 @@
1-
import { dsfs } from '../../utils/filesystem.js';
2-
import type { OutputFile, SizeModes, Theme, TokenSets } from '../types.js';
1+
import type { ColorNamesByCategory, OutputFile, TokenSetDimensions, TokenSets } from '../types.js';
32
import { generate$Designsystemet } from './generators/$designsystemet.js';
43
import { generate$Metadata } from './generators/$metadata.js';
54
import { generate$Themes } from './generators/$themes.js';
65

76
export const stringify = (data: unknown) => JSON.stringify(data, null, 2);
87

98
type CreateTokenFilesOptions = {
10-
outDir: string;
11-
theme: Theme;
12-
tokenSets: TokenSets;
9+
tokenSetDimensions: TokenSetDimensions;
10+
colors: ColorNamesByCategory;
1311
themeNames: string[];
1412
};
1513

16-
export const createTokenFiles = async (options: CreateTokenFilesOptions) => {
17-
const {
18-
outDir,
19-
tokenSets,
20-
theme: { colors },
21-
themeNames,
22-
} = options;
14+
/**
15+
* Creates system token files (`$themes.json`, `$metadata.json`, `$designsystemet.jsonc`) based on the provided token set dimensions and theme names.
16+
*
17+
* `$themes.json` and `$metadata.json` are essential for Token Studio and Style Dictionary to correctly interpret and manage the design tokens.
18+
*/
19+
export const createSystemTokenFiles = async (options: CreateTokenFilesOptions) => {
20+
const { colors, themeNames, tokenSetDimensions } = options;
2321

22+
const files: OutputFile[] = [];
2423
const $themesPath = '$themes.json';
2524
const $metadataPath = '$metadata.json';
2625
const $designsystemetPath = '$designsystemet.jsonc';
27-
// let themeObjects: ThemeObject[] = [];
28-
const sizeModes: SizeModes[] = ['small', 'medium', 'large'];
29-
30-
await dsfs.mkdir(outDir);
3126

32-
// Create metadata and themes json for Token Studio and build script
33-
const $themes = await generate$Themes(['dark', 'light'], themeNames, colors, sizeModes);
34-
const $metadata = generate$Metadata(['dark', 'light'], themeNames, colors, sizeModes);
27+
const $themes = await generate$Themes(tokenSetDimensions, themeNames, colors);
28+
const $metadata = generate$Metadata(tokenSetDimensions, themeNames, colors);
3529
const $designsystemet = generate$Designsystemet();
3630

37-
const files: OutputFile[] = [];
38-
3931
files.push({ destination: $themesPath, output: stringify($themes) });
4032
files.push({ destination: $metadataPath, output: stringify($metadata) });
4133
files.push({ destination: $designsystemetPath, output: stringify($designsystemet) });
4234

35+
return files;
36+
};
37+
38+
export const tokenSetsToFiles = (tokenSets: TokenSets): OutputFile[] => {
39+
const files: OutputFile[] = [];
40+
4341
for (const [set, tokens] of tokenSets) {
4442
const filePath = `${set}.json`;
4543
files.push({ destination: filePath, output: stringify(tokens) });
4644
}
47-
4845
return files;
4946
};

packages/cli/src/tokens/create/generators/$metadata.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,35 @@
1-
import type { ColorScheme } from '../../../colors/types.js';
2-
import type { Colors, SizeModes } from '../../types.js';
1+
import type { ColorNamesByCategory, TokenSetDimensions } from '../../types.js';
32

43
type Metadata = {
54
tokenSetOrder: string[];
65
};
76

7+
/**
8+
* Generates metadata for the given token set dimensions, theme names, and colors.
9+
*
10+
* This is used to order tokens in Token Studio
11+
*/
812
export function generate$Metadata(
9-
schemes: ColorScheme[],
10-
themes: string[],
11-
colors: Colors,
12-
sizeModes: SizeModes[],
13+
tokenSetDimensions: TokenSetDimensions,
14+
themeNames: string[],
15+
colors: ColorNamesByCategory,
1316
): Metadata {
17+
const { colorSchemes, sizeModes } = tokenSetDimensions;
1418
return {
1519
tokenSetOrder: [
1620
'primitives/globals',
1721
...sizeModes.map((size) => `primitives/modes/size/${size}`),
1822
'primitives/modes/size/global',
1923
...sizeModes.map((size) => `primitives/modes/typography/size/${size}`),
20-
...themes.map((theme) => `primitives/modes/typography/primary/${theme}`),
21-
...themes.map((theme) => `primitives/modes/typography/secondary/${theme}`),
22-
...schemes.flatMap((scheme) => [...themes.map((theme) => `primitives/modes/color-scheme/${scheme}/${theme}`)]),
23-
...themes.map((theme) => `themes/${theme}`),
24+
...themeNames.map((theme) => `primitives/modes/typography/primary/${theme}`),
25+
...themeNames.map((theme) => `primitives/modes/typography/secondary/${theme}`),
26+
...colorSchemes.flatMap((scheme) => [
27+
...themeNames.map((theme) => `primitives/modes/color-scheme/${scheme}/${theme}`),
28+
]),
29+
...themeNames.map((theme) => `themes/${theme}`),
2430
'semantic/color',
25-
...Object.entries(colors.main).map(([color]) => `semantic/modes/main-color/${color}`),
26-
...Object.entries(colors.support).map(([color]) => `semantic/modes/support-color/${color}`),
31+
...colors.main.map((color) => `semantic/modes/main-color/${color}`),
32+
...colors.support.map((color) => `semantic/modes/support-color/${color}`),
2733
'semantic/style',
2834
],
2935
};

packages/cli/src/tokens/create/generators/$themes.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { type ThemeObject, TokenSetStatus } from '@tokens-studio/types';
22

33
import type { ColorScheme } from '../../../colors/types.js';
4-
import type { Colors, SizeModes } from '../../types.js';
4+
import type { ColorNamesByCategory, SizeModes, TokenSetDimensions } from '../../types.js';
55

66
const capitalize = (word: string) => word.charAt(0).toUpperCase() + word.slice(1);
77

@@ -36,19 +36,19 @@ type ThemeObject_ = ThemeObject & {
3636
3737
*/
3838
export async function generate$Themes(
39-
colorSchemes: ColorSchemes,
40-
themes: string[],
41-
colors: Colors,
42-
sizeModes: SizeModes[],
39+
tokenSetDimensions: TokenSetDimensions,
40+
themeNames: string[],
41+
colors: ColorNamesByCategory,
4342
): Promise<ThemeObject_[]> {
43+
const { colorSchemes, sizeModes } = tokenSetDimensions;
4444
return [
4545
...generateSizeGroup(sizeModes),
46-
...(await generateThemesGroup(themes)),
47-
...generateTypographyGroup(themes),
48-
...generateColorSchemesGroup(colorSchemes, themes),
46+
...(await generateThemesGroup(themeNames)),
47+
...generateTypographyGroup(themeNames),
48+
...generateColorSchemesGroup(colorSchemes, themeNames),
4949
generateSemanticGroup(),
50-
...(await generateColorGroup('main', colors)),
51-
...(await generateColorGroup('support', colors)),
50+
...(await generateColorGroup('main', colors.main)),
51+
...(await generateColorGroup('support', colors.support)),
5252
];
5353
}
5454

@@ -164,10 +164,13 @@ function generateSemanticGroup(): ThemeObject_ {
164164
};
165165
}
166166

167-
async function generateColorGroup(group: 'main' | 'support', colors: Colors): Promise<ThemeObject_[]> {
167+
async function generateColorGroup(
168+
group: 'main' | 'support',
169+
colors: ColorNamesByCategory['main'] | ColorNamesByCategory['support'],
170+
): Promise<ThemeObject_[]> {
168171
return Promise.all(
169-
Object.entries(colors[group]).map(
170-
async ([color]): Promise<ThemeObject_> => ({
172+
colors.map(
173+
async (color): Promise<ThemeObject_> => ({
171174
id: await createHash(`${group}-${color}`),
172175
name: color,
173176
selectedTokenSets: {

packages/cli/src/tokens/format.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import * as R from 'ramda';
22
import { generate$Themes } from './create/generators/$themes.js';
3-
import { createTokens } from './create.js';
3+
import { createTokens, tokenSetDimensions } from './create.js';
44
import { createThemeCSSFiles } from './process/output/theme.js';
55
import { type FormatOptions, processPlatform } from './process/platform.js';
66
import { processThemeObject } from './process/utils/getMultidimensionalThemes.js';
7-
import type { SizeModes, Theme } from './types.js';
7+
import type { Theme } from './types.js';
8+
import { colorNamesByCategory } from './utils.js';
89

910
export const formatTokens = async (options: Omit<FormatOptions, 'type' | 'buildTokenFormats'>) => {
1011
const processedBuilds = await processPlatform({
@@ -18,9 +19,11 @@ export const formatTokens = async (options: Omit<FormatOptions, 'type' | 'buildT
1819

1920
export const formatTheme = async (themeConfig: Theme) => {
2021
const { tokenSets } = await createTokens(themeConfig);
21-
const sizeModes: SizeModes[] = ['small', 'medium', 'large'];
2222

23-
const $themes = await generate$Themes(['dark', 'light'], [themeConfig.name], themeConfig.colors, sizeModes);
23+
const themeNames = [themeConfig.name];
24+
const colors = colorNamesByCategory(themeConfig.colors);
25+
const $themes = await generate$Themes(tokenSetDimensions, themeNames, colors);
26+
2427
const processed$themes = $themes.map(processThemeObject);
2528

2629
const processedBuilds = await formatTokens({

packages/cli/src/tokens/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Config as SDConfig } from 'style-dictionary/types';
22
import type { ConfigSchemaTheme } from '../config.js';
3+
import type { ColorScheme } from '../index.js';
34
import type { GetStyleDictionaryConfig } from './process/configs/shared.js';
45

56
export type Token =
@@ -29,6 +30,7 @@ export const colorCategories = {
2930
} as const;
3031

3132
export type ColorCategories = keyof typeof colorCategories;
33+
export type ColorNamesByCategory = Record<ColorCategories, string[]>;
3234

3335
export type BuiltInColors = 'neutral' | 'success' | 'warning' | 'danger' | 'info';
3436

@@ -49,6 +51,11 @@ export type ThemePermutation = {
4951

5052
export type ThemeDimension = keyof ThemePermutation;
5153

54+
export type TokenSetDimensions = {
55+
colorSchemes: ColorScheme[];
56+
sizeModes: SizeModes[];
57+
};
58+
5259
export type GetSDConfigOptions = {
5360
tokensDir?: string;
5461
dry?: boolean;

packages/cli/src/tokens/utils.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import * as R from 'ramda';
22
import type { Tokens } from 'style-dictionary';
33
import type { DesignToken, TransformedToken } from 'style-dictionary/types';
4-
import { type ColorCategories, colorCategories, type TokenSet } from './types.js';
4+
import {
5+
type ColorCategories,
6+
type ColorNamesByCategory,
7+
type Colors,
8+
colorCategories,
9+
type TokenSet,
10+
} from './types.js';
511

612
const mapToLowerCase = R.map<string, string>(R.toLower);
713

@@ -159,3 +165,11 @@ export const sizeComparator = (size: string): number => {
159165
export function orderBySize(sizes: string[]): string[] {
160166
return R.sortBy(sizeComparator, sizes);
161167
}
168+
169+
export function colorNamesByCategory(colors: Colors): ColorNamesByCategory {
170+
const result = {} as ColorNamesByCategory;
171+
for (const category of Object.values(colorCategories)) {
172+
result[category] = Object.keys(colors[category] ?? {});
173+
}
174+
return result;
175+
}

0 commit comments

Comments
 (0)