storybook-addon-dependency-previews 0.5.4 → 0.6.0

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/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  A plugin for [Storybook](https://storybook.js.org/) that shows the full dependency tree in both directions (built with and used by) the components in your application.
10
10
 
11
- Currently works with **React**, **Svelte**, **Angular**, and **Next.js**. The automated `sb-deps setup` wizard handles Vite-based projects (React, Svelte) end-to-end. Webpack-based projects (Angular, Next.js) need a one-time manual setup — see the [manual-setup-webpack guide](https://github.com/Dan503/storybook-addon-dependency-previews/blob/main/storybook-addon-package/docs/manual-setup-webpack.md) below.
11
+ Currently works with **React**, **Svelte**, **Vue 3**, **Angular**, and **Next.js**. The automated `sb-deps setup` wizard handles Vite-based projects (React, Svelte, Vue 3) end-to-end. Webpack-based projects (Angular, Next.js) need a one-time manual setup — see the [manual-setup-webpack guide](https://github.com/Dan503/storybook-addon-dependency-previews/blob/main/storybook-addon-package/docs/manual-setup-webpack.md) below.
12
12
 
13
13
  This is what you will see in Storybook after Dependency Previews have been installed and configured:
14
14
 
@@ -28,10 +28,18 @@ The below image demonstrates what you will see when you open up some of the depe
28
28
 
29
29
  #### Svelte demos
30
30
 
31
- - [Svelte Storybook demo site](https://dependency-previews-storybook-svelte.netlify.app/)
31
+ - [Svelte Storybook demo site](https://dependency-previews-storybook-svelte.netlify.app/?path=/docs/04-templates-home-template--docs)
32
32
  - [Svelte rendered example website](https://dependency-previews-demo-site-svelte.netlify.app/)
33
33
  - [Svelte demo source code](https://github.com/Dan503/storybook-addon-dependency-previews/tree/main/example-site/svelte)
34
34
 
35
+ #### Vue demos
36
+
37
+ Vue version built for Vue 3.
38
+
39
+ - [Vue Storybook demo site](https://dependency-previews-storybook-vue.netlify.app/?path=/docs/04-templates-home-template--docs)
40
+ - [Vue rendered example website](https://dependency-previews-demo-site-vue.netlify.app/)
41
+ - [Vue demo source code](https://github.com/Dan503/storybook-addon-dependency-previews/tree/main/example-site/vue)
42
+
35
43
  #### Angular demos
36
44
 
37
45
  - [Angular Storybook demo site](https://dependency-previews-storybook-angular.netlify.app/?path=/docs/04-templates-home-template--docs)
@@ -42,7 +50,7 @@ The below image demonstrates what you will see when you open up some of the depe
42
50
 
43
51
  ## Installation guide
44
52
 
45
- ### Quick start (React and Svelte)
53
+ ### Quick start (React, Svelte, and Vue 3)
46
54
 
47
55
  After running `npx storybook@latest init` in your project, run the setup wizard:
48
56
 
@@ -84,9 +92,9 @@ When it finishes, run `npm run sb` (or your package manager's equivalent) to sta
84
92
 
85
93
  ### Manual setup
86
94
 
87
- The wizard supports React (`@storybook/react-vite`) and Svelte (`@storybook/sveltekit`, `@storybook/svelte-vite`) — all Vite-based. **Angular (`@storybook/angular`) and Next.js (`@storybook/nextjs`) projects are both webpack-based and require manual setup** — the wizard's preview-patcher relies on Vite's `import.meta.glob`, which webpack doesn't expose. Follow the matching guide below:
95
+ The wizard supports React (`@storybook/react-vite`), Svelte (`@storybook/sveltekit`, `@storybook/svelte-vite`), and Vue 3 (`@storybook/vue3-vite`) — all Vite-based. **Angular (`@storybook/angular`) and Next.js (`@storybook/nextjs`) projects are both webpack-based and require manual setup** — the wizard's preview-patcher relies on Vite's `import.meta.glob`, which webpack doesn't expose. Follow the matching guide below:
88
96
 
89
- - [Manual setup — Vite (React, Svelte)](https://github.com/Dan503/storybook-addon-dependency-previews/blob/main/storybook-addon-package/docs/manual-setup-vite.md)
97
+ - [Manual setup — Vite (React, Svelte, Vue 3)](https://github.com/Dan503/storybook-addon-dependency-previews/blob/main/storybook-addon-package/docs/manual-setup-vite.md)
90
98
  - [Manual setup — webpack (`@storybook/angular`, `@storybook/nextjs`)](https://github.com/Dan503/storybook-addon-dependency-previews/blob/main/storybook-addon-package/docs/manual-setup-webpack.md)
91
99
 
92
100
  ## Configuration file (optional)
@@ -176,6 +184,12 @@ export function ${componentName}({}: ${propsName}) {
176
184
  /** Customize the generated .stories.svelte file */
177
185
  story: ({ componentName, title, tags }) => '...',
178
186
  },
187
+ vue: {
188
+ /** Customize the generated .vue component file */
189
+ component: ({ componentName }) => '...',
190
+ /** Customize the generated .stories.ts file */
191
+ story: ({ componentName, title, tags }) => '...',
192
+ },
179
193
  angular: {
180
194
  /** Customize the generated .component.ts file */
181
195
  component: ({
@@ -5,6 +5,11 @@ let node_path = require("node:path");
5
5
  node_path = require_rolldown_runtime.__toESM(node_path);
6
6
 
7
7
  //#region src/addon/vitePlugin.ts
8
+ const jsonUrlPath = "/dependency-previews.json";
9
+ function readDependencyPreviewsJson() {
10
+ const jsonPath = (0, node_path.resolve)(process.cwd(), ".storybook/dependency-previews.json");
11
+ return (0, node_fs.existsSync)(jsonPath) ? (0, node_fs.readFileSync)(jsonPath, "utf8") : "{}";
12
+ }
8
13
  function sbDepsVitePlugin() {
9
14
  const virtId = "virtual:dependency-previews-json";
10
15
  const resolved = "\0" + virtId;
@@ -15,9 +20,20 @@ function sbDepsVitePlugin() {
15
20
  },
16
21
  load(id) {
17
22
  if (id !== resolved) return null;
18
- const jsonPath = (0, node_path.resolve)(process.cwd(), ".storybook/dependency-previews.json");
19
- const json = (0, node_fs.existsSync)(jsonPath) ? (0, node_fs.readFileSync)(jsonPath, "utf8") : "{}";
20
- return `export default ${json};`;
23
+ return `export default ${readDependencyPreviewsJson()};`;
24
+ },
25
+ configureServer(server) {
26
+ server.middlewares.use(jsonUrlPath, (_req, res) => {
27
+ res.setHeader("Content-Type", "application/json");
28
+ res.end(readDependencyPreviewsJson());
29
+ });
30
+ },
31
+ generateBundle() {
32
+ this.emitFile({
33
+ type: "asset",
34
+ fileName: "dependency-previews.json",
35
+ source: readDependencyPreviewsJson()
36
+ });
21
37
  }
22
38
  };
23
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"vitePlugin.cjs","names":[],"sources":["../../src/addon/vitePlugin.ts"],"sourcesContent":["import { readFileSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nexport function sbDepsVitePlugin() {\n\tconst virtId = 'virtual:dependency-previews-json'\n\tconst resolved = '\\0' + virtId\n\treturn {\n\t\tname: 'sb-deps',\n\t\tresolveId(id: string) {\n\t\t\treturn id === virtId ? resolved : null\n\t\t},\n\t\tload(id: string) {\n\t\t\tif (id !== resolved) return null\n\t\t\tconst jsonPath = resolve(\n\t\t\t\tprocess.cwd(),\n\t\t\t\t'.storybook/dependency-previews.json',\n\t\t\t)\n\t\t\tconst json = existsSync(jsonPath) ? readFileSync(jsonPath, 'utf8') : '{}'\n\t\t\treturn `export default ${json};`\n\t\t},\n\t}\n}\n"],"mappings":";;;;;;;AAGA,SAAgB,mBAAmB;CAClC,MAAM,SAAS;CACf,MAAM,WAAW,OAAO;AACxB,QAAO;EACN,MAAM;EACN,UAAU,IAAY;AACrB,UAAO,OAAO,SAAS,WAAW;;EAEnC,KAAK,IAAY;AAChB,OAAI,OAAO,SAAU,QAAO;GAC5B,MAAM,kCACL,QAAQ,KAAK,EACb,sCACA;GACD,MAAM,+BAAkB,SAAS,6BAAgB,UAAU,OAAO,GAAG;AACrE,UAAO,kBAAkB,KAAK;;EAE/B"}
1
+ {"version":3,"file":"vitePlugin.cjs","names":[],"sources":["../../src/addon/vitePlugin.ts"],"sourcesContent":["import { readFileSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { Plugin } from 'vite'\n\nconst jsonUrlPath = '/dependency-previews.json'\n\nfunction readDependencyPreviewsJson(): string {\n\tconst jsonPath = resolve(\n\t\tprocess.cwd(),\n\t\t'.storybook/dependency-previews.json',\n\t)\n\treturn existsSync(jsonPath) ? readFileSync(jsonPath, 'utf8') : '{}'\n}\n\nexport function sbDepsVitePlugin(): Plugin {\n\tconst virtId = 'virtual:dependency-previews-json'\n\tconst resolved = '\\0' + virtId\n\treturn {\n\t\tname: 'sb-deps',\n\t\tresolveId(id: string) {\n\t\t\treturn id === virtId ? resolved : null\n\t\t},\n\t\tload(id: string) {\n\t\t\tif (id !== resolved) return null\n\t\t\treturn `export default ${readDependencyPreviewsJson()};`\n\t\t},\n\t\t// The manager-side panel (GraphView) fetches the JSON over HTTP — it\n\t\t// can't import the virtual module above because the manager bundle is\n\t\t// prebuilt by Storybook, not bundled by the project's Vite config.\n\t\tconfigureServer(server) {\n\t\t\tserver.middlewares.use(jsonUrlPath, (_req, res) => {\n\t\t\t\t// Read per-request so `sb-deps --watch` regenerations are served\n\t\t\t\t// without restarting Storybook.\n\t\t\t\tres.setHeader('Content-Type', 'application/json')\n\t\t\t\tres.end(readDependencyPreviewsJson())\n\t\t\t})\n\t\t},\n\t\t// Emit the JSON into `storybook build` output so the panel's fetch also\n\t\t// works in deployed static Storybooks, mirroring the dev middleware.\n\t\tgenerateBundle() {\n\t\t\tthis.emitFile({\n\t\t\t\ttype: 'asset',\n\t\t\t\tfileName: 'dependency-previews.json',\n\t\t\t\tsource: readDependencyPreviewsJson(),\n\t\t\t})\n\t\t},\n\t}\n}\n"],"mappings":";;;;;;;AAIA,MAAM,cAAc;AAEpB,SAAS,6BAAqC;CAC7C,MAAM,kCACL,QAAQ,KAAK,EACb,sCACA;AACD,gCAAkB,SAAS,6BAAgB,UAAU,OAAO,GAAG;;AAGhE,SAAgB,mBAA2B;CAC1C,MAAM,SAAS;CACf,MAAM,WAAW,OAAO;AACxB,QAAO;EACN,MAAM;EACN,UAAU,IAAY;AACrB,UAAO,OAAO,SAAS,WAAW;;EAEnC,KAAK,IAAY;AAChB,OAAI,OAAO,SAAU,QAAO;AAC5B,UAAO,kBAAkB,4BAA4B,CAAC;;EAKvD,gBAAgB,QAAQ;AACvB,UAAO,YAAY,IAAI,cAAc,MAAM,QAAQ;AAGlD,QAAI,UAAU,gBAAgB,mBAAmB;AACjD,QAAI,IAAI,4BAA4B,CAAC;KACpC;;EAIH,iBAAiB;AAChB,QAAK,SAAS;IACb,MAAM;IACN,UAAU;IACV,QAAQ,4BAA4B;IACpC,CAAC;;EAEH"}
@@ -1,9 +1,7 @@
1
+ import { Plugin } from "vite";
2
+
1
3
  //#region src/addon/vitePlugin.d.ts
2
- declare function sbDepsVitePlugin(): {
3
- name: string;
4
- resolveId(id: string): string | null;
5
- load(id: string): string | null;
6
- };
4
+ declare function sbDepsVitePlugin(): Plugin;
7
5
  //#endregion
8
6
  export { sbDepsVitePlugin };
9
7
  //# sourceMappingURL=vitePlugin.d.cts.map
@@ -1,9 +1,7 @@
1
+ import { Plugin } from "vite";
2
+
1
3
  //#region src/addon/vitePlugin.d.ts
2
- declare function sbDepsVitePlugin(): {
3
- name: string;
4
- resolveId(id: string): string | null;
5
- load(id: string): string | null;
6
- };
4
+ declare function sbDepsVitePlugin(): Plugin;
7
5
  //#endregion
8
6
  export { sbDepsVitePlugin };
9
7
  //# sourceMappingURL=vitePlugin.d.mts.map
@@ -2,6 +2,11 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
 
4
4
  //#region src/addon/vitePlugin.ts
5
+ const jsonUrlPath = "/dependency-previews.json";
6
+ function readDependencyPreviewsJson() {
7
+ const jsonPath = resolve(process.cwd(), ".storybook/dependency-previews.json");
8
+ return existsSync(jsonPath) ? readFileSync(jsonPath, "utf8") : "{}";
9
+ }
5
10
  function sbDepsVitePlugin() {
6
11
  const virtId = "virtual:dependency-previews-json";
7
12
  const resolved = "\0" + virtId;
@@ -12,9 +17,20 @@ function sbDepsVitePlugin() {
12
17
  },
13
18
  load(id) {
14
19
  if (id !== resolved) return null;
15
- const jsonPath = resolve(process.cwd(), ".storybook/dependency-previews.json");
16
- const json = existsSync(jsonPath) ? readFileSync(jsonPath, "utf8") : "{}";
17
- return `export default ${json};`;
20
+ return `export default ${readDependencyPreviewsJson()};`;
21
+ },
22
+ configureServer(server) {
23
+ server.middlewares.use(jsonUrlPath, (_req, res) => {
24
+ res.setHeader("Content-Type", "application/json");
25
+ res.end(readDependencyPreviewsJson());
26
+ });
27
+ },
28
+ generateBundle() {
29
+ this.emitFile({
30
+ type: "asset",
31
+ fileName: "dependency-previews.json",
32
+ source: readDependencyPreviewsJson()
33
+ });
18
34
  }
19
35
  };
20
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"vitePlugin.mjs","names":[],"sources":["../../src/addon/vitePlugin.ts"],"sourcesContent":["import { readFileSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nexport function sbDepsVitePlugin() {\n\tconst virtId = 'virtual:dependency-previews-json'\n\tconst resolved = '\\0' + virtId\n\treturn {\n\t\tname: 'sb-deps',\n\t\tresolveId(id: string) {\n\t\t\treturn id === virtId ? resolved : null\n\t\t},\n\t\tload(id: string) {\n\t\t\tif (id !== resolved) return null\n\t\t\tconst jsonPath = resolve(\n\t\t\t\tprocess.cwd(),\n\t\t\t\t'.storybook/dependency-previews.json',\n\t\t\t)\n\t\t\tconst json = existsSync(jsonPath) ? readFileSync(jsonPath, 'utf8') : '{}'\n\t\t\treturn `export default ${json};`\n\t\t},\n\t}\n}\n"],"mappings":";;;;AAGA,SAAgB,mBAAmB;CAClC,MAAM,SAAS;CACf,MAAM,WAAW,OAAO;AACxB,QAAO;EACN,MAAM;EACN,UAAU,IAAY;AACrB,UAAO,OAAO,SAAS,WAAW;;EAEnC,KAAK,IAAY;AAChB,OAAI,OAAO,SAAU,QAAO;GAC5B,MAAM,WAAW,QAChB,QAAQ,KAAK,EACb,sCACA;GACD,MAAM,OAAO,WAAW,SAAS,GAAG,aAAa,UAAU,OAAO,GAAG;AACrE,UAAO,kBAAkB,KAAK;;EAE/B"}
1
+ {"version":3,"file":"vitePlugin.mjs","names":[],"sources":["../../src/addon/vitePlugin.ts"],"sourcesContent":["import { readFileSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { Plugin } from 'vite'\n\nconst jsonUrlPath = '/dependency-previews.json'\n\nfunction readDependencyPreviewsJson(): string {\n\tconst jsonPath = resolve(\n\t\tprocess.cwd(),\n\t\t'.storybook/dependency-previews.json',\n\t)\n\treturn existsSync(jsonPath) ? readFileSync(jsonPath, 'utf8') : '{}'\n}\n\nexport function sbDepsVitePlugin(): Plugin {\n\tconst virtId = 'virtual:dependency-previews-json'\n\tconst resolved = '\\0' + virtId\n\treturn {\n\t\tname: 'sb-deps',\n\t\tresolveId(id: string) {\n\t\t\treturn id === virtId ? resolved : null\n\t\t},\n\t\tload(id: string) {\n\t\t\tif (id !== resolved) return null\n\t\t\treturn `export default ${readDependencyPreviewsJson()};`\n\t\t},\n\t\t// The manager-side panel (GraphView) fetches the JSON over HTTP — it\n\t\t// can't import the virtual module above because the manager bundle is\n\t\t// prebuilt by Storybook, not bundled by the project's Vite config.\n\t\tconfigureServer(server) {\n\t\t\tserver.middlewares.use(jsonUrlPath, (_req, res) => {\n\t\t\t\t// Read per-request so `sb-deps --watch` regenerations are served\n\t\t\t\t// without restarting Storybook.\n\t\t\t\tres.setHeader('Content-Type', 'application/json')\n\t\t\t\tres.end(readDependencyPreviewsJson())\n\t\t\t})\n\t\t},\n\t\t// Emit the JSON into `storybook build` output so the panel's fetch also\n\t\t// works in deployed static Storybooks, mirroring the dev middleware.\n\t\tgenerateBundle() {\n\t\t\tthis.emitFile({\n\t\t\t\ttype: 'asset',\n\t\t\t\tfileName: 'dependency-previews.json',\n\t\t\t\tsource: readDependencyPreviewsJson(),\n\t\t\t})\n\t\t},\n\t}\n}\n"],"mappings":";;;;AAIA,MAAM,cAAc;AAEpB,SAAS,6BAAqC;CAC7C,MAAM,WAAW,QAChB,QAAQ,KAAK,EACb,sCACA;AACD,QAAO,WAAW,SAAS,GAAG,aAAa,UAAU,OAAO,GAAG;;AAGhE,SAAgB,mBAA2B;CAC1C,MAAM,SAAS;CACf,MAAM,WAAW,OAAO;AACxB,QAAO;EACN,MAAM;EACN,UAAU,IAAY;AACrB,UAAO,OAAO,SAAS,WAAW;;EAEnC,KAAK,IAAY;AAChB,OAAI,OAAO,SAAU,QAAO;AAC5B,UAAO,kBAAkB,4BAA4B,CAAC;;EAKvD,gBAAgB,QAAQ;AACvB,UAAO,YAAY,IAAI,cAAc,MAAM,QAAQ;AAGlD,QAAI,UAAU,gBAAgB,mBAAmB;AACjD,QAAI,IAAI,4BAA4B,CAAC;KACpC;;EAIH,iBAAiB;AAChB,QAAK,SAAS;IACb,MAAM;IACN,UAAU;IACV,QAAQ,4BAA4B;IACpC,CAAC;;EAEH"}
@@ -227,6 +227,10 @@ function isDecoratorSvelte(absPath) {
227
227
  const norm = absPath.replace(/\\/g, "/");
228
228
  return srcSubpathRegex("\\.decorator\\.svelte$").test(norm);
229
229
  }
230
+ function isComponentsVue(absPath) {
231
+ const norm = absPath.replace(/\\/g, "/");
232
+ return srcSubpathRegex("\\.vue$").test(norm) && !STORY_FILE_REGEX.test(norm);
233
+ }
230
234
  function isComponentsAngularTs(absPath) {
231
235
  const norm = absPath.replace(/\\/g, "/");
232
236
  return srcSubpathRegex("\\.component\\.ts$").test(norm);
@@ -241,6 +245,9 @@ function componentBaseFromComponent(absCompPath) {
241
245
  function componentBaseFromSvelteComponent(absCompPath) {
242
246
  return (0, node_path.basename)(absCompPath, ".svelte");
243
247
  }
248
+ function componentBaseFromVueComponent(absCompPath) {
249
+ return (0, node_path.basename)(absCompPath, ".vue");
250
+ }
244
251
  function componentBaseFromAngularComponent(absCompPath) {
245
252
  return (0, node_path.basename)(absCompPath).replace(/\.component\.(ts|html)$/i, "");
246
253
  }
@@ -278,6 +285,11 @@ function storyPathForSvelteComponent(absCompPath) {
278
285
  const base = componentBaseFromSvelteComponent(absCompPath);
279
286
  return (0, node_path.join)(dir, `${base}.stories.svelte`);
280
287
  }
288
+ function storyPathForVueComponent(absCompPath) {
289
+ const dir = (0, node_path.dirname)(absCompPath);
290
+ const base = componentBaseFromVueComponent(absCompPath);
291
+ return (0, node_path.join)(dir, `${base}.stories.ts`);
292
+ }
281
293
  function makeTitleFromComponent(absCompPath) {
282
294
  const srcRoot = (0, node_path.join)(projectRoot, SRC_DIR) + node_path.sep;
283
295
  const normAbs = absCompPath.replace(/\\/g, "/");
@@ -464,6 +476,91 @@ function ensureStoryForSvelteComponent(absCompPath) {
464
476
  if ((0, node_fs.existsSync)(sPath)) return null;
465
477
  return scaffoldStoryForSvelteComponent(absCompPath);
466
478
  }
479
+ function scaffoldVueComponent(absCompPath) {
480
+ const base = componentBaseFromVueComponent(absCompPath);
481
+ const componentName = toPascalCase(base);
482
+ const tpl = SCAFFOLD_CONFIG?.vue?.component?.({ componentName }) ?? `<script setup lang="ts">
483
+ export interface PropsFor${componentName} {
484
+ }
485
+
486
+ const { } = defineProps<PropsFor${componentName}>()
487
+ <\/script>
488
+
489
+ <template>
490
+ <div class="${componentName}">
491
+ <slot />
492
+ </div>
493
+ </template>
494
+ `;
495
+ (0, node_fs.writeFileSync)(absCompPath, tpl, "utf8");
496
+ info(`scaffolded vue component → ${rel(absCompPath)}`);
497
+ }
498
+ function makeTitleFromVueComponent(absCompPath) {
499
+ const srcRoot = (0, node_path.join)(projectRoot, SRC_DIR) + node_path.sep;
500
+ const normAbs = absCompPath.replace(/\\/g, "/");
501
+ const relFromSrc = normAbs.startsWith(srcRoot.replace(/\\/g, "/")) ? normAbs.slice(srcRoot.length) : absCompPath.replace(projectRoot + node_path.sep, "").replace(/\\/g, "/");
502
+ const dir = node_path.posix.dirname(relFromSrc);
503
+ let segments = dir.split("/").filter(Boolean);
504
+ if (segments[0] && /^components?$/i.test(segments[0])) segments = segments.slice(1);
505
+ const titledFolders = segments.map((s) => toTitleCase(toWords(s)));
506
+ const compName = componentBaseFromVueComponent(absCompPath);
507
+ const compTitle = toTitleCase(toWords(compName));
508
+ const fullStoryPath = [...titledFolders, compTitle].filter(Boolean);
509
+ const dedupedStoryPath = [...new Set(fullStoryPath)];
510
+ return dedupedStoryPath.join(" / ");
511
+ }
512
+ function scaffoldStoryForVueComponent(absCompPath) {
513
+ const base = componentBaseFromVueComponent(absCompPath);
514
+ const componentName = toPascalCase(base);
515
+ const title = makeTitleFromVueComponent(absCompPath);
516
+ const atomic = detectAtomicTag(absCompPath);
517
+ const tags = ["autodocs"];
518
+ if (atomic) tags.push(atomic);
519
+ const storyTpl = SCAFFOLD_CONFIG?.vue?.story?.({
520
+ componentName,
521
+ title,
522
+ tags
523
+ }) ?? `import type { Meta, StoryObj } from '@storybook/vue3-vite'
524
+ import type { StoryParameters } from 'storybook-addon-dependency-previews'
525
+ import ${componentName}, { type PropsFor${componentName} } from './${componentName}.vue'
526
+
527
+ const meta: Meta<typeof ${componentName}> = {
528
+ title: '${title}',
529
+ component: ${componentName},
530
+ tags: ${JSON.stringify(tags)},
531
+ parameters: {
532
+ layout: 'padded',
533
+ } satisfies StoryParameters,
534
+ }
535
+
536
+ export default meta
537
+
538
+ type Story = StoryObj<typeof meta>
539
+
540
+ export const Primary: Story = {
541
+ args: {} satisfies PropsFor${componentName},
542
+ render: (args) => ({
543
+ components: { ${componentName} },
544
+ setup() {
545
+ return { args }
546
+ },
547
+ template: \`
548
+ <${componentName} v-bind="args">
549
+ ${componentName}
550
+ </${componentName}>\`,
551
+ }),
552
+ }
553
+ `;
554
+ const storyPath = storyPathForVueComponent(absCompPath);
555
+ (0, node_fs.writeFileSync)(storyPath, storyTpl, "utf8");
556
+ info(`scaffolded vue story → ${rel(storyPath)}`);
557
+ return storyPath;
558
+ }
559
+ function ensureStoryForVueComponent(absCompPath) {
560
+ const sPath = storyPathForVueComponent(absCompPath);
561
+ if ((0, node_fs.existsSync)(sPath)) return null;
562
+ return scaffoldStoryForVueComponent(absCompPath);
563
+ }
467
564
  function storyPathForAngularComponent(absCompPath) {
468
565
  const dir = (0, node_path.dirname)(absCompPath);
469
566
  const base = componentBaseFromAngularComponent(absCompPath);
@@ -671,7 +768,7 @@ function startWatcher() {
671
768
  const includeGlobs = [
672
769
  "**/*.stories.{ts,tsx,js,jsx,mdx,svelte}",
673
770
  "**/*.story.{ts,tsx,js,jsx,mdx,svelte}",
674
- `${srcPrefix}**/*.{ts,tsx,js,jsx,svelte}`,
771
+ `${srcPrefix}**/*.{ts,tsx,js,jsx,svelte,vue}`,
675
772
  `${srcPrefix}**/*.component.html`,
676
773
  "depcruise.config.cjs",
677
774
  ".dependency-cruiser.{js,cjs}"
@@ -720,6 +817,10 @@ function startWatcher() {
720
817
  await handleSvelteComponentCreation(abs, relPath);
721
818
  continue;
722
819
  }
820
+ if (isComponentsVue(abs) && ev.type === "create") {
821
+ await handleVueComponentCreation(abs, relPath);
822
+ continue;
823
+ }
723
824
  if (isComponentsAngularTs(abs) && ev.type === "create") {
724
825
  await handleAngularComponentCreation(abs, relPath, "internal");
725
826
  continue;
@@ -771,6 +872,16 @@ function startWatcher() {
771
872
  kick("create:story", createdStory);
772
873
  }
773
874
  }
875
+ async function handleVueComponentCreation(abs, relPath) {
876
+ if (isEmptyOrWhitespace(abs)) {
877
+ scaffoldVueComponent(abs);
878
+ }
879
+ console.log("Vue component creation detected:", relPath);
880
+ const createdStory = ensureStoryForVueComponent(abs);
881
+ if (createdStory) {
882
+ kick("create:story", createdStory);
883
+ }
884
+ }
774
885
  async function handleAngularComponentCreation(abs, relPath, templateStyle) {
775
886
  if (isEmptyOrWhitespace(abs)) {
776
887
  scaffoldAngularComponent(abs, templateStyle);