@mgcrea/react-native-tailwind 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +437 -10
- package/dist/babel/config-loader.ts +1 -23
- package/dist/babel/index.cjs +543 -150
- package/dist/babel/index.d.ts +27 -2
- package/dist/babel/index.test.ts +268 -0
- package/dist/babel/index.ts +352 -44
- package/dist/components/Pressable.d.ts +2 -0
- package/dist/components/TextInput.d.ts +2 -0
- package/dist/config/palettes.d.ts +302 -0
- package/dist/config/palettes.js +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -1
- package/dist/parser/__snapshots__/colors.test.js.snap +242 -90
- package/dist/parser/__snapshots__/transforms.test.js.snap +58 -0
- package/dist/parser/colors.js +1 -1
- package/dist/parser/colors.test.js +1 -1
- package/dist/parser/layout.js +1 -1
- package/dist/parser/layout.test.js +1 -1
- package/dist/parser/typography.js +1 -1
- package/dist/parser/typography.test.js +1 -1
- package/dist/runtime.cjs +2 -0
- package/dist/runtime.cjs.map +7 -0
- package/dist/runtime.d.ts +139 -0
- package/dist/runtime.js +2 -0
- package/dist/runtime.js.map +7 -0
- package/dist/runtime.test.js +1 -0
- package/dist/stubs/tw.d.ts +60 -0
- package/dist/stubs/tw.js +1 -0
- package/dist/utils/flattenColors.d.ts +16 -0
- package/dist/utils/flattenColors.js +1 -0
- package/dist/utils/flattenColors.test.js +1 -0
- package/dist/utils/modifiers.d.ts +29 -0
- package/dist/utils/modifiers.js +1 -0
- package/dist/utils/modifiers.test.js +1 -0
- package/dist/utils/styleKey.test.js +1 -0
- package/package.json +15 -3
- package/src/babel/config-loader.ts +1 -23
- package/src/babel/index.test.ts +268 -0
- package/src/babel/index.ts +352 -44
- package/src/components/Pressable.tsx +1 -0
- package/src/components/TextInput.tsx +1 -0
- package/src/config/palettes.ts +304 -0
- package/src/index.ts +5 -0
- package/src/parser/colors.test.ts +47 -31
- package/src/parser/colors.ts +5 -110
- package/src/parser/layout.test.ts +35 -0
- package/src/parser/layout.ts +26 -0
- package/src/parser/typography.test.ts +10 -0
- package/src/parser/typography.ts +8 -0
- package/src/runtime.test.ts +325 -0
- package/src/runtime.ts +280 -0
- package/src/stubs/tw.ts +80 -0
- package/src/utils/flattenColors.test.ts +361 -0
- package/src/utils/flattenColors.ts +32 -0
- package/src/utils/modifiers.test.ts +286 -0
- package/src/utils/modifiers.ts +63 -0
- package/src/utils/styleKey.test.ts +168 -0
package/src/stubs/tw.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile-time stub for tw/twStyle functions
|
|
3
|
+
*
|
|
4
|
+
* These functions are transformed by the Babel plugin at compile-time.
|
|
5
|
+
* If you see these errors at runtime, it means the Babel plugin is not configured correctly.
|
|
6
|
+
*
|
|
7
|
+
* For runtime parsing, use: import { tw } from '@mgcrea/react-native-tailwind/runtime'
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ImageStyle, TextStyle, ViewStyle } from "react-native";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Union type for all React Native style types
|
|
14
|
+
*/
|
|
15
|
+
export type NativeStyle = ViewStyle | TextStyle | ImageStyle;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Return type for tw/twStyle functions with separate style properties for modifiers
|
|
19
|
+
*/
|
|
20
|
+
export type TwStyle<T extends NativeStyle = NativeStyle> = {
|
|
21
|
+
style: T;
|
|
22
|
+
activeStyle?: T;
|
|
23
|
+
focusStyle?: T;
|
|
24
|
+
disabledStyle?: T;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Compile-time Tailwind CSS template tag (transformed by Babel plugin)
|
|
29
|
+
*
|
|
30
|
+
* This function is replaced at compile-time by the Babel plugin.
|
|
31
|
+
* The import is removed and calls are transformed to inline style objects.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* import { tw } from '@mgcrea/react-native-tailwind';
|
|
36
|
+
*
|
|
37
|
+
* const styles = tw`bg-blue-500 active:bg-blue-700`;
|
|
38
|
+
* // Transformed to:
|
|
39
|
+
* // const styles = {
|
|
40
|
+
* // style: styles._bg_blue_500,
|
|
41
|
+
* // activeStyle: styles._active_bg_blue_700
|
|
42
|
+
* // };
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function tw<T extends NativeStyle = NativeStyle>(
|
|
46
|
+
_strings: TemplateStringsArray,
|
|
47
|
+
..._values: unknown[]
|
|
48
|
+
): TwStyle<T> {
|
|
49
|
+
throw new Error(
|
|
50
|
+
"tw() must be transformed by the Babel plugin. " +
|
|
51
|
+
"Ensure @mgcrea/react-native-tailwind/babel is configured in your babel.config.js. " +
|
|
52
|
+
"For runtime parsing, use: import { tw } from '@mgcrea/react-native-tailwind/runtime'",
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Compile-time Tailwind CSS string function (transformed by Babel plugin)
|
|
58
|
+
*
|
|
59
|
+
* This function is replaced at compile-time by the Babel plugin.
|
|
60
|
+
* The import is removed and calls are transformed to inline style objects.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* import { twStyle } from '@mgcrea/react-native-tailwind';
|
|
65
|
+
*
|
|
66
|
+
* const styles = twStyle('bg-blue-500 active:bg-blue-700');
|
|
67
|
+
* // Transformed to:
|
|
68
|
+
* // const styles = {
|
|
69
|
+
* // style: styles._bg_blue_500,
|
|
70
|
+
* // activeStyle: styles._active_bg_blue_700
|
|
71
|
+
* // };
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export function twStyle<T extends NativeStyle = NativeStyle>(_className: string): TwStyle<T> | undefined {
|
|
75
|
+
throw new Error(
|
|
76
|
+
"twStyle() must be transformed by the Babel plugin. " +
|
|
77
|
+
"Ensure @mgcrea/react-native-tailwind/babel is configured in your babel.config.js. " +
|
|
78
|
+
"For runtime parsing, use: import { twStyle } from '@mgcrea/react-native-tailwind/runtime'",
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { flattenColors } from "./flattenColors";
|
|
3
|
+
|
|
4
|
+
describe("flattenColors", () => {
|
|
5
|
+
it("should handle flat color objects", () => {
|
|
6
|
+
const colors = {
|
|
7
|
+
red: "#ff0000",
|
|
8
|
+
blue: "#0000ff",
|
|
9
|
+
green: "#00ff00",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
expect(flattenColors(colors)).toEqual({
|
|
13
|
+
red: "#ff0000",
|
|
14
|
+
blue: "#0000ff",
|
|
15
|
+
green: "#00ff00",
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should flatten single-level nested objects", () => {
|
|
20
|
+
const colors = {
|
|
21
|
+
brand: {
|
|
22
|
+
primary: "#ff6b6b",
|
|
23
|
+
secondary: "#4ecdc4",
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
expect(flattenColors(colors)).toEqual({
|
|
28
|
+
"brand-primary": "#ff6b6b",
|
|
29
|
+
"brand-secondary": "#4ecdc4",
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should flatten multi-level nested objects", () => {
|
|
34
|
+
const colors = {
|
|
35
|
+
brand: {
|
|
36
|
+
light: {
|
|
37
|
+
primary: "#ffcccc",
|
|
38
|
+
secondary: "#ccffff",
|
|
39
|
+
},
|
|
40
|
+
dark: {
|
|
41
|
+
primary: "#990000",
|
|
42
|
+
secondary: "#006666",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
expect(flattenColors(colors)).toEqual({
|
|
48
|
+
"brand-light-primary": "#ffcccc",
|
|
49
|
+
"brand-light-secondary": "#ccffff",
|
|
50
|
+
"brand-dark-primary": "#990000",
|
|
51
|
+
"brand-dark-secondary": "#006666",
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should handle mixed flat and nested objects", () => {
|
|
56
|
+
const colors = {
|
|
57
|
+
white: "#ffffff",
|
|
58
|
+
black: "#000000",
|
|
59
|
+
brand: {
|
|
60
|
+
primary: "#ff6b6b",
|
|
61
|
+
secondary: "#4ecdc4",
|
|
62
|
+
},
|
|
63
|
+
accent: "#ffe66d",
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
expect(flattenColors(colors)).toEqual({
|
|
67
|
+
white: "#ffffff",
|
|
68
|
+
black: "#000000",
|
|
69
|
+
"brand-primary": "#ff6b6b",
|
|
70
|
+
"brand-secondary": "#4ecdc4",
|
|
71
|
+
accent: "#ffe66d",
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should handle Tailwind-style color scale objects", () => {
|
|
76
|
+
const colors = {
|
|
77
|
+
gray: {
|
|
78
|
+
"50": "#f9fafb",
|
|
79
|
+
"100": "#f3f4f6",
|
|
80
|
+
"200": "#e5e7eb",
|
|
81
|
+
"500": "#6b7280",
|
|
82
|
+
"900": "#111827",
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
expect(flattenColors(colors)).toEqual({
|
|
87
|
+
"gray-50": "#f9fafb",
|
|
88
|
+
"gray-100": "#f3f4f6",
|
|
89
|
+
"gray-200": "#e5e7eb",
|
|
90
|
+
"gray-500": "#6b7280",
|
|
91
|
+
"gray-900": "#111827",
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should handle empty object", () => {
|
|
96
|
+
expect(flattenColors({})).toEqual({});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should handle single color", () => {
|
|
100
|
+
const colors = {
|
|
101
|
+
primary: "#ff0000",
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
expect(flattenColors(colors)).toEqual({
|
|
105
|
+
primary: "#ff0000",
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should handle deeply nested objects (3+ levels)", () => {
|
|
110
|
+
const colors = {
|
|
111
|
+
theme: {
|
|
112
|
+
light: {
|
|
113
|
+
brand: {
|
|
114
|
+
primary: "#ff6b6b",
|
|
115
|
+
secondary: "#4ecdc4",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
dark: {
|
|
119
|
+
brand: {
|
|
120
|
+
primary: "#990000",
|
|
121
|
+
secondary: "#006666",
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
expect(flattenColors(colors)).toEqual({
|
|
128
|
+
"theme-light-brand-primary": "#ff6b6b",
|
|
129
|
+
"theme-light-brand-secondary": "#4ecdc4",
|
|
130
|
+
"theme-dark-brand-primary": "#990000",
|
|
131
|
+
"theme-dark-brand-secondary": "#006666",
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should handle numeric keys", () => {
|
|
136
|
+
const colors = {
|
|
137
|
+
blue: {
|
|
138
|
+
"100": "#dbeafe",
|
|
139
|
+
"500": "#3b82f6",
|
|
140
|
+
"900": "#1e3a8a",
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
expect(flattenColors(colors)).toEqual({
|
|
145
|
+
"blue-100": "#dbeafe",
|
|
146
|
+
"blue-500": "#3b82f6",
|
|
147
|
+
"blue-900": "#1e3a8a",
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should handle keys with hyphens", () => {
|
|
152
|
+
const colors = {
|
|
153
|
+
"brand-primary": "#ff0000",
|
|
154
|
+
"brand-secondary": {
|
|
155
|
+
light: "#00ff00",
|
|
156
|
+
dark: "#006600",
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
expect(flattenColors(colors)).toEqual({
|
|
161
|
+
"brand-primary": "#ff0000",
|
|
162
|
+
"brand-secondary-light": "#00ff00",
|
|
163
|
+
"brand-secondary-dark": "#006600",
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should handle uppercase and lowercase hex values", () => {
|
|
168
|
+
const colors = {
|
|
169
|
+
red: "#FF0000",
|
|
170
|
+
blue: "#0000ff",
|
|
171
|
+
green: "#00Ff00",
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
expect(flattenColors(colors)).toEqual({
|
|
175
|
+
red: "#FF0000",
|
|
176
|
+
blue: "#0000ff",
|
|
177
|
+
green: "#00Ff00",
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("should handle 3-digit hex values", () => {
|
|
182
|
+
const colors = {
|
|
183
|
+
red: "#f00",
|
|
184
|
+
blue: "#00f",
|
|
185
|
+
green: "#0f0",
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
expect(flattenColors(colors)).toEqual({
|
|
189
|
+
red: "#f00",
|
|
190
|
+
blue: "#00f",
|
|
191
|
+
green: "#0f0",
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("should handle 8-digit hex values (with alpha)", () => {
|
|
196
|
+
const colors = {
|
|
197
|
+
"red-50": "#ff000080",
|
|
198
|
+
"blue-50": "#0000ff80",
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
expect(flattenColors(colors)).toEqual({
|
|
202
|
+
"red-50": "#ff000080",
|
|
203
|
+
"blue-50": "#0000ff80",
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should handle complex real-world Tailwind config", () => {
|
|
208
|
+
const colors = {
|
|
209
|
+
transparent: "transparent",
|
|
210
|
+
current: "currentColor",
|
|
211
|
+
white: "#ffffff",
|
|
212
|
+
black: "#000000",
|
|
213
|
+
gray: {
|
|
214
|
+
"50": "#f9fafb",
|
|
215
|
+
"100": "#f3f4f6",
|
|
216
|
+
"500": "#6b7280",
|
|
217
|
+
"900": "#111827",
|
|
218
|
+
},
|
|
219
|
+
brand: {
|
|
220
|
+
primary: "#ff6b6b",
|
|
221
|
+
secondary: "#4ecdc4",
|
|
222
|
+
accent: {
|
|
223
|
+
light: "#ffe66d",
|
|
224
|
+
dark: "#ffb900",
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
expect(flattenColors(colors)).toEqual({
|
|
230
|
+
transparent: "transparent",
|
|
231
|
+
current: "currentColor",
|
|
232
|
+
white: "#ffffff",
|
|
233
|
+
black: "#000000",
|
|
234
|
+
"gray-50": "#f9fafb",
|
|
235
|
+
"gray-100": "#f3f4f6",
|
|
236
|
+
"gray-500": "#6b7280",
|
|
237
|
+
"gray-900": "#111827",
|
|
238
|
+
"brand-primary": "#ff6b6b",
|
|
239
|
+
"brand-secondary": "#4ecdc4",
|
|
240
|
+
"brand-accent-light": "#ffe66d",
|
|
241
|
+
"brand-accent-dark": "#ffb900",
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("should not mutate input object", () => {
|
|
246
|
+
const colors = {
|
|
247
|
+
brand: {
|
|
248
|
+
primary: "#ff6b6b",
|
|
249
|
+
secondary: "#4ecdc4",
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const original = JSON.parse(JSON.stringify(colors));
|
|
254
|
+
flattenColors(colors);
|
|
255
|
+
|
|
256
|
+
expect(colors).toEqual(original);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("should handle undefined values gracefully", () => {
|
|
260
|
+
const colors = {
|
|
261
|
+
red: "#ff0000",
|
|
262
|
+
blue: undefined as unknown as string, // Testing runtime edge case
|
|
263
|
+
green: "#00ff00",
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// undefined values are skipped (not objects or strings)
|
|
267
|
+
expect(flattenColors(colors)).toEqual({
|
|
268
|
+
red: "#ff0000",
|
|
269
|
+
green: "#00ff00",
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should handle special color keywords", () => {
|
|
274
|
+
const colors = {
|
|
275
|
+
transparent: "transparent",
|
|
276
|
+
current: "currentColor",
|
|
277
|
+
inherit: "inherit",
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
expect(flattenColors(colors)).toEqual({
|
|
281
|
+
transparent: "transparent",
|
|
282
|
+
current: "currentColor",
|
|
283
|
+
inherit: "inherit",
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it("should handle RGB/RGBA color values", () => {
|
|
288
|
+
const colors = {
|
|
289
|
+
primary: "rgb(255, 0, 0)",
|
|
290
|
+
secondary: "rgba(0, 255, 0, 0.5)",
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
expect(flattenColors(colors)).toEqual({
|
|
294
|
+
primary: "rgb(255, 0, 0)",
|
|
295
|
+
secondary: "rgba(0, 255, 0, 0.5)",
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it("should handle very deeply nested structures (stress test)", () => {
|
|
300
|
+
const colors = {
|
|
301
|
+
level1: {
|
|
302
|
+
level2: {
|
|
303
|
+
level3: {
|
|
304
|
+
level4: {
|
|
305
|
+
level5: "#ff0000",
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
expect(flattenColors(colors)).toEqual({
|
|
313
|
+
"level1-level2-level3-level4-level5": "#ff0000",
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it("should handle camelCase keys", () => {
|
|
318
|
+
const colors = {
|
|
319
|
+
brandPrimary: "#ff0000",
|
|
320
|
+
accentColor: {
|
|
321
|
+
lightShade: "#ffcccc",
|
|
322
|
+
darkShade: "#cc0000",
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
expect(flattenColors(colors)).toEqual({
|
|
327
|
+
brandPrimary: "#ff0000",
|
|
328
|
+
"accentColor-lightShade": "#ffcccc",
|
|
329
|
+
"accentColor-darkShade": "#cc0000",
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("should produce consistent output", () => {
|
|
334
|
+
const colors = {
|
|
335
|
+
brand: {
|
|
336
|
+
primary: "#ff6b6b",
|
|
337
|
+
secondary: "#4ecdc4",
|
|
338
|
+
},
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const result1 = flattenColors(colors);
|
|
342
|
+
const result2 = flattenColors(colors);
|
|
343
|
+
const result3 = flattenColors(colors);
|
|
344
|
+
|
|
345
|
+
expect(result1).toEqual(result2);
|
|
346
|
+
expect(result2).toEqual(result3);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("should maintain key order (insertion order)", () => {
|
|
350
|
+
const colors = {
|
|
351
|
+
z: "#000001",
|
|
352
|
+
a: "#000002",
|
|
353
|
+
m: "#000003",
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
const flattened = flattenColors(colors);
|
|
357
|
+
const keys = Object.keys(flattened);
|
|
358
|
+
|
|
359
|
+
expect(keys).toEqual(["z", "a", "m"]);
|
|
360
|
+
});
|
|
361
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type representing a nested color structure that can be arbitrarily deep
|
|
3
|
+
*/
|
|
4
|
+
type NestedColors = {
|
|
5
|
+
[key: string]: string | NestedColors;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Flatten nested color objects into flat key-value map
|
|
10
|
+
* Example: { brand: { light: '#fff', dark: '#000' } } => { 'brand-light': '#fff', 'brand-dark': '#000' }
|
|
11
|
+
*
|
|
12
|
+
* @param colors - Nested color object where values can be strings or objects
|
|
13
|
+
* @param prefix - Optional prefix for nested keys (used for recursion)
|
|
14
|
+
* @returns Flattened color map with dash-separated keys
|
|
15
|
+
*/
|
|
16
|
+
export function flattenColors(colors: NestedColors, prefix = ""): Record<string, string> {
|
|
17
|
+
const result: Record<string, string> = {};
|
|
18
|
+
|
|
19
|
+
for (const [key, value] of Object.entries(colors)) {
|
|
20
|
+
const newKey = prefix ? `${prefix}-${key}` : key;
|
|
21
|
+
|
|
22
|
+
if (typeof value === "string") {
|
|
23
|
+
result[newKey] = value;
|
|
24
|
+
} else if (typeof value === "object" && value !== null) {
|
|
25
|
+
// Recursively flatten nested objects
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
27
|
+
Object.assign(result, flattenColors(value as NestedColors, newKey));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return result;
|
|
32
|
+
}
|