@recursica/mantine-adapter 0.9.2 → 0.9.4

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.
Files changed (48) hide show
  1. package/dist/adapter/generateBorderRadiusType.d.ts +3 -0
  2. package/dist/adapter/generateBorderRadiusType.d.ts.map +1 -0
  3. package/dist/adapter/generateColorTypes.d.ts +6 -0
  4. package/dist/adapter/generateColorTypes.d.ts.map +1 -0
  5. package/dist/adapter/generateIcons.d.ts +8 -0
  6. package/dist/adapter/generateIcons.d.ts.map +1 -0
  7. package/dist/adapter/generateMantineTheme.d.ts +19 -0
  8. package/dist/adapter/generateMantineTheme.d.ts.map +1 -0
  9. package/dist/adapter/generatePrettierignore.d.ts +3 -0
  10. package/dist/adapter/generatePrettierignore.d.ts.map +1 -0
  11. package/dist/adapter/generateRecursicaObject.d.ts +7 -0
  12. package/dist/adapter/generateRecursicaObject.d.ts.map +1 -0
  13. package/dist/adapter/generateRecursicaThemes.d.ts +12 -0
  14. package/dist/adapter/generateRecursicaThemes.d.ts.map +1 -0
  15. package/dist/adapter/generateRecursicaTokens.d.ts +3 -0
  16. package/dist/adapter/generateRecursicaTokens.d.ts.map +1 -0
  17. package/dist/adapter/generateSpacersType.d.ts +3 -0
  18. package/dist/adapter/generateSpacersType.d.ts.map +1 -0
  19. package/dist/adapter/generateUiKit.d.ts +8 -0
  20. package/dist/adapter/generateUiKit.d.ts.map +1 -0
  21. package/dist/adapter/generateVanillaExtractThemes.d.ts +12 -0
  22. package/dist/adapter/generateVanillaExtractThemes.d.ts.map +1 -0
  23. package/dist/adapter/index.d.ts +44 -0
  24. package/dist/adapter/index.d.ts.map +1 -0
  25. package/dist/cli.d.ts +6 -0
  26. package/dist/cli.d.ts.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +921 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/main.cjs +928 -0
  32. package/dist/main.cjs.map +1 -0
  33. package/dist/main.d.ts +2 -0
  34. package/dist/main.d.ts.map +1 -0
  35. package/dist/main.js +926 -0
  36. package/dist/main.js.map +1 -0
  37. package/dist/shared/processTokens.d.ts +22 -0
  38. package/dist/shared/processTokens.d.ts.map +1 -0
  39. package/dist/types.d.ts +62 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/utils/fileCheck.d.ts +8 -0
  42. package/dist/utils/fileCheck.d.ts.map +1 -0
  43. package/dist/utils/loadConfig.d.ts +24 -0
  44. package/dist/utils/loadConfig.d.ts.map +1 -0
  45. package/dist/webworker.d.ts +2 -0
  46. package/dist/webworker.d.ts.map +1 -0
  47. package/dist/webworker.js +791 -0
  48. package/package.json +1 -1
package/dist/main.cjs ADDED
@@ -0,0 +1,928 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var fs = require('fs');
5
+ var path = require('path');
6
+
7
+ /**
8
+ * Checks if a given directory contains files with either theme-tokens or ui-kit suffix
9
+ * @param directoryPath - The path to check for files
10
+ * @returns FileCheckResult - Object containing boolean result and array of matching files with full paths
11
+ */
12
+ function hasThemeOrKitFiles(directoryPath) {
13
+ try {
14
+ const files = fs.readdirSync(directoryPath);
15
+ const matchingFiles = files.find((file) => {
16
+ const fileName = file.toLowerCase();
17
+ return fileName === "recursica-bundle.json";
18
+ });
19
+ return matchingFiles ? path.join(directoryPath, matchingFiles) : undefined;
20
+ }
21
+ catch (error) {
22
+ console.error(`Error checking directory ${directoryPath}:`, error);
23
+ return undefined;
24
+ }
25
+ }
26
+ function hasIconsJsonFiles(directoryPath) {
27
+ try {
28
+ const files = fs.readdirSync(directoryPath);
29
+ const matchingFiles = files
30
+ .filter((file) => {
31
+ const fileName = file.toLowerCase();
32
+ return fileName === "recursica-icons.json";
33
+ })
34
+ .map((file) => path.join(directoryPath, file));
35
+ return matchingFiles.length > 0 ? matchingFiles[0] : undefined;
36
+ }
37
+ catch (error) {
38
+ console.error(`Error checking directory ${directoryPath}:`, error);
39
+ return undefined;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Loads and validates the configuration from recursicaConfig.json
45
+ *
46
+ * @throws {Error} If the config file is not found or required fields are missing
47
+ * @returns {Object} Configuration object with the following properties:
48
+ * - jsons: Path to the themes-tokens and ui-kit directories
49
+ * - srcPath: Path to the source directory
50
+ * - project: Project name
51
+ */
52
+ function loadConfig() {
53
+ let rootPath = getRootPath();
54
+ const configPath = path.join(rootPath, "recursica.json");
55
+ if (!fs.existsSync(configPath)) {
56
+ throw new Error("Config file not found at: " + configPath);
57
+ }
58
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
59
+ if (typeof config.project === "object" && config.project?.root) {
60
+ rootPath = path.join(rootPath, config.project.root);
61
+ }
62
+ const bundledJson = hasThemeOrKitFiles(rootPath);
63
+ const iconsJson = hasIconsJsonFiles(rootPath);
64
+ const project = config.project;
65
+ if (!project) {
66
+ throw new Error("project is required in config file");
67
+ }
68
+ return {
69
+ rootPath,
70
+ srcPath: path.join(rootPath, "src"),
71
+ project,
72
+ bundledJson,
73
+ iconsJson,
74
+ overrides: config.overrides,
75
+ iconsConfig: config.icons,
76
+ };
77
+ }
78
+ function getRootPath() {
79
+ // recursively search for the package.json file starting from the current working directory
80
+ let currentDir = process.cwd();
81
+ let level = 0;
82
+ while (!fs.existsSync(path.join(currentDir, "recursica.json"))) {
83
+ currentDir = path.join(currentDir, "..");
84
+ level++;
85
+ if (level > 10) {
86
+ throw new Error("Could not find recursica.json");
87
+ }
88
+ }
89
+ return currentDir;
90
+ }
91
+
92
+ /**
93
+ * Type guard function to check if a token is a FontFamilyToken
94
+ *
95
+ * @param token - The token to check
96
+ * @returns True if the token has fontFamily and variableName properties, indicating it's a FontFamilyToken
97
+ */
98
+ function isFontFamilyToken(token) {
99
+ return "fontFamily" in token && "variableName" in token;
100
+ }
101
+ /**
102
+ * Type guard function to check if a token is an EffectToken
103
+ *
104
+ * @param token - The token to check
105
+ * @returns True if the token has effects and variableName properties, indicating it's an EffectToken
106
+ */
107
+ function isEffectToken(token) {
108
+ return "effects" in token && "variableName" in token;
109
+ }
110
+ /**
111
+ * Type guard function to check if a token is a basic Token (color or float)
112
+ *
113
+ * @param token - The token to check
114
+ * @returns True if the token has mode, type, name, and value properties, indicating it's a basic Token
115
+ */
116
+ function isColorOrFloatToken(token) {
117
+ return ("mode" in token && "type" in token && "name" in token && "value" in token);
118
+ }
119
+
120
+ function autoGeneratedFile() {
121
+ return `/* prettier-ignore */
122
+ /* eslint-disable */
123
+ /* tslint:disable */
124
+ /*
125
+ Auto-generated by Recursica.
126
+ Do NOT edit these files directly\n
127
+ For more information about Recursica, go to https://recursica.com
128
+ */
129
+ `;
130
+ }
131
+
132
+ function capitalize(str) {
133
+ return str.replace(/-/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
134
+ }
135
+
136
+ class ProcessTokens {
137
+ constructor(overrides) {
138
+ this.tokens = {};
139
+ this.themes = {};
140
+ this.breakpoints = {};
141
+ this.colors = [];
142
+ this.spacers = [];
143
+ this.borderRadius = [];
144
+ this.uiKit = {};
145
+ this.processValue = (target, token) => {
146
+ if (typeof token.value === "string") {
147
+ target[token.name] = token.value;
148
+ return true;
149
+ }
150
+ if (typeof token.value === "number") {
151
+ target[token.name] = `${token.value}px`;
152
+ return true;
153
+ }
154
+ if (typeof token.value === "object") {
155
+ target[token.name] = token.value;
156
+ return true;
157
+ }
158
+ return false;
159
+ };
160
+ this.overrides = overrides;
161
+ }
162
+ processTokenValue(token, modeName, jsonThemeName) {
163
+ if (token.collection === "Breakpoints") {
164
+ this.processValue(this.breakpoints, token);
165
+ // Add breakpoints to uiKit with 'breakpoints/' prefix
166
+ const uiKitTarget = {};
167
+ this.processValue(uiKitTarget, token);
168
+ Object.entries(uiKitTarget).forEach(([key, value]) => {
169
+ // Ensure we only store string values
170
+ if (typeof value === "string") {
171
+ this.uiKit[`breakpoint/${key}`] = value;
172
+ }
173
+ else if (typeof value === "number") {
174
+ this.uiKit[`breakpoint/${key}`] = `${value.toString()}px`;
175
+ }
176
+ });
177
+ }
178
+ else if (token.collection === "UI Kit") {
179
+ this.processValue(this.uiKit, token);
180
+ }
181
+ else if (token.collection === "Tokens") {
182
+ this.processValue(this.tokens, token);
183
+ }
184
+ else {
185
+ if (!jsonThemeName)
186
+ return;
187
+ if (!this.themes[jsonThemeName])
188
+ this.themes[jsonThemeName] = {};
189
+ if (!this.themes[jsonThemeName][modeName])
190
+ this.themes[jsonThemeName][modeName] = {};
191
+ this.processValue(this.themes[jsonThemeName][modeName], token);
192
+ }
193
+ }
194
+ processTokens(variables, jsonThemeName) {
195
+ // Process tokens collection
196
+ for (const token of Object.values(variables)) {
197
+ if (isFontFamilyToken(token)) {
198
+ if (!jsonThemeName)
199
+ continue;
200
+ if (!this.tokens[jsonThemeName])
201
+ this.tokens[jsonThemeName] = {};
202
+ if (typeof this.tokens[jsonThemeName] !== "object")
203
+ this.tokens[jsonThemeName] = {};
204
+ this.tokens[jsonThemeName][`typography/${token.variableName}`] =
205
+ this.overrides?.fontFamily?.[token.fontFamily] ?? token.fontFamily;
206
+ this.tokens[jsonThemeName][`typography/${token.variableName}-size`] =
207
+ `${token.fontSize.toString()}px`;
208
+ // check if overrides.fontWeight is defined
209
+ if (this.overrides?.fontWeight) {
210
+ const weight = this.overrides.fontWeight.find((weight) => weight.alias === token.fontWeight.alias &&
211
+ weight.fontFamily === token.fontFamily);
212
+ // check if there's a weight that matches the alias and fontFamily
213
+ // if there is, use the value from the overrides
214
+ // if there isn't, use the value from the token
215
+ if (weight) {
216
+ this.tokens[jsonThemeName][`typography/${token.variableName}-weight`] = weight.value.toString();
217
+ }
218
+ else {
219
+ this.tokens[jsonThemeName][`typography/${token.variableName}-weight`] = token.fontWeight.value.toString();
220
+ }
221
+ }
222
+ else {
223
+ this.tokens[jsonThemeName][`typography/${token.variableName}-weight`] = token.fontWeight.value.toString();
224
+ }
225
+ if (token.lineHeight.unit === "PERCENT") {
226
+ this.tokens[jsonThemeName][`typography/${token.variableName}-line-height`] = `${token.lineHeight.value.toString()}%`;
227
+ }
228
+ else {
229
+ this.tokens[jsonThemeName][`typography/${token.variableName}-line-height`] = "1.2";
230
+ }
231
+ this.tokens[jsonThemeName][`typography/${token.variableName}-letter-spacing`] =
232
+ token.letterSpacing.unit === "PIXELS"
233
+ ? `${token.letterSpacing.value.toString()}px`
234
+ : `${token.letterSpacing.value.toString()}%`;
235
+ this.tokens[jsonThemeName][`typography/${token.variableName}-text-case`] = token.textCase;
236
+ this.tokens[jsonThemeName][`typography/${token.variableName}-text-decoration`] = token.textDecoration;
237
+ continue;
238
+ }
239
+ if (isEffectToken(token)) {
240
+ const effectValue = [];
241
+ token.effects.forEach((effect) => {
242
+ const { color: { r, g, b, a }, offset: { x, y }, radius, spread, } = effect;
243
+ effectValue.push(`${x.toString()}px ${y.toString()}px ${radius.toString()}px ${spread.toString()}px rgba(${r.toString()}, ${g.toString()}, ${b.toString()}, ${a.toString()})`);
244
+ });
245
+ this.tokens[`effect/${token.variableName}`] = effectValue.join(", ");
246
+ continue;
247
+ }
248
+ if (isColorOrFloatToken(token)) {
249
+ const modeName = capitalize(token.mode)
250
+ .replace(/[()/]/g, "-")
251
+ .replace(/\s/g, "")
252
+ .replace(/-$/, "");
253
+ if (modeName !== "mode1")
254
+ this.themes[modeName] = {};
255
+ if (token.type === "color" && !this.colors.includes(token.name)) {
256
+ this.colors.push(token.name);
257
+ }
258
+ if (token.name.startsWith("size/spacer/") &&
259
+ !this.spacers.includes(token.name)) {
260
+ this.spacers.push(token.name);
261
+ }
262
+ if (token.name.startsWith("size/border-radius/") &&
263
+ !this.borderRadius.includes(token.name)) {
264
+ this.borderRadius.push(token.name);
265
+ }
266
+ this.processTokenValue(token, modeName, jsonThemeName);
267
+ }
268
+ else {
269
+ console.warn(`${JSON.stringify(token, null, 2)} could not be processed`);
270
+ }
271
+ }
272
+ }
273
+ }
274
+
275
+ function parseValue(value, recursicaTokens) {
276
+ if (typeof value === "object") {
277
+ if (value.collection === "Tokens") {
278
+ return `${recursicaTokens}["${value.name}"]`;
279
+ }
280
+ if (value.collection === "Themes") {
281
+ return `themeVars["${value.name}"]`;
282
+ }
283
+ }
284
+ else if (!isNaN(Number(value))) {
285
+ return `"${value}"`;
286
+ }
287
+ return `"${value.toString()}"`;
288
+ }
289
+ function generateTypeDefinitions(themeDef) {
290
+ // Extract all unique theme modes from themeDef
291
+ const allThemeModes = new Set();
292
+ Object.values(themeDef).forEach((themeVariants) => {
293
+ Object.keys(themeVariants).forEach((mode) => {
294
+ allThemeModes.add(mode);
295
+ });
296
+ });
297
+ // Generate the ThemeVariant interface dynamically
298
+ const themeVariantProperties = Array.from(allThemeModes)
299
+ .sort() // Sort for consistent output
300
+ .map((mode) => ` ${mode}: string;`)
301
+ .join("\n");
302
+ return `${autoGeneratedFile()}
303
+ import { THEMES } from "./RecursicaThemes";
304
+
305
+ export interface ThemeVariant {
306
+ ${themeVariantProperties}
307
+ }
308
+
309
+ // TypeScript will automatically infer this as a union of literal types
310
+ export type ThemeType = typeof THEMES[keyof typeof THEMES];
311
+
312
+ export type ThemeDictionary = Record<ThemeType, ThemeVariant>;
313
+ `;
314
+ }
315
+ function generateVanillaExtractThemes(tokens, themes, recursicaTokensFilename, { outputPath, project }) {
316
+ const themesContent = [];
317
+ // Contract tokens
318
+ const projectName = typeof project === "string" ? project : (project.name ?? "Recursica");
319
+ const themeContractFilename = `Recursica${projectName}ContractTheme.css`;
320
+ const contractThemeOutputPath = outputPath + "/" + `${themeContractFilename}.ts`;
321
+ const contractTokens = {};
322
+ const themeDef = {};
323
+ for (const [rawThemeName, currentTheme] of Object.entries(themes)) {
324
+ for (const [key, theme] of Object.entries(currentTheme)) {
325
+ const currentThemeName = capitalize(rawThemeName);
326
+ const recursicaTokens = `Recursica${projectName}Tokens`;
327
+ const themeKey = key.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
328
+ const themeName = `${currentThemeName}${themeKey}Theme`;
329
+ if (!themeDef[currentThemeName]) {
330
+ themeDef[currentThemeName] = {};
331
+ }
332
+ themeDef[currentThemeName][themeKey] = themeName;
333
+ const generatedThemeContent = `${autoGeneratedFile()}
334
+ import { createTheme } from '@vanilla-extract/css';
335
+
336
+ import { themeVars } from './${themeContractFilename.replace(".ts", "")}'
337
+ import { ${recursicaTokens} } from './${recursicaTokensFilename.replace(".ts", "")}'
338
+
339
+ export const ${themeName} = createTheme(themeVars,{
340
+ ${Object.entries(theme)
341
+ .map(([key, value]) => {
342
+ contractTokens[key] = null;
343
+ return `'${key}': ${parseValue(value, recursicaTokens)}`;
344
+ })
345
+ .join(",\n\t")},
346
+ ${Object.entries(tokens?.[rawThemeName] ?? {})
347
+ .map(([key, value]) => {
348
+ contractTokens[key] = null;
349
+ return `'${key}': ${parseValue(value, recursicaTokens)}`;
350
+ })
351
+ .join(",\n\t")}
352
+ })`;
353
+ themesContent.push({
354
+ name: themeName,
355
+ content: generatedThemeContent,
356
+ });
357
+ }
358
+ }
359
+ let themesFileContent = autoGeneratedFile();
360
+ const vanillaExtractThemes = [];
361
+ for (const theme of themesContent) {
362
+ const themeName = `Recursica${projectName}${theme.name}`;
363
+ const autoGeneratedThemeFilename = `${themeName}.css.ts`;
364
+ const themeFilePath = outputPath + "/" + autoGeneratedThemeFilename;
365
+ vanillaExtractThemes.push({
366
+ content: theme.content,
367
+ path: themeFilePath,
368
+ filename: autoGeneratedThemeFilename,
369
+ });
370
+ // generate a theme.css.ts where we import all the themes using just 1 variables (1 export)
371
+ themesFileContent += `export { ${theme.name} } from './${autoGeneratedThemeFilename.replace(".ts", "")}';\n`;
372
+ themesFileContent += `import { ${theme.name} } from './${autoGeneratedThemeFilename.replace(".ts", "")}';\n`;
373
+ }
374
+ themesFileContent += `\nexport const Themes = {
375
+ ${Object.entries(themeDef)
376
+ .map(([key, value]) => `'${key}': {
377
+ ${Object.entries(value)
378
+ .map(([key, value]) => `'${key}': ${value}`)
379
+ .join(",\n\t\t")}`)
380
+ .join("\n\t},\n\t")}
381
+ }
382
+ }`;
383
+ // create the themes.ts file
384
+ const availableThemesContent = `${autoGeneratedFile()}
385
+ export const AvailableThemes = [${themesContent.map((theme) => `"${theme.name}"`).join(", ")}] as const;
386
+ export type AvailableThemesType = (typeof AvailableThemes)[number];
387
+ `;
388
+ const availableThemesPath = outputPath + "/types.ts";
389
+ const themeContractContent = `${autoGeneratedFile()}
390
+ import { createThemeContract } from '@vanilla-extract/css';
391
+
392
+ export const themeVars = createThemeContract(${JSON.stringify(contractTokens, null, 2)});
393
+ `;
394
+ const themesFilename = `Recursica${projectName}Themes.css.ts`;
395
+ const themesFilePath = outputPath + "/" + themesFilename;
396
+ // Generate type definitions in types.d.ts
397
+ const typeDefinitionsContent = generateTypeDefinitions(themeDef);
398
+ const typesPath = outputPath + "/types.d.ts";
399
+ return {
400
+ typeDefinitions: {
401
+ content: typeDefinitionsContent,
402
+ path: typesPath,
403
+ filename: "types.d.ts",
404
+ },
405
+ themesFileContent: {
406
+ content: themesFileContent,
407
+ path: themesFilePath,
408
+ filename: themesFilename,
409
+ },
410
+ availableThemes: {
411
+ content: availableThemesContent,
412
+ path: availableThemesPath,
413
+ filename: "types.ts",
414
+ },
415
+ vanillaExtractThemes,
416
+ themeContract: {
417
+ content: themeContractContent,
418
+ path: contractThemeOutputPath,
419
+ filename: themeContractFilename,
420
+ },
421
+ contractTokens,
422
+ };
423
+ }
424
+
425
+ function generateRecursicaTokens(baseTokens, { outputPath, project }) {
426
+ const projectName = typeof project === "string" ? project : (project.name ?? "Recursica");
427
+ const recursicaTokensFilename = `Recursica${projectName}Tokens.ts`;
428
+ const recursicaTokensPath = outputPath + "/" + recursicaTokensFilename;
429
+ const recursicaTokensContent = `${autoGeneratedFile()}
430
+ export const Recursica${projectName}Tokens = {
431
+ ${Object.entries(baseTokens)
432
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
433
+ .filter(([_, value]) => typeof value === "string")
434
+ .map(([key, value]) => `"${key}": "${value}"`)
435
+ .join(",\n ")}
436
+ };
437
+ `;
438
+ return {
439
+ content: recursicaTokensContent,
440
+ path: recursicaTokensPath,
441
+ filename: recursicaTokensFilename,
442
+ };
443
+ }
444
+
445
+ function generateUiKit(uiKit, { recursicaTokensFilename, themeContractFilename }, { outputPath, project }) {
446
+ const projectName = typeof project === "string" ? project : (project.name ?? "Recursica");
447
+ const uiKitFilename = `Recursica${projectName}UiKit.ts`;
448
+ const uiKitPath = outputPath + "/" + uiKitFilename;
449
+ const recursicaTokens = `Recursica${projectName}Tokens`;
450
+ const uiKitContent = `${autoGeneratedFile()}
451
+ import { themeVars } from './${themeContractFilename.replace(".ts", "")}'
452
+ import { ${recursicaTokens} } from './${recursicaTokensFilename.replace(".ts", "")}'
453
+
454
+ export const uiKit = {
455
+ ${Object.entries(uiKit)
456
+ .map(([key, value]) => `'${key}': ${parseValue(value, recursicaTokens)}`)
457
+ .join(",\n\t")}\n\t}`;
458
+ return {
459
+ content: uiKitContent,
460
+ path: uiKitPath,
461
+ filename: uiKitFilename,
462
+ };
463
+ }
464
+
465
+ function parseKey(key) {
466
+ return key.replaceAll("/", "-");
467
+ }
468
+ function generateMantineTheme({ mantineThemeOverride, tokens, breakpoints, contractTokens: { tokens: contractTokens, filename: contractFilename }, exportingProps: { outputPath, project, rootPath }, }) {
469
+ const themeTokens = {
470
+ colors: {},
471
+ radius: {},
472
+ fontSizes: {},
473
+ primaryColor: mantineThemeOverride?.["1-scale"],
474
+ white: mantineThemeOverride?.background,
475
+ };
476
+ for (const [key, value] of Object.entries(tokens)) {
477
+ if (typeof value === "object")
478
+ continue;
479
+ if (key.includes("border-radius")) {
480
+ themeTokens.radius[parseKey(key)] = value;
481
+ }
482
+ if (key.includes("font/size")) {
483
+ themeTokens.fontSizes[parseKey(key)] = `"${value}"`;
484
+ }
485
+ }
486
+ for (const [key] of Object.entries(contractTokens)) {
487
+ if (key.includes("color/") || key.includes("color-on/")) {
488
+ themeTokens.colors[parseKey(key)] = `themeVars['${key}']`;
489
+ }
490
+ if (/font\/(\w+)\/size/.test(key)) {
491
+ themeTokens.fontSizes[parseKey(key)] = `themeVars['${key}']`;
492
+ }
493
+ }
494
+ const postCssFilename = "postcss.config.cjs";
495
+ let postCssContent = `${autoGeneratedFile()}\n`;
496
+ postCssContent += `module.exports = {
497
+ plugins: {
498
+ 'postcss-preset-mantine': {},
499
+ 'postcss-simple-vars': {
500
+ variables: {`;
501
+ for (const [key, value] of Object.entries(breakpoints)) {
502
+ postCssContent += `\n\t\t\t\t'mantine-breakpoint-${key}': '${value}',`;
503
+ }
504
+ postCssContent += `
505
+ }
506
+ }
507
+ }
508
+ }`;
509
+ const postCssFileContent = {
510
+ content: postCssContent,
511
+ path: rootPath ? rootPath + "/" + postCssFilename : postCssFilename,
512
+ filename: postCssFilename,
513
+ };
514
+ const fileContent = `${autoGeneratedFile()}
515
+ import { colorsTuple, createTheme } from '@mantine/core'
516
+ import { themeVars } from './${contractFilename.replace(".ts", "")}'
517
+
518
+ export const mantineTheme = createTheme({
519
+ ${themeTokens.primaryColor ? `primaryColor: ${themeTokens.primaryColor},` : ""}
520
+ ${themeTokens.white ? `white: ${themeTokens.white},` : ""}
521
+ breakpoints: {
522
+ ${Object.entries(breakpoints)
523
+ .map(([key, value]) => `'${key}': '${value}'`)
524
+ .join(",\n\t\t")}
525
+ },
526
+ colors: {
527
+ ${Object.entries(themeTokens.colors)
528
+ .map(([key, value]) => `"${key}": colorsTuple(${value})`)
529
+ .join(",\n\t\t")}
530
+ },
531
+ radius: {
532
+ ${Object.entries(themeTokens.radius)
533
+ .map(([key, value]) => `"${key}": "${value}"`)
534
+ .join(",\n\t\t")}
535
+ },
536
+ fontSizes: {
537
+ ${Object.entries(themeTokens.fontSizes)
538
+ .map(([key, value]) => `"${key}": ${value}`)
539
+ .join(",\n\t\t")}
540
+ }
541
+ })`;
542
+ const projectName = typeof project === "string" ? project : (project.name ?? "Recursica");
543
+ const filename = `Recursica${projectName}MantineTheme.ts`;
544
+ const mantineThemeFileContent = {
545
+ content: fileContent,
546
+ path: outputPath + "/" + filename,
547
+ filename,
548
+ };
549
+ return { mantineTheme: mantineThemeFileContent, postCss: postCssFileContent };
550
+ }
551
+
552
+ function createRecursicaObject(project, outputPath) {
553
+ const projectName = typeof project === "string" ? project : (project.name ?? "Recursica");
554
+ const tokens = `Recursica${projectName}Tokens`;
555
+ const contract = `Recursica${projectName}ContractTheme`;
556
+ const uiKit = `Recursica${projectName}UiKit`;
557
+ const recursicaObjectContent = `${autoGeneratedFile()}
558
+ import { ${tokens} } from './${tokens}';
559
+ import { themeVars } from './${contract}.css';
560
+ import { uiKit } from './${uiKit}';
561
+
562
+ export const recursica = {
563
+ ...uiKit,
564
+ ...themeVars,
565
+ ...${tokens},
566
+ }
567
+ `;
568
+ return {
569
+ content: recursicaObjectContent,
570
+ path: outputPath + "/Recursica.ts",
571
+ filename: "Recursica.ts",
572
+ };
573
+ }
574
+
575
+ function generateColorsType(colorTokens, outputPath) {
576
+ const colorsType = `${autoGeneratedFile()}
577
+ export type RecursicaColors = \n\t"${colorTokens.join('" |\n\t"')}";\n`;
578
+ return {
579
+ content: colorsType,
580
+ path: `${outputPath}/RecursicaColorsType.ts`,
581
+ filename: "RecursicaColorsType.ts",
582
+ };
583
+ }
584
+
585
+ function generateIcons(icons, srcPath, config) {
586
+ let iconsPath;
587
+ if (!config?.output) {
588
+ iconsPath = srcPath + "/components" + "/Icons";
589
+ }
590
+ else {
591
+ iconsPath = srcPath + "/" + config.output;
592
+ }
593
+ const svgPath = iconsPath + "/Svg";
594
+ const exportedIcons = [];
595
+ // Generate svg files
596
+ for (const [rawIconName, iconPath] of Object.entries(icons)) {
597
+ const [iconName, variant] = rawIconName.split("[");
598
+ let cleanIconName = iconName.replaceAll("-", "_");
599
+ // check if the iconName is in the names array, if not, skip
600
+ if (config?.include) {
601
+ if (!config?.include?.names?.includes(cleanIconName)) {
602
+ continue;
603
+ }
604
+ }
605
+ // detect if the iconName starts with a number, if so, add an underscore to the beginning
606
+ if (cleanIconName.match(/^\d/)) {
607
+ cleanIconName = `_${cleanIconName}`;
608
+ }
609
+ const cleanVariant = variant.replace("]", "").replace("Style=", "");
610
+ const codedVariant = cleanVariant.replaceAll(" ", "_");
611
+ // check if the codedVariant is in the variants array, if not, skip
612
+ if (config?.include) {
613
+ if (!config?.include?.variants?.includes(codedVariant)) {
614
+ continue;
615
+ }
616
+ }
617
+ const finalIconName = `${cleanIconName}_${codedVariant}`;
618
+ exportedIcons.push({
619
+ content: iconPath
620
+ .replaceAll('fill="black"', "")
621
+ .replaceAll('fill="none"', ""),
622
+ path: `${svgPath}/${finalIconName}.svg`,
623
+ filename: `${finalIconName}`,
624
+ });
625
+ }
626
+ // Generate icon exports file
627
+ const exportsPath = iconsPath + "/icon_exports.ts";
628
+ let exportsContent = `${autoGeneratedFile()}
629
+ /// <reference types="vite-plugin-svgr/client" />\n`;
630
+ for (const icon of exportedIcons) {
631
+ exportsContent += `import ${icon.filename} from './Svg/${icon.filename}.svg?react';\n`;
632
+ exportsContent += `export { ${icon.filename} };\n`;
633
+ }
634
+ // Generate icon map file
635
+ const mapPath = iconsPath + "/icon_resource_map.ts";
636
+ let mapContent = `${autoGeneratedFile()}\nimport * as IconExports from './icon_exports';\n\n`;
637
+ mapContent += "export const IconResourceMap = {";
638
+ mapContent += exportedIcons
639
+ .map((icon) => `\n\t'${icon.filename}': IconExports.${icon.filename},`)
640
+ .join("");
641
+ mapContent += "\n};\n";
642
+ return {
643
+ exportedIcons,
644
+ iconExports: {
645
+ content: exportsContent,
646
+ path: exportsPath,
647
+ filename: "icon_exports.ts",
648
+ },
649
+ iconResourceMap: {
650
+ content: mapContent,
651
+ path: mapPath,
652
+ filename: "icon_resource_map.ts",
653
+ },
654
+ };
655
+ }
656
+
657
+ function generateSpacersType(spacerTokens, outputPath) {
658
+ const spacersType = `${autoGeneratedFile()}
659
+ export type RecursicaSpacersType = \n\t"${spacerTokens.join('" |\n\t"')}";\n`;
660
+ return {
661
+ content: spacersType,
662
+ path: `${outputPath}/RecursicaSpacersType.ts`,
663
+ filename: "RecursicaSpacersType.ts",
664
+ };
665
+ }
666
+
667
+ function generateBorderRadiusType(borderRadius, outputPath) {
668
+ const borderRadiusTypeContent = `${autoGeneratedFile()}
669
+ export type RecursicaBorderRadiusType = ${borderRadius
670
+ .map((key) => `'${key}'`)
671
+ .join(" | ")};
672
+ `;
673
+ return {
674
+ content: borderRadiusTypeContent,
675
+ path: `${outputPath}/RecursicaBorderRadiusType.ts`,
676
+ filename: "RecursicaBorderRadiusType.ts",
677
+ };
678
+ }
679
+
680
+ /**
681
+ * Generates the RecursicaThemes.ts file that contains the THEMES constant
682
+ * based on the theme dictionary
683
+ */
684
+ function generateRecursicaThemes({ outputPath, themes, }) {
685
+ const themeDef = {};
686
+ // Build themeDef object similar to generateVanillaExtractThemes
687
+ for (const [rawThemeName, currentTheme] of Object.entries(themes)) {
688
+ for (const [key] of Object.entries(currentTheme)) {
689
+ const currentThemeName = capitalize(rawThemeName);
690
+ const themeKey = key.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
691
+ themeDef[currentThemeName] ?? (themeDef[currentThemeName] = {});
692
+ themeDef[currentThemeName][themeKey] = currentThemeName;
693
+ }
694
+ }
695
+ const content = `/* prettier-ignore */
696
+ /* eslint-disable */
697
+ /* tslint:disable */
698
+ /*
699
+ Auto-generated by Recursica.
700
+ Do NOT edit these files directly
701
+
702
+ For more information about Recursica, go to https://recursica.com
703
+ */
704
+
705
+ // Auto-generated THEMES constant from ThemeType
706
+ export const THEMES = {
707
+ ${Object.entries(themeDef)
708
+ .map(([key]) => ` ${key}: '${key}'`)
709
+ .join(",\n")}
710
+ } as const;
711
+ `;
712
+ return {
713
+ content,
714
+ path: outputPath + "/RecursicaThemes.ts",
715
+ filename: "RecursicaThemes.ts",
716
+ };
717
+ }
718
+
719
+ function generatePrettierignore() {
720
+ return {
721
+ filename: ".prettierignore",
722
+ path: ".prettierignore",
723
+ content: `recursica/
724
+ recursica.json
725
+ recursica-bundle.json
726
+ recursica-icons.json
727
+ icon_exports.ts
728
+ icon_resource_map.ts`,
729
+ };
730
+ }
731
+
732
+ function runAdapter({ rootPath, overrides, srcPath, project, icons, iconsConfig, processTokens, }) {
733
+ const outputPath = srcPath + "/recursica";
734
+ const recursicaTokens = generateRecursicaTokens(processTokens.tokens, {
735
+ outputPath,
736
+ project,
737
+ });
738
+ const vanillaExtractThemes = generateVanillaExtractThemes(processTokens.tokens, processTokens.themes, recursicaTokens.filename, {
739
+ outputPath,
740
+ project,
741
+ });
742
+ const mantineTheme = generateMantineTheme({
743
+ mantineThemeOverride: overrides?.mantineTheme,
744
+ tokens: processTokens.tokens,
745
+ breakpoints: processTokens.breakpoints,
746
+ contractTokens: {
747
+ tokens: vanillaExtractThemes.contractTokens,
748
+ filename: vanillaExtractThemes.themeContract.filename,
749
+ },
750
+ exportingProps: {
751
+ outputPath,
752
+ project,
753
+ rootPath,
754
+ },
755
+ });
756
+ const uiKitObject = generateUiKit(processTokens.uiKit, {
757
+ recursicaTokensFilename: recursicaTokens.filename,
758
+ themeContractFilename: vanillaExtractThemes.themeContract.filename,
759
+ }, { outputPath, project });
760
+ const recursicaObject = createRecursicaObject(project, outputPath);
761
+ const colorsType = generateColorsType(processTokens.colors, outputPath);
762
+ const spacersType = generateSpacersType(processTokens.spacers, outputPath);
763
+ const borderRadiusType = generateBorderRadiusType(processTokens.borderRadius, outputPath);
764
+ let iconsObject;
765
+ if (icons) {
766
+ iconsObject = generateIcons(icons, srcPath, iconsConfig);
767
+ }
768
+ const recursicaThemes = generateRecursicaThemes({
769
+ outputPath,
770
+ themes: processTokens.themes,
771
+ });
772
+ const prettierignore = generatePrettierignore();
773
+ const fileContents = {
774
+ recursicaTokens,
775
+ vanillaExtractThemes,
776
+ mantineTheme,
777
+ uiKitObject,
778
+ recursicaObject,
779
+ colorsType,
780
+ spacersType,
781
+ borderRadiusType,
782
+ iconsObject,
783
+ recursicaThemes,
784
+ prettierignore,
785
+ };
786
+ return fileContents;
787
+ }
788
+
789
+ /**
790
+ * Processes JSON content and creates ProcessTokens instance
791
+ * This is shared logic between CLI and WebWorker
792
+ */
793
+ function processJsonContent(jsonFileContent, { project, overrides }) {
794
+ const jsonContent = JSON.parse(jsonFileContent);
795
+ const jsonProjectId = jsonContent.projectId;
796
+ if (!jsonProjectId) {
797
+ throw new Error("project-id is required in the json file");
798
+ }
799
+ if (jsonProjectId.toLowerCase() !==
800
+ (typeof project === "string"
801
+ ? project.toLowerCase()
802
+ : project.name?.toLowerCase())) {
803
+ throw new Error("project-id does not match the project in the config file");
804
+ }
805
+ const processTokens = new ProcessTokens(overrides);
806
+ processTokens.processTokens(jsonContent.tokens);
807
+ for (const theme of Object.keys(jsonContent.themes)) {
808
+ processTokens.processTokens(jsonContent.themes[theme], theme);
809
+ }
810
+ processTokens.processTokens(jsonContent.uiKit);
811
+ return processTokens;
812
+ }
813
+ /**
814
+ * Processes icons JSON content and returns icons object
815
+ * This is shared logic between CLI and WebWorker
816
+ */
817
+ function processIcons(iconsJsonContent) {
818
+ const icons = {};
819
+ const iconsJsonParsed = JSON.parse(iconsJsonContent);
820
+ for (const [iconName, iconPath] of Object.entries(iconsJsonParsed)) {
821
+ icons[iconName] = iconPath;
822
+ }
823
+ return icons;
824
+ }
825
+ /**
826
+ * Core adapter processing logic shared between CLI and WebWorker
827
+ * This function handles the main processing workflow
828
+ */
829
+ function processAdapter({ rootPath, bundledJsonContent, project, overrides, srcPath, iconsJsonContent, iconsConfig, }) {
830
+ let icons = {};
831
+ // Process icons if provided
832
+ if (iconsJsonContent) {
833
+ icons = processIcons(iconsJsonContent);
834
+ }
835
+ if (!bundledJsonContent) {
836
+ throw new Error("bundledJson content not found");
837
+ }
838
+ // Process the main JSON content
839
+ const processTokens = processJsonContent(bundledJsonContent, {
840
+ project,
841
+ overrides,
842
+ });
843
+ // Run the adapter
844
+ const files = runAdapter({
845
+ rootPath,
846
+ overrides,
847
+ srcPath,
848
+ icons,
849
+ processTokens,
850
+ project,
851
+ iconsConfig,
852
+ });
853
+ return files;
854
+ }
855
+
856
+ /**
857
+ * Main CLI function that can be called programmatically
858
+ * This is the same logic as main.ts but exported as a function
859
+ */
860
+ async function runMain() {
861
+ try {
862
+ const { rootPath, bundledJson, srcPath, project, iconsJson, overrides, iconsConfig, } = loadConfig();
863
+ if (!bundledJson)
864
+ throw new Error("bundledJson not found");
865
+ // Read file contents
866
+ const bundledJsonContent = fs.readFileSync(bundledJson, "utf-8");
867
+ const iconsJsonContent = iconsJson
868
+ ? fs.readFileSync(iconsJson, "utf-8")
869
+ : undefined;
870
+ // Use shared processing logic
871
+ const files = processAdapter({
872
+ bundledJsonContent,
873
+ project,
874
+ overrides,
875
+ rootPath,
876
+ srcPath,
877
+ iconsJsonContent,
878
+ iconsConfig,
879
+ });
880
+ const { recursicaTokens, vanillaExtractThemes, mantineTheme, uiKitObject, recursicaObject, colorsType, iconsObject, spacersType, borderRadiusType, recursicaThemes, prettierignore, } = files;
881
+ const filesToWrite = [
882
+ recursicaTokens,
883
+ vanillaExtractThemes.availableThemes,
884
+ vanillaExtractThemes.themeContract,
885
+ vanillaExtractThemes.themesFileContent,
886
+ vanillaExtractThemes.typeDefinitions,
887
+ mantineTheme.mantineTheme,
888
+ mantineTheme.postCss,
889
+ uiKitObject,
890
+ recursicaObject,
891
+ colorsType,
892
+ spacersType,
893
+ borderRadiusType,
894
+ recursicaThemes,
895
+ prettierignore,
896
+ ];
897
+ // check if src/recursica folder exists, if not create it
898
+ const outputPath = srcPath + "/recursica";
899
+ if (!fs.existsSync(outputPath)) {
900
+ fs.mkdirSync(outputPath);
901
+ }
902
+ for (const file of filesToWrite) {
903
+ fs.writeFileSync(file.path, file.content);
904
+ }
905
+ for (const theme of vanillaExtractThemes.vanillaExtractThemes) {
906
+ fs.writeFileSync(theme.path, theme.content);
907
+ }
908
+ if (iconsObject) {
909
+ fs.writeFileSync(iconsObject.iconExports.path, iconsObject.iconExports.content);
910
+ fs.writeFileSync(iconsObject.iconResourceMap.path, iconsObject.iconResourceMap.content);
911
+ for (const icon of iconsObject.exportedIcons) {
912
+ fs.writeFileSync(icon.path, icon.content);
913
+ }
914
+ }
915
+ console.log("Theme generated successfully");
916
+ }
917
+ catch (error) {
918
+ console.error("Error generating theme:", error);
919
+ throw error;
920
+ }
921
+ }
922
+
923
+ // Run the CLI
924
+ runMain().catch((error) => {
925
+ console.error("Error running recursica mantine adapter:", error);
926
+ process.exit(1);
927
+ });
928
+ //# sourceMappingURL=main.cjs.map