vibe-design-system 2.8.69 → 2.8.71
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
|
@@ -4036,10 +4036,39 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
4036
4036
|
return name.replace(/[-\s]+(.)/g, (_, c) => c.toUpperCase()).replace(/^(.)/, c => c.toUpperCase());
|
|
4037
4037
|
}
|
|
4038
4038
|
|
|
4039
|
-
const importInfoMap = {}; // comp.name → { identifier, importAlias, isDefault }
|
|
4039
|
+
const importInfoMap = {}; // comp.name → { identifier, importAlias, isDefault, actualExport, skip }
|
|
4040
4040
|
const seenAliases = new Set();
|
|
4041
4041
|
const orderedImports = []; // deduplicated
|
|
4042
4042
|
|
|
4043
|
+
// Detect actual usable export from a source file.
|
|
4044
|
+
// Returns { actualExport, isDefault } or null if no PascalCase export found.
|
|
4045
|
+
function detectExport(srcPath, expectedId) {
|
|
4046
|
+
try {
|
|
4047
|
+
const src = fs.readFileSync(srcPath, 'utf-8');
|
|
4048
|
+
// Exact named export: export { Foo } or export const/function/class Foo
|
|
4049
|
+
if (new RegExp(`export\\s*\\{[^}]*\\b${expectedId}\\b`).test(src) ||
|
|
4050
|
+
new RegExp(`export\\s+(?:const|function|class)\\s+${expectedId}\\b`).test(src)) {
|
|
4051
|
+
return { actualExport: expectedId, isDefault: false };
|
|
4052
|
+
}
|
|
4053
|
+
// Default export
|
|
4054
|
+
if (/export\s+default\b/.test(src)) {
|
|
4055
|
+
return { actualExport: expectedId, isDefault: true };
|
|
4056
|
+
}
|
|
4057
|
+
// Any PascalCase named export from brace-export block
|
|
4058
|
+
const braceMatch = src.match(/export\s*\{([^}]+)\}/);
|
|
4059
|
+
if (braceMatch) {
|
|
4060
|
+
const names = braceMatch[1].split(',')
|
|
4061
|
+
.map(n => n.trim().replace(/\s+as\s+\S+/, '').trim())
|
|
4062
|
+
.filter(n => /^[A-Z]/.test(n));
|
|
4063
|
+
if (names.length > 0) return { actualExport: names[0], isDefault: false };
|
|
4064
|
+
}
|
|
4065
|
+
// Any PascalCase direct export
|
|
4066
|
+
const directMatch = src.match(/export\s+(?:const|function|class)\s+([A-Z]\w*)/);
|
|
4067
|
+
if (directMatch) return { actualExport: directMatch[1], isDefault: false };
|
|
4068
|
+
return null; // no usable export
|
|
4069
|
+
} catch { return { actualExport: expectedId, isDefault: false }; }
|
|
4070
|
+
}
|
|
4071
|
+
|
|
4043
4072
|
for (const comp of components) {
|
|
4044
4073
|
if (!comp.file) continue;
|
|
4045
4074
|
const identifier = toPascalLocal(comp.name);
|
|
@@ -4057,20 +4086,26 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
4057
4086
|
importAlias = `@/${compBase}/${posixNoExt}`;
|
|
4058
4087
|
}
|
|
4059
4088
|
|
|
4060
|
-
// Detect
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
: path.join(PROJECT_ROOT, COMPONENTS_REL_DIR, comp.file);
|
|
4066
|
-
isDefault = /export\s+default\b/.test(fs.readFileSync(srcPath, 'utf-8'));
|
|
4067
|
-
} catch { /* keep false */ }
|
|
4089
|
+
// Detect actual export name in the file
|
|
4090
|
+
const srcPath = isProjectRelative
|
|
4091
|
+
? absFromRoot
|
|
4092
|
+
: path.join(PROJECT_ROOT, COMPONENTS_REL_DIR, comp.file);
|
|
4093
|
+
const exportInfo = detectExport(srcPath, identifier);
|
|
4068
4094
|
|
|
4069
|
-
|
|
4095
|
+
if (!exportInfo) {
|
|
4096
|
+
// No usable export — skip import, will fall back to shape HTML
|
|
4097
|
+
importInfoMap[comp.name] = { identifier, importAlias, isDefault: false, actualExport: null, skip: true };
|
|
4098
|
+
continue;
|
|
4099
|
+
}
|
|
4100
|
+
|
|
4101
|
+
const { actualExport, isDefault } = exportInfo;
|
|
4102
|
+
const isShadcn = (comp.group || '').toLowerCase() === 'shadcn';
|
|
4103
|
+
importInfoMap[comp.name] = { identifier, importAlias, isDefault, actualExport, skip: false, isShadcn };
|
|
4070
4104
|
|
|
4071
|
-
|
|
4105
|
+
// Only import shadcn UI primitives — project components are shown via story iframes
|
|
4106
|
+
if (isShadcn && !seenAliases.has(importAlias)) {
|
|
4072
4107
|
seenAliases.add(importAlias);
|
|
4073
|
-
orderedImports.push({ identifier, importAlias, isDefault });
|
|
4108
|
+
orderedImports.push({ identifier, importAlias, isDefault, actualExport });
|
|
4074
4109
|
}
|
|
4075
4110
|
}
|
|
4076
4111
|
|
|
@@ -4144,16 +4179,22 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
4144
4179
|
)].length;
|
|
4145
4180
|
|
|
4146
4181
|
// ── Build import lines ─────────────────────────────────────────────────────
|
|
4147
|
-
const importLines = orderedImports.map(imp =>
|
|
4148
|
-
imp.isDefault
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4182
|
+
const importLines = orderedImports.map(imp => {
|
|
4183
|
+
if (imp.isDefault) return `import ${imp.identifier} from "${imp.importAlias}";`;
|
|
4184
|
+
// If actual export name differs from identifier, use "as" renaming
|
|
4185
|
+
const namedPart = (imp.actualExport && imp.actualExport !== imp.identifier)
|
|
4186
|
+
? `${imp.actualExport} as ${imp.identifier}`
|
|
4187
|
+
: imp.identifier;
|
|
4188
|
+
return `import { ${namedPart} } from "${imp.importAlias}";`;
|
|
4189
|
+
});
|
|
4152
4190
|
|
|
4153
|
-
// ── PREVIEWS map
|
|
4191
|
+
// ── PREVIEWS map: only shadcn UI primitives (safe to render with no props) ──
|
|
4154
4192
|
const TEXT_CHILD_NAMES = new Set(['button','badge','toggle','label','link','chip','tag','pill']);
|
|
4155
4193
|
const previewEntries = components
|
|
4156
|
-
.filter(comp =>
|
|
4194
|
+
.filter(comp => {
|
|
4195
|
+
const info = importInfoMap[comp.name];
|
|
4196
|
+
return info && !info.skip && info.isShadcn;
|
|
4197
|
+
})
|
|
4157
4198
|
.map(comp => {
|
|
4158
4199
|
const { identifier } = importInfoMap[comp.name];
|
|
4159
4200
|
const hasText = TEXT_CHILD_NAMES.has(identifier.toLowerCase());
|
|
@@ -4163,6 +4204,26 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
4163
4204
|
return ` ${JSON.stringify(comp.name)}: ${call}`;
|
|
4164
4205
|
});
|
|
4165
4206
|
|
|
4207
|
+
// ── STORY_IDS map: project components get embedded as story iframes ─────────
|
|
4208
|
+
// Story ID = "{category}/{name}" → lowercase, spaces/slashes → hyphens → "--default"
|
|
4209
|
+
function toStoryId(category, name) {
|
|
4210
|
+
return [category, name].join('/')
|
|
4211
|
+
.toLowerCase().replace(/[^a-z0-9/]+/g, '-').replace(/-*\/+/g, '-')
|
|
4212
|
+
.replace(/-+/g, '-').replace(/^-|-$/g, '') + '--default';
|
|
4213
|
+
}
|
|
4214
|
+
const storyIdEntries = components
|
|
4215
|
+
.filter(comp => {
|
|
4216
|
+
const info = importInfoMap[comp.name];
|
|
4217
|
+
return info && !info.isShadcn; // project (non-shadcn) components only
|
|
4218
|
+
})
|
|
4219
|
+
.map(comp => {
|
|
4220
|
+
// Find the category for this component from categorized
|
|
4221
|
+
const cat = Object.keys(categorized).find(c => categorized[c].some(x => x.name === comp.name));
|
|
4222
|
+
if (!cat) return null;
|
|
4223
|
+
return ` ${JSON.stringify(comp.name)}: ${JSON.stringify(toStoryId(cat, comp.name))}`;
|
|
4224
|
+
})
|
|
4225
|
+
.filter(Boolean);
|
|
4226
|
+
|
|
4166
4227
|
// ── Generate story file ────────────────────────────────────────────────────
|
|
4167
4228
|
const content = [
|
|
4168
4229
|
`import React from "react";`,
|
|
@@ -4188,10 +4249,14 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
4188
4249
|
] : [
|
|
4189
4250
|
`const _PW = ({ children }: { children: React.ReactNode }) => React.createElement(React.Fragment, null, children) as React.ReactElement;`,
|
|
4190
4251
|
]),
|
|
4191
|
-
// PREVIEWS:
|
|
4252
|
+
// PREVIEWS: shadcn UI primitives rendered directly (safe with no props)
|
|
4192
4253
|
`const PREVIEWS: Record<string, () => React.ReactElement> = {`,
|
|
4193
4254
|
...previewEntries.map(e => e + ','),
|
|
4194
4255
|
`};`,
|
|
4256
|
+
// STORY_IDS: project components shown via their own story iframe
|
|
4257
|
+
`const STORY_IDS: Record<string, string> = {`,
|
|
4258
|
+
...storyIdEntries.map(e => e + ','),
|
|
4259
|
+
`};`,
|
|
4195
4260
|
``,
|
|
4196
4261
|
// Inventory data (metadata only — visual rendering is done at runtime via PREVIEWS)
|
|
4197
4262
|
`const inventoryData: { category: string; components: { name: string; group: string; tokenCount: number; propCount: number; colorSwatches: { token: string; hex: string }[]; previewHtml: string; previewScale: number; active: boolean }[] }[] = ${JSON.stringify(inventoryData)};`,
|
|
@@ -4199,30 +4264,44 @@ function writeComponentInventoryStory(components, foundations) {
|
|
|
4199
4264
|
`const activeComponents = ${activeComponents};`,
|
|
4200
4265
|
`const uniqueTokens = ${uniqueTokens};`,
|
|
4201
4266
|
``,
|
|
4202
|
-
// CardPreview:
|
|
4267
|
+
// CardPreview: shadcn → direct render; project → story iframe; else → shape HTML
|
|
4203
4268
|
`const _InvPreview = ({ comp }: { comp: any }) => {`,
|
|
4204
|
-
` const s: number = comp.previewScale || 0.4;`,
|
|
4205
|
-
` const centered = s >= 0.9;`,
|
|
4206
4269
|
` const fn = PREVIEWS[comp.name];`,
|
|
4270
|
+
` const storyId = STORY_IDS[comp.name];`,
|
|
4207
4271
|
` const shapeHtml = (`,
|
|
4208
4272
|
` <div style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}`,
|
|
4209
4273
|
` dangerouslySetInnerHTML={{ __html: comp.previewHtml }} />`,
|
|
4210
4274
|
` );`,
|
|
4211
|
-
`
|
|
4212
|
-
`
|
|
4213
|
-
`
|
|
4214
|
-
`
|
|
4215
|
-
`
|
|
4216
|
-
`
|
|
4217
|
-
`
|
|
4218
|
-
`
|
|
4219
|
-
`
|
|
4220
|
-
`
|
|
4221
|
-
`
|
|
4222
|
-
`
|
|
4223
|
-
`
|
|
4224
|
-
`
|
|
4225
|
-
`
|
|
4275
|
+
` // Shadcn primitives: render directly with scale`,
|
|
4276
|
+
` if (fn) {`,
|
|
4277
|
+
` const s: number = comp.previewScale || 0.65;`,
|
|
4278
|
+
` const centered = s >= 0.9;`,
|
|
4279
|
+
` const wPct = (+(100 / s).toFixed(1)) + "%";`,
|
|
4280
|
+
` const innerStyle: React.CSSProperties = centered`,
|
|
4281
|
+
` ? { position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%) scale(" + s + ")", transformOrigin: "center center", pointerEvents: "none" }`,
|
|
4282
|
+
` : { position: "absolute", top: 0, left: 0, width: wPct, transform: "scale(" + s + ")", transformOrigin: "top left", pointerEvents: "none" };`,
|
|
4283
|
+
` return (`,
|
|
4284
|
+
` <div style={{ height: 140, overflow: "hidden", position: "relative", background: "#fff" }}>`,
|
|
4285
|
+
` <_EB fallback={shapeHtml}>`,
|
|
4286
|
+
` <_PW><div style={innerStyle}>{fn()}</div></_PW>`,
|
|
4287
|
+
` </_EB>`,
|
|
4288
|
+
` </div>`,
|
|
4289
|
+
` );`,
|
|
4290
|
+
` }`,
|
|
4291
|
+
` // Project components: embed their own story as iframe`,
|
|
4292
|
+
` if (storyId) {`,
|
|
4293
|
+
` return (`,
|
|
4294
|
+
` <div style={{ height: 140, overflow: "hidden", position: "relative", background: "#fff" }}>`,
|
|
4295
|
+
` <iframe`,
|
|
4296
|
+
` src={"/iframe.html?id=" + storyId + "&viewMode=story"}`,
|
|
4297
|
+
` style={{ width: "300%", height: "424px", transform: "scale(0.333)", transformOrigin: "top left", border: "none", pointerEvents: "none", display: "block" }}`,
|
|
4298
|
+
` loading="lazy"`,
|
|
4299
|
+
` />`,
|
|
4300
|
+
` </div>`,
|
|
4301
|
+
` );`,
|
|
4302
|
+
` }`,
|
|
4303
|
+
` // Fallback: shape HTML`,
|
|
4304
|
+
` return <div style={{ height: 140, display: "flex", alignItems: "center", justifyContent: "center" }} dangerouslySetInnerHTML={{ __html: comp.previewHtml }} />;`,
|
|
4226
4305
|
`};`,
|
|
4227
4306
|
`const InventoryCard = ({ comp }: { comp: any }) => (`,
|
|
4228
4307
|
` <div style={{ border: "1px solid " + (comp.active ? "#e5e7eb" : "#f0f0f0"), borderRadius: 10, overflow: "hidden", background: comp.active ? "#fff" : "#fafafa", display: "flex", flexDirection: "column" as any, boxShadow: comp.active ? "0 1px 3px rgba(0,0,0,0.05)" : "none", opacity: comp.active ? 1 : 0.55 }}>`,
|