@onlook/storybook-plugin 0.4.0-beta.1 → 0.4.0-beta.2

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.
Files changed (2) hide show
  1. package/dist/index.js +155 -41
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import fs5, { existsSync } from 'fs';
2
- import path, { dirname, join, relative } from 'path';
2
+ import path6, { dirname, join, relative } from 'path';
3
3
  import { fileURLToPath } from 'url';
4
- import autoStoryGenerator from '@takuma-ru/auto-story-generator';
5
4
  import { withDefaultConfig } from 'react-docgen-typescript';
6
5
  import generateModule from '@babel/generator';
7
6
  import { parse } from '@babel/parser';
@@ -10,7 +9,12 @@ import * as t from '@babel/types';
10
9
  import crypto from 'crypto';
11
10
  import { chromium } from 'playwright';
12
11
 
13
- // src/storybook-onlook-plugin.ts
12
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
13
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
14
+ }) : x)(function(x) {
15
+ if (typeof require !== "undefined") return require.apply(this, arguments);
16
+ throw Error('Dynamic require of "' + x + '" is not supported');
17
+ });
14
18
  var FIXED_MARKER = "// @onlook-fixed";
15
19
  var parser = withDefaultConfig({
16
20
  shouldExtractLiteralValuesFromEnum: true,
@@ -21,11 +25,11 @@ var parser = withDefaultConfig({
21
25
  }
22
26
  });
23
27
  function resolveComponentPath(storyFilePath) {
24
- const dir = path.dirname(storyFilePath);
25
- const parentDir = path.dirname(dir);
26
- const storyName = path.basename(storyFilePath);
28
+ const dir = path6.dirname(storyFilePath);
29
+ const parentDir = path6.dirname(dir);
30
+ const storyName = path6.basename(storyFilePath);
27
31
  const componentName = storyName.replace(".stories.tsx", ".tsx");
28
- const componentPath = path.join(parentDir, componentName);
32
+ const componentPath = path6.join(parentDir, componentName);
29
33
  return fs5.existsSync(componentPath) ? componentPath : null;
30
34
  }
31
35
  function generateArgTypes(componentPath) {
@@ -87,7 +91,7 @@ export default meta;`
87
91
  );
88
92
  if (enriched !== content) {
89
93
  fs5.writeFileSync(storyFilePath, enriched);
90
- console.log(`[AutoStories] Enriched ${path.basename(storyFilePath)} with argTypes`);
94
+ console.log(`[AutoStories] Enriched ${path6.basename(storyFilePath)} with argTypes`);
91
95
  }
92
96
  } catch (err) {
93
97
  console.error(`[AutoStories] Failed to enrich story: ${storyFilePath}`, err);
@@ -115,7 +119,7 @@ function componentLocPlugin(options = {}) {
115
119
  sourceFilename: filepath
116
120
  });
117
121
  let mutated = false;
118
- const relativePath = path.relative(root, filepath);
122
+ const relativePath = path6.relative(root, filepath);
119
123
  traverse(ast, {
120
124
  JSXElement(nodePath) {
121
125
  const opening = nodePath.node.openingElement;
@@ -152,9 +156,9 @@ function componentLocPlugin(options = {}) {
152
156
  }
153
157
  };
154
158
  }
155
- var CACHE_DIR = path.join(process.cwd(), ".storybook-cache");
156
- var SCREENSHOTS_DIR = path.join(CACHE_DIR, "screenshots");
157
- var MANIFEST_PATH = path.join(CACHE_DIR, "manifest.json");
159
+ var CACHE_DIR = path6.join(process.cwd(), ".storybook-cache");
160
+ var SCREENSHOTS_DIR = path6.join(CACHE_DIR, "screenshots");
161
+ var MANIFEST_PATH = path6.join(CACHE_DIR, "manifest.json");
158
162
  var VIEWPORT_WIDTH = 1920;
159
163
  var VIEWPORT_HEIGHT = 1080;
160
164
  var MIN_COMPONENT_WIDTH = 420;
@@ -211,8 +215,8 @@ async function getBrowser() {
211
215
  return browser;
212
216
  }
213
217
  function getScreenshotPath(storyId, theme) {
214
- const storyDir = path.join(SCREENSHOTS_DIR, storyId);
215
- return path.join(storyDir, `${theme}.png`);
218
+ const storyDir = path6.join(SCREENSHOTS_DIR, storyId);
219
+ return path6.join(storyDir, `${theme}.png`);
216
220
  }
217
221
  async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, height = VIEWPORT_HEIGHT, storybookUrl = "http://localhost:6006", timeoutMs = 3e4) {
218
222
  const browser2 = await getBrowser();
@@ -299,7 +303,7 @@ async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, h
299
303
  async function generateScreenshot(storyId, theme, storybookUrl = "http://localhost:6006", timeoutMs = 3e4) {
300
304
  try {
301
305
  ensureCacheDirectories();
302
- const storyDir = path.join(SCREENSHOTS_DIR, storyId);
306
+ const storyDir = path6.join(SCREENSHOTS_DIR, storyId);
303
307
  if (!fs5.existsSync(storyDir)) {
304
308
  fs5.mkdirSync(storyDir, { recursive: true });
305
309
  }
@@ -339,7 +343,7 @@ async function fetchStorybookIndex() {
339
343
  }
340
344
  function getStoriesForFile(filePath) {
341
345
  if (!cachedIndex) return [];
342
- const fileName = path.basename(filePath);
346
+ const fileName = path6.basename(filePath);
343
347
  return Object.values(cachedIndex.entries).filter((entry) => entry.type === "story" && entry.importPath.endsWith(fileName)).map((entry) => entry.id);
344
348
  }
345
349
  async function regenerateScreenshotsForFiles(files) {
@@ -428,6 +432,18 @@ var DEFAULT_ALLOWED_ORIGINS = [
428
432
  ];
429
433
  var AUTO_STORIES_FOLDER = ".onlook-stories";
430
434
  var storyRuntimeErrors = /* @__PURE__ */ new Map();
435
+ var discoveryConfig = {
436
+ imports: ["src/**/*.tsx"],
437
+ ignores: []
438
+ };
439
+ function deriveTitleFromPath(filePath) {
440
+ const parts = filePath.replace(/^src\//, "").split("/");
441
+ parts.pop();
442
+ return parts.filter((p) => !p.startsWith("(") && !p.startsWith("[")).join("/");
443
+ }
444
+ function toStoryId(title, name) {
445
+ return `${title.replace(/\//g, "-").toLowerCase()}--${name.toLowerCase()}`;
446
+ }
431
447
  var serveMetadataAndScreenshots = (req, res, next) => {
432
448
  if (req.url === "/onbook-health.json") {
433
449
  const cacheBuster = Date.now();
@@ -499,9 +515,124 @@ var serveMetadataAndScreenshots = (req, res, next) => {
499
515
  });
500
516
  return;
501
517
  }
518
+ if (req.url === "/onbook-components.json") {
519
+ try {
520
+ const { globSync } = __require("glob");
521
+ const files = discoveryConfig.imports.flatMap(
522
+ (pattern) => globSync(pattern, {
523
+ ignore: discoveryConfig.ignores,
524
+ cwd: process.cwd()
525
+ })
526
+ );
527
+ const components = files.map((file) => ({
528
+ filePath: file,
529
+ componentName: path6.basename(file, path6.extname(file)),
530
+ title: deriveTitleFromPath(file)
531
+ }));
532
+ res.setHeader("Content-Type", "application/json");
533
+ res.setHeader("Access-Control-Allow-Origin", "*");
534
+ res.end(JSON.stringify({ components }));
535
+ } catch (error) {
536
+ res.statusCode = 500;
537
+ res.setHeader("Content-Type", "application/json");
538
+ res.end(
539
+ JSON.stringify({
540
+ error: "Failed to discover components",
541
+ details: String(error)
542
+ })
543
+ );
544
+ }
545
+ return;
546
+ }
547
+ if (req.url === "/onbook-generate-story" && req.method === "POST") {
548
+ let body = "";
549
+ req.on("data", (chunk) => {
550
+ body += chunk.toString();
551
+ });
552
+ req.on("end", () => {
553
+ try {
554
+ const { filePath } = JSON.parse(body);
555
+ if (!filePath) {
556
+ res.statusCode = 400;
557
+ res.setHeader("Content-Type", "application/json");
558
+ res.end(JSON.stringify({ error: "filePath is required" }));
559
+ return;
560
+ }
561
+ const absPath = path6.resolve(filePath);
562
+ const dir = path6.dirname(absPath);
563
+ const ext = path6.extname(absPath);
564
+ const baseName = path6.basename(absPath, ext);
565
+ const storyDir = path6.join(dir, AUTO_STORIES_FOLDER);
566
+ const storyPath = path6.join(storyDir, `${baseName}.stories.tsx`);
567
+ const title = deriveTitleFromPath(filePath);
568
+ const storyId = toStoryId(title, "default");
569
+ if (fs5.existsSync(storyPath)) {
570
+ res.setHeader("Content-Type", "application/json");
571
+ res.setHeader("Access-Control-Allow-Origin", "*");
572
+ res.end(
573
+ JSON.stringify({
574
+ storyId,
575
+ storyPath,
576
+ importPath: `./${filePath.replace(ext, `/${AUTO_STORIES_FOLDER}/${baseName}.stories.tsx`)}`,
577
+ existed: true
578
+ })
579
+ );
580
+ return;
581
+ }
582
+ const storyContent = [
583
+ "import type { Meta, StoryObj } from '@storybook/react';",
584
+ `import ${baseName} from '../${baseName}';`,
585
+ "",
586
+ `const meta: Meta<typeof ${baseName}> = {`,
587
+ ` title: '${title}',`,
588
+ ` component: ${baseName},`,
589
+ "};",
590
+ "export default meta;",
591
+ "",
592
+ `type Story = StoryObj<typeof ${baseName}>;`,
593
+ "",
594
+ "export const Default: Story = {};",
595
+ ""
596
+ ].join("\n");
597
+ if (!fs5.existsSync(storyDir)) {
598
+ fs5.mkdirSync(storyDir, { recursive: true });
599
+ }
600
+ fs5.writeFileSync(storyPath, storyContent);
601
+ console.log(`[STORYBOOK_PLUGIN] Generated story: ${storyPath}`);
602
+ res.setHeader("Content-Type", "application/json");
603
+ res.setHeader("Access-Control-Allow-Origin", "*");
604
+ res.end(
605
+ JSON.stringify({
606
+ storyId,
607
+ storyPath,
608
+ importPath: `./${path6.relative(process.cwd(), storyPath)}`,
609
+ existed: false
610
+ })
611
+ );
612
+ } catch (error) {
613
+ res.statusCode = 500;
614
+ res.setHeader("Content-Type", "application/json");
615
+ res.end(
616
+ JSON.stringify({
617
+ error: "Failed to generate story",
618
+ details: String(error)
619
+ })
620
+ );
621
+ }
622
+ });
623
+ return;
624
+ }
625
+ if (req.method === "OPTIONS" && req.url?.startsWith("/onbook-")) {
626
+ res.setHeader("Access-Control-Allow-Origin", "*");
627
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
628
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
629
+ res.statusCode = 204;
630
+ res.end();
631
+ return;
632
+ }
502
633
  if (req.url === "/onbook-index.json") {
503
634
  console.log("[STORYBOOK_PLUGIN] Serving /onbook-index.json endpoint");
504
- const manifestPath = path.join(process.cwd(), ".storybook-cache", "manifest.json");
635
+ const manifestPath = path6.join(process.cwd(), ".storybook-cache", "manifest.json");
505
636
  const cacheBuster = Date.now();
506
637
  console.log("[STORYBOOK_PLUGIN] Fetching http://localhost:6006/index.json");
507
638
  fetch(`http://localhost:6006/index.json?_t=${cacheBuster}`, {
@@ -586,7 +717,7 @@ var serveMetadataAndScreenshots = (req, res, next) => {
586
717
  return;
587
718
  }
588
719
  if (req.url?.startsWith("/screenshots/")) {
589
- const screenshotPath = path.join(
720
+ const screenshotPath = path6.join(
590
721
  process.cwd(),
591
722
  ".storybook-cache",
592
723
  req.url.replace("/screenshots/", "screenshots/")
@@ -607,7 +738,7 @@ var serveMetadataAndScreenshots = (req, res, next) => {
607
738
  `[STORYBOOK_PLUGIN] Generating screenshot on-demand: ${storyId}/${theme}`
608
739
  );
609
740
  captureScreenshotBuffer(storyId, theme).then(({ buffer }) => {
610
- const storyDir = path.join(
741
+ const storyDir = path6.join(
611
742
  process.cwd(),
612
743
  ".storybook-cache",
613
744
  "screenshots",
@@ -699,8 +830,8 @@ function storybookOnlookPlugin(options = {}) {
699
830
  };
700
831
  const plugins = [componentLocPlugin(), mainPlugin];
701
832
  if (options.autoStories !== false) {
702
- const imports = options.autoStories ?? ["src/**/*.tsx"];
703
- const ignores = options.autoStoriesIgnore ?? [
833
+ discoveryConfig.imports = options.autoStories ?? ["src/**/*.tsx"];
834
+ discoveryConfig.ignores = options.autoStoriesIgnore ?? [
704
835
  "src/**/*.stories.tsx",
705
836
  "src/**/*.stories.ts",
706
837
  "src/**/*.test.tsx",
@@ -710,27 +841,10 @@ function storybookOnlookPlugin(options = {}) {
710
841
  "node_modules/**",
711
842
  "**/.onlook-stories/**"
712
843
  ];
713
- console.log("[STORYBOOK_PLUGIN] Auto-story generation enabled", {
714
- imports,
715
- ignores,
716
- storiesFolder: AUTO_STORIES_FOLDER
844
+ console.log("[STORYBOOK_PLUGIN] Component discovery configured", {
845
+ imports: discoveryConfig.imports,
846
+ ignores: discoveryConfig.ignores
717
847
  });
718
- try {
719
- plugins.push(
720
- autoStoryGenerator.vite({
721
- preset: "react",
722
- imports,
723
- ignores,
724
- storiesFolder: AUTO_STORIES_FOLDER,
725
- isGenerateStoriesFileAtBuild: true
726
- })
727
- );
728
- } catch (err) {
729
- console.error(
730
- "[STORYBOOK_PLUGIN] ASG plugin failed to initialize, continuing without auto-stories",
731
- err
732
- );
733
- }
734
848
  }
735
849
  return plugins;
736
850
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlook/storybook-plugin",
3
- "version": "0.4.0-beta.1",
3
+ "version": "0.4.0-beta.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "onlook-storybook": "./dist/cli/index.js"
@@ -37,7 +37,7 @@
37
37
  "@babel/traverse": "^7.26.9",
38
38
  "@babel/types": "^7.26.9",
39
39
  "@drizzle-team/brocli": "^0.11.0",
40
- "@takuma-ru/auto-story-generator": "^0.4.0",
40
+ "glob": "^11.0.0",
41
41
  "playwright": "^1.52.0",
42
42
  "react-docgen-typescript": "^2.4.0"
43
43
  },