@rogieking/figui3 2.29.3 → 2.30.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/propkit.html CHANGED
@@ -9,9 +9,23 @@
9
9
  <link rel="stylesheet"
10
10
  type="text/css"
11
11
  href="fig.css">
12
- <link rel="stylesheet"
13
- href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css">
12
+ <link rel="preconnect" href="https://fonts.googleapis.com">
13
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
14
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&display=swap">
14
15
  <script src="fig.js"></script>
16
+ <script type="importmap">
17
+ {
18
+ "imports": {
19
+ "style-mod": "https://esm.sh/style-mod@4.1.2",
20
+ "w3c-keyname": "https://esm.sh/w3c-keyname@2.2.8",
21
+ "crelt": "https://esm.sh/crelt@1.0.6",
22
+ "@marijn/find-cluster-break": "https://esm.sh/@marijn/find-cluster-break@1.0.2",
23
+ "@lezer/": "https://esm.sh/*@lezer/",
24
+ "@codemirror/": "https://esm.sh/*@codemirror/",
25
+ "codemirror": "https://esm.sh/*codemirror"
26
+ }
27
+ }
28
+ </script>
15
29
  <style>
16
30
  * {
17
31
  box-sizing: border-box;
@@ -19,14 +33,15 @@
19
33
 
20
34
  body {
21
35
  margin: 0;
22
- min-height: 100vh;
36
+ height: 100vh;
23
37
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
24
- overflow-x: hidden;
38
+ overflow: hidden;
39
+ display: flex;
25
40
  }
26
41
 
27
42
  nav {
28
- position: fixed;
29
- width: 180px;
43
+ width: 220px;
44
+ min-width: 220px;
30
45
  height: 100vh;
31
46
  overflow-y: auto;
32
47
  background: var(--figma-color-bg-secondary);
@@ -39,6 +54,7 @@
39
54
  nav .nav-links {
40
55
  flex: 1;
41
56
  overflow-y: auto;
57
+ padding: 0 8px;
42
58
  }
43
59
 
44
60
  nav .nav-links h1 {
@@ -47,29 +63,12 @@
47
63
  text-transform: uppercase;
48
64
  letter-spacing: 0.05em;
49
65
  color: var(--figma-color-text-secondary);
50
- padding: 8px 20px;
51
- margin: 0 0 8px 0;
52
- }
53
-
54
- nav .nav-links a {
55
- display: block;
56
- padding: 6px 12px;
57
- margin: 0 8px;
58
- color: var(--figma-color-text-secondary);
59
- text-decoration: none;
60
- font-size: 13px;
61
- border-radius: var(--radius-medium);
62
- transition: background 0.15s, color 0.15s;
66
+ padding: 8px 12px;
67
+ margin: 0 0 4px 0;
63
68
  }
64
69
 
65
- nav .nav-links a:hover {
66
- color: var(--figma-color-text);
67
- background: var(--figma-color-bg-hover);
68
- }
69
-
70
- nav .nav-links a.active {
71
- color: var(--figma-color-text-brand);
72
- background: var(--figma-color-bg-selected);
70
+ nav fig-layer>.fig-layer-row>label {
71
+ font-weight: 600;
73
72
  }
74
73
 
75
74
  nav .theme-switch {
@@ -103,23 +102,21 @@
103
102
  }
104
103
 
105
104
  main {
106
- margin-left: 180px;
105
+ flex: 1;
107
106
  padding: 24px 32px;
108
107
  max-width: 600px;
109
- min-height: 100vh;
108
+ height: 100vh;
109
+ overflow-y: auto;
110
110
  display: flex;
111
111
  flex-direction: column;
112
112
  }
113
113
 
114
114
  section {
115
- scroll-margin-top: 24px;
116
- padding-bottom: 32px;
115
+ display: none;
117
116
  }
118
117
 
119
- main>hr {
120
- border: none;
121
- border-top: 1px solid var(--figma-color-border);
122
- margin: 0 0 32px 0;
118
+ section.active {
119
+ display: block;
123
120
  }
124
121
 
125
122
  section h2 {
@@ -129,21 +126,20 @@
129
126
  margin: 0 0 8px 0;
130
127
  }
131
128
 
132
- fig-header.propkit-subheader {
133
- padding-left: 0;
134
-
135
- h3 {
136
- margin-right: var(--spacer-2);
137
- flex-grow: 0;
138
- }
139
- }
140
-
141
129
  section>p.description {
142
130
  font-size: 13px;
143
131
  color: var(--figma-color-text-secondary);
144
132
  margin: 0 0 24px 0;
145
133
  }
146
134
 
135
+ .propkit-example {
136
+ display: none;
137
+ }
138
+
139
+ .propkit-example.active {
140
+ display: block;
141
+ }
142
+
147
143
  .prop-panel {
148
144
  width: 240px;
149
145
  flex-shrink: 0;
@@ -177,27 +173,30 @@
177
173
  color: var(--figma-color-text);
178
174
  }
179
175
 
180
- /* Prism theme reset: remove glow/shadow from highlighted code */
181
- pre[class*="language-"],
182
- code[class*="language-"],
183
- .token {
184
- text-shadow: none !important;
176
+ .event-dump {
177
+ margin-top: var(--spacer-2);
178
+ width: 240px;
185
179
  }
186
180
 
187
- pre.event-dump {
188
- margin: 0;
189
- padding: var(--spacer-2) var(--spacer-3);
190
- background: var(--figma-color-bg-secondary);
181
+ .event-dump .cm-editor,
182
+ .propkit-code-view .cm-editor {
191
183
  border: 1px solid var(--figma-color-border);
192
184
  border-radius: var(--radius-large);
193
- margin-top: var(--spacer-2);
194
- white-space: pre-wrap;
195
- word-break: break-word;
196
- width: 240px;
185
+ overflow: hidden;
197
186
  }
198
187
 
199
- pre.event-dump code {
200
- font-size: 11px;
188
+ .propkit-code-view {
189
+ margin-top: 24px;
190
+ }
191
+
192
+ .propkit-code-view-actions {
193
+ display: flex;
194
+ gap: var(--spacer-2);
195
+ margin-bottom: var(--spacer-2);
196
+ }
197
+
198
+ .propkit-code-view .cm-editor {
199
+ max-width: 100%;
201
200
  }
202
201
  </style>
203
202
  </head>
@@ -206,19 +205,210 @@
206
205
  <nav>
207
206
  <div class="nav-links">
208
207
  <h1>PropKit</h1>
209
- <a href="#image">Image</a>
210
- <a href="#color">Color</a>
211
- <a href="#fill">Fill</a>
212
- <a href="#slider">Slider</a>
213
- <a href="#switch">Switch</a>
214
- <a href="#dropdown">Dropdown</a>
215
- <a href="#segment">Segment</a>
216
- <a href="#dial">Dial</a>
217
- <a href="#easing">Easing Curve</a>
218
- <a href="#3d-rotate">3D Rotate</a>
219
- <a href="#angle">Angle</a>
220
- <hr>
221
- <a href="#combined">Combined Panel</a>
208
+
209
+ <fig-layer data-section="image">
210
+ <div class="fig-layer-row"><label>Image</label></div>
211
+ <fig-layer data-section="image"
212
+ data-example="upload">
213
+ <div class="fig-layer-row"><label>Upload</label></div>
214
+ </fig-layer>
215
+ <fig-layer data-section="image"
216
+ data-example="auto-aspect-ratio">
217
+ <div class="fig-layer-row"><label>Auto Aspect Ratio</label></div>
218
+ </fig-layer>
219
+ <fig-layer data-section="image"
220
+ data-example="16-9">
221
+ <div class="fig-layer-row"><label>16:9</label></div>
222
+ </fig-layer>
223
+ <fig-layer data-section="image"
224
+ data-example="4-3">
225
+ <div class="fig-layer-row"><label>4:3</label></div>
226
+ </fig-layer>
227
+ <fig-layer data-section="image"
228
+ data-example="cover">
229
+ <div class="fig-layer-row"><label>Cover</label></div>
230
+ </fig-layer>
231
+ <fig-layer data-section="image"
232
+ data-example="contain">
233
+ <div class="fig-layer-row"><label>Contain</label></div>
234
+ </fig-layer>
235
+ </fig-layer>
236
+
237
+ <fig-layer data-section="color">
238
+ <div class="fig-layer-row"><label>Color</label></div>
239
+ <fig-layer data-section="color"
240
+ data-example="default">
241
+ <div class="fig-layer-row"><label>Default</label></div>
242
+ </fig-layer>
243
+ <fig-layer data-section="color"
244
+ data-example="with-alpha">
245
+ <div class="fig-layer-row"><label>With Alpha</label></div>
246
+ </fig-layer>
247
+ </fig-layer>
248
+
249
+ <fig-layer data-section="fill">
250
+ <div class="fig-layer-row"><label>Fill</label></div>
251
+ <fig-layer data-section="fill"
252
+ data-example="solid">
253
+ <div class="fig-layer-row"><label>Solid</label></div>
254
+ </fig-layer>
255
+ <fig-layer data-section="fill"
256
+ data-example="linear-gradient">
257
+ <div class="fig-layer-row"><label>Linear Gradient</label></div>
258
+ </fig-layer>
259
+ <fig-layer data-section="fill"
260
+ data-example="radial-gradient">
261
+ <div class="fig-layer-row"><label>Radial Gradient</label></div>
262
+ </fig-layer>
263
+ <fig-layer data-section="fill"
264
+ data-example="angular-gradient">
265
+ <div class="fig-layer-row"><label>Angular Gradient</label></div>
266
+ </fig-layer>
267
+ <fig-layer data-section="fill"
268
+ data-example="image">
269
+ <div class="fig-layer-row"><label>Image</label></div>
270
+ </fig-layer>
271
+ </fig-layer>
272
+
273
+ <fig-layer data-section="slider">
274
+ <div class="fig-layer-row"><label>Slider</label></div>
275
+ <fig-layer data-section="slider"
276
+ data-example="default">
277
+ <div class="fig-layer-row"><label>Default</label></div>
278
+ </fig-layer>
279
+ <fig-layer data-section="slider"
280
+ data-example="units">
281
+ <div class="fig-layer-row"><label>Units</label></div>
282
+ </fig-layer>
283
+ <fig-layer data-section="slider"
284
+ data-example="opacity">
285
+ <div class="fig-layer-row"><label>Opacity</label></div>
286
+ </fig-layer>
287
+ <fig-layer data-section="slider"
288
+ data-example="hue">
289
+ <div class="fig-layer-row"><label>Hue</label></div>
290
+ </fig-layer>
291
+ <fig-layer data-section="slider"
292
+ data-example="stepper">
293
+ <div class="fig-layer-row"><label>Stepper</label></div>
294
+ </fig-layer>
295
+ <fig-layer data-section="slider"
296
+ data-example="delta">
297
+ <div class="fig-layer-row"><label>Delta</label></div>
298
+ </fig-layer>
299
+ <fig-layer data-section="slider"
300
+ data-example="transform">
301
+ <div class="fig-layer-row"><label>Transform</label></div>
302
+ </fig-layer>
303
+ </fig-layer>
304
+
305
+ <fig-layer data-section="switch">
306
+ <div class="fig-layer-row"><label>Switch</label></div>
307
+ <fig-layer data-section="switch"
308
+ data-example="default">
309
+ <div class="fig-layer-row"><label>Default</label></div>
310
+ </fig-layer>
311
+ </fig-layer>
312
+
313
+ <fig-layer data-section="dropdown">
314
+ <div class="fig-layer-row"><label>Dropdown</label></div>
315
+ <fig-layer data-section="dropdown"
316
+ data-example="default">
317
+ <div class="fig-layer-row"><label>Default</label></div>
318
+ </fig-layer>
319
+ </fig-layer>
320
+
321
+ <fig-layer data-section="segment">
322
+ <div class="fig-layer-row"><label>Segment</label></div>
323
+ <fig-layer data-section="segment"
324
+ data-example="default">
325
+ <div class="fig-layer-row"><label>Default</label></div>
326
+ </fig-layer>
327
+ </fig-layer>
328
+
329
+ <fig-layer data-section="dial">
330
+ <div class="fig-layer-row"><label>Dial</label></div>
331
+ <fig-layer data-section="dial"
332
+ data-example="default">
333
+ <div class="fig-layer-row"><label>Default</label></div>
334
+ </fig-layer>
335
+ </fig-layer>
336
+
337
+ <fig-layer data-section="easing">
338
+ <div class="fig-layer-row"><label>Easing Curve</label></div>
339
+ <fig-layer data-section="easing"
340
+ data-example="default">
341
+ <div class="fig-layer-row"><label>Default</label></div>
342
+ </fig-layer>
343
+ <fig-layer data-section="easing"
344
+ data-example="no-dropdown">
345
+ <div class="fig-layer-row"><label>No Dropdown</label></div>
346
+ </fig-layer>
347
+ <fig-layer data-section="easing"
348
+ data-example="16-9-horizontal">
349
+ <div class="fig-layer-row"><label>16:9 Horizontal</label></div>
350
+ </fig-layer>
351
+ <fig-layer data-section="easing"
352
+ data-example="no-label">
353
+ <div class="fig-layer-row"><label>No Label</label></div>
354
+ </fig-layer>
355
+ </fig-layer>
356
+
357
+ <fig-layer data-section="3d-rotate">
358
+ <div class="fig-layer-row"><label>3D Rotate</label></div>
359
+ <fig-layer data-section="3d-rotate"
360
+ data-example="default">
361
+ <div class="fig-layer-row"><label>Default</label></div>
362
+ </fig-layer>
363
+ <fig-layer data-section="3d-rotate"
364
+ data-example="16-9-horizontal">
365
+ <div class="fig-layer-row"><label>16:9 Horizontal</label></div>
366
+ </fig-layer>
367
+ <fig-layer data-section="3d-rotate"
368
+ data-example="4-3">
369
+ <div class="fig-layer-row"><label>4:3</label></div>
370
+ </fig-layer>
371
+ <fig-layer data-section="3d-rotate"
372
+ data-example="no-label">
373
+ <div class="fig-layer-row"><label>No Label</label></div>
374
+ </fig-layer>
375
+ <fig-layer data-section="3d-rotate"
376
+ data-example="fields-all-axes">
377
+ <div class="fig-layer-row"><label>Fields (All Axes)</label></div>
378
+ </fig-layer>
379
+ <fig-layer data-section="3d-rotate"
380
+ data-example="fields-y-only">
381
+ <div class="fig-layer-row"><label>Fields (Y Only)</label></div>
382
+ </fig-layer>
383
+ <fig-layer data-section="3d-rotate"
384
+ data-example="fields-x-y">
385
+ <div class="fig-layer-row"><label>Fields (X &amp; Y)</label></div>
386
+ </fig-layer>
387
+ <fig-layer data-section="3d-rotate"
388
+ data-example="fields-16-9-preset">
389
+ <div class="fig-layer-row"><label>Fields + 16:9 + Preset</label></div>
390
+ </fig-layer>
391
+ <fig-layer data-section="3d-rotate"
392
+ data-example="fields-no-label">
393
+ <div class="fig-layer-row"><label>Fields, No Label</label></div>
394
+ </fig-layer>
395
+ </fig-layer>
396
+
397
+ <fig-layer data-section="angle">
398
+ <div class="fig-layer-row"><label>Angle</label></div>
399
+ <fig-layer data-section="angle"
400
+ data-example="default">
401
+ <div class="fig-layer-row"><label>Default</label></div>
402
+ </fig-layer>
403
+ </fig-layer>
404
+
405
+ <fig-layer data-section="combined">
406
+ <div class="fig-layer-row"><label>Combined Panel</label></div>
407
+ <fig-layer data-section="combined"
408
+ data-example="default">
409
+ <div class="fig-layer-row"><label>Default</label></div>
410
+ </fig-layer>
411
+ </fig-layer>
222
412
  </div>
223
413
  <div class="theme-switch">
224
414
  <fig-button id="theme-light-btn"
@@ -257,1016 +447,1048 @@
257
447
  <h2>Image</h2>
258
448
  <p class="description">An image upload field for selecting or previewing image assets.</p>
259
449
 
260
- <fig-header borderless
261
- class="propkit-subheader">
262
- <h3>Upload</h3>
263
- <fig-button variant="secondary"
264
- class="copy-prompt-btn">Copy prompt</fig-button>
265
- </fig-header>
266
- <hstack>
267
- <div class="prop-panel">
268
- <fig-field direction="horizontal">
269
- <label>Image</label>
270
- <fig-image full="true"
271
- upload="true"
272
- label="Upload"
273
- size="auto"></fig-image>
274
- </fig-field>
275
- </div>
450
+ <div class="propkit-example"
451
+ data-example="upload">
452
+ <hstack>
453
+ <div class="prop-panel">
454
+ <fig-field direction="horizontal">
455
+ <label>Image</label>
456
+ <fig-image full="true"
457
+ upload="true"
458
+ label="Upload"
459
+ size="auto"></fig-image>
460
+ </fig-field>
461
+ </div>
462
+ <div class="prop-panel">
463
+ <fig-field direction="horizontal">
464
+ <label>Image</label>
465
+ <fig-image full="true"
466
+ upload="true"
467
+ src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=260&h=400&fit=crop"
468
+ size="auto"></fig-image>
469
+ </fig-field>
470
+ </div>
471
+ </hstack>
472
+ </div>
473
+
474
+ <div class="propkit-example"
475
+ data-example="auto-aspect-ratio">
276
476
  <div class="prop-panel">
277
477
  <fig-field direction="horizontal">
278
478
  <label>Image</label>
279
479
  <fig-image full="true"
280
- upload="true"
281
480
  src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=260&h=400&fit=crop"
282
- size="auto"></fig-image>
481
+ aspect-ratio="auto"></fig-image>
283
482
  </fig-field>
284
483
  </div>
285
- </hstack>
286
-
287
- <fig-header borderless
288
- class="propkit-subheader">
289
- <h3>Auto Aspect Ratio</h3>
290
- <fig-button variant="secondary"
291
- class="copy-prompt-btn">Copy prompt</fig-button>
292
- </fig-header>
293
- <div class="prop-panel">
294
- <fig-field direction="horizontal">
295
- <label>Image</label>
296
- <fig-image full="true"
297
- src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=260&h=400&fit=crop"
298
- aspect-ratio="auto"></fig-image>
299
- </fig-field>
300
- </div>
301
-
302
- <fig-header borderless
303
- class="propkit-subheader">
304
- <h3>16:9</h3>
305
- <fig-button variant="secondary"
306
- class="copy-prompt-btn">Copy prompt</fig-button>
307
- </fig-header>
308
- <div class="prop-panel">
309
- <fig-field direction="horizontal">
310
- <label>Image</label>
311
- <fig-image full="true"
312
- src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=480&h=270&fit=crop"
313
- aspect-ratio="16/9"></fig-image>
314
- </fig-field>
315
- </div>
316
-
317
- <fig-header borderless
318
- class="propkit-subheader">
319
- <h3>4:3</h3>
320
- <fig-button variant="secondary"
321
- class="copy-prompt-btn">Copy prompt</fig-button>
322
- </fig-header>
323
- <div class="prop-panel">
324
- <fig-field direction="horizontal">
325
- <label>Image</label>
326
- <fig-image full="true"
327
- src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=400&h=300&fit=crop"
328
- aspect-ratio="4/3"></fig-image>
329
- </fig-field>
330
484
  </div>
331
485
 
332
- <fig-header borderless
333
- class="propkit-subheader">
334
- <h3>Cover</h3>
335
- <fig-button variant="secondary"
336
- class="copy-prompt-btn">Copy prompt</fig-button>
337
- </fig-header>
338
- <hstack>
339
- <div class="prop-panel">
340
- <fig-field direction="horizontal">
341
- <label>Portrait</label>
342
- <fig-image full="true"
343
- src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=260&h=400&fit=crop"
344
- fit="cover"
345
- size="auto"
346
- aspect-ratio="4/3"></fig-image>
347
- </fig-field>
348
- </div>
486
+ <div class="propkit-example"
487
+ data-example="16-9">
349
488
  <div class="prop-panel">
350
489
  <fig-field direction="horizontal">
351
- <label>Landscape</label>
490
+ <label>Image</label>
352
491
  <fig-image full="true"
353
492
  src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=480&h=270&fit=crop"
354
- fit="cover"
355
- size="auto"
356
- aspect-ratio="4/3"></fig-image>
493
+ aspect-ratio="16/9"></fig-image>
357
494
  </fig-field>
358
495
  </div>
359
- </hstack>
496
+ </div>
360
497
 
361
- <fig-header borderless
362
- class="propkit-subheader">
363
- <h3>Contain</h3>
364
- <fig-button variant="secondary"
365
- class="copy-prompt-btn">Copy prompt</fig-button>
366
- </fig-header>
367
- <hstack>
498
+ <div class="propkit-example"
499
+ data-example="4-3">
368
500
  <div class="prop-panel">
369
501
  <fig-field direction="horizontal">
370
- <label>Portrait</label>
371
- <fig-image full="true"
372
- src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=260&h=400&fit=crop"
373
- fit="contain"
374
- size="auto"
375
- aspect-ratio="4/3"></fig-image>
376
- </fig-field>
377
- </div>
378
- <div class="prop-panel">
379
- <fig-field direction="horizontal">
380
- <label>Landscape</label>
502
+ <label>Image</label>
381
503
  <fig-image full="true"
382
- src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=480&h=270&fit=crop"
383
- fit="contain"
384
- size="auto"
504
+ src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=400&h=300&fit=crop"
385
505
  aspect-ratio="4/3"></fig-image>
386
506
  </fig-field>
387
507
  </div>
388
- </hstack>
389
- </section>
508
+ </div>
509
+
510
+ <div class="propkit-example"
511
+ data-example="cover">
512
+ <hstack>
513
+ <div class="prop-panel">
514
+ <fig-field direction="horizontal">
515
+ <label>Portrait</label>
516
+ <fig-image full="true"
517
+ src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=260&h=400&fit=crop"
518
+ fit="cover"
519
+ size="auto"
520
+ aspect-ratio="4/3"></fig-image>
521
+ </fig-field>
522
+ </div>
523
+ <div class="prop-panel">
524
+ <fig-field direction="horizontal">
525
+ <label>Landscape</label>
526
+ <fig-image full="true"
527
+ src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=480&h=270&fit=crop"
528
+ fit="cover"
529
+ size="auto"
530
+ aspect-ratio="4/3"></fig-image>
531
+ </fig-field>
532
+ </div>
533
+ </hstack>
534
+ </div>
390
535
 
391
- <hr>
536
+ <div class="propkit-example"
537
+ data-example="contain">
538
+ <hstack>
539
+ <div class="prop-panel">
540
+ <fig-field direction="horizontal">
541
+ <label>Portrait</label>
542
+ <fig-image full="true"
543
+ src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=260&h=400&fit=crop"
544
+ fit="contain"
545
+ size="auto"
546
+ aspect-ratio="4/3"></fig-image>
547
+ </fig-field>
548
+ </div>
549
+ <div class="prop-panel">
550
+ <fig-field direction="horizontal">
551
+ <label>Landscape</label>
552
+ <fig-image full="true"
553
+ src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=480&h=270&fit=crop"
554
+ fit="contain"
555
+ size="auto"
556
+ aspect-ratio="4/3"></fig-image>
557
+ </fig-field>
558
+ </div>
559
+ </hstack>
560
+ </div>
561
+ </section>
392
562
 
393
563
  <!-- Color -->
394
564
  <section id="color">
395
565
  <h2>Color</h2>
396
566
  <p class="description">A solid color picker field with hex input and optional alpha.</p>
397
567
 
398
- <fig-header borderless
399
- class="propkit-subheader">
400
- <h3>Default</h3>
401
- <fig-button variant="secondary"
402
- class="copy-prompt-btn">Copy prompt</fig-button>
403
- </fig-header>
404
- <hstack>
568
+ <div class="propkit-example"
569
+ data-example="default">
405
570
  <div class="prop-panel">
406
571
  <fig-field direction="horizontal">
407
572
  <label>Color</label>
408
- <fig-input-color value="#0D99FF80"
573
+ <fig-input-color value="#0D99FF"
409
574
  text="true"
410
- alpha="true"
411
575
  picker="figma"
412
576
  picker-anchor="self"
413
577
  full></fig-input-color>
414
578
  </fig-field>
415
579
  </div>
580
+ </div>
581
+
582
+ <div class="propkit-example"
583
+ data-example="with-alpha">
416
584
  <div class="prop-panel">
417
585
  <fig-field direction="horizontal">
418
586
  <label>Color</label>
419
- <fig-input-color value="#0D99FF"
587
+ <fig-input-color value="#0D99FF80"
420
588
  text="true"
589
+ alpha="true"
421
590
  picker="figma"
422
591
  picker-anchor="self"
423
592
  full></fig-input-color>
424
593
  </fig-field>
425
594
  </div>
426
- </hstack>
595
+ </div>
427
596
  </section>
428
597
 
429
- <hr>
430
-
431
598
  <!-- Fill -->
432
599
  <section id="fill">
433
600
  <h2>Fill</h2>
434
601
  <p class="description">A multi-mode fill field supporting solid, gradient, and image fills.</p>
435
602
 
436
- <fig-header borderless
437
- class="propkit-subheader">
438
- <h3>Solid</h3>
439
- <fig-button variant="secondary"
440
- class="copy-prompt-btn">Copy prompt</fig-button>
441
- </fig-header>
442
- <hstack>
603
+ <div class="propkit-example"
604
+ data-example="solid">
605
+ <hstack>
606
+ <div class="prop-panel">
607
+ <fig-field direction="horizontal">
608
+ <label>Fill</label>
609
+ <fig-input-fill value='{"type":"solid","color":"#667eea"}'
610
+ experimental="modern"></fig-input-fill>
611
+ </fig-field>
612
+ </div>
613
+ <div class="prop-panel">
614
+ <fig-field direction="horizontal">
615
+ <label>Fill</label>
616
+ <fig-input-fill value='{"type":"solid","color":"#667eea"}'
617
+ alpha="false"
618
+ experimental="modern"></fig-input-fill>
619
+ </fig-field>
620
+ </div>
621
+ </hstack>
622
+ </div>
623
+
624
+ <div class="propkit-example"
625
+ data-example="linear-gradient">
626
+ <hstack>
627
+ <div class="prop-panel">
628
+ <fig-field direction="horizontal">
629
+ <label>Fill</label>
630
+ <fig-input-fill value='{"type":"gradient","gradient":{"type":"linear","angle":135,"stops":[{"position":0,"color":"#667eea","opacity":100},{"position":100,"color":"#764ba2","opacity":100}]}}'
631
+ experimental="modern"></fig-input-fill>
632
+ </fig-field>
633
+ </div>
634
+ <div class="prop-panel">
635
+ <fig-field direction="horizontal">
636
+ <label>Fill</label>
637
+ <fig-input-fill value='{"type":"gradient","gradient":{"type":"linear","angle":90,"stops":[{"position":0,"color":"#f093fb","opacity":100},{"position":50,"color":"#f5576c","opacity":100},{"position":100,"color":"#ffd868","opacity":100}]}}'
638
+ experimental="modern"></fig-input-fill>
639
+ </fig-field>
640
+ </div>
641
+ </hstack>
642
+ </div>
643
+
644
+ <div class="propkit-example"
645
+ data-example="radial-gradient">
646
+ <hstack>
647
+ <div class="prop-panel">
648
+ <fig-field direction="horizontal">
649
+ <label>Fill</label>
650
+ <fig-input-fill value='{"type":"gradient","gradient":{"type":"radial","centerX":50,"centerY":50,"stops":[{"position":0,"color":"#ff6b6b","opacity":100},{"position":100,"color":"#4ecdc4","opacity":100}]}}'
651
+ experimental="modern"></fig-input-fill>
652
+ </fig-field>
653
+ </div>
654
+ <div class="prop-panel">
655
+ <fig-field direction="horizontal">
656
+ <label>Fill</label>
657
+ <fig-input-fill value='{"type":"gradient","gradient":{"type":"radial","centerX":50,"centerY":50,"stops":[{"position":0,"color":"#ffffff","opacity":100},{"position":100,"color":"#0D99FF","opacity":100}]}}'
658
+ experimental="modern"></fig-input-fill>
659
+ </fig-field>
660
+ </div>
661
+ </hstack>
662
+ </div>
663
+
664
+ <div class="propkit-example"
665
+ data-example="angular-gradient">
666
+ <hstack>
667
+ <div class="prop-panel">
668
+ <fig-field direction="horizontal">
669
+ <label>Fill</label>
670
+ <fig-input-fill value='{"type":"gradient","gradient":{"type":"angular","stops":[{"position":0,"color":"#ff0000","opacity":100},{"position":33,"color":"#00ff00","opacity":100},{"position":66,"color":"#0000ff","opacity":100},{"position":100,"color":"#ff0000","opacity":100}]}}'
671
+ experimental="modern"></fig-input-fill>
672
+ </fig-field>
673
+ </div>
674
+ <div class="prop-panel">
675
+ <fig-field direction="horizontal">
676
+ <label>Fill</label>
677
+ <fig-input-fill value='{"type":"gradient","gradient":{"type":"angular","stops":[{"position":0,"color":"#f7971e","opacity":100},{"position":100,"color":"#ffd200","opacity":100}]}}'
678
+ experimental="modern"></fig-input-fill>
679
+ </fig-field>
680
+ </div>
681
+ </hstack>
682
+ </div>
683
+
684
+ <div class="propkit-example"
685
+ data-example="image">
686
+ <hstack>
687
+ <div class="prop-panel">
688
+ <fig-field direction="horizontal">
689
+ <label>Fill</label>
690
+ <fig-input-fill value='{"type":"image","image":{"url":"https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=200&h=200&fit=crop","scaleMode":"fill","scale":50,"opacity":1}}'
691
+ experimental="modern"></fig-input-fill>
692
+ </fig-field>
693
+ </div>
694
+ <div class="prop-panel">
695
+ <fig-field direction="horizontal">
696
+ <label>Fill</label>
697
+ <fig-input-fill value='{"type":"image","image":{"url":"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200&h=200&fit=crop","scaleMode":"fill","scale":50,"opacity":0.5}}'
698
+ experimental="modern"></fig-input-fill>
699
+ </fig-field>
700
+ </div>
701
+ </hstack>
702
+ </div>
703
+ </section>
704
+
705
+ <!-- Slider -->
706
+ <section id="slider">
707
+ <h2>Slider</h2>
708
+ <p class="description">A range slider with optional text input for precise numeric values.</p>
709
+
710
+ <div class="propkit-example"
711
+ data-example="default">
712
+ <hstack>
713
+ <div class="prop-panel">
714
+ <fig-field direction="horizontal">
715
+ <label>Amount</label>
716
+ <fig-slider value="50"
717
+ min="0"
718
+ max="100"
719
+ text="true"
720
+ full></fig-slider>
721
+ </fig-field>
722
+ </div>
723
+ <div class="prop-panel">
724
+ <fig-field direction="horizontal">
725
+ <label>Amount</label>
726
+ <fig-slider value="50"
727
+ min="0"
728
+ max="100"
729
+ full></fig-slider>
730
+ </fig-field>
731
+ </div>
732
+ </hstack>
733
+ </div>
734
+
735
+ <div class="propkit-example"
736
+ data-example="units">
737
+ <hstack>
738
+ <div class="prop-panel">
739
+ <fig-field direction="horizontal">
740
+ <label>Opacity</label>
741
+ <fig-slider value="75"
742
+ min="0"
743
+ max="100"
744
+ text="true"
745
+ units="%"
746
+ full></fig-slider>
747
+ </fig-field>
748
+ </div>
749
+ <div class="prop-panel">
750
+ <fig-field direction="horizontal">
751
+ <label>Opacity</label>
752
+ <fig-slider value="75"
753
+ min="0"
754
+ max="100"
755
+ units="%"
756
+ full></fig-slider>
757
+ </fig-field>
758
+ </div>
759
+ </hstack>
760
+ </div>
761
+
762
+ <div class="propkit-example"
763
+ data-example="opacity">
764
+ <hstack>
765
+ <div class="prop-panel">
766
+ <fig-field direction="horizontal">
767
+ <label>Opacity</label>
768
+ <fig-slider type="opacity"
769
+ value="0.75"
770
+ color="#ff0000"
771
+ units="%"
772
+ text="true"
773
+ full></fig-slider>
774
+ </fig-field>
775
+ </div>
776
+ <div class="prop-panel">
777
+ <fig-field direction="horizontal">
778
+ <label>Opacity</label>
779
+ <fig-slider type="opacity"
780
+ value="0.75"
781
+ color="#ff0000"
782
+ units="%"
783
+ full></fig-slider>
784
+ </fig-field>
785
+ </div>
786
+ </hstack>
787
+ </div>
788
+
789
+ <div class="propkit-example"
790
+ data-example="hue">
791
+ <hstack>
792
+ <div class="prop-panel">
793
+ <fig-field direction="horizontal">
794
+ <label>Hue</label>
795
+ <fig-slider type="hue"
796
+ value="180"
797
+ text="true"
798
+ full></fig-slider>
799
+ </fig-field>
800
+ </div>
801
+ <div class="prop-panel">
802
+ <fig-field direction="horizontal">
803
+ <label>Hue</label>
804
+ <fig-slider type="hue"
805
+ value="180"
806
+ full></fig-slider>
807
+ </fig-field>
808
+ </div>
809
+ </hstack>
810
+ </div>
811
+
812
+ <div class="propkit-example"
813
+ data-example="stepper">
814
+ <hstack>
815
+ <div class="prop-panel">
816
+ <fig-field direction="horizontal">
817
+ <label>Steps</label>
818
+ <fig-slider type="stepper"
819
+ value="50"
820
+ step="25"
821
+ text="true"
822
+ full>
823
+ <datalist>
824
+ <option value="0"></option>
825
+ <option value="25"></option>
826
+ <option value="50"></option>
827
+ <option value="75"></option>
828
+ <option value="100"></option>
829
+ </datalist>
830
+ </fig-slider>
831
+ </fig-field>
832
+ </div>
833
+ <div class="prop-panel">
834
+ <fig-field direction="horizontal">
835
+ <label>Steps</label>
836
+ <fig-slider type="stepper"
837
+ value="50"
838
+ step="25"
839
+ full>
840
+ <datalist>
841
+ <option value="0"></option>
842
+ <option value="25"></option>
843
+ <option value="50"></option>
844
+ <option value="75"></option>
845
+ <option value="100"></option>
846
+ </datalist>
847
+ </fig-slider>
848
+ </fig-field>
849
+ </div>
850
+ </hstack>
851
+ </div>
852
+
853
+ <div class="propkit-example"
854
+ data-example="delta">
855
+ <hstack>
856
+ <div class="prop-panel">
857
+ <fig-field direction="horizontal">
858
+ <label>Offset</label>
859
+ <fig-slider type="delta"
860
+ value="0"
861
+ default="0"
862
+ step="0.25"
863
+ min="-5"
864
+ max="5"
865
+ text="true"
866
+ full>
867
+ <datalist>
868
+ <option value="0"></option>
869
+ </datalist>
870
+ </fig-slider>
871
+ </fig-field>
872
+ </div>
873
+ <div class="prop-panel">
874
+ <fig-field direction="horizontal">
875
+ <label>Offset</label>
876
+ <fig-slider type="delta"
877
+ value="0"
878
+ default="0"
879
+ step="0.25"
880
+ min="-5"
881
+ max="5"
882
+ full>
883
+ <datalist>
884
+ <option value="0"></option>
885
+ </datalist>
886
+ </fig-slider>
887
+ </fig-field>
888
+ </div>
889
+ </hstack>
890
+ </div>
891
+
892
+ <div class="propkit-example"
893
+ data-example="transform">
894
+ <hstack>
895
+ <div class="prop-panel">
896
+ <fig-field direction="horizontal">
897
+ <label>Scale</label>
898
+ <fig-slider min="0"
899
+ max="1"
900
+ value="0.5"
901
+ step="0.01"
902
+ transform="100"
903
+ text="true"
904
+ units="%"
905
+ full></fig-slider>
906
+ </fig-field>
907
+ </div>
908
+ <div class="prop-panel">
909
+ <fig-field direction="horizontal">
910
+ <label>Scale</label>
911
+ <fig-slider min="0"
912
+ max="1"
913
+ value="0.5"
914
+ step="0.01"
915
+ transform="100"
916
+ units="%"
917
+ full></fig-slider>
918
+ </fig-field>
919
+ </div>
920
+ </hstack>
921
+ </div>
922
+ </section>
923
+
924
+ <!-- Switch -->
925
+ <section id="switch">
926
+ <h2>Switch</h2>
927
+ <p class="description">A toggle switch for boolean on/off properties.</p>
928
+
929
+ <div class="propkit-example"
930
+ data-example="default">
443
931
  <div class="prop-panel">
444
932
  <fig-field direction="horizontal">
445
- <label>Fill</label>
446
- <fig-input-fill value='{"type":"solid","color":"#667eea"}'
447
- experimental="modern"></fig-input-fill>
933
+ <label>Visible</label>
934
+ <fig-switch checked="true"></fig-switch>
448
935
  </fig-field>
449
936
  </div>
937
+ </div>
938
+ </section>
939
+
940
+ <!-- Dropdown -->
941
+ <section id="dropdown">
942
+ <h2>Dropdown</h2>
943
+ <p class="description">A dropdown select field for choosing from a set of options.</p>
944
+
945
+ <div class="propkit-example"
946
+ data-example="default">
450
947
  <div class="prop-panel">
451
948
  <fig-field direction="horizontal">
452
- <label>Fill</label>
453
- <fig-input-fill value='{"type":"solid","color":"#667eea"}'
454
- alpha="false"
455
- experimental="modern"></fig-input-fill>
949
+ <label>Blend Mode</label>
950
+ <fig-dropdown full
951
+ experimental="modern">
952
+ <option selected>Normal</option>
953
+ <option>Multiply</option>
954
+ <option>Screen</option>
955
+ <option>Overlay</option>
956
+ <option>Darken</option>
957
+ <option>Lighten</option>
958
+ </fig-dropdown>
456
959
  </fig-field>
457
960
  </div>
458
- </hstack>
961
+ </div>
962
+ </section>
459
963
 
460
- <fig-header borderless
461
- class="propkit-subheader">
462
- <h3>Linear Gradient</h3>
463
- <fig-button variant="secondary"
464
- class="copy-prompt-btn">Copy prompt</fig-button>
465
- </fig-header>
466
- <hstack>
964
+ <!-- Segment -->
965
+ <section id="segment">
966
+ <h2>Segment</h2>
967
+ <p class="description">A segmented control for mutually exclusive choices.</p>
968
+
969
+ <div class="propkit-example"
970
+ data-example="default">
467
971
  <div class="prop-panel">
468
972
  <fig-field direction="horizontal">
469
- <label>Fill</label>
470
- <fig-input-fill value='{"type":"gradient","gradient":{"type":"linear","angle":135,"stops":[{"position":0,"color":"#667eea","opacity":100},{"position":100,"color":"#764ba2","opacity":100}]}}'
471
- experimental="modern"></fig-input-fill>
973
+ <label>Align</label>
974
+ <fig-segmented-control full>
975
+ <fig-segment value="left"
976
+ selected>Left</fig-segment>
977
+ <fig-segment value="center">Center</fig-segment>
978
+ <fig-segment value="right">Right</fig-segment>
979
+ </fig-segmented-control>
472
980
  </fig-field>
473
981
  </div>
982
+ </div>
983
+ </section>
984
+
985
+ <!-- Dial -->
986
+ <section id="dial">
987
+ <h2>Dial</h2>
988
+ <p class="description">A rotary dial for continuous value input. <em>Not yet built.</em></p>
989
+
990
+ <div class="propkit-example"
991
+ data-example="default">
474
992
  <div class="prop-panel">
475
993
  <fig-field direction="horizontal">
476
- <label>Fill</label>
477
- <fig-input-fill value='{"type":"gradient","gradient":{"type":"linear","angle":90,"stops":[{"position":0,"color":"#f093fb","opacity":100},{"position":50,"color":"#f5576c","opacity":100},{"position":100,"color":"#ffd868","opacity":100}]}}'
478
- experimental="modern"></fig-input-fill>
994
+ <label>Amount</label>
995
+ <div class="placeholder-field">fig-input-dial</div>
479
996
  </fig-field>
480
997
  </div>
481
- </hstack>
998
+ </div>
999
+ </section>
482
1000
 
483
- <fig-header borderless
484
- class="propkit-subheader">
485
- <h3>Radial Gradient</h3>
486
- <fig-button variant="secondary"
487
- class="copy-prompt-btn">Copy prompt</fig-button>
488
- </fig-header>
489
- <hstack>
1001
+ <!-- Easing Curve -->
1002
+ <section id="easing">
1003
+ <h2>Easing Curve</h2>
1004
+ <p class="description">A bezier curve editor for animation easing with preset dropdown.</p>
1005
+
1006
+ <div class="propkit-example"
1007
+ data-example="default">
490
1008
  <div class="prop-panel">
491
1009
  <fig-field direction="horizontal">
492
- <label>Fill</label>
493
- <fig-input-fill value='{"type":"gradient","gradient":{"type":"radial","centerX":50,"centerY":50,"stops":[{"position":0,"color":"#ff6b6b","opacity":100},{"position":100,"color":"#4ecdc4","opacity":100}]}}'
494
- experimental="modern"></fig-input-fill>
1010
+ <label>Easing</label>
1011
+ <fig-easing-curve value="0.42, 0, 0.58, 1"
1012
+ id="easing-curve-observed"
1013
+ dropdown="true"></fig-easing-curve>
495
1014
  </fig-field>
496
1015
  </div>
1016
+ <div class="event-dump" id="easing-curve-dump"></div>
1017
+ </div>
1018
+
1019
+ <div class="propkit-example"
1020
+ data-example="no-dropdown">
497
1021
  <div class="prop-panel">
498
1022
  <fig-field direction="horizontal">
499
- <label>Fill</label>
500
- <fig-input-fill value='{"type":"gradient","gradient":{"type":"radial","centerX":50,"centerY":50,"stops":[{"position":0,"color":"#ffffff","opacity":100},{"position":100,"color":"#0D99FF","opacity":100}]}}'
501
- experimental="modern"></fig-input-fill>
1023
+ <label>Easing</label>
1024
+ <fig-easing-curve value="0.25, 0.1, 0.25, 1"></fig-easing-curve>
502
1025
  </fig-field>
503
1026
  </div>
504
- </hstack>
1027
+ </div>
505
1028
 
506
- <fig-header borderless
507
- class="propkit-subheader">
508
- <h3>Angular Gradient</h3>
509
- <fig-button variant="secondary"
510
- class="copy-prompt-btn">Copy prompt</fig-button>
511
- </fig-header>
512
- <hstack>
1029
+ <div class="propkit-example"
1030
+ data-example="16-9-horizontal">
513
1031
  <div class="prop-panel">
514
1032
  <fig-field direction="horizontal">
515
- <label>Fill</label>
516
- <fig-input-fill value='{"type":"gradient","gradient":{"type":"angular","stops":[{"position":0,"color":"#ff0000","opacity":100},{"position":33,"color":"#00ff00","opacity":100},{"position":66,"color":"#0000ff","opacity":100},{"position":100,"color":"#ff0000","opacity":100}]}}'
517
- experimental="modern"></fig-input-fill>
1033
+ <label>Easing</label>
1034
+ <fig-easing-curve value="0.25, 0.1, 0.25, 1"
1035
+ aspect-ratio="16/9"></fig-easing-curve>
518
1036
  </fig-field>
519
1037
  </div>
1038
+ </div>
1039
+
1040
+ <div class="propkit-example"
1041
+ data-example="no-label">
520
1042
  <div class="prop-panel">
521
1043
  <fig-field direction="horizontal">
522
- <label>Fill</label>
523
- <fig-input-fill value='{"type":"gradient","gradient":{"type":"angular","stops":[{"position":0,"color":"#f7971e","opacity":100},{"position":100,"color":"#ffd200","opacity":100}]}}'
524
- experimental="modern"></fig-input-fill>
1044
+ <fig-easing-curve value="spring(250, 8, 1)"
1045
+ dropdown="true"></fig-easing-curve>
525
1046
  </fig-field>
526
1047
  </div>
527
- </hstack>
1048
+ </div>
1049
+ </section>
528
1050
 
529
- <fig-header borderless
530
- class="propkit-subheader">
531
- <h3>Image</h3>
532
- <fig-button variant="secondary"
533
- class="copy-prompt-btn">Copy prompt</fig-button>
534
- </fig-header>
535
- <hstack>
1051
+ <!-- 3D Rotate -->
1052
+ <section id="3d-rotate">
1053
+ <h2>3D Rotate</h2>
1054
+ <p class="description">An interactive 3D rotation control with a draggable cube preview.</p>
1055
+
1056
+ <div class="propkit-example"
1057
+ data-example="default">
536
1058
  <div class="prop-panel">
537
1059
  <fig-field direction="horizontal">
538
- <label>Fill</label>
539
- <fig-input-fill value='{"type":"image","image":{"url":"https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=200&h=200&fit=crop","scaleMode":"fill","scale":50,"opacity":1}}'
540
- experimental="modern"></fig-input-fill>
1060
+ <label>Rotation</label>
1061
+ <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1062
+ id="3d-rotate-observed"></fig-3d-rotate>
541
1063
  </fig-field>
542
1064
  </div>
1065
+ <div class="event-dump" id="3d-rotate-dump"></div>
1066
+ </div>
1067
+
1068
+ <div class="propkit-example"
1069
+ data-example="16-9-horizontal">
543
1070
  <div class="prop-panel">
544
1071
  <fig-field direction="horizontal">
545
- <label>Fill</label>
546
- <fig-input-fill value='{"type":"image","image":{"url":"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200&h=200&fit=crop","scaleMode":"fill","scale":50,"opacity":0.5}}'
547
- experimental="modern"></fig-input-fill>
1072
+ <label>Rotation</label>
1073
+ <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1074
+ aspect-ratio="16/9"></fig-3d-rotate>
548
1075
  </fig-field>
549
1076
  </div>
550
- </hstack>
551
- </section>
552
-
553
- <hr>
554
-
555
- <!-- Slider -->
556
- <section id="slider">
557
- <h2>Slider</h2>
558
- <p class="description">A range slider with optional text input for precise numeric values.</p>
1077
+ </div>
559
1078
 
560
- <fig-header borderless
561
- class="propkit-subheader">
562
- <h3>Default</h3>
563
- <fig-button variant="secondary"
564
- class="copy-prompt-btn">Copy prompt</fig-button>
565
- </fig-header>
566
- <hstack>
1079
+ <div class="propkit-example"
1080
+ data-example="4-3">
567
1081
  <div class="prop-panel">
568
1082
  <fig-field direction="horizontal">
569
- <label>Amount</label>
570
- <fig-slider value="50"
571
- min="0"
572
- max="100"
573
- text="true"
574
- full></fig-slider>
1083
+ <label>Rotation</label>
1084
+ <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1085
+ aspect-ratio="4/3"></fig-3d-rotate>
575
1086
  </fig-field>
576
1087
  </div>
1088
+ </div>
1089
+
1090
+ <div class="propkit-example"
1091
+ data-example="no-label">
577
1092
  <div class="prop-panel">
578
1093
  <fig-field direction="horizontal">
579
- <label>Amount</label>
580
- <fig-slider value="50"
581
- min="0"
582
- max="100"
583
- full></fig-slider>
1094
+ <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1095
+ aspect-ratio="16/9"></fig-3d-rotate>
584
1096
  </fig-field>
585
1097
  </div>
586
- </hstack>
1098
+ </div>
587
1099
 
588
- <fig-header borderless
589
- class="propkit-subheader">
590
- <h3>Units</h3>
591
- <fig-button variant="secondary"
592
- class="copy-prompt-btn">Copy prompt</fig-button>
593
- </fig-header>
594
- <hstack>
1100
+ <div class="propkit-example"
1101
+ data-example="fields-all-axes">
595
1102
  <div class="prop-panel">
596
1103
  <fig-field direction="horizontal">
597
- <label>Opacity</label>
598
- <fig-slider value="75"
599
- min="0"
600
- max="100"
601
- text="true"
602
- units="%"
603
- full></fig-slider>
1104
+ <label>Rotation</label>
1105
+ <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1106
+ fields="rotateX,rotateY,rotateZ"></fig-3d-rotate>
604
1107
  </fig-field>
605
1108
  </div>
1109
+ </div>
1110
+
1111
+ <div class="propkit-example"
1112
+ data-example="fields-y-only">
606
1113
  <div class="prop-panel">
607
1114
  <fig-field direction="horizontal">
608
- <label>Opacity</label>
609
- <fig-slider value="75"
610
- min="0"
611
- max="100"
612
- units="%"
613
- full></fig-slider>
1115
+ <label>Rotation</label>
1116
+ <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1117
+ fields="rotateY"></fig-3d-rotate>
614
1118
  </fig-field>
615
1119
  </div>
616
- </hstack>
1120
+ </div>
617
1121
 
618
- <fig-header borderless
619
- class="propkit-subheader">
620
- <h3>Opacity</h3>
621
- <fig-button variant="secondary"
622
- class="copy-prompt-btn">Copy prompt</fig-button>
623
- </fig-header>
624
- <hstack>
1122
+ <div class="propkit-example"
1123
+ data-example="fields-x-y">
625
1124
  <div class="prop-panel">
626
1125
  <fig-field direction="horizontal">
627
- <label>Opacity</label>
628
- <fig-slider type="opacity"
629
- value="0.75"
630
- color="#ff0000"
631
- units="%"
632
- text="true"
633
- full></fig-slider>
1126
+ <label>Rotation</label>
1127
+ <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1128
+ fields="rotateX,rotateY"></fig-3d-rotate>
634
1129
  </fig-field>
635
1130
  </div>
1131
+ </div>
1132
+
1133
+ <div class="propkit-example"
1134
+ data-example="fields-16-9-preset">
636
1135
  <div class="prop-panel">
637
1136
  <fig-field direction="horizontal">
638
- <label>Opacity</label>
639
- <fig-slider type="opacity"
640
- value="0.75"
641
- color="#ff0000"
642
- units="%"
643
- full></fig-slider>
1137
+ <label>Rotation</label>
1138
+ <fig-3d-rotate value="rotateX(25deg) rotateY(-35deg) rotateZ(10deg)"
1139
+ fields="rotateX,rotateY,rotateZ"
1140
+ aspect-ratio="16/9"></fig-3d-rotate>
644
1141
  </fig-field>
645
1142
  </div>
646
- </hstack>
1143
+ </div>
647
1144
 
648
- <fig-header borderless
649
- class="propkit-subheader">
650
- <h3>Hue</h3>
651
- <fig-button variant="secondary"
652
- class="copy-prompt-btn">Copy prompt</fig-button>
653
- </fig-header>
654
- <hstack>
1145
+ <div class="propkit-example"
1146
+ data-example="fields-no-label">
655
1147
  <div class="prop-panel">
656
1148
  <fig-field direction="horizontal">
657
- <label>Hue</label>
658
- <fig-slider type="hue"
659
- value="180"
660
- text="true"
661
- full></fig-slider>
1149
+ <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1150
+ fields="rotateX,rotateY,rotateZ"></fig-3d-rotate>
662
1151
  </fig-field>
663
1152
  </div>
1153
+ </div>
1154
+ </section>
1155
+
1156
+ <!-- Angle -->
1157
+ <section id="angle">
1158
+ <h2>Angle</h2>
1159
+ <p class="description">An angle input with a visual dial and numeric text field.</p>
1160
+
1161
+ <div class="propkit-example"
1162
+ data-example="default">
664
1163
  <div class="prop-panel">
665
1164
  <fig-field direction="horizontal">
666
- <label>Hue</label>
667
- <fig-slider type="hue"
668
- value="180"
669
- full></fig-slider>
1165
+ <label>Rotation</label>
1166
+ <fig-input-angle value="45"
1167
+ text="true"
1168
+ full></fig-input-angle>
670
1169
  </fig-field>
671
1170
  </div>
672
- </hstack>
1171
+ </div>
1172
+ </section>
673
1173
 
674
- <fig-header borderless
675
- class="propkit-subheader">
676
- <h3>Stepper</h3>
677
- <fig-button variant="secondary"
678
- class="copy-prompt-btn">Copy prompt</fig-button>
679
- </fig-header>
680
- <hstack>
1174
+ <!-- Combined Panel -->
1175
+ <section id="combined">
1176
+ <h2>Combined Panel</h2>
1177
+ <p class="description">A realistic property panel combining multiple field types.</p>
1178
+
1179
+ <div class="propkit-example"
1180
+ data-example="default">
681
1181
  <div class="prop-panel">
682
1182
  <fig-field direction="horizontal">
683
- <label>Steps</label>
684
- <fig-slider type="stepper"
685
- value="50"
686
- step="25"
1183
+ <label>Fill</label>
1184
+ <fig-input-fill value='{"type":"solid","color":"#667eea"}'
1185
+ experimental="modern"></fig-input-fill>
1186
+ </fig-field>
1187
+ <fig-field direction="horizontal">
1188
+ <label>Opacity</label>
1189
+ <fig-slider value="100"
1190
+ min="0"
1191
+ max="100"
687
1192
  text="true"
688
- full>
689
- <datalist>
690
- <option value="0"></option>
691
- <option value="25"></option>
692
- <option value="50"></option>
693
- <option value="75"></option>
694
- <option value="100"></option>
695
- </datalist>
696
- </fig-slider>
1193
+ full></fig-slider>
697
1194
  </fig-field>
698
- </div>
699
- <div class="prop-panel">
700
1195
  <fig-field direction="horizontal">
701
- <label>Steps</label>
702
- <fig-slider type="stepper"
703
- value="50"
704
- step="25"
705
- full>
706
- <datalist>
707
- <option value="0"></option>
708
- <option value="25"></option>
709
- <option value="50"></option>
710
- <option value="75"></option>
711
- <option value="100"></option>
712
- </datalist>
713
- </fig-slider>
1196
+ <label>Blend</label>
1197
+ <fig-dropdown full
1198
+ experimental="modern">
1199
+ <option selected>Normal</option>
1200
+ <option>Multiply</option>
1201
+ <option>Screen</option>
1202
+ <option>Overlay</option>
1203
+ </fig-dropdown>
714
1204
  </fig-field>
715
- </div>
716
- </hstack>
717
-
718
- <fig-header borderless
719
- class="propkit-subheader">
720
- <h3>Delta</h3>
721
- <fig-button variant="secondary"
722
- class="copy-prompt-btn">Copy prompt</fig-button>
723
- </fig-header>
724
- <hstack>
725
- <div class="prop-panel">
726
1205
  <fig-field direction="horizontal">
727
- <label>Offset</label>
728
- <fig-slider type="delta"
729
- value="0"
730
- default="0"
731
- step="0.25"
732
- min="-5"
733
- max="5"
734
- text="true"
735
- full>
736
- <datalist>
737
- <option value="0"></option>
738
- </datalist>
739
- </fig-slider>
1206
+ <label>Visible</label>
1207
+ <fig-switch checked="true"></fig-switch>
1208
+ </fig-field>
1209
+ <fig-field direction="horizontal">
1210
+ <label>Rotation</label>
1211
+ <fig-input-angle value="0"
1212
+ text="true"
1213
+ full></fig-input-angle>
740
1214
  </fig-field>
741
- </div>
742
- <div class="prop-panel">
743
1215
  <fig-field direction="horizontal">
744
- <label>Offset</label>
745
- <fig-slider type="delta"
746
- value="0"
747
- default="0"
748
- step="0.25"
749
- min="-5"
750
- max="5"
751
- full>
752
- <datalist>
753
- <option value="0"></option>
754
- </datalist>
755
- </fig-slider>
1216
+ <label>Align</label>
1217
+ <fig-segmented-control full>
1218
+ <fig-segment value="left">Left</fig-segment>
1219
+ <fig-segment value="center"
1220
+ selected>Center</fig-segment>
1221
+ <fig-segment value="right">Right</fig-segment>
1222
+ </fig-segmented-control>
756
1223
  </fig-field>
757
- </div>
758
- </hstack>
759
-
760
- <fig-header borderless
761
- class="propkit-subheader">
762
- <h3>Transform</h3>
763
- <fig-button variant="secondary"
764
- class="copy-prompt-btn">Copy prompt</fig-button>
765
- </fig-header>
766
- <hstack>
767
- <div class="prop-panel">
768
1224
  <fig-field direction="horizontal">
769
- <label>Scale</label>
770
- <fig-slider min="0"
771
- max="1"
772
- value="0.5"
773
- step="0.01"
774
- transform="100"
775
- text="true"
776
- units="%"
777
- full></fig-slider>
1225
+ <label>Image</label>
1226
+ <fig-image full="true"
1227
+ upload="true"
1228
+ label="Upload"
1229
+ size="medium"></fig-image>
778
1230
  </fig-field>
779
- </div>
780
- <div class="prop-panel">
781
1231
  <fig-field direction="horizontal">
782
- <label>Scale</label>
783
- <fig-slider min="0"
784
- max="1"
785
- value="0.5"
786
- step="0.01"
787
- transform="100"
788
- units="%"
789
- full></fig-slider>
1232
+ <label>Tint</label>
1233
+ <fig-input-color value="#FFFFFF"
1234
+ text="true"
1235
+ picker="figma"
1236
+ picker-anchor="self"
1237
+ full></fig-input-color>
790
1238
  </fig-field>
791
1239
  </div>
792
- </hstack>
793
- </section>
794
-
795
- <hr>
796
-
797
- <!-- Switch -->
798
- <section id="switch">
799
- <h2>Switch</h2>
800
- <p class="description">A toggle switch for boolean on/off properties.</p>
801
-
802
- <fig-header borderless
803
- class="propkit-subheader">
804
- <h3>Default</h3>
805
- <fig-button variant="secondary"
806
- class="copy-prompt-btn">Copy prompt</fig-button>
807
- </fig-header>
808
- <div class="prop-panel">
809
- <fig-field direction="horizontal">
810
- <label>Visible</label>
811
- <fig-switch checked="true"></fig-switch>
812
- </fig-field>
813
- </div>
814
- </section>
815
-
816
- <hr>
817
-
818
- <!-- Dropdown -->
819
- <section id="dropdown">
820
- <h2>Dropdown</h2>
821
- <p class="description">A dropdown select field for choosing from a set of options.</p>
822
-
823
- <fig-header borderless
824
- class="propkit-subheader">
825
- <h3>Default</h3>
826
- <fig-button variant="secondary"
827
- class="copy-prompt-btn">Copy prompt</fig-button>
828
- </fig-header>
829
- <div class="prop-panel">
830
- <fig-field direction="horizontal">
831
- <label>Blend Mode</label>
832
- <fig-dropdown full
833
- experimental="modern">
834
- <option selected>Normal</option>
835
- <option>Multiply</option>
836
- <option>Screen</option>
837
- <option>Overlay</option>
838
- <option>Darken</option>
839
- <option>Lighten</option>
840
- </fig-dropdown>
841
- </fig-field>
842
- </div>
843
- </section>
844
-
845
- <hr>
846
-
847
- <!-- Segment -->
848
- <section id="segment">
849
- <h2>Segment</h2>
850
- <p class="description">A segmented control for mutually exclusive choices.</p>
851
-
852
- <fig-header borderless
853
- class="propkit-subheader">
854
- <h3>Default</h3>
855
- <fig-button variant="secondary"
856
- class="copy-prompt-btn">Copy prompt</fig-button>
857
- </fig-header>
858
- <div class="prop-panel">
859
- <fig-field direction="horizontal">
860
- <label>Align</label>
861
- <fig-segmented-control full>
862
- <fig-segment value="left"
863
- selected>Left</fig-segment>
864
- <fig-segment value="center">Center</fig-segment>
865
- <fig-segment value="right">Right</fig-segment>
866
- </fig-segmented-control>
867
- </fig-field>
868
- </div>
869
- </section>
870
-
871
- <hr>
872
-
873
- <!-- Dial -->
874
- <section id="dial">
875
- <h2>Dial</h2>
876
- <p class="description">A rotary dial for continuous value input. <em>Not yet built.</em></p>
877
-
878
- <fig-header borderless
879
- class="propkit-subheader">
880
- <h3>Default</h3>
881
- <fig-button variant="secondary"
882
- class="copy-prompt-btn">Copy prompt</fig-button>
883
- </fig-header>
884
- <div class="prop-panel">
885
- <fig-field direction="horizontal">
886
- <label>Amount</label>
887
- <div class="placeholder-field">fig-input-dial</div>
888
- </fig-field>
889
1240
  </div>
890
1241
  </section>
891
1242
 
892
- <hr>
893
-
894
- <!-- Easing Curve -->
895
- <section id="easing">
896
- <h2>Easing Curve</h2>
897
- <p class="description">A bezier curve editor for animation easing with preset dropdown.</p>
898
-
899
- <fig-header borderless
900
- class="propkit-subheader">
901
- <h3>Default</h3>
902
- <fig-button variant="secondary"
903
- class="copy-prompt-btn">Copy prompt</fig-button>
904
- </fig-header>
905
- <div class="prop-panel">
906
- <fig-field direction="horizontal">
907
- <label>Easing</label>
908
- <fig-easing-curve value="0.42, 0, 0.58, 1"
909
- id="easing-curve-observed"
910
- dropdown="true"></fig-easing-curve>
911
- </fig-field>
912
- </div>
913
- <pre class="event-dump language-json"><code id="easing-curve-dump"
914
- class="language-json">{
915
- "event": "ready",
916
- "value": "0.42, 0, 0.58, 1"
917
- }</code></pre>
918
-
919
- <fig-header borderless
920
- class="propkit-subheader">
921
- <h3>No Dropdown</h3>
922
- <fig-button variant="secondary"
923
- class="copy-prompt-btn">Copy prompt</fig-button>
924
- </fig-header>
925
- <div class="prop-panel">
926
- <fig-field direction="horizontal">
927
- <label>Easing</label>
928
- <fig-easing-curve value="0.25, 0.1, 0.25, 1"></fig-easing-curve>
929
- </fig-field>
930
- </div>
931
-
932
- <fig-header borderless
933
- class="propkit-subheader">
934
- <h3>16:9 Horizontal</h3>
935
- <fig-button variant="secondary"
936
- class="copy-prompt-btn">Copy prompt</fig-button>
937
- </fig-header>
938
- <div class="prop-panel">
939
- <fig-field direction="horizontal">
940
- <label>Easing</label>
941
- <fig-easing-curve value="0.25, 0.1, 0.25, 1"
942
- aspect-ratio="16/9"></fig-easing-curve>
943
- </fig-field>
944
- </div>
945
-
946
- <fig-header borderless
947
- class="propkit-subheader">
948
- <h3>No Label</h3>
949
- <fig-button variant="secondary"
950
- class="copy-prompt-btn">Copy prompt</fig-button>
951
- </fig-header>
952
- <div class="prop-panel">
953
- <fig-field direction="horizontal">
954
- <fig-easing-curve value="spring(250, 8, 1)"
955
- dropdown="true"></fig-easing-curve>
956
- </fig-field>
957
- </div>
958
- </section>
959
-
960
- <hr>
961
-
962
- <!-- 3D Rotate -->
963
- <section id="3d-rotate">
964
- <h2>3D Rotate</h2>
965
- <p class="description">An interactive 3D rotation control with a draggable cube preview.</p>
966
-
967
- <fig-header borderless
968
- class="propkit-subheader">
969
- <h3>Default</h3>
970
- <fig-button variant="secondary"
971
- class="copy-prompt-btn">Copy prompt</fig-button>
972
- </fig-header>
973
- <div class="prop-panel">
974
- <fig-field direction="horizontal">
975
- <label>Rotation</label>
976
- <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
977
- id="3d-rotate-observed"></fig-3d-rotate>
978
- </fig-field>
979
- </div>
980
- <pre class="event-dump language-json"><code id="3d-rotate-dump"
981
- class="language-json">{
982
- "event": "ready",
983
- "value": "rotateX(0.0deg) rotateY(0.0deg) rotateZ(0.0deg)"
984
- }</code></pre>
985
-
986
- <fig-header borderless
987
- class="propkit-subheader">
988
- <h3>16:9 Horizontal</h3>
1243
+ <div class="propkit-code-view">
1244
+ <div class="propkit-code-view-actions">
989
1245
  <fig-button variant="secondary"
990
- class="copy-prompt-btn">Copy prompt</fig-button>
991
- </fig-header>
992
- <div class="prop-panel">
993
- <fig-field direction="horizontal">
994
- <label>Rotation</label>
995
- <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
996
- aspect-ratio="16/9"></fig-3d-rotate>
997
- </fig-field>
998
- </div>
999
-
1000
- <fig-header borderless
1001
- class="propkit-subheader">
1002
- <h3>4:3</h3>
1246
+ class="copy-code-btn">Copy</fig-button>
1003
1247
  <fig-button variant="secondary"
1004
1248
  class="copy-prompt-btn">Copy prompt</fig-button>
1005
- </fig-header>
1006
- <div class="prop-panel">
1007
- <fig-field direction="horizontal">
1008
- <label>Rotation</label>
1009
- <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1010
- aspect-ratio="4/3"></fig-3d-rotate>
1011
- </fig-field>
1012
1249
  </div>
1250
+ <div id="propkit-code"></div>
1251
+ </div>
1252
+ </main>
1013
1253
 
1014
- <fig-header borderless
1015
- class="propkit-subheader">
1016
- <h3>No Label</h3>
1017
- <fig-button variant="secondary"
1018
- class="copy-prompt-btn">Copy prompt</fig-button>
1019
- </fig-header>
1020
- <div class="prop-panel">
1021
- <fig-field direction="horizontal">
1022
- <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1023
- aspect-ratio="16/9"></fig-3d-rotate>
1024
- </fig-field>
1025
- </div>
1254
+ <dialog is="fig-toast"
1255
+ id="prompt-copy-toast"
1256
+ duration="1500"
1257
+ theme="dark">Copied</dialog>
1258
+
1259
+ <script type="module">
1260
+ import { minimalSetup } from "codemirror";
1261
+ import { EditorView, highlightActiveLine, highlightSpecialChars, drawSelection } from "@codemirror/view";
1262
+ import { EditorState } from "@codemirror/state";
1263
+ import { html as htmlLang } from "@codemirror/lang-html";
1264
+ import { json as jsonLang } from "@codemirror/lang-json";
1265
+ import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
1266
+ import { closeBrackets } from "@codemirror/autocomplete";
1267
+ import { history, defaultKeymap, historyKeymap } from "@codemirror/commands";
1268
+ import { keymap } from "@codemirror/view";
1269
+ import { tags } from "@lezer/highlight";
1270
+
1271
+ // --- CodeMirror setup ---
1272
+ const figmaTheme = EditorView.theme({
1273
+ '&': {
1274
+ fontSize: '11px',
1275
+ backgroundColor: 'var(--figma-color-bg-secondary)',
1276
+ color: 'var(--figma-color-text)',
1277
+ },
1278
+ '.cm-content': {
1279
+ fontFamily: '"IBM Plex Mono", monospace',
1280
+ fontWeight: '400',
1281
+ padding: '8px 0',
1282
+ caretColor: 'var(--figma-color-bg-brand)',
1283
+ },
1284
+ '&.cm-focused .cm-cursor': {
1285
+ borderLeftColor: 'var(--figma-color-bg-brand)',
1286
+ },
1287
+ '.cm-selectionBackground': {
1288
+ backgroundColor: 'var(--figma-color-bg-selected) !important',
1289
+ },
1290
+ '.cm-activeLine': {
1291
+ backgroundColor: 'color-mix(in srgb, var(--figma-color-bg-hover) 50%, transparent)',
1292
+ },
1293
+ '.cm-selectionMatch': {
1294
+ backgroundColor: 'var(--figma-color-bg-brand-tertiary)',
1295
+ },
1296
+ });
1026
1297
 
1027
- <fig-header borderless
1028
- class="propkit-subheader">
1029
- <h3>With Fields (All Axes)</h3>
1030
- <fig-button variant="secondary"
1031
- class="copy-prompt-btn">Copy prompt</fig-button>
1032
- </fig-header>
1033
- <div class="prop-panel">
1034
- <fig-field direction="horizontal">
1035
- <label>Rotation</label>
1036
- <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1037
- fields="rotateX,rotateY,rotateZ"></fig-3d-rotate>
1038
- </fig-field>
1039
- </div>
1298
+ const figmaHighlight = HighlightStyle.define([
1299
+ { tag: tags.keyword, color: 'var(--figma-color-text-component)' },
1300
+ { tag: tags.tagName, color: 'var(--figma-color-text-component)' },
1301
+ { tag: tags.attributeName, color: 'var(--figma-color-text-brand)' },
1302
+ { tag: tags.attributeValue, color: 'var(--figma-color-text-success)' },
1303
+ { tag: tags.string, color: 'var(--figma-color-text-success)' },
1304
+ { tag: tags.number, color: 'var(--figma-color-text-warning)' },
1305
+ { tag: tags.bool, color: 'var(--figma-color-text-warning)' },
1306
+ { tag: tags.comment, color: 'var(--figma-color-text-tertiary)', fontStyle: 'italic' },
1307
+ { tag: tags.punctuation, color: 'var(--figma-color-text-secondary)' },
1308
+ { tag: tags.bracket, color: 'var(--figma-color-text-secondary)' },
1309
+ { tag: tags.angleBracket, color: 'var(--figma-color-text-secondary)' },
1310
+ { tag: tags.propertyName, color: 'var(--figma-color-text-brand)' },
1311
+ { tag: tags.operator, color: 'var(--figma-color-text-secondary)' },
1312
+ { tag: tags.typeName, color: 'var(--figma-color-text-component)' },
1313
+ { tag: tags.definition(tags.variableName), color: 'var(--figma-color-text-brand)' },
1314
+ ]);
1315
+
1316
+ const codeSetup = [
1317
+ highlightSpecialChars(),
1318
+ history(),
1319
+ drawSelection(),
1320
+ syntaxHighlighting(figmaHighlight),
1321
+ closeBrackets(),
1322
+ highlightActiveLine(),
1323
+ keymap.of([...defaultKeymap, ...historyKeymap]),
1324
+ ];
1325
+
1326
+ function createEditor(parent, { lang, readOnly = false, minimal = false, doc = '' } = {}) {
1327
+ if (!parent) return null;
1328
+ const extensions = [
1329
+ minimal ? minimalSetup : codeSetup,
1330
+ lang,
1331
+ figmaTheme,
1332
+ EditorView.lineWrapping,
1333
+ ];
1334
+ if (minimal) extensions.push(syntaxHighlighting(figmaHighlight));
1335
+ if (readOnly) {
1336
+ extensions.push(EditorView.editable.of(false), EditorState.readOnly.of(true));
1337
+ }
1338
+ return new EditorView({
1339
+ state: EditorState.create({ doc, extensions }),
1340
+ parent,
1341
+ });
1342
+ }
1040
1343
 
1041
- <fig-header borderless
1042
- class="propkit-subheader">
1043
- <h3>With Fields (Y Only)</h3>
1044
- <fig-button variant="secondary"
1045
- class="copy-prompt-btn">Copy prompt</fig-button>
1046
- </fig-header>
1047
- <div class="prop-panel">
1048
- <fig-field direction="horizontal">
1049
- <label>Rotation</label>
1050
- <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1051
- fields="rotateY"></fig-3d-rotate>
1052
- </fig-field>
1053
- </div>
1344
+ function replaceDoc(view, newDoc) {
1345
+ if (!view) return;
1346
+ view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: newDoc } });
1347
+ }
1054
1348
 
1055
- <fig-header borderless
1056
- class="propkit-subheader">
1057
- <h3>With Fields (X &amp; Y)</h3>
1058
- <fig-button variant="secondary"
1059
- class="copy-prompt-btn">Copy prompt</fig-button>
1060
- </fig-header>
1061
- <div class="prop-panel">
1062
- <fig-field direction="horizontal">
1063
- <label>Rotation</label>
1064
- <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1065
- fields="rotateX,rotateY"></fig-3d-rotate>
1066
- </fig-field>
1067
- </div>
1349
+ const codeEditor = createEditor(document.getElementById('propkit-code'), { lang: htmlLang() });
1350
+ const easingDumpEditor = createEditor(document.getElementById('easing-curve-dump'), { lang: jsonLang(), readOnly: true, minimal: true });
1351
+ const rotate3dDumpEditor = createEditor(document.getElementById('3d-rotate-dump'), { lang: jsonLang(), readOnly: true, minimal: true });
1352
+
1353
+ // --- Code View --- (must be before Navigation so LEAF_TAGS exists when navigateTo runs)
1354
+ const LEAF_TAGS = new Set([
1355
+ 'fig-easing-curve', 'fig-3d-rotate', 'fig-input-color', 'fig-input-fill',
1356
+ 'fig-slider', 'fig-switch', 'fig-input-angle', 'fig-image', 'fig-input-number',
1357
+ 'fig-input-joystick', 'fig-button', 'fig-input-text', 'fig-avatar', 'fig-shimmer'
1358
+ ]);
1359
+
1360
+ function getCleanSource(exampleEl) {
1361
+ if (!exampleEl) return '';
1362
+ const container = exampleEl.querySelector('hstack') || exampleEl.querySelector('.prop-panel');
1363
+ if (!container) return '';
1364
+
1365
+ const clone = container.cloneNode(true);
1366
+ clone.querySelectorAll('.event-dump').forEach(el => el.remove());
1367
+ clone.querySelectorAll('[id]').forEach(el => el.removeAttribute('id'));
1368
+ clone.querySelectorAll('[style]').forEach(el => el.removeAttribute('style'));
1369
+
1370
+ clone.querySelectorAll('*').forEach(el => {
1371
+ const tag = el.tagName.toLowerCase();
1372
+ if (LEAF_TAGS.has(tag)) {
1373
+ const keep = el.querySelectorAll('[slot], option, datalist, fig-segment');
1374
+ if (keep.length) {
1375
+ const frag = document.createDocumentFragment();
1376
+ keep.forEach(k => frag.appendChild(k.cloneNode(true)));
1377
+ el.innerHTML = '';
1378
+ el.appendChild(frag);
1379
+ } else {
1380
+ el.innerHTML = '';
1381
+ }
1382
+ }
1383
+ });
1068
1384
 
1069
- <fig-header borderless
1070
- class="propkit-subheader">
1071
- <h3>Fields + 16:9 + Preset Values</h3>
1072
- <fig-button variant="secondary"
1073
- class="copy-prompt-btn">Copy prompt</fig-button>
1074
- </fig-header>
1075
- <div class="prop-panel">
1076
- <fig-field direction="horizontal">
1077
- <label>Rotation</label>
1078
- <fig-3d-rotate value="rotateX(25deg) rotateY(-35deg) rotateZ(10deg)"
1079
- fields="rotateX,rotateY,rotateZ"
1080
- aspect-ratio="16/9"></fig-3d-rotate>
1081
- </fig-field>
1082
- </div>
1385
+ return formatHTML(clone.outerHTML);
1386
+ }
1083
1387
 
1084
- <fig-header borderless
1085
- class="propkit-subheader">
1086
- <h3>Fields, No Label</h3>
1087
- <fig-button variant="secondary"
1088
- class="copy-prompt-btn">Copy prompt</fig-button>
1089
- </fig-header>
1090
- <div class="prop-panel">
1091
- <fig-field direction="horizontal">
1092
- <fig-3d-rotate value="rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
1093
- fields="rotateX,rotateY,rotateZ"></fig-3d-rotate>
1094
- </fig-field>
1095
- </div>
1096
- </section>
1388
+ function formatHTML(src) {
1389
+ let indent = 0;
1390
+ const lines = [];
1391
+ const tokens = src.replace(/>\s+</g, '><').replace(/></g, '>\n<').split('\n');
1392
+ for (const token of tokens) {
1393
+ const trimmed = token.trim();
1394
+ if (!trimmed) continue;
1395
+ if (trimmed.startsWith('</')) indent = Math.max(0, indent - 1);
1396
+ lines.push(' '.repeat(indent) + trimmed);
1397
+ if (trimmed.startsWith('<') && !trimmed.startsWith('</') && !trimmed.endsWith('/>') && !trimmed.includes('</')) {
1398
+ indent++;
1399
+ }
1400
+ }
1401
+ return lines.join('\n');
1402
+ }
1097
1403
 
1098
- <hr>
1404
+ function populateCodeView(exampleEl) {
1405
+ if (!codeEditor || !exampleEl) return;
1406
+ replaceDoc(codeEditor, getCleanSource(exampleEl));
1407
+ }
1099
1408
 
1100
- <!-- Angle -->
1101
- <section id="angle">
1102
- <h2>Angle</h2>
1103
- <p class="description">An angle input with a visual dial and numeric text field.</p>
1409
+ // --- Navigation ---
1410
+ const navLayers = document.querySelectorAll('nav fig-layer[data-example]');
1411
+ const sections = document.querySelectorAll('main > section');
1412
+ const promptCopyToast = document.getElementById('prompt-copy-toast');
1104
1413
 
1105
- <fig-header borderless
1106
- class="propkit-subheader">
1107
- <h3>Default</h3>
1108
- <fig-button variant="secondary"
1109
- class="copy-prompt-btn">Copy prompt</fig-button>
1110
- </fig-header>
1111
- <div class="prop-panel">
1112
- <fig-field direction="horizontal">
1113
- <label>Rotation</label>
1114
- <fig-input-angle value="45"
1115
- text="true"
1116
- full></fig-input-angle>
1117
- </fig-field>
1118
- </div>
1119
- </section>
1414
+ function navigateTo(sectionId, exampleId) {
1415
+ sections.forEach(s => s.classList.remove('active'));
1416
+ document.querySelectorAll('.propkit-example').forEach(e => e.classList.remove('active'));
1417
+ navLayers.forEach(l => l.removeAttribute('selected'));
1120
1418
 
1121
- <hr>
1419
+ const section = document.getElementById(sectionId);
1420
+ if (!section) return;
1421
+ section.classList.add('active');
1122
1422
 
1123
- <!-- Combined Panel -->
1124
- <section id="combined">
1125
- <h2>Combined Panel</h2>
1126
- <p class="description">A realistic property panel combining multiple field types.</p>
1423
+ const example = section.querySelector(`.propkit-example[data-example="${exampleId}"]`);
1424
+ if (example) example.classList.add('active');
1127
1425
 
1128
- <fig-header borderless
1129
- class="propkit-subheader">
1130
- <h3>Default</h3>
1131
- <fig-button variant="secondary"
1132
- class="copy-prompt-btn">Copy prompt</fig-button>
1133
- </fig-header>
1134
- <div class="prop-panel">
1135
- <fig-field direction="horizontal">
1136
- <label>Fill</label>
1137
- <fig-input-fill value='{"type":"solid","color":"#667eea"}'
1138
- experimental="modern"></fig-input-fill>
1139
- </fig-field>
1140
- <fig-field direction="horizontal">
1141
- <label>Opacity</label>
1142
- <fig-slider value="100"
1143
- min="0"
1144
- max="100"
1145
- text="true"
1146
- full></fig-slider>
1147
- </fig-field>
1148
- <fig-field direction="horizontal">
1149
- <label>Blend</label>
1150
- <fig-dropdown full
1151
- experimental="modern">
1152
- <option selected>Normal</option>
1153
- <option>Multiply</option>
1154
- <option>Screen</option>
1155
- <option>Overlay</option>
1156
- </fig-dropdown>
1157
- </fig-field>
1158
- <fig-field direction="horizontal">
1159
- <label>Visible</label>
1160
- <fig-switch checked="true"></fig-switch>
1161
- </fig-field>
1162
-
1163
- <fig-field direction="horizontal">
1164
- <label>Rotation</label>
1165
- <fig-input-angle value="0"
1166
- text="true"
1167
- full></fig-input-angle>
1168
- </fig-field>
1169
- <fig-field direction="horizontal">
1170
- <label>Align</label>
1171
- <fig-segmented-control full>
1172
- <fig-segment value="left">Left</fig-segment>
1173
- <fig-segment value="center"
1174
- selected>Center</fig-segment>
1175
- <fig-segment value="right">Right</fig-segment>
1176
- </fig-segmented-control>
1177
- </fig-field>
1178
-
1179
- <fig-field direction="horizontal">
1180
- <label>Image</label>
1181
- <fig-image full="true"
1182
- upload="true"
1183
- label="Upload"
1184
- size="medium"></fig-image>
1185
- </fig-field>
1186
- <fig-field direction="horizontal">
1187
- <label>Tint</label>
1188
- <fig-input-color value="#FFFFFF"
1189
- text="true"
1190
- picker="figma"
1191
- picker-anchor="self"
1192
- full></fig-input-color>
1193
- </fig-field>
1194
- </div>
1195
- </section>
1196
- </main>
1426
+ const navLayer = document.querySelector(`nav fig-layer[data-section="${sectionId}"][data-example="${exampleId}"]`);
1427
+ if (navLayer) {
1428
+ navLayer.setAttribute('selected', 'true');
1429
+ const parent = navLayer.parentElement?.closest('fig-layer');
1430
+ if (parent && !parent.hasAttribute('open')) {
1431
+ parent.setAttribute('open', 'true');
1432
+ }
1433
+ }
1197
1434
 
1198
- <dialog is="fig-toast"
1199
- id="prompt-copy-toast"
1200
- duration="1500"
1201
- theme="dark">Prompt copied</dialog>
1202
-
1203
- <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js"></script>
1204
- <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-clike.min.js"></script>
1205
- <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-javascript.min.js"></script>
1206
- <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-json.min.js"></script>
1207
- <script>
1208
- // Nav highlighting
1209
- function updateActiveNav() {
1210
- const hash = location.hash || '#image';
1211
- document.querySelectorAll('nav .nav-links a').forEach(a => {
1212
- a.classList.toggle('active', a.getAttribute('href') === hash);
1213
- });
1435
+ populateCodeView(example);
1436
+ history.replaceState(null, '', `#${sectionId}/${exampleId}`);
1214
1437
  }
1215
1438
 
1216
- let isClickScrolling = false;
1217
-
1218
- const observer = new IntersectionObserver(entries => {
1219
- if (isClickScrolling) return;
1220
- entries.forEach(entry => {
1221
- if (entry.isIntersecting) {
1222
- history.replaceState(null, '', '#' + entry.target.id);
1223
- updateActiveNav();
1224
- }
1225
- });
1226
- }, { threshold: 0.3 });
1227
-
1228
- document.querySelectorAll('section[id]').forEach(s => observer.observe(s));
1229
-
1230
- document.querySelectorAll('nav .nav-links a').forEach(a => {
1231
- a.addEventListener('click', (e) => {
1232
- e.preventDefault();
1233
- const targetId = a.getAttribute('href');
1234
- const target = document.getElementById(targetId.slice(1));
1235
- if (target) {
1236
- isClickScrolling = true;
1237
- history.pushState(null, '', targetId);
1238
- updateActiveNav();
1239
- target.scrollIntoView({ behavior: 'smooth' });
1240
- setTimeout(() => { isClickScrolling = false; }, 500);
1241
- }
1439
+ navLayers.forEach(layer => {
1440
+ const row = layer.querySelector(':scope > .fig-layer-row');
1441
+ if (!row) return;
1442
+ row.addEventListener('click', (e) => {
1443
+ if (e.target.closest('.fig-layer-chevron')) return;
1444
+ const sectionId = layer.dataset.section;
1445
+ const exampleId = layer.dataset.example;
1446
+ if (sectionId && exampleId) navigateTo(sectionId, exampleId);
1242
1447
  });
1243
1448
  });
1244
1449
 
1245
- window.addEventListener('load', () => {
1246
- updateActiveNav();
1247
- if (location.hash) {
1248
- document.getElementById(location.hash.slice(1))?.scrollIntoView();
1450
+ document.querySelectorAll('nav > .nav-links > fig-layer[data-section]').forEach(parentLayer => {
1451
+ if (!parentLayer.dataset.example) {
1452
+ const row = parentLayer.querySelector(':scope > .fig-layer-row');
1453
+ if (!row) return;
1454
+ row.addEventListener('click', (e) => {
1455
+ if (e.target.closest('.fig-layer-chevron')) return;
1456
+ parentLayer.setAttribute('open', 'true');
1457
+ const firstChild = parentLayer.querySelector('fig-layer[data-example]');
1458
+ if (firstChild) navigateTo(firstChild.dataset.section, firstChild.dataset.example);
1459
+ });
1249
1460
  }
1250
1461
  });
1251
1462
 
1252
- window.addEventListener('hashchange', updateActiveNav);
1463
+ function navigateFromHash() {
1464
+ const hash = location.hash.slice(1);
1465
+ if (hash.includes('/')) {
1466
+ const [sectionId, exampleId] = hash.split('/');
1467
+ navigateTo(sectionId, exampleId);
1468
+ return true;
1469
+ }
1470
+ return false;
1471
+ }
1472
+
1473
+ if (!navigateFromHash()) {
1474
+ const first = document.querySelector('nav fig-layer[data-example]');
1475
+ if (first) navigateTo(first.dataset.section, first.dataset.example);
1476
+ }
1253
1477
 
1254
- // Theme toggle
1478
+ window.addEventListener('hashchange', navigateFromHash);
1479
+
1480
+ // --- Theme toggle ---
1255
1481
  const themeToggle = document.getElementById('theme-toggle');
1256
1482
  const themeLightBtn = document.getElementById('theme-light-btn');
1257
1483
  const themeDarkBtn = document.getElementById('theme-dark-btn');
1258
- document.querySelectorAll('fig-slider').forEach((slider) => {
1259
- slider.setAttribute('variant', 'neue');
1260
- });
1484
+
1485
+ document.querySelectorAll('fig-slider').forEach(s => s.setAttribute('variant', 'neue'));
1261
1486
 
1262
1487
  function setTheme(isDark) {
1263
1488
  document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';
1264
1489
  localStorage.setItem('theme', isDark ? 'dark' : 'light');
1265
- if (isDark) {
1266
- themeToggle.setAttribute('checked', 'true');
1267
- } else {
1268
- themeToggle.removeAttribute('checked');
1269
- }
1490
+ if (isDark) themeToggle.setAttribute('checked', 'true');
1491
+ else themeToggle.removeAttribute('checked');
1270
1492
  }
1271
1493
 
1272
1494
  const savedTheme = localStorage.getItem('theme');
@@ -1276,29 +1498,23 @@
1276
1498
  themeToggle.addEventListener('change', (e) => setTheme(e.target.checked));
1277
1499
  themeLightBtn.addEventListener('click', () => setTheme(false));
1278
1500
  themeDarkBtn.addEventListener('click', () => setTheme(true));
1279
-
1280
1501
  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
1281
1502
  if (!localStorage.getItem('theme')) setTheme(e.matches);
1282
1503
  });
1283
1504
 
1284
- // Easing curve event observer dump
1505
+ // --- Event dumps ---
1285
1506
  const easingCurveObserved = document.getElementById('easing-curve-observed');
1286
- const easingCurveDump = document.getElementById('easing-curve-dump');
1287
- const promptCopyToast = document.getElementById('prompt-copy-toast');
1507
+ const rotate3dObserved = document.getElementById('3d-rotate-observed');
1288
1508
 
1289
1509
  function updateEasingDump(eventName, detail = null) {
1290
- if (!easingCurveDump || !easingCurveObserved) return;
1291
- const payload = {
1510
+ if (!easingDumpEditor || !easingCurveObserved) return;
1511
+ replaceDoc(easingDumpEditor, JSON.stringify({
1292
1512
  event: eventName,
1293
1513
  mode: detail?.mode ?? null,
1294
1514
  preset: detail?.preset ?? null,
1295
1515
  value: detail?.value ?? easingCurveObserved.value,
1296
1516
  cssValue: detail?.cssValue ?? easingCurveObserved.cssValue,
1297
- };
1298
- easingCurveDump.textContent = JSON.stringify(payload, null, 2);
1299
- if (window.Prism) {
1300
- window.Prism.highlightElement(easingCurveDump);
1301
- }
1517
+ }, null, 2));
1302
1518
  }
1303
1519
 
1304
1520
  if (easingCurveObserved) {
@@ -1307,23 +1523,15 @@
1307
1523
  easingCurveObserved.addEventListener('change', (e) => updateEasingDump('change', e.detail));
1308
1524
  }
1309
1525
 
1310
- // 3D rotate event observer dump
1311
- const rotate3dObserved = document.getElementById('3d-rotate-observed');
1312
- const rotate3dDump = document.getElementById('3d-rotate-dump');
1313
-
1314
1526
  function updateRotate3dDump(eventName, detail = null) {
1315
- if (!rotate3dDump || !rotate3dObserved) return;
1316
- const payload = {
1527
+ if (!rotate3dDumpEditor || !rotate3dObserved) return;
1528
+ replaceDoc(rotate3dDumpEditor, JSON.stringify({
1317
1529
  event: eventName,
1318
1530
  value: detail?.value ?? rotate3dObserved.value,
1319
1531
  rotateX: detail?.rotateX ?? rotate3dObserved.rotateX,
1320
1532
  rotateY: detail?.rotateY ?? rotate3dObserved.rotateY,
1321
1533
  rotateZ: detail?.rotateZ ?? rotate3dObserved.rotateZ,
1322
- };
1323
- rotate3dDump.textContent = JSON.stringify(payload, null, 2);
1324
- if (window.Prism) {
1325
- window.Prism.highlightElement(rotate3dDump);
1326
- }
1534
+ }, null, 2));
1327
1535
  }
1328
1536
 
1329
1537
  if (rotate3dObserved) {
@@ -1332,42 +1540,36 @@
1332
1540
  rotate3dObserved.addEventListener('change', (e) => updateRotate3dDump('change', e.detail));
1333
1541
  }
1334
1542
 
1335
- function collectComponentTargets(subheaderEl, maxTargets = 1) {
1543
+ // --- Copy buttons ---
1544
+ function collectComponentTargets(exampleEl, maxTargets = 1) {
1336
1545
  const targets = [];
1337
- let node = subheaderEl.nextElementSibling;
1338
- while (node) {
1339
- if (node.matches('fig-header.propkit-subheader') || node.tagName === 'H2' || node.tagName === 'HR') break;
1340
- node.querySelectorAll('fig-field').forEach((field) => {
1341
- const component = Array.from(field.children).find((child) => child.tagName !== 'LABEL');
1342
- const label = field.querySelector('label')?.textContent?.trim() || '';
1343
- if (component && targets.length < maxTargets) targets.push({ component, label });
1344
- });
1345
- if (targets.length >= maxTargets) break;
1346
- node = node.nextElementSibling;
1347
- }
1546
+ exampleEl.querySelectorAll('fig-field').forEach(field => {
1547
+ const component = Array.from(field.children).find(c => c.tagName !== 'LABEL');
1548
+ const label = field.querySelector('label')?.textContent?.trim() || '';
1549
+ if (component && targets.length < maxTargets) targets.push({ component, label });
1550
+ });
1348
1551
  return targets;
1349
1552
  }
1350
1553
 
1351
1554
  function formatAttrs(el) {
1352
1555
  return Array.from(el.attributes)
1353
- .filter((a) => !['id', 'class', 'src', 'style', 'label', 'value'].includes(a.name))
1354
- .map((a) => `${a.name}="${a.value}"`)
1556
+ .filter(a => !['id', 'class', 'src', 'style', 'label', 'value'].includes(a.name))
1557
+ .map(a => `${a.name}="${a.value}"`)
1355
1558
  .join(' ');
1356
1559
  }
1357
1560
 
1358
- function buildPropkitPrompt(subheaderEl) {
1359
- const targets = collectComponentTargets(subheaderEl);
1360
- if (!targets.length) {
1361
- return 'Use a horizontal fig-field. With a label of [Label name].';
1362
- }
1561
+ function buildPropkitPrompt(exampleEl) {
1562
+ const targets = collectComponentTargets(exampleEl);
1563
+ if (!targets.length) return 'Use a horizontal fig-field. With a label of [Label name].';
1363
1564
  const { component: el, label } = targets[0];
1364
1565
  const labelText = label || '[Label name]';
1365
1566
  const tag = el.tagName.toLowerCase();
1567
+
1366
1568
  if (tag === 'fig-image') {
1367
1569
  const parts = [];
1368
1570
  if (el.getAttribute('full') === 'true' || el.hasAttribute('full')) parts.push('full fig-image');
1369
1571
  else parts.push('fig-image');
1370
- if (el.getAttribute('upload') === 'true' || el.hasAttribute('upload')) parts.push('upload');
1572
+ if (el.getAttribute('upload') === 'true') parts.push('upload');
1371
1573
  if (el.getAttribute('size') === 'auto') parts.push('auto size');
1372
1574
  if (el.hasAttribute('fit')) parts.push(`fit ${el.getAttribute('fit')}`);
1373
1575
  if (el.hasAttribute('aspect-ratio')) parts.push(`aspect ratio ${el.getAttribute('aspect-ratio')}`);
@@ -1381,17 +1583,16 @@
1381
1583
  if (val.type === 'solid') {
1382
1584
  parts.push(`solid fill, color=${val.color}`);
1383
1585
  } else if (val.type === 'gradient' && val.gradient) {
1384
- const g = val.gradient;
1385
- parts.push(`${g.type} gradient`);
1386
- if (g.angle !== undefined) parts.push(`angle=${g.angle}`);
1387
- const colors = (g.stops || []).map(s => s.color).join(' → ');
1586
+ parts.push(`${val.gradient.type} gradient`);
1587
+ if (val.gradient.angle !== undefined) parts.push(`angle=${val.gradient.angle}`);
1588
+ const colors = (val.gradient.stops || []).map(s => s.color).join(' → ');
1388
1589
  if (colors) parts.push(`stops=${colors}`);
1389
1590
  } else if (val.type === 'image') {
1390
1591
  parts.push('image fill');
1391
1592
  if (val.image?.scaleMode) parts.push(`scaleMode=${val.image.scaleMode}`);
1392
1593
  if (val.image?.opacity !== undefined && val.image.opacity < 1) parts.push(`opacity=${val.image.opacity}`);
1393
1594
  }
1394
- if (el.hasAttribute('alpha') && el.getAttribute('alpha') === 'false') parts.push('alpha=false');
1595
+ if (el.getAttribute('alpha') === 'false') parts.push('alpha=false');
1395
1596
  return `Use a horizontal fig-field, with a ${parts.join(', ')}. With a label of ${labelText}.`;
1396
1597
  } catch (e) { /* fall through */ }
1397
1598
  }
@@ -1409,8 +1610,7 @@
1409
1610
  const textarea = document.createElement('textarea');
1410
1611
  textarea.value = text;
1411
1612
  textarea.setAttribute('readonly', '');
1412
- textarea.style.position = 'fixed';
1413
- textarea.style.opacity = '0';
1613
+ textarea.style.cssText = 'position:fixed;opacity:0';
1414
1614
  document.body.appendChild(textarea);
1415
1615
  textarea.select();
1416
1616
  document.execCommand('copy');
@@ -1418,15 +1618,22 @@
1418
1618
  }
1419
1619
 
1420
1620
  document.addEventListener('click', async (e) => {
1421
- const btn = e.target.closest('.copy-prompt-btn');
1422
- if (!btn) return;
1621
+ const copyCodeBtn = e.target.closest('.copy-code-btn');
1622
+ const copyPromptBtn = e.target.closest('.copy-prompt-btn');
1623
+ if (!copyCodeBtn && !copyPromptBtn) return;
1624
+
1423
1625
  try {
1424
- const subheaderEl = btn.closest('fig-header.propkit-subheader');
1425
- const prompt = buildPropkitPrompt(subheaderEl);
1426
- await copyText(prompt);
1626
+ const activeExample = document.querySelector('.propkit-example.active');
1627
+ if (!activeExample) return;
1628
+
1629
+ if (copyCodeBtn) {
1630
+ await copyText(getCleanSource(activeExample));
1631
+ } else {
1632
+ await copyText(buildPropkitPrompt(activeExample));
1633
+ }
1427
1634
  promptCopyToast?.showToast();
1428
1635
  } catch (err) {
1429
- console.error('Failed to copy prompt', err);
1636
+ console.error('Failed to copy', err);
1430
1637
  }
1431
1638
  });
1432
1639
  </script>