Skip to content

Commit 2518909

Browse files
committed
feat(variables): update variables #69
1 parent 3de19fc commit 2518909

5 files changed

Lines changed: 65 additions & 89 deletions

File tree

scripts/variable-exporter.ts

Lines changed: 15 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
12
import fs from "fs";
23
import path from "path";
34

45
const FIGMA_VARIABLE_TOKEN = process.env.FIGMA_VARIABLE_TOKEN;
56
const FIGMA_FILE_KEY = process.env.FIGMA_FILE_KEY;
67
const OUTPUT_DIR = "src/variables";
78

8-
// Must match exactly the collection names in your Figma file
99
const WANTED_COLLECTIONS = new Set([
1010
"1. Semantic colors",
1111
"1.1 Base colors",
@@ -15,7 +15,6 @@ const WANTED_COLLECTIONS = new Set([
1515
"3.1 Base fonts",
1616
]);
1717

18-
// Themes
1918
const THEME_MAP: Record<string, { folder: string; fileSuffix: string }> = {
2019
default: { folder: "default", fileSuffix: "default" },
2120
light: { folder: "default", fileSuffix: "default" },
@@ -30,9 +29,6 @@ const RESPONSIVE_MEDIA: Record<string, string> = {
3029
mobile: "(max-width: 48rem)",
3130
};
3231

33-
/* ==========================================================================
34-
UTILITIES
35-
========================================================================== */
3632
function sortCssVars(list: string[]) {
3733
list.sort((a, b) => {
3834
const nameA = a.trim().split(":")[0];
@@ -52,10 +48,6 @@ function kebab(str: string): string {
5248
return str.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
5349
}
5450

55-
/* ==========================================================================
56-
THEME HELPERS – DATA-DRIVEN MAGIC
57-
========================================================================== */
58-
// Find theme config by checking if the mode name contains any key from THEME_MAP
5951
function getThemeConfigFromMode(modeName: string): { folder: string; fileSuffix: string } | undefined {
6052
const lower = modeName.toLowerCase();
6153
for (const [key, config] of Object.entries(THEME_MAP)) {
@@ -64,28 +56,23 @@ function getThemeConfigFromMode(modeName: string): { folder: string; fileSuffix:
6456
return undefined;
6557
}
6658

67-
// Returns true for "brand" themes (muis, rit, etc.) – used to skip responsive overrides
6859
function isBrandTheme(modeName: string): boolean {
6960
const config = getThemeConfigFromMode(modeName);
7061
if (!config) return false;
7162
const lower = modeName.toLowerCase();
7263
return !(lower.includes("default") || lower.includes("light") || lower.includes("dark"));
7364
}
7465

75-
/* ==========================================================================
76-
FIGMA API
77-
========================================================================== */
78-
async function fetchFigmaVariables() {
66+
async function fetchFigmaVariables(): Promise<FigmaVariablesResponse> {
7967
const res = await fetch(`https://api.figma.com/v1/files/${FIGMA_FILE_KEY}/variables/local`, {
8068
headers: { "X-Figma-Token": FIGMA_VARIABLE_TOKEN ?? "" },
8169
});
70+
8271
if (!res.ok) throw new Error(`Figma API error: ${res.status}`);
83-
return await res.json();
72+
73+
return (await res.json()) as FigmaVariablesResponse;
8474
}
8575

86-
/* ==========================================================================
87-
UNIT & CONVERSION LOGIC
88-
========================================================================== */
8976
function getUnit(collectionName: string): "px" | "rem" | null {
9077
const l = collectionName.toLowerCase();
9178
if (l.includes("dimension")) return "px";
@@ -130,13 +117,11 @@ function resolveValue(
130117
): string {
131118
if (!raw) return "0";
132119

133-
// Alias
134120
if (raw && typeof raw === "object" && (raw.type === "VARIABLE_ALIAS" || (raw.id && !("value" in raw)))) {
135121
const cssVar = aliasMap[raw.id];
136122
return cssVar ? `var(${cssVar})` : "0";
137123
}
138124

139-
// Color
140125
if (raw && typeof raw === "object" && "r" in raw) {
141126
const v = "value" in raw ? raw.value : raw;
142127
const { r, g, b, a = 1 } = v;
@@ -148,31 +133,24 @@ function resolveValue(
148133
const lowerName = varName.toLowerCase();
149134

150135
if (typeof value === "number") {
151-
// ─────────────────────── BASE VARIABLES ───────────────────────
152136
if (convertToRemForBase) {
153-
// 1. Font-weight → always unitless
154137
if (lowerName.includes("weight")) {
155138
return value.toString();
156139
}
157140

158-
// 2. Things we explicitly want in rem
159141
if (shouldConvertBaseToRem(varName)) {
160142
return pxToRem(value);
161143
}
162144

163-
// 3. Everything else in base → px (containers, breakpoints, etc.)
164145
return `${Math.round(value * 100) / 100}px`;
165146
}
166147

167-
// ─────────────────────── SEMANTIC LAYERS ───────────────────────
168-
// Fonts collection
169148
if (lowerName.includes("font") || unit === "rem") {
170-
if (lowerName.includes("weight")) return value.toString(); // ← unitless
171-
if (isLineHeight(varName)) return pxToRem(value); // ← rem
172-
return pxToRem(value); // ← rem (font-size, etc.)
149+
if (lowerName.includes("weight")) return value.toString();
150+
if (isLineHeight(varName)) return pxToRem(value);
151+
return pxToRem(value);
173152
}
174153

175-
// Dimensions collection
176154
if (unit === "px" || lowerName.includes("radius") || lowerName.includes("border")) {
177155
return `${Math.round(value * 100) / 100}px`;
178156
}
@@ -183,9 +161,6 @@ function resolveValue(
183161
return value !== undefined ? String(value) : "0";
184162
}
185163

186-
/* ==========================================================================
187-
TYPES & MAIN
188-
========================================================================== */
189164
interface FigmaVariable {
190165
name: string;
191166
resolvedValuesByMode?: Record<string, any>;
@@ -197,6 +172,12 @@ interface FigmaCollection {
197172
variableIds: string[];
198173
defaultModeId?: string;
199174
}
175+
interface FigmaVariablesResponse {
176+
meta: {
177+
variables: Record<string, FigmaVariable>;
178+
variableCollections: Record<string, FigmaCollection>;
179+
};
180+
}
200181

201182
async function run() {
202183
const data = await fetchFigmaVariables();
@@ -212,7 +193,6 @@ async function run() {
212193
WANTED_COLLECTIONS.has(c.name.trim())
213194
);
214195

215-
/* ———————————————————————— 1. BASE VARIABLES ———————————————————————— */
216196
const baseLines: string[] = [];
217197
for (const coll of wantedColls.filter(c => c.name.includes("Base"))) {
218198
const modeId = coll.defaultModeId ?? coll.modes[0]?.modeId;
@@ -236,14 +216,12 @@ async function run() {
236216
fs.writeFileSync(path.join(OUTPUT_DIR, "_base-variables.scss"), css);
237217
}
238218

239-
/* ———————————————————————— 2. SEMANTIC VARIABLES ———————————————————————— */
240219
for (const coll of wantedColls.filter(c => !c.name.includes("Base"))) {
241220
const unit = getUnit(coll.name);
242221
const isFonts = coll.name === "3. Semantic fonts";
243222
const isColors = coll.name === "1. Semantic colors";
244223
const isDimensions = coll.name === "2. Semantic dimensions";
245224

246-
/* ——— Responsive Fonts (default/light/dark only) ——— */
247225
if (isFonts) {
248226
const desktopLines: string[] = [];
249227
const tabletLines: string[] = [];
@@ -252,7 +230,6 @@ async function run() {
252230
for (const mode of coll.modes) {
253231
const lower = mode.name.toLowerCase();
254232

255-
// Skip brand themes – they get their own full theme files
256233
if (isBrandTheme(mode.name)) continue;
257234

258235
const target = lower.includes("mobile") ? mobileLines
@@ -281,10 +258,9 @@ async function run() {
281258
}
282259
}
283260

284-
/* ——— Theme-specific files ——— */
285261
for (const mode of coll.modes) {
286262
const themeConfig = getThemeConfigFromMode(mode.name);
287-
if (!themeConfig) continue; // not a recognized theme → skip
263+
if (!themeConfig) continue;
288264

289265
const lines: string[] = [];
290266
for (const varId of coll.variableIds) {
@@ -308,7 +284,6 @@ async function run() {
308284
fs.writeFileSync(path.join(dir, fileName), css);
309285
}
310286

311-
/* ——— Responsive Dimensions ——— */
312287
if (isDimensions) {
313288
const rootLines: string[] = [];
314289
const mediaBlocks: string[] = [];

src/variables/_dimensional-variables.scss

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,8 @@
244244
--layout-page-spacing-x: 40px;
245245
--layout-to-be-deleted-outer-container: 1520px;
246246
--link-icon-default: var(--icon-03);
247-
--link-icon-padding-top: var(--dimensions-02);
248-
--link-icon-padding-y: var(--dimensions-03);
247+
--link-icon-padding-y: 3px;
248+
--link-icon-padding-y-sm: var(--dimensions-03);
249249
--link-icon-responsive: var(--icon-02);
250250
--link-icon-small: var(--icon-02);
251251
--link-inner-spacing-x: var(--dimensions-03);
@@ -327,10 +327,10 @@
327327
--progress-bar-height: var(--form-slider-height);
328328
--progress-bar-height-sm: var(--dimensions-03);
329329
--progress-bar-radius: var(--form-slider-radius);
330-
--separator-dotted-dot-lg: 15px;
331-
--separator-dotted-dot-md: 9px;
332-
--separator-dotted-dot-sm: var(--dimensions-03);
333-
--separator-dotted-dot-xs: var(--dimensions-02);
330+
--separator-dot-size-lg: 15px;
331+
--separator-dot-size-md: 9px;
332+
--separator-dot-size-sm: var(--dimensions-03);
333+
--separator-dot-size-xs: var(--dimensions-02);
334334
--separator-dotted-line-width: var(--dimensions-01);
335335
--separator-spacing-x-01: var(--dimensions-04);
336336
--separator-spacing-x-02: var(--dimensions-07);
@@ -339,12 +339,11 @@
339339
--separator-spacing-y-02: var(--dimensions-05);
340340
--separator-spacing-y-03: var(--dimensions-10);
341341
--separator-spacing-y-04: var(--dimensions-13);
342-
--separator-top-spacing-large-dot-lg: 21px;
343-
--separator-top-spacing-large-dot-md: 15.5px;
344-
--separator-top-spacing-large-dot-sm: var(--dimensions-03);
345-
--separator-top-spacing-small-dot-lg: var(--dimensions-13);
346-
--separator-top-spacing-small-dot-md: var(--dimensions-06);
347-
--separator-top-spacing-small-dot-sm: var(--dimensions-05);
342+
--separator-thickness-lg: var(--dimensions-02);
343+
--separator-thickness-md: var(--dimensions-01);
344+
--separator-thickness-sm: 0.5px;
345+
--separator-thickness-xs: 0.25px;
346+
--separator-top-spacing-large-dot-sm: 4px;
348347
--status-indicator-inner-spacing: var(--dimensions-05);
349348
--status-indicator-lg: var(--dimensions-07);
350349
--status-indicator-sm: var(--dimensions-05);
@@ -366,7 +365,7 @@
366365
--stepper-item-vertical-padding-y-sm: 2px;
367366
--stepper-item-vertical-step-size-lg: 24px;
368367
--stepper-item-vertical-step-size-md: 16px;
369-
--stepper-item-vertical-step-size-sm: var(--separator-dotted-dot-md);
368+
--stepper-item-vertical-step-size-sm: var(--separator-dot-size-md);
370369
--stepper-item-vertical-sub-line-bottom: 9px;
371370
--stepper-item-vertical-sub-line-top: 9.5px;
372371
--tab-icon: 18px;
@@ -663,8 +662,8 @@
663662
--layout-page-spacing-x: 24px;
664663
--layout-to-be-deleted-outer-container: 1520px;
665664
--link-icon-default: var(--icon-03);
666-
--link-icon-padding-top: var(--dimensions-02);
667-
--link-icon-padding-y: var(--dimensions-03);
665+
--link-icon-padding-y: 3px;
666+
--link-icon-padding-y-sm: var(--dimensions-03);
668667
--link-icon-responsive: var(--icon-03);
669668
--link-icon-small: var(--icon-02);
670669
--link-inner-spacing-x: var(--dimensions-03);
@@ -746,10 +745,10 @@
746745
--progress-bar-height: var(--form-slider-height);
747746
--progress-bar-height-sm: var(--dimensions-03);
748747
--progress-bar-radius: var(--form-slider-radius);
749-
--separator-dotted-dot-lg: 15px;
750-
--separator-dotted-dot-md: 9px;
751-
--separator-dotted-dot-sm: var(--dimensions-03);
752-
--separator-dotted-dot-xs: var(--dimensions-02);
748+
--separator-dot-size-lg: 15px;
749+
--separator-dot-size-md: 9px;
750+
--separator-dot-size-sm: var(--dimensions-03);
751+
--separator-dot-size-xs: var(--dimensions-02);
753752
--separator-dotted-line-width: var(--dimensions-01);
754753
--separator-spacing-x-01: var(--dimensions-04);
755754
--separator-spacing-x-02: var(--dimensions-07);
@@ -758,12 +757,11 @@
758757
--separator-spacing-y-02: var(--dimensions-05);
759758
--separator-spacing-y-03: var(--dimensions-10);
760759
--separator-spacing-y-04: var(--dimensions-13);
761-
--separator-top-spacing-large-dot-lg: 21px;
762-
--separator-top-spacing-large-dot-md: 15.5px;
760+
--separator-thickness-lg: var(--dimensions-02);
761+
--separator-thickness-md: var(--dimensions-01);
762+
--separator-thickness-sm: 0.5px;
763+
--separator-thickness-xs: 0.25px;
763764
--separator-top-spacing-large-dot-sm: var(--dimensions-03);
764-
--separator-top-spacing-small-dot-lg: var(--dimensions-13);
765-
--separator-top-spacing-small-dot-md: var(--dimensions-06);
766-
--separator-top-spacing-small-dot-sm: var(--dimensions-05);
767765
--status-indicator-inner-spacing: var(--dimensions-05);
768766
--status-indicator-lg: var(--dimensions-07);
769767
--status-indicator-sm: var(--dimensions-05);
@@ -785,7 +783,7 @@
785783
--stepper-item-vertical-padding-y-sm: 2px;
786784
--stepper-item-vertical-step-size-lg: 24px;
787785
--stepper-item-vertical-step-size-md: 16px;
788-
--stepper-item-vertical-step-size-sm: var(--separator-dotted-dot-md);
786+
--stepper-item-vertical-step-size-sm: var(--separator-dot-size-md);
789787
--stepper-item-vertical-sub-line-bottom: 9px;
790788
--stepper-item-vertical-sub-line-top: 9.5px;
791789
--tab-icon: 18px;
@@ -1083,8 +1081,8 @@
10831081
--layout-page-spacing-x: 8px;
10841082
--layout-to-be-deleted-outer-container: 1520px;
10851083
--link-icon-default: var(--icon-03);
1086-
--link-icon-padding-top: var(--dimensions-02);
1087-
--link-icon-padding-y: var(--dimensions-03);
1084+
--link-icon-padding-y: 3px;
1085+
--link-icon-padding-y-sm: 3px;
10881086
--link-icon-responsive: var(--icon-03);
10891087
--link-icon-small: var(--icon-02);
10901088
--link-inner-spacing-x: var(--dimensions-03);
@@ -1166,10 +1164,10 @@
11661164
--progress-bar-height: var(--form-slider-height);
11671165
--progress-bar-height-sm: var(--dimensions-03);
11681166
--progress-bar-radius: var(--form-slider-radius);
1169-
--separator-dotted-dot-lg: 15px;
1170-
--separator-dotted-dot-md: 9px;
1171-
--separator-dotted-dot-sm: var(--dimensions-03);
1172-
--separator-dotted-dot-xs: var(--dimensions-02);
1167+
--separator-dot-size-lg: 15px;
1168+
--separator-dot-size-md: 9px;
1169+
--separator-dot-size-sm: var(--dimensions-03);
1170+
--separator-dot-size-xs: var(--dimensions-02);
11731171
--separator-dotted-line-width: var(--dimensions-01);
11741172
--separator-spacing-x-01: var(--dimensions-04);
11751173
--separator-spacing-x-02: var(--dimensions-07);
@@ -1178,12 +1176,11 @@
11781176
--separator-spacing-y-02: var(--dimensions-05);
11791177
--separator-spacing-y-03: var(--dimensions-10);
11801178
--separator-spacing-y-04: var(--dimensions-13);
1181-
--separator-top-spacing-large-dot-lg: 21px;
1182-
--separator-top-spacing-large-dot-md: 15.5px;
1179+
--separator-thickness-lg: var(--dimensions-02);
1180+
--separator-thickness-md: var(--dimensions-01);
1181+
--separator-thickness-sm: 0.5px;
1182+
--separator-thickness-xs: 0.25px;
11831183
--separator-top-spacing-large-dot-sm: var(--dimensions-03);
1184-
--separator-top-spacing-small-dot-lg: var(--dimensions-13);
1185-
--separator-top-spacing-small-dot-md: var(--dimensions-06);
1186-
--separator-top-spacing-small-dot-sm: var(--dimensions-05);
11871184
--status-indicator-inner-spacing: var(--dimensions-05);
11881185
--status-indicator-lg: var(--dimensions-07);
11891186
--status-indicator-sm: var(--dimensions-05);
@@ -1205,7 +1202,7 @@
12051202
--stepper-item-vertical-padding-y-sm: 2px;
12061203
--stepper-item-vertical-step-size-lg: 24px;
12071204
--stepper-item-vertical-step-size-md: 16px;
1208-
--stepper-item-vertical-step-size-sm: var(--separator-dotted-dot-md);
1205+
--stepper-item-vertical-step-size-sm: var(--separator-dot-size-md);
12091206
--stepper-item-vertical-sub-line-bottom: 9px;
12101207
--stepper-item-vertical-sub-line-top: 9.5px;
12111208
--tab-icon: 18px;

src/variables/themes/default/font-variables__default.scss

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@
4444
--body-extra-small-size: var(--tedi-size-00);
4545
--body-extra-small-weight: var(--tedi-weight-02);
4646
--body-extra-small-line-height: var(--tedi-line-height-00);
47-
--body-link-regular: var(--body-regular-size);
48-
--body-link-small: var(--body-small-regular-size);
49-
--body-link-responsive: var(--body-small-regular-size);
47+
--body-link-line-height: var(--body-regular-line-height);
48+
--body-link-size-small: var(--body-small-regular-size);
49+
--body-link-size-regular: var(--body-regular-size);
50+
--body-link-size-responsive: var(--body-small-regular-size);
5051

5152
@media (width <= 48rem) {
5253
--family-default: var(--tedi-family-roboto);
@@ -93,8 +94,9 @@
9394
--body-extra-small-size: var(--tedi-size-00);
9495
--body-extra-small-weight: var(--tedi-weight-02);
9596
--body-extra-small-line-height: var(--tedi-line-height-00);
96-
--body-link-regular: var(--body-regular-size);
97-
--body-link-small: var(--body-small-regular-size);
98-
--body-link-responsive: var(--body-regular-size);
97+
--body-link-line-height: var(--body-regular-line-height);
98+
--body-link-size-small: var(--body-small-regular-size);
99+
--body-link-size-regular: var(--body-regular-size);
100+
--body-link-size-responsive: var(--body-regular-size);
99101
}
100102
}

src/variables/themes/muis/font-variables__muis.scss

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
--body-extra-small-line-height: var(--tedi-line-height-00);
99
--body-extra-small-size: var(--tedi-size-00);
1010
--body-extra-small-weight: var(--tedi-weight-02);
11-
--body-link-regular: var(--body-regular-size);
12-
--body-link-responsive: var(--body-small-regular-size);
13-
--body-link-small: var(--body-small-regular-size);
11+
--body-link-line-height: var(--body-regular-line-height);
12+
--body-link-size-regular: var(--body-regular-size);
13+
--body-link-size-responsive: var(--body-small-regular-size);
14+
--body-link-size-small: var(--body-small-regular-size);
1415
--body-regular-line-height: var(--tedi-line-height-03);
1516
--body-regular-size: var(--tedi-size-02);
1617
--body-regular-weight: var(--tedi-weight-02);

0 commit comments

Comments
 (0)