@fragments-sdk/cli 0.9.0 → 0.9.1

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 (123) hide show
  1. package/dist/bin.js +83 -33
  2. package/dist/bin.js.map +1 -1
  3. package/dist/{chunk-WI6SLMSO.js → chunk-5GT62FCB.js} +2 -2
  4. package/dist/{chunk-CJEGT3WD.js → chunk-BW3ZATBW.js} +20 -3
  5. package/dist/chunk-BW3ZATBW.js.map +1 -0
  6. package/dist/{chunk-2JIKCJX3.js → chunk-D7372LQX.js} +13 -6
  7. package/dist/chunk-D7372LQX.js.map +1 -0
  8. package/dist/chunk-EZYXYWNF.js +131 -0
  9. package/dist/chunk-EZYXYWNF.js.map +1 -0
  10. package/dist/{chunk-NGIMCIK2.js → chunk-GF6OVPIN.js} +2 -2
  11. package/dist/{chunk-GOVI6COW.js → chunk-NVSPGSKB.js} +12 -4
  12. package/dist/chunk-NVSPGSKB.js.map +1 -0
  13. package/dist/core/index.d.ts +105 -3
  14. package/dist/core/index.js +12 -2
  15. package/dist/{defineFragment-D0UTve-I.d.ts → defineFragment-CBMS7Bab.d.ts} +21 -1
  16. package/dist/generate-LQA2R7FN.js +461 -0
  17. package/dist/generate-LQA2R7FN.js.map +1 -0
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.js +5 -4
  20. package/dist/index.js.map +1 -1
  21. package/dist/{init-KSAAS7X3.js → init-2GEGVIUQ.js} +13 -75
  22. package/dist/init-2GEGVIUQ.js.map +1 -0
  23. package/dist/mcp-bin.js +4 -3
  24. package/dist/mcp-bin.js.map +1 -1
  25. package/dist/{scan-65RH3QMM.js → scan-JGS65S7P.js} +6 -5
  26. package/dist/{service-A5GIGGGK.js → service-XP2EAJXD.js} +4 -3
  27. package/dist/{static-viewer-NSODM5VX.js → static-viewer-XCS7UJTO.js} +4 -3
  28. package/dist/storyFilters-3LUYAFZF.js +15 -0
  29. package/dist/storyFilters-3LUYAFZF.js.map +1 -0
  30. package/dist/{test-RPWZAYSJ.js → test-TD6TJNVY.js} +3 -3
  31. package/dist/{tokens-NIXSZRX7.js → tokens-2EXPCVP3.js} +5 -4
  32. package/dist/{tokens-NIXSZRX7.js.map → tokens-2EXPCVP3.js.map} +1 -1
  33. package/dist/{viewer-SBTJDMP7.js → viewer-RFA2KVBG.js} +243 -18
  34. package/dist/viewer-RFA2KVBG.js.map +1 -0
  35. package/package.json +1 -1
  36. package/src/build.ts +12 -2
  37. package/src/commands/build.ts +16 -2
  38. package/src/commands/generate.ts +383 -68
  39. package/src/commands/init.ts +9 -51
  40. package/src/core/config.ts +15 -2
  41. package/src/core/generators/typescript-extractor.ts +10 -0
  42. package/src/core/index.ts +15 -0
  43. package/src/core/schema.ts +10 -2
  44. package/src/core/storyFilters.test.ts +350 -0
  45. package/src/core/storyFilters.ts +253 -0
  46. package/src/core/types.ts +22 -0
  47. package/src/migrate/converter.ts +9 -1
  48. package/src/migrate/parser.ts +2 -0
  49. package/src/migrate/types.ts +2 -0
  50. package/src/setup.ts +69 -24
  51. package/src/viewer/__tests__/viewer-integration.test.ts +1 -1
  52. package/src/viewer/components/AccessibilityPanel.tsx +305 -312
  53. package/src/viewer/components/ActionsPanel.tsx +31 -29
  54. package/src/viewer/components/AllVariantsPreview.tsx +78 -0
  55. package/src/viewer/components/App.tsx +187 -740
  56. package/src/viewer/components/BottomPanel.tsx +228 -132
  57. package/src/viewer/components/CodePanel.tsx +1 -1
  58. package/src/viewer/components/CommandPalette.tsx +7 -10
  59. package/src/viewer/components/ComponentDocView.tsx +164 -0
  60. package/src/viewer/components/ComponentGraph.tsx +111 -142
  61. package/src/viewer/components/ContractPanel.tsx +6 -6
  62. package/src/viewer/components/EmptyVariantMessage.tsx +54 -0
  63. package/src/viewer/components/FigmaEmbed.tsx +20 -18
  64. package/src/viewer/components/FragmentEditor.tsx +92 -115
  65. package/src/viewer/components/HeaderSearch.tsx +24 -0
  66. package/src/viewer/components/HealthDashboard.tsx +16 -2
  67. package/src/viewer/components/Icons.tsx +9 -0
  68. package/src/viewer/components/InteractionsPanel.tsx +101 -117
  69. package/src/viewer/components/IsolatedPreviewFrame.tsx +1 -0
  70. package/src/viewer/components/LandingPage.tsx +3 -3
  71. package/src/viewer/components/LeftSidebar.tsx +141 -63
  72. package/src/viewer/components/LoadErrorMessage.tsx +102 -0
  73. package/src/viewer/components/MultiViewportPreview.tsx +61 -142
  74. package/src/viewer/components/NoVariantsMessage.tsx +59 -0
  75. package/src/viewer/components/PanelShell.tsx +161 -0
  76. package/src/viewer/components/PerformancePanel.tsx +31 -28
  77. package/src/viewer/components/PreviewArea.tsx +1 -1
  78. package/src/viewer/components/PreviewAside.tsx +168 -0
  79. package/src/viewer/components/PreviewFrameHost.tsx +3 -3
  80. package/src/viewer/components/PropsEditor.tsx +70 -156
  81. package/src/viewer/components/ResizablePanel.tsx +103 -263
  82. package/src/viewer/components/RightSidebar.tsx +3 -9
  83. package/src/viewer/components/SkeletonLoader.tsx +13 -13
  84. package/src/viewer/components/TokenStylePanel.tsx +182 -209
  85. package/src/viewer/components/TopToolbar.tsx +159 -0
  86. package/src/viewer/components/VariantMatrix.tsx +42 -86
  87. package/src/viewer/components/VariantTabs.tsx +3 -3
  88. package/src/viewer/components/ViewerHeader.tsx +69 -0
  89. package/src/viewer/components/WebMCPDevTools.tsx +17 -23
  90. package/src/viewer/components/viewer-utils.ts +16 -0
  91. package/src/viewer/entry.tsx +5 -0
  92. package/src/viewer/hooks/useAppState.ts +27 -4
  93. package/src/viewer/hooks/usePreviewBridge.ts +2 -2
  94. package/src/viewer/preview-frame.html +6 -12
  95. package/src/viewer/server.ts +169 -2
  96. package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss +10 -0
  97. package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss.d.ts +2 -0
  98. package/src/viewer/vendor/shared/src/ComponentDocContent.tsx +274 -0
  99. package/src/viewer/vendor/shared/src/DocsHeaderBar.tsx +6 -18
  100. package/src/viewer/vendor/shared/src/DocsPageShell.tsx +5 -0
  101. package/src/viewer/vendor/shared/src/DocsSidebarNav.tsx +5 -16
  102. package/src/viewer/vendor/shared/src/PropsTable.module.scss +68 -0
  103. package/src/viewer/vendor/shared/src/PropsTable.module.scss.d.ts +2 -0
  104. package/src/viewer/vendor/shared/src/PropsTable.tsx +76 -0
  105. package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss +122 -0
  106. package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss.d.ts +2 -0
  107. package/src/viewer/vendor/shared/src/VariantPreviewCard.tsx +134 -0
  108. package/src/viewer/vendor/shared/src/index.ts +8 -0
  109. package/src/viewer/vendor/shared/src/types.ts +12 -0
  110. package/src/viewer/vite-plugin.ts +109 -4
  111. package/dist/chunk-2JIKCJX3.js.map +0 -1
  112. package/dist/chunk-CJEGT3WD.js.map +0 -1
  113. package/dist/chunk-GOVI6COW.js.map +0 -1
  114. package/dist/generate-35OIMW4Y.js +0 -252
  115. package/dist/generate-35OIMW4Y.js.map +0 -1
  116. package/dist/init-KSAAS7X3.js.map +0 -1
  117. package/dist/viewer-SBTJDMP7.js.map +0 -1
  118. /package/dist/{chunk-WI6SLMSO.js.map → chunk-5GT62FCB.js.map} +0 -0
  119. /package/dist/{chunk-NGIMCIK2.js.map → chunk-GF6OVPIN.js.map} +0 -0
  120. /package/dist/{scan-65RH3QMM.js.map → scan-JGS65S7P.js.map} +0 -0
  121. /package/dist/{service-A5GIGGGK.js.map → service-XP2EAJXD.js.map} +0 -0
  122. /package/dist/{static-viewer-NSODM5VX.js.map → static-viewer-XCS7UJTO.js.map} +0 -0
  123. /package/dist/{test-RPWZAYSJ.js.map → test-TD6TJNVY.js.map} +0 -0
package/dist/bin.js CHANGED
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
3
+ import {
4
+ scan
5
+ } from "./chunk-5GT62FCB.js";
3
6
  import {
4
7
  buildFragments,
5
8
  buildFragmentsDir,
@@ -12,14 +15,11 @@ import {
12
15
  validateCoverage,
13
16
  validateSchema,
14
17
  validateSnippets
15
- } from "./chunk-2JIKCJX3.js";
16
- import {
17
- scan
18
- } from "./chunk-WI6SLMSO.js";
18
+ } from "./chunk-D7372LQX.js";
19
19
  import {
20
20
  loadConfig,
21
21
  loadFragmentFile
22
- } from "./chunk-CJEGT3WD.js";
22
+ } from "./chunk-BW3ZATBW.js";
23
23
  import {
24
24
  discoverFragmentFiles
25
25
  } from "./chunk-AWYCDRPG.js";
@@ -44,8 +44,9 @@ import {
44
44
  formatBytes,
45
45
  generateContext,
46
46
  resolvePerformanceConfig
47
- } from "./chunk-NGIMCIK2.js";
48
- import "./chunk-GOVI6COW.js";
47
+ } from "./chunk-GF6OVPIN.js";
48
+ import "./chunk-NVSPGSKB.js";
49
+ import "./chunk-EZYXYWNF.js";
49
50
  import {
50
51
  BRAND
51
52
  } from "./chunk-EKLMXTWU.js";
@@ -176,9 +177,20 @@ ${BRAND.name} Build
176
177
  }
177
178
  fragmentCount = result.fragmentCount;
178
179
  outputPath = result.outputPath;
179
- console.log(pc2.green(`\u2713 Built ${result.fragmentCount} fragment(s)`));
180
- console.log(pc2.dim(` Output: ${result.outputPath}
180
+ if (result.fragmentCount === 0 && result.errors.length === 0) {
181
+ console.log(pc2.dim("No compilable fragment files found. Falling back to source scan...\n"));
182
+ const scanResult = await scan({
183
+ config: options.config,
184
+ output: options.output,
185
+ verbose: options.verbose
186
+ });
187
+ fragmentCount = scanResult.componentCount;
188
+ outputPath = scanResult.outputPath;
189
+ } else {
190
+ console.log(pc2.green(`\u2713 Built ${result.fragmentCount} fragment(s)`));
191
+ console.log(pc2.dim(` Output: ${result.outputPath}
181
192
  `));
193
+ }
182
194
  }
183
195
  if (options.registry || options.registryOnly) {
184
196
  console.log(pc2.dim("Generating registry and context...\n"));
@@ -602,6 +614,7 @@ function parseMeta(content, filePath, warnings) {
602
614
  );
603
615
  if (importMatch) {
604
616
  result.componentImport = importMatch[1];
617
+ result.isDefaultImport = false;
605
618
  } else {
606
619
  const defaultImportMatch = content.match(
607
620
  new RegExp(
@@ -610,6 +623,7 @@ function parseMeta(content, filePath, warnings) {
610
623
  );
611
624
  if (defaultImportMatch) {
612
625
  result.componentImport = defaultImportMatch[1];
626
+ result.isDefaultImport = true;
613
627
  }
614
628
  }
615
629
  }
@@ -1199,6 +1213,7 @@ function convertToFragment(parsed) {
1199
1213
  const code = generateFragmentCode({
1200
1214
  componentName,
1201
1215
  componentImport: parsed.meta.componentImport,
1216
+ isDefaultImport: parsed.meta.isDefaultImport,
1202
1217
  description: parsed.meta.description,
1203
1218
  category,
1204
1219
  tags: parsed.meta.tags,
@@ -1434,6 +1449,7 @@ function generateFragmentCode(options) {
1434
1449
  const {
1435
1450
  componentName,
1436
1451
  componentImport,
1452
+ isDefaultImport,
1437
1453
  description,
1438
1454
  category,
1439
1455
  tags,
@@ -1461,8 +1477,9 @@ ${generated.skippedVariants.map((sv) => ` { name: "${escapeString(sv.name)}
1461
1477
  },
1462
1478
  `;
1463
1479
  }
1480
+ const componentImportStatement = isDefaultImport ? `import ${componentName} from "${componentImport}";` : `import { ${componentName} } from "${componentImport}";`;
1464
1481
  return `import { defineFragment } from "@fragments-sdk/cli/core";
1465
- import { ${componentName} } from "${componentImport}";
1482
+ ${componentImportStatement}
1466
1483
 
1467
1484
  export default defineFragment({
1468
1485
  component: ${componentName},
@@ -1717,27 +1734,48 @@ async function runSetup(options = {}) {
1717
1734
  const sbConfig = await detectStorybookConfig(configDir);
1718
1735
  if (sbConfig) {
1719
1736
  log(pc6.dim(` Found Storybook at ${sbConfig.configPath}`));
1720
- log(pc6.dim(" Converting stories to fragments...\n"));
1721
- const storyFiles = await discoverStoryFiles(configDir, sbConfig.storyPatterns);
1722
- if (storyFiles.length > 0) {
1723
- let converted = 0;
1724
- for (const storyFile of storyFiles) {
1725
- try {
1726
- const parsed = await parseStoryFile(storyFile);
1727
- const fragmentResult = convertToFragment(parsed);
1728
- await fs2.mkdir(path.dirname(fragmentResult.outputFile), { recursive: true });
1729
- await fs2.writeFile(fragmentResult.outputFile, fragmentResult.code);
1730
- converted++;
1731
- } catch {
1737
+ const hasStoryPatterns = config.include.some((p) => p.includes(".stories."));
1738
+ if (hasStoryPatterns) {
1739
+ log(pc6.dim(" Stories included in config \u2014 viewer will load them directly\n"));
1740
+ fragmentFiles = await discoverFragmentFiles(config, configDir);
1741
+ if (fragmentFiles.length > 0) {
1742
+ log(pc6.green(` Found ${fragmentFiles.length} story/fragment file(s)`));
1743
+ }
1744
+ } else {
1745
+ log(pc6.dim(" Converting stories to fragments...\n"));
1746
+ const storyFiles = await discoverStoryFiles(configDir, sbConfig.storyPatterns);
1747
+ if (storyFiles.length > 0) {
1748
+ let converted = 0;
1749
+ for (const storyFile of storyFiles) {
1750
+ try {
1751
+ const parsed = await parseStoryFile(storyFile);
1752
+ const fragmentResult = convertToFragment(parsed);
1753
+ await fs2.mkdir(path.dirname(fragmentResult.outputFile), { recursive: true });
1754
+ await fs2.writeFile(fragmentResult.outputFile, fragmentResult.code);
1755
+ converted++;
1756
+ } catch {
1757
+ }
1732
1758
  }
1759
+ result.fragmentFilesCreated = converted;
1760
+ log(pc6.green(` Generated ${converted} fragment file(s)`));
1761
+ fragmentFiles = await discoverFragmentFiles(config, configDir);
1733
1762
  }
1734
- result.fragmentFilesCreated = converted;
1735
- log(pc6.green(` Generated ${converted} fragment file(s)`));
1736
- fragmentFiles = await discoverFragmentFiles(config, configDir);
1737
1763
  }
1738
1764
  } else {
1739
1765
  log(pc6.dim(" No Storybook config found"));
1740
- log(pc6.dim(` Run ${pc6.cyan(`${BRAND.cliCommand} add <ComponentName>`)} to create your first fragment`));
1766
+ log(pc6.dim(" Auto-scanning source code...\n"));
1767
+ try {
1768
+ const scanResult = await scan({
1769
+ config: options.configPath,
1770
+ verbose: false
1771
+ });
1772
+ if (scanResult.componentCount > 0) {
1773
+ result.fragmentsBuilt = scanResult.componentCount;
1774
+ log(pc6.green(` Scanned ${scanResult.componentCount} component(s) from source`));
1775
+ }
1776
+ } catch {
1777
+ log(pc6.dim(` Run ${pc6.cyan(`${BRAND.cliCommand} scan`)} to generate documentation from source`));
1778
+ }
1741
1779
  }
1742
1780
  } else if (fragmentFiles.length > 0) {
1743
1781
  log(pc6.green(` Found ${fragmentFiles.length} fragment file(s)`));
@@ -1757,7 +1795,19 @@ ${reason} ${BRAND.outFile}...`));
1757
1795
  result.errors.push(`${err.file}: ${err.error}`);
1758
1796
  }
1759
1797
  }
1760
- log(pc6.green(` Built ${buildResult.fragmentCount} fragment(s)`));
1798
+ if (buildResult.fragmentCount > 0) {
1799
+ log(pc6.green(` Built ${buildResult.fragmentCount} fragment(s)`));
1800
+ } else {
1801
+ log(pc6.dim(" No compilable fragments found, falling back to source scan..."));
1802
+ try {
1803
+ const scanResult = await scan({ verbose: false });
1804
+ if (scanResult.componentCount > 0) {
1805
+ result.fragmentsBuilt = scanResult.componentCount;
1806
+ log(pc6.green(` Scanned ${scanResult.componentCount} component(s) from source`));
1807
+ }
1808
+ } catch {
1809
+ }
1810
+ }
1761
1811
  } catch (error) {
1762
1812
  result.errors.push(`Build failed: ${error instanceof Error ? error.message : "Unknown error"}`);
1763
1813
  }
@@ -1811,7 +1861,7 @@ ${BRAND.name} Dev Server
1811
1861
  }
1812
1862
  }
1813
1863
  }
1814
- const { createDevServer } = await import("./viewer-SBTJDMP7.js");
1864
+ const { createDevServer } = await import("./viewer-RFA2KVBG.js");
1815
1865
  console.log(pc7.dim("\nStarting dev server..."));
1816
1866
  const parsedPort = typeof port === "string" ? parseInt(port, 10) : port;
1817
1867
  try {
@@ -6108,7 +6158,7 @@ Make sure the dev server is running: ${BRAND.cliCommand} dev`));
6108
6158
  });
6109
6159
  program.command("view").description(`Generate a static HTML viewer for ${BRAND.outFile}`).option("-i, --input <path>", `Path to ${BRAND.outFile}`, BRAND.outFile).option("-o, --output <path>", "Output HTML file path", BRAND.viewerHtmlFile).option("--open", "Open in browser after generation").action(async (options) => {
6110
6160
  try {
6111
- const { generateViewerFromJson } = await import("./static-viewer-NSODM5VX.js");
6161
+ const { generateViewerFromJson } = await import("./static-viewer-XCS7UJTO.js");
6112
6162
  const fs2 = await import("fs/promises");
6113
6163
  const path = await import("path");
6114
6164
  const inputPath = path.resolve(process.cwd(), options.input);
@@ -6156,7 +6206,7 @@ program.command("add").argument("[name]", 'Component name (e.g., "Button", "Text
6156
6206
  });
6157
6207
  program.command("init").description("Initialize fragments in a project (interactive by default)").option("--force", "Overwrite existing config").option("-y, --yes", "Non-interactive mode - auto-detect and use defaults").action(async (options) => {
6158
6208
  try {
6159
- const { init } = await import("./init-KSAAS7X3.js");
6209
+ const { init } = await import("./init-2GEGVIUQ.js");
6160
6210
  const result = await init({
6161
6211
  projectRoot: process.cwd(),
6162
6212
  force: options.force,
@@ -6176,7 +6226,7 @@ program.command("init").description("Initialize fragments in a project (interact
6176
6226
  });
6177
6227
  program.command("tokens").description("Discover and list design tokens from CSS/SCSS files").option("-c, --config <path>", "Path to config file").option("--json", "Output as JSON").option("--categories", "Group tokens by category").option("--theme <theme>", "Filter by theme name").option("--category <category>", "Filter by category (color, spacing, typography, etc.)").option("--verbose", "Show all tokens (no truncation)").action(async (options) => {
6178
6228
  try {
6179
- const { tokens } = await import("./tokens-NIXSZRX7.js");
6229
+ const { tokens } = await import("./tokens-2EXPCVP3.js");
6180
6230
  const result = await tokens({
6181
6231
  config: options.config,
6182
6232
  json: options.json,
@@ -6195,7 +6245,7 @@ program.command("tokens").description("Discover and list design tokens from CSS/
6195
6245
  });
6196
6246
  program.command("generate").description("Generate fragment files from component source code").argument("[component]", "Specific component name to generate (optional)").option("--force", "Overwrite existing fragment files").option("--pattern <glob>", "Pattern for component files", "src/components/**/*.tsx").action(async (component, options) => {
6197
6247
  try {
6198
- const { generate } = await import("./generate-35OIMW4Y.js");
6248
+ const { generate } = await import("./generate-LQA2R7FN.js");
6199
6249
  const result = await generate({
6200
6250
  projectRoot: process.cwd(),
6201
6251
  component,
@@ -6240,7 +6290,7 @@ program.command("perf").description("Profile component bundle sizes and performa
6240
6290
  program.command("test").description("Run interaction tests for fragments with play functions").option("-c, --config <path>", "Path to config file").option("--component <name>", "Filter by component name").option("--tags <tags>", "Filter by tags (comma-separated)").option("--grep <pattern>", "Filter by variant name pattern").option("--exclude <pattern>", "Exclude tests matching pattern").option("--parallel <count>", "Number of parallel browser contexts", parseInt, 4).option("--timeout <ms>", "Timeout per test in milliseconds", parseInt, 3e4).option("--retries <count>", "Number of retries for failed tests", parseInt, 0).option("--bail", "Stop on first failure").option("--browser <name>", "Browser to use (chromium, firefox, webkit)", "chromium").option("--headed", "Run in headed mode (show browser)").option("--a11y", "Run accessibility checks with axe-core").option("--visual", "Capture screenshots for visual regression").option("--update-snapshots", "Update visual snapshots").option("--watch", "Watch mode - re-run on file changes").option("--reporters <names>", "Reporters to use (console, junit, json)", "console").option("-o, --output <dir>", "Output directory for results", "./test-results").option("--server-url <url>", "URL of running dev server (skips starting server)").option("-p, --port <port>", "Port for dev server", parseInt, 6006).option("--ci", "CI mode - non-interactive, exit with code 1 on failure").option("--list", "List available tests without running them").action(async (options) => {
6241
6291
  try {
6242
6292
  const { config, configDir } = await loadConfig(options.config);
6243
- const { runTestCommand, listTests } = await import("./test-RPWZAYSJ.js");
6293
+ const { runTestCommand, listTests } = await import("./test-TD6TJNVY.js");
6244
6294
  if (options.list) {
6245
6295
  await listTests(config, configDir, {
6246
6296
  component: options.component,