vibe-design-system 2.5.9 → 2.5.11
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/bin/init.js +6 -3
- package/package.json +1 -1
- package/vds-core-template/scan.mjs +49 -107
- package/vds-core-template/story-generator.mjs +15 -20
package/bin/init.js
CHANGED
|
@@ -63,18 +63,21 @@ const preview: Preview = {
|
|
|
63
63
|
"Foundations",
|
|
64
64
|
["Introduction", "Page to Components", "Colors", "Typography", "Brand", "Icons", "Component Suggestions", "Changelog"],
|
|
65
65
|
"Layout",
|
|
66
|
-
["Navigation", "Footer", "ScrollToTop"],
|
|
67
66
|
"Components",
|
|
68
67
|
"Actions",
|
|
69
68
|
"Data Display",
|
|
70
69
|
"Examples",
|
|
71
|
-
["Pages"],
|
|
72
70
|
],
|
|
73
71
|
},
|
|
74
72
|
},
|
|
75
73
|
},
|
|
76
74
|
decorators: [
|
|
77
|
-
(Story) =>
|
|
75
|
+
(Story, context) => {
|
|
76
|
+
const needsRouter = context.parameters?.router !== false;
|
|
77
|
+
return needsRouter
|
|
78
|
+
? React.createElement(MemoryRouter, null, React.createElement(Story, null))
|
|
79
|
+
: React.createElement(Story, null);
|
|
80
|
+
},
|
|
78
81
|
],
|
|
79
82
|
};
|
|
80
83
|
|
package/package.json
CHANGED
|
@@ -237,101 +237,11 @@ function compareComponents(prevList, newResults) {
|
|
|
237
237
|
return { added, removed, modified };
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
{
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
"figmalibrarygenerator",
|
|
246
|
-
"integrationguide",
|
|
247
|
-
"projectdropzone",
|
|
248
|
-
"repoconnect",
|
|
249
|
-
"tokensstudioguide",
|
|
250
|
-
],
|
|
251
|
-
group: "Sections",
|
|
252
|
-
category: "Features",
|
|
253
|
-
},
|
|
254
|
-
{ keywords: ["hover-card"], group: "Feedback", category: "Feedback" },
|
|
255
|
-
{
|
|
256
|
-
keywords: [
|
|
257
|
-
"card",
|
|
258
|
-
"table",
|
|
259
|
-
"list",
|
|
260
|
-
"badge",
|
|
261
|
-
"avatar",
|
|
262
|
-
"chart",
|
|
263
|
-
"accordion",
|
|
264
|
-
"tabs",
|
|
265
|
-
"collapsible",
|
|
266
|
-
"toggle-group",
|
|
267
|
-
"carousel",
|
|
268
|
-
"scroll-area",
|
|
269
|
-
],
|
|
270
|
-
group: "Data Display",
|
|
271
|
-
category: "Data Display",
|
|
272
|
-
},
|
|
273
|
-
{ keywords: ["toggle"], group: "Actions", category: "Toggle" },
|
|
274
|
-
{ keywords: ["button", "cta"], group: "Actions", category: "Button" },
|
|
275
|
-
{ keywords: ["drawer", "sheet"], group: "Feedback", category: "Overlay" },
|
|
276
|
-
{
|
|
277
|
-
keywords: [
|
|
278
|
-
"modal",
|
|
279
|
-
"dialog",
|
|
280
|
-
"alert",
|
|
281
|
-
"toast",
|
|
282
|
-
"toaster",
|
|
283
|
-
"sonner",
|
|
284
|
-
"tooltip",
|
|
285
|
-
"popover",
|
|
286
|
-
"hover-card",
|
|
287
|
-
"progress",
|
|
288
|
-
"skeleton",
|
|
289
|
-
],
|
|
290
|
-
group: "Feedback",
|
|
291
|
-
category: "Feedback",
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
keywords: [
|
|
295
|
-
"input",
|
|
296
|
-
"form",
|
|
297
|
-
"select",
|
|
298
|
-
"checkbox",
|
|
299
|
-
"textarea",
|
|
300
|
-
"label",
|
|
301
|
-
"switch",
|
|
302
|
-
"radio",
|
|
303
|
-
"slider",
|
|
304
|
-
"calendar",
|
|
305
|
-
"input-otp",
|
|
306
|
-
"command",
|
|
307
|
-
],
|
|
308
|
-
group: "Forms",
|
|
309
|
-
category: "Forms",
|
|
310
|
-
},
|
|
311
|
-
{
|
|
312
|
-
keywords: [
|
|
313
|
-
"nav",
|
|
314
|
-
"header",
|
|
315
|
-
"sidebar",
|
|
316
|
-
"menu",
|
|
317
|
-
"menubar",
|
|
318
|
-
"dropdown-menu",
|
|
319
|
-
"navigation-menu",
|
|
320
|
-
"context-menu",
|
|
321
|
-
"navlink",
|
|
322
|
-
"breadcrumb",
|
|
323
|
-
"pagination",
|
|
324
|
-
],
|
|
325
|
-
group: "Navigation",
|
|
326
|
-
category: "Navigation",
|
|
327
|
-
},
|
|
328
|
-
{ keywords: ["separator", "aspect-ratio", "resizable"], group: "Layout", category: "Layout" },
|
|
329
|
-
{
|
|
330
|
-
keywords: ["hero", "banner", "section", "pricing", "feature", "featuresgrid", "interactivedemo", "modernhero"],
|
|
331
|
-
group: "Sections",
|
|
332
|
-
category: "Sections",
|
|
333
|
-
},
|
|
334
|
-
];
|
|
240
|
+
/** Path-based classification: ui/ → shadcn, components root → Components, else Uncategorized. */
|
|
241
|
+
function classifyByPath(rel) {
|
|
242
|
+
if (rel.startsWith("ui/")) return { group: "shadcn", category: "UI" };
|
|
243
|
+
return { group: "Components", category: "Components" };
|
|
244
|
+
}
|
|
335
245
|
|
|
336
246
|
function getAllComponentFiles(dir, baseDir = dir) {
|
|
337
247
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -441,14 +351,6 @@ function extractVdsTags(content) {
|
|
|
441
351
|
return Object.keys(tags).length ? tags : null;
|
|
442
352
|
}
|
|
443
353
|
|
|
444
|
-
function classifyByFileName(filePath) {
|
|
445
|
-
const baseName = path.basename(filePath, path.extname(filePath)).toLowerCase();
|
|
446
|
-
for (const rule of CLASSIFICATION_RULES) {
|
|
447
|
-
const found = rule.keywords.some((kw) => baseName.includes(kw));
|
|
448
|
-
if (found) return { group: rule.group, category: rule.category };
|
|
449
|
-
}
|
|
450
|
-
return { group: "Uncategorized", category: "Uncategorized" };
|
|
451
|
-
}
|
|
452
354
|
|
|
453
355
|
function humanizeName(filePath) {
|
|
454
356
|
const base = path.basename(filePath, path.extname(filePath));
|
|
@@ -872,9 +774,27 @@ function parseCssVarBlock(block) {
|
|
|
872
774
|
return out;
|
|
873
775
|
}
|
|
874
776
|
|
|
777
|
+
/** Return only theme.extend.colors from tailwind config (user-defined colors), not the default Tailwind palette. */
|
|
778
|
+
function getTailwindExtendColors() {
|
|
779
|
+
try {
|
|
780
|
+
const twPath = path.join(PROJECT_ROOT, "tailwind.config.js");
|
|
781
|
+
const twPathMjs = path.join(PROJECT_ROOT, "tailwind.config.mjs");
|
|
782
|
+
let config = null;
|
|
783
|
+
if (fs.existsSync(twPath)) {
|
|
784
|
+
config = projectRequire(twPath);
|
|
785
|
+
} else if (fs.existsSync(twPathMjs)) {
|
|
786
|
+
config = projectRequire(twPathMjs);
|
|
787
|
+
}
|
|
788
|
+
if (config && typeof config === "object" && config.default) config = config.default;
|
|
789
|
+
return config?.theme?.extend?.colors ?? null;
|
|
790
|
+
} catch (_) {
|
|
791
|
+
return null;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
875
795
|
/** Resolve Tailwind theme for boxShadow, spacing, screens, zIndex, motion. Uses resolveConfig when available. */
|
|
876
796
|
function getTailwindTheme() {
|
|
877
|
-
const empty = { shadows: {}, spacing: {}, breakpoints: {}, zIndex: {}, transitionDuration: {}, transitionTimingFunction: {}, animation: {} };
|
|
797
|
+
const empty = { shadows: {}, spacing: {}, breakpoints: {}, zIndex: {}, transitionDuration: {}, transitionTimingFunction: {}, animation: {}, colors: {} };
|
|
878
798
|
try {
|
|
879
799
|
const resolveConfig = projectRequire("tailwindcss/resolveConfig");
|
|
880
800
|
let config = { content: [{ raw: "", extension: "html" }], theme: {} };
|
|
@@ -896,6 +816,7 @@ function getTailwindTheme() {
|
|
|
896
816
|
const transitionDuration = theme.transitionDuration;
|
|
897
817
|
const transitionTimingFunction = theme.transitionTimingFunction;
|
|
898
818
|
const animation = theme.animation;
|
|
819
|
+
const themeColors = theme.colors;
|
|
899
820
|
const toObj = (v) => (v && typeof v === "object" && !Array.isArray(v) ? v : {});
|
|
900
821
|
return {
|
|
901
822
|
shadows: toObj(boxShadow),
|
|
@@ -905,6 +826,7 @@ function getTailwindTheme() {
|
|
|
905
826
|
transitionDuration: toObj(transitionDuration),
|
|
906
827
|
transitionTimingFunction: toObj(transitionTimingFunction),
|
|
907
828
|
animation: toObj(animation),
|
|
829
|
+
colors: toObj(themeColors),
|
|
908
830
|
};
|
|
909
831
|
} catch (_) {
|
|
910
832
|
return empty;
|
|
@@ -919,8 +841,15 @@ function extractFoundations() {
|
|
|
919
841
|
const borderRadiusScale = {};
|
|
920
842
|
const cssPath = path.join(PROJECT_ROOT, "src", "index.css");
|
|
921
843
|
const globalsCss = path.join(PROJECT_ROOT, "src", "globals.css");
|
|
844
|
+
const stylesGlobals = path.join(PROJECT_ROOT, "src", "styles", "globals.css");
|
|
922
845
|
const appGlobals = path.join(PROJECT_ROOT, "app", "globals.css");
|
|
923
|
-
const cssToRead = fs.existsSync(cssPath)
|
|
846
|
+
const cssToRead = fs.existsSync(cssPath)
|
|
847
|
+
? cssPath
|
|
848
|
+
: fs.existsSync(globalsCss)
|
|
849
|
+
? globalsCss
|
|
850
|
+
: fs.existsSync(stylesGlobals)
|
|
851
|
+
? stylesGlobals
|
|
852
|
+
: appGlobals;
|
|
924
853
|
|
|
925
854
|
try {
|
|
926
855
|
if (fs.existsSync(cssToRead)) {
|
|
@@ -1130,6 +1059,19 @@ function extractFoundations() {
|
|
|
1130
1059
|
const foundationsColors = { ...colors };
|
|
1131
1060
|
if (Object.keys(colorsDark).length > 0) foundationsColors._dark = colorsDark;
|
|
1132
1061
|
|
|
1062
|
+
const extendColors = getTailwindExtendColors();
|
|
1063
|
+
if (extendColors && typeof extendColors === "object") {
|
|
1064
|
+
for (const [key, val] of Object.entries(extendColors)) {
|
|
1065
|
+
if (typeof val === "string" && (val.startsWith("#") || /^[a-z]/.test(val))) {
|
|
1066
|
+
foundationsColors[key] = { value: val, hex: val.startsWith("#") ? val : val };
|
|
1067
|
+
} else if (typeof val === "object" && val !== null && !Array.isArray(val)) {
|
|
1068
|
+
for (const [k, v] of Object.entries(val)) {
|
|
1069
|
+
if (typeof v === "string") foundationsColors[`${key}-${k}`] = { value: v, hex: v.startsWith("#") ? v : v };
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1133
1075
|
const twTheme = getTailwindTheme();
|
|
1134
1076
|
const normalizeThemeObj = (obj) => {
|
|
1135
1077
|
if (!obj || typeof obj !== "object") return {};
|
|
@@ -1173,7 +1115,7 @@ function scan() {
|
|
|
1173
1115
|
name = vdsTags.name ?? humanizeName(rel);
|
|
1174
1116
|
description = vdsTags.description ?? "";
|
|
1175
1117
|
} else {
|
|
1176
|
-
const classified =
|
|
1118
|
+
const classified = classifyByPath(rel);
|
|
1177
1119
|
group = classified.group;
|
|
1178
1120
|
category = classified.category;
|
|
1179
1121
|
name = humanizeName(rel);
|
|
@@ -1192,7 +1134,7 @@ function scan() {
|
|
|
1192
1134
|
results.push({
|
|
1193
1135
|
file: "pages/" + rel,
|
|
1194
1136
|
name,
|
|
1195
|
-
group: "
|
|
1137
|
+
group: "Pages",
|
|
1196
1138
|
category: "Pages",
|
|
1197
1139
|
description: "",
|
|
1198
1140
|
tokens,
|
|
@@ -350,6 +350,12 @@ function needsRouter(source) {
|
|
|
350
350
|
return false;
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
+
/** Detect if component provides its own router (BrowserRouter or RouterProvider). Preview should not wrap with MemoryRouter. */
|
|
354
|
+
function usesOwnRouter(source) {
|
|
355
|
+
if (!source || typeof source !== "string") return false;
|
|
356
|
+
return /\bBrowserRouter\b|\bRouterProvider\b/.test(source);
|
|
357
|
+
}
|
|
358
|
+
|
|
353
359
|
/** Void HTML elements: img, input, hr, br — must not receive children. If component wraps one and has children in props, omit children in story args. */
|
|
354
360
|
function componentWrapsVoidElement(source) {
|
|
355
361
|
if (!source || typeof source !== "string") return false;
|
|
@@ -486,7 +492,6 @@ function buildSpecialStories(componentName, variants) {
|
|
|
486
492
|
function buildRecipeStoryContent(comp, componentName, importPath, title, source, exportStyle, recipe) {
|
|
487
493
|
const lines = [];
|
|
488
494
|
lines.push(`import type { Meta, StoryObj } from "@storybook/react";`);
|
|
489
|
-
const useRouterDecorator = needsRouter(source);
|
|
490
495
|
if (exportStyle === "default") {
|
|
491
496
|
lines.push(`import ${componentName} from "${importPath}";`);
|
|
492
497
|
if (recipe.imports?.length) {
|
|
@@ -507,18 +512,14 @@ function buildRecipeStoryContent(comp, componentName, importPath, title, source,
|
|
|
507
512
|
for (const ext of recipe.extraImports || []) {
|
|
508
513
|
lines.push(`import { ${ext.names.join(", ")} } from "${ext.from}";`);
|
|
509
514
|
}
|
|
510
|
-
|
|
515
|
+
const skipPreviewRouter = usesOwnRouter(source);
|
|
511
516
|
lines.push("");
|
|
512
517
|
lines.push(`const meta = {`);
|
|
513
518
|
lines.push(` title: ${JSON.stringify(title)},`);
|
|
514
519
|
lines.push(` component: ComponentRef,`);
|
|
515
520
|
lines.push(` tags: ["autodocs"],`);
|
|
516
|
-
if (
|
|
517
|
-
lines.push(`
|
|
518
|
-
lines.push(` <MemoryRouter>`);
|
|
519
|
-
lines.push(` <Story />`);
|
|
520
|
-
lines.push(` </MemoryRouter>`);
|
|
521
|
-
lines.push(` )],`);
|
|
521
|
+
if (skipPreviewRouter) {
|
|
522
|
+
lines.push(` parameters: { router: false },`);
|
|
522
523
|
}
|
|
523
524
|
lines.push(`} satisfies Meta<typeof ComponentRef>;`);
|
|
524
525
|
lines.push("");
|
|
@@ -619,22 +620,14 @@ function buildStoryFileContent(comp) {
|
|
|
619
620
|
lines.push(`const ComponentRef = ${namedAlias} ?? ${defaultAlias};`);
|
|
620
621
|
}
|
|
621
622
|
|
|
622
|
-
const
|
|
623
|
-
if (useRouterDecorator) {
|
|
624
|
-
lines.push(`import { MemoryRouter } from "react-router-dom";`);
|
|
625
|
-
}
|
|
626
|
-
|
|
623
|
+
const skipPreviewRouter = usesOwnRouter(source);
|
|
627
624
|
lines.push("");
|
|
628
625
|
lines.push(`const meta = {`);
|
|
629
626
|
lines.push(` title: ${JSON.stringify(title)},`);
|
|
630
627
|
lines.push(` component: ComponentRef,`);
|
|
631
628
|
lines.push(` tags: ["autodocs"],`);
|
|
632
|
-
if (
|
|
633
|
-
lines.push(`
|
|
634
|
-
lines.push(` <MemoryRouter>`);
|
|
635
|
-
lines.push(` <Story />`);
|
|
636
|
-
lines.push(` </MemoryRouter>`);
|
|
637
|
-
lines.push(` )],`);
|
|
629
|
+
if (skipPreviewRouter) {
|
|
630
|
+
lines.push(` parameters: { router: false },`);
|
|
638
631
|
}
|
|
639
632
|
lines.push(`} satisfies Meta<typeof ComponentRef>;`);
|
|
640
633
|
lines.push("");
|
|
@@ -958,9 +951,11 @@ function main() {
|
|
|
958
951
|
}
|
|
959
952
|
|
|
960
953
|
for (const comp of components) {
|
|
954
|
+
if (comp.group === "shadcn" || comp.group === "Uncategorized") continue;
|
|
955
|
+
if (comp.group !== "Components") continue;
|
|
956
|
+
|
|
961
957
|
const componentName = toSafeComponentName(comp.name, comp.file);
|
|
962
958
|
if (onlyName && componentName !== onlyName) continue;
|
|
963
|
-
if (!comp.file.startsWith("ui/") && !comp.file.startsWith("pages/")) continue;
|
|
964
959
|
|
|
965
960
|
const storyFileName = `${componentName}.stories.tsx`;
|
|
966
961
|
const storyPath = path.join(STORIES_DIR, storyFileName);
|