@tamagui/cli 3.0.0-beta.924.1 → 3.0.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/dist/build.cjs CHANGED
@@ -39,7 +39,6 @@ var import_node_os = require("node:os");
39
39
  var import_node_child_process = require("node:child_process");
40
40
  var import_node_crypto = require("node:crypto");
41
41
  var import_node_module = require("node:module");
42
- var import_typescript = require("typescript");
43
42
  const import_meta = {};
44
43
  const cliVersion = (0, import_node_module.createRequire)(typeof __filename === "string" ? __filename : import_meta.url)("@tamagui/cli/package.json").version;
45
44
  function insertCssImport(jsContent, cssImport) {
@@ -108,15 +107,12 @@ const build = async (options) => {
108
107
  const outputCSSPath = buildOptions.outputCSS ? (0, import_node_path.resolve)(root, buildOptions.outputCSS) : null;
109
108
  if (outputCSSPath) await trackFile(outputCSSPath);
110
109
  const require2 = (0, import_node_module.createRequire)(typeof __filename === "string" ? __filename : import_meta.url);
111
- const configPath = (0, import_typescript.findConfigFile)(root, import_typescript.sys.fileExists, "tsconfig.json") || (0, import_typescript.findConfigFile)(root, import_typescript.sys.fileExists, "jsconfig.json");
112
- const compilerOptions = configPath ? (0, import_typescript.parseJsonConfigFileContent)((() => {
113
- const loaded = (0, import_typescript.readConfigFile)(configPath, import_typescript.sys.readFile);
114
- if (loaded.error) throw new Error(String(loaded.error.messageText));
115
- return loaded.config;
116
- })(), import_typescript.sys, (0, import_node_path.dirname)(configPath)).options : {};
110
+ const tsconfigPaths = (0, import_static.createTsconfigPathsMatcher)(void 0, root);
117
111
  const resolveCompilerId = (specifier, importer) => {
118
- const resolved = (0, import_typescript.nodeModuleNameResolver)(specifier, importer, compilerOptions, import_typescript.sys).resolvedModule?.resolvedFileName;
119
- if (resolved && !resolved.endsWith(".d.ts")) return resolved;
112
+ for (const candidate of tsconfigPaths?.(specifier) ?? []) try {
113
+ const resolved = require2.resolve(candidate, { paths: [(0, import_node_path.dirname)(importer), root] });
114
+ if (!resolved.endsWith(".d.ts")) return resolved;
115
+ } catch {}
120
116
  try {
121
117
  return require2.resolve(specifier, { paths: [(0, import_node_path.dirname)(importer), root] });
122
118
  } catch {
package/dist/cli.cjs CHANGED
@@ -30,26 +30,45 @@ const COMMAND_MAP = {
30
30
  "--debug": Boolean,
31
31
  "--verbose": Boolean,
32
32
  "--styles-only": Boolean,
33
- "--deps-only": Boolean
33
+ "--deps-only": Boolean,
34
+ "--strict": Boolean
34
35
  },
35
36
  async run() {
36
37
  const { _, ...flags2 } = (0, import_arg.default)(this.flags);
37
- const options = await (0, import_utils.getOptions)({ debug: flags2["--debug"] ? flags2["--verbose"] ? "verbose" : true : false });
38
+ const options = await (0, import_utils.getOptions)({
39
+ debug: flags2["--debug"] ? flags2["--verbose"] ? "verbose" : true : false,
40
+ loadTamaguiOptions: flags2["--strict"] && !flags2["--deps-only"]
41
+ });
38
42
  if (!flags2["--styles-only"]) {
39
43
  const { checkDeps } = require("@tamagui/static/checkDeps");
40
44
  await checkDeps(options.paths.root);
41
45
  }
42
46
  if (flags2["--deps-only"]) return;
47
+ if (flags2["--strict"]) {
48
+ if (!options.tamaguiOptions.config) {
49
+ throw new Error("Strict style checking requires a Tamagui config.");
50
+ }
51
+ const { loadTamagui } = require("@tamagui/static/loadTamagui");
52
+ process.env.TAMAGUI_KEEP_THEMES = "1";
53
+ const loaded = await loadTamagui({
54
+ ...options.tamaguiOptions,
55
+ platform: "web"
56
+ }, true);
57
+ if (!loaded?.tamaguiConfig) {
58
+ throw new Error("Unable to load the Tamagui config for strict style checking.");
59
+ }
60
+ }
43
61
  const { checkStyleFiles, formatCheckResults, MissingConfigArtifactError } = require("@tamagui/language-service/check");
44
62
  try {
45
63
  const result = checkStyleFiles({
46
64
  root: options.paths.root,
47
- configPath: options.paths.conf
65
+ configPath: options.paths.conf,
66
+ strict: flags2["--strict"]
48
67
  });
49
68
  console.info(formatCheckResults(result));
50
69
  if (result.diagnosticCount > 0) process.exitCode = 1;
51
70
  } catch (error) {
52
- if (error instanceof MissingConfigArtifactError) {
71
+ if (error instanceof MissingConfigArtifactError && !flags2["--strict"]) {
53
72
  console.warn(import_chalk.default.yellow(`skipping flat value check: ${error.message}`));
54
73
  return;
55
74
  }
@@ -76,13 +95,7 @@ const COMMAND_MAP = {
76
95
  await loadTamagui({
77
96
  ...options.tamaguiOptions,
78
97
  platform: "web"
79
- });
80
- const { generatePrompt } = require("./generate-prompt.cjs");
81
- const { join } = require("node:path");
82
- await generatePrompt({
83
- ...options,
84
- output: join(options.paths.dotDir, "prompt.md")
85
- });
98
+ }, true);
86
99
  }
87
100
  },
88
101
  "generate-css": {
@@ -156,6 +169,37 @@ const COMMAND_MAP = {
156
169
  await installGeneratedPackage(type, path);
157
170
  }
158
171
  },
172
+ icons: {
173
+ shorthands: [],
174
+ description: `Generate themed SVG icon components from Lucide, Heroicons, Phosphor, or a folder of svgs.`,
175
+ usage: `$ tamagui icons add Search ChevronDown
176
+ $ tamagui icons add Copy --from phosphor --weight bold
177
+ $ tamagui icons add Clipboard --from heroicons --variant solid
178
+ $ tamagui icons add Logo --from ./assets/icons --out src/icons
179
+ $ tamagui icons add Search=magnifying-glass --from phosphor`,
180
+ flags: {
181
+ "--help": Boolean,
182
+ "--from": String,
183
+ "--weight": String,
184
+ "--variant": String,
185
+ "--out": String
186
+ },
187
+ async run() {
188
+ const { _, ...flags2 } = (0, import_arg.default)(this.flags);
189
+ const [_cmd, subcommand, ...names] = _;
190
+ if (subcommand !== "add") {
191
+ throw new Error("usage: tamagui icons add <Name...> [--from] [--out]");
192
+ }
193
+ const { addIcons } = require("./icons.cjs");
194
+ await addIcons({
195
+ names,
196
+ from: flags2["--from"],
197
+ weight: flags2["--weight"],
198
+ variant: flags2["--variant"],
199
+ out: flags2["--out"]
200
+ });
201
+ }
202
+ },
159
203
  build: {
160
204
  shorthands: ["b"],
161
205
  description: `Use to pre-build a Tamagui component directory. Use -- to run a command after optimization, then auto-restore files.`,
@@ -308,6 +352,30 @@ $ tamagui migrate --from v1`,
308
352
  output: flags2["--output"]
309
353
  });
310
354
  }
355
+ },
356
+ "preview-theme": {
357
+ shorthands: ["preview"],
358
+ description: `Preview a theme configuration in the browser on tamagui.dev/theme`,
359
+ usage: `$ tamagui preview-theme ./theme.json
360
+ $ tamagui preview-theme --theme '{"palettes": ...}'
361
+ $ tamagui preview-theme ./theme.json --print`,
362
+ flags: {
363
+ "--help": Boolean,
364
+ "--theme": String,
365
+ "--url": String,
366
+ "--print": Boolean
367
+ },
368
+ async run() {
369
+ const { _, ...flags2 } = (0, import_arg.default)(this.flags);
370
+ const [_cmd, themeArg] = _;
371
+ const { previewTheme } = require("./preview-theme.cjs");
372
+ await previewTheme({
373
+ theme: flags2["--theme"],
374
+ themeArg,
375
+ url: flags2["--url"],
376
+ print: flags2["--print"]
377
+ });
378
+ }
311
379
  }
312
380
  };
313
381
  const commandEntries = Object.keys(COMMAND_MAP).flatMap((command2) => {
@@ -27,6 +27,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
27
27
  var generate_prompt_exports = {};
28
28
  __export(generate_prompt_exports, { generatePrompt: () => generatePrompt });
29
29
  module.exports = __toCommonJS(generate_prompt_exports);
30
+ var import_static = require("@tamagui/static");
30
31
  var import_node_path = require("node:path");
31
32
  var FS = __toESM(require("fs-extra"));
32
33
  async function generatePrompt(options) {
@@ -36,350 +37,20 @@ async function generatePrompt(options) {
36
37
  await loadTamagui({
37
38
  ...options.tamaguiOptions,
38
39
  platform: "web"
39
- });
40
+ }, true);
40
41
  const configPath = (0, import_node_path.join)(paths.dotDir, "tamagui.config.json");
41
42
  if (!FS.existsSync(configPath)) {
42
43
  throw new Error(`Config file not found at ${configPath}. Please run 'tamagui generate' first.`);
43
44
  }
44
45
  const config = await FS.readJSON(configPath);
45
- const markdown = generateMarkdown(config);
46
+ const configSetting = config.tamaguiConfig?.settings?.styleValueSyntax;
47
+ const explicitChoice = options.styleValueSyntax || process.env.TAMAGUI_STYLE_VALUE_SYNTAX || configSetting;
48
+ const { resolveStyleValueSyntax } = require("./setup-prompt.cjs");
49
+ const resolvedSyntax = await resolveStyleValueSyntax(explicitChoice);
50
+ const markdown = (0, import_static.generateConfigMarkdown)(config, { styleValueSyntax: resolvedSyntax });
46
51
  const outputPath = output || (0, import_node_path.join)(process.cwd(), "tamagui-prompt.md");
47
52
  await FS.writeFile(outputPath, markdown, "utf-8");
48
53
  console.info(`
49
54
  \u2713 Generated prompt file at ${outputPath}
50
55
  `);
51
56
  }
52
- function generateMarkdown(config) {
53
- const sections = [];
54
- sections.push("# Tamagui Configuration\n\n");
55
- sections.push("This document provides an overview of the Tamagui configuration for this project.\n\n");
56
- const shorthands = config.tamaguiConfig?.shorthands || {};
57
- const reverseShorthands = {};
58
- for (const [short, full] of Object.entries(shorthands)) {
59
- reverseShorthands[full] = short;
60
- }
61
- const getPropName = (fullProp) => {
62
- const settings2 = config.tamaguiConfig?.settings || {};
63
- if (settings2.onlyAllowShorthands && reverseShorthands[fullProp]) {
64
- return reverseShorthands[fullProp];
65
- }
66
- return fullProp;
67
- };
68
- const settings = config.tamaguiConfig?.settings || {};
69
- if (Object.keys(settings).length > 0) {
70
- sections.push("## Configuration Settings\n\n");
71
- sections.push("**IMPORTANT:** These settings affect how you write Tamagui code in this project.\n\n");
72
- if (settings.defaultFont) {
73
- sections.push(`### Default Font: \`${settings.defaultFont}\`
74
-
75
- `);
76
- sections.push(`All text components will use the "${settings.defaultFont}" font family by default.
77
-
78
- `);
79
- }
80
- if (settings.onlyAllowShorthands !== void 0) {
81
- sections.push(`### Only Allow Shorthands: \`${settings.onlyAllowShorthands}\`
82
-
83
- `);
84
- if (settings.onlyAllowShorthands) {
85
- sections.push("**You MUST use shorthand properties in this project.**\n\n");
86
- sections.push("Full property names are not allowed. For example:\n");
87
- sections.push("- ✅ `<View w=\"10\" />` (correct)\n");
88
- sections.push("- ❌ `<View width=\"10\" />` (will error)\n\n");
89
- sections.push("See the Shorthand Properties section below for all available shorthands.\n\n");
90
- } else {
91
- sections.push("You can use either shorthand or full property names.\n\n");
92
- }
93
- }
94
- if (settings.addThemeClassName !== void 0) {
95
- sections.push(`### Theme Class Name: \`${settings.addThemeClassName}\`
96
-
97
- `);
98
- if (settings.addThemeClassName === "html") {
99
- sections.push("Theme classes are applied to the root HTML element.\n\n");
100
- }
101
- }
102
- const platform = settings.platform || settings.defaultProps?.platform;
103
- if (platform) {
104
- sections.push(`### Platform Mode: \`${platform}\`
105
-
106
- `);
107
- if (platform === "web") {
108
- sections.push("This project is configured for **web only**.\n\n");
109
- } else if (platform === "native") {
110
- sections.push("This project is configured for **React Native only**.\n\n");
111
- }
112
- }
113
- const configString = JSON.stringify(config.tamaguiConfig);
114
- if (configString.includes("semi-strict-web")) {
115
- sections.push("### Mode: `semi-strict-web`\n\n");
116
- sections.push("This configuration uses semi-strict-web mode, which:\n");
117
- sections.push("- Optimizes for web performance\n");
118
- sections.push("- May have limited React Native API support\n");
119
- sections.push("- Focuses on web-first development\n\n");
120
- }
121
- }
122
- const componentsSection = [];
123
- const allComponents = [];
124
- for (const componentModule of config.components) {
125
- const componentNames = Object.keys(componentModule.nameToInfo);
126
- allComponents.push(...componentNames);
127
- }
128
- const componentGroups = /* @__PURE__ */ new Map();
129
- const processed = /* @__PURE__ */ new Set();
130
- const sortedComponents = [...allComponents].sort((a, b) => a.length - b.length);
131
- for (const name of sortedComponents) {
132
- if (processed.has(name)) continue;
133
- const children = allComponents.filter((other) => other !== name && other.startsWith(name) && other[name.length]?.match(/[A-Z]/));
134
- if (children.length > 0) {
135
- componentGroups.set(name, new Set(children));
136
- processed.add(name);
137
- children.forEach((child) => processed.add(child));
138
- }
139
- }
140
- const standaloneComponents = allComponents.filter((name) => !processed.has(name));
141
- componentsSection.push("## Components\n\n");
142
- componentsSection.push("The following components are available:\n\n");
143
- const allBaseComponents = [...standaloneComponents, ...Array.from(componentGroups.keys())].sort();
144
- for (const name of allBaseComponents) {
145
- componentsSection.push(`- ${name}
146
- `);
147
- if (componentGroups.has(name)) {
148
- const children = Array.from(componentGroups.get(name)).sort();
149
- for (const child of children) {
150
- const suffix = child.slice(name.length);
151
- componentsSection.push(` - ${name}.${suffix}
152
- `);
153
- }
154
- }
155
- }
156
- componentsSection.push("\n");
157
- sections.push("## Shorthand Properties\n\n");
158
- sections.push("These shorthand properties are available for styling:\n\n");
159
- const shorthandEntries = Object.entries(shorthands).sort(([a], [b]) => a.localeCompare(b));
160
- sections.push(shorthandEntries.map(([short, full]) => `- \`${short}\` \u2192 \`${full}\``).join("\n"));
161
- sections.push("\n\n");
162
- sections.push("## Themes\n\n");
163
- const themes = config.tamaguiConfig?.themes || {};
164
- const themeNames = Object.keys(themes).sort();
165
- const hierarchy = {
166
- level1: /* @__PURE__ */ new Set(),
167
- level2: /* @__PURE__ */ new Set(),
168
- level3: /* @__PURE__ */ new Set(),
169
- components: /* @__PURE__ */ new Set()
170
- };
171
- for (const themeName of themeNames) {
172
- const parts = themeName.split("_");
173
- if (parts[0] === "light" || parts[0] === "dark") {
174
- hierarchy.level1.add(parts[0]);
175
- if (parts.length > 1 && parts[1] && !parts[1].startsWith("alt") && parts[1] !== "active") {
176
- if (parts[1][0] === parts[1][0].toLowerCase()) {
177
- hierarchy.level2.add(parts[1]);
178
- }
179
- }
180
- for (const part of parts) {
181
- if (part.startsWith("alt") || part === "active") {
182
- hierarchy.level3.add(part);
183
- }
184
- }
185
- for (const part of parts) {
186
- if (part[0] && part[0] === part[0].toUpperCase() && part[0] !== part[0].toLowerCase()) {
187
- hierarchy.components.add(part);
188
- }
189
- }
190
- } else {
191
- if (parts.length === 1) {
192
- hierarchy.level1.add(themeName);
193
- }
194
- }
195
- }
196
- sections.push("Themes are organized hierarchically and can be combined:\n\n");
197
- if (hierarchy.level1.size > 0) {
198
- sections.push("**Level 1 (Base):**\n\n");
199
- sections.push(Array.from(hierarchy.level1).sort().map((name) => `- ${name}`).join("\n"));
200
- sections.push("\n\n");
201
- }
202
- if (hierarchy.level2.size > 0) {
203
- sections.push("**Level 2 (Color Schemes):**\n\n");
204
- sections.push(Array.from(hierarchy.level2).sort().map((name) => `- ${name}`).join("\n"));
205
- sections.push("\n\n");
206
- }
207
- if (hierarchy.level3.size > 0) {
208
- sections.push("**Level 3 (Variants):**\n\n");
209
- sections.push(Array.from(hierarchy.level3).sort().map((name) => `- ${name}`).join("\n"));
210
- sections.push("\n\n");
211
- }
212
- if (hierarchy.components.size > 0) {
213
- sections.push("**Component Themes:**\n\n");
214
- sections.push(Array.from(hierarchy.components).sort().map((name) => `- ${name}`).join("\n"));
215
- sections.push("\n\n");
216
- }
217
- sections.push("### Theme Usage\n\n");
218
- sections.push("Themes are combined hierarchically. For example, `light_blue_alt1_Button` combines:\n");
219
- sections.push("- Base: `light`\n");
220
- sections.push("- Color: `blue`\n");
221
- sections.push("- Variant: `alt1`\n");
222
- sections.push("- Component: `Button`\n\n");
223
- sections.push("**Basic usage:**\n\n");
224
- sections.push("```tsx\n");
225
- sections.push("// Apply a theme to components\n");
226
- sections.push("export default () => (\n");
227
- sections.push(" <Theme name=\"dark\">\n");
228
- sections.push(" <Button>I'm a dark button</Button>\n");
229
- sections.push(" </Theme>\n");
230
- sections.push(")\n\n");
231
- sections.push("// Themes nest and combine automatically\n");
232
- sections.push("export default () => (\n");
233
- sections.push(" <Theme name=\"dark\">\n");
234
- sections.push(" <Theme name=\"blue\">\n");
235
- sections.push(" <Button>Uses dark_blue theme</Button>\n");
236
- sections.push(" </Theme>\n");
237
- sections.push(" </Theme>\n");
238
- sections.push(")\n");
239
- sections.push("```\n\n");
240
- sections.push("**Accessing theme values:**\n\n");
241
- sections.push("Components access theme values by their bare names:\n\n");
242
- sections.push("```tsx\n");
243
- sections.push(`<View ${getPropName("backgroundColor")}="background" ${getPropName("color")}="color" />
244
- `);
245
- sections.push("```\n\n");
246
- sections.push("**Special props:**\n\n");
247
- sections.push("- `theme=\"inverse\"`: Uses the opposite light or dark sub-theme\n");
248
- sections.push("- `reset`: Reverts to grandparent theme\n\n");
249
- sections.push("## Tokens\n\n");
250
- sections.push("Tokens are design system values referenced by their bare names.\n\n");
251
- const tokens = config.tamaguiConfig?.tokens || {};
252
- if (tokens.space) {
253
- sections.push("### Space Tokens\n\n");
254
- const spaceTokens = Object.entries(tokens.space).sort(([a], [b]) => {
255
- const numA = parseFloat(a);
256
- const numB = parseFloat(b);
257
- if (!isNaN(numA) && !isNaN(numB)) {
258
- return numA - numB;
259
- }
260
- return a.localeCompare(b);
261
- });
262
- sections.push(spaceTokens.map(([key, value]) => `- \`${key}\`: ${formatTokenValue(value)}`).join("\n"));
263
- sections.push("\n\n");
264
- }
265
- if (tokens.size) {
266
- sections.push("### Size Tokens\n\n");
267
- const sizeTokens = Object.entries(tokens.size).sort(([a], [b]) => {
268
- const numA = parseFloat(a);
269
- const numB = parseFloat(b);
270
- if (!isNaN(numA) && !isNaN(numB)) {
271
- return numA - numB;
272
- }
273
- return a.localeCompare(b);
274
- });
275
- sections.push(sizeTokens.map(([key, value]) => `- \`${key}\`: ${formatTokenValue(value)}`).join("\n"));
276
- sections.push("\n\n");
277
- }
278
- if (tokens.radius) {
279
- sections.push("### Radius Tokens\n\n");
280
- const radiusTokens = Object.entries(tokens.radius).sort(([a], [b]) => {
281
- const numA = parseFloat(a);
282
- const numB = parseFloat(b);
283
- if (!isNaN(numA) && !isNaN(numB)) {
284
- return numA - numB;
285
- }
286
- return a.localeCompare(b);
287
- });
288
- sections.push(radiusTokens.map(([key, value]) => `- \`${key}\`: ${formatTokenValue(value)}`).join("\n"));
289
- sections.push("\n\n");
290
- }
291
- if (tokens.zIndex) {
292
- sections.push("### Z-Index Tokens\n\n");
293
- const zIndexTokens = Object.entries(tokens.zIndex).sort(([a], [b]) => {
294
- const numA = parseFloat(a);
295
- const numB = parseFloat(b);
296
- if (!isNaN(numA) && !isNaN(numB)) {
297
- return numA - numB;
298
- }
299
- return a.localeCompare(b);
300
- });
301
- sections.push(zIndexTokens.map(([key, value]) => `- \`${key}\`: ${formatTokenValue(value)}`).join("\n"));
302
- sections.push("\n\n");
303
- }
304
- if (tokens.color) {
305
- sections.push("### Color Tokens\n\n");
306
- const colorTokens = Object.entries(tokens.color).sort(([a], [b]) => a.localeCompare(b));
307
- sections.push(colorTokens.map(([key, value]) => `- \`${key}\`: ${formatTokenValue(value)}`).join("\n"));
308
- sections.push("\n\n");
309
- }
310
- sections.push("### Token Usage\n\n");
311
- sections.push("Tokens can be used in component props by their bare names:\n\n");
312
- sections.push("```tsx\n");
313
- sections.push("// Space tokens - for margin, padding, gap\n");
314
- sections.push(`<View ${getPropName("padding")}="4" ${getPropName("gap")}="2" ${getPropName("margin")}="3" />
315
-
316
- `);
317
- sections.push("// Size tokens - for width, height, dimensions\n");
318
- sections.push(`<View ${getPropName("width")}="10" ${getPropName("height")}="6" />
319
-
320
- `);
321
- sections.push("// Color tokens - for colors and backgrounds\n");
322
- sections.push(`<View ${getPropName("backgroundColor")}="blue5" ${getPropName("color")}="gray12" />
323
-
324
- `);
325
- sections.push("// Radius tokens - for border-radius\n");
326
- sections.push(`<View ${getPropName("borderRadius")}="4" />
327
- `);
328
- sections.push("```\n\n");
329
- if (config.tamaguiConfig?.media) {
330
- sections.push("## Media Queries\n\n");
331
- sections.push("Available responsive breakpoints:\n\n");
332
- const media = config.tamaguiConfig.media;
333
- const mediaEntries = Object.entries(media).sort(([a], [b]) => a.localeCompare(b));
334
- for (const [name, query] of mediaEntries) {
335
- sections.push(`- **${name}**: ${JSON.stringify(query)}
336
- `);
337
- }
338
- sections.push("\n");
339
- sections.push("### Media Query Usage\n\n");
340
- sections.push("Media queries can be used as style props or with the `useMedia` hook:\n\n");
341
- sections.push("```tsx\n");
342
- sections.push("// As a clause in the same style value\n");
343
- const firstMediaName = mediaEntries[0]?.[0];
344
- if (firstMediaName) {
345
- sections.push(`<View ${getPropName("width")}="100% ${firstMediaName}:50%" />
346
-
347
- `);
348
- }
349
- sections.push("// Using the useMedia hook\n");
350
- sections.push("const media = useMedia()\n");
351
- if (firstMediaName) {
352
- sections.push(`if (media.${firstMediaName}) {
353
- `);
354
- sections.push(" // Render for this breakpoint\n");
355
- sections.push("}\n");
356
- }
357
- sections.push("```\n\n");
358
- }
359
- if (config.tamaguiConfig?.fonts) {
360
- sections.push("## Fonts\n\n");
361
- sections.push("Available font families:\n\n");
362
- const fonts = config.tamaguiConfig.fonts;
363
- const fontNames = Object.keys(fonts).sort();
364
- sections.push(fontNames.map((name) => `- ${name}`).join("\n"));
365
- sections.push("\n\n");
366
- }
367
- if (config.tamaguiConfig?.animations) {
368
- sections.push("## Animations\n\n");
369
- sections.push("Available animation presets:\n\n");
370
- const animations = config.tamaguiConfig.animations;
371
- if (animations.animations) {
372
- const animationNames = Object.keys(animations.animations).sort();
373
- sections.push(animationNames.map((name) => `- ${name}`).join("\n"));
374
- sections.push("\n\n");
375
- }
376
- }
377
- sections.push(...componentsSection);
378
- return sections.join("");
379
- }
380
- function formatTokenValue(value) {
381
- if (typeof value === "object" && value !== null && "val" in value) {
382
- return String(value.val);
383
- }
384
- return String(value);
385
- }