vibe-design-system 2.8.63 → 2.8.64
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
|
@@ -1991,6 +1991,44 @@ function buildStoryFileContent(comp) {
|
|
|
1991
1991
|
return buildRecipeStoryContent(comp, componentName, importPath, title, source, exportStyle, RECIPES[componentName], defaultArgLines, lucideImports, iconPropNames, needReact, variantMap);
|
|
1992
1992
|
}
|
|
1993
1993
|
|
|
1994
|
+
// Detect if the component uses @tanstack/react-query hooks → needs QueryClientProvider in story.
|
|
1995
|
+
// Checks direct imports AND one level deep into local hook files (e.g. @/hooks/use-crypto.ts).
|
|
1996
|
+
const needsQueryClient = (() => {
|
|
1997
|
+
if (!source.length) return false;
|
|
1998
|
+
// Direct usage in this file
|
|
1999
|
+
if (/from\s+['"]@tanstack\/react-query['"]/m.test(source) ||
|
|
2000
|
+
/\b(useQuery|useMutation|useQueryClient|useInfiniteQuery|useSuspenseQuery)\b/.test(source)) {
|
|
2001
|
+
return true;
|
|
2002
|
+
}
|
|
2003
|
+
// One level deep: check imported hook files (e.g. @/hooks/*, ../hooks/*, ./hooks/*)
|
|
2004
|
+
// Derive the @/ alias source root from COMPONENTS_REL_DIR:
|
|
2005
|
+
// "src/components" → srcRoot = "src"
|
|
2006
|
+
// "client/src/components" → srcRoot = "client/src"
|
|
2007
|
+
const atAliasRoot = path.dirname(COMPONENTS_REL_DIR); // e.g. "src" or "client/src"
|
|
2008
|
+
const hookImportRe = /from\s+['"]([^'"]*\/hooks\/[^'"]+)['"]/g;
|
|
2009
|
+
let m;
|
|
2010
|
+
while ((m = hookImportRe.exec(source)) !== null) {
|
|
2011
|
+
try {
|
|
2012
|
+
let rel = m[1];
|
|
2013
|
+
// Resolve @ alias using derived source root
|
|
2014
|
+
if (rel.startsWith("@/")) rel = atAliasRoot + "/" + rel.slice(2);
|
|
2015
|
+
const exts = [".ts", ".tsx", ".js", ".jsx"];
|
|
2016
|
+
for (const ext of exts) {
|
|
2017
|
+
const full = path.join(PROJECT_ROOT, rel + ext);
|
|
2018
|
+
if (fs.existsSync(full)) {
|
|
2019
|
+
const hookSrc = fs.readFileSync(full, "utf-8");
|
|
2020
|
+
if (/from\s+['"]@tanstack\/react-query['"]/m.test(hookSrc) ||
|
|
2021
|
+
/\b(useQuery|useMutation|useQueryClient|useInfiniteQuery)\b/.test(hookSrc)) {
|
|
2022
|
+
return true;
|
|
2023
|
+
}
|
|
2024
|
+
break;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
} catch { /* ignore */ }
|
|
2028
|
+
}
|
|
2029
|
+
return false;
|
|
2030
|
+
})();
|
|
2031
|
+
|
|
1994
2032
|
const lines = [];
|
|
1995
2033
|
lines.push(`// @vds-regenerate — VDS auto-generated. Remove this line to prevent overwrite.`);
|
|
1996
2034
|
lines.push(`import type { Meta, StoryObj } from "@storybook/react";`);
|
|
@@ -1998,11 +2036,17 @@ function buildStoryFileContent(comp) {
|
|
|
1998
2036
|
if (lucideImports.length > 0) {
|
|
1999
2037
|
lines.push(`import { ${lucideImports.join(", ")} } from "lucide-react";`);
|
|
2000
2038
|
}
|
|
2039
|
+
if (needsQueryClient) {
|
|
2040
|
+
lines.push(`import { QueryClient, QueryClientProvider } from "@tanstack/react-query";`);
|
|
2041
|
+
}
|
|
2001
2042
|
|
|
2002
2043
|
// Dynamic import + catch so "Failed to fetch dynamically imported module" shows a fallback instead of breaking Storybook
|
|
2003
2044
|
const loadFallback = `() => React.createElement('div', { style: { padding: 16, color: '#666', fontSize: 14 } }, 'Component could not be loaded (import error).')`;
|
|
2004
2045
|
const getDefault = `(m) => ({ default: m["${componentName}"] ?? m.default })`;
|
|
2005
2046
|
lines.push(`const ComponentRef = React.lazy(() => import(/* @vite-ignore */ "${importPath}").then(${getDefault}).catch(() => ({ default: ${loadFallback} })));`);
|
|
2047
|
+
if (needsQueryClient) {
|
|
2048
|
+
lines.push(`const _queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, staleTime: Infinity } } });`);
|
|
2049
|
+
}
|
|
2006
2050
|
lines.push("");
|
|
2007
2051
|
|
|
2008
2052
|
const safeDefaultsObj = componentName && SAFE_WRAPPER_DEFAULTS[componentName];
|
|
@@ -2018,6 +2062,10 @@ function buildStoryFileContent(comp) {
|
|
|
2018
2062
|
if (profile !== "SECTION") lines.push(` tags: ["autodocs"],`);
|
|
2019
2063
|
// Center small components (VARIANT, WRAPPER, CONFIGURED, SAFE) to prevent vertical stretching
|
|
2020
2064
|
if (profile !== "SECTION") lines.push(` parameters: { layout: "centered" },`);
|
|
2065
|
+
// Wrap with QueryClientProvider for components that use @tanstack/react-query hooks
|
|
2066
|
+
if (needsQueryClient) {
|
|
2067
|
+
lines.push(` decorators: [(Story: any) => React.createElement(QueryClientProvider, { client: _queryClient }, React.createElement(Story))],`);
|
|
2068
|
+
}
|
|
2021
2069
|
|
|
2022
2070
|
// Build argTypes from extracted TypeScript props + icon-specific overrides
|
|
2023
2071
|
const argTypeEntries = [];
|
|
@@ -2161,7 +2209,7 @@ function buildStoryFileContent(comp) {
|
|
|
2161
2209
|
lines.push(` </section>`);
|
|
2162
2210
|
lines.push(` );`);
|
|
2163
2211
|
lines.push(` return (`);
|
|
2164
|
-
lines.push(` <div style={{ padding: 40, background: "#fff", fontFamily: "system-ui,sans-serif", color: "#111", minHeight: "100vh" }}>`);
|
|
2212
|
+
lines.push(` <div style={{ padding: 40, background: "#fff", fontFamily: "system-ui,sans-serif", color: "#111", minHeight: "100vh", width: "100%" }}>`);
|
|
2165
2213
|
lines.push(` <h2 style={{ fontSize: 22, fontWeight: 700, margin: "0 0 6px" }}>Design Tokens</h2>`);
|
|
2166
2214
|
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>`);
|
|
2167
2215
|
lines.push(` {colorTokens.length > 0 && section("Color", (`);
|
|
@@ -2230,7 +2278,7 @@ function buildStoryFileContent(comp) {
|
|
|
2230
2278
|
lines.push(` <p style={{ margin: "0 0 12px", fontSize: 11, fontWeight: 700, color: "#6b7280", textTransform: "uppercase" as any, letterSpacing: "0.08em" }}>{label}</p>`);
|
|
2231
2279
|
lines.push(` );`);
|
|
2232
2280
|
lines.push(` return (`);
|
|
2233
|
-
lines.push(` <div style={{ padding: 40, background: "#fff", fontFamily: "system-ui,sans-serif", color: "#111", minHeight: "100vh" }}>`);
|
|
2281
|
+
lines.push(` <div style={{ padding: 40, background: "#fff", fontFamily: "system-ui,sans-serif", color: "#111", minHeight: "100vh", width: "100%" }}>`);
|
|
2234
2282
|
lines.push(` <div style={{ marginBottom: 32 }}>`);
|
|
2235
2283
|
lines.push(` <h2 style={{ fontSize: 22, fontWeight: 700, margin: "0 0 6px" }}>Usage</h2>`);
|
|
2236
2284
|
lines.push(` <p style={{ fontSize: 13, color: "#6b7280", margin: 0 }}>`);
|
|
@@ -2596,7 +2644,7 @@ function writeFoundationsStories(foundations) {
|
|
|
2596
2644
|
"",
|
|
2597
2645
|
"export const Default: Story = {",
|
|
2598
2646
|
" render: () => (",
|
|
2599
|
-
" <div style={{ fontFamily: \"system-ui,sans-serif\", padding: 32,
|
|
2647
|
+
" <div style={{ fontFamily: \"system-ui,sans-serif\", padding: 32, color: \"#111\", background: \"#fff\", minHeight: \"100vh\", width: \"100%\" }}>",
|
|
2600
2648
|
" <h2 style={{ fontSize: 20, fontWeight: 700, margin: \"0 0 4px\" }}>Typography</h2>",
|
|
2601
2649
|
" <p style={{ fontSize: 13, color: \"#888\", margin: \"0 0 32px\" }}>Type scale, font families, and weights</p>",
|
|
2602
2650
|
"",
|
|
@@ -2752,7 +2800,7 @@ function writeFoundationsStories(foundations) {
|
|
|
2752
2800
|
"",
|
|
2753
2801
|
"export const Default: Story = {",
|
|
2754
2802
|
" render: () => (",
|
|
2755
|
-
" <div style={{ display: \"flex\", gap: 24, flexWrap: \"wrap\", padding: 32, background: \"#fff\", minHeight: \"100vh\" }}>",
|
|
2803
|
+
" <div style={{ display: \"flex\", gap: 24, flexWrap: \"wrap\", padding: 32, background: \"#fff\", minHeight: \"100vh\", width: \"100%\" }}>",
|
|
2756
2804
|
" {assets.length === 0 ? <p style={{ color: '#888', fontFamily: 'monospace' }}>No brand assets found — add images to public/ or client/public/</p> : assets.map((a, i) => (",
|
|
2757
2805
|
" <div key={i} style={{ textAlign: \"center\", background: '#f8f8f8', borderRadius: 8, padding: 12, minWidth: 120 }}>",
|
|
2758
2806
|
" <img src={a.url || (\"/\" + String(a.path || \"\").replace(/^public\\//, \"\"))} style={{ maxHeight: 100, maxWidth: 180, objectFit: \"contain\", display: 'block', margin: '0 auto' }} alt={a.name || \"\"} />",
|
|
@@ -2849,7 +2897,7 @@ function writeFoundationsStories(foundations) {
|
|
|
2849
2897
|
" ];",
|
|
2850
2898
|
" const TILE_SIZES = [16, 20, 24];",
|
|
2851
2899
|
" return (",
|
|
2852
|
-
" <div style={{ padding: 32, fontFamily: \"system-ui,sans-serif\", background: \"#fff\", minHeight: \"100vh\", color: \"#111\" }}>",
|
|
2900
|
+
" <div style={{ padding: 32, fontFamily: \"system-ui,sans-serif\", background: \"#fff\", minHeight: \"100vh\", width: \"100%\", color: \"#111\" }}>",
|
|
2853
2901
|
" <h2 style={{ fontSize: 20, fontWeight: 700, margin: \"0 0 4px\" }}>Icons</h2>",
|
|
2854
2902
|
" <div style={{ marginBottom: 28 }}>",
|
|
2855
2903
|
" <p style={{ margin: 0, marginBottom: 4, fontSize: 13, color: \"#6b7280\" }}>",
|
|
@@ -2992,7 +3040,7 @@ function writeFoundationsStories(foundations) {
|
|
|
2992
3040
|
" );",
|
|
2993
3041
|
" };",
|
|
2994
3042
|
" return (",
|
|
2995
|
-
" <div style={{ padding: 24, fontFamily: \"sans-serif\",
|
|
3043
|
+
" <div style={{ padding: 24, fontFamily: \"sans-serif\", background: \"#fff\", minHeight: \"100vh\", width: \"100%\", color: \"#111\" }}>",
|
|
2996
3044
|
"",
|
|
2997
3045
|
" {/* ── Breakpoints ── */}",
|
|
2998
3046
|
" <section style={{ marginBottom: 40 }}>",
|
|
@@ -3148,7 +3196,7 @@ function writeFoundationsStories(foundations) {
|
|
|
3148
3196
|
"",
|
|
3149
3197
|
"export const Default: Story = {",
|
|
3150
3198
|
" render: () => (",
|
|
3151
|
-
" <div style={{ padding: 32, fontFamily: \"system-ui, sans-serif\", background: \"#fff\", minHeight: \"100vh\", color: \"#111\" }}>",
|
|
3199
|
+
" <div style={{ padding: 32, fontFamily: \"system-ui, sans-serif\", background: \"#fff\", minHeight: \"100vh\", width: \"100%\", color: \"#111\" }}>",
|
|
3152
3200
|
" <h2 style={{ marginBottom: 8 }}>Used Button variants in app code</h2>",
|
|
3153
3201
|
" <p style={{ marginBottom: 16, color: \"#888\", fontSize: 13 }}>Based on <Button ... /> usages in src/ (ignores lowercase <button>).</p>",
|
|
3154
3202
|
" <table style={{ borderCollapse: \"collapse\", width: \"100%\", fontSize: 13 }}>",
|
|
@@ -3225,7 +3273,7 @@ function writeFoundationsStories(foundations) {
|
|
|
3225
3273
|
"",
|
|
3226
3274
|
"export const Default: Story = {",
|
|
3227
3275
|
" render: () => (",
|
|
3228
|
-
" <div style={{ fontFamily: \"system-ui,sans-serif\", padding: 32,
|
|
3276
|
+
" <div style={{ fontFamily: \"system-ui,sans-serif\", padding: 32, color: \"#111\", background: \"#fff\", minHeight: \"100vh\", width: \"100%\" }}>",
|
|
3229
3277
|
" <h2 style={{ fontSize: 20, fontWeight: 700, margin: \"0 0 4px\" }}>Spacing Scale</h2>",
|
|
3230
3278
|
" <p style={{ fontSize: 13, color: \"#888\", margin: \"0 0 24px\" }}>Base unit: 0.25rem = 4px · built on an 8px grid system</p>",
|
|
3231
3279
|
" {usedSpacing.length > 0 && (",
|
|
@@ -3335,7 +3383,7 @@ function writeFoundationsStories(foundations) {
|
|
|
3335
3383
|
"",
|
|
3336
3384
|
"export const Default: Story = {",
|
|
3337
3385
|
" render: () => (",
|
|
3338
|
-
" <div style={{ fontFamily: \"system-ui,sans-serif\", padding: 32, background: \"#fff\", minHeight: \"100vh\", color: \"#111\" }}>",
|
|
3386
|
+
" <div style={{ fontFamily: \"system-ui,sans-serif\", padding: 32, background: \"#fff\", minHeight: \"100vh\", width: \"100%\", color: \"#111\" }}>",
|
|
3339
3387
|
" <h2 style={{ fontSize: 20, fontWeight: 700, margin: \"0 0 4px\", color: \"#111\" }}>Elevation & Shadows</h2>",
|
|
3340
3388
|
" <p style={{ fontSize: 13, color: \"#888\", margin: \"0 0 32px\" }}>Depth is communicated through layered shadow levels</p>",
|
|
3341
3389
|
" <h3 style={{ fontSize: 15, fontWeight: 600, margin: \"0 0 14px\", color: \"#374151\" }}>Shadow Scale</h3>",
|
|
@@ -3453,7 +3501,7 @@ function writeFoundationsStories(foundations) {
|
|
|
3453
3501
|
"",
|
|
3454
3502
|
"export const Default: Story = {",
|
|
3455
3503
|
" render: () => (",
|
|
3456
|
-
" <div style={{ fontFamily: \"system-ui,sans-serif\", padding: 32,
|
|
3504
|
+
" <div style={{ fontFamily: \"system-ui,sans-serif\", padding: 32, background: \"#fff\", minHeight: \"100vh\", width: \"100%\", color: \"#111\" }}>",
|
|
3457
3505
|
" <h2 style={{ fontSize: 20, fontWeight: 700, margin: \"0 0 4px\" }}>Border & Radius</h2>",
|
|
3458
3506
|
" <p style={{ fontSize: 13, color: \"#888\", margin: \"0 0 32px\" }}>Corner radius scale — from sharp edges to fully rounded</p>",
|
|
3459
3507
|
" {usedRadius.length > 0 && (",
|
|
@@ -3584,7 +3632,7 @@ function writeFoundationsStories(foundations) {
|
|
|
3584
3632
|
" );",
|
|
3585
3633
|
"",
|
|
3586
3634
|
" return (",
|
|
3587
|
-
" <div style={{ padding: 40, fontFamily: \"system-ui,sans-serif\", background: \"#fff\", minHeight: \"100vh\", color: \"#111\" }}>",
|
|
3635
|
+
" <div style={{ padding: 40, fontFamily: \"system-ui,sans-serif\", background: \"#fff\", minHeight: \"100vh\", width: \"100%\", color: \"#111\" }}>",
|
|
3588
3636
|
" <h2 style={{ fontSize: 22, fontWeight: 700, margin: \"0 0 4px\" }}>Motion & Interaction</h2>",
|
|
3589
3637
|
" <p style={{ fontSize: 13, color: \"#6b7280\", margin: \"0 0 40px\" }}>Consistent timing and easing for smooth, intentional motion.</p>",
|
|
3590
3638
|
"",
|
|
@@ -3753,7 +3801,7 @@ function writeComponentSuggestionsStory(componentSuggestions) {
|
|
|
3753
3801
|
"",
|
|
3754
3802
|
"export const Default: Story = {",
|
|
3755
3803
|
" render: () => (",
|
|
3756
|
-
" <div style={{ padding: 32, fontFamily: 'system-ui, sans-serif', background: '#fff', minHeight: '100vh', color: '#111' }}>",
|
|
3804
|
+
" <div style={{ padding: 32, fontFamily: 'system-ui, sans-serif', background: '#fff', minHeight: '100vh', width: '100%', color: '#111' }}>",
|
|
3757
3805
|
" <h2 style={{ marginBottom: 8, fontSize: 24, fontWeight: 700, color: '#1a202c' }}>Component Suggestions</h2>",
|
|
3758
3806
|
" <p style={{ color: '#718096', marginBottom: 32, fontSize: 14 }}>Bu pattern'ler birden fazla dosyada tekrar ediyor. Her biri ayrı bir component olabilir. <strong>Copy Prompt</strong> butonuna tıklayıp Cursor veya Superflex'e yapıştır.</p>",
|
|
3759
3807
|
" <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>",
|
|
@@ -3782,23 +3830,49 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
3782
3830
|
"Forms and Input", "Status Indicators", "Navigation", "Overlays and Layering",
|
|
3783
3831
|
"Loading", "Messaging", "Images and Icons", "Layout and Structure", "Text and Data Display",
|
|
3784
3832
|
];
|
|
3785
|
-
const categorized = {}; // category → [{ name, group, tokenCount, propCount }]
|
|
3833
|
+
const categorized = {}; // category → [{ name, group, tokenCount, propCount, colorSwatches }]
|
|
3834
|
+
const foundColors = (foundations && foundations.colors) ? foundations.colors : {};
|
|
3786
3835
|
|
|
3787
3836
|
for (const comp of components) {
|
|
3788
3837
|
const g = comp.group || "Components";
|
|
3789
3838
|
const gLower = g.toLowerCase();
|
|
3790
|
-
const isShadcnGroup = gLower === "shadcn" || gLower === "ui";
|
|
3791
3839
|
const tokens = Array.isArray(comp.tokens) ? comp.tokens : [];
|
|
3792
3840
|
const props = Array.isArray(comp.props) ? comp.props : [];
|
|
3793
3841
|
const semantic = classifyComponent(comp.name, tokens, props);
|
|
3794
3842
|
const category = semantic || g;
|
|
3795
3843
|
|
|
3844
|
+
// Resolve color tokens to hex swatches from foundations.colors (max 6)
|
|
3845
|
+
const colorSwatches = tokens
|
|
3846
|
+
.filter(t => !/:/.test(t) &&
|
|
3847
|
+
/^(bg|text|border|ring|from|to|fill|stroke)-/.test(t) &&
|
|
3848
|
+
// Exclude border-side shorthands (b, t, l, r, x, y) and alignment/size text-* tokens
|
|
3849
|
+
!/^border-[btlrxy]$/.test(t) &&
|
|
3850
|
+
!/^text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl|\d|left|right|center|justify|start|end|wrap|nowrap|balance|pretty|clip|ellipsis)/.test(t))
|
|
3851
|
+
.slice(0, 6)
|
|
3852
|
+
.map(token => {
|
|
3853
|
+
const m = token.match(/^(?:bg|text|border|ring|from|to|fill|stroke)-(.+)$/);
|
|
3854
|
+
let key = m ? m[1] : null;
|
|
3855
|
+
// Strip opacity modifier: "muted/20" → "muted", "primary/5" → "primary"
|
|
3856
|
+
if (key) key = key.replace(/\/\d+$/, "");
|
|
3857
|
+
const entry = key ? foundColors[key] : null;
|
|
3858
|
+
const hex = entry?.hex && /^#[0-9a-fA-F]{3,8}$/.test(entry.hex) ? entry.hex : null;
|
|
3859
|
+
return { token, hex };
|
|
3860
|
+
})
|
|
3861
|
+
.filter(s => s.hex); // only swatches with resolved hex
|
|
3862
|
+
|
|
3863
|
+
// Representative token fingerprint (spacing + typography, max 4, no color)
|
|
3864
|
+
const tokenFingerprint = tokens
|
|
3865
|
+
.filter(t => !/:/.test(t) && !/^(bg|text|border|ring|from|to|fill|stroke)-/.test(t))
|
|
3866
|
+
.slice(0, 4);
|
|
3867
|
+
|
|
3796
3868
|
if (!categorized[category]) categorized[category] = [];
|
|
3797
3869
|
categorized[category].push({
|
|
3798
|
-
name:
|
|
3799
|
-
group:
|
|
3800
|
-
tokenCount:
|
|
3801
|
-
propCount:
|
|
3870
|
+
name: comp.name,
|
|
3871
|
+
group: g,
|
|
3872
|
+
tokenCount: tokens.filter(t => !/:/.test(t)).length,
|
|
3873
|
+
propCount: props.length,
|
|
3874
|
+
colorSwatches,
|
|
3875
|
+
tokenFingerprint,
|
|
3802
3876
|
});
|
|
3803
3877
|
}
|
|
3804
3878
|
|
|
@@ -3828,13 +3902,13 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
3828
3902
|
`export default meta;`,
|
|
3829
3903
|
`type Story = StoryObj;`,
|
|
3830
3904
|
``,
|
|
3831
|
-
`const inventoryData: { category: string; components: { name: string; group: string; tokenCount: number; propCount: number }[] }[] = ${JSON.stringify(inventoryData)};`,
|
|
3905
|
+
`const inventoryData: { category: string; components: { name: string; group: string; tokenCount: number; propCount: number; colorSwatches: { token: string; hex: string }[]; tokenFingerprint: string[] }[] }[] = ${JSON.stringify(inventoryData)};`,
|
|
3832
3906
|
`const totalComponents = ${totalComponents};`,
|
|
3833
3907
|
`const uniqueTokens = ${uniqueTokens};`,
|
|
3834
3908
|
``,
|
|
3835
3909
|
`export const Default: Story = {`,
|
|
3836
3910
|
` render: () => (`,
|
|
3837
|
-
` <div style={{ padding: 32, background: "#fff", fontFamily: "system-ui,sans-serif", color: "#111", minHeight: "100vh" }}>`,
|
|
3911
|
+
` <div style={{ padding: 32, background: "#fff", fontFamily: "system-ui,sans-serif", color: "#111", minHeight: "100vh", width: "100%" }}>`,
|
|
3838
3912
|
` {/* Header */}`,
|
|
3839
3913
|
` <div style={{ marginBottom: 40 }}>`,
|
|
3840
3914
|
` <h2 style={{ fontSize: 28, fontWeight: 700, margin: "0 0 8px" }}>Component Inventory</h2>`,
|
|
@@ -3859,26 +3933,51 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
3859
3933
|
` <h3 style={{ margin: 0, fontSize: 15, fontWeight: 700, color: "#111" }}>{group.category}</h3>`,
|
|
3860
3934
|
` <span style={{ fontSize: 12, background: "#e0e7ff", color: "#3730a3", padding: "2px 9px", borderRadius: 12, fontWeight: 600 }}>{group.components.length}</span>`,
|
|
3861
3935
|
` </div>`,
|
|
3862
|
-
` <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(
|
|
3936
|
+
` <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(210px, 1fr))", gap: 12 }}>`,
|
|
3863
3937
|
` {group.components.map(comp => (`,
|
|
3864
|
-
` <div key={comp.name} style={{ border: "1px solid #e5e7eb", borderRadius: 10,
|
|
3865
|
-
`
|
|
3866
|
-
`
|
|
3867
|
-
` {
|
|
3868
|
-
`
|
|
3869
|
-
` {
|
|
3870
|
-
`
|
|
3871
|
-
`
|
|
3872
|
-
`
|
|
3873
|
-
`
|
|
3874
|
-
`
|
|
3875
|
-
`
|
|
3876
|
-
`
|
|
3877
|
-
` {
|
|
3878
|
-
`
|
|
3879
|
-
`
|
|
3880
|
-
`
|
|
3938
|
+
` <div key={comp.name} style={{ border: "1px solid #e5e7eb", borderRadius: 10, overflow: "hidden", background: "#fff", display: "flex", flexDirection: "column" as any }}>`,
|
|
3939
|
+
` {/* Color swatch strip — project-resolved colors from foundations */}`,
|
|
3940
|
+
` {comp.colorSwatches.length > 0 ? (`,
|
|
3941
|
+
` <div style={{ display: "flex", height: 8 }}>`,
|
|
3942
|
+
` {comp.colorSwatches.map((s: any) => (`,
|
|
3943
|
+
` <div key={s.token} title={s.token} style={{ flex: 1, background: s.hex }} />`,
|
|
3944
|
+
` ))}`,
|
|
3945
|
+
` </div>`,
|
|
3946
|
+
` ) : (`,
|
|
3947
|
+
` <div style={{ height: 4, background: "#f3f4f6" }} />`,
|
|
3948
|
+
` )}`,
|
|
3949
|
+
` <div style={{ padding: "12px 14px", flexGrow: 1 }}>`,
|
|
3950
|
+
` <div style={{ fontWeight: 700, fontSize: 13, color: "#111", marginBottom: 6 }}>{comp.name}</div>`,
|
|
3951
|
+
` {/* Token fingerprint pills */}`,
|
|
3952
|
+
` {comp.tokenFingerprint.length > 0 && (`,
|
|
3953
|
+
` <div style={{ display: "flex", gap: 4, flexWrap: "wrap" as any, marginBottom: 8 }}>`,
|
|
3954
|
+
` {comp.tokenFingerprint.map((t: string) => (`,
|
|
3955
|
+
` <code key={t} style={{ fontSize: 9, background: "#f3f4f6", color: "#6b7280", padding: "1px 5px", borderRadius: 4, border: "1px solid #e5e7eb" }}>{t}</code>`,
|
|
3956
|
+
` ))}`,
|
|
3957
|
+
` </div>`,
|
|
3881
3958
|
` )}`,
|
|
3959
|
+
` <div style={{ display: "flex", gap: 5, flexWrap: "wrap" as any }}>`,
|
|
3960
|
+
` {comp.propCount > 0 && (`,
|
|
3961
|
+
` <span style={{ fontSize: 10, background: "#f3f4f6", color: "#6b7280", padding: "2px 7px", borderRadius: 10, border: "1px solid #e5e7eb" }}>`,
|
|
3962
|
+
` {comp.propCount} props`,
|
|
3963
|
+
` </span>`,
|
|
3964
|
+
` )}`,
|
|
3965
|
+
` {comp.tokenCount > 0 && (`,
|
|
3966
|
+
` <span style={{ fontSize: 10, background: "#eff6ff", color: "#1d4ed8", padding: "2px 7px", borderRadius: 10, border: "1px solid #dbeafe" }}>`,
|
|
3967
|
+
` {comp.tokenCount} tokens`,
|
|
3968
|
+
` </span>`,
|
|
3969
|
+
` )}`,
|
|
3970
|
+
` {comp.colorSwatches.length > 0 && (`,
|
|
3971
|
+
` <span style={{ fontSize: 10, background: "#fef9c3", color: "#713f12", padding: "2px 7px", borderRadius: 10, border: "1px solid #fde68a" }}>`,
|
|
3972
|
+
` {comp.colorSwatches.length} colors`,
|
|
3973
|
+
` </span>`,
|
|
3974
|
+
` )}`,
|
|
3975
|
+
` {comp.group && comp.group !== "shadcn" && comp.group !== "UI" && comp.group !== "Components" && (`,
|
|
3976
|
+
` <span style={{ fontSize: 10, background: "#f0fdf4", color: "#166534", padding: "2px 7px", borderRadius: 10, border: "1px solid #bbf7d0" }}>`,
|
|
3977
|
+
` {comp.group}`,
|
|
3978
|
+
` </span>`,
|
|
3979
|
+
` )}`,
|
|
3980
|
+
` </div>`,
|
|
3882
3981
|
` </div>`,
|
|
3883
3982
|
` </div>`,
|
|
3884
3983
|
` ))}`,
|
|
@@ -3894,6 +3993,46 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
3894
3993
|
console.log("[VDS] Wrote " + path.relative(PROJECT_ROOT, path.join(foundationsDir, "ComponentInventory.stories.tsx")));
|
|
3895
3994
|
}
|
|
3896
3995
|
|
|
3996
|
+
/**
|
|
3997
|
+
* Patches .storybook/preview.tsx so that Foundations stories bypass app-specific
|
|
3998
|
+
* provider decorators (SidebarProvider, etc.) that constrain child width in flex layout.
|
|
3999
|
+
* Uses the context.title to detect "Foundations/" prefix at runtime.
|
|
4000
|
+
*/
|
|
4001
|
+
function patchPreviewTsxFoundations() {
|
|
4002
|
+
const candidates = [
|
|
4003
|
+
path.join(PROJECT_ROOT, ".storybook", "preview.tsx"),
|
|
4004
|
+
path.join(PROJECT_ROOT, ".storybook", "preview.ts"),
|
|
4005
|
+
path.join(PROJECT_ROOT, ".storybook", "preview.jsx"),
|
|
4006
|
+
path.join(PROJECT_ROOT, ".storybook", "preview.js"),
|
|
4007
|
+
];
|
|
4008
|
+
const previewPath = candidates.find(p => fs.existsSync(p));
|
|
4009
|
+
if (!previewPath) return;
|
|
4010
|
+
|
|
4011
|
+
let content;
|
|
4012
|
+
try { content = fs.readFileSync(previewPath, "utf-8"); } catch { return; }
|
|
4013
|
+
|
|
4014
|
+
// Already patched?
|
|
4015
|
+
if (content.includes('startsWith("Foundations")')) return;
|
|
4016
|
+
|
|
4017
|
+
// Match: const withProviders = (Story: any) => React.createElement(AnyProvider, null, React.createElement(Story));
|
|
4018
|
+
const re = /const withProviders = \(Story(?:: any)?\) => (React\.createElement\([^;]+\));/;
|
|
4019
|
+
const match = content.match(re);
|
|
4020
|
+
if (!match) return; // Pattern not found — nothing to patch
|
|
4021
|
+
|
|
4022
|
+
const providerExpr = match[1]; // e.g. React.createElement(SidebarProvider, null, React.createElement(Story))
|
|
4023
|
+
const patched =
|
|
4024
|
+
`const withProviders = (Story: any, context: any) => ` +
|
|
4025
|
+
`context?.title?.startsWith("Foundations") ? React.createElement(Story) : ${providerExpr};`;
|
|
4026
|
+
|
|
4027
|
+
content = content.replace(re, patched);
|
|
4028
|
+
try {
|
|
4029
|
+
fs.writeFileSync(previewPath, content, "utf-8");
|
|
4030
|
+
console.log("[VDS] Patched .storybook/preview.tsx — Foundations stories now bypass app providers");
|
|
4031
|
+
} catch (e) {
|
|
4032
|
+
console.warn("[VDS] Could not patch preview.tsx:", e.message);
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
4035
|
+
|
|
3897
4036
|
function writeChangelogStory(changelog) {
|
|
3898
4037
|
const foundationsDir = path.join(STORIES_DIR, "foundations");
|
|
3899
4038
|
ensureDir(foundationsDir);
|
|
@@ -3910,7 +4049,7 @@ function writeChangelogStory(changelog) {
|
|
|
3910
4049
|
"",
|
|
3911
4050
|
"export const Default: Story = {",
|
|
3912
4051
|
" render: () => (",
|
|
3913
|
-
" <div style={{ fontFamily: \"system-ui,sans-serif\", padding: 32, background: \"#fff\", minHeight: \"100vh\", color: \"#111\" }}>",
|
|
4052
|
+
" <div style={{ fontFamily: \"system-ui,sans-serif\", padding: 32, background: \"#fff\", minHeight: \"100vh\", width: \"100%\", color: \"#111\" }}>",
|
|
3914
4053
|
" <h2>CHANGELOG</h2>",
|
|
3915
4054
|
" {changelog.length === 0 ? <p>No changes recorded yet.</p> : changelog.map((entry) => (",
|
|
3916
4055
|
" <div key={entry.version}>",
|
|
@@ -4168,6 +4307,7 @@ function main() {
|
|
|
4168
4307
|
}
|
|
4169
4308
|
writeComponentInventoryStory(components, foundations);
|
|
4170
4309
|
writeChangelogStory(data.changelog);
|
|
4310
|
+
patchPreviewTsxFoundations();
|
|
4171
4311
|
try {
|
|
4172
4312
|
const fd = path.join(STORIES_DIR, "foundations");
|
|
4173
4313
|
if (fs.existsSync(fd)) {
|