@fragments-sdk/cli 0.7.14 → 0.7.16

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 (67) hide show
  1. package/dist/bin.js +7 -7
  2. package/dist/{chunk-CRTN6BIW.js → chunk-QLTLLQBI.js} +2 -2
  3. package/dist/{chunk-TQOGBAOZ.js → chunk-WLXFE6XW.js} +91 -2
  4. package/dist/chunk-WLXFE6XW.js.map +1 -0
  5. package/dist/core/index.d.ts +44 -3
  6. package/dist/core/index.js +11 -3
  7. package/dist/{defineFragment-C6PFzZyo.d.ts → defineFragment-BI9KoPrs.d.ts} +1 -1
  8. package/dist/{generate-ZPERYZLF.js → generate-ICIPKCKV.js} +2 -2
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +2 -2
  11. package/dist/init-DIZ6UNBL.js +806 -0
  12. package/dist/init-DIZ6UNBL.js.map +1 -0
  13. package/dist/mcp-bin.js +2 -2
  14. package/dist/{scan-BSMLGBX4.js → scan-X3DI2X5G.js} +2 -2
  15. package/dist/{service-QACVPR37.js → service-JEWWTSKI.js} +2 -2
  16. package/dist/{static-viewer-2RQD5QLR.js → static-viewer-JIWCYKVK.js} +2 -2
  17. package/dist/{tokens-A3BZIQPB.js → tokens-K2AGUUOJ.js} +2 -2
  18. package/dist/{viewer-CNLZQUFO.js → viewer-QKIAPTPG.js} +126 -15
  19. package/dist/viewer-QKIAPTPG.js.map +1 -0
  20. package/package.json +3 -2
  21. package/src/commands/init-framework.ts +414 -0
  22. package/src/commands/init.ts +41 -1
  23. package/src/core/__tests__/preview-runtime.test.tsx +111 -0
  24. package/src/core/index.ts +13 -0
  25. package/src/core/preview-runtime.tsx +144 -0
  26. package/src/viewer/components/App.tsx +8 -3
  27. package/src/viewer/components/FragmentRenderer.tsx +61 -0
  28. package/src/viewer/components/HealthDashboard.tsx +1 -1
  29. package/src/viewer/components/IsolatedPreviewFrame.tsx +10 -8
  30. package/src/viewer/components/PreviewFrameHost.tsx +27 -60
  31. package/src/viewer/components/PropsTable.tsx +2 -2
  32. package/src/viewer/components/RuntimeToolsRegistrar.tsx +17 -0
  33. package/src/viewer/components/SkeletonLoader.tsx +114 -125
  34. package/src/viewer/components/VariantMatrix.tsx +3 -3
  35. package/src/viewer/components/ViewerStateSync.tsx +52 -0
  36. package/src/viewer/components/WebMCPDevTools.tsx +509 -0
  37. package/src/viewer/components/WebMCPIntegration.tsx +47 -0
  38. package/src/viewer/components/WebMCPStatusIndicator.tsx +60 -0
  39. package/src/viewer/entry.tsx +32 -5
  40. package/src/viewer/hooks/useA11yService.ts +1 -135
  41. package/src/viewer/hooks/useCompiledFragments.ts +42 -0
  42. package/src/viewer/index.html +1 -1
  43. package/src/viewer/public/favicon.ico +0 -0
  44. package/src/viewer/server.ts +59 -3
  45. package/src/viewer/vendor/shared/src/DocsHeaderBar.tsx +19 -0
  46. package/src/viewer/vendor/shared/src/DocsPageAsideHost.tsx +1 -1
  47. package/src/viewer/vendor/shared/src/DocsSearchCommand.tsx +69 -104
  48. package/src/viewer/vite-plugin.ts +76 -1
  49. package/src/viewer/webmcp/__tests__/analytics.test.ts +108 -0
  50. package/src/viewer/webmcp/analytics.ts +165 -0
  51. package/src/viewer/webmcp/index.ts +3 -0
  52. package/src/viewer/webmcp/posthog-bridge.ts +39 -0
  53. package/src/viewer/webmcp/runtime-tools.ts +152 -0
  54. package/src/viewer/webmcp/scan-utils.ts +135 -0
  55. package/src/viewer/webmcp/use-tool-analytics.ts +69 -0
  56. package/src/viewer/webmcp/viewer-state.ts +45 -0
  57. package/dist/chunk-TQOGBAOZ.js.map +0 -1
  58. package/dist/init-GID2DXB3.js +0 -498
  59. package/dist/init-GID2DXB3.js.map +0 -1
  60. package/dist/viewer-CNLZQUFO.js.map +0 -1
  61. package/src/viewer/components/StoryRenderer.tsx +0 -121
  62. /package/dist/{chunk-CRTN6BIW.js.map → chunk-QLTLLQBI.js.map} +0 -0
  63. /package/dist/{generate-ZPERYZLF.js.map → generate-ICIPKCKV.js.map} +0 -0
  64. /package/dist/{scan-BSMLGBX4.js.map → scan-X3DI2X5G.js.map} +0 -0
  65. /package/dist/{service-QACVPR37.js.map → service-JEWWTSKI.js.map} +0 -0
  66. /package/dist/{static-viewer-2RQD5QLR.js.map → static-viewer-JIWCYKVK.js.map} +0 -0
  67. /package/dist/{tokens-A3BZIQPB.js.map → tokens-K2AGUUOJ.js.map} +0 -0
@@ -11,149 +11,138 @@ import { Skeleton, Loading } from '@fragments-sdk/ui';
11
11
  */
12
12
  export function AppSkeleton() {
13
13
  return (
14
- <div style={{ display: 'flex', height: '100vh', backgroundColor: 'var(--bg-primary)' }}>
15
- {/* Sidebar skeleton */}
16
- <div style={{
17
- width: '240px',
18
- borderRight: '1px solid var(--border)',
19
- backgroundColor: 'var(--bg-secondary)',
20
- display: 'flex',
21
- flexDirection: 'column',
22
- }}>
23
- {/* Header */}
24
- <div style={{
14
+ <div
15
+ style={{
16
+ display: 'grid',
17
+ minHeight: '100vh',
18
+ minHeight: '100dvh',
19
+ gridTemplateRows: '56px 1fr',
20
+ gridTemplateColumns: '260px 1fr 240px',
21
+ gridTemplateAreas: '"header header header" "sidebar main aside"',
22
+ backgroundColor: 'var(--bg-primary)',
23
+ }}
24
+ >
25
+ <div
26
+ style={{
27
+ gridArea: 'header',
25
28
  display: 'flex',
26
29
  alignItems: 'center',
27
30
  justifyContent: 'space-between',
28
- padding: '8px 16px',
31
+ gap: '16px',
32
+ padding: '0 16px',
29
33
  borderBottom: '1px solid var(--border)',
30
- }}>
31
- <Skeleton variant="text" style={{ width: '80px' }} />
32
- <Skeleton variant="circular" style={{ width: '24px', height: '24px' }} />
33
- </div>
34
-
35
- {/* Search */}
36
- <div style={{ padding: '12px' }}>
37
- <Skeleton variant="rectangular" style={{ width: '100%', height: '32px', borderRadius: '6px' }} />
38
- </div>
39
-
40
- {/* Component list */}
41
- <div style={{ flex: 1, padding: '0 8px', overflow: 'hidden' }}>
42
- {/* Category 1 */}
43
- <div style={{ marginBottom: '16px' }}>
44
- <Skeleton variant="text" style={{ width: '64px', margin: '0 8px 8px' }} />
45
- <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
46
- <Skeleton variant="rectangular" style={{ width: '100%', height: '28px', borderRadius: '6px' }} />
47
- <Skeleton variant="rectangular" style={{ width: '100%', height: '28px', borderRadius: '6px' }} />
48
- <Skeleton variant="rectangular" style={{ width: '75%', height: '28px', borderRadius: '6px' }} />
49
- </div>
50
- </div>
51
-
52
- {/* Category 2 */}
53
- <div style={{ marginBottom: '16px' }}>
54
- <Skeleton variant="text" style={{ width: '80px', margin: '0 8px 8px' }} />
55
- <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
56
- <Skeleton variant="rectangular" style={{ width: '100%', height: '28px', borderRadius: '6px' }} />
57
- <Skeleton variant="rectangular" style={{ width: '83%', height: '28px', borderRadius: '6px' }} />
58
- <Skeleton variant="rectangular" style={{ width: '100%', height: '28px', borderRadius: '6px' }} />
59
- <Skeleton variant="rectangular" style={{ width: '66%', height: '28px', borderRadius: '6px' }} />
60
- </div>
61
- </div>
62
-
63
- {/* Category 3 */}
64
- <div>
65
- <Skeleton variant="text" style={{ width: '96px', margin: '0 8px 8px' }} />
66
- <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
67
- <Skeleton variant="rectangular" style={{ width: '80%', height: '28px', borderRadius: '6px' }} />
68
- <Skeleton variant="rectangular" style={{ width: '100%', height: '28px', borderRadius: '6px' }} />
69
- </div>
70
- </div>
34
+ backgroundColor: 'var(--bg-primary)',
35
+ }}
36
+ >
37
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
38
+ <Skeleton.Circle size={20} />
39
+ <Skeleton variant="text" width={96} />
40
+ <Skeleton variant="text" width={64} />
71
41
  </div>
72
-
73
- {/* Footer */}
74
- <div style={{ padding: '12px 16px', borderTop: '1px solid var(--border-subtle)' }}>
75
- <Skeleton variant="text" style={{ width: '96px' }} />
42
+ <Skeleton variant="rect" width={240} height={32} radius="md" />
43
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
44
+ <Skeleton variant="rect" width={64} height={28} radius="md" />
45
+ <Skeleton.Circle size={20} />
46
+ <Skeleton.Circle size={20} />
47
+ <Skeleton.Circle size={20} />
76
48
  </div>
77
49
  </div>
78
50
 
79
- {/* Main content skeleton */}
80
- <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
81
- {/* Toolbar */}
82
- <div style={{
51
+ <aside
52
+ style={{
53
+ gridArea: 'sidebar',
54
+ borderRight: '1px solid var(--border)',
55
+ backgroundColor: 'var(--bg-primary)',
83
56
  display: 'flex',
84
- alignItems: 'center',
85
- justifyContent: 'space-between',
86
- padding: '8px 16px',
87
- borderBottom: '1px solid var(--border)',
88
- backgroundColor: 'var(--bg-secondary)',
89
- }}>
90
- <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
91
- <Skeleton variant="text" style={{ width: '96px', height: '20px' }} />
92
- <Skeleton variant="text" style={{ width: '64px', height: '16px' }} />
93
- </div>
94
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
95
- <Skeleton variant="rectangular" style={{ width: '64px', height: '28px', borderRadius: '4px' }} />
96
- <Skeleton variant="rectangular" style={{ width: '96px', height: '28px', borderRadius: '4px' }} />
97
- <Skeleton variant="rectangular" style={{ width: '80px', height: '28px', borderRadius: '4px' }} />
98
- <Skeleton variant="circular" style={{ width: '24px', height: '24px' }} />
99
- <Skeleton variant="circular" style={{ width: '24px', height: '24px' }} />
100
- </div>
57
+ flexDirection: 'column',
58
+ minHeight: 0,
59
+ }}
60
+ >
61
+ <div style={{ padding: '12px 16px' }}>
62
+ <Skeleton variant="rect" height={32} radius="md" />
101
63
  </div>
102
-
103
- {/* Variant tabs */}
104
- <div style={{
105
- padding: '8px 16px',
106
- borderBottom: '1px solid var(--border)',
107
- backgroundColor: 'var(--bg-primary)',
108
- }}>
109
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
110
- <Skeleton variant="rectangular" style={{ width: '64px', height: '28px', borderRadius: '6px' }} />
111
- <Skeleton variant="rectangular" style={{ width: '80px', height: '28px', borderRadius: '6px' }} />
112
- <Skeleton variant="rectangular" style={{ width: '56px', height: '28px', borderRadius: '6px' }} />
113
- <Skeleton variant="rectangular" style={{ width: '72px', height: '28px', borderRadius: '6px' }} />
114
- <Skeleton variant="rectangular" style={{ width: '48px', height: '28px', borderRadius: '6px' }} />
115
- </div>
64
+ <div style={{ padding: '0 12px', display: 'flex', flexDirection: 'column', gap: '12px', overflow: 'hidden' }}>
65
+ <Skeleton variant="text" width={68} />
66
+ <Skeleton variant="rect" height={30} radius="md" />
67
+ <Skeleton variant="rect" height={30} radius="md" />
68
+ <Skeleton variant="rect" height={30} radius="md" />
69
+ <Skeleton variant="text" width={84} />
70
+ <Skeleton variant="rect" height={30} radius="md" />
71
+ <Skeleton variant="rect" height={30} radius="md" />
72
+ <Skeleton variant="rect" width="78%" height={30} radius="md" />
116
73
  </div>
117
-
118
- {/* Preview area */}
119
- <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '32px' }}>
120
- <Skeleton variant="rectangular" style={{ width: '256px', height: '128px', borderRadius: '8px' }} />
74
+ <div style={{ marginTop: 'auto', padding: '12px 16px', borderTop: '1px solid var(--border-subtle)' }}>
75
+ <Skeleton variant="text" width={92} />
121
76
  </div>
77
+ </aside>
122
78
 
123
- {/* Bottom panel */}
124
- <div style={{
125
- height: '256px',
126
- borderTop: '1px solid var(--border)',
127
- backgroundColor: 'var(--bg-secondary)',
128
- }}>
129
- <div style={{
130
- display: 'flex',
131
- alignItems: 'center',
132
- gap: '4px',
133
- padding: '0 16px',
134
- height: '40px',
135
- borderBottom: '1px solid var(--border-subtle)',
136
- }}>
137
- <Skeleton variant="rectangular" style={{ width: '48px', height: '24px', borderRadius: '4px' }} />
138
- <Skeleton variant="rectangular" style={{ width: '40px', height: '24px', borderRadius: '4px' }} />
139
- <Skeleton variant="rectangular" style={{ width: '48px', height: '24px', borderRadius: '4px' }} />
140
- </div>
141
- <div style={{ padding: '16px', display: 'flex', flexDirection: 'column', gap: '12px' }}>
142
- <div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
143
- <Skeleton variant="text" style={{ width: '80px' }} />
144
- <Skeleton variant="rectangular" style={{ width: '128px', height: '32px', borderRadius: '4px' }} />
79
+ <main
80
+ style={{
81
+ gridArea: 'main',
82
+ display: 'flex',
83
+ flexDirection: 'column',
84
+ minWidth: 0,
85
+ minHeight: 0,
86
+ backgroundColor: 'var(--bg-primary)',
87
+ }}
88
+ >
89
+ <div style={{ flex: 1, padding: '20px', overflow: 'hidden' }}>
90
+ <div
91
+ style={{
92
+ border: '1px solid var(--border)',
93
+ borderRadius: '10px',
94
+ overflow: 'hidden',
95
+ marginBottom: '16px',
96
+ }}
97
+ >
98
+ <div style={{ padding: '12px 14px', borderBottom: '1px solid var(--border-subtle)', backgroundColor: 'var(--bg-secondary)', display: 'flex', gap: '10px' }}>
99
+ <Skeleton variant="text" width={84} />
100
+ <Skeleton variant="text" width={120} />
101
+ </div>
102
+ <div style={{ padding: '24px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
103
+ <Skeleton variant="rect" width={280} height={120} radius="lg" />
145
104
  </div>
146
- <div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
147
- <Skeleton variant="text" style={{ width: '64px' }} />
148
- <Skeleton variant="rectangular" style={{ width: '96px', height: '32px', borderRadius: '4px' }} />
105
+ </div>
106
+
107
+ <div
108
+ style={{
109
+ border: '1px solid var(--border)',
110
+ borderRadius: '10px',
111
+ overflow: 'hidden',
112
+ }}
113
+ >
114
+ <div style={{ height: '40px', display: 'flex', alignItems: 'center', gap: '6px', padding: '0 14px', borderBottom: '1px solid var(--border-subtle)', backgroundColor: 'var(--bg-secondary)' }}>
115
+ <Skeleton variant="rect" width={52} height={22} radius="md" />
116
+ <Skeleton variant="rect" width={88} height={22} radius="md" />
117
+ <Skeleton variant="rect" width={58} height={22} radius="md" />
149
118
  </div>
150
- <div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
151
- <Skeleton variant="text" style={{ width: '96px' }} />
152
- <Skeleton variant="rectangular" style={{ width: '80px', height: '32px', borderRadius: '4px' }} />
119
+ <div style={{ padding: '16px' }}>
120
+ <Skeleton.Text lines={4} lastLineWidth={72} />
153
121
  </div>
154
122
  </div>
155
123
  </div>
156
- </div>
124
+ </main>
125
+
126
+ <aside
127
+ style={{
128
+ gridArea: 'aside',
129
+ borderLeft: '1px solid var(--border)',
130
+ backgroundColor: 'var(--bg-primary)',
131
+ padding: '16px 14px',
132
+ }}
133
+ >
134
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
135
+ <Skeleton variant="text" width={92} />
136
+ <Skeleton variant="text" width={64} />
137
+ <Skeleton variant="text" width={48} />
138
+ <Skeleton variant="text" width={76} />
139
+ <Skeleton variant="rect" height={1} />
140
+ <Skeleton variant="text" width={86} />
141
+ <Skeleton variant="rect" width="100%" height={26} radius="md" />
142
+ <Skeleton variant="rect" width="84%" height={26} radius="md" />
143
+ <Skeleton variant="rect" width="70%" height={26} radius="md" />
144
+ </div>
145
+ </aside>
157
146
  </div>
158
147
  );
159
148
  }
@@ -14,7 +14,7 @@ import { useState, useMemo, useRef, useCallback } from "react";
14
14
  import { useVirtualizer } from "@tanstack/react-virtual";
15
15
  import type { FragmentVariant } from "../../core/index.js";
16
16
  import { ErrorBoundary } from "./ErrorBoundary.js";
17
- import { StoryRenderer, LoaderIndicator } from "./StoryRenderer.js";
17
+ import { FragmentRenderer, LoaderIndicator } from "./FragmentRenderer.js";
18
18
  import { IsolatedPreviewFrame } from "./IsolatedPreviewFrame.js";
19
19
  import { ChevronDownIcon } from "./Icons.js";
20
20
 
@@ -389,7 +389,7 @@ function VariantCard({
389
389
  </div>
390
390
  }
391
391
  >
392
- <StoryRenderer variant={variant}>
392
+ <FragmentRenderer variant={variant}>
393
393
  {(content, isLoading, error) => {
394
394
  if (isLoading) {
395
395
  return (
@@ -407,7 +407,7 @@ function VariantCard({
407
407
  }
408
408
  return content;
409
409
  }}
410
- </StoryRenderer>
410
+ </FragmentRenderer>
411
411
  </ErrorBoundary>
412
412
  </div>
413
413
  )}
@@ -0,0 +1,52 @@
1
+ import { useEffect } from 'react';
2
+ import { setViewerState } from '../webmcp/viewer-state.js';
3
+ import { useUrlState } from '../hooks/useUrlState.js';
4
+ import { useAppState } from '../hooks/useAppState.js';
5
+ import { useViewSettings } from '../hooks/useViewSettings.js';
6
+ import { useTheme } from './ThemeProvider.js';
7
+ import { BRAND, type FragmentDefinition } from '../../core/index.js';
8
+
9
+ interface ViewerStateSyncProps {
10
+ fragments: Array<{ path: string; fragment: FragmentDefinition }>;
11
+ activeVariantIndex: number;
12
+ }
13
+
14
+ export function ViewerStateSync({ fragments, activeVariantIndex }: ViewerStateSyncProps) {
15
+ const { state: urlState } = useUrlState();
16
+ const { state: uiState } = useAppState();
17
+ const viewSettings = useViewSettings();
18
+ const { resolvedTheme } = useTheme();
19
+
20
+ useEffect(() => {
21
+ const activeFragment = urlState.component
22
+ ? fragments.find(f => f.fragment.meta.name.toLowerCase() === urlState.component!.toLowerCase())
23
+ : null;
24
+
25
+ const variants = activeFragment?.fragment.variants ?? [];
26
+
27
+ setViewerState({
28
+ currentComponent: activeFragment?.fragment.meta.name ?? null,
29
+ currentVariant: variants[activeVariantIndex]?.name ?? null,
30
+ variantIndex: activeVariantIndex,
31
+ totalVariants: variants.length,
32
+ viewport: viewSettings.viewport,
33
+ zoom: viewSettings.zoom,
34
+ theme: resolvedTheme,
35
+ panels: {
36
+ activePanel: uiState.activePanel,
37
+ panelOpen: uiState.panelOpen,
38
+ },
39
+ viewMode: {
40
+ matrixView: uiState.showMatrixView,
41
+ multiViewport: uiState.showMultiViewport,
42
+ comparison: uiState.showComparison,
43
+ },
44
+ designSystem: {
45
+ name: BRAND.name,
46
+ componentCount: fragments.length,
47
+ },
48
+ });
49
+ }, [urlState, uiState, viewSettings, resolvedTheme, fragments, activeVariantIndex]);
50
+
51
+ return null;
52
+ }