@fragments-sdk/cli 0.10.1 → 0.11.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 (149) hide show
  1. package/dist/bin.js +20 -2
  2. package/dist/bin.js.map +1 -1
  3. package/dist/{init-NDQXUWDU.js → init-UFGK5TCN.js} +75 -4
  4. package/dist/init-UFGK5TCN.js.map +1 -0
  5. package/dist/snapshot-SV2JOFZH.js +139 -0
  6. package/dist/snapshot-SV2JOFZH.js.map +1 -0
  7. package/dist/{viewer-DNMNC5VS.js → viewer-DLLJIMCK.js} +68 -46
  8. package/dist/viewer-DLLJIMCK.js.map +1 -0
  9. package/package.json +6 -14
  10. package/src/bin.ts +30 -0
  11. package/src/commands/init.ts +76 -1
  12. package/src/commands/snapshot.ts +197 -0
  13. package/src/viewer/__tests__/viewer-integration.test.ts +85 -74
  14. package/src/viewer/server.ts +37 -22
  15. package/src/viewer/vite-plugin.ts +25 -9
  16. package/dist/init-NDQXUWDU.js.map +0 -1
  17. package/dist/viewer-DNMNC5VS.js.map +0 -1
  18. package/src/viewer/__tests__/a11y-fixes.test.ts +0 -358
  19. package/src/viewer/__tests__/jsx-parser.test.ts +0 -502
  20. package/src/viewer/__tests__/render-utils.test.ts +0 -232
  21. package/src/viewer/__tests__/style-utils.test.ts +0 -404
  22. package/src/viewer/assets/fragments-logo.ts +0 -4
  23. package/src/viewer/assets/fragments_logo.png +0 -0
  24. package/src/viewer/components/AccessibilityPanel.tsx +0 -1457
  25. package/src/viewer/components/ActionCapture.tsx +0 -172
  26. package/src/viewer/components/ActionsPanel.tsx +0 -332
  27. package/src/viewer/components/AllVariantsPreview.tsx +0 -78
  28. package/src/viewer/components/App.tsx +0 -582
  29. package/src/viewer/components/BottomPanel.tsx +0 -288
  30. package/src/viewer/components/CodePanel.naming.test.tsx +0 -59
  31. package/src/viewer/components/CodePanel.tsx +0 -118
  32. package/src/viewer/components/CommandPalette.tsx +0 -392
  33. package/src/viewer/components/ComponentDocView.tsx +0 -164
  34. package/src/viewer/components/ComponentGraph.tsx +0 -380
  35. package/src/viewer/components/ComponentHeader.tsx +0 -88
  36. package/src/viewer/components/ContractPanel.tsx +0 -241
  37. package/src/viewer/components/EmptyVariantMessage.tsx +0 -54
  38. package/src/viewer/components/ErrorBoundary.tsx +0 -97
  39. package/src/viewer/components/FigmaEmbed.tsx +0 -238
  40. package/src/viewer/components/FragmentEditor.tsx +0 -525
  41. package/src/viewer/components/FragmentRenderer.tsx +0 -61
  42. package/src/viewer/components/HeaderSearch.tsx +0 -24
  43. package/src/viewer/components/HealthDashboard.tsx +0 -441
  44. package/src/viewer/components/HmrStatusIndicator.tsx +0 -61
  45. package/src/viewer/components/Icons.tsx +0 -479
  46. package/src/viewer/components/InteractionsPanel.tsx +0 -757
  47. package/src/viewer/components/IsolatedPreviewFrame.tsx +0 -346
  48. package/src/viewer/components/IsolatedRender.tsx +0 -113
  49. package/src/viewer/components/KeyboardShortcutsHelp.tsx +0 -53
  50. package/src/viewer/components/LandingPage.tsx +0 -421
  51. package/src/viewer/components/Layout.tsx +0 -27
  52. package/src/viewer/components/LeftSidebar.tsx +0 -472
  53. package/src/viewer/components/LoadErrorMessage.tsx +0 -102
  54. package/src/viewer/components/MultiViewportPreview.tsx +0 -522
  55. package/src/viewer/components/NoVariantsMessage.tsx +0 -59
  56. package/src/viewer/components/PanelShell.tsx +0 -161
  57. package/src/viewer/components/PerformancePanel.tsx +0 -304
  58. package/src/viewer/components/PreviewArea.tsx +0 -472
  59. package/src/viewer/components/PreviewAside.tsx +0 -168
  60. package/src/viewer/components/PreviewFrameHost.tsx +0 -303
  61. package/src/viewer/components/PreviewPane.tsx +0 -149
  62. package/src/viewer/components/PreviewToolbar.tsx +0 -80
  63. package/src/viewer/components/PropsEditor.tsx +0 -506
  64. package/src/viewer/components/PropsTable.tsx +0 -111
  65. package/src/viewer/components/RelationsSection.tsx +0 -88
  66. package/src/viewer/components/ResizablePanel.tsx +0 -271
  67. package/src/viewer/components/RightSidebar.tsx +0 -102
  68. package/src/viewer/components/RuntimeToolsRegistrar.tsx +0 -17
  69. package/src/viewer/components/ScreenshotButton.tsx +0 -90
  70. package/src/viewer/components/Sidebar.tsx +0 -169
  71. package/src/viewer/components/SkeletonLoader.tsx +0 -161
  72. package/src/viewer/components/ThemeProvider.tsx +0 -42
  73. package/src/viewer/components/Toast.tsx +0 -3
  74. package/src/viewer/components/TokenStylePanel.tsx +0 -699
  75. package/src/viewer/components/TopToolbar.tsx +0 -159
  76. package/src/viewer/components/UsageSection.tsx +0 -95
  77. package/src/viewer/components/VariantMatrix.tsx +0 -388
  78. package/src/viewer/components/VariantRenderer.tsx +0 -131
  79. package/src/viewer/components/VariantTabs.tsx +0 -40
  80. package/src/viewer/components/ViewerHeader.tsx +0 -69
  81. package/src/viewer/components/ViewerStateSync.tsx +0 -52
  82. package/src/viewer/components/ViewportSelector.tsx +0 -172
  83. package/src/viewer/components/WebMCPDevTools.tsx +0 -503
  84. package/src/viewer/components/WebMCPIntegration.tsx +0 -47
  85. package/src/viewer/components/WebMCPStatusIndicator.tsx +0 -60
  86. package/src/viewer/components/_future/CreatePage.tsx +0 -836
  87. package/src/viewer/components/viewer-utils.ts +0 -16
  88. package/src/viewer/composition-renderer.ts +0 -381
  89. package/src/viewer/constants/index.ts +0 -1
  90. package/src/viewer/constants/ui.ts +0 -166
  91. package/src/viewer/entry.tsx +0 -335
  92. package/src/viewer/hooks/index.ts +0 -2
  93. package/src/viewer/hooks/useA11yCache.ts +0 -383
  94. package/src/viewer/hooks/useA11yService.ts +0 -364
  95. package/src/viewer/hooks/useActions.ts +0 -138
  96. package/src/viewer/hooks/useAppState.ts +0 -147
  97. package/src/viewer/hooks/useCompiledFragments.ts +0 -42
  98. package/src/viewer/hooks/useFigmaIntegration.ts +0 -132
  99. package/src/viewer/hooks/useHmrStatus.ts +0 -109
  100. package/src/viewer/hooks/useKeyboardShortcuts.ts +0 -270
  101. package/src/viewer/hooks/usePreviewBridge.ts +0 -347
  102. package/src/viewer/hooks/useScrollSpy.ts +0 -78
  103. package/src/viewer/hooks/useUrlState.ts +0 -318
  104. package/src/viewer/hooks/useViewSettings.ts +0 -111
  105. package/src/viewer/index.html +0 -28
  106. package/src/viewer/intelligence/healthReport.ts +0 -505
  107. package/src/viewer/intelligence/styleDrift.ts +0 -340
  108. package/src/viewer/intelligence/usageScanner.ts +0 -309
  109. package/src/viewer/jsx-parser.ts +0 -486
  110. package/src/viewer/preview-frame-entry.tsx +0 -25
  111. package/src/viewer/preview-frame.html +0 -125
  112. package/src/viewer/public/favicon.ico +0 -0
  113. package/src/viewer/render-template.html +0 -68
  114. package/src/viewer/styles/globals.css +0 -278
  115. package/src/viewer/types/a11y.ts +0 -197
  116. package/src/viewer/utils/a11y-fixes.ts +0 -509
  117. package/src/viewer/utils/actionExport.ts +0 -372
  118. package/src/viewer/utils/colorSchemes.ts +0 -201
  119. package/src/viewer/utils/detectRelationships.ts +0 -256
  120. package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss +0 -10
  121. package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss.d.ts +0 -2
  122. package/src/viewer/vendor/shared/src/ComponentDocContent.tsx +0 -274
  123. package/src/viewer/vendor/shared/src/DocsHeaderBar.tsx +0 -129
  124. package/src/viewer/vendor/shared/src/DocsPageAsideHost.tsx +0 -89
  125. package/src/viewer/vendor/shared/src/DocsPageShell.tsx +0 -124
  126. package/src/viewer/vendor/shared/src/DocsSearchCommand.tsx +0 -99
  127. package/src/viewer/vendor/shared/src/DocsSidebarNav.tsx +0 -66
  128. package/src/viewer/vendor/shared/src/PropsTable.module.scss +0 -68
  129. package/src/viewer/vendor/shared/src/PropsTable.module.scss.d.ts +0 -2
  130. package/src/viewer/vendor/shared/src/PropsTable.tsx +0 -76
  131. package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss +0 -114
  132. package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss.d.ts +0 -2
  133. package/src/viewer/vendor/shared/src/VariantPreviewCard.tsx +0 -137
  134. package/src/viewer/vendor/shared/src/docs-data/index.ts +0 -32
  135. package/src/viewer/vendor/shared/src/docs-data/mcp-configs.ts +0 -72
  136. package/src/viewer/vendor/shared/src/docs-data/palettes.ts +0 -75
  137. package/src/viewer/vendor/shared/src/docs-data/setup-examples.ts +0 -55
  138. package/src/viewer/vendor/shared/src/docs-layout.scss +0 -28
  139. package/src/viewer/vendor/shared/src/docs-layout.scss.d.ts +0 -2
  140. package/src/viewer/vendor/shared/src/index.ts +0 -34
  141. package/src/viewer/vendor/shared/src/types.ts +0 -53
  142. package/src/viewer/webmcp/__tests__/analytics.test.ts +0 -108
  143. package/src/viewer/webmcp/analytics.ts +0 -165
  144. package/src/viewer/webmcp/index.ts +0 -3
  145. package/src/viewer/webmcp/posthog-bridge.ts +0 -39
  146. package/src/viewer/webmcp/runtime-tools.ts +0 -152
  147. package/src/viewer/webmcp/scan-utils.ts +0 -135
  148. package/src/viewer/webmcp/use-tool-analytics.ts +0 -69
  149. package/src/viewer/webmcp/viewer-state.ts +0 -45
@@ -1,486 +0,0 @@
1
- /**
2
- * JSX Parser
3
- *
4
- * Parses JSX strings into a structured component tree that can be
5
- * used for rendering multi-component compositions.
6
- */
7
-
8
- import { parse } from "@babel/parser";
9
- import type {
10
- JSXElement,
11
- JSXFragment,
12
- JSXText,
13
- JSXExpressionContainer,
14
- JSXAttribute,
15
- JSXSpreadAttribute,
16
- Expression,
17
- Node,
18
- } from "@babel/types";
19
-
20
- /**
21
- * Represents a parsed JSX component node
22
- */
23
- export interface ComponentNode {
24
- /** Component name (e.g., "Button", "Card") or HTML element name (e.g., "div") */
25
- name: string;
26
- /** Whether this is an HTML element (lowercase) vs custom component (PascalCase) */
27
- isHtmlElement: boolean;
28
- /** Props/attributes passed to the component */
29
- props: Record<string, unknown>;
30
- /** Child nodes (can be ComponentNode, string, or expression) */
31
- children: Array<ComponentNode | string>;
32
- }
33
-
34
- /**
35
- * Result of parsing a JSX string
36
- */
37
- export interface ParseResult {
38
- /** The root component tree */
39
- tree: ComponentNode | ComponentNode[];
40
- /** List of all unique component names found (excluding HTML elements) */
41
- components: string[];
42
- /** Any parsing errors */
43
- errors: string[];
44
- }
45
-
46
- /**
47
- * Parse a JSX string into a component tree.
48
- *
49
- * @param jsx - The JSX string to parse
50
- * @returns ParseResult with the component tree and metadata
51
- *
52
- * @example
53
- * ```ts
54
- * const result = parseJSX('<Card><Button variant="primary">Click</Button></Card>');
55
- * // result.tree = { name: 'Card', props: {}, children: [{ name: 'Button', props: { variant: 'primary' }, children: ['Click'] }] }
56
- * // result.components = ['Card', 'Button']
57
- * ```
58
- */
59
- export function parseJSX(jsx: string): ParseResult {
60
- const errors: string[] = [];
61
- const components = new Set<string>();
62
-
63
- try {
64
- // Wrap in a fragment to handle multiple root elements
65
- const wrappedJsx = `<>${jsx}</>`;
66
-
67
- const ast = parse(wrappedJsx, {
68
- sourceType: "module",
69
- plugins: ["jsx"],
70
- });
71
-
72
- // Find the expression statement containing our JSX
73
- const program = ast.program;
74
- const firstStatement = program.body[0];
75
-
76
- if (firstStatement?.type !== "ExpressionStatement") {
77
- return {
78
- tree: [],
79
- components: [],
80
- errors: ["Invalid JSX: expected expression statement"],
81
- };
82
- }
83
-
84
- const expression = firstStatement.expression;
85
-
86
- if (expression.type !== "JSXFragment" && expression.type !== "JSXElement") {
87
- return {
88
- tree: [],
89
- components: [],
90
- errors: ["Invalid JSX: expected JSX element or fragment"],
91
- };
92
- }
93
-
94
- // Parse the JSX tree
95
- const parseNode = (
96
- node: JSXElement | JSXFragment | JSXText | JSXExpressionContainer
97
- ): ComponentNode | string | null => {
98
- if (node.type === "JSXText") {
99
- const text = node.value.trim();
100
- return text || null;
101
- }
102
-
103
- if (node.type === "JSXExpressionContainer") {
104
- // Handle expressions like {variable} or {condition && <Component />}
105
- const exprValue = evaluateExpression(node.expression);
106
- // Convert to string or return null if not renderable
107
- if (exprValue === null || exprValue === undefined) {
108
- return null;
109
- }
110
- if (typeof exprValue === "string") {
111
- return exprValue;
112
- }
113
- // For non-string primitives, convert to string
114
- return String(exprValue);
115
- }
116
-
117
- if (node.type === "JSXFragment") {
118
- // For fragments, return children directly
119
- const children = node.children
120
- .map((child) => parseNode(child as JSXElement | JSXFragment | JSXText | JSXExpressionContainer))
121
- .filter((c): c is ComponentNode | string => c !== null);
122
-
123
- // If only one child, return it directly
124
- if (children.length === 1 && typeof children[0] !== "string") {
125
- return children[0];
126
- }
127
-
128
- // Return a special fragment node
129
- return {
130
- name: "Fragment",
131
- isHtmlElement: false,
132
- props: {},
133
- children,
134
- };
135
- }
136
-
137
- if (node.type === "JSXElement") {
138
- const openingElement = node.openingElement;
139
- let name: string;
140
-
141
- if (openingElement.name.type === "JSXIdentifier") {
142
- name = openingElement.name.name;
143
- } else if (openingElement.name.type === "JSXMemberExpression") {
144
- // Handle things like MyLib.Button
145
- name = getMemberExpressionName(openingElement.name);
146
- } else {
147
- name = "Unknown";
148
- }
149
-
150
- // Check if it's an HTML element (lowercase first letter)
151
- const isHtmlElement = /^[a-z]/.test(name);
152
-
153
- // Track custom components
154
- if (!isHtmlElement && name !== "Fragment") {
155
- components.add(name);
156
- }
157
-
158
- // Parse props
159
- const props: Record<string, unknown> = {};
160
- for (const attr of openingElement.attributes) {
161
- if (attr.type === "JSXAttribute") {
162
- const propName = attr.name.type === "JSXIdentifier" ? attr.name.name : String(attr.name.name);
163
- const propValue = parseAttributeValue(attr);
164
- props[propName] = propValue;
165
- } else if (attr.type === "JSXSpreadAttribute") {
166
- // Handle spread attributes {...props}
167
- const spreadValue = evaluateExpression(attr.argument);
168
- if (typeof spreadValue === "object" && spreadValue !== null) {
169
- Object.assign(props, spreadValue);
170
- }
171
- }
172
- }
173
-
174
- // Parse children
175
- const children = node.children
176
- .map((child) => parseNode(child as JSXElement | JSXFragment | JSXText | JSXExpressionContainer))
177
- .filter((c): c is ComponentNode | string => c !== null);
178
-
179
- return {
180
- name,
181
- isHtmlElement,
182
- props,
183
- children,
184
- };
185
- }
186
-
187
- return null;
188
- };
189
-
190
- // Parse the root
191
- const rootNode = parseNode(expression);
192
-
193
- if (rootNode === null) {
194
- return {
195
- tree: [],
196
- components: [],
197
- errors: ["Failed to parse JSX"],
198
- };
199
- }
200
-
201
- // If we got a Fragment with multiple children from our wrapper, unwrap it
202
- if (
203
- typeof rootNode !== "string" &&
204
- rootNode.name === "Fragment" &&
205
- rootNode.children.length > 0
206
- ) {
207
- // Check if all children are component nodes
208
- const componentChildren = rootNode.children.filter(
209
- (c): c is ComponentNode => typeof c !== "string"
210
- );
211
-
212
- if (componentChildren.length === 1) {
213
- return {
214
- tree: componentChildren[0],
215
- components: Array.from(components).sort(),
216
- errors,
217
- };
218
- }
219
-
220
- if (componentChildren.length > 1) {
221
- return {
222
- tree: componentChildren,
223
- components: Array.from(components).sort(),
224
- errors,
225
- };
226
- }
227
- }
228
-
229
- return {
230
- tree: typeof rootNode === "string" ? [] : rootNode,
231
- components: Array.from(components).sort(),
232
- errors,
233
- };
234
- } catch (error) {
235
- const message = error instanceof Error ? error.message : "Unknown parse error";
236
- return {
237
- tree: [],
238
- components: [],
239
- errors: [message],
240
- };
241
- }
242
- }
243
-
244
- /**
245
- * Get the full name from a JSX member expression (e.g., MyLib.Button)
246
- */
247
- function getMemberExpressionName(node: any): string {
248
- if (node.type === "JSXIdentifier") {
249
- return node.name;
250
- }
251
- if (node.type === "JSXMemberExpression") {
252
- return `${getMemberExpressionName(node.object)}.${node.property.name}`;
253
- }
254
- return "Unknown";
255
- }
256
-
257
- /**
258
- * Parse a JSX attribute value
259
- */
260
- function parseAttributeValue(attr: JSXAttribute): unknown {
261
- const value = attr.value;
262
-
263
- // Boolean attribute (no value means true)
264
- if (value === null || value === undefined) {
265
- return true;
266
- }
267
-
268
- // String literal
269
- if (value.type === "StringLiteral") {
270
- return (value as { value: string }).value;
271
- }
272
-
273
- // Expression container {value}
274
- if (value.type === "JSXExpressionContainer") {
275
- return evaluateExpression((value as JSXExpressionContainer).expression);
276
- }
277
-
278
- // JSX element as attribute value
279
- if (value.type === "JSXElement" || value.type === "JSXFragment") {
280
- // This would be something like <Component prop={<Other />} />
281
- // We'll return a string representation for now
282
- return "[JSX Element]";
283
- }
284
-
285
- return null;
286
- }
287
-
288
- /**
289
- * Evaluate a JavaScript expression from JSX.
290
- * This handles common cases but is intentionally limited for safety.
291
- */
292
- function evaluateExpression(expr: Expression | Node): unknown {
293
- if (!expr || expr.type === "JSXEmptyExpression") {
294
- return null;
295
- }
296
-
297
- switch (expr.type) {
298
- case "StringLiteral":
299
- return expr.value;
300
-
301
- case "NumericLiteral":
302
- return expr.value;
303
-
304
- case "BooleanLiteral":
305
- return expr.value;
306
-
307
- case "NullLiteral":
308
- return null;
309
-
310
- case "Identifier":
311
- // Handle special identifiers
312
- if (expr.name === "undefined") return undefined;
313
- if (expr.name === "true") return true;
314
- if (expr.name === "false") return false;
315
- // Return the identifier name as a placeholder
316
- return `{${expr.name}}`;
317
-
318
- case "TemplateLiteral":
319
- // Handle template literals with no expressions
320
- if (expr.expressions.length === 0 && expr.quasis.length === 1) {
321
- return expr.quasis[0].value.cooked || expr.quasis[0].value.raw;
322
- }
323
- // For template literals with expressions, return a placeholder
324
- return "[Template Literal]";
325
-
326
- case "ObjectExpression": {
327
- // Parse object literals like {{ key: 'value' }}
328
- const obj: Record<string, unknown> = {};
329
- for (const prop of expr.properties) {
330
- if (prop.type === "ObjectProperty") {
331
- const key =
332
- prop.key.type === "Identifier"
333
- ? prop.key.name
334
- : prop.key.type === "StringLiteral"
335
- ? prop.key.value
336
- : String(prop.key);
337
- obj[key] = evaluateExpression(prop.value as Expression);
338
- }
339
- }
340
- return obj;
341
- }
342
-
343
- case "ArrayExpression":
344
- // Parse array literals like {[1, 2, 3]}
345
- return expr.elements.map((el) =>
346
- el ? evaluateExpression(el as Expression) : null
347
- );
348
-
349
- case "ArrowFunctionExpression":
350
- case "FunctionExpression":
351
- // Return a placeholder for functions
352
- return "[Function]";
353
-
354
- case "UnaryExpression":
355
- // Handle negation like {-5}
356
- if (expr.operator === "-" && expr.argument.type === "NumericLiteral") {
357
- return -expr.argument.value;
358
- }
359
- if (expr.operator === "!" && expr.argument.type === "BooleanLiteral") {
360
- return !expr.argument.value;
361
- }
362
- return null;
363
-
364
- case "ConditionalExpression":
365
- // Ternary operator - return a placeholder
366
- return "[Conditional]";
367
-
368
- case "LogicalExpression":
369
- // && or || - return a placeholder
370
- return "[Logical Expression]";
371
-
372
- case "MemberExpression":
373
- // Something like obj.prop - return placeholder
374
- return "[Member Expression]";
375
-
376
- case "CallExpression":
377
- // Function call - return placeholder
378
- return "[Function Call]";
379
-
380
- default:
381
- return null;
382
- }
383
- }
384
-
385
- /**
386
- * Extract all component names from a parsed tree
387
- */
388
- export function extractComponents(tree: ComponentNode | ComponentNode[]): string[] {
389
- const components = new Set<string>();
390
-
391
- const visit = (node: ComponentNode) => {
392
- if (!node.isHtmlElement && node.name !== "Fragment") {
393
- components.add(node.name);
394
- }
395
- for (const child of node.children) {
396
- if (typeof child !== "string") {
397
- visit(child);
398
- }
399
- }
400
- };
401
-
402
- if (Array.isArray(tree)) {
403
- for (const node of tree) {
404
- visit(node);
405
- }
406
- } else {
407
- visit(tree);
408
- }
409
-
410
- return Array.from(components).sort();
411
- }
412
-
413
- /**
414
- * Validate that all components in the tree exist in the available components
415
- */
416
- export function validateComponents(
417
- tree: ComponentNode | ComponentNode[],
418
- availableComponents: string[]
419
- ): { valid: boolean; missing: string[]; suggestions: Map<string, string[]> } {
420
- const used = extractComponents(tree);
421
- const available = new Set(availableComponents.map((c) => c.toLowerCase()));
422
- const availableOriginal = new Map(
423
- availableComponents.map((c) => [c.toLowerCase(), c])
424
- );
425
-
426
- const missing: string[] = [];
427
- const suggestions = new Map<string, string[]>();
428
-
429
- for (const component of used) {
430
- const lower = component.toLowerCase();
431
- if (!available.has(lower)) {
432
- missing.push(component);
433
-
434
- // Find similar components for suggestions
435
- const similar = availableComponents.filter((c) => {
436
- const clower = c.toLowerCase();
437
- // Check for partial matches
438
- return (
439
- clower.includes(lower) ||
440
- lower.includes(clower) ||
441
- levenshteinDistance(lower, clower) <= 2
442
- );
443
- });
444
-
445
- if (similar.length > 0) {
446
- suggestions.set(component, similar.slice(0, 3));
447
- }
448
- }
449
- }
450
-
451
- return {
452
- valid: missing.length === 0,
453
- missing,
454
- suggestions,
455
- };
456
- }
457
-
458
- /**
459
- * Simple Levenshtein distance for fuzzy matching
460
- */
461
- function levenshteinDistance(a: string, b: string): number {
462
- const matrix: number[][] = [];
463
-
464
- for (let i = 0; i <= b.length; i++) {
465
- matrix[i] = [i];
466
- }
467
- for (let j = 0; j <= a.length; j++) {
468
- matrix[0][j] = j;
469
- }
470
-
471
- for (let i = 1; i <= b.length; i++) {
472
- for (let j = 1; j <= a.length; j++) {
473
- if (b.charAt(i - 1) === a.charAt(j - 1)) {
474
- matrix[i][j] = matrix[i - 1][j - 1];
475
- } else {
476
- matrix[i][j] = Math.min(
477
- matrix[i - 1][j - 1] + 1,
478
- matrix[i][j - 1] + 1,
479
- matrix[i - 1][j] + 1
480
- );
481
- }
482
- }
483
- }
484
-
485
- return matrix[b.length][a.length];
486
- }
@@ -1,25 +0,0 @@
1
- /**
2
- * Preview Frame Entry Point
3
- *
4
- * This is the entry point for the isolated iframe that renders component previews.
5
- * It runs inside the iframe and receives render requests from the parent window
6
- * via postMessage.
7
- */
8
-
9
- import { createRoot } from 'react-dom/client';
10
- import { PreviewFrameHost } from './components/PreviewFrameHost.js';
11
-
12
- // Mount the preview host
13
- const rootElement = document.getElementById('preview-root');
14
-
15
- if (rootElement) {
16
- const root = createRoot(rootElement);
17
- root.render(<PreviewFrameHost />);
18
- }
19
-
20
- // HMR support
21
- // @ts-expect-error Vite HMR types
22
- if (import.meta.hot) {
23
- // @ts-expect-error Vite HMR types
24
- import.meta.hot.accept();
25
- }
@@ -1,125 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Fragment Preview</title>
7
- <style>
8
- /* Reset and base styles for isolated preview */
9
- *, *::before, *::after {
10
- box-sizing: border-box;
11
- }
12
-
13
- html, body {
14
- margin: 0;
15
- padding: 0;
16
- font-family: var(--fui-font-sans, Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
17
- -webkit-font-smoothing: antialiased;
18
- -moz-osx-font-smoothing: grayscale;
19
- width: 100%;
20
- height: 100%;
21
- overflow: hidden;
22
- }
23
-
24
- body {
25
- background: var(--fui-bg-primary, #ffffff);
26
- min-height: 100%;
27
- }
28
-
29
- #preview-root {
30
- width: 100%;
31
- height: 100%;
32
- min-height: 400px;
33
- padding: 16px;
34
- display: flex;
35
- flex-direction: column;
36
- box-sizing: border-box;
37
- overflow: auto;
38
- }
39
-
40
- #preview-root > * {
41
- width: 100%;
42
- flex: 1;
43
- }
44
-
45
- /* Hide scrollbars but allow scrolling */
46
- html::-webkit-scrollbar {
47
- width: 0;
48
- height: 0;
49
- }
50
-
51
- html {
52
- scrollbar-width: none;
53
- }
54
-
55
- /* Error display styles */
56
- .preview-error {
57
- padding: 16px;
58
- background: #fef2f2;
59
- border: 1px solid #fecaca;
60
- border-radius: 8px;
61
- color: #dc2626;
62
- font-size: 14px;
63
- max-width: 400px;
64
- }
65
-
66
- .preview-error pre {
67
- margin: 8px 0 0;
68
- padding: 8px;
69
- background: #fff;
70
- border-radius: 4px;
71
- overflow-x: auto;
72
- font-size: 12px;
73
- font-family: 'JetBrains Mono', ui-monospace, monospace;
74
- }
75
-
76
- /* Visually hidden but accessible to screen readers */
77
- .sr-only {
78
- position: absolute;
79
- width: 1px;
80
- height: 1px;
81
- padding: 0;
82
- margin: -1px;
83
- overflow: hidden;
84
- clip: rect(0, 0, 0, 0);
85
- white-space: nowrap;
86
- border-width: 0;
87
- }
88
-
89
- /* Loading indicator */
90
- .preview-loading {
91
- display: flex;
92
- align-items: center;
93
- justify-content: center;
94
- gap: 8px;
95
- color: #6b7280;
96
- font-size: 14px;
97
- }
98
-
99
- .preview-loading .spinner {
100
- width: 20px;
101
- height: 20px;
102
- border: 2px solid #e5e7eb;
103
- border-top-color: #3b82f6;
104
- border-radius: 50%;
105
- animation: spin 0.8s linear infinite;
106
- }
107
-
108
- @keyframes spin {
109
- to { transform: rotate(360deg); }
110
- }
111
- </style>
112
- </head>
113
- <body>
114
- <main style="height: 100%">
115
- <h1 class="sr-only">Component Preview</h1>
116
- <div id="preview-root">
117
- <div class="preview-loading">
118
- <div class="spinner"></div>
119
- <span>Loading preview...</span>
120
- </div>
121
- </div>
122
- </main>
123
- <script type="module" src="/src/preview-frame-entry.tsx"></script>
124
- </body>
125
- </html>
Binary file
@@ -1,68 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Fragments Render</title>
7
- <link rel="preconnect" href="https://fonts.googleapis.com" />
8
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
- <link
10
- href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
11
- rel="stylesheet"
12
- />
13
- <style>
14
- /* Reset and base styles for isolated rendering */
15
- *, *::before, *::after {
16
- box-sizing: border-box;
17
- }
18
-
19
- html, body {
20
- margin: 0;
21
- padding: 0;
22
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
23
- -webkit-font-smoothing: antialiased;
24
- -moz-osx-font-smoothing: grayscale;
25
- }
26
-
27
- body {
28
- background: #ffffff;
29
- min-height: 100vh;
30
- }
31
-
32
- #render-root {
33
- padding: 16px;
34
- display: inline-block;
35
- }
36
-
37
- /* Signal that rendering is complete */
38
- #render-root.ready {
39
- /* Used by Playwright to know when to capture */
40
- }
41
-
42
- /* Error display */
43
- .render-error {
44
- padding: 16px;
45
- background: #fef2f2;
46
- border: 1px solid #fecaca;
47
- border-radius: 8px;
48
- color: #dc2626;
49
- font-size: 14px;
50
- }
51
-
52
- .render-error pre {
53
- margin: 8px 0 0;
54
- padding: 8px;
55
- background: #fff;
56
- border-radius: 4px;
57
- overflow-x: auto;
58
- font-size: 12px;
59
- font-family: 'JetBrains Mono', monospace;
60
- }
61
- </style>
62
- <!-- PROJECT_STYLES_PLACEHOLDER -->
63
- </head>
64
- <body>
65
- <div id="render-root"></div>
66
- <!-- RENDER_SCRIPT_PLACEHOLDER -->
67
- </body>
68
- </html>