@rogieking/figui3 8.9.44 → 8.9.45
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/.cursor/skills/fig-editor/SKILL.md +11 -138
- package/.cursor/skills/fig-editor/components.md +134 -0
- package/.cursor/skills/fig-editor/reference.md +2 -3
- package/.cursor/skills/fig-lab/SKILL.md +9 -109
- package/.cursor/skills/fig-lab/components.md +371 -0
- package/.cursor/skills/fig-lab/reference.md +5 -3
- package/.cursor/skills/figui3/SKILL.md +23 -132
- package/.cursor/skills/figui3/components.md +643 -0
- package/.cursor/skills/figui3/react.md +263 -0
- package/.cursor/skills/figui3/reference.md +3 -4
- package/.cursor/skills/propkit/SKILL.md +25 -35
- package/package.json +1 -1
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
# FigUI3 core components (`fig.js`)
|
|
2
|
+
|
|
3
|
+
React contract: [react.md](react.md). Attrs: [reference.md](reference.md).
|
|
4
|
+
|
|
5
|
+
Handlers below assume `onInput` / `onChange` / `onClick` from [react.md](react.md).
|
|
6
|
+
|
|
7
|
+
## Buttons and inputs
|
|
8
|
+
|
|
9
|
+
### `fig-button`
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
<fig-button variant="ghost" icon aria-label="Close" onClick={onClick}>
|
|
13
|
+
<fig-icon name="close" />
|
|
14
|
+
</fig-button>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- Attrs: `variant` (`""` primary, `secondary`, `destructive`, `destructiveSecondary`, `destructiveGhost`, `destructiveLink`, `ghost`, `link`, `input`, `overlay`), `type` (`button`, `toggle`, `submit`, `select`, `upload`), `size` (`""`, `large`, `compact`), `align`, `selected`, `disabled`, `icon`, `close-dialog`
|
|
18
|
+
- Events: `click`; toggle also reflects `selected`
|
|
19
|
+
|
|
20
|
+
### `fig-button-combo`
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
<fig-button-combo>
|
|
24
|
+
<fig-button>Save</fig-button>
|
|
25
|
+
<fig-button variant="secondary">Cancel</fig-button>
|
|
26
|
+
</fig-button-combo>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Attrs: none required. Children stay in light DOM.
|
|
30
|
+
|
|
31
|
+
### `fig-dropdown`
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<fig-dropdown value={value} variant="ghost" full onChange={onChange}>
|
|
35
|
+
<option value="left">Left</option>
|
|
36
|
+
<option value="center">Center</option>
|
|
37
|
+
</fig-dropdown>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- Attrs: `value`, `type` (`select` | `dropdown`), `variant` (`ghost`), `full`, `disabled`
|
|
41
|
+
- Events: `input` / `change` → `currentTarget.value`
|
|
42
|
+
- Prefer `fig-select` (editor) for Figma-style menus.
|
|
43
|
+
|
|
44
|
+
### `fig-combo-input`
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
<fig-combo-input
|
|
48
|
+
value={value}
|
|
49
|
+
options="Small,Medium,Large"
|
|
50
|
+
placeholder="Size"
|
|
51
|
+
full
|
|
52
|
+
onInput={onInput}
|
|
53
|
+
onChange={onChange}
|
|
54
|
+
/>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- Attrs: `value`, `options`, `placeholder`, `disabled`, `full`
|
|
58
|
+
|
|
59
|
+
### `fig-input-text`
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
<fig-input-text
|
|
63
|
+
value={value}
|
|
64
|
+
placeholder="Name"
|
|
65
|
+
full
|
|
66
|
+
onInput={onInput}
|
|
67
|
+
onChange={onChange}
|
|
68
|
+
/>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- Attrs: `type` (`text`, `email`, `password`, `search`, `url`), `multiline`, `autoresize`, `resizable`, `disabled`, `readonly`, `placeholder`, `full`
|
|
72
|
+
|
|
73
|
+
### `fig-input-number`
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
<fig-input-number
|
|
77
|
+
value={String(n)}
|
|
78
|
+
min="0"
|
|
79
|
+
max="100"
|
|
80
|
+
step="1"
|
|
81
|
+
units="%"
|
|
82
|
+
steppers="true"
|
|
83
|
+
full
|
|
84
|
+
onInput={onInput}
|
|
85
|
+
onChange={onChange}
|
|
86
|
+
/>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- Attrs: `min`, `max`, `step`, `precision`, `units`, `units-disallow`, `steppers`, `disabled`, `full`
|
|
90
|
+
|
|
91
|
+
### `fig-input-combo`
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
<fig-input-combo>
|
|
95
|
+
<fig-input-text value={value} onInput={onInput} />
|
|
96
|
+
<fig-button>Go</fig-button>
|
|
97
|
+
</fig-input-combo>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- Children stay in light DOM.
|
|
101
|
+
|
|
102
|
+
### `fig-input-file`
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<fig-input-file
|
|
106
|
+
label="Upload"
|
|
107
|
+
accepts="image/*"
|
|
108
|
+
multiple
|
|
109
|
+
onChange={onChange}
|
|
110
|
+
/>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
- Attrs: `label`, `accepts`, `multiple`, `disabled`, `variant` (`input`, `primary`, `secondary`, `ghost`, `link`, `overlay`)
|
|
114
|
+
- Events: `change` / `input` with files on the host
|
|
115
|
+
|
|
116
|
+
### `fig-checkbox`
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
<fig-checkbox
|
|
120
|
+
label="Enabled"
|
|
121
|
+
checked={on ? "true" : undefined}
|
|
122
|
+
onInput={onInput}
|
|
123
|
+
/>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- Attrs: `label`, `checked`, `disabled`, `value`
|
|
127
|
+
- Events: `input` / `change` → `detail.checked` ?? `host.checked`
|
|
128
|
+
|
|
129
|
+
### `fig-radio`
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
<fig-radio
|
|
133
|
+
name="align"
|
|
134
|
+
value="left"
|
|
135
|
+
label="Left"
|
|
136
|
+
checked={value === "left" ? "true" : undefined}
|
|
137
|
+
onInput={onInput}
|
|
138
|
+
/>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
- Attrs: `name`, `value`, `label`, `checked`, `disabled`
|
|
142
|
+
|
|
143
|
+
### `fig-switch`
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
<fig-switch
|
|
147
|
+
checked={on ? "true" : undefined}
|
|
148
|
+
onInput={onInput}
|
|
149
|
+
/>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
- Attrs: `checked`, `disabled`, `label`, `indeterminate`
|
|
153
|
+
- Events: `input` / `change` → `detail.checked` ?? `host.checked`
|
|
154
|
+
|
|
155
|
+
### `fig-slider`
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
<fig-slider
|
|
159
|
+
value={String(opacity)}
|
|
160
|
+
min="0"
|
|
161
|
+
max="100"
|
|
162
|
+
step="1"
|
|
163
|
+
text="true"
|
|
164
|
+
units="%"
|
|
165
|
+
full
|
|
166
|
+
onInput={onInput}
|
|
167
|
+
onChange={onChange}
|
|
168
|
+
/>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- Attrs: `type` (`range`, `opacity`, `hue`, `stepper`, `delta`), `min`, `max`, `step`, `text`, `units`, `transform`, `color`, `default`, `variant` (`classic`), `placeholder`, `full`, `disabled`
|
|
172
|
+
- Events: `input` / `change` → `currentTarget.value`
|
|
173
|
+
- React: keep `value` a string; do not remount during drag. Opacity: set `color`. Delta: set `default`. Stepper: include a `<datalist>` of stops.
|
|
174
|
+
|
|
175
|
+
### `fig-options`
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
<fig-options
|
|
179
|
+
options="Light,Dark"
|
|
180
|
+
value={isDark ? "Dark" : "Light"}
|
|
181
|
+
full
|
|
182
|
+
onChange={onChange}
|
|
183
|
+
/>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
- Attrs: `options` (comma / newline / JSON), `value`, `full`, `disabled`
|
|
187
|
+
- Events: `input` / `change` → `detail` ?? `target.value`
|
|
188
|
+
|
|
189
|
+
## Color and fill
|
|
190
|
+
|
|
191
|
+
### `fig-input-color`
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
<fig-input-color
|
|
195
|
+
value={color}
|
|
196
|
+
text="true"
|
|
197
|
+
alpha="true"
|
|
198
|
+
full
|
|
199
|
+
onInput={onInput}
|
|
200
|
+
onChange={onChange}
|
|
201
|
+
/>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
- Attrs: `value`, `text`, `alpha`, `full`, `disabled`. Forwards `picker-*` when `fig-fill-picker` is registered. Do not use `picker` / `picker-anchor`.
|
|
205
|
+
- Events: `input` / `change` → `detail.{ color, alpha, opacity }` plus legacy `value` / `hex` / `rgba`
|
|
206
|
+
|
|
207
|
+
### `fig-input-fill`
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
<fig-input-fill
|
|
211
|
+
value={fillJson}
|
|
212
|
+
full
|
|
213
|
+
onInput={onInput}
|
|
214
|
+
onChange={onChange}
|
|
215
|
+
/>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
- Attrs: `value` (JSON or string), `mode`, `webcam-mode`, `default-video`, `picker-*`, `disabled`, `full`
|
|
219
|
+
- Events: `input` / `change` with fill payload in `detail`
|
|
220
|
+
- Custom modes: include the name in `mode`; slot `slot="mode-<name>"`. Closed chrome matches image fills. In React, listen for `modeready` and mount into `e.detail.container` (see `fig-editor`).
|
|
221
|
+
|
|
222
|
+
### `fig-input-palette`
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
<fig-input-palette
|
|
226
|
+
value='["#0D99FF","#14AE5C"]'
|
|
227
|
+
onInput={onInput}
|
|
228
|
+
onChange={onChange}
|
|
229
|
+
/>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
- Attrs: `value`, `fixed`, `open`, `disabled`
|
|
233
|
+
|
|
234
|
+
### `fig-input-gradient`
|
|
235
|
+
|
|
236
|
+
```tsx
|
|
237
|
+
<fig-input-gradient
|
|
238
|
+
value={gradientJson}
|
|
239
|
+
mode="tip"
|
|
240
|
+
onInput={onInput}
|
|
241
|
+
onChange={onChange}
|
|
242
|
+
/>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
- Attrs: `value`, `edit`, `mode` (`handle` | `tip`), `disabled`
|
|
246
|
+
|
|
247
|
+
### `fig-swatch`
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
<fig-swatch background="#14AE5C" size="small" selected={selected || undefined} />
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
- Attrs: `background`, `size` (`small` | `medium` | `large`), `selected`, `disabled`, `alpha`
|
|
254
|
+
|
|
255
|
+
### `fig-chit`
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
<fig-chit background="#14AE5C" />
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
- Alias-style color chip. Same idea as `fig-swatch`.
|
|
262
|
+
|
|
263
|
+
### `fig-color-tip`
|
|
264
|
+
|
|
265
|
+
```tsx
|
|
266
|
+
<fig-color-tip value="#0D99FF" control="color" />
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
- Attrs: `value`, `control` (`color` | `add` | `remove`)
|
|
270
|
+
|
|
271
|
+
## Layout and chrome
|
|
272
|
+
|
|
273
|
+
### `fig-field`
|
|
274
|
+
|
|
275
|
+
```tsx
|
|
276
|
+
<fig-field direction="horizontal">
|
|
277
|
+
<label>Opacity</label>
|
|
278
|
+
<fig-slider value="75" min="0" max="100" text="true" units="%" full />
|
|
279
|
+
</fig-field>
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
- Attrs: `direction` (`horizontal` | `vertical`), `label`, `columns`
|
|
283
|
+
- Put control attrs on the control, not the field.
|
|
284
|
+
|
|
285
|
+
### `fig-group`
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
<fig-group name="Appearance" collapsible open compact>
|
|
289
|
+
{children}
|
|
290
|
+
</fig-group>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
- Attrs: `name`, `collapsible`, `open`, `compact`
|
|
294
|
+
|
|
295
|
+
### `fig-header`
|
|
296
|
+
|
|
297
|
+
```tsx
|
|
298
|
+
<fig-header borderless compact>
|
|
299
|
+
<h3>Title</h3>
|
|
300
|
+
</fig-header>
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
- Attrs: `borderless`, `compact`
|
|
304
|
+
|
|
305
|
+
### `fig-footer`
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
<fig-footer sticky>
|
|
309
|
+
<fig-button>Save</fig-button>
|
|
310
|
+
</fig-footer>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
- Attrs: `borderless`, `sticky`
|
|
314
|
+
|
|
315
|
+
### `fig-content`
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
<fig-content>Body</fig-content>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### `fig-tabs` / `fig-tab` / `fig-tab-content`
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
324
|
+
<fig-tabs value={tab} onChange={onChange}>
|
|
325
|
+
<fig-tab value="general" selected={tab === "general" || undefined}>
|
|
326
|
+
General
|
|
327
|
+
</fig-tab>
|
|
328
|
+
<fig-tab value="export" content="#export">
|
|
329
|
+
Export
|
|
330
|
+
</fig-tab>
|
|
331
|
+
</fig-tabs>
|
|
332
|
+
<fig-tab-content id="export">…</fig-tab-content>
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
- Tabs: roving tabindex, `aria-controls` via `content="#id"`
|
|
336
|
+
- Children stay in light DOM (overflow chrome must not steal them)
|
|
337
|
+
- Events: `input` / `change` → `currentTarget.value`
|
|
338
|
+
|
|
339
|
+
### `fig-segmented-control` / `fig-segment`
|
|
340
|
+
|
|
341
|
+
```tsx
|
|
342
|
+
<fig-segmented-control value={align} onChange={onChange}>
|
|
343
|
+
<fig-segment value="left">Left</fig-segment>
|
|
344
|
+
<fig-segment value="center">Center</fig-segment>
|
|
345
|
+
</fig-segmented-control>
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
- Radio-group pattern. Segments stay light-DOM children.
|
|
349
|
+
- Events: `input` / `change` → `currentTarget.value`
|
|
350
|
+
|
|
351
|
+
### `fig-chooser` / `fig-choice`
|
|
352
|
+
|
|
353
|
+
```tsx
|
|
354
|
+
<fig-chooser value={value} layout="vertical" onChange={onChange}>
|
|
355
|
+
<fig-choice value="a" selected={value === "a" || undefined}>
|
|
356
|
+
A
|
|
357
|
+
</fig-choice>
|
|
358
|
+
<fig-choice value="b">B</fig-choice>
|
|
359
|
+
</fig-chooser>
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
- Attrs (chooser): `value`, `layout` (`vertical` | `horizontal` | `grid`), `columns`, `drag`, `loop`, `auto-scroll`, `scroll-behavior`
|
|
363
|
+
- Choice: always set `value`. Omit chooser `value` to select first; `value=""` means none.
|
|
364
|
+
- Children stay in light DOM.
|
|
365
|
+
|
|
366
|
+
### `fig-separator` / `fig-menu-separator`
|
|
367
|
+
|
|
368
|
+
```tsx
|
|
369
|
+
<fig-separator label="Darken" sticky />
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
- Attrs: `label`, `sticky`, `borderless`. First separator in a panel is auto-`borderless`.
|
|
373
|
+
|
|
374
|
+
### `fig-menu` / `fig-menu-item`
|
|
375
|
+
|
|
376
|
+
```tsx
|
|
377
|
+
<fig-menu position="bottom left" offset="8 8" onChange={onChange}>
|
|
378
|
+
<fig-button slot="trigger">Menu</fig-button>
|
|
379
|
+
<fig-menu-item value="copy">Copy</fig-menu-item>
|
|
380
|
+
<fig-separator />
|
|
381
|
+
<fig-menu-item value="paste" disabled>
|
|
382
|
+
Paste
|
|
383
|
+
</fig-menu-item>
|
|
384
|
+
</fig-menu>
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
- Attrs (menu): `position`, `offset`, `closedby` (`auto` | `any` | `none`), `open`, `disabled`, `trigger="contextmenu"`
|
|
388
|
+
- Item: `value`, `disabled`, `subtle`. Also valid as a row in `fig-popup`.
|
|
389
|
+
- Trigger: `slot="trigger"` (also assigned automatically). Items stay in light DOM and slot into the popup — do not relocate.
|
|
390
|
+
- Internal popup uses `popover="manual"` (top layer) so lists work inside `fig-popup variant="popover"`.
|
|
391
|
+
- Events: `change` → `detail.{ value }`
|
|
392
|
+
|
|
393
|
+
### `fig-icon`
|
|
394
|
+
|
|
395
|
+
```tsx
|
|
396
|
+
<fig-icon name="search" size="small" color="secondary" />
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
- Attrs: `name`, `size` (`medium` | `small`), `color` (token)
|
|
400
|
+
|
|
401
|
+
### `fig-avatar`
|
|
402
|
+
|
|
403
|
+
```tsx
|
|
404
|
+
<fig-avatar name="Rogie King" src={src} size="large" />
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
- Attrs: `src`, `name`, `size` (`""` | `large`)
|
|
408
|
+
|
|
409
|
+
### `fig-truncate`
|
|
410
|
+
|
|
411
|
+
```tsx
|
|
412
|
+
<fig-truncate position="middle" tooltip tail="…">
|
|
413
|
+
A very long layer name
|
|
414
|
+
</fig-truncate>
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
- Attrs: `position` (`right` | `left` | `middle`), `tooltip`, `tail`
|
|
418
|
+
|
|
419
|
+
## Overlays
|
|
420
|
+
|
|
421
|
+
### `dialog is="fig-dialog"`
|
|
422
|
+
|
|
423
|
+
```tsx
|
|
424
|
+
<dialog is="fig-dialog" drag handle="fig-header" modal>
|
|
425
|
+
<fig-header>
|
|
426
|
+
Title
|
|
427
|
+
<fig-button variant="ghost" icon close-dialog aria-label="Close">
|
|
428
|
+
<fig-icon name="close" />
|
|
429
|
+
</fig-button>
|
|
430
|
+
</fig-header>
|
|
431
|
+
<fig-content>Body</fig-content>
|
|
432
|
+
</dialog>
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
- Attrs: `modal`, `drag`, `resizable`, `autoresize`, `handle`, `closedby` (`any` | `closerequest` | `none`), `position` (viewport: `top left` … `bottom right`). No `anchor`.
|
|
436
|
+
- Events: native `close` / `cancel` — listen on the dialog ref.
|
|
437
|
+
|
|
438
|
+
### `dialog is="fig-popup"`
|
|
439
|
+
|
|
440
|
+
```tsx
|
|
441
|
+
<dialog
|
|
442
|
+
ref={popupRef}
|
|
443
|
+
is="fig-popup"
|
|
444
|
+
variant="popover"
|
|
445
|
+
position="bottom left"
|
|
446
|
+
offset="8 8"
|
|
447
|
+
className="menu"
|
|
448
|
+
open={open ? true : undefined}
|
|
449
|
+
>
|
|
450
|
+
<fig-content>…</fig-content>
|
|
451
|
+
</dialog>
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
- Attrs: `anchor` (selector or element on the ref), `position`, `offset`, `viewport-margin`, `variant` (`popover` | `tooltip`), `theme` (`default` | `light` | `dark` | `menu`), `title` (auto header)
|
|
455
|
+
- `variant="popover"` uses CSS `filter` (containing block for `position: fixed`). Nested `fig-menu` / `fig-select` keep `popover="manual"`.
|
|
456
|
+
- Set `anchor` as an element after mount. Listen for `close`.
|
|
457
|
+
|
|
458
|
+
### `dialog is="fig-toast"`
|
|
459
|
+
|
|
460
|
+
```tsx
|
|
461
|
+
<dialog ref={toastRef} is="fig-toast" theme="success" duration="3000" dismiss>
|
|
462
|
+
Saved
|
|
463
|
+
</dialog>
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
```tsx
|
|
467
|
+
toastRef.current?.showToast();
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
- Attrs: `theme`, `duration`, `offset`, `dismiss`, `live` (`polite` | `assertive`), `icon`
|
|
471
|
+
|
|
472
|
+
### `fig-tooltip`
|
|
473
|
+
|
|
474
|
+
```tsx
|
|
475
|
+
<fig-tooltip ref={tipRef} text="Copy command">
|
|
476
|
+
<fig-button variant="ghost" icon onClick={onCopy} aria-label="Copy">
|
|
477
|
+
<fig-icon name="copy" />
|
|
478
|
+
</fig-button>
|
|
479
|
+
</fig-tooltip>
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
- Attrs: `text`, `action` (`hover` | `click` | `manual`), `delay`, `theme`, `pointer`, `show`
|
|
483
|
+
- Imperative: `tooltip.text = "Copied"; tooltip.showPopup(); tooltip.hidePopup();`
|
|
484
|
+
|
|
485
|
+
## Media
|
|
486
|
+
|
|
487
|
+
### `fig-preview`
|
|
488
|
+
|
|
489
|
+
```tsx
|
|
490
|
+
<fig-preview aspect-ratio="16/9" fit="cover" checkerboard>
|
|
491
|
+
<img src={src} alt="" />
|
|
492
|
+
</fig-preview>
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
- Attrs: `aspect-ratio`, `fit`, `full`, `checkerboard`
|
|
496
|
+
- Overlay: `slot="overlay"` — stays light DOM.
|
|
497
|
+
|
|
498
|
+
### `fig-media`
|
|
499
|
+
|
|
500
|
+
```tsx
|
|
501
|
+
<fig-media
|
|
502
|
+
type="image"
|
|
503
|
+
src={src}
|
|
504
|
+
fit="cover"
|
|
505
|
+
checkerboard="true"
|
|
506
|
+
upload
|
|
507
|
+
onChange={onChange}
|
|
508
|
+
/>
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
- Attrs: `type`, `src`, `caption`, `aspect-ratio`, `fit`, `upload`, `loading-indicator`, `checkerboard`, `controls`, `autoplay`, `loop`, `muted`, `poster`
|
|
512
|
+
- Events: `loaded` (`detail.src`), `input` / `change`
|
|
513
|
+
|
|
514
|
+
### `fig-image`
|
|
515
|
+
|
|
516
|
+
```tsx
|
|
517
|
+
<fig-image src={src} fit="cover" upload checkerboard="true" onChange={onChange} />
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
- Attrs: same media surface attrs. `loaded` → `detail.src`
|
|
521
|
+
|
|
522
|
+
### `fig-video`
|
|
523
|
+
|
|
524
|
+
```tsx
|
|
525
|
+
<fig-video poster={poster} muted fit="cover" controls="true" />
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
- Controls render **below** the preview, not as an overlay.
|
|
529
|
+
|
|
530
|
+
### `fig-card`
|
|
531
|
+
|
|
532
|
+
```tsx
|
|
533
|
+
<fig-card
|
|
534
|
+
src={src}
|
|
535
|
+
label="Card"
|
|
536
|
+
aspect-ratio="1/1"
|
|
537
|
+
selected={selected || undefined}
|
|
538
|
+
onClick={onClick}
|
|
539
|
+
/>
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
- Attrs: `src`, `label`, `sublabel`, `selected`, `disabled`, `full`, `size`, `aspect-ratio`, `fit`, `label-line-clamp`
|
|
543
|
+
|
|
544
|
+
### `fig-media-controls`
|
|
545
|
+
|
|
546
|
+
```tsx
|
|
547
|
+
<fig-media-controls
|
|
548
|
+
duration="120"
|
|
549
|
+
time={String(time)}
|
|
550
|
+
playing={playing || undefined}
|
|
551
|
+
onInput={onInput}
|
|
552
|
+
/>
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
- Attrs: `playing`, `overlay`, `disabled`, `duration`, `time`
|
|
556
|
+
|
|
557
|
+
## Specialized
|
|
558
|
+
|
|
559
|
+
### `fig-easing-curve`
|
|
560
|
+
|
|
561
|
+
```tsx
|
|
562
|
+
<fig-easing-curve value="ease-in-out" onInput={onInput} onChange={onChange} />
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### `fig-3d-rotate`
|
|
566
|
+
|
|
567
|
+
```tsx
|
|
568
|
+
<fig-3d-rotate value='{"x":0,"y":0}' onInput={onInput} onChange={onChange} />
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
- JSON `value`. Pass as a string attr.
|
|
572
|
+
|
|
573
|
+
### `fig-origin-grid`
|
|
574
|
+
|
|
575
|
+
```tsx
|
|
576
|
+
<fig-origin-grid value="50% 50%" fields="true" onInput={onInput} />
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
### `fig-joystick`
|
|
580
|
+
|
|
581
|
+
```tsx
|
|
582
|
+
<fig-joystick value="50% 50%" axis-labels="X Y" onInput={onInput} />
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
### `fig-handle`
|
|
586
|
+
|
|
587
|
+
```tsx
|
|
588
|
+
<div style={{ position: "relative", width: 120, height: 80 }}>
|
|
589
|
+
<fig-handle value="50% 50%" drag type="default" />
|
|
590
|
+
</div>
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
- Attrs: `type` (`default` | `minimal` | `color` | `canvas`), `tip`, `size`, `color`, `selected`, `disabled`, `drag`, `drag-axes`, `drag-snapping`
|
|
594
|
+
|
|
595
|
+
### `fig-spinner`
|
|
596
|
+
|
|
597
|
+
```tsx
|
|
598
|
+
<fig-spinner size="small" />
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### `fig-shimmer`
|
|
602
|
+
|
|
603
|
+
```tsx
|
|
604
|
+
<fig-shimmer>
|
|
605
|
+
<span>Thinking…</span>
|
|
606
|
+
</fig-shimmer>
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
- Attrs: `duration`, `direction`, `playing`
|
|
610
|
+
|
|
611
|
+
### `fig-skeleton`
|
|
612
|
+
|
|
613
|
+
```tsx
|
|
614
|
+
<fig-skeleton>
|
|
615
|
+
<fig-field>
|
|
616
|
+
<label>Name</label>
|
|
617
|
+
<fig-input-text value="Loading" />
|
|
618
|
+
</fig-field>
|
|
619
|
+
</fig-skeleton>
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
- Attrs: `duration`, `direction`, `playing`
|
|
623
|
+
|
|
624
|
+
## `fig-layer` (separate bundle)
|
|
625
|
+
|
|
626
|
+
Not registered by `fig.js`. Import `fig-layer.css` + `fig-layer.js`.
|
|
627
|
+
|
|
628
|
+
```tsx
|
|
629
|
+
<fig-layer data-section="button" open>
|
|
630
|
+
<div className="fig-layer-row">
|
|
631
|
+
<label>Button</label>
|
|
632
|
+
</div>
|
|
633
|
+
<fig-layer data-section="button" data-example="primary">
|
|
634
|
+
<div className="fig-layer-row">
|
|
635
|
+
<label>Primary</label>
|
|
636
|
+
</div>
|
|
637
|
+
</fig-layer>
|
|
638
|
+
</fig-layer>
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
- Attrs: `open`, `visible`, `disabled`, `selected`
|
|
642
|
+
- Events: `openchange`, `visibilitychange`. Nested layers are React children; sync `selected` / `open` via attrs or `setAttribute` after render.
|
|
643
|
+
- Clicks on `.fig-layer-chevron` toggle; row clicks are yours (delegate on a parent).
|