@fragments-sdk/cli 0.9.0 → 0.10.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.
Files changed (166) hide show
  1. package/dist/bin.d.ts +1 -0
  2. package/dist/bin.js +502 -84
  3. package/dist/bin.js.map +1 -1
  4. package/dist/{chunk-CJEGT3WD.js → chunk-566BNPQZ.js} +21 -6
  5. package/dist/chunk-566BNPQZ.js.map +1 -0
  6. package/dist/{chunk-WI6SLMSO.js → chunk-CAMXG5HJ.js} +5 -5
  7. package/dist/chunk-D2CDBRNU.js +2 -0
  8. package/dist/{chunk-YMPGYEWK.js → chunk-D5PYOXEI.js} +2 -2
  9. package/dist/{chunk-NGIMCIK2.js → chunk-OQO55NKV.js} +405 -34
  10. package/dist/chunk-OQO55NKV.js.map +1 -0
  11. package/dist/{chunk-TOIE7VXF.js → chunk-PW7QTQA6.js} +2 -2
  12. package/dist/{chunk-AWYCDRPG.js → chunk-WXSR2II7.js} +2 -2
  13. package/dist/chunk-WXSR2II7.js.map +1 -0
  14. package/dist/{chunk-2JIKCJX3.js → chunk-ZDA3PLQ6.js} +17 -14
  15. package/dist/chunk-ZDA3PLQ6.js.map +1 -0
  16. package/dist/core/index.d.ts +1 -2092
  17. package/dist/core/index.js +26 -21
  18. package/dist/{discovery-Z4RDDFVR.js → discovery-NEOY4MPN.js} +3 -3
  19. package/dist/generate-BGKTKO6E.js +459 -0
  20. package/dist/generate-BGKTKO6E.js.map +1 -0
  21. package/dist/index.d.ts +3 -5
  22. package/dist/index.js +7 -8
  23. package/dist/index.js.map +1 -1
  24. package/dist/{init-KSAAS7X3.js → init-Q53R5Q2T.js} +66 -76
  25. package/dist/init-Q53R5Q2T.js.map +1 -0
  26. package/dist/mcp-bin.js +5 -7
  27. package/dist/mcp-bin.js.map +1 -1
  28. package/dist/scan-OQU7M4GH.js +14 -0
  29. package/dist/scan-generate-T5QNUG7N.js +691 -0
  30. package/dist/scan-generate-T5QNUG7N.js.map +1 -0
  31. package/dist/{service-A5GIGGGK.js → service-TQYWY65E.js} +4 -5
  32. package/dist/{static-viewer-NSODM5VX.js → static-viewer-NUBFPKWH.js} +4 -5
  33. package/dist/static-viewer-NUBFPKWH.js.map +1 -0
  34. package/dist/{test-RPWZAYSJ.js → test-2CSOSS3B.js} +4 -5
  35. package/dist/{test-RPWZAYSJ.js.map → test-2CSOSS3B.js.map} +1 -1
  36. package/dist/{tokens-NIXSZRX7.js → tokens-DXEGYTOJ.js} +6 -7
  37. package/dist/{tokens-NIXSZRX7.js.map → tokens-DXEGYTOJ.js.map} +1 -1
  38. package/dist/{viewer-SBTJDMP7.js → viewer-DBEPYM3G.js} +245 -23
  39. package/dist/viewer-DBEPYM3G.js.map +1 -0
  40. package/package.json +2 -1
  41. package/src/bin.ts +33 -1
  42. package/src/build.ts +13 -3
  43. package/src/commands/__tests__/scan-generate.test.ts +308 -0
  44. package/src/commands/build.ts +16 -2
  45. package/src/commands/generate.ts +383 -68
  46. package/src/commands/init.ts +81 -56
  47. package/src/commands/perf.ts +1 -1
  48. package/src/commands/scan-generate.ts +1013 -0
  49. package/src/commands/setup.ts +499 -0
  50. package/src/core/auto-props.ts +1 -1
  51. package/src/core/bundle-measurer.ts +2 -2
  52. package/src/core/config.ts +16 -4
  53. package/src/core/discovery.ts +2 -2
  54. package/src/core/generators/context.ts +1 -1
  55. package/src/core/generators/registry.ts +3 -3
  56. package/src/core/generators/typescript-extractor.ts +11 -1
  57. package/src/core/graph-extractor.ts +1 -1
  58. package/src/core/index.ts +3 -190
  59. package/src/core/loader.ts +2 -2
  60. package/src/core/parser.ts +1 -1
  61. package/src/core/previewLoader.ts +1 -1
  62. package/src/index.ts +2 -2
  63. package/src/migrate/converter.ts +9 -1
  64. package/src/migrate/parser.ts +2 -0
  65. package/src/migrate/types.ts +2 -0
  66. package/src/service/snippet-validation.test.ts +1 -1
  67. package/src/service/snippet-validation.ts +2 -2
  68. package/src/setup.ts +69 -24
  69. package/src/viewer/__tests__/viewer-integration.test.ts +4 -10
  70. package/src/viewer/components/AccessibilityPanel.tsx +305 -312
  71. package/src/viewer/components/ActionsPanel.tsx +31 -29
  72. package/src/viewer/components/AllVariantsPreview.tsx +78 -0
  73. package/src/viewer/components/App.tsx +187 -740
  74. package/src/viewer/components/BottomPanel.tsx +228 -132
  75. package/src/viewer/components/CodePanel.tsx +1 -1
  76. package/src/viewer/components/CommandPalette.tsx +7 -10
  77. package/src/viewer/components/ComponentDocView.tsx +164 -0
  78. package/src/viewer/components/ComponentGraph.tsx +111 -142
  79. package/src/viewer/components/ContractPanel.tsx +6 -6
  80. package/src/viewer/components/EmptyVariantMessage.tsx +54 -0
  81. package/src/viewer/components/FigmaEmbed.tsx +20 -18
  82. package/src/viewer/components/FragmentEditor.tsx +92 -115
  83. package/src/viewer/components/HeaderSearch.tsx +24 -0
  84. package/src/viewer/components/HealthDashboard.tsx +16 -2
  85. package/src/viewer/components/Icons.tsx +9 -0
  86. package/src/viewer/components/InteractionsPanel.tsx +101 -117
  87. package/src/viewer/components/IsolatedPreviewFrame.tsx +1 -0
  88. package/src/viewer/components/LandingPage.tsx +3 -3
  89. package/src/viewer/components/LeftSidebar.tsx +141 -63
  90. package/src/viewer/components/LoadErrorMessage.tsx +102 -0
  91. package/src/viewer/components/MultiViewportPreview.tsx +61 -142
  92. package/src/viewer/components/NoVariantsMessage.tsx +59 -0
  93. package/src/viewer/components/PanelShell.tsx +161 -0
  94. package/src/viewer/components/PerformancePanel.tsx +31 -28
  95. package/src/viewer/components/PreviewArea.tsx +1 -1
  96. package/src/viewer/components/PreviewAside.tsx +168 -0
  97. package/src/viewer/components/PreviewFrameHost.tsx +3 -3
  98. package/src/viewer/components/PropsEditor.tsx +70 -156
  99. package/src/viewer/components/ResizablePanel.tsx +103 -263
  100. package/src/viewer/components/RightSidebar.tsx +3 -9
  101. package/src/viewer/components/SkeletonLoader.tsx +13 -13
  102. package/src/viewer/components/TokenStylePanel.tsx +182 -209
  103. package/src/viewer/components/TopToolbar.tsx +159 -0
  104. package/src/viewer/components/VariantMatrix.tsx +42 -86
  105. package/src/viewer/components/VariantTabs.tsx +3 -3
  106. package/src/viewer/components/ViewerHeader.tsx +69 -0
  107. package/src/viewer/components/WebMCPDevTools.tsx +17 -23
  108. package/src/viewer/components/viewer-utils.ts +16 -0
  109. package/src/viewer/entry.tsx +5 -0
  110. package/src/viewer/hooks/useAppState.ts +27 -4
  111. package/src/viewer/hooks/usePreviewBridge.ts +2 -2
  112. package/src/viewer/preview-frame.html +6 -12
  113. package/src/viewer/server.ts +169 -2
  114. package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss +10 -0
  115. package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss.d.ts +2 -0
  116. package/src/viewer/vendor/shared/src/ComponentDocContent.tsx +274 -0
  117. package/src/viewer/vendor/shared/src/DocsHeaderBar.tsx +6 -18
  118. package/src/viewer/vendor/shared/src/DocsPageShell.tsx +5 -0
  119. package/src/viewer/vendor/shared/src/DocsSidebarNav.tsx +5 -16
  120. package/src/viewer/vendor/shared/src/PropsTable.module.scss +68 -0
  121. package/src/viewer/vendor/shared/src/PropsTable.module.scss.d.ts +2 -0
  122. package/src/viewer/vendor/shared/src/PropsTable.tsx +76 -0
  123. package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss +114 -0
  124. package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss.d.ts +2 -0
  125. package/src/viewer/vendor/shared/src/VariantPreviewCard.tsx +134 -0
  126. package/src/viewer/vendor/shared/src/index.ts +8 -0
  127. package/src/viewer/vendor/shared/src/types.ts +12 -0
  128. package/src/viewer/vite-plugin.ts +109 -4
  129. package/dist/chunk-2JIKCJX3.js.map +0 -1
  130. package/dist/chunk-AWYCDRPG.js.map +0 -1
  131. package/dist/chunk-CJEGT3WD.js.map +0 -1
  132. package/dist/chunk-EKLMXTWU.js +0 -80
  133. package/dist/chunk-EKLMXTWU.js.map +0 -1
  134. package/dist/chunk-GOVI6COW.js +0 -195
  135. package/dist/chunk-GOVI6COW.js.map +0 -1
  136. package/dist/chunk-NGIMCIK2.js.map +0 -1
  137. package/dist/defineFragment-D0UTve-I.d.ts +0 -665
  138. package/dist/generate-35OIMW4Y.js +0 -252
  139. package/dist/generate-35OIMW4Y.js.map +0 -1
  140. package/dist/init-KSAAS7X3.js.map +0 -1
  141. package/dist/scan-65RH3QMM.js +0 -15
  142. package/dist/viewer-SBTJDMP7.js.map +0 -1
  143. package/src/core/__tests__/preview-runtime.test.tsx +0 -111
  144. package/src/core/composition.test.ts +0 -262
  145. package/src/core/composition.ts +0 -318
  146. package/src/core/constants.ts +0 -114
  147. package/src/core/context.ts +0 -2
  148. package/src/core/defineFragment.ts +0 -141
  149. package/src/core/figma.ts +0 -263
  150. package/src/core/fragment-types.ts +0 -214
  151. package/src/core/performance-presets.ts +0 -142
  152. package/src/core/preview-runtime.tsx +0 -144
  153. package/src/core/schema.ts +0 -221
  154. package/src/core/storyAdapter.test.ts +0 -571
  155. package/src/core/storyAdapter.ts +0 -761
  156. package/src/core/storybook-csf.ts +0 -11
  157. package/src/core/token-parser.ts +0 -321
  158. package/src/core/token-types.ts +0 -287
  159. package/src/core/types.ts +0 -762
  160. /package/dist/{chunk-WI6SLMSO.js.map → chunk-CAMXG5HJ.js.map} +0 -0
  161. /package/dist/{discovery-Z4RDDFVR.js.map → chunk-D2CDBRNU.js.map} +0 -0
  162. /package/dist/{chunk-YMPGYEWK.js.map → chunk-D5PYOXEI.js.map} +0 -0
  163. /package/dist/{chunk-TOIE7VXF.js.map → chunk-PW7QTQA6.js.map} +0 -0
  164. /package/dist/{scan-65RH3QMM.js.map → discovery-NEOY4MPN.js.map} +0 -0
  165. /package/dist/{service-A5GIGGGK.js.map → scan-OQU7M4GH.js.map} +0 -0
  166. /package/dist/{static-viewer-NSODM5VX.js.map → service-TQYWY65E.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/tokens.ts"],"sourcesContent":["/**\n * CLI Tokens Command\n *\n * Discover and list design tokens from CSS/SCSS files.\n *\n * Usage:\n * fragments tokens # List all tokens\n * fragments tokens --json # Output as JSON\n * fragments tokens --categories # Group by category\n * fragments tokens --theme dark # Filter by theme\n */\n\nimport pc from \"picocolors\";\nimport { BRAND } from \"../core/index.js\";\nimport type { DesignToken, TokenCategory, TokenConfig } from \"../core/index.js\";\nimport { loadConfig } from \"../core/node.js\";\nimport { parseTokenFiles, createTokenRegistry } from \"../service/index.js\";\n\nexport interface TokensCommandOptions {\n config?: string;\n json?: boolean;\n categories?: boolean;\n theme?: string;\n category?: string;\n verbose?: boolean;\n}\n\nexport interface TokensCommandResult {\n success: boolean;\n tokenCount: number;\n errors: string[];\n}\n\n/**\n * Run the tokens command\n */\nexport async function tokens(\n options: TokensCommandOptions\n): Promise<TokensCommandResult> {\n const errors: string[] = [];\n\n try {\n console.log(pc.cyan(`\\n${BRAND.name} Token Discovery\\n`));\n\n // Load config\n const { config, configDir } = await loadConfig(options.config);\n\n // Check for token configuration\n if (!config.tokens || !config.tokens.include || config.tokens.include.length === 0) {\n console.log(pc.yellow(\"No token configuration found.\\n\"));\n console.log(pc.dim(\"Add 'tokens' config to fragments.config.ts:\"));\n console.log(pc.dim(`\n tokens: {\n include: ['src/styles/theme.scss', 'src/styles/variables.css'],\n themeSelectors: {\n ':root': 'default',\n '[data-theme=\"dark\"]': 'dark',\n },\n },\n`));\n return { success: false, tokenCount: 0, errors: [\"No token configuration\"] };\n }\n\n console.log(pc.dim(`Scanning files: ${config.tokens.include.join(\", \")}\\n`));\n\n // Parse token files\n const parseResult = await parseTokenFiles(config.tokens, configDir);\n\n if (parseResult.errors.length > 0) {\n console.log(pc.yellow(\"Parse errors:\"));\n for (const err of parseResult.errors) {\n console.log(pc.red(` ${err.file}: ${err.message}`));\n errors.push(`${err.file}: ${err.message}`);\n }\n console.log();\n }\n\n if (parseResult.warnings.length > 0 && options.verbose) {\n console.log(pc.yellow(\"Warnings:\"));\n for (const warning of parseResult.warnings) {\n console.log(pc.dim(` ${warning}`));\n }\n console.log();\n }\n\n let tokens = parseResult.tokens;\n\n // Filter by theme if specified\n if (options.theme) {\n tokens = tokens.filter(\n (t) => t.theme === options.theme || t.theme === \"default\"\n );\n }\n\n // Filter by category if specified\n if (options.category) {\n tokens = tokens.filter((t) => t.category === options.category);\n }\n\n if (tokens.length === 0) {\n console.log(pc.yellow(\"No tokens found.\\n\"));\n console.log(pc.dim(\"Make sure your CSS files contain CSS custom properties (--token-name: value;)\"));\n return { success: true, tokenCount: 0, errors };\n }\n\n // Output based on format\n if (options.json) {\n outputJson(tokens, parseResult.parseTimeMs);\n } else if (options.categories) {\n outputByCategory(tokens, parseResult.parseTimeMs);\n } else {\n outputList(tokens, parseResult.parseTimeMs, options.verbose);\n }\n\n return { success: true, tokenCount: tokens.length, errors };\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n console.error(pc.red(\"Error:\"), message);\n errors.push(message);\n return { success: false, tokenCount: 0, errors };\n }\n}\n\n/**\n * Output tokens as JSON\n */\nfunction outputJson(tokens: DesignToken[], parseTimeMs: number): void {\n const output = {\n tokens,\n meta: {\n totalTokens: tokens.length,\n parseTimeMs,\n discoveredAt: new Date().toISOString(),\n },\n };\n\n console.log(JSON.stringify(output, null, 2));\n}\n\n/**\n * Output tokens grouped by category\n */\nfunction outputByCategory(tokens: DesignToken[], parseTimeMs: number): void {\n // Group by category\n const byCategory = new Map<TokenCategory, DesignToken[]>();\n\n for (const token of tokens) {\n const list = byCategory.get(token.category) || [];\n list.push(token);\n byCategory.set(token.category, list);\n }\n\n // Sort categories alphabetically\n const categories = Array.from(byCategory.keys()).sort();\n\n for (const category of categories) {\n const categoryTokens = byCategory.get(category) || [];\n console.log(pc.bold(`${category} (${categoryTokens.length})`));\n console.log(pc.dim(\"─\".repeat(40)));\n\n for (const token of categoryTokens.slice(0, 10)) {\n const levelLabel = token.level === 1 ? \"base\" : token.level === 2 ? \"semantic\" : \"component\";\n console.log(` ${pc.cyan(token.name)}`);\n console.log(` ${pc.dim(\"Value:\")} ${token.resolvedValue}`);\n console.log(` ${pc.dim(\"Level:\")} ${levelLabel} ${pc.dim(`(${token.theme})`)}`);\n }\n\n if (categoryTokens.length > 10) {\n console.log(pc.dim(` ... and ${categoryTokens.length - 10} more`));\n }\n console.log();\n }\n\n // Summary\n console.log(pc.dim(\"─\".repeat(40)));\n console.log(pc.green(`✓ Found ${tokens.length} token(s) in ${categories.length} categories`));\n console.log(pc.dim(` Parsed in ${parseTimeMs.toFixed(1)}ms\\n`));\n}\n\n/**\n * Output tokens as a simple list\n */\nfunction outputList(tokens: DesignToken[], parseTimeMs: number, verbose?: boolean): void {\n // Group by theme first\n const byTheme = new Map<string, DesignToken[]>();\n\n for (const token of tokens) {\n const list = byTheme.get(token.theme) || [];\n list.push(token);\n byTheme.set(token.theme, list);\n }\n\n const themes = Array.from(byTheme.keys()).sort();\n\n for (const theme of themes) {\n const themeTokens = byTheme.get(theme) || [];\n\n if (themes.length > 1) {\n console.log(pc.bold(`Theme: ${theme} (${themeTokens.length} tokens)`));\n console.log(pc.dim(\"─\".repeat(50)));\n }\n\n // Sort tokens by name\n themeTokens.sort((a, b) => a.name.localeCompare(b.name));\n\n // Table header\n console.log(\n pc.dim(\n `${\"Token Name\".padEnd(32)} ${\"Value\".padEnd(20)} ${\"Category\".padEnd(12)}`\n )\n );\n console.log(pc.dim(\"─\".repeat(70)));\n\n const displayTokens = verbose ? themeTokens : themeTokens.slice(0, 30);\n\n for (const token of displayTokens) {\n const name = token.name.length > 30 ? token.name.slice(0, 27) + \"...\" : token.name;\n const value = token.resolvedValue.length > 18 ? token.resolvedValue.slice(0, 15) + \"...\" : token.resolvedValue;\n\n console.log(\n `${pc.cyan(name.padEnd(32))} ${value.padEnd(20)} ${pc.dim(token.category.padEnd(12))}`\n );\n }\n\n if (!verbose && themeTokens.length > 30) {\n console.log(pc.dim(`\\n ... and ${themeTokens.length - 30} more (use --verbose to show all)`));\n }\n\n console.log();\n }\n\n // Summary\n console.log(pc.dim(\"─\".repeat(50)));\n console.log(pc.green(`✓ Found ${tokens.length} token(s)`));\n\n // Category breakdown\n const categoryCounts: Record<string, number> = {};\n for (const token of tokens) {\n categoryCounts[token.category] = (categoryCounts[token.category] || 0) + 1;\n }\n\n const breakdown = Object.entries(categoryCounts)\n .sort((a, b) => b[1] - a[1])\n .map(([cat, count]) => `${cat}: ${count}`)\n .join(\", \");\n\n console.log(pc.dim(` ${breakdown}`));\n console.log(pc.dim(` Parsed in ${parseTimeMs.toFixed(1)}ms\\n`));\n}\n\nexport default tokens;\n"],"mappings":"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","names":["tokens"]}
1
+ {"version":3,"sources":["../src/commands/tokens.ts"],"sourcesContent":["/**\n * CLI Tokens Command\n *\n * Discover and list design tokens from CSS/SCSS files.\n *\n * Usage:\n * fragments tokens # List all tokens\n * fragments tokens --json # Output as JSON\n * fragments tokens --categories # Group by category\n * fragments tokens --theme dark # Filter by theme\n */\n\nimport pc from \"picocolors\";\nimport { BRAND } from \"../core/index.js\";\nimport type { DesignToken, TokenCategory, TokenConfig } from \"../core/index.js\";\nimport { loadConfig } from \"../core/node.js\";\nimport { parseTokenFiles, createTokenRegistry } from \"../service/index.js\";\n\nexport interface TokensCommandOptions {\n config?: string;\n json?: boolean;\n categories?: boolean;\n theme?: string;\n category?: string;\n verbose?: boolean;\n}\n\nexport interface TokensCommandResult {\n success: boolean;\n tokenCount: number;\n errors: string[];\n}\n\n/**\n * Run the tokens command\n */\nexport async function tokens(\n options: TokensCommandOptions\n): Promise<TokensCommandResult> {\n const errors: string[] = [];\n\n try {\n console.log(pc.cyan(`\\n${BRAND.name} Token Discovery\\n`));\n\n // Load config\n const { config, configDir } = await loadConfig(options.config);\n\n // Check for token configuration\n if (!config.tokens || !config.tokens.include || config.tokens.include.length === 0) {\n console.log(pc.yellow(\"No token configuration found.\\n\"));\n console.log(pc.dim(\"Add 'tokens' config to fragments.config.ts:\"));\n console.log(pc.dim(`\n tokens: {\n include: ['src/styles/theme.scss', 'src/styles/variables.css'],\n themeSelectors: {\n ':root': 'default',\n '[data-theme=\"dark\"]': 'dark',\n },\n },\n`));\n return { success: false, tokenCount: 0, errors: [\"No token configuration\"] };\n }\n\n console.log(pc.dim(`Scanning files: ${config.tokens.include.join(\", \")}\\n`));\n\n // Parse token files\n const parseResult = await parseTokenFiles(config.tokens, configDir);\n\n if (parseResult.errors.length > 0) {\n console.log(pc.yellow(\"Parse errors:\"));\n for (const err of parseResult.errors) {\n console.log(pc.red(` ${err.file}: ${err.message}`));\n errors.push(`${err.file}: ${err.message}`);\n }\n console.log();\n }\n\n if (parseResult.warnings.length > 0 && options.verbose) {\n console.log(pc.yellow(\"Warnings:\"));\n for (const warning of parseResult.warnings) {\n console.log(pc.dim(` ${warning}`));\n }\n console.log();\n }\n\n let tokens = parseResult.tokens;\n\n // Filter by theme if specified\n if (options.theme) {\n tokens = tokens.filter(\n (t) => t.theme === options.theme || t.theme === \"default\"\n );\n }\n\n // Filter by category if specified\n if (options.category) {\n tokens = tokens.filter((t) => t.category === options.category);\n }\n\n if (tokens.length === 0) {\n console.log(pc.yellow(\"No tokens found.\\n\"));\n console.log(pc.dim(\"Make sure your CSS files contain CSS custom properties (--token-name: value;)\"));\n return { success: true, tokenCount: 0, errors };\n }\n\n // Output based on format\n if (options.json) {\n outputJson(tokens, parseResult.parseTimeMs);\n } else if (options.categories) {\n outputByCategory(tokens, parseResult.parseTimeMs);\n } else {\n outputList(tokens, parseResult.parseTimeMs, options.verbose);\n }\n\n return { success: true, tokenCount: tokens.length, errors };\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n console.error(pc.red(\"Error:\"), message);\n errors.push(message);\n return { success: false, tokenCount: 0, errors };\n }\n}\n\n/**\n * Output tokens as JSON\n */\nfunction outputJson(tokens: DesignToken[], parseTimeMs: number): void {\n const output = {\n tokens,\n meta: {\n totalTokens: tokens.length,\n parseTimeMs,\n discoveredAt: new Date().toISOString(),\n },\n };\n\n console.log(JSON.stringify(output, null, 2));\n}\n\n/**\n * Output tokens grouped by category\n */\nfunction outputByCategory(tokens: DesignToken[], parseTimeMs: number): void {\n // Group by category\n const byCategory = new Map<TokenCategory, DesignToken[]>();\n\n for (const token of tokens) {\n const list = byCategory.get(token.category) || [];\n list.push(token);\n byCategory.set(token.category, list);\n }\n\n // Sort categories alphabetically\n const categories = Array.from(byCategory.keys()).sort();\n\n for (const category of categories) {\n const categoryTokens = byCategory.get(category) || [];\n console.log(pc.bold(`${category} (${categoryTokens.length})`));\n console.log(pc.dim(\"─\".repeat(40)));\n\n for (const token of categoryTokens.slice(0, 10)) {\n const levelLabel = token.level === 1 ? \"base\" : token.level === 2 ? \"semantic\" : \"component\";\n console.log(` ${pc.cyan(token.name)}`);\n console.log(` ${pc.dim(\"Value:\")} ${token.resolvedValue}`);\n console.log(` ${pc.dim(\"Level:\")} ${levelLabel} ${pc.dim(`(${token.theme})`)}`);\n }\n\n if (categoryTokens.length > 10) {\n console.log(pc.dim(` ... and ${categoryTokens.length - 10} more`));\n }\n console.log();\n }\n\n // Summary\n console.log(pc.dim(\"─\".repeat(40)));\n console.log(pc.green(`✓ Found ${tokens.length} token(s) in ${categories.length} categories`));\n console.log(pc.dim(` Parsed in ${parseTimeMs.toFixed(1)}ms\\n`));\n}\n\n/**\n * Output tokens as a simple list\n */\nfunction outputList(tokens: DesignToken[], parseTimeMs: number, verbose?: boolean): void {\n // Group by theme first\n const byTheme = new Map<string, DesignToken[]>();\n\n for (const token of tokens) {\n const list = byTheme.get(token.theme) || [];\n list.push(token);\n byTheme.set(token.theme, list);\n }\n\n const themes = Array.from(byTheme.keys()).sort();\n\n for (const theme of themes) {\n const themeTokens = byTheme.get(theme) || [];\n\n if (themes.length > 1) {\n console.log(pc.bold(`Theme: ${theme} (${themeTokens.length} tokens)`));\n console.log(pc.dim(\"─\".repeat(50)));\n }\n\n // Sort tokens by name\n themeTokens.sort((a, b) => a.name.localeCompare(b.name));\n\n // Table header\n console.log(\n pc.dim(\n `${\"Token Name\".padEnd(32)} ${\"Value\".padEnd(20)} ${\"Category\".padEnd(12)}`\n )\n );\n console.log(pc.dim(\"─\".repeat(70)));\n\n const displayTokens = verbose ? themeTokens : themeTokens.slice(0, 30);\n\n for (const token of displayTokens) {\n const name = token.name.length > 30 ? token.name.slice(0, 27) + \"...\" : token.name;\n const value = token.resolvedValue.length > 18 ? token.resolvedValue.slice(0, 15) + \"...\" : token.resolvedValue;\n\n console.log(\n `${pc.cyan(name.padEnd(32))} ${value.padEnd(20)} ${pc.dim(token.category.padEnd(12))}`\n );\n }\n\n if (!verbose && themeTokens.length > 30) {\n console.log(pc.dim(`\\n ... and ${themeTokens.length - 30} more (use --verbose to show all)`));\n }\n\n console.log();\n }\n\n // Summary\n console.log(pc.dim(\"─\".repeat(50)));\n console.log(pc.green(`✓ Found ${tokens.length} token(s)`));\n\n // Category breakdown\n const categoryCounts: Record<string, number> = {};\n for (const token of tokens) {\n categoryCounts[token.category] = (categoryCounts[token.category] || 0) + 1;\n }\n\n const breakdown = Object.entries(categoryCounts)\n .sort((a, b) => b[1] - a[1])\n .map(([cat, count]) => `${cat}: ${count}`)\n .join(\", \");\n\n console.log(pc.dim(` ${breakdown}`));\n console.log(pc.dim(` Parsed in ${parseTimeMs.toFixed(1)}ms\\n`));\n}\n\nexport default tokens;\n"],"mappings":"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","names":["tokens"]}
@@ -5,18 +5,16 @@ import {
5
5
  generatePreviewModule,
6
6
  loadConfig,
7
7
  parseFragmentFile
8
- } from "./chunk-CJEGT3WD.js";
8
+ } from "./chunk-566BNPQZ.js";
9
9
  import {
10
10
  discoverFragmentFiles,
11
11
  discoverInstalledFragments
12
- } from "./chunk-AWYCDRPG.js";
12
+ } from "./chunk-WXSR2II7.js";
13
+ import "./chunk-D2CDBRNU.js";
13
14
  import {
15
+ BRAND,
14
16
  generateContext
15
- } from "./chunk-NGIMCIK2.js";
16
- import "./chunk-GOVI6COW.js";
17
- import {
18
- BRAND
19
- } from "./chunk-EKLMXTWU.js";
17
+ } from "./chunk-OQO55NKV.js";
20
18
  import "./chunk-Z7EY4VHE.js";
21
19
 
22
20
  // src/viewer/server.ts
@@ -28,6 +26,7 @@ import {
28
26
  import react from "@vitejs/plugin-react";
29
27
  import { resolve as resolve2, dirname as dirname2, join } from "path";
30
28
  import { existsSync, realpathSync } from "fs";
29
+ import { readFile as readFile2 } from "fs/promises";
31
30
  import { fileURLToPath as fileURLToPath2 } from "url";
32
31
 
33
32
  // src/viewer/vite-plugin.ts
@@ -361,7 +360,7 @@ var sharedRenderPool = null;
361
360
  var browserPoolModule = null;
362
361
  async function getSharedRenderPool() {
363
362
  if (!browserPoolModule) {
364
- browserPoolModule = await import("./service-A5GIGGGK.js");
363
+ browserPoolModule = await import("./service-TQYWY65E.js");
365
364
  }
366
365
  if (!sharedRenderPool) {
367
366
  sharedRenderPool = new browserPoolModule.BrowserPool({
@@ -604,7 +603,7 @@ function fragmentsPlugin(options) {
604
603
  const address = _server.httpServer?.address();
605
604
  const port = typeof address === "object" && address ? address.port : 6006;
606
605
  const renderViewport = viewport || { width: 800, height: 600 };
607
- const { FigmaClient, bufferToBase64Url } = await import("./service-A5GIGGGK.js");
606
+ const { FigmaClient, bufferToBase64Url } = await import("./service-TQYWY65E.js");
608
607
  const figmaClient = new FigmaClient({
609
608
  accessToken: figmaToken
610
609
  });
@@ -695,7 +694,7 @@ function fragmentsPlugin(options) {
695
694
  );
696
695
  return;
697
696
  }
698
- const { FigmaClient } = await import("./service-A5GIGGGK.js");
697
+ const { FigmaClient } = await import("./service-TQYWY65E.js");
699
698
  const figmaClient = new FigmaClient({ accessToken: figmaToken });
700
699
  const { fileKey, nodeId } = figmaClient.parseUrl(figmaUrl);
701
700
  const figmaDesignProps = await figmaClient.getNodeProperties(
@@ -736,7 +735,7 @@ function fragmentsPlugin(options) {
736
735
  }));
737
736
  return;
738
737
  }
739
- const { getSharedTokenRegistry } = await import("./service-A5GIGGGK.js");
738
+ const { getSharedTokenRegistry } = await import("./service-TQYWY65E.js");
740
739
  const registry = getSharedTokenRegistry();
741
740
  if (!registry.isInitialized()) {
742
741
  await registry.initialize(config.tokens, projectRoot);
@@ -796,7 +795,7 @@ function fragmentsPlugin(options) {
796
795
  }));
797
796
  return;
798
797
  }
799
- const { getSharedTokenRegistry } = await import("./service-A5GIGGGK.js");
798
+ const { getSharedTokenRegistry } = await import("./service-TQYWY65E.js");
800
799
  const registry = getSharedTokenRegistry();
801
800
  if (!registry.isInitialized()) {
802
801
  await registry.initialize(config.tokens, projectRoot);
@@ -858,7 +857,7 @@ function fragmentsPlugin(options) {
858
857
  res.end(JSON.stringify({ error: "Could not resolve fragment file path" }));
859
858
  return;
860
859
  }
861
- const { getSharedTokenRegistry } = await import("./service-A5GIGGGK.js");
860
+ const { getSharedTokenRegistry } = await import("./service-TQYWY65E.js");
862
861
  const registry = getSharedTokenRegistry();
863
862
  if (!registry.isInitialized()) {
864
863
  await registry.initialize(config.tokens, projectRoot);
@@ -1036,7 +1035,7 @@ function fragmentsPlugin(options) {
1036
1035
  }
1037
1036
  if (!config.tokens || !config.tokens.include || config.tokens.include.length === 0) {
1038
1037
  try {
1039
- const { discoverTokenFiles } = await import("./discovery-Z4RDDFVR.js");
1038
+ const { discoverTokenFiles } = await import("./discovery-NEOY4MPN.js");
1040
1039
  const discovered = await discoverTokenFiles(projectRoot);
1041
1040
  if (discovered.length > 0) {
1042
1041
  config.tokens = {
@@ -1073,7 +1072,7 @@ function fragmentsPlugin(options) {
1073
1072
  const {
1074
1073
  getSharedTokenRegistry,
1075
1074
  generateTokenPatches
1076
- } = await import("./service-A5GIGGGK.js");
1075
+ } = await import("./service-TQYWY65E.js");
1077
1076
  const registry = getSharedTokenRegistry();
1078
1077
  if (!registry.isInitialized()) {
1079
1078
  await registry.initialize(config.tokens, projectRoot);
@@ -1370,7 +1369,7 @@ function fragmentsPlugin(options) {
1370
1369
  // Load virtual modules
1371
1370
  load(id) {
1372
1371
  if (id === VIRTUAL_FRAGMENTS_RESOLVED) {
1373
- return generateFragmentsModule(fragmentFiles, config, previewConfigPath);
1372
+ return generateFragmentsModule(fragmentFiles, config, previewConfigPath, projectRoot);
1374
1373
  }
1375
1374
  if (id === VIRTUAL_VIEWER_ENTRY_RESOLVED) {
1376
1375
  return generateViewerEntry();
@@ -1455,6 +1454,14 @@ function extractComponentName(filePath) {
1455
1454
  const match = filePath.match(/([^/\\]+)\.(fragment|stories)\.(tsx?|jsx?)$/);
1456
1455
  return match ? match[1] : filePath.split("/").pop() || filePath;
1457
1456
  }
1457
+ async function readProjectPackageName(root) {
1458
+ try {
1459
+ const pkgJson = JSON.parse(await readFile(resolve(root, "package.json"), "utf-8"));
1460
+ return pkgJson.name || null;
1461
+ } catch {
1462
+ return null;
1463
+ }
1464
+ }
1458
1465
  async function extractDependenciesFromSource(absolutePath) {
1459
1466
  try {
1460
1467
  const source = await readFile(absolutePath, "utf-8");
@@ -1471,7 +1478,7 @@ async function extractDependenciesFromSource(absolutePath) {
1471
1478
  return [];
1472
1479
  }
1473
1480
  }
1474
- async function generateFragmentsModule(fragmentFiles, config, previewConfigPath) {
1481
+ async function generateFragmentsModule(fragmentFiles, config, previewConfigPath, projectRoot) {
1475
1482
  const authoredVariantCodeCache = /* @__PURE__ */ new Map();
1476
1483
  async function loadAuthoredVariantCode(fragmentFilePath) {
1477
1484
  if (authoredVariantCodeCache.has(fragmentFilePath)) {
@@ -1494,6 +1501,9 @@ async function generateFragmentsModule(fragmentFiles, config, previewConfigPath)
1494
1501
  return {};
1495
1502
  }
1496
1503
  }
1504
+ const storyOnlyFiles = fragmentFiles.filter((f) => isStoryFile(f.relativePath));
1505
+ const { detectSubComponentPaths: _detectSubs } = await import("./core/index.js");
1506
+ const subComponentMap = _detectSubs(storyOnlyFiles);
1497
1507
  const filesByBasePath = /* @__PURE__ */ new Map();
1498
1508
  for (const file of fragmentFiles) {
1499
1509
  const basePath = getBaseComponentPath(file.relativePath);
@@ -1517,11 +1527,14 @@ async function generateFragmentsModule(fragmentFiles, config, previewConfigPath)
1517
1527
  const componentName = extractComponentName(primaryFile.relativePath);
1518
1528
  const fragmentSource = files.fragmentFile || primaryFile;
1519
1529
  const dependencies = await extractDependenciesFromSource(fragmentSource.absolutePath);
1530
+ const parentComponent = isStory ? subComponentMap.get(primaryFile.relativePath) : void 0;
1520
1531
  return ` {
1521
1532
  path: "${primaryFile.relativePath}",
1522
1533
  isStory: ${isStory},
1523
1534
  componentName: ${JSON.stringify(componentName)},
1524
1535
  dependencies: ${JSON.stringify(dependencies)},
1536
+ isSubComponent: ${!!parentComponent},
1537
+ parentComponent: ${parentComponent ? JSON.stringify(parentComponent) : "null"},
1525
1538
  loader: () => import("${primaryFile.absolutePath}"),
1526
1539
  metadataLoader: ${metadataPath ? `() => import("${metadataPath}")` : "null"},
1527
1540
  authoredVariantCode: ${JSON.stringify(authoredVariantCode)}
@@ -1541,10 +1554,14 @@ setPreviewConfig({
1541
1554
  loaders: previewConfig.loaders,
1542
1555
  });
1543
1556
  ` : "";
1557
+ const storybookFilterConfig = JSON.stringify(config.storybook ?? {});
1544
1558
  return `
1545
- import { storyModuleToFragment, setPreviewConfig } from "@fragments-sdk/cli/core";
1559
+ import { storyModuleToFragment, setPreviewConfig, checkStoryExclusion, isForceIncluded, isConfigExcluded } from "@fragments-sdk/cli/core";
1546
1560
  ${previewImport}
1547
1561
  ${previewSetup}
1562
+ // Storybook filter config (deep-merged with defaults at build time)
1563
+ const storybookFilterConfig = ${storybookFilterConfig};
1564
+
1548
1565
  // Lazy fragment loaders (supports both .fragment.tsx and .stories.tsx)
1549
1566
  const fragmentLoaders = [
1550
1567
  ${loaders}
@@ -1607,8 +1624,24 @@ function mergeAuthoredVariantCode(fragment, authoredVariantCode) {
1607
1624
  return fragment;
1608
1625
  }
1609
1626
 
1627
+ // Diagnostics: track exclusions for FRAGMENTS_DEBUG
1628
+ const exclusionLog = [];
1629
+
1630
+ /**
1631
+ * Try to load a paired .fragment.tsx file as fallback when a story is excluded.
1632
+ * Returns the fragment if available, null otherwise.
1633
+ */
1634
+ async function tryFallbackFragment(loader) {
1635
+ if (!loader.metadataLoader) return null;
1636
+ try {
1637
+ const mod = await loader.metadataLoader();
1638
+ return mod?.default ? { path: loader.path, fragment: mod.default } : null;
1639
+ } catch { return null; }
1640
+ }
1641
+
1610
1642
  // Load all fragments (for initial render)
1611
1643
  // Gracefully handles individual failures - one bad story won't break all fragments
1644
+ // Applies smart filtering for Storybook stories (SVG icons, deprecated, test stories, sub-components)
1612
1645
  export async function loadAllFragments() {
1613
1646
  const results = await Promise.all(
1614
1647
  fragmentLoaders.map(async (loader) => {
@@ -1618,6 +1651,30 @@ export async function loadAllFragments() {
1618
1651
  return cached ? { path: loader.path, fragment: cached } : null;
1619
1652
  }
1620
1653
 
1654
+ // --- Pre-load filtering (config-level and sub-component checks) ---
1655
+ if (loader.isStory) {
1656
+ // Force-include bypasses all filters
1657
+ if (!isForceIncluded(loader.componentName, storybookFilterConfig)) {
1658
+ // Config explicit exclude
1659
+ if (isConfigExcluded(loader.componentName, storybookFilterConfig)) {
1660
+ exclusionLog.push({ component: loader.componentName, reason: 'config-excluded', detail: 'Matches storybook.exclude pattern', path: loader.path });
1661
+ const fallback = await tryFallbackFragment(loader);
1662
+ if (fallback) return fallback;
1663
+ loadedFragments.set(loader.path, null);
1664
+ return null;
1665
+ }
1666
+
1667
+ // Sub-component check (directory-based, computed at build time)
1668
+ if (loader.isSubComponent && storybookFilterConfig.excludeSubComponents !== false) {
1669
+ exclusionLog.push({ component: loader.componentName, reason: 'sub-component', detail: 'Sub-component of ' + loader.parentComponent, path: loader.path });
1670
+ const fallback = await tryFallbackFragment(loader);
1671
+ if (fallback) return fallback;
1672
+ loadedFragments.set(loader.path, null);
1673
+ return null;
1674
+ }
1675
+ }
1676
+ }
1677
+
1621
1678
  const module = await loader.loader();
1622
1679
 
1623
1680
  // Convert story modules to fragments at runtime
@@ -1629,6 +1686,29 @@ export async function loadAllFragments() {
1629
1686
  loadedFragments.set(loader.path, null);
1630
1687
  return null;
1631
1688
  }
1689
+
1690
+ // --- Post-load filtering (needs loaded module data) ---
1691
+ if (!isForceIncluded(loader.componentName, storybookFilterConfig)) {
1692
+ const meta = module.default || {};
1693
+ const exclusion = checkStoryExclusion({
1694
+ storybookTitle: meta.title,
1695
+ componentName: fragment.meta?.name || loader.componentName,
1696
+ componentDisplayName: meta.component?.displayName,
1697
+ componentFunctionName: meta.component?.name,
1698
+ tags: meta.tags,
1699
+ variantCount: fragment.variants?.length || 0,
1700
+ filePath: loader.path,
1701
+ config: storybookFilterConfig,
1702
+ });
1703
+
1704
+ if (exclusion.excluded) {
1705
+ exclusionLog.push({ component: fragment.meta?.name || loader.componentName, reason: exclusion.reason, detail: exclusion.detail, path: loader.path });
1706
+ const fallback = await tryFallbackFragment(loader);
1707
+ if (fallback) return fallback;
1708
+ loadedFragments.set(loader.path, null);
1709
+ return null;
1710
+ }
1711
+ }
1632
1712
  } else {
1633
1713
  fragment = module.default;
1634
1714
  }
@@ -1670,6 +1750,15 @@ export async function loadAllFragments() {
1670
1750
  }
1671
1751
  })
1672
1752
  );
1753
+
1754
+ // Log exclusions in debug mode
1755
+ if (exclusionLog.length > 0) {
1756
+ console.log("[Fragments] Filtered " + exclusionLog.length + " component(s)");
1757
+ if (typeof process !== 'undefined' && process.env?.FRAGMENTS_DEBUG) {
1758
+ console.table(exclusionLog);
1759
+ }
1760
+ }
1761
+
1673
1762
  // Filter out nulls (fragments that had no component)
1674
1763
  return results.filter(r => r !== null);
1675
1764
  }
@@ -1718,9 +1807,12 @@ export async function loadFragment(path) {
1718
1807
  let fragments = [];
1719
1808
  const fragmentsPromise = loadAllFragments().then(s => { fragments = s; return s; });
1720
1809
 
1721
- export { fragments, fragmentsPromise };
1810
+ export { fragments, fragmentsPromise, exclusionLog };
1722
1811
  export const config = ${JSON.stringify(config)};
1723
1812
 
1813
+ // Auto-detect consumer package name from package.json
1814
+ export const projectPackageName = ${JSON.stringify(await readProjectPackageName(projectRoot))};
1815
+
1724
1816
  // HMR support
1725
1817
  if (import.meta.hot) {
1726
1818
  import.meta.hot.accept();
@@ -2088,7 +2180,7 @@ async function loadFullFragmentForCompare(_server, _fragmentFiles, componentName
2088
2180
  }
2089
2181
  }
2090
2182
  async function compareImages(image1Base64, image2Base64, threshold) {
2091
- const { DiffEngine, base64UrlToBuffer, bufferToBase64Url } = await import("./service-A5GIGGGK.js");
2183
+ const { DiffEngine, base64UrlToBuffer, bufferToBase64Url } = await import("./service-TQYWY65E.js");
2092
2184
  const { PNG } = await import("pngjs");
2093
2185
  const buffer1 = base64UrlToBuffer(image1Base64);
2094
2186
  const buffer2 = base64UrlToBuffer(image2Base64);
@@ -2308,6 +2400,100 @@ export function useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServ
2308
2400
  }
2309
2401
  };
2310
2402
  }
2403
+ function optionalPeerDepsPlugin(uiLibRoot) {
2404
+ const optionalDeps = [
2405
+ "@tanstack/react-table",
2406
+ "shiki",
2407
+ "recharts",
2408
+ "react-day-picker",
2409
+ "date-fns",
2410
+ "react-colorful",
2411
+ "react-markdown",
2412
+ "remark-gfm",
2413
+ "@tiptap/react",
2414
+ "@tiptap/starter-kit",
2415
+ "@tiptap/extension-link"
2416
+ ];
2417
+ let resolvedUiRoot;
2418
+ try {
2419
+ resolvedUiRoot = realpathSync(uiLibRoot);
2420
+ } catch {
2421
+ resolvedUiRoot = uiLibRoot;
2422
+ }
2423
+ const availableDeps = /* @__PURE__ */ new Set();
2424
+ for (const dep of optionalDeps) {
2425
+ const depPath = join(uiLibRoot, "..", "node_modules", ...dep.split("/"));
2426
+ if (existsSync(depPath)) availableDeps.add(dep);
2427
+ }
2428
+ return {
2429
+ name: "fragments:optional-peer-deps",
2430
+ enforce: "pre",
2431
+ transform(code, id) {
2432
+ let resolvedId;
2433
+ try {
2434
+ resolvedId = realpathSync(id);
2435
+ } catch {
2436
+ resolvedId = id;
2437
+ }
2438
+ if (!resolvedId.startsWith(resolvedUiRoot)) return;
2439
+ if (!id.endsWith(".tsx") && !id.endsWith(".ts")) return;
2440
+ if (!code.includes("require(")) return;
2441
+ let transformed = code;
2442
+ const imports = [];
2443
+ let counter = 0;
2444
+ for (const dep of availableDeps) {
2445
+ const escapedDep = dep.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2446
+ const regex = new RegExp(`require\\(['"]${escapedDep}['"]\\)`, "g");
2447
+ if (regex.test(code)) {
2448
+ const varName = `__fui_dep_${counter++}`;
2449
+ imports.push(`import * as ${varName} from '${dep}';`);
2450
+ regex.lastIndex = 0;
2451
+ transformed = transformed.replace(regex, varName);
2452
+ }
2453
+ }
2454
+ if (imports.length > 0) {
2455
+ transformed = imports.join("\n") + "\n" + transformed;
2456
+ return { code: transformed, map: null };
2457
+ }
2458
+ }
2459
+ };
2460
+ }
2461
+ async function detectTsconfigPaths(projectRoot) {
2462
+ const aliases = {};
2463
+ const tsconfigPath = join(projectRoot, "tsconfig.json");
2464
+ if (!existsSync(tsconfigPath)) return aliases;
2465
+ try {
2466
+ const content = await readFile2(tsconfigPath, "utf-8");
2467
+ const cleaned = content.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
2468
+ const tsconfig = JSON.parse(cleaned);
2469
+ const paths = tsconfig?.compilerOptions?.paths;
2470
+ const baseUrl = tsconfig?.compilerOptions?.baseUrl || ".";
2471
+ if (paths) {
2472
+ for (const [alias, targets] of Object.entries(paths)) {
2473
+ const target = targets[0];
2474
+ if (target) {
2475
+ const cleanAlias = alias.replace("/*", "");
2476
+ const cleanTarget = target.replace("/*", "");
2477
+ aliases[cleanAlias] = resolve2(projectRoot, baseUrl, cleanTarget);
2478
+ }
2479
+ }
2480
+ }
2481
+ } catch {
2482
+ }
2483
+ return aliases;
2484
+ }
2485
+ async function detectStorybookAliases(projectRoot) {
2486
+ const aliases = {};
2487
+ const assetsDir = resolve2(projectRoot, "assets");
2488
+ const fontsDir = resolve2(projectRoot, "assets/fonts");
2489
+ if (existsSync(fontsDir)) {
2490
+ aliases["/fonts"] = fontsDir;
2491
+ }
2492
+ if (existsSync(assetsDir)) {
2493
+ aliases["/assets"] = assetsDir;
2494
+ }
2495
+ return aliases;
2496
+ }
2311
2497
  async function createDevServer(options = {}) {
2312
2498
  const startTime = performance.now();
2313
2499
  const {
@@ -2349,6 +2535,16 @@ async function createDevServer(options = {}) {
2349
2535
  const isWebMCPSource = existsSync(join(webmcpLibRoot, "react/index.ts"));
2350
2536
  const isContextSource = existsSync(join(contextLibRoot, "types/index.ts"));
2351
2537
  console.log(`\u{1F4C1} Using node_modules: ${nodeModulesPath}`);
2538
+ const tsconfigAliases = await detectTsconfigPaths(projectRoot);
2539
+ const storybookAliases = await detectStorybookAliases(projectRoot);
2540
+ const storybookDir = resolve2(projectRoot, ".storybook");
2541
+ const hasStorybookDir = existsSync(storybookDir);
2542
+ if (Object.keys(tsconfigAliases).length > 0) {
2543
+ console.log(`\u{1F4CE} Detected ${Object.keys(tsconfigAliases).length} tsconfig path alias(es)`);
2544
+ }
2545
+ if (hasStorybookDir) {
2546
+ console.log(`\u{1F4D8} Detected .storybook directory`);
2547
+ }
2352
2548
  const installedPkgRoots = [...new Set(
2353
2549
  installedFiles.map((f) => {
2354
2550
  const idx = f.absolutePath.indexOf("/node_modules/");
@@ -2370,8 +2566,19 @@ async function createDevServer(options = {}) {
2370
2566
  port,
2371
2567
  open: open ? "/fragments/" : false,
2372
2568
  fs: {
2373
- // Allow serving files from viewer package, project, shared libs, and node_modules root
2374
- allow: [viewerRoot, uiLibRoot, sharedLibRoot, webmcpLibRoot, contextLibRoot, projectRoot, configDir, dirname2(nodeModulesPath), ...installedPkgRoots]
2569
+ // Allow serving files from viewer package, project, shared libs, node_modules root, and .storybook
2570
+ allow: [
2571
+ viewerRoot,
2572
+ uiLibRoot,
2573
+ sharedLibRoot,
2574
+ webmcpLibRoot,
2575
+ contextLibRoot,
2576
+ projectRoot,
2577
+ configDir,
2578
+ dirname2(nodeModulesPath),
2579
+ ...hasStorybookDir ? [storybookDir] : [],
2580
+ ...installedPkgRoots
2581
+ ]
2375
2582
  }
2376
2583
  },
2377
2584
  plugins: [
@@ -2379,6 +2586,8 @@ async function createDevServer(options = {}) {
2379
2586
  ...hasReactPlugin(projectViteConfig) ? [] : [react()],
2380
2587
  // CJS interop for packages imported from within node_modules
2381
2588
  cjsInteropPlugin(nodeModulesPath),
2589
+ // Rewrite require() → ESM import for optional peer deps (e.g., @tanstack/react-table)
2590
+ optionalPeerDepsPlugin(uiLibRoot),
2382
2591
  // Fragments plugins (array including SVGR)
2383
2592
  ...fragmentsPlugin({
2384
2593
  fragmentFiles: allFragmentFiles,
@@ -2391,6 +2600,15 @@ async function createDevServer(options = {}) {
2391
2600
  css: {
2392
2601
  modules: {
2393
2602
  localsConvention: "camelCase"
2603
+ },
2604
+ preprocessorOptions: {
2605
+ scss: {
2606
+ api: "modern-compiler",
2607
+ loadPaths: [
2608
+ resolve2(projectRoot, "src"),
2609
+ resolve2(projectRoot, "src/styles")
2610
+ ]
2611
+ }
2394
2612
  }
2395
2613
  },
2396
2614
  optimizeDeps: {
@@ -2402,6 +2620,10 @@ async function createDevServer(options = {}) {
2402
2620
  // Dedupe ensures all imports of these packages resolve to the same copy
2403
2621
  dedupe: ["react", "react-dom"],
2404
2622
  alias: {
2623
+ // Project-specific aliases (tsconfig paths, Storybook static dirs)
2624
+ // Listed first — Fragments-specific aliases below take precedence
2625
+ ...tsconfigAliases,
2626
+ ...storybookAliases,
2405
2627
  // Resolve @fragments-sdk/ui to local source or installed package
2406
2628
  "@fragments-sdk/ui": uiLibRoot,
2407
2629
  // Resolve @fragments-sdk/shared to monorepo source or vendored fallback
@@ -2483,4 +2705,4 @@ export {
2483
2705
  createDevServer,
2484
2706
  fragmentsPlugin
2485
2707
  };
2486
- //# sourceMappingURL=viewer-SBTJDMP7.js.map
2708
+ //# sourceMappingURL=viewer-DBEPYM3G.js.map