vibe-design-system 2.5.1 → 2.5.3
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
|
@@ -620,7 +620,7 @@ function extractComponentSuggestions() {
|
|
|
620
620
|
if (count < 2) continue;
|
|
621
621
|
const suggestedName = suggestNameFromContent(innerText) || suggestNameFromPattern(pattern);
|
|
622
622
|
suggestions.push({
|
|
623
|
-
suggestedName: suggestedName.replace(/\s+/g, ""),
|
|
623
|
+
suggestedName: sanitizeComponentName(suggestedName.replace(/\s+/g, "")),
|
|
624
624
|
tagName: tagName || "div",
|
|
625
625
|
pattern,
|
|
626
626
|
fullJsx,
|
|
@@ -635,10 +635,55 @@ function extractComponentSuggestions() {
|
|
|
635
635
|
|
|
636
636
|
const VDS_GENERATED_DIR = path.join(COMPONENTS_DIR, "vds-generated");
|
|
637
637
|
|
|
638
|
+
/** Ensure component name is valid JS: no leading digits/special chars, PascalCase. */
|
|
639
|
+
function sanitizeComponentName(name) {
|
|
640
|
+
if (!name || typeof name !== "string") return "Extracted";
|
|
641
|
+
let s = name.replace(/\s+/g, "").replace(/^[0-9\W_]+/, "");
|
|
642
|
+
if (!s) return "Extracted";
|
|
643
|
+
s = s.charAt(0).toUpperCase() + s.slice(1);
|
|
644
|
+
return s;
|
|
645
|
+
}
|
|
646
|
+
|
|
638
647
|
function toKebab(str) {
|
|
639
648
|
return str.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
640
649
|
}
|
|
641
650
|
|
|
651
|
+
/** Flatten JSX: replace ${...} and {...} (variables/expressions) with placeholders so generated component has no "item is not defined". */
|
|
652
|
+
function flattenJsx(jsx) {
|
|
653
|
+
let result = "";
|
|
654
|
+
let i = 0;
|
|
655
|
+
const len = jsx.length;
|
|
656
|
+
while (i < len) {
|
|
657
|
+
if (jsx.slice(i, i + 2) === "${") {
|
|
658
|
+
i += 2;
|
|
659
|
+
let depth = 1;
|
|
660
|
+
while (i < len && depth > 0) {
|
|
661
|
+
if (jsx[i] === "{") depth++;
|
|
662
|
+
else if (jsx[i] === "}") depth--;
|
|
663
|
+
i++;
|
|
664
|
+
}
|
|
665
|
+
result += '"Sample"';
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
if (jsx[i] === "{" && (i === 0 || jsx[i - 1] !== "{")) {
|
|
669
|
+
const start = i;
|
|
670
|
+
i++;
|
|
671
|
+
let depth = 1;
|
|
672
|
+
while (i < len && depth > 0) {
|
|
673
|
+
const c = jsx[i];
|
|
674
|
+
if (c === "{") depth++;
|
|
675
|
+
else if (c === "}") depth--;
|
|
676
|
+
i++;
|
|
677
|
+
}
|
|
678
|
+
result += '{"Sample"}';
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
result += jsx[i];
|
|
682
|
+
i++;
|
|
683
|
+
}
|
|
684
|
+
return result;
|
|
685
|
+
}
|
|
686
|
+
|
|
642
687
|
/** Collect PascalCase tag names from JSX that are not known HTML. */
|
|
643
688
|
function collectComponentTags(jsx) {
|
|
644
689
|
const tags = new Set();
|
|
@@ -659,7 +704,7 @@ function writeVdsGeneratedComponents(suggestions) {
|
|
|
659
704
|
const entries = [];
|
|
660
705
|
for (let i = 0; i < suggestions.length; i++) {
|
|
661
706
|
const s = suggestions[i];
|
|
662
|
-
let baseName = (s.suggestedName || "Extracted")
|
|
707
|
+
let baseName = sanitizeComponentName(s.suggestedName || "Extracted");
|
|
663
708
|
let fileName = baseName + ".tsx";
|
|
664
709
|
if (usedNames.has(fileName)) fileName = baseName + String(i + 1) + ".tsx";
|
|
665
710
|
usedNames.add(fileName);
|
|
@@ -670,7 +715,7 @@ function writeVdsGeneratedComponents(suggestions) {
|
|
|
670
715
|
let bodyJsx;
|
|
671
716
|
const tokens = [];
|
|
672
717
|
if (s.fullJsx && s.fullJsx.trim().length > 0) {
|
|
673
|
-
bodyJsx = s.fullJsx;
|
|
718
|
+
bodyJsx = flattenJsx(s.fullJsx);
|
|
674
719
|
const componentTags = collectComponentTags(bodyJsx);
|
|
675
720
|
const lucideTags = [];
|
|
676
721
|
const uiTags = [];
|
|
@@ -587,9 +587,10 @@ function buildStoryFileContent(comp) {
|
|
|
587
587
|
}
|
|
588
588
|
const exportStyle = detectExportStyle(source, componentName);
|
|
589
589
|
const omitChildren = componentWrapsVoidElement(source);
|
|
590
|
+
const isPage = comp.file.startsWith("pages/");
|
|
590
591
|
|
|
591
|
-
// Skip story if
|
|
592
|
-
if (exportStyle === "unknown" && (!source.includes("export") || !new RegExp(`\\b${componentName}\\b`).test(source))) {
|
|
592
|
+
// Skip story only if not a page and no export found
|
|
593
|
+
if (exportStyle === "unknown" && !isPage && (!source.includes("export") || !new RegExp(`\\b${componentName}\\b`).test(source))) {
|
|
593
594
|
return null;
|
|
594
595
|
}
|
|
595
596
|
|
|
@@ -600,7 +601,10 @@ function buildStoryFileContent(comp) {
|
|
|
600
601
|
const lines = [];
|
|
601
602
|
lines.push(`import type { Meta, StoryObj } from "@storybook/react";`);
|
|
602
603
|
|
|
603
|
-
if (exportStyle
|
|
604
|
+
if (isPage && exportStyle !== "default") {
|
|
605
|
+
lines.push(`import * as Named from "${importPath}";`);
|
|
606
|
+
lines.push(`const ComponentRef = Named["${componentName}"] ?? Named.default;`);
|
|
607
|
+
} else if (exportStyle === "default") {
|
|
604
608
|
lines.push(`import ${componentName} from "${importPath}";`);
|
|
605
609
|
lines.push(`const ComponentRef = ${componentName};`);
|
|
606
610
|
} else if (exportStyle === "named" || exportStyle === "unknown") {
|