@fragments-sdk/cli 0.2.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 (259) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/dist/bin.d.ts +1 -0
  4. package/dist/bin.js +4783 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/chunk-4FDQSGKX.js +786 -0
  7. package/dist/chunk-4FDQSGKX.js.map +1 -0
  8. package/dist/chunk-7H2MMGYG.js +369 -0
  9. package/dist/chunk-7H2MMGYG.js.map +1 -0
  10. package/dist/chunk-BSCG3IP7.js +619 -0
  11. package/dist/chunk-BSCG3IP7.js.map +1 -0
  12. package/dist/chunk-LY2CFFPY.js +898 -0
  13. package/dist/chunk-LY2CFFPY.js.map +1 -0
  14. package/dist/chunk-MUZ6CM66.js +6636 -0
  15. package/dist/chunk-MUZ6CM66.js.map +1 -0
  16. package/dist/chunk-OAENNG3G.js +1489 -0
  17. package/dist/chunk-OAENNG3G.js.map +1 -0
  18. package/dist/chunk-XHNKNI6J.js +235 -0
  19. package/dist/chunk-XHNKNI6J.js.map +1 -0
  20. package/dist/core-DWKLGY4N.js +68 -0
  21. package/dist/core-DWKLGY4N.js.map +1 -0
  22. package/dist/generate-4LQNJ7SX.js +249 -0
  23. package/dist/generate-4LQNJ7SX.js.map +1 -0
  24. package/dist/index.d.ts +775 -0
  25. package/dist/index.js +41 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/init-EMVI47QG.js +416 -0
  28. package/dist/init-EMVI47QG.js.map +1 -0
  29. package/dist/mcp-bin.d.ts +1 -0
  30. package/dist/mcp-bin.js +1117 -0
  31. package/dist/mcp-bin.js.map +1 -0
  32. package/dist/scan-4YPRF7FV.js +12 -0
  33. package/dist/scan-4YPRF7FV.js.map +1 -0
  34. package/dist/service-QSZMZJBJ.js +208 -0
  35. package/dist/service-QSZMZJBJ.js.map +1 -0
  36. package/dist/static-viewer-MIPGZ4Z7.js +12 -0
  37. package/dist/static-viewer-MIPGZ4Z7.js.map +1 -0
  38. package/dist/test-SQ5ZHXWU.js +1067 -0
  39. package/dist/test-SQ5ZHXWU.js.map +1 -0
  40. package/dist/tokens-HSGMYK64.js +173 -0
  41. package/dist/tokens-HSGMYK64.js.map +1 -0
  42. package/dist/viewer-YRF4SQE4.js +11101 -0
  43. package/dist/viewer-YRF4SQE4.js.map +1 -0
  44. package/package.json +107 -0
  45. package/src/ai.ts +266 -0
  46. package/src/analyze.ts +265 -0
  47. package/src/bin.ts +916 -0
  48. package/src/build.ts +248 -0
  49. package/src/commands/a11y.ts +302 -0
  50. package/src/commands/add.ts +313 -0
  51. package/src/commands/audit.ts +195 -0
  52. package/src/commands/baseline.ts +221 -0
  53. package/src/commands/build.ts +144 -0
  54. package/src/commands/compare.ts +337 -0
  55. package/src/commands/context.ts +107 -0
  56. package/src/commands/dev.ts +107 -0
  57. package/src/commands/enhance.ts +858 -0
  58. package/src/commands/generate.ts +391 -0
  59. package/src/commands/init.ts +531 -0
  60. package/src/commands/link/figma.ts +645 -0
  61. package/src/commands/link/index.ts +10 -0
  62. package/src/commands/link/storybook.ts +267 -0
  63. package/src/commands/list.ts +49 -0
  64. package/src/commands/metrics.ts +114 -0
  65. package/src/commands/reset.ts +242 -0
  66. package/src/commands/scan.ts +537 -0
  67. package/src/commands/storygen.ts +207 -0
  68. package/src/commands/tokens.ts +251 -0
  69. package/src/commands/validate.ts +93 -0
  70. package/src/commands/verify.ts +215 -0
  71. package/src/core/composition.test.ts +262 -0
  72. package/src/core/composition.ts +255 -0
  73. package/src/core/config.ts +84 -0
  74. package/src/core/constants.ts +111 -0
  75. package/src/core/context.ts +380 -0
  76. package/src/core/defineSegment.ts +137 -0
  77. package/src/core/discovery.ts +337 -0
  78. package/src/core/figma.ts +263 -0
  79. package/src/core/fragment-types.ts +214 -0
  80. package/src/core/generators/context.ts +389 -0
  81. package/src/core/generators/index.ts +23 -0
  82. package/src/core/generators/registry.ts +364 -0
  83. package/src/core/generators/typescript-extractor.ts +374 -0
  84. package/src/core/importAnalyzer.ts +217 -0
  85. package/src/core/index.ts +149 -0
  86. package/src/core/loader.ts +155 -0
  87. package/src/core/node.ts +63 -0
  88. package/src/core/parser.ts +551 -0
  89. package/src/core/previewLoader.ts +172 -0
  90. package/src/core/schema/fragment.schema.json +189 -0
  91. package/src/core/schema/registry.schema.json +137 -0
  92. package/src/core/schema.ts +182 -0
  93. package/src/core/storyAdapter.test.ts +571 -0
  94. package/src/core/storyAdapter.ts +761 -0
  95. package/src/core/token-types.ts +287 -0
  96. package/src/core/types.ts +754 -0
  97. package/src/diff.ts +323 -0
  98. package/src/index.ts +43 -0
  99. package/src/mcp/__tests__/projectFields.test.ts +130 -0
  100. package/src/mcp/bin.ts +36 -0
  101. package/src/mcp/index.ts +8 -0
  102. package/src/mcp/server.ts +1310 -0
  103. package/src/mcp/utils.ts +54 -0
  104. package/src/mcp-bin.ts +36 -0
  105. package/src/migrate/__tests__/argTypes/argTypes.test.ts +189 -0
  106. package/src/migrate/__tests__/args/args.test.ts +452 -0
  107. package/src/migrate/__tests__/meta/meta.test.ts +198 -0
  108. package/src/migrate/__tests__/stories/stories.test.ts +278 -0
  109. package/src/migrate/__tests__/utils/utils.test.ts +371 -0
  110. package/src/migrate/__tests__/values/values.test.ts +303 -0
  111. package/src/migrate/bin.ts +108 -0
  112. package/src/migrate/converter.ts +658 -0
  113. package/src/migrate/detect.ts +196 -0
  114. package/src/migrate/index.ts +45 -0
  115. package/src/migrate/migrate.ts +163 -0
  116. package/src/migrate/parser.ts +1136 -0
  117. package/src/migrate/report.ts +624 -0
  118. package/src/migrate/types.ts +169 -0
  119. package/src/screenshot.ts +249 -0
  120. package/src/service/__tests__/ast-utils.test.ts +426 -0
  121. package/src/service/__tests__/enhance-scanner.test.ts +200 -0
  122. package/src/service/__tests__/figma/figma.test.ts +652 -0
  123. package/src/service/__tests__/metrics-store.test.ts +409 -0
  124. package/src/service/__tests__/patch-generator.test.ts +186 -0
  125. package/src/service/__tests__/props-extractor.test.ts +365 -0
  126. package/src/service/__tests__/token-registry.test.ts +267 -0
  127. package/src/service/analytics.ts +659 -0
  128. package/src/service/ast-utils.ts +444 -0
  129. package/src/service/browser-pool.ts +339 -0
  130. package/src/service/capture.ts +267 -0
  131. package/src/service/diff.ts +279 -0
  132. package/src/service/enhance/aggregator.ts +489 -0
  133. package/src/service/enhance/cache.ts +275 -0
  134. package/src/service/enhance/codebase-scanner.ts +357 -0
  135. package/src/service/enhance/context-generator.ts +529 -0
  136. package/src/service/enhance/doc-extractor.ts +523 -0
  137. package/src/service/enhance/index.ts +131 -0
  138. package/src/service/enhance/props-extractor.ts +665 -0
  139. package/src/service/enhance/scanner.ts +445 -0
  140. package/src/service/enhance/storybook-parser.ts +552 -0
  141. package/src/service/enhance/types.ts +346 -0
  142. package/src/service/enhance/variant-renderer.ts +479 -0
  143. package/src/service/figma.ts +1008 -0
  144. package/src/service/index.ts +249 -0
  145. package/src/service/metrics-store.ts +333 -0
  146. package/src/service/patch-generator.ts +349 -0
  147. package/src/service/report.ts +854 -0
  148. package/src/service/storage.ts +401 -0
  149. package/src/service/token-fixes.ts +281 -0
  150. package/src/service/token-parser.ts +504 -0
  151. package/src/service/token-registry.ts +721 -0
  152. package/src/service/utils.ts +172 -0
  153. package/src/setup.ts +241 -0
  154. package/src/shared/command-wrapper.ts +81 -0
  155. package/src/shared/dev-server-client.ts +199 -0
  156. package/src/shared/index.ts +8 -0
  157. package/src/shared/segment-loader.ts +59 -0
  158. package/src/shared/types.ts +147 -0
  159. package/src/static-viewer.ts +715 -0
  160. package/src/test/discovery.ts +172 -0
  161. package/src/test/index.ts +281 -0
  162. package/src/test/reporters/console.ts +194 -0
  163. package/src/test/reporters/json.ts +190 -0
  164. package/src/test/reporters/junit.ts +186 -0
  165. package/src/test/runner.ts +598 -0
  166. package/src/test/types.ts +245 -0
  167. package/src/test/watch.ts +200 -0
  168. package/src/validators.ts +152 -0
  169. package/src/viewer/__tests__/jsx-parser.test.ts +502 -0
  170. package/src/viewer/__tests__/render-utils.test.ts +232 -0
  171. package/src/viewer/__tests__/style-utils.test.ts +404 -0
  172. package/src/viewer/bin.ts +86 -0
  173. package/src/viewer/cli/health.ts +256 -0
  174. package/src/viewer/cli/index.ts +33 -0
  175. package/src/viewer/cli/scan.ts +124 -0
  176. package/src/viewer/cli/utils.ts +174 -0
  177. package/src/viewer/components/AccessibilityPanel.tsx +1404 -0
  178. package/src/viewer/components/ActionCapture.tsx +172 -0
  179. package/src/viewer/components/ActionsPanel.tsx +371 -0
  180. package/src/viewer/components/App.tsx +638 -0
  181. package/src/viewer/components/BottomPanel.tsx +224 -0
  182. package/src/viewer/components/CodePanel.tsx +589 -0
  183. package/src/viewer/components/CommandPalette.tsx +336 -0
  184. package/src/viewer/components/ComponentGraph.tsx +394 -0
  185. package/src/viewer/components/ComponentHeader.tsx +85 -0
  186. package/src/viewer/components/ContractPanel.tsx +234 -0
  187. package/src/viewer/components/ErrorBoundary.tsx +85 -0
  188. package/src/viewer/components/FigmaEmbed.tsx +231 -0
  189. package/src/viewer/components/FragmentEditor.tsx +485 -0
  190. package/src/viewer/components/HealthDashboard.tsx +452 -0
  191. package/src/viewer/components/HmrStatusIndicator.tsx +71 -0
  192. package/src/viewer/components/Icons.tsx +417 -0
  193. package/src/viewer/components/InteractionsPanel.tsx +720 -0
  194. package/src/viewer/components/IsolatedPreviewFrame.tsx +321 -0
  195. package/src/viewer/components/IsolatedRender.tsx +111 -0
  196. package/src/viewer/components/KeyboardShortcutsHelp.tsx +89 -0
  197. package/src/viewer/components/LandingPage.tsx +441 -0
  198. package/src/viewer/components/Layout.tsx +22 -0
  199. package/src/viewer/components/LeftSidebar.tsx +391 -0
  200. package/src/viewer/components/MultiViewportPreview.tsx +429 -0
  201. package/src/viewer/components/PreviewArea.tsx +404 -0
  202. package/src/viewer/components/PreviewFrameHost.tsx +310 -0
  203. package/src/viewer/components/PreviewPane.tsx +150 -0
  204. package/src/viewer/components/PreviewToolbar.tsx +176 -0
  205. package/src/viewer/components/PropsEditor.tsx +512 -0
  206. package/src/viewer/components/PropsTable.tsx +98 -0
  207. package/src/viewer/components/RelationsSection.tsx +57 -0
  208. package/src/viewer/components/ResizablePanel.tsx +328 -0
  209. package/src/viewer/components/RightSidebar.tsx +118 -0
  210. package/src/viewer/components/ScreenshotButton.tsx +90 -0
  211. package/src/viewer/components/Sidebar.tsx +169 -0
  212. package/src/viewer/components/SkeletonLoader.tsx +156 -0
  213. package/src/viewer/components/StoryRenderer.tsx +128 -0
  214. package/src/viewer/components/ThemeProvider.tsx +96 -0
  215. package/src/viewer/components/Toast.tsx +67 -0
  216. package/src/viewer/components/TokenStylePanel.tsx +708 -0
  217. package/src/viewer/components/UsageSection.tsx +95 -0
  218. package/src/viewer/components/VariantMatrix.tsx +350 -0
  219. package/src/viewer/components/VariantRenderer.tsx +131 -0
  220. package/src/viewer/components/VariantTabs.tsx +84 -0
  221. package/src/viewer/components/ViewportSelector.tsx +165 -0
  222. package/src/viewer/components/_future/CreatePage.tsx +836 -0
  223. package/src/viewer/composition-renderer.ts +381 -0
  224. package/src/viewer/constants/index.ts +1 -0
  225. package/src/viewer/constants/ui.ts +185 -0
  226. package/src/viewer/entry.tsx +299 -0
  227. package/src/viewer/hooks/index.ts +2 -0
  228. package/src/viewer/hooks/useA11yCache.ts +383 -0
  229. package/src/viewer/hooks/useA11yService.ts +498 -0
  230. package/src/viewer/hooks/useActions.ts +138 -0
  231. package/src/viewer/hooks/useAppState.ts +124 -0
  232. package/src/viewer/hooks/useFigmaIntegration.ts +132 -0
  233. package/src/viewer/hooks/useHmrStatus.ts +109 -0
  234. package/src/viewer/hooks/useKeyboardShortcuts.ts +222 -0
  235. package/src/viewer/hooks/usePreviewBridge.ts +347 -0
  236. package/src/viewer/hooks/useScrollSpy.ts +78 -0
  237. package/src/viewer/hooks/useUrlState.ts +330 -0
  238. package/src/viewer/hooks/useViewSettings.ts +125 -0
  239. package/src/viewer/index.html +28 -0
  240. package/src/viewer/index.ts +14 -0
  241. package/src/viewer/intelligence/healthReport.ts +505 -0
  242. package/src/viewer/intelligence/styleDrift.ts +340 -0
  243. package/src/viewer/intelligence/usageScanner.ts +309 -0
  244. package/src/viewer/jsx-parser.ts +485 -0
  245. package/src/viewer/postcss.config.js +6 -0
  246. package/src/viewer/preview-frame-entry.tsx +25 -0
  247. package/src/viewer/preview-frame.html +109 -0
  248. package/src/viewer/render-template.html +68 -0
  249. package/src/viewer/render-utils.ts +170 -0
  250. package/src/viewer/server.ts +276 -0
  251. package/src/viewer/style-utils.ts +414 -0
  252. package/src/viewer/styles/globals.css +355 -0
  253. package/src/viewer/tailwind.config.js +37 -0
  254. package/src/viewer/types/a11y.ts +197 -0
  255. package/src/viewer/utils/a11y-fixes.ts +471 -0
  256. package/src/viewer/utils/actionExport.ts +372 -0
  257. package/src/viewer/utils/colorSchemes.ts +201 -0
  258. package/src/viewer/utils/detectRelationships.ts +256 -0
  259. package/src/viewer/vite-plugin.ts +2143 -0
@@ -0,0 +1,898 @@
1
+ import { createRequire } from 'module'; const require = createRequire(import.meta.url);
2
+ import {
3
+ recipeDefinitionSchema,
4
+ segmentDefinitionSchema
5
+ } from "./chunk-XHNKNI6J.js";
6
+
7
+ // src/core/defineSegment.ts
8
+ function defineSegment(definition) {
9
+ if (process.env.NODE_ENV !== "production") {
10
+ const result = segmentDefinitionSchema.safeParse(definition);
11
+ if (!result.success) {
12
+ const errors = result.error.errors.map((e) => ` - ${e.path.join(".")}: ${e.message}`).join("\n");
13
+ throw new Error(
14
+ `Invalid segment definition for "${definition.meta?.name || "unknown"}":
15
+ ${errors}`
16
+ );
17
+ }
18
+ }
19
+ return definition;
20
+ }
21
+ var defineFragment = defineSegment;
22
+ function compileSegment(definition, filePath) {
23
+ return {
24
+ filePath,
25
+ meta: definition.meta,
26
+ usage: definition.usage,
27
+ props: definition.props,
28
+ relations: definition.relations,
29
+ variants: definition.variants.map((v) => ({
30
+ name: v.name,
31
+ description: v.description,
32
+ code: v.code,
33
+ figma: v.figma
34
+ })),
35
+ contract: definition.contract,
36
+ _generated: definition._generated
37
+ };
38
+ }
39
+ function defineRecipe(definition) {
40
+ if (process.env.NODE_ENV !== "production") {
41
+ const result = recipeDefinitionSchema.safeParse(definition);
42
+ if (!result.success) {
43
+ const errors = result.error.errors.map((e) => ` - ${e.path.join(".")}: ${e.message}`).join("\n");
44
+ throw new Error(
45
+ `Invalid recipe definition for "${definition.name || "unknown"}":
46
+ ${errors}`
47
+ );
48
+ }
49
+ }
50
+ return definition;
51
+ }
52
+ function compileRecipe(definition, filePath) {
53
+ return {
54
+ filePath,
55
+ name: definition.name,
56
+ description: definition.description,
57
+ category: definition.category,
58
+ components: definition.components,
59
+ code: definition.code,
60
+ tags: definition.tags
61
+ };
62
+ }
63
+
64
+ // src/core/storyAdapter.ts
65
+ import { createElement } from "react";
66
+ import { toId, storyNameFromExport, isExportStory } from "@storybook/csf";
67
+ var globalPreviewConfig = {};
68
+ function setPreviewConfig(config) {
69
+ globalPreviewConfig = config;
70
+ }
71
+ function getPreviewConfig() {
72
+ return globalPreviewConfig;
73
+ }
74
+ function storyModuleToSegment(storyModule, filePath) {
75
+ const meta = storyModule.default;
76
+ const component = meta.component;
77
+ if (!component) {
78
+ return null;
79
+ }
80
+ const componentName = extractComponentName(meta, filePath);
81
+ const category = extractCategory(meta.title);
82
+ const props = convertArgTypes(meta.argTypes ?? {}, globalPreviewConfig.argTypes);
83
+ const variants = extractVariants(storyModule, component, meta);
84
+ const figmaUrl = extractFigmaUrl(meta.parameters);
85
+ const segmentMeta = {
86
+ name: componentName,
87
+ description: meta.parameters?.docs?.description?.component ?? `${componentName} component`,
88
+ category,
89
+ tags: meta.tags?.filter((t) => t !== "autodocs"),
90
+ status: "stable",
91
+ figma: figmaUrl
92
+ };
93
+ const usage = {
94
+ when: [`Use ${componentName} for its intended purpose`],
95
+ whenNot: ["When a more specific component is available"]
96
+ };
97
+ return {
98
+ component,
99
+ meta: segmentMeta,
100
+ usage,
101
+ props,
102
+ variants
103
+ };
104
+ }
105
+ function extractComponentName(meta, filePath) {
106
+ if (meta.title) {
107
+ const parts = meta.title.split("/");
108
+ return parts[parts.length - 1];
109
+ }
110
+ if (meta.component?.displayName) {
111
+ return meta.component.displayName;
112
+ }
113
+ if (meta.component?.name && meta.component.name !== "Component") {
114
+ return meta.component.name;
115
+ }
116
+ const match = filePath.match(/([^/\\]+)\.stories\.(tsx?|jsx?)$/);
117
+ return match?.[1] ?? "Unknown";
118
+ }
119
+ function extractCategory(title) {
120
+ if (!title) return "general";
121
+ const parts = title.split("/");
122
+ if (parts.length >= 3) {
123
+ return parts[parts.length - 2].toLowerCase();
124
+ }
125
+ return "general";
126
+ }
127
+ function extractFigmaUrl(parameters) {
128
+ if (!parameters) return void 0;
129
+ const design = parameters.design;
130
+ if (design?.url && typeof design.url === "string") {
131
+ return design.url;
132
+ }
133
+ if (typeof parameters.figma === "string") {
134
+ return parameters.figma;
135
+ }
136
+ return void 0;
137
+ }
138
+ function convertArgTypes(argTypes, globalArgTypes) {
139
+ const props = {};
140
+ const mergedArgTypes = { ...globalArgTypes, ...argTypes };
141
+ for (const [name, argType] of Object.entries(mergedArgTypes)) {
142
+ if (argType.table?.disable) continue;
143
+ if (argType.control === false && argType.action) continue;
144
+ const { controlType, controlOptions } = extractControlInfo(argType);
145
+ props[name] = {
146
+ type: inferPropType(argType),
147
+ description: argType.description ?? `${name} prop`,
148
+ ...argType.options && { values: argType.options },
149
+ ...argType.table?.defaultValue && {
150
+ default: argType.table.defaultValue.summary
151
+ },
152
+ ...argType.defaultValue !== void 0 && {
153
+ default: argType.defaultValue
154
+ },
155
+ ...argType.type?.required && { required: true },
156
+ ...controlType && { controlType },
157
+ ...controlOptions && Object.keys(controlOptions).length > 0 && { controlOptions }
158
+ };
159
+ }
160
+ return props;
161
+ }
162
+ function extractControlInfo(argType) {
163
+ if (argType.control === void 0 || argType.control === false) {
164
+ return {};
165
+ }
166
+ const control = typeof argType.control === "string" ? { type: argType.control } : argType.control;
167
+ const validControlTypes = [
168
+ "text",
169
+ "number",
170
+ "range",
171
+ "boolean",
172
+ "select",
173
+ "multi-select",
174
+ "radio",
175
+ "inline-radio",
176
+ "check",
177
+ "inline-check",
178
+ "object",
179
+ "file",
180
+ "color",
181
+ "date"
182
+ ];
183
+ const controlType = validControlTypes.includes(control.type) ? control.type : void 0;
184
+ const controlOptions = {};
185
+ if (control.min !== void 0) controlOptions.min = control.min;
186
+ if (control.max !== void 0) controlOptions.max = control.max;
187
+ if (control.step !== void 0) controlOptions.step = control.step;
188
+ if (control.presetColors) controlOptions.presetColors = control.presetColors;
189
+ return {
190
+ controlType,
191
+ controlOptions: Object.keys(controlOptions).length > 0 ? controlOptions : void 0
192
+ };
193
+ }
194
+ function inferPropType(argType) {
195
+ if (argType.action) return "function";
196
+ if (argType.options?.length) return "enum";
197
+ if (argType.type?.name) {
198
+ const typeMap = {
199
+ string: "string",
200
+ number: "number",
201
+ boolean: "boolean",
202
+ object: "object",
203
+ array: "array",
204
+ function: "function"
205
+ };
206
+ const mapped = typeMap[argType.type.name];
207
+ if (mapped) return mapped;
208
+ }
209
+ const control = typeof argType.control === "string" ? argType.control : argType.control ? argType.control.type : void 0;
210
+ if (control) {
211
+ const controlMap = {
212
+ // Text controls
213
+ text: "string",
214
+ // Number controls
215
+ number: "number",
216
+ range: "number",
217
+ // Boolean controls
218
+ boolean: "boolean",
219
+ check: "boolean",
220
+ "inline-check": "boolean",
221
+ // Enum/selection controls
222
+ select: "enum",
223
+ "multi-select": "enum",
224
+ radio: "enum",
225
+ "inline-radio": "enum",
226
+ // Object controls
227
+ object: "object",
228
+ file: "object",
229
+ // Special string controls
230
+ color: "string",
231
+ date: "string"
232
+ };
233
+ const mapped = controlMap[control];
234
+ if (mapped) return mapped;
235
+ }
236
+ return "string";
237
+ }
238
+ function isStory(value) {
239
+ if (typeof value === "object" && value !== null) {
240
+ const obj = value;
241
+ if ("args" in obj || "render" in obj || "play" in obj) return true;
242
+ }
243
+ if (typeof value === "function") {
244
+ const fn = value;
245
+ if ("args" in fn) return true;
246
+ }
247
+ return false;
248
+ }
249
+ function extractVariants(storyModule, component, meta) {
250
+ const variants = [];
251
+ for (const [exportName, exportValue] of Object.entries(storyModule)) {
252
+ if (exportName === "default") continue;
253
+ if (!isExportStory(exportName, meta)) continue;
254
+ if (!isStory(exportValue)) continue;
255
+ const story = exportValue;
256
+ const storyName = typeof story === "object" && story.name || typeof story === "object" && story.storyName || typeof story === "function" && story.storyName || storyNameFromExport(exportName);
257
+ const storyId = toId(meta.title || "Unknown", exportName);
258
+ let description = `${storyName} variant`;
259
+ if (typeof story === "object" && story.parameters?.docs?.description?.story) {
260
+ description = story.parameters.docs.description.story;
261
+ }
262
+ const storyPlayFn = typeof story === "object" ? story.play : story.play;
263
+ const hasPlayFunction = !!storyPlayFn;
264
+ const wrappedPlay = storyPlayFn ? async (context) => {
265
+ const args = {
266
+ ...globalPreviewConfig.args,
267
+ ...meta.args,
268
+ ...typeof story === "function" ? story.args : story.args
269
+ };
270
+ const fullContext = buildStoryContext(meta, story, args, storyId, storyName);
271
+ const playContext = {
272
+ ...fullContext,
273
+ canvasElement: context.canvasElement,
274
+ args: context.args,
275
+ step: context.step
276
+ };
277
+ await storyPlayFn(playContext);
278
+ } : void 0;
279
+ const storyTags = typeof story === "object" ? story.tags : void 0;
280
+ const loaders = collectLoaders(meta, story);
281
+ const variantArgs = {
282
+ ...globalPreviewConfig.args,
283
+ ...meta.args,
284
+ ...typeof story === "function" ? story.args : story.args
285
+ };
286
+ const hasArgs = Object.keys(variantArgs).length > 0;
287
+ variants.push({
288
+ name: storyName,
289
+ description,
290
+ render: createRenderFunction(story, component, meta, storyId, storyName),
291
+ // Store Storybook-specific metadata
292
+ ...hasPlayFunction && { hasPlayFunction: true },
293
+ ...wrappedPlay && { play: wrappedPlay },
294
+ ...storyId && { storyId },
295
+ ...storyTags && { tags: storyTags },
296
+ ...loaders.length > 0 && { loaders },
297
+ ...hasArgs && { args: variantArgs }
298
+ });
299
+ }
300
+ return variants;
301
+ }
302
+ function collectLoaders(meta, story) {
303
+ const allLoaders = [
304
+ ...globalPreviewConfig.loaders ?? [],
305
+ ...meta.loaders ?? [],
306
+ ...typeof story === "function" ? story.loaders ?? [] : story.loaders ?? []
307
+ ];
308
+ if (allLoaders.length === 0) {
309
+ return [];
310
+ }
311
+ return allLoaders.map((loader) => {
312
+ return async () => {
313
+ const minimalContext = {
314
+ args: {},
315
+ argTypes: {},
316
+ globals: {},
317
+ parameters: {},
318
+ id: "",
319
+ kind: meta.title || "Unknown",
320
+ name: "",
321
+ story: "",
322
+ viewMode: "story",
323
+ loaded: {},
324
+ abortSignal: new AbortController().signal,
325
+ componentId: "",
326
+ title: meta.title || "Unknown"
327
+ };
328
+ return loader(minimalContext);
329
+ };
330
+ });
331
+ }
332
+ function buildStoryContext(meta, story, args, storyId, storyName, loadedData) {
333
+ const mergedArgs = {
334
+ ...globalPreviewConfig.args,
335
+ ...meta.args,
336
+ ...typeof story === "object" ? story.args : story.args,
337
+ ...args
338
+ };
339
+ const mergedArgTypes = {
340
+ ...globalPreviewConfig.argTypes,
341
+ ...meta.argTypes,
342
+ ...typeof story === "object" ? story.argTypes : story.argTypes
343
+ };
344
+ const mergedParameters = {
345
+ ...globalPreviewConfig.parameters,
346
+ ...meta.parameters,
347
+ ...typeof story === "object" ? story.parameters : story.parameters
348
+ };
349
+ return {
350
+ args: mergedArgs,
351
+ argTypes: mergedArgTypes ?? {},
352
+ globals: {},
353
+ parameters: mergedParameters ?? {},
354
+ id: storyId,
355
+ kind: meta.title || "Unknown",
356
+ name: storyName,
357
+ story: storyName,
358
+ viewMode: "story",
359
+ loaded: loadedData ?? {},
360
+ abortSignal: new AbortController().signal,
361
+ componentId: toId(meta.title || "Unknown", ""),
362
+ title: meta.title || "Unknown"
363
+ };
364
+ }
365
+ function createRenderFunction(story, component, meta, storyId, storyName) {
366
+ return (options) => {
367
+ const args = {
368
+ ...globalPreviewConfig.args,
369
+ ...meta.args,
370
+ ...typeof story === "function" ? story.args : story.args,
371
+ ...options?.args
372
+ // Runtime overrides from viewer props panel
373
+ };
374
+ const loadedData = options?.loadedData;
375
+ const context = buildStoryContext(meta, story, args, storyId, storyName, loadedData);
376
+ let renderFn;
377
+ if (typeof story === "function") {
378
+ renderFn = () => story(args);
379
+ } else if (story.render) {
380
+ renderFn = () => story.render.length >= 2 ? story.render(args, context) : story.render(args);
381
+ } else if (meta.render) {
382
+ renderFn = () => meta.render.length >= 2 ? meta.render(args, context) : meta.render(args);
383
+ } else {
384
+ renderFn = () => createElement(component, args);
385
+ }
386
+ const allDecorators = [
387
+ ...globalPreviewConfig.decorators ?? [],
388
+ ...meta.decorators ?? [],
389
+ ...typeof story === "function" ? story.decorators ?? [] : story.decorators ?? []
390
+ ].reverse();
391
+ if (allDecorators.length > 0) {
392
+ return applyDecorators(renderFn, allDecorators, context);
393
+ }
394
+ return renderFn();
395
+ };
396
+ }
397
+ function applyDecorators(renderFn, decorators, context) {
398
+ let storyFn = renderFn;
399
+ for (const decorator of decorators) {
400
+ const wrappedFn = storyFn;
401
+ storyFn = () => decorator(wrappedFn, context);
402
+ }
403
+ return storyFn();
404
+ }
405
+
406
+ // src/core/context.ts
407
+ var PLACEHOLDER_PATTERNS = [
408
+ /^\w+ component is needed$/i,
409
+ /^Alternative component is more appropriate$/i,
410
+ /^Use \w+ when you need/i
411
+ ];
412
+ function filterPlaceholders(items) {
413
+ return items.filter(
414
+ (item) => !PLACEHOLDER_PATTERNS.some((pattern) => pattern.test(item.trim()))
415
+ );
416
+ }
417
+ function generateContext(segments, options = {}, recipes) {
418
+ const format = options.format ?? "markdown";
419
+ const compact = options.compact ?? false;
420
+ const include = {
421
+ props: options.include?.props ?? true,
422
+ variants: options.include?.variants ?? true,
423
+ usage: options.include?.usage ?? true,
424
+ relations: options.include?.relations ?? false,
425
+ code: options.include?.code ?? false
426
+ };
427
+ const sorted = [...segments].sort((a, b) => {
428
+ const catCompare = a.meta.category.localeCompare(b.meta.category);
429
+ if (catCompare !== 0) return catCompare;
430
+ return a.meta.name.localeCompare(b.meta.name);
431
+ });
432
+ if (format === "json") {
433
+ return generateJsonContext(sorted, include, compact, recipes);
434
+ }
435
+ return generateMarkdownContext(sorted, include, compact, recipes);
436
+ }
437
+ function generateMarkdownContext(segments, include, compact, recipes) {
438
+ const lines = [];
439
+ lines.push("# Design System Reference");
440
+ lines.push("");
441
+ lines.push("## Quick Reference");
442
+ lines.push("");
443
+ lines.push("| Component | Category | Use For |");
444
+ lines.push("|-----------|----------|---------|");
445
+ for (const segment of segments) {
446
+ const filteredWhen = filterPlaceholders(segment.usage.when);
447
+ const useFor = filteredWhen.slice(0, 2).join(", ") || segment.meta.description;
448
+ lines.push(`| ${segment.meta.name} | ${segment.meta.category} | ${truncate(useFor, 50)} |`);
449
+ }
450
+ lines.push("");
451
+ if (compact) {
452
+ const content2 = lines.join("\n");
453
+ return {
454
+ content: content2,
455
+ tokenEstimate: estimateTokens(content2)
456
+ };
457
+ }
458
+ lines.push("## Components");
459
+ lines.push("");
460
+ for (const segment of segments) {
461
+ lines.push(`### ${segment.meta.name}`);
462
+ lines.push("");
463
+ const statusParts = [`**Category:** ${segment.meta.category}`];
464
+ if (segment.meta.status) {
465
+ statusParts.push(`**Status:** ${segment.meta.status}`);
466
+ }
467
+ lines.push(statusParts.join(" | "));
468
+ lines.push("");
469
+ if (segment.meta.description) {
470
+ lines.push(segment.meta.description);
471
+ lines.push("");
472
+ }
473
+ const whenFiltered = filterPlaceholders(segment.usage.when);
474
+ const whenNotFiltered = filterPlaceholders(segment.usage.whenNot);
475
+ if (include.usage && (whenFiltered.length > 0 || whenNotFiltered.length > 0)) {
476
+ if (whenFiltered.length > 0) {
477
+ lines.push("**When to use:**");
478
+ for (const when of whenFiltered) {
479
+ lines.push(`- ${when}`);
480
+ }
481
+ lines.push("");
482
+ }
483
+ if (whenNotFiltered.length > 0) {
484
+ lines.push("**When NOT to use:**");
485
+ for (const whenNot of whenNotFiltered) {
486
+ lines.push(`- ${whenNot}`);
487
+ }
488
+ lines.push("");
489
+ }
490
+ }
491
+ if (include.props && Object.keys(segment.props).length > 0) {
492
+ lines.push("**Props:**");
493
+ for (const [name, prop] of Object.entries(segment.props)) {
494
+ lines.push(`- \`${name}\`: ${formatPropType(prop)}${prop.required ? " (required)" : ""}`);
495
+ }
496
+ lines.push("");
497
+ }
498
+ if (include.variants && segment.variants.length > 0) {
499
+ const variantNames = segment.variants.map((v) => v.name).join(", ");
500
+ lines.push(`**Variants:** ${variantNames}`);
501
+ lines.push("");
502
+ if (include.code) {
503
+ for (const variant of segment.variants) {
504
+ if (variant.code) {
505
+ lines.push(`*${variant.name}:*`);
506
+ lines.push("```tsx");
507
+ lines.push(variant.code);
508
+ lines.push("```");
509
+ lines.push("");
510
+ }
511
+ }
512
+ }
513
+ }
514
+ if (include.relations && segment.relations && segment.relations.length > 0) {
515
+ lines.push("**Related:**");
516
+ for (const relation of segment.relations) {
517
+ lines.push(`- ${relation.component} (${relation.relationship}): ${relation.note}`);
518
+ }
519
+ lines.push("");
520
+ }
521
+ lines.push("---");
522
+ lines.push("");
523
+ }
524
+ if (recipes && recipes.length > 0) {
525
+ lines.push("## Recipes");
526
+ lines.push("");
527
+ lines.push("Composition patterns showing how components wire together.");
528
+ lines.push("");
529
+ for (const recipe of recipes) {
530
+ lines.push(`### ${recipe.name}`);
531
+ lines.push("");
532
+ lines.push(recipe.description);
533
+ lines.push("");
534
+ lines.push(`**Category:** ${recipe.category}`);
535
+ lines.push(`**Components:** ${recipe.components.join(", ")}`);
536
+ if (recipe.tags && recipe.tags.length > 0) {
537
+ lines.push(`**Tags:** ${recipe.tags.join(", ")}`);
538
+ }
539
+ lines.push("");
540
+ lines.push("```tsx");
541
+ lines.push(recipe.code);
542
+ lines.push("```");
543
+ lines.push("");
544
+ lines.push("---");
545
+ lines.push("");
546
+ }
547
+ }
548
+ const content = lines.join("\n");
549
+ return {
550
+ content,
551
+ tokenEstimate: estimateTokens(content)
552
+ };
553
+ }
554
+ function generateJsonContext(segments, include, compact, recipes) {
555
+ const categories = [...new Set(segments.map((s) => s.meta.category))].sort();
556
+ const components = {};
557
+ for (const segment of segments) {
558
+ const component = {
559
+ category: segment.meta.category,
560
+ description: segment.meta.description
561
+ };
562
+ if (segment.meta.status) {
563
+ component.status = segment.meta.status;
564
+ }
565
+ if (!compact) {
566
+ if (include.usage) {
567
+ const whenFiltered = filterPlaceholders(segment.usage.when);
568
+ const whenNotFiltered = filterPlaceholders(segment.usage.whenNot);
569
+ if (whenFiltered.length > 0) {
570
+ component.whenToUse = whenFiltered;
571
+ }
572
+ if (whenNotFiltered.length > 0) {
573
+ component.whenNotToUse = whenNotFiltered;
574
+ }
575
+ }
576
+ if (include.props && Object.keys(segment.props).length > 0) {
577
+ component.props = {};
578
+ for (const [name, prop] of Object.entries(segment.props)) {
579
+ component.props[name] = {
580
+ type: formatPropType(prop),
581
+ description: prop.description
582
+ };
583
+ if (prop.required) {
584
+ component.props[name].required = true;
585
+ }
586
+ if (prop.default !== void 0) {
587
+ component.props[name].default = prop.default;
588
+ }
589
+ }
590
+ }
591
+ if (include.variants && segment.variants.length > 0) {
592
+ component.variants = segment.variants.map((v) => v.name);
593
+ }
594
+ if (include.relations && segment.relations && segment.relations.length > 0) {
595
+ component.relations = segment.relations.map((r) => ({
596
+ component: r.component,
597
+ relationship: r.relationship,
598
+ note: r.note
599
+ }));
600
+ }
601
+ }
602
+ components[segment.meta.name] = component;
603
+ }
604
+ const recipesMap = recipes && recipes.length > 0 ? Object.fromEntries(recipes.map((r) => [r.name, {
605
+ description: r.description,
606
+ category: r.category,
607
+ components: r.components,
608
+ code: r.code,
609
+ tags: r.tags
610
+ }])) : void 0;
611
+ const output = {
612
+ version: "1.0",
613
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
614
+ summary: {
615
+ totalComponents: segments.length,
616
+ categories,
617
+ ...recipesMap && { totalRecipes: recipes.length }
618
+ },
619
+ components,
620
+ ...recipesMap && { recipes: recipesMap }
621
+ };
622
+ const content = JSON.stringify(output, null, 2);
623
+ return {
624
+ content,
625
+ tokenEstimate: estimateTokens(content)
626
+ };
627
+ }
628
+ function formatPropType(prop) {
629
+ if (prop.type === "enum" && prop.values) {
630
+ return prop.values.map((v) => `"${v}"`).join(" | ");
631
+ }
632
+ if (prop.default !== void 0) {
633
+ return `${prop.type} (default: ${JSON.stringify(prop.default)})`;
634
+ }
635
+ return prop.type;
636
+ }
637
+ function truncate(str, maxLength) {
638
+ if (str.length <= maxLength) return str;
639
+ return str.slice(0, maxLength - 3) + "...";
640
+ }
641
+ function estimateTokens(text) {
642
+ return Math.ceil(text.length / 4);
643
+ }
644
+
645
+ // src/core/figma.ts
646
+ function string(figmaProperty) {
647
+ return {
648
+ __type: "figma-string",
649
+ figmaProperty
650
+ };
651
+ }
652
+ function boolean(figmaProperty, valueMapping) {
653
+ return {
654
+ __type: "figma-boolean",
655
+ figmaProperty,
656
+ valueMapping
657
+ };
658
+ }
659
+ function enumValue(figmaProperty, valueMapping) {
660
+ return {
661
+ __type: "figma-enum",
662
+ figmaProperty,
663
+ valueMapping
664
+ };
665
+ }
666
+ function instance(figmaProperty) {
667
+ return {
668
+ __type: "figma-instance",
669
+ figmaProperty
670
+ };
671
+ }
672
+ function children(layers) {
673
+ return {
674
+ __type: "figma-children",
675
+ layers
676
+ };
677
+ }
678
+ function textContent(layer) {
679
+ return {
680
+ __type: "figma-text-content",
681
+ layer
682
+ };
683
+ }
684
+ var figma = {
685
+ string,
686
+ boolean,
687
+ enum: enumValue,
688
+ instance,
689
+ children,
690
+ textContent
691
+ };
692
+ function isFigmaPropMapping(value) {
693
+ if (typeof value !== "object" || value === null || !("__type" in value)) {
694
+ return false;
695
+ }
696
+ const typeValue = value.__type;
697
+ return typeof typeValue === "string" && typeValue.startsWith("figma-");
698
+ }
699
+ function resolveFigmaMapping(mapping, figmaValues) {
700
+ switch (mapping.__type) {
701
+ case "figma-string":
702
+ return figmaValues[mapping.figmaProperty] ?? "";
703
+ case "figma-boolean": {
704
+ const boolValue = figmaValues[mapping.figmaProperty];
705
+ if (mapping.valueMapping) {
706
+ return boolValue ? mapping.valueMapping.true : mapping.valueMapping.false;
707
+ }
708
+ return boolValue;
709
+ }
710
+ case "figma-enum": {
711
+ const enumKey = figmaValues[mapping.figmaProperty];
712
+ return mapping.valueMapping[enumKey] ?? enumKey;
713
+ }
714
+ case "figma-instance":
715
+ return figmaValues[mapping.figmaProperty];
716
+ case "figma-children":
717
+ return mapping.layers.map((layer) => figmaValues[layer]);
718
+ case "figma-text-content":
719
+ return figmaValues[mapping.layer] ?? "";
720
+ default:
721
+ return void 0;
722
+ }
723
+ }
724
+
725
+ // src/core/composition.ts
726
+ var CATEGORY_AFFINITIES = {
727
+ forms: ["feedback"],
728
+ actions: ["feedback"]
729
+ };
730
+ function analyzeComposition(segments, componentNames, _context) {
731
+ const allNames = new Set(Object.keys(segments));
732
+ const components = [];
733
+ const unknown = [];
734
+ for (const name of componentNames) {
735
+ if (allNames.has(name)) {
736
+ components.push(name);
737
+ } else {
738
+ unknown.push(name);
739
+ }
740
+ }
741
+ const selectedSet = new Set(components);
742
+ const warnings = [];
743
+ const suggestions = [];
744
+ const guidelines = [];
745
+ const suggestedSet = /* @__PURE__ */ new Set();
746
+ for (const name of components) {
747
+ const segment = segments[name];
748
+ if (segment.relations) {
749
+ for (const rel of segment.relations) {
750
+ switch (rel.relationship) {
751
+ case "parent":
752
+ if (!selectedSet.has(rel.component)) {
753
+ warnings.push({
754
+ type: "missing_parent",
755
+ component: name,
756
+ message: `"${name}" expects to be wrapped by "${rel.component}"${rel.note ? `: ${rel.note}` : ""}`,
757
+ relatedComponent: rel.component
758
+ });
759
+ }
760
+ break;
761
+ case "child":
762
+ if (!selectedSet.has(rel.component) && !suggestedSet.has(rel.component)) {
763
+ suggestions.push({
764
+ component: rel.component,
765
+ reason: `"${name}" typically contains "${rel.component}"${rel.note ? `: ${rel.note}` : ""}`,
766
+ relationship: "child",
767
+ sourceComponent: name
768
+ });
769
+ suggestedSet.add(rel.component);
770
+ }
771
+ break;
772
+ case "composition":
773
+ if (!selectedSet.has(rel.component)) {
774
+ warnings.push({
775
+ type: "missing_composition",
776
+ component: name,
777
+ message: `"${name}" is typically used together with "${rel.component}"${rel.note ? `: ${rel.note}` : ""}`,
778
+ relatedComponent: rel.component
779
+ });
780
+ }
781
+ break;
782
+ case "sibling":
783
+ if (!selectedSet.has(rel.component) && !suggestedSet.has(rel.component)) {
784
+ suggestions.push({
785
+ component: rel.component,
786
+ reason: `"${rel.component}" is a sibling of "${name}"${rel.note ? `: ${rel.note}` : ""}`,
787
+ relationship: "sibling",
788
+ sourceComponent: name
789
+ });
790
+ suggestedSet.add(rel.component);
791
+ }
792
+ break;
793
+ case "alternative":
794
+ if (selectedSet.has(rel.component)) {
795
+ warnings.push({
796
+ type: "redundant_alternative",
797
+ component: name,
798
+ message: `"${name}" and "${rel.component}" are alternatives \u2014 using both may be redundant${rel.note ? `: ${rel.note}` : ""}`,
799
+ relatedComponent: rel.component
800
+ });
801
+ }
802
+ break;
803
+ }
804
+ }
805
+ }
806
+ if (segment.usage?.whenNot) {
807
+ for (const whenNotEntry of segment.usage.whenNot) {
808
+ const lower = whenNotEntry.toLowerCase();
809
+ for (const other of components) {
810
+ if (other !== name && lower.includes(other.toLowerCase())) {
811
+ guidelines.push({
812
+ component: name,
813
+ guideline: `Potential conflict with "${other}": ${whenNotEntry}`
814
+ });
815
+ }
816
+ }
817
+ }
818
+ }
819
+ if (segment.meta.status === "deprecated") {
820
+ warnings.push({
821
+ type: "deprecated",
822
+ component: name,
823
+ message: segment.meta.description ? `"${name}" is deprecated: ${segment.meta.description}` : `"${name}" is deprecated`
824
+ });
825
+ } else if (segment.meta.status === "experimental") {
826
+ warnings.push({
827
+ type: "experimental",
828
+ component: name,
829
+ message: `"${name}" is experimental and may change without notice`
830
+ });
831
+ }
832
+ }
833
+ const selectedCategories = new Set(
834
+ components.map((name) => segments[name].meta.category)
835
+ );
836
+ for (const [category, affinities] of Object.entries(CATEGORY_AFFINITIES)) {
837
+ if (!selectedCategories.has(category)) continue;
838
+ for (const neededCategory of affinities) {
839
+ if (selectedCategories.has(neededCategory)) continue;
840
+ const candidate = findBestCategoryCandidate(
841
+ segments,
842
+ neededCategory,
843
+ selectedSet,
844
+ suggestedSet
845
+ );
846
+ if (candidate) {
847
+ suggestions.push({
848
+ component: candidate,
849
+ reason: `Compositions using "${category}" components often benefit from a "${neededCategory}" component`,
850
+ relationship: "category_gap",
851
+ sourceComponent: components.find(
852
+ (n) => segments[n].meta.category === category
853
+ )
854
+ });
855
+ suggestedSet.add(candidate);
856
+ }
857
+ }
858
+ }
859
+ return { components, unknown, warnings, suggestions, guidelines };
860
+ }
861
+ function findBestCategoryCandidate(segments, category, selectedSet, suggestedSet) {
862
+ let best = null;
863
+ let bestScore = -1;
864
+ for (const [name, segment] of Object.entries(segments)) {
865
+ if (segment.meta.category !== category) continue;
866
+ if (selectedSet.has(name) || suggestedSet.has(name)) continue;
867
+ const status = segment.meta.status ?? "stable";
868
+ let score = 0;
869
+ if (status === "stable") score = 3;
870
+ else if (status === "beta") score = 2;
871
+ else if (status === "experimental") score = 1;
872
+ if (score > bestScore) {
873
+ bestScore = score;
874
+ best = name;
875
+ }
876
+ }
877
+ return best;
878
+ }
879
+
880
+ export {
881
+ defineSegment,
882
+ defineFragment,
883
+ compileSegment,
884
+ defineRecipe,
885
+ compileRecipe,
886
+ toId,
887
+ storyNameFromExport,
888
+ isExportStory,
889
+ setPreviewConfig,
890
+ getPreviewConfig,
891
+ storyModuleToSegment,
892
+ generateContext,
893
+ figma,
894
+ isFigmaPropMapping,
895
+ resolveFigmaMapping,
896
+ analyzeComposition
897
+ };
898
+ //# sourceMappingURL=chunk-LY2CFFPY.js.map