vibe-design-system 2.8.81 → 2.8.82

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-design-system",
3
- "version": "2.8.81",
3
+ "version": "2.8.82",
4
4
  "description": "Auto-generate design systems for vibe coding projects",
5
5
  "homepage": "https://vibedesign.tech",
6
6
  "repository": {
@@ -1429,11 +1429,17 @@ function extractFoundations() {
1429
1429
  }
1430
1430
  }
1431
1431
 
1432
- // body { font-family } — supports nested @layer base { body { } } structure
1433
- const bodyMatch = css.match(/\bbody\s*\{[\s\S]*?font-family:\s*([^;]+);/) ||
1434
- css.match(/body\s*\{[^}]*font-family:\s*([^;]+);/s);
1432
+ // body { font-family } — Tailwind v4 sets font on html/:host, NOT body
1433
+ // Use [^}]* to stay within block boundaries ([\s\S]*? crosses blocks → mono font false-positive)
1434
+ const bodyMatch =
1435
+ css.match(/\bbody\s*\{[^}]*font-family:\s*([^;]+);/) ||
1436
+ css.match(/html\s*(?:,\s*:host)?\s*\{[^}]*font-family:\s*([^;]+);/); // Tailwind v4
1435
1437
  if (bodyMatch) typography.body = bodyMatch[1].trim();
1436
- const monoMatch = css.match(/code,\s*pre,\s*\.font-mono\s*\{[^}]*font-family:\s*([^;]+);/s);
1438
+ // Mono: code/kbd/samp/pre block (Tailwind v4 uses code,kbd,samp,pre not code,pre,.font-mono)
1439
+ const monoMatch =
1440
+ css.match(/code,\s*pre,\s*\.font-mono\s*\{[^}]*font-family:\s*([^;]+);/) ||
1441
+ css.match(/code,\s*kbd[^{]*\{[^}]*font-family:\s*([^;]+);/) ||
1442
+ css.match(/\bcode\b[^{,]*\{[^}]*font-family:\s*([^;]+);/);
1437
1443
  if (monoMatch) typography.mono = monoMatch[1].trim();
1438
1444
  // CSS custom properties for fonts (--font-sans, --font-mono, --font-display, etc.)
1439
1445
  const fontVarRe = /--font([\w-]*):\s*([^;\n]+);/g;
@@ -1444,14 +1450,27 @@ function extractFoundations() {
1444
1450
  if (!typography[key]) typography[key] = val;
1445
1451
  }
1446
1452
  // Resolve var(--font-*) references in body/mono to actual font names
1447
- // Key construction must match the fontVarRe loop: --font-sans "font-sans" → "fontSans"
1453
+ // Also handles Tailwind v4 --default-font-family / --default-mono-font-family chain
1448
1454
  function resolveTypoVar(val) {
1449
1455
  if (!val || !val.startsWith("var(")) return val;
1456
+ // Direct --font-* reference: var(--font-sans) → typography.fontSans
1450
1457
  const m = val.match(/var\(--font-([\w-]+)\)/);
1451
- if (!m) return val;
1452
- // prepend "-" so camelCase conversion matches: "font-" + "sans" "fontSans"
1453
- const key = `font-${m[1]}`.replace(/-([a-zA-Z])/g, (_, c) => c.toUpperCase());
1454
- return (typography[key] && !typography[key].startsWith("var(")) ? typography[key] : val;
1458
+ if (m) {
1459
+ const key = `font-${m[1]}`.replace(/-([a-zA-Z])/g, (_, c) => c.toUpperCase());
1460
+ return (typography[key] && !typography[key].startsWith("var(")) ? typography[key] : val;
1461
+ }
1462
+ // Tailwind v4: var(--default-font-family, ...) → resolve via fontSans
1463
+ if (val.includes("--default-font-family") && !val.includes("--default-mono")) {
1464
+ if (typography.fontSans && !typography.fontSans.startsWith("var(")) return typography.fontSans;
1465
+ // Fallback: strip the var() wrapper to get the fallback list
1466
+ return val.replace(/^var\(--default-font-family,\s*/, "").replace(/\)\s*$/, "").trim() || val;
1467
+ }
1468
+ // Tailwind v4: var(--default-mono-font-family, ...) → resolve via fontMono
1469
+ if (val.includes("--default-mono-font-family")) {
1470
+ if (typography.fontMono && !typography.fontMono.startsWith("var(")) return typography.fontMono;
1471
+ return val.replace(/^var\(--default-mono-font-family,\s*/, "").replace(/\)\s*$/, "").trim() || val;
1472
+ }
1473
+ return val;
1455
1474
  }
1456
1475
  if (typography.body) typography.body = resolveTypoVar(typography.body);
1457
1476
  if (typography.mono) typography.mono = resolveTypoVar(typography.mono);
@@ -1792,6 +1792,96 @@ function buildRecipeStoryContent(comp, componentName, importPath, title, source,
1792
1792
  }
1793
1793
  lines.push(`};`);
1794
1794
  }
1795
+
1796
+ // --- Design Tokens story (same block as generateStoryFile) ---
1797
+ {
1798
+ const compTokens = Array.isArray(comp.tokens) ? comp.tokens : [];
1799
+ const foundColors = FOUNDATIONS_DATA?.colors || {};
1800
+ if (compTokens.length >= 3) {
1801
+ const cleanTokens = compTokens.filter(t => !/:/.test(t));
1802
+ const colorRaw = cleanTokens.filter(t =>
1803
+ /^(bg|text|border|ring|from|to|fill|stroke)-/.test(t) &&
1804
+ !/^text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl|\d)/.test(t)
1805
+ );
1806
+ const spacingRaw = cleanTokens.filter(t => /^(p[xylrbt]?-|m[xylrbt]?-|gap|space-[xy]|w-|h-|min-[wh]|max-[wh]|size-)/.test(t));
1807
+ const typographyRaw = cleanTokens.filter(t => /^(text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl)|font-)/.test(t));
1808
+ const radiusRaw = cleanTokens.filter(t => /^rounded/.test(t));
1809
+ const animRaw = cleanTokens.filter(t => /^(transition|duration|animate|ease|delay)-/.test(t));
1810
+ const resolvedColors = colorRaw.map(token => {
1811
+ const m = token.match(/^(?:bg|text|border|ring|from|to|fill|stroke)-(.+)$/);
1812
+ const key = m ? m[1] : null;
1813
+ const baseKey = key ? key.replace(/\/[\d.]+$/, "") : null;
1814
+ const entry = key ? (foundColors[key] || (baseKey !== key ? foundColors[baseKey] : null)) : null;
1815
+ const isValidCssColor = (v) => /^#[0-9a-fA-F]{3,8}$/.test(v) || /^(rgb|rgba|hsl|hsla|oklch|oklab|lch|lab|color)\s*\(/.test(v) || v === 'transparent';
1816
+ const hex = entry?.hex && isValidCssColor(entry.hex) ? entry.hex : null;
1817
+ return { token, hex, label: baseKey || key };
1818
+ });
1819
+ const hasContent = resolvedColors.length > 0 || spacingRaw.length > 0 || typographyRaw.length > 0 || radiusRaw.length > 0 || animRaw.length > 0;
1820
+ if (hasContent) {
1821
+ lines.push("");
1822
+ lines.push(`export const Tokens: Story = {`);
1823
+ lines.push(` name: "Design Tokens",`);
1824
+ lines.push(` parameters: { layout: "fullscreen" },`);
1825
+ lines.push(` render: () => {`);
1826
+ lines.push(` const colorTokens = ${JSON.stringify(resolvedColors)};`);
1827
+ lines.push(` const spacingTokens = ${JSON.stringify(spacingRaw)};`);
1828
+ lines.push(` const typographyTokens = ${JSON.stringify(typographyRaw)};`);
1829
+ lines.push(` const radiusTokens = ${JSON.stringify(radiusRaw)};`);
1830
+ lines.push(` const animationTokens = ${JSON.stringify(animRaw)};`);
1831
+ lines.push(` const chip = (label: string, bg: string, color: string) => (`);
1832
+ lines.push(` <span key={label} style={{ fontFamily: "monospace", fontSize: 11, background: bg, color, padding: "3px 9px", borderRadius: 5, border: \`1px solid \${bg === "#f9fafb" ? "#e5e7eb" : bg}\`, whiteSpace: "nowrap" as any }}>{label}</span>`);
1833
+ lines.push(` );`);
1834
+ lines.push(` const section = (title: string, children: any) => (`);
1835
+ lines.push(` <section style={{ marginBottom: 28 }}>`);
1836
+ lines.push(` <p style={{ margin: "0 0 10px", fontSize: 11, fontWeight: 700, color: "#6b7280", textTransform: "uppercase", letterSpacing: "0.08em" }}>{title}</p>`);
1837
+ lines.push(` {children}`);
1838
+ lines.push(` </section>`);
1839
+ lines.push(` );`);
1840
+ lines.push(` return (`);
1841
+ lines.push(` <div style={{ padding: 40, background: "#fff", fontFamily: "system-ui,sans-serif", color: "#111", minHeight: "100vh", width: "100%" }}>`);
1842
+ lines.push(` <h2 style={{ fontSize: 22, fontWeight: 700, margin: "0 0 6px" }}>Design Tokens</h2>`);
1843
+ lines.push(` <p style={{ fontSize: 13, color: "#6b7280", margin: "0 0 32px" }}>Tailwind utilities used in <code style={{ background: "#f3f4f6", padding: "1px 6px", borderRadius: 4, fontSize: 12 }}>${componentName}</code> — resolved to project values.</p>`);
1844
+ lines.push(` {colorTokens.length > 0 && section("Color", (`);
1845
+ lines.push(` <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>`);
1846
+ lines.push(` {colorTokens.map(({ token, hex, label }) => (`);
1847
+ lines.push(` <div key={token} style={{ display: "flex", alignItems: "center", gap: 7, padding: "7px 12px", border: "1px solid #e5e7eb", borderRadius: 8, background: "#f9fafb" }}>`);
1848
+ lines.push(` {hex && <span style={{ display: "inline-block", width: 16, height: 16, borderRadius: 4, background: hex, border: "1px solid rgba(0,0,0,0.1)", flexShrink: 0 }} />}`);
1849
+ lines.push(` <code style={{ fontSize: 12, color: "#374151", fontWeight: 600 }}>{token}</code>`);
1850
+ lines.push(` {hex && <span style={{ fontSize: 11, color: "#9ca3af" }}>{hex}</span>}`);
1851
+ lines.push(` </div>`);
1852
+ lines.push(` ))}`);
1853
+ lines.push(` </div>`);
1854
+ lines.push(` ))}`);
1855
+ lines.push(` {spacingTokens.length > 0 && section("Spacing", (`);
1856
+ lines.push(` <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>{spacingTokens.map(t => chip(t, "#faf5ff", "#6d28d9"))}</div>`);
1857
+ lines.push(` ))}`);
1858
+ lines.push(` {typographyTokens.length > 0 && section("Typography", (`);
1859
+ lines.push(` <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>{typographyTokens.map(t => chip(t, "#fffbeb", "#92400e"))}</div>`);
1860
+ lines.push(` ))}`);
1861
+ lines.push(` {radiusTokens.length > 0 && section("Border Radius", (`);
1862
+ lines.push(` <div style={{ display: "flex", gap: 16, flexWrap: "wrap", alignItems: "flex-end" }}>`);
1863
+ lines.push(` {radiusTokens.map(t => {`);
1864
+ lines.push(` const px = t === "rounded-none" ? 0 : t === "rounded-sm" ? 2 : t === "rounded" ? 4 : t === "rounded-md" ? 6 : t === "rounded-lg" ? 8 : t === "rounded-xl" ? 12 : t === "rounded-2xl" ? 16 : t === "rounded-3xl" ? 24 : t === "rounded-full" ? 9999 : 4;`);
1865
+ lines.push(` return (`);
1866
+ lines.push(` <div key={t} style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 6 }}>`);
1867
+ lines.push(` <div style={{ width: 44, height: 44, background: "#6366f1", borderRadius: px }} />`);
1868
+ lines.push(` <code style={{ fontSize: 10, color: "#6b7280" }}>{t}</code>`);
1869
+ lines.push(` </div>`);
1870
+ lines.push(` );`);
1871
+ lines.push(` })}`);
1872
+ lines.push(` </div>`);
1873
+ lines.push(` ))}`);
1874
+ lines.push(` {animationTokens.length > 0 && section("Motion", (`);
1875
+ lines.push(` <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>{animationTokens.map(t => chip(t, "#f0fdf4", "#166534"))}</div>`);
1876
+ lines.push(` ))}`);
1877
+ lines.push(` </div>`);
1878
+ lines.push(` );`);
1879
+ lines.push(` },`);
1880
+ lines.push(`};`);
1881
+ }
1882
+ }
1883
+ }
1884
+
1795
1885
  return lines.join("\n");
1796
1886
  }
1797
1887
 
@@ -2115,42 +2205,46 @@ function buildStoryFileContent(comp) {
2115
2205
  // Component-specific stories for non-variant components (Input, Textarea, etc.)
2116
2206
  // Skip buildSpecialStories when multi-dimension detection found CVA dimensions —
2117
2207
  // generic detection produces better stories than hardcoded ones.
2208
+ let generatedSpecialStories = false;
2118
2209
  if (!hasDimensions) {
2119
2210
  const specialStories = buildSpecialStories(componentName, variants);
2120
2211
  if (specialStories) {
2121
2212
  lines.push(specialStories);
2122
- return lines.join("\n");
2213
+ generatedSpecialStories = true;
2214
+ // Do NOT return here — fall through to Tokens + Usage stories below
2123
2215
  }
2124
2216
  }
2125
2217
 
2126
- // Profile-driven render + children — single source of truth via getStoryProfile()
2127
- const useSafeWrapper = profile === "SAFE";
2128
- const RenderTarget = useSafeWrapper ? "SafeWrapper" : "ComponentRef";
2129
- const argsFallback = !useSafeWrapper && (componentName && RENDER_ARGS_FALLBACKS[componentName]) || "";
2130
- const renderLine = buildProfileRenderLine(profile, RenderTarget, argsFallback);
2131
- const childrenArgLine = buildProfileChildrenArgLine(profile);
2218
+ if (!generatedSpecialStories) {
2219
+ // Profile-driven render + children — single source of truth via getStoryProfile()
2220
+ const useSafeWrapper = profile === "SAFE";
2221
+ const RenderTarget = useSafeWrapper ? "SafeWrapper" : "ComponentRef";
2222
+ const argsFallback = !useSafeWrapper && (componentName && RENDER_ARGS_FALLBACKS[componentName]) || "";
2223
+ const renderLine = buildProfileRenderLine(profile, RenderTarget, argsFallback);
2224
+ const childrenArgLine = buildProfileChildrenArgLine(profile);
2132
2225
 
2133
- if (hasDimensions) {
2134
- const multiStories = buildMultiDimensionStories(
2135
- variantMap, renderLine, childrenArgLine, defaultArgLines, componentName,
2136
- comp.variantUsage || null
2137
- );
2138
- if (multiStories) {
2139
- lines.push(multiStories);
2140
- }
2141
- } else {
2142
- // No dimensions detected: single Default story
2143
- lines.push(`export const Default: Story = {`);
2144
- lines.push(renderLine);
2145
- const storyArgLines = [];
2146
- if (childrenArgLine(componentName)) storyArgLines.push(childrenArgLine(componentName));
2147
- for (const line of defaultArgLines) storyArgLines.push(line);
2148
- if (storyArgLines.length > 0) {
2149
- lines.push(` args: {`);
2150
- for (const line of storyArgLines) lines.push(line);
2151
- lines.push(` },`);
2226
+ if (hasDimensions) {
2227
+ const multiStories = buildMultiDimensionStories(
2228
+ variantMap, renderLine, childrenArgLine, defaultArgLines, componentName,
2229
+ comp.variantUsage || null
2230
+ );
2231
+ if (multiStories) {
2232
+ lines.push(multiStories);
2233
+ }
2234
+ } else {
2235
+ // No dimensions detected: single Default story
2236
+ lines.push(`export const Default: Story = {`);
2237
+ lines.push(renderLine);
2238
+ const storyArgLines = [];
2239
+ if (childrenArgLine(componentName)) storyArgLines.push(childrenArgLine(componentName));
2240
+ for (const line of defaultArgLines) storyArgLines.push(line);
2241
+ if (storyArgLines.length > 0) {
2242
+ lines.push(` args: {`);
2243
+ for (const line of storyArgLines) lines.push(line);
2244
+ lines.push(` },`);
2245
+ }
2246
+ lines.push(`};`);
2152
2247
  }
2153
- lines.push(`};`);
2154
2248
  }
2155
2249
 
2156
2250
  // --- Project-specific usage stories ---
@@ -2190,7 +2284,7 @@ function buildStoryFileContent(comp) {
2190
2284
  /^(bg|text|border|ring|from|to|fill|stroke)-/.test(t) &&
2191
2285
  !/^text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl|\d)/.test(t)
2192
2286
  );
2193
- const spacingRaw = cleanTokens.filter(t => /^(p[xylrbt]?|m[xylrbt]?|gap|space-[xy]|w-|h-|min-[wh]|max-[wh]|size-)/.test(t));
2287
+ const spacingRaw = cleanTokens.filter(t => /^(p[xylrbt]?-|m[xylrbt]?-|gap|space-[xy]|w-|h-|min-[wh]|max-[wh]|size-)/.test(t));
2194
2288
  const typographyRaw = cleanTokens.filter(t => /^(text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl)|font-)/.test(t));
2195
2289
  const radiusRaw = cleanTokens.filter(t => /^rounded/.test(t));
2196
2290
  const animRaw = cleanTokens.filter(t => /^(transition|duration|animate|ease|delay)-/.test(t));