@fragments-sdk/cli 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +996 -79
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-ICAIQ57V.js → chunk-6JBGU74P.js} +5 -3
- package/dist/chunk-6JBGU74P.js.map +1 -0
- package/dist/chunk-7OPWMLOE.js +1625 -0
- package/dist/chunk-7OPWMLOE.js.map +1 -0
- package/dist/{chunk-2H2JAA3U.js → chunk-CVXKXVOY.js} +3 -3
- package/dist/{chunk-2H2JAA3U.js.map → chunk-CVXKXVOY.js.map} +1 -1
- package/dist/{chunk-IOJE35DZ.js → chunk-NWQ4CJOQ.js} +3 -3
- package/dist/{chunk-2DJH4F4P.js → chunk-RVRTRESS.js} +3 -3
- package/dist/{chunk-V7YLRR4C.js → chunk-TJ34N7C7.js} +41 -4
- package/dist/{chunk-V7YLRR4C.js.map → chunk-TJ34N7C7.js.map} +1 -1
- package/dist/{chunk-XNWDI6UT.js → chunk-XHUDJNN3.js} +5 -5
- package/dist/{core-DKHB7FYV.js → core-W2HYIQW6.js} +4 -4
- package/dist/{generate-KL24VZVD.js → generate-LMTISDIJ.js} +5 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/{init-NION5S3M.js → init-7CHRKQ7P.js} +5 -5
- package/dist/mcp-bin.js +8 -220
- package/dist/mcp-bin.js.map +1 -1
- package/dist/scan-WY23TJCP.js +12 -0
- package/dist/{service-RWUMZ3EW.js → service-T2L7VLTE.js} +5 -5
- package/dist/static-viewer-GBR7YNF3.js +12 -0
- package/dist/{test-ECPEXFDN.js → test-OJRXNDO2.js} +4 -4
- package/dist/{tokens-ITADYVPF.js → tokens-3BWDESVM.js} +6 -6
- package/dist/viewer-SUFOISZM.js +1822 -0
- package/dist/viewer-SUFOISZM.js.map +1 -0
- package/package.json +6 -5
- package/src/bin.ts +31 -0
- package/src/build.ts +147 -13
- package/src/cli-commands.ts +18 -0
- package/src/commands/__tests__/a11y-scoring.test.ts +278 -0
- package/src/commands/a11y-report.ts +625 -0
- package/src/commands/a11y.ts +168 -14
- package/src/commands/build.ts +16 -0
- package/src/commands/graph.ts +274 -0
- package/src/core/auto-props.ts +464 -0
- package/src/core/composition.ts +64 -1
- package/src/core/graph-extractor.test.ts +542 -0
- package/src/core/graph-extractor.ts +601 -0
- package/src/core/importAnalyzer.ts +5 -0
- package/src/core/schema.ts +2 -0
- package/src/core/types.ts +3 -1
- package/src/index.ts +4 -0
- package/src/mcp/server.ts +13 -220
- package/src/theme/__tests__/component-contrast.test.ts +338 -0
- package/src/theme/__tests__/contrast-validation.test.ts +326 -0
- package/src/theme/contrast.test.ts +331 -0
- package/src/theme/contrast.ts +246 -0
- package/src/theme/generator.ts +213 -1
- package/src/theme/index.ts +16 -0
- package/src/theme/types.ts +51 -0
- package/src/viewer/__tests__/a11y-fixes.test.ts +358 -0
- package/src/viewer/__tests__/viewer-integration.test.ts +2 -7
- package/src/viewer/components/AccessibilityPanel.tsx +493 -433
- package/src/viewer/components/ActionCapture.tsx +1 -1
- package/src/viewer/components/ActionsPanel.tsx +142 -183
- package/src/viewer/components/App.tsx +276 -183
- package/src/viewer/components/BottomPanel.tsx +40 -80
- package/src/viewer/components/CodePanel.tsx +9 -87
- package/src/viewer/components/CommandPalette.tsx +117 -74
- package/src/viewer/components/ComponentGraph.tsx +143 -126
- package/src/viewer/components/ComponentHeader.tsx +46 -43
- package/src/viewer/components/ContractPanel.tsx +124 -117
- package/src/viewer/components/ErrorBoundary.tsx +47 -35
- package/src/viewer/components/FigmaEmbed.tsx +18 -13
- package/src/viewer/components/FragmentEditor.tsx +126 -63
- package/src/viewer/components/HealthDashboard.tsx +146 -171
- package/src/viewer/components/HmrStatusIndicator.tsx +31 -41
- package/src/viewer/components/Icons.tsx +151 -98
- package/src/viewer/components/InteractionsPanel.tsx +317 -264
- package/src/viewer/components/IsolatedPreviewFrame.tsx +52 -27
- package/src/viewer/components/IsolatedRender.tsx +12 -6
- package/src/viewer/components/KeyboardShortcutsHelp.tsx +34 -70
- package/src/viewer/components/LandingPage.tsx +285 -305
- package/src/viewer/components/Layout.tsx +12 -10
- package/src/viewer/components/LeftSidebar.tsx +103 -155
- package/src/viewer/components/MultiViewportPreview.tsx +254 -63
- package/src/viewer/components/PreviewArea.tsx +113 -44
- package/src/viewer/components/PreviewFrameHost.tsx +36 -6
- package/src/viewer/components/PreviewPane.tsx +2 -3
- package/src/viewer/components/PreviewToolbar.tsx +109 -105
- package/src/viewer/components/PropsEditor.tsx +154 -74
- package/src/viewer/components/PropsTable.tsx +95 -82
- package/src/viewer/components/RelationsSection.tsx +71 -40
- package/src/viewer/components/ResizablePanel.tsx +158 -55
- package/src/viewer/components/RightSidebar.tsx +46 -56
- package/src/viewer/components/ScreenshotButton.tsx +12 -12
- package/src/viewer/components/SkeletonLoader.tsx +99 -83
- package/src/viewer/components/StoryRenderer.tsx +4 -11
- package/src/viewer/components/Toast.tsx +3 -67
- package/src/viewer/components/TokenStylePanel.tsx +136 -118
- package/src/viewer/components/UsageSection.tsx +26 -26
- package/src/viewer/components/VariantMatrix.tsx +140 -47
- package/src/viewer/components/VariantTabs.tsx +24 -68
- package/src/viewer/components/ViewportSelector.tsx +121 -114
- package/src/viewer/constants/ui.ts +23 -22
- package/src/viewer/entry.tsx +8 -3
- package/src/viewer/index.ts +3 -6
- package/src/viewer/preview-frame.html +43 -18
- package/src/viewer/server.ts +7 -16
- package/src/viewer/styles/globals.css +46 -85
- package/src/viewer/utils/a11y-fixes.ts +53 -30
- package/dist/chunk-ICAIQ57V.js.map +0 -1
- package/dist/chunk-U4GQ2JTD.js +0 -832
- package/dist/chunk-U4GQ2JTD.js.map +0 -1
- package/dist/scan-ESEXV7LF.js +0 -12
- package/dist/static-viewer-O37MJ5B6.js +0 -12
- package/dist/viewer-YDGFDTK5.js +0 -11104
- package/dist/viewer-YDGFDTK5.js.map +0 -1
- package/src/viewer/postcss.config.js +0 -6
- package/src/viewer/tailwind.config.js +0 -37
- /package/dist/{chunk-IOJE35DZ.js.map → chunk-NWQ4CJOQ.js.map} +0 -0
- /package/dist/{chunk-2DJH4F4P.js.map → chunk-RVRTRESS.js.map} +0 -0
- /package/dist/{chunk-XNWDI6UT.js.map → chunk-XHUDJNN3.js.map} +0 -0
- /package/dist/{core-DKHB7FYV.js.map → core-W2HYIQW6.js.map} +0 -0
- /package/dist/{generate-KL24VZVD.js.map → generate-LMTISDIJ.js.map} +0 -0
- /package/dist/{init-NION5S3M.js.map → init-7CHRKQ7P.js.map} +0 -0
- /package/dist/{scan-ESEXV7LF.js.map → scan-WY23TJCP.js.map} +0 -0
- /package/dist/{service-RWUMZ3EW.js.map → service-T2L7VLTE.js.map} +0 -0
- /package/dist/{static-viewer-O37MJ5B6.js.map → static-viewer-GBR7YNF3.js.map} +0 -0
- /package/dist/{test-ECPEXFDN.js.map → test-OJRXNDO2.js.map} +0 -0
- /package/dist/{tokens-ITADYVPF.js.map → tokens-3BWDESVM.js.map} +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useState, useCallback } from "react";
|
|
2
2
|
import { useForm, useFieldArray, Controller } from "react-hook-form";
|
|
3
3
|
import type { Fragment, FragmentUsage, FragmentMeta } from "../../core/index.js";
|
|
4
|
-
import clsx from "clsx";
|
|
5
4
|
import { ChevronDownIcon } from "./Icons.js";
|
|
6
5
|
|
|
7
6
|
interface FragmentEditorProps {
|
|
@@ -39,6 +38,44 @@ interface FormData {
|
|
|
39
38
|
};
|
|
40
39
|
}
|
|
41
40
|
|
|
41
|
+
const inputStyle: React.CSSProperties = {
|
|
42
|
+
width: '100%',
|
|
43
|
+
padding: '6px 12px',
|
|
44
|
+
fontSize: '14px',
|
|
45
|
+
background: 'var(--bg-elevated)',
|
|
46
|
+
border: '1px solid var(--border)',
|
|
47
|
+
borderRadius: '8px',
|
|
48
|
+
outline: 'none',
|
|
49
|
+
color: 'var(--text-primary)',
|
|
50
|
+
boxSizing: 'border-box',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const labelStyle: React.CSSProperties = {
|
|
54
|
+
display: 'block',
|
|
55
|
+
fontSize: '12px',
|
|
56
|
+
fontWeight: 500,
|
|
57
|
+
color: 'var(--text-secondary)',
|
|
58
|
+
marginBottom: '6px',
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const removeButtonStyle: React.CSSProperties = {
|
|
62
|
+
padding: '0 8px',
|
|
63
|
+
color: 'var(--text-secondary)',
|
|
64
|
+
background: 'none',
|
|
65
|
+
border: 'none',
|
|
66
|
+
cursor: 'pointer',
|
|
67
|
+
fontSize: '16px',
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const addButtonStyle: React.CSSProperties = {
|
|
71
|
+
fontSize: '12px',
|
|
72
|
+
color: 'var(--color-accent)',
|
|
73
|
+
background: 'none',
|
|
74
|
+
border: 'none',
|
|
75
|
+
cursor: 'pointer',
|
|
76
|
+
padding: 0,
|
|
77
|
+
};
|
|
78
|
+
|
|
42
79
|
export function FragmentEditor({
|
|
43
80
|
componentName,
|
|
44
81
|
fragment,
|
|
@@ -156,27 +193,30 @@ export function FragmentEditor({
|
|
|
156
193
|
return (
|
|
157
194
|
<form
|
|
158
195
|
onSubmit={handleSubmit(onSubmit)}
|
|
159
|
-
|
|
196
|
+
style={{ height: '100%', display: 'flex', flexDirection: 'column', background: 'var(--bg-primary)' }}
|
|
160
197
|
>
|
|
161
198
|
{/* Header */}
|
|
162
|
-
<div
|
|
163
|
-
<h3
|
|
164
|
-
<p
|
|
199
|
+
<div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', background: 'var(--bg-secondary)' }}>
|
|
200
|
+
<h3 style={{ fontSize: '14px', fontWeight: 600, color: 'var(--text-primary)', margin: 0 }}>Fragment Editor</h3>
|
|
201
|
+
<p style={{ fontSize: '12px', color: 'var(--text-secondary)', marginTop: '2px', marginBottom: 0 }}>
|
|
165
202
|
Enrich {componentName} with metadata
|
|
166
203
|
</p>
|
|
167
204
|
</div>
|
|
168
205
|
|
|
169
206
|
{/* Scrollable content */}
|
|
170
|
-
<div
|
|
207
|
+
<div style={{ flex: 1, overflowY: 'auto' }}>
|
|
171
208
|
{/* Basic Info */}
|
|
172
|
-
<div
|
|
173
|
-
<label
|
|
209
|
+
<div style={{ padding: '16px', borderBottom: '1px solid var(--border)' }}>
|
|
210
|
+
<label style={labelStyle}>
|
|
174
211
|
Description
|
|
175
212
|
</label>
|
|
176
213
|
<textarea
|
|
177
214
|
{...register("description")}
|
|
178
215
|
rows={3}
|
|
179
|
-
|
|
216
|
+
style={{
|
|
217
|
+
...inputStyle,
|
|
218
|
+
resize: 'none',
|
|
219
|
+
}}
|
|
180
220
|
placeholder="Brief description of the component's purpose..."
|
|
181
221
|
/>
|
|
182
222
|
</div>
|
|
@@ -188,22 +228,22 @@ export function FragmentEditor({
|
|
|
188
228
|
onToggle={() => toggleSection("usage")}
|
|
189
229
|
>
|
|
190
230
|
{/* When to Use */}
|
|
191
|
-
<div
|
|
192
|
-
<label
|
|
231
|
+
<div style={{ marginBottom: '16px' }}>
|
|
232
|
+
<label style={{ ...labelStyle, marginBottom: '8px' }}>
|
|
193
233
|
When to Use
|
|
194
234
|
</label>
|
|
195
|
-
<div
|
|
235
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
196
236
|
{whenFields.map((field, index) => (
|
|
197
|
-
<div key={field.id}
|
|
237
|
+
<div key={field.id} style={{ display: 'flex', gap: '8px' }}>
|
|
198
238
|
<input
|
|
199
239
|
{...register(`usage.when.${index}` as const)}
|
|
200
|
-
|
|
240
|
+
style={{ ...inputStyle, flex: 1 }}
|
|
201
241
|
placeholder="Scenario..."
|
|
202
242
|
/>
|
|
203
243
|
<button
|
|
204
244
|
type="button"
|
|
205
245
|
onClick={() => removeWhen(index)}
|
|
206
|
-
|
|
246
|
+
style={removeButtonStyle}
|
|
207
247
|
>
|
|
208
248
|
×
|
|
209
249
|
</button>
|
|
@@ -212,7 +252,7 @@ export function FragmentEditor({
|
|
|
212
252
|
<button
|
|
213
253
|
type="button"
|
|
214
254
|
onClick={() => appendWhen("")}
|
|
215
|
-
|
|
255
|
+
style={addButtonStyle}
|
|
216
256
|
>
|
|
217
257
|
+ Add scenario
|
|
218
258
|
</button>
|
|
@@ -221,26 +261,26 @@ export function FragmentEditor({
|
|
|
221
261
|
|
|
222
262
|
{/* Do Not */}
|
|
223
263
|
<div>
|
|
224
|
-
<label
|
|
264
|
+
<label style={{ ...labelStyle, marginBottom: '8px' }}>
|
|
225
265
|
Do Not
|
|
226
266
|
</label>
|
|
227
|
-
<div
|
|
267
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
228
268
|
{doNotFields.map((field, index) => (
|
|
229
|
-
<div key={field.id}
|
|
269
|
+
<div key={field.id} style={{ display: 'flex', gap: '8px' }}>
|
|
230
270
|
<input
|
|
231
271
|
{...register(`usage.doNot.${index}.text` as const)}
|
|
232
|
-
|
|
272
|
+
style={{ ...inputStyle, flex: 1 }}
|
|
233
273
|
placeholder="What not to do..."
|
|
234
274
|
/>
|
|
235
275
|
<input
|
|
236
276
|
{...register(`usage.doNot.${index}.instead` as const)}
|
|
237
|
-
|
|
277
|
+
style={{ ...inputStyle, width: '128px' }}
|
|
238
278
|
placeholder="Instead..."
|
|
239
279
|
/>
|
|
240
280
|
<button
|
|
241
281
|
type="button"
|
|
242
282
|
onClick={() => removeDoNot(index)}
|
|
243
|
-
|
|
283
|
+
style={removeButtonStyle}
|
|
244
284
|
>
|
|
245
285
|
×
|
|
246
286
|
</button>
|
|
@@ -249,7 +289,7 @@ export function FragmentEditor({
|
|
|
249
289
|
<button
|
|
250
290
|
type="button"
|
|
251
291
|
onClick={() => appendDoNot({ text: "", instead: "" })}
|
|
252
|
-
|
|
292
|
+
style={addButtonStyle}
|
|
253
293
|
>
|
|
254
294
|
+ Add anti-pattern
|
|
255
295
|
</button>
|
|
@@ -263,35 +303,35 @@ export function FragmentEditor({
|
|
|
263
303
|
expanded={expandedSections.has("accessibility")}
|
|
264
304
|
onToggle={() => toggleSection("accessibility")}
|
|
265
305
|
>
|
|
266
|
-
<div
|
|
267
|
-
<label
|
|
306
|
+
<div style={{ marginBottom: '16px' }}>
|
|
307
|
+
<label style={labelStyle}>
|
|
268
308
|
ARIA Role
|
|
269
309
|
</label>
|
|
270
310
|
<input
|
|
271
311
|
{...register("accessibility.role")}
|
|
272
|
-
|
|
312
|
+
style={inputStyle}
|
|
273
313
|
placeholder="button, dialog, etc."
|
|
274
314
|
/>
|
|
275
315
|
</div>
|
|
276
316
|
|
|
277
317
|
<div>
|
|
278
|
-
<label
|
|
318
|
+
<label style={{ ...labelStyle, marginBottom: '8px' }}>
|
|
279
319
|
Requirements
|
|
280
320
|
</label>
|
|
281
|
-
<div
|
|
321
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
282
322
|
{requirementsFields.map((field, index) => (
|
|
283
|
-
<div key={field.id}
|
|
323
|
+
<div key={field.id} style={{ display: 'flex', gap: '8px' }}>
|
|
284
324
|
<input
|
|
285
325
|
{...register(
|
|
286
326
|
`accessibility.requirements.${index}` as const
|
|
287
327
|
)}
|
|
288
|
-
|
|
328
|
+
style={{ ...inputStyle, flex: 1 }}
|
|
289
329
|
placeholder="Requirement..."
|
|
290
330
|
/>
|
|
291
331
|
<button
|
|
292
332
|
type="button"
|
|
293
333
|
onClick={() => removeRequirement(index)}
|
|
294
|
-
|
|
334
|
+
style={removeButtonStyle}
|
|
295
335
|
>
|
|
296
336
|
×
|
|
297
337
|
</button>
|
|
@@ -300,7 +340,7 @@ export function FragmentEditor({
|
|
|
300
340
|
<button
|
|
301
341
|
type="button"
|
|
302
342
|
onClick={() => appendRequirement("")}
|
|
303
|
-
|
|
343
|
+
style={addButtonStyle}
|
|
304
344
|
>
|
|
305
345
|
+ Add requirement
|
|
306
346
|
</button>
|
|
@@ -343,14 +383,14 @@ export function FragmentEditor({
|
|
|
343
383
|
expanded={expandedSections.has("meta")}
|
|
344
384
|
onToggle={() => toggleSection("meta")}
|
|
345
385
|
>
|
|
346
|
-
<div
|
|
386
|
+
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px', marginBottom: '16px' }}>
|
|
347
387
|
<div>
|
|
348
|
-
<label
|
|
388
|
+
<label style={labelStyle}>
|
|
349
389
|
Status
|
|
350
390
|
</label>
|
|
351
391
|
<select
|
|
352
392
|
{...register("meta.status")}
|
|
353
|
-
|
|
393
|
+
style={inputStyle}
|
|
354
394
|
>
|
|
355
395
|
<option value="draft">Draft</option>
|
|
356
396
|
<option value="experimental">Experimental</option>
|
|
@@ -360,23 +400,23 @@ export function FragmentEditor({
|
|
|
360
400
|
</select>
|
|
361
401
|
</div>
|
|
362
402
|
<div>
|
|
363
|
-
<label
|
|
403
|
+
<label style={labelStyle}>
|
|
364
404
|
Since Version
|
|
365
405
|
</label>
|
|
366
406
|
<input
|
|
367
407
|
{...register("meta.since")}
|
|
368
|
-
|
|
408
|
+
style={inputStyle}
|
|
369
409
|
placeholder="1.0.0"
|
|
370
410
|
/>
|
|
371
411
|
</div>
|
|
372
412
|
</div>
|
|
373
|
-
<div
|
|
374
|
-
<label
|
|
413
|
+
<div style={{ marginBottom: '16px' }}>
|
|
414
|
+
<label style={labelStyle}>
|
|
375
415
|
Owner
|
|
376
416
|
</label>
|
|
377
417
|
<input
|
|
378
418
|
{...register("meta.owner")}
|
|
379
|
-
|
|
419
|
+
style={inputStyle}
|
|
380
420
|
placeholder="@team-name or email"
|
|
381
421
|
/>
|
|
382
422
|
</div>
|
|
@@ -384,16 +424,22 @@ export function FragmentEditor({
|
|
|
384
424
|
</div>
|
|
385
425
|
|
|
386
426
|
{/* Footer with save button */}
|
|
387
|
-
<div
|
|
427
|
+
<div style={{ padding: '12px 16px', borderTop: '1px solid var(--border)', background: 'var(--bg-secondary)' }}>
|
|
388
428
|
<button
|
|
389
429
|
type="submit"
|
|
390
430
|
disabled={!isDirty || saving}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
431
|
+
style={{
|
|
432
|
+
width: '100%',
|
|
433
|
+
padding: '8px 16px',
|
|
434
|
+
fontSize: '14px',
|
|
435
|
+
fontWeight: 500,
|
|
436
|
+
borderRadius: '8px',
|
|
437
|
+
transition: 'background-color 150ms',
|
|
438
|
+
border: 'none',
|
|
439
|
+
cursor: isDirty && !saving ? 'pointer' : 'not-allowed',
|
|
440
|
+
background: isDirty && !saving ? 'var(--color-accent)' : 'var(--bg-secondary)',
|
|
441
|
+
color: isDirty && !saving ? 'white' : 'var(--text-tertiary)',
|
|
442
|
+
}}
|
|
397
443
|
>
|
|
398
444
|
{saving ? "Saving..." : "Save Fragment"}
|
|
399
445
|
</button>
|
|
@@ -410,24 +456,41 @@ interface SectionProps {
|
|
|
410
456
|
}
|
|
411
457
|
|
|
412
458
|
function Section({ title, expanded, onToggle, children }: SectionProps) {
|
|
459
|
+
const [hovered, setHovered] = useState(false);
|
|
460
|
+
|
|
413
461
|
return (
|
|
414
|
-
<div
|
|
462
|
+
<div style={{ borderBottom: '1px solid var(--border)' }}>
|
|
415
463
|
<button
|
|
416
464
|
type="button"
|
|
417
465
|
onClick={onToggle}
|
|
418
|
-
|
|
466
|
+
onMouseEnter={() => setHovered(true)}
|
|
467
|
+
onMouseLeave={() => setHovered(false)}
|
|
468
|
+
style={{
|
|
469
|
+
width: '100%',
|
|
470
|
+
padding: '12px 16px',
|
|
471
|
+
display: 'flex',
|
|
472
|
+
alignItems: 'center',
|
|
473
|
+
justifyContent: 'space-between',
|
|
474
|
+
background: hovered ? 'var(--bg-hover)' : 'var(--bg-secondary)',
|
|
475
|
+
transition: 'background-color 150ms',
|
|
476
|
+
border: 'none',
|
|
477
|
+
cursor: 'pointer',
|
|
478
|
+
}}
|
|
419
479
|
>
|
|
420
|
-
<span
|
|
480
|
+
<span style={{ fontSize: '12px', fontWeight: 600, color: 'var(--text-primary)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>
|
|
421
481
|
{title}
|
|
422
482
|
</span>
|
|
423
483
|
<ChevronDownIcon
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
484
|
+
style={{
|
|
485
|
+
width: '16px',
|
|
486
|
+
height: '16px',
|
|
487
|
+
color: 'var(--text-tertiary)',
|
|
488
|
+
transition: 'transform 150ms',
|
|
489
|
+
transform: expanded ? 'rotate(0deg)' : 'rotate(-90deg)',
|
|
490
|
+
}}
|
|
428
491
|
/>
|
|
429
492
|
</button>
|
|
430
|
-
{expanded && <div
|
|
493
|
+
{expanded && <div style={{ padding: '16px' }}>{children}</div>}
|
|
431
494
|
</div>
|
|
432
495
|
);
|
|
433
496
|
}
|
|
@@ -450,23 +513,23 @@ function RelatedField({
|
|
|
450
513
|
const { fields, append, remove } = useFieldArray({ control, name });
|
|
451
514
|
|
|
452
515
|
return (
|
|
453
|
-
<div
|
|
454
|
-
<label
|
|
516
|
+
<div style={{ marginBottom: '16px' }}>
|
|
517
|
+
<label style={{ display: 'block', fontSize: '12px', fontWeight: 500, color: 'var(--text-secondary)', marginBottom: '2px' }}>
|
|
455
518
|
{label}
|
|
456
519
|
</label>
|
|
457
|
-
<p
|
|
458
|
-
<div
|
|
520
|
+
<p style={{ fontSize: '10px', color: 'var(--text-tertiary)', marginBottom: '8px', marginTop: 0 }}>{description}</p>
|
|
521
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
459
522
|
{fields.map((field, index) => (
|
|
460
|
-
<div key={field.id}
|
|
523
|
+
<div key={field.id} style={{ display: 'flex', gap: '8px' }}>
|
|
461
524
|
<input
|
|
462
525
|
{...register(`${name}.${index}` as const)}
|
|
463
|
-
|
|
526
|
+
style={{ ...inputStyle, flex: 1 }}
|
|
464
527
|
placeholder="ComponentName"
|
|
465
528
|
/>
|
|
466
529
|
<button
|
|
467
530
|
type="button"
|
|
468
531
|
onClick={() => remove(index)}
|
|
469
|
-
|
|
532
|
+
style={removeButtonStyle}
|
|
470
533
|
>
|
|
471
534
|
×
|
|
472
535
|
</button>
|
|
@@ -475,7 +538,7 @@ function RelatedField({
|
|
|
475
538
|
<button
|
|
476
539
|
type="button"
|
|
477
540
|
onClick={() => append("")}
|
|
478
|
-
|
|
541
|
+
style={addButtonStyle}
|
|
479
542
|
>
|
|
480
543
|
+ Add component
|
|
481
544
|
</button>
|