Skip to content

Commit 0803ddb

Browse files
committed
Refactor theme tokens to use SCSS and TypeScript
Replaces CSS variables and JSON token files with a new SCSS file (tokens-light-dark.scss) and TypeScript token files for light and dark themes. Updates the build-tokens.js script to use a new configuration-based approach, removes direct imports of old CSS variable files, and updates dependencies to use the latest style-dictionary and @tokens-studio/sd-transforms. Cleans up unused variable files and updates related imports and scripts for improved theme management.
1 parent 106b293 commit 0803ddb

19 files changed

+35374
-12875
lines changed

.storybook/preview.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React from "react";
22
import type { Preview } from "@storybook/react-vite";
3-
import "../src/styles/variables.css";
43
import { Decorator } from "@storybook/react-vite";
54
import styled from "styled-components";
65
import { themes } from "storybook/theming";

build-tokens.js

Lines changed: 11 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,14 @@
1-
import _ from "lodash";
2-
import { registerTransforms, transforms } from "@tokens-studio/sd-transforms";
3-
import StyleDictionary from "style-dictionary";
1+
import StyleDictionary, { getStyleDictionaryConfig } from "./style-dictionary.config.js";
42

5-
registerTransforms(StyleDictionary);
6-
const themes = ["dark", "light"];
3+
const config = await getStyleDictionaryConfig();
4+
const { themes, configs } = config;
75

8-
function generateThemeFromDictionary(dictionary, valueFunc = (value) => value) {
9-
const theme = {};
10-
dictionary.allTokens.forEach((token) => {
11-
_.setWith(theme, token.name, valueFunc(token.value), Object)
12-
});
13-
return theme;
14-
}
15-
16-
StyleDictionary.registerTransform({
17-
type: "name",
18-
name: "name/cti/dot",
19-
transformer: (token, options) => {
20-
if (options.prefix && options.prefix.length) {
21-
return [options.prefix].concat(token.path).join(".");
22-
} else {
23-
return token.path.join(".");
24-
}
25-
}
26-
});
27-
28-
StyleDictionary.registerFormat({
29-
name: "ThemeFormat",
30-
formatter: function ({ dictionary, platform, options, file }) {
31-
const theme = generateThemeFromDictionary(dictionary);
32-
return JSON.stringify(theme, null, 2);
33-
}
34-
});
35-
36-
StyleDictionary.registerFormat({
37-
name: "TypescriptFormat",
38-
formatter: function ({ dictionary, platform, options, file }) {
39-
const theme = generateThemeFromDictionary(dictionary, (value) => typeof value);
40-
41-
// Convert the theme object to a TypeScript interface string
42-
// Prettier will format this automatically via the generate-tokens script
43-
let jsonString = JSON.stringify(theme, null, 2);
6+
const scssSD = new StyleDictionary(configs.scss);
7+
await scssSD.cleanAllPlatforms();
8+
await scssSD.buildAllPlatforms();
449

45-
// Replace type strings with TypeScript types
46-
jsonString = jsonString.replaceAll('"string"', 'string');
47-
jsonString = jsonString.replaceAll('"number"', 'number');
48-
49-
return `export interface Theme ${jsonString}\n`;
50-
}
51-
});
52-
53-
StyleDictionary.extend({
54-
source: [`./tokens/**/!(${themes.join("|*.")}).json`],
55-
platforms: {
56-
css: {
57-
transforms: [...transforms, "name/cti/kebab"],
58-
buildPath: "build/css/",
59-
files: [
60-
{
61-
destination: "variables.css",
62-
format: "css/variables",
63-
options: {
64-
outputReferences: true,
65-
},
66-
},
67-
],
68-
},
69-
js: {
70-
transforms: [...transforms, "name/cti/dot"],
71-
buildPath: "src/theme/tokens/",
72-
files: [
73-
{
74-
destination: "variables.json",
75-
format: "ThemeFormat",
76-
options: {
77-
outputReferences: true,
78-
},
79-
},
80-
],
81-
},
82-
ts: {
83-
transforms: [...transforms, "name/cti/dot"],
84-
buildPath: "src/theme/tokens/",
85-
files: [
86-
{
87-
destination: "types.ts",
88-
format: "TypescriptFormat",
89-
options: {
90-
outputReferences: true,
91-
},
92-
},
93-
],
94-
},
95-
},
96-
})
97-
.cleanAllPlatforms()
98-
.buildAllPlatforms();
99-
100-
themes.forEach(theme =>
101-
StyleDictionary.extend({
102-
include: [`./tokens/**/!(${themes.join("|*.")}).json`],
103-
source: [`./tokens/**/${theme}.json`],
104-
platforms: {
105-
css: {
106-
transforms: [...transforms, "name/cti/kebab"],
107-
buildPath: "build/css/",
108-
files: [
109-
{
110-
destination: `variables.${theme}.css`,
111-
format: "css/variables",
112-
filter: token => token.filePath.indexOf(`${theme}`) > -1,
113-
options: {
114-
outputReferences: true,
115-
},
116-
},
117-
],
118-
},
119-
js: {
120-
transforms: [...transforms, "name/cti/dot"],
121-
buildPath: "src/theme/tokens/",
122-
files: [
123-
{
124-
destination: `variables.${theme}.json`,
125-
format: "ThemeFormat",
126-
filter: token => token.filePath.indexOf(`${theme}`) > -1,
127-
options: {
128-
outputReferences: true,
129-
},
130-
},
131-
],
132-
},
133-
},
134-
})
135-
.cleanAllPlatforms()
136-
.buildAllPlatforms()
137-
);
10+
for (const theme of themes) {
11+
const themeSD = new StyleDictionary(configs.theme(theme));
12+
await themeSD.cleanAllPlatforms();
13+
await themeSD.buildAllPlatforms();
14+
}

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"build:watch": "watch 'yarn build' ./src",
4040
"chromatic": "npx chromatic",
4141
"dev": "vite",
42-
"generate-tokens": "node build-tokens.js && prettier --write src/theme/tokens/types.ts",
42+
"generate-tokens": "node build-tokens.js",
4343
"lint": "eslint src --report-unused-disable-directives --max-warnings 0",
4444
"prettify": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\" --config .prettierrc",
4545
"prettier:check": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\" --config .prettierrc",
@@ -84,7 +84,7 @@
8484
"@testing-library/jest-dom": "^6.4.5",
8585
"@testing-library/react": "^15.0.7",
8686
"@testing-library/user-event": "^14.5.2",
87-
"@tokens-studio/sd-transforms": "^0.10.3",
87+
"@tokens-studio/sd-transforms": "^1.2.0",
8888
"@types/lodash-es": "^4.17.7",
8989
"@types/node": "^24.10.1",
9090
"@types/react": "18.3.2",
@@ -113,6 +113,7 @@
113113
"react-dom": "18.3.1",
114114
"storybook": "^10.0.7",
115115
"storybook-addon-pseudo-states": "^10.0.7",
116+
"style-dictionary": "^5.0.0",
116117
"styled-components": "^6.1.11",
117118
"stylis": "^4.3.0",
118119
"ts-node": "^10.9.1",

src/App.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { useRef, useState } from "react";
22

33
import "@/styles/globals.css";
4-
import "./styles/variables.css";
5-
import "./styles/variables.dark.css";
64

75
import styles from "./App.module.css";
86
import { ThemeName } from "./theme";

src/styles/globals.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
@import "variables.css";
21

32
:root {
43
--max-width: 1100px;

0 commit comments

Comments
 (0)