@fragments-sdk/cli 0.7.0 → 0.7.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.
- package/dist/bin.js +245 -245
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-XHUDJNN3.js → chunk-32VIEOQY.js} +18 -18
- package/dist/chunk-32VIEOQY.js.map +1 -0
- package/dist/{chunk-CVXKXVOY.js → chunk-5ITIP3ES.js} +27 -27
- package/dist/chunk-5ITIP3ES.js.map +1 -0
- package/dist/{chunk-RVRTRESS.js → chunk-DQHWLAUV.js} +29 -29
- package/dist/chunk-DQHWLAUV.js.map +1 -0
- package/dist/{chunk-TJ34N7C7.js → chunk-GCZMFLDI.js} +30 -32
- package/dist/chunk-GCZMFLDI.js.map +1 -0
- package/dist/{chunk-6JBGU74P.js → chunk-GHYYFAQN.js} +23 -23
- package/dist/chunk-GHYYFAQN.js.map +1 -0
- package/dist/{chunk-NWQ4CJOQ.js → chunk-GKX2HPZ6.js} +40 -40
- package/dist/chunk-GKX2HPZ6.js.map +1 -0
- package/dist/{chunk-7OPWMLOE.js → chunk-U6VTHBNI.js} +110 -110
- package/dist/chunk-U6VTHBNI.js.map +1 -0
- package/dist/{core-W2HYIQW6.js → core-SFHPYR5H.js} +24 -26
- package/dist/{generate-LMTISDIJ.js → generate-54GJAWUY.js} +5 -5
- package/dist/generate-54GJAWUY.js.map +1 -0
- package/dist/index.d.ts +23 -27
- package/dist/index.js +10 -10
- package/dist/{init-7CHRKQ7P.js → init-EIM5WNMP.js} +5 -5
- package/dist/{init-7CHRKQ7P.js.map → init-EIM5WNMP.js.map} +1 -1
- package/dist/mcp-bin.js +73 -73
- package/dist/mcp-bin.js.map +1 -1
- package/dist/scan-KQBKUS64.js +12 -0
- package/dist/{service-T2L7VLTE.js → service-ED2LNCTU.js} +6 -6
- package/dist/{static-viewer-GBR7YNF3.js → static-viewer-Q4F4QP5M.js} +4 -4
- package/dist/{test-OJRXNDO2.js → test-6VN2DA3S.js} +19 -19
- package/dist/test-6VN2DA3S.js.map +1 -0
- package/dist/{tokens-3BWDESVM.js → tokens-P2B7ZAM3.js} +5 -5
- package/dist/{viewer-SUFOISZM.js → viewer-GM7IQPPB.js} +199 -199
- package/dist/viewer-GM7IQPPB.js.map +1 -0
- package/package.json +2 -2
- package/src/ai.ts +5 -5
- package/src/analyze.ts +11 -11
- package/src/bin.ts +1 -1
- package/src/build.ts +33 -33
- package/src/commands/a11y.ts +6 -6
- package/src/commands/add.ts +11 -11
- package/src/commands/audit.ts +4 -4
- package/src/commands/baseline.ts +3 -3
- package/src/commands/build.ts +8 -8
- package/src/commands/compare.ts +20 -20
- package/src/commands/context.ts +16 -16
- package/src/commands/enhance.ts +36 -36
- package/src/commands/generate.ts +1 -1
- package/src/commands/graph.ts +3 -3
- package/src/commands/init.ts +1 -1
- package/src/commands/link/figma.ts +82 -82
- package/src/commands/link/index.ts +3 -3
- package/src/commands/link/storybook.ts +9 -9
- package/src/commands/list.ts +2 -2
- package/src/commands/reset.ts +15 -15
- package/src/commands/scan.ts +27 -27
- package/src/commands/storygen.ts +24 -24
- package/src/commands/validate.ts +2 -2
- package/src/commands/verify.ts +8 -8
- package/src/core/auto-props.ts +4 -4
- package/src/core/composition.test.ts +36 -36
- package/src/core/composition.ts +19 -19
- package/src/core/config.ts +6 -6
- package/src/core/{defineSegment.ts → defineFragment.ts} +16 -22
- package/src/core/discovery.ts +6 -6
- package/src/core/figma.ts +2 -2
- package/src/core/graph-extractor.test.ts +77 -77
- package/src/core/graph-extractor.ts +32 -32
- package/src/core/importAnalyzer.ts +1 -1
- package/src/core/index.ts +22 -23
- package/src/core/loader.ts +22 -22
- package/src/core/node.ts +5 -5
- package/src/core/parser.ts +31 -31
- package/src/core/previewLoader.ts +1 -1
- package/src/core/schema.ts +16 -16
- package/src/core/storyAdapter.test.ts +87 -87
- package/src/core/storyAdapter.ts +16 -16
- package/src/core/types.ts +21 -26
- package/src/diff.ts +22 -22
- package/src/index.ts +2 -2
- package/src/mcp/server.ts +80 -80
- package/src/migrate/__tests__/utils/utils.test.ts +3 -3
- package/src/migrate/bin.ts +4 -4
- package/src/migrate/converter.ts +16 -16
- package/src/migrate/index.ts +3 -3
- package/src/migrate/migrate.ts +3 -3
- package/src/migrate/parser.ts +8 -8
- package/src/migrate/report.ts +2 -2
- package/src/migrate/types.ts +4 -4
- package/src/screenshot.ts +22 -22
- package/src/service/__tests__/props-extractor.test.ts +15 -15
- package/src/service/analytics.ts +39 -39
- package/src/service/enhance/codebase-scanner.ts +1 -1
- package/src/service/enhance/index.ts +1 -1
- package/src/service/enhance/props-extractor.ts +2 -2
- package/src/service/enhance/types.ts +2 -2
- package/src/service/index.ts +2 -2
- package/src/service/metrics-store.ts +1 -1
- package/src/service/patch-generator.ts +1 -1
- package/src/setup.ts +52 -52
- package/src/shared/dev-server-client.ts +7 -7
- package/src/shared/fragment-loader.ts +59 -0
- package/src/shared/index.ts +1 -1
- package/src/shared/types.ts +4 -4
- package/src/static-viewer.ts +35 -35
- package/src/test/discovery.ts +6 -6
- package/src/test/index.ts +5 -5
- package/src/test/reporters/console.ts +1 -1
- package/src/test/reporters/junit.ts +1 -1
- package/src/test/runner.ts +7 -7
- package/src/test/types.ts +3 -3
- package/src/test/watch.ts +9 -9
- package/src/validators.ts +26 -26
- package/src/viewer/__tests__/render-utils.test.ts +28 -28
- package/src/viewer/__tests__/viewer-integration.test.ts +4 -4
- package/src/viewer/cli/health.ts +26 -26
- package/src/viewer/components/App.tsx +79 -79
- package/src/viewer/components/BottomPanel.tsx +17 -17
- package/src/viewer/components/CodePanel.tsx +3 -3
- package/src/viewer/components/CommandPalette.tsx +11 -11
- package/src/viewer/components/ComponentGraph.tsx +28 -28
- package/src/viewer/components/ComponentHeader.tsx +2 -2
- package/src/viewer/components/ContractPanel.tsx +6 -6
- package/src/viewer/components/FigmaEmbed.tsx +9 -9
- package/src/viewer/components/HealthDashboard.tsx +17 -17
- package/src/viewer/components/InteractionsPanel.tsx +2 -2
- package/src/viewer/components/IsolatedPreviewFrame.tsx +6 -6
- package/src/viewer/components/IsolatedRender.tsx +10 -10
- package/src/viewer/components/LeftSidebar.tsx +28 -28
- package/src/viewer/components/MultiViewportPreview.tsx +14 -14
- package/src/viewer/components/PreviewArea.tsx +11 -11
- package/src/viewer/components/PreviewFrameHost.tsx +51 -51
- package/src/viewer/components/RightSidebar.tsx +9 -9
- package/src/viewer/components/Sidebar.tsx +17 -17
- package/src/viewer/components/StoryRenderer.tsx +2 -2
- package/src/viewer/components/TokenStylePanel.tsx +1 -1
- package/src/viewer/components/UsageSection.tsx +2 -2
- package/src/viewer/components/VariantMatrix.tsx +11 -11
- package/src/viewer/components/VariantRenderer.tsx +3 -3
- package/src/viewer/components/VariantTabs.tsx +2 -2
- package/src/viewer/components/_future/CreatePage.tsx +6 -6
- package/src/viewer/composition-renderer.ts +11 -11
- package/src/viewer/entry.tsx +40 -40
- package/src/viewer/hooks/useFigmaIntegration.ts +1 -1
- package/src/viewer/hooks/usePreviewBridge.ts +5 -5
- package/src/viewer/hooks/useUrlState.ts +6 -6
- package/src/viewer/index.ts +2 -2
- package/src/viewer/intelligence/healthReport.ts +17 -17
- package/src/viewer/intelligence/styleDrift.ts +1 -1
- package/src/viewer/intelligence/usageScanner.ts +1 -1
- package/src/viewer/render-template.html +1 -1
- package/src/viewer/render-utils.ts +21 -21
- package/src/viewer/server.ts +18 -18
- package/src/viewer/utils/detectRelationships.ts +22 -22
- package/src/viewer/vite-plugin.ts +213 -213
- package/dist/chunk-6JBGU74P.js.map +0 -1
- package/dist/chunk-7OPWMLOE.js.map +0 -1
- package/dist/chunk-CVXKXVOY.js.map +0 -1
- package/dist/chunk-NWQ4CJOQ.js.map +0 -1
- package/dist/chunk-RVRTRESS.js.map +0 -1
- package/dist/chunk-TJ34N7C7.js.map +0 -1
- package/dist/chunk-XHUDJNN3.js.map +0 -1
- package/dist/generate-LMTISDIJ.js.map +0 -1
- package/dist/scan-WY23TJCP.js +0 -12
- package/dist/test-OJRXNDO2.js.map +0 -1
- package/dist/viewer-SUFOISZM.js.map +0 -1
- package/src/shared/segment-loader.ts +0 -59
- /package/dist/{core-W2HYIQW6.js.map → core-SFHPYR5H.js.map} +0 -0
- /package/dist/{scan-WY23TJCP.js.map → scan-KQBKUS64.js.map} +0 -0
- /package/dist/{service-T2L7VLTE.js.map → service-ED2LNCTU.js.map} +0 -0
- /package/dist/{static-viewer-GBR7YNF3.js.map → static-viewer-Q4F4QP5M.js.map} +0 -0
- /package/dist/{tokens-3BWDESVM.js.map → tokens-P2B7ZAM3.js.map} +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { useState, useMemo, useEffect, useCallback, useRef, type RefObject } from "react";
|
|
7
|
-
import { BRAND, type
|
|
7
|
+
import { BRAND, type FragmentDefinition } from "../../core/index.js";
|
|
8
8
|
|
|
9
9
|
// Layout & Navigation
|
|
10
10
|
import { Layout } from "./Layout.js";
|
|
@@ -39,7 +39,7 @@ import { useViewSettings } from "../hooks/useViewSettings.js";
|
|
|
39
39
|
import { useFigmaIntegration } from "../hooks/useFigmaIntegration.js";
|
|
40
40
|
import { useKeyboardShortcuts } from "../hooks/useKeyboardShortcuts.js";
|
|
41
41
|
import { useActions } from "../hooks/useActions.js";
|
|
42
|
-
import { useUrlState,
|
|
42
|
+
import { useUrlState, findFragmentByName, findVariantIndex } from "../hooks/useUrlState.js";
|
|
43
43
|
import { usePanelDock } from "./ResizablePanel.js";
|
|
44
44
|
import { useTheme } from "./ThemeProvider.js";
|
|
45
45
|
|
|
@@ -47,10 +47,10 @@ import { useTheme } from "./ThemeProvider.js";
|
|
|
47
47
|
import { ScreenshotButton } from "./ScreenshotButton.js";
|
|
48
48
|
|
|
49
49
|
interface AppProps {
|
|
50
|
-
|
|
50
|
+
fragments: Array<{ path: string; fragment: FragmentDefinition }>;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export function App({
|
|
53
|
+
export function App({ fragments }: AppProps) {
|
|
54
54
|
// URL state management
|
|
55
55
|
const { state: urlState, setComponent: setUrlComponent, setVariant: setUrlVariant, setViewSettings: setUrlViewSettings, copyUrl } = useUrlState();
|
|
56
56
|
|
|
@@ -84,18 +84,18 @@ export function App({ segments }: AppProps) {
|
|
|
84
84
|
const { info, success } = useToast();
|
|
85
85
|
|
|
86
86
|
// Navigation state
|
|
87
|
-
const [
|
|
87
|
+
const [activeFragmentPath, setActiveFragmentPath] = useState<string | null>(() => {
|
|
88
88
|
if (urlState.component) {
|
|
89
|
-
const found =
|
|
90
|
-
return found?.path ??
|
|
89
|
+
const found = findFragmentByName(fragments, urlState.component);
|
|
90
|
+
return found?.path ?? fragments[0]?.path ?? null;
|
|
91
91
|
}
|
|
92
|
-
return
|
|
92
|
+
return fragments[0]?.path ?? null;
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
const [activeVariantIndex, setActiveVariantIndex] = useState<number>(() => {
|
|
96
|
-
const
|
|
97
|
-
if (urlState.variant &&
|
|
98
|
-
return findVariantIndex(
|
|
96
|
+
const fragment = fragments.find(s => s.path === activeFragmentPath);
|
|
97
|
+
if (urlState.variant && fragment?.fragment.variants) {
|
|
98
|
+
return findVariantIndex(fragment.fragment.variants, urlState.variant);
|
|
99
99
|
}
|
|
100
100
|
return 0;
|
|
101
101
|
});
|
|
@@ -103,18 +103,18 @@ export function App({ segments }: AppProps) {
|
|
|
103
103
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
|
104
104
|
|
|
105
105
|
// Derived values
|
|
106
|
-
const
|
|
107
|
-
() =>
|
|
108
|
-
[
|
|
106
|
+
const activeFragment = useMemo(
|
|
107
|
+
() => fragments.find((s) => s.path === activeFragmentPath),
|
|
108
|
+
[fragments, activeFragmentPath]
|
|
109
109
|
);
|
|
110
|
-
const activeVariant =
|
|
111
|
-
const figmaUrl = activeVariant?.figma ||
|
|
110
|
+
const activeVariant = activeFragment?.fragment.variants?.[activeVariantIndex];
|
|
111
|
+
const figmaUrl = activeVariant?.figma || activeFragment?.fragment.meta.figma;
|
|
112
112
|
|
|
113
113
|
// Figma integration
|
|
114
114
|
const figmaIntegration = useFigmaIntegration({
|
|
115
115
|
figmaUrl,
|
|
116
116
|
showComparison: uiState.showComparison,
|
|
117
|
-
dependencies: [
|
|
117
|
+
dependencies: [activeFragmentPath, activeVariantIndex],
|
|
118
118
|
});
|
|
119
119
|
|
|
120
120
|
// Actions logging
|
|
@@ -123,12 +123,12 @@ export function App({ segments }: AppProps) {
|
|
|
123
123
|
useActionsRef.current = { logAction };
|
|
124
124
|
|
|
125
125
|
// Figma URLs for preloading
|
|
126
|
-
const allFigmaUrls = useAllFigmaUrls(
|
|
126
|
+
const allFigmaUrls = useAllFigmaUrls(activeFragment?.fragment);
|
|
127
127
|
|
|
128
128
|
// Reset action logs on variant change
|
|
129
129
|
useEffect(() => {
|
|
130
130
|
clearActionLogs();
|
|
131
|
-
}, [
|
|
131
|
+
}, [activeFragmentPath, activeVariantIndex, clearActionLogs]);
|
|
132
132
|
|
|
133
133
|
// Extract rendered styles after component renders
|
|
134
134
|
useEffect(() => {
|
|
@@ -141,14 +141,14 @@ export function App({ segments }: AppProps) {
|
|
|
141
141
|
// Sync URL state on browser navigation
|
|
142
142
|
useEffect(() => {
|
|
143
143
|
if (urlState.component) {
|
|
144
|
-
const found =
|
|
145
|
-
if (found && found.path !==
|
|
146
|
-
|
|
147
|
-
const variantIndex = findVariantIndex(found.
|
|
144
|
+
const found = findFragmentByName(fragments, urlState.component);
|
|
145
|
+
if (found && found.path !== activeFragmentPath) {
|
|
146
|
+
setActiveFragmentPath(found.path);
|
|
147
|
+
const variantIndex = findVariantIndex(found.fragment.variants, urlState.variant);
|
|
148
148
|
setActiveVariantIndex(variantIndex);
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
|
-
}, [urlState.component, urlState.variant,
|
|
151
|
+
}, [urlState.component, urlState.variant, fragments, activeFragmentPath]);
|
|
152
152
|
|
|
153
153
|
// HMR toast notifications
|
|
154
154
|
useEffect(() => {
|
|
@@ -167,22 +167,22 @@ export function App({ segments }: AppProps) {
|
|
|
167
167
|
}, [info]);
|
|
168
168
|
|
|
169
169
|
// Navigation handlers
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
const componentName =
|
|
173
|
-
const firstVariant =
|
|
170
|
+
const handleSelectFragment = useCallback((path: string) => {
|
|
171
|
+
const fragment = fragments.find((s) => s.path === path);
|
|
172
|
+
const componentName = fragment?.fragment.meta.name || path;
|
|
173
|
+
const firstVariant = fragment?.fragment.variants?.[0]?.name;
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
setActiveFragmentPath(path);
|
|
176
176
|
setActiveVariantIndex(0);
|
|
177
177
|
uiActions.setHealthDashboard(false);
|
|
178
178
|
setUrlComponent(componentName, firstVariant);
|
|
179
|
-
}, [
|
|
179
|
+
}, [fragments, setUrlComponent, uiActions]);
|
|
180
180
|
|
|
181
181
|
const handleSelectVariant = useCallback((index: number) => {
|
|
182
|
-
const variantName =
|
|
182
|
+
const variantName = activeFragment?.fragment.variants?.[index]?.name;
|
|
183
183
|
setActiveVariantIndex(index);
|
|
184
184
|
setUrlVariant(variantName || null);
|
|
185
|
-
}, [
|
|
185
|
+
}, [activeFragment, setUrlVariant]);
|
|
186
186
|
|
|
187
187
|
// Copy link handler
|
|
188
188
|
const handleCopyLink = useCallback(async () => {
|
|
@@ -199,27 +199,27 @@ export function App({ segments }: AppProps) {
|
|
|
199
199
|
searchInputRef.current?.select();
|
|
200
200
|
}, []);
|
|
201
201
|
|
|
202
|
-
// Sorted
|
|
203
|
-
const
|
|
204
|
-
return [...
|
|
205
|
-
.filter(s => s.
|
|
206
|
-
.sort((a, b) => a.
|
|
202
|
+
// Sorted fragment paths for keyboard navigation
|
|
203
|
+
const sortedFragmentPaths = useMemo(() => {
|
|
204
|
+
return [...fragments]
|
|
205
|
+
.filter(s => s.fragment?.meta?.name)
|
|
206
|
+
.sort((a, b) => a.fragment.meta.name.localeCompare(b.fragment.meta.name))
|
|
207
207
|
.map(s => s.path);
|
|
208
|
-
}, [
|
|
208
|
+
}, [fragments]);
|
|
209
209
|
|
|
210
|
-
const
|
|
211
|
-
const variantCount =
|
|
210
|
+
const currentFragmentIndex = sortedFragmentPaths.indexOf(activeFragmentPath || '');
|
|
211
|
+
const variantCount = activeFragment?.fragment.variants?.length || 0;
|
|
212
212
|
|
|
213
213
|
// Keyboard shortcuts
|
|
214
214
|
useKeyboardShortcuts(
|
|
215
215
|
{
|
|
216
216
|
nextComponent: () => {
|
|
217
|
-
const nextIndex =
|
|
218
|
-
|
|
217
|
+
const nextIndex = currentFragmentIndex < sortedFragmentPaths.length - 1 ? currentFragmentIndex + 1 : 0;
|
|
218
|
+
handleSelectFragment(sortedFragmentPaths[nextIndex]);
|
|
219
219
|
},
|
|
220
220
|
prevComponent: () => {
|
|
221
|
-
const prevIndex =
|
|
222
|
-
|
|
221
|
+
const prevIndex = currentFragmentIndex > 0 ? currentFragmentIndex - 1 : sortedFragmentPaths.length - 1;
|
|
222
|
+
handleSelectFragment(sortedFragmentPaths[prevIndex]);
|
|
223
223
|
},
|
|
224
224
|
nextVariant: () => handleSelectVariant(activeVariantIndex < variantCount - 1 ? activeVariantIndex + 1 : 0),
|
|
225
225
|
prevVariant: () => handleSelectVariant(activeVariantIndex > 0 ? activeVariantIndex - 1 : variantCount - 1),
|
|
@@ -269,7 +269,7 @@ export function App({ segments }: AppProps) {
|
|
|
269
269
|
}, []);
|
|
270
270
|
|
|
271
271
|
if (isIsolated) {
|
|
272
|
-
return <IsolatedRender
|
|
272
|
+
return <IsolatedRender fragments={fragments} />;
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
return (
|
|
@@ -278,19 +278,19 @@ export function App({ segments }: AppProps) {
|
|
|
278
278
|
<CommandPalette
|
|
279
279
|
isOpen={uiState.showCommandPalette}
|
|
280
280
|
onClose={() => uiActions.setCommandPalette(false)}
|
|
281
|
-
|
|
282
|
-
onSelectComponent={
|
|
281
|
+
fragments={fragments}
|
|
282
|
+
onSelectComponent={handleSelectFragment}
|
|
283
283
|
onSelectVariant={(path, variantIndex) => {
|
|
284
|
-
|
|
284
|
+
handleSelectFragment(path);
|
|
285
285
|
setTimeout(() => handleSelectVariant(variantIndex), 0);
|
|
286
286
|
}}
|
|
287
287
|
/>
|
|
288
288
|
|
|
289
289
|
<Layout
|
|
290
290
|
header={
|
|
291
|
-
|
|
291
|
+
activeFragment && !uiState.showHealthDashboard ? (
|
|
292
292
|
<TopToolbar
|
|
293
|
-
|
|
293
|
+
fragment={activeFragment}
|
|
294
294
|
variant={activeVariant}
|
|
295
295
|
viewSettings={viewSettings}
|
|
296
296
|
uiState={uiState}
|
|
@@ -313,14 +313,14 @@ export function App({ segments }: AppProps) {
|
|
|
313
313
|
}
|
|
314
314
|
leftSidebar={
|
|
315
315
|
<LeftSidebar
|
|
316
|
-
|
|
317
|
-
|
|
316
|
+
fragments={fragments}
|
|
317
|
+
activeFragment={uiState.showHealthDashboard ? null : activeFragmentPath}
|
|
318
318
|
searchQuery={searchQuery}
|
|
319
|
-
onSelect={
|
|
319
|
+
onSelect={handleSelectFragment}
|
|
320
320
|
showHealth={uiState.showHealthDashboard}
|
|
321
321
|
onHealthClick={() => {
|
|
322
322
|
uiActions.setHealthDashboard(true);
|
|
323
|
-
|
|
323
|
+
setActiveFragmentPath(null);
|
|
324
324
|
}}
|
|
325
325
|
/>
|
|
326
326
|
}
|
|
@@ -329,25 +329,25 @@ export function App({ segments }: AppProps) {
|
|
|
329
329
|
<div style={{ height: '100%', overflow: 'auto', backgroundColor: 'var(--bg-primary)' }}>
|
|
330
330
|
<Box padding="lg" style={{ maxWidth: '896px', margin: '0 auto' }}>
|
|
331
331
|
<HealthDashboard
|
|
332
|
-
|
|
332
|
+
fragments={fragments}
|
|
333
333
|
onNavigate={(componentName) => {
|
|
334
|
-
const target =
|
|
334
|
+
const target = fragments.find(s => s.fragment.meta.name === componentName);
|
|
335
335
|
if (target) {
|
|
336
336
|
uiActions.setHealthDashboard(false);
|
|
337
|
-
|
|
337
|
+
handleSelectFragment(target.path);
|
|
338
338
|
}
|
|
339
339
|
}}
|
|
340
340
|
/>
|
|
341
341
|
</Box>
|
|
342
342
|
</div>
|
|
343
|
-
) :
|
|
343
|
+
) : activeFragment ? (
|
|
344
344
|
<div style={{ display: 'flex', height: '100%', flexDirection: panelDock === "bottom" ? 'column' : 'row' }}>
|
|
345
345
|
{/* Main Content Area */}
|
|
346
346
|
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0, minHeight: 0 }}>
|
|
347
347
|
{/* Variant Tabs */}
|
|
348
|
-
{
|
|
348
|
+
{activeFragment.fragment.variants && activeFragment.fragment.variants.length > 0 && (
|
|
349
349
|
<VariantTabsBar
|
|
350
|
-
variants={
|
|
350
|
+
variants={activeFragment.fragment.variants}
|
|
351
351
|
activeIndex={activeVariantIndex}
|
|
352
352
|
onSelect={handleSelectVariant}
|
|
353
353
|
showMatrixView={uiState.showMatrixView}
|
|
@@ -368,10 +368,10 @@ export function App({ segments }: AppProps) {
|
|
|
368
368
|
>
|
|
369
369
|
{activeVariant ? (
|
|
370
370
|
<PreviewArea
|
|
371
|
-
componentName={
|
|
372
|
-
|
|
371
|
+
componentName={activeFragment.fragment.meta.name}
|
|
372
|
+
fragmentPath={activeFragment.path}
|
|
373
373
|
variant={activeVariant}
|
|
374
|
-
variants={
|
|
374
|
+
variants={activeFragment.fragment.variants}
|
|
375
375
|
zoom={viewSettings.zoom}
|
|
376
376
|
background={viewSettings.background}
|
|
377
377
|
viewport={viewSettings.viewport}
|
|
@@ -388,10 +388,10 @@ export function App({ segments }: AppProps) {
|
|
|
388
388
|
}}
|
|
389
389
|
onRetry={uiActions.incrementPreviewKey}
|
|
390
390
|
renderContent={renderVariantWithProps}
|
|
391
|
-
previewKey={`${
|
|
391
|
+
previewKey={`${activeFragmentPath}-${activeVariantIndex}-${uiState.previewKey}`}
|
|
392
392
|
/>
|
|
393
393
|
) : (
|
|
394
|
-
<NoVariantsMessage
|
|
394
|
+
<NoVariantsMessage fragment={activeFragment?.fragment} />
|
|
395
395
|
)}
|
|
396
396
|
</div>
|
|
397
397
|
</div>
|
|
@@ -399,9 +399,9 @@ export function App({ segments }: AppProps) {
|
|
|
399
399
|
{/* Bottom Panel */}
|
|
400
400
|
{activeVariant && (
|
|
401
401
|
<BottomPanel
|
|
402
|
-
|
|
402
|
+
fragment={activeFragment.fragment}
|
|
403
403
|
variant={activeVariant}
|
|
404
|
-
|
|
404
|
+
fragments={fragments}
|
|
405
405
|
activePanel={uiState.activePanel}
|
|
406
406
|
onPanelChange={uiActions.setActivePanel}
|
|
407
407
|
figmaUrl={figmaUrl}
|
|
@@ -414,11 +414,11 @@ export function App({ segments }: AppProps) {
|
|
|
414
414
|
actionLogs={actionLogs}
|
|
415
415
|
onClearActionLogs={clearActionLogs}
|
|
416
416
|
onNavigateToComponent={(name) => {
|
|
417
|
-
const target =
|
|
418
|
-
if (target)
|
|
417
|
+
const target = fragments.find(s => s.fragment.meta.name === name);
|
|
418
|
+
if (target) handleSelectFragment(target.path);
|
|
419
419
|
}}
|
|
420
420
|
previewKey={uiState.previewKey}
|
|
421
|
-
|
|
421
|
+
fragmentKey={`${activeFragmentPath}-${activeVariantIndex}`}
|
|
422
422
|
/>
|
|
423
423
|
)}
|
|
424
424
|
</div>
|
|
@@ -438,7 +438,7 @@ export function App({ segments }: AppProps) {
|
|
|
438
438
|
|
|
439
439
|
// Top Toolbar Component
|
|
440
440
|
interface TopToolbarProps {
|
|
441
|
-
|
|
441
|
+
fragment: { path: string; fragment: FragmentDefinition };
|
|
442
442
|
variant: any;
|
|
443
443
|
viewSettings: ReturnType<typeof useViewSettings>;
|
|
444
444
|
uiState: ReturnType<typeof useAppState>['state'];
|
|
@@ -498,7 +498,7 @@ function ViewerHeader({ showHealth, searchQuery, onSearchChange, searchInputRef
|
|
|
498
498
|
}
|
|
499
499
|
|
|
500
500
|
function TopToolbar({
|
|
501
|
-
|
|
501
|
+
fragment,
|
|
502
502
|
variant,
|
|
503
503
|
viewSettings,
|
|
504
504
|
uiState,
|
|
@@ -515,8 +515,8 @@ function TopToolbar({
|
|
|
515
515
|
<Header.Trigger />
|
|
516
516
|
<Header.Brand>
|
|
517
517
|
<Stack direction="row" align="center" gap="sm">
|
|
518
|
-
<Text weight="medium" size="sm">{
|
|
519
|
-
<Text size="xs" color="tertiary">{
|
|
518
|
+
<Text weight="medium" size="sm">{fragment.fragment.meta.name}</Text>
|
|
519
|
+
<Text size="xs" color="tertiary">{fragment.fragment.meta.category}</Text>
|
|
520
520
|
</Stack>
|
|
521
521
|
</Header.Brand>
|
|
522
522
|
<HeaderSearch value={searchQuery} onChange={onSearchChange} inputRef={searchInputRef} />
|
|
@@ -570,7 +570,7 @@ function TopToolbar({
|
|
|
570
570
|
const url = new URL(window.location.href);
|
|
571
571
|
url.hash = '';
|
|
572
572
|
url.searchParams.set('isolated', 'true');
|
|
573
|
-
url.searchParams.set('component',
|
|
573
|
+
url.searchParams.set('component', fragment.fragment.meta.name);
|
|
574
574
|
url.searchParams.set('variant', variant.name);
|
|
575
575
|
if (viewSettings.zoom !== 100) url.searchParams.set('zoom', String(viewSettings.zoom));
|
|
576
576
|
if (viewSettings.background !== 'transparent') url.searchParams.set('bg', viewSettings.background);
|
|
@@ -582,7 +582,7 @@ function TopToolbar({
|
|
|
582
582
|
<ExternalLinkIcon style={{ width: '16px', height: '16px' }} />
|
|
583
583
|
</Button>
|
|
584
584
|
</Tooltip>
|
|
585
|
-
<ScreenshotButton componentName={
|
|
585
|
+
<ScreenshotButton componentName={fragment.fragment.meta.name} variantName={variant.name} />
|
|
586
586
|
<Tooltip content="Copy link to share">
|
|
587
587
|
<Button
|
|
588
588
|
onClick={onCopyLink}
|
|
@@ -651,11 +651,11 @@ function VariantTabsBar({ variants, activeIndex, onSelect, showMatrixView, showM
|
|
|
651
651
|
|
|
652
652
|
// No variants message
|
|
653
653
|
interface NoVariantsMessageProps {
|
|
654
|
-
|
|
654
|
+
fragment?: FragmentDefinition;
|
|
655
655
|
}
|
|
656
656
|
|
|
657
|
-
function NoVariantsMessage({
|
|
658
|
-
const skippedVariants = (
|
|
657
|
+
function NoVariantsMessage({ fragment }: NoVariantsMessageProps) {
|
|
658
|
+
const skippedVariants = (fragment?._generated as any)?.skippedVariants;
|
|
659
659
|
|
|
660
660
|
if (!skippedVariants || skippedVariants.length === 0) {
|
|
661
661
|
return (
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { memo, useCallback } from 'react';
|
|
7
|
-
import type {
|
|
7
|
+
import type { FragmentDefinition, FragmentVariant } from '../../core/index.js';
|
|
8
8
|
import { Tabs, Badge } from '@fragments/ui';
|
|
9
9
|
import { ResizablePanel } from './ResizablePanel.js';
|
|
10
10
|
import { CodePanel } from './CodePanel.js';
|
|
@@ -19,9 +19,9 @@ import type { ActionLog } from '../hooks/useActions.js';
|
|
|
19
19
|
|
|
20
20
|
interface BottomPanelProps {
|
|
21
21
|
// Component data
|
|
22
|
-
|
|
23
|
-
variant:
|
|
24
|
-
|
|
22
|
+
fragment: FragmentDefinition;
|
|
23
|
+
variant: FragmentVariant;
|
|
24
|
+
fragments: Array<{ path: string; fragment: FragmentDefinition }>;
|
|
25
25
|
|
|
26
26
|
// Panel state
|
|
27
27
|
activePanel: ActivePanel;
|
|
@@ -45,13 +45,13 @@ interface BottomPanelProps {
|
|
|
45
45
|
|
|
46
46
|
// Keys
|
|
47
47
|
previewKey: number;
|
|
48
|
-
|
|
48
|
+
fragmentKey: string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export const BottomPanel = memo(function BottomPanel({
|
|
52
|
-
|
|
52
|
+
fragment,
|
|
53
53
|
variant,
|
|
54
|
-
|
|
54
|
+
fragments,
|
|
55
55
|
activePanel,
|
|
56
56
|
onPanelChange,
|
|
57
57
|
figmaUrl,
|
|
@@ -65,7 +65,7 @@ export const BottomPanel = memo(function BottomPanel({
|
|
|
65
65
|
onClearActionLogs,
|
|
66
66
|
onNavigateToComponent,
|
|
67
67
|
previewKey,
|
|
68
|
-
|
|
68
|
+
fragmentKey,
|
|
69
69
|
}: BottomPanelProps) {
|
|
70
70
|
const handleStylesClick = useCallback(() => {
|
|
71
71
|
onPanelChange('styles');
|
|
@@ -121,8 +121,8 @@ export const BottomPanel = memo(function BottomPanel({
|
|
|
121
121
|
<div style={{ padding: '16px' }}>
|
|
122
122
|
<CodePanel
|
|
123
123
|
variant={variant}
|
|
124
|
-
componentName={
|
|
125
|
-
propDefs={
|
|
124
|
+
componentName={fragment.meta.name}
|
|
125
|
+
propDefs={fragment.props}
|
|
126
126
|
compact
|
|
127
127
|
/>
|
|
128
128
|
</div>
|
|
@@ -142,17 +142,17 @@ export const BottomPanel = memo(function BottomPanel({
|
|
|
142
142
|
|
|
143
143
|
{activePanel === 'accessibility' && (
|
|
144
144
|
<AccessibilityPanel
|
|
145
|
-
cacheKey={
|
|
145
|
+
cacheKey={fragmentKey}
|
|
146
146
|
previewKey={previewKey}
|
|
147
147
|
autoScan={true}
|
|
148
|
-
componentName={
|
|
148
|
+
componentName={fragment.meta.name}
|
|
149
149
|
variantName={variant.name}
|
|
150
150
|
/>
|
|
151
151
|
)}
|
|
152
152
|
|
|
153
153
|
{activePanel === 'interactions' && (
|
|
154
154
|
<InteractionsPanel
|
|
155
|
-
key={
|
|
155
|
+
key={fragmentKey}
|
|
156
156
|
variant={variant}
|
|
157
157
|
previewKey={previewKey}
|
|
158
158
|
/>
|
|
@@ -167,16 +167,16 @@ export const BottomPanel = memo(function BottomPanel({
|
|
|
167
167
|
|
|
168
168
|
{activePanel === 'graph' && (
|
|
169
169
|
<ComponentGraph
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
fragment={fragment}
|
|
171
|
+
allFragments={fragments}
|
|
172
172
|
onNavigate={onNavigateToComponent}
|
|
173
173
|
/>
|
|
174
174
|
)}
|
|
175
175
|
|
|
176
176
|
{activePanel === 'contract' && (
|
|
177
177
|
<ContractPanel
|
|
178
|
-
contract={
|
|
179
|
-
componentName={
|
|
178
|
+
contract={fragment.contract}
|
|
179
|
+
componentName={fragment.meta.name}
|
|
180
180
|
/>
|
|
181
181
|
)}
|
|
182
182
|
</ResizablePanel>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { useMemo, isValidElement, type ReactNode } from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { FragmentVariant, PropDefinition } from '../../core/index.js';
|
|
3
3
|
import { CodeBlock } from '@fragments/ui';
|
|
4
4
|
|
|
5
5
|
interface CodePanelProps {
|
|
6
|
-
variant:
|
|
6
|
+
variant: FragmentVariant;
|
|
7
7
|
componentName: string;
|
|
8
8
|
compact?: boolean;
|
|
9
9
|
propDefs?: Record<string, PropDefinition>;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// Extract props from rendered element by calling render() and introspecting
|
|
13
|
-
function extractPropsFromRender(variant:
|
|
13
|
+
function extractPropsFromRender(variant: FragmentVariant, componentName: string): Record<string, unknown> | null {
|
|
14
14
|
try {
|
|
15
15
|
const rendered = variant.render();
|
|
16
16
|
if (!isValidElement(rendered)) return null;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { useState, useEffect, useRef, useMemo, useCallback } from "react";
|
|
13
13
|
import { Dialog, Stack, Text, Badge, Separator, Input } from '@fragments/ui';
|
|
14
|
-
import type {
|
|
14
|
+
import type { FragmentDefinition } from "../../core/index.js";
|
|
15
15
|
import { SearchIcon, ChevronRightIcon } from "./Icons.js";
|
|
16
16
|
|
|
17
17
|
interface CommandPaletteProps {
|
|
@@ -19,8 +19,8 @@ interface CommandPaletteProps {
|
|
|
19
19
|
isOpen: boolean;
|
|
20
20
|
/** Callback to close the palette */
|
|
21
21
|
onClose: () => void;
|
|
22
|
-
/** All available
|
|
23
|
-
|
|
22
|
+
/** All available fragments */
|
|
23
|
+
fragments: Array<{ path: string; fragment: FragmentDefinition }>;
|
|
24
24
|
/** Callback when a component is selected */
|
|
25
25
|
onSelectComponent: (path: string) => void;
|
|
26
26
|
/** Callback when a variant is selected */
|
|
@@ -40,7 +40,7 @@ interface SearchResult {
|
|
|
40
40
|
export function CommandPalette({
|
|
41
41
|
isOpen,
|
|
42
42
|
onClose,
|
|
43
|
-
|
|
43
|
+
fragments,
|
|
44
44
|
onSelectComponent,
|
|
45
45
|
onSelectVariant,
|
|
46
46
|
}: CommandPaletteProps) {
|
|
@@ -53,9 +53,9 @@ export function CommandPalette({
|
|
|
53
53
|
const results = useMemo(() => {
|
|
54
54
|
const allResults: SearchResult[] = [];
|
|
55
55
|
|
|
56
|
-
for (const { path,
|
|
57
|
-
const componentName =
|
|
58
|
-
const category =
|
|
56
|
+
for (const { path, fragment } of fragments) {
|
|
57
|
+
const componentName = fragment.meta.name;
|
|
58
|
+
const category = fragment.meta.category;
|
|
59
59
|
|
|
60
60
|
// Add component result
|
|
61
61
|
allResults.push({
|
|
@@ -67,9 +67,9 @@ export function CommandPalette({
|
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
// Add variant results
|
|
70
|
-
if (
|
|
71
|
-
for (let i = 0; i <
|
|
72
|
-
const variant =
|
|
70
|
+
if (fragment.variants) {
|
|
71
|
+
for (let i = 0; i < fragment.variants.length; i++) {
|
|
72
|
+
const variant = fragment.variants[i];
|
|
73
73
|
allResults.push({
|
|
74
74
|
type: "variant",
|
|
75
75
|
path,
|
|
@@ -106,7 +106,7 @@ export function CommandPalette({
|
|
|
106
106
|
.slice(0, 20);
|
|
107
107
|
|
|
108
108
|
return scored;
|
|
109
|
-
}, [
|
|
109
|
+
}, [fragments, query]);
|
|
110
110
|
|
|
111
111
|
// Reset selection when results change
|
|
112
112
|
useEffect(() => {
|