vibe-design-system 2.5.2 → 2.5.4
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
|
@@ -648,6 +648,74 @@ function toKebab(str) {
|
|
|
648
648
|
return str.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
649
649
|
}
|
|
650
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
|
+
i++;
|
|
670
|
+
let depth = 1;
|
|
671
|
+
while (i < len && depth > 0) {
|
|
672
|
+
const c = jsx[i];
|
|
673
|
+
if (c === "{") depth++;
|
|
674
|
+
else if (c === "}") depth--;
|
|
675
|
+
i++;
|
|
676
|
+
}
|
|
677
|
+
result += '{"Sample"}';
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
result += jsx[i];
|
|
681
|
+
i++;
|
|
682
|
+
}
|
|
683
|
+
return result;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/** Convert HTML style="key: value; ..." to React style={{ key: 'value', ... }} (camelCase keys). */
|
|
687
|
+
function convertHtmlStyleToReact(jsx) {
|
|
688
|
+
return jsx.replace(
|
|
689
|
+
/style\s*=\s*["']([^"']*)["']/g,
|
|
690
|
+
(_, cssStr) => {
|
|
691
|
+
const obj = {};
|
|
692
|
+
const parts = (cssStr || "").split(";").map((s) => s.trim()).filter(Boolean);
|
|
693
|
+
for (const part of parts) {
|
|
694
|
+
const colon = part.indexOf(":");
|
|
695
|
+
if (colon <= 0) continue;
|
|
696
|
+
const key = part.slice(0, colon).trim().replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
697
|
+
const value = part.slice(colon + 1).trim().replace(/^["']|["']$/g, "");
|
|
698
|
+
if (key) obj[key] = value;
|
|
699
|
+
}
|
|
700
|
+
if (Object.keys(obj).length === 0) return "style={{}}";
|
|
701
|
+
const entries = Object.entries(obj).map(([k, v]) => `${k}: "${String(v).replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`).join(", ");
|
|
702
|
+
return `style={{ ${entries} }}`;
|
|
703
|
+
}
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/** Replace Lucide icon tags with LucideIcons.TagName so namespace import works. */
|
|
708
|
+
function applyLucideNamespace(jsx, lucideTags) {
|
|
709
|
+
let out = jsx;
|
|
710
|
+
for (const tag of lucideTags) {
|
|
711
|
+
const openRe = new RegExp("<" + tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "(?=[\\s/>])", "g");
|
|
712
|
+
const closeRe = new RegExp("</" + tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + ">", "g");
|
|
713
|
+
out = out.replace(openRe, "<LucideIcons." + tag);
|
|
714
|
+
out = out.replace(closeRe, "</LucideIcons." + tag + ">");
|
|
715
|
+
}
|
|
716
|
+
return out;
|
|
717
|
+
}
|
|
718
|
+
|
|
651
719
|
/** Collect PascalCase tag names from JSX that are not known HTML. */
|
|
652
720
|
function collectComponentTags(jsx) {
|
|
653
721
|
const tags = new Set();
|
|
@@ -679,7 +747,8 @@ function writeVdsGeneratedComponents(suggestions) {
|
|
|
679
747
|
let bodyJsx;
|
|
680
748
|
const tokens = [];
|
|
681
749
|
if (s.fullJsx && s.fullJsx.trim().length > 0) {
|
|
682
|
-
bodyJsx = s.fullJsx;
|
|
750
|
+
bodyJsx = flattenJsx(s.fullJsx);
|
|
751
|
+
bodyJsx = convertHtmlStyleToReact(bodyJsx);
|
|
683
752
|
const componentTags = collectComponentTags(bodyJsx);
|
|
684
753
|
const lucideTags = [];
|
|
685
754
|
const uiTags = [];
|
|
@@ -687,15 +756,14 @@ function writeVdsGeneratedComponents(suggestions) {
|
|
|
687
756
|
if (/^[A-Z][a-z0-9]+$/.test(tag) && tag.length > 2) lucideTags.push(tag);
|
|
688
757
|
else uiTags.push(tag);
|
|
689
758
|
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
}
|
|
759
|
+
bodyJsx = applyLucideNamespace(bodyJsx, lucideTags);
|
|
760
|
+
const standardImports = [
|
|
761
|
+
'import React from "react";',
|
|
762
|
+
'import { motion } from "framer-motion";',
|
|
763
|
+
'import * as LucideIcons from "lucide-react";',
|
|
764
|
+
];
|
|
765
|
+
const uiImportLines = uiTags.map((tag) => `import { ${tag} } from "@/components/ui/${toKebab(tag)}";`);
|
|
766
|
+
const importLines = [...standardImports, ...uiImportLines];
|
|
699
767
|
const content = importLines.join("\n") + "\n\n" +
|
|
700
768
|
`export function ${componentName}() {\n return (\n ` +
|
|
701
769
|
bodyJsx.replace(/\n/g, "\n ") + "\n );\n}\n";
|
|
@@ -705,7 +773,9 @@ function writeVdsGeneratedComponents(suggestions) {
|
|
|
705
773
|
const tagName = s.tagName || "div";
|
|
706
774
|
const className = s.pattern || "";
|
|
707
775
|
bodyJsx = `<${tagName} className="${className.replace(/"/g, '\\"')}">\n {null}\n </${tagName}>`;
|
|
708
|
-
const content = `import
|
|
776
|
+
const content = `import React from "react";
|
|
777
|
+
import { motion } from "framer-motion";
|
|
778
|
+
import * as LucideIcons from "lucide-react";
|
|
709
779
|
|
|
710
780
|
export function ${componentName}() {
|
|
711
781
|
return (
|
|
@@ -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") {
|