@rogieking/figui3 8.9.44 → 8.9.46
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/components.css +4 -3
- package/dist/components.css +1 -1
- package/dist/fig.css +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
# FigUI3 lab components (`fig-lab.js`)
|
|
2
|
+
|
|
3
|
+
Experimental. APIs may change. React contract: [../figui3/react.md](../figui3/react.md). Attrs: [reference.md](reference.md).
|
|
4
|
+
|
|
5
|
+
Install `fig-lab.css` + `fig-lab.js`. `propskit-select` prefers `fig-select` — also import `fig-editor.js` + `fig-editor.css` for rich menus. `fig-editor.js` already imports `fig-lab.js`; lab **CSS** is still required.
|
|
6
|
+
|
|
7
|
+
Handlers below assume `onInput` / `onChange` from the React contract.
|
|
8
|
+
|
|
9
|
+
## Shared propskit
|
|
10
|
+
|
|
11
|
+
Full-surface `fig-field` wrappers. Prefer these over hand-rolled label+control rows.
|
|
12
|
+
|
|
13
|
+
Shared attrs: `label`, `direction` (`horizontal` default), `size` (`""` | `small`; `large` is an alias for default), `disabled`, `variant="minimal"` (no vertical padding; field background on hover), `default` (reset target, may differ from initial `value`).
|
|
14
|
+
|
|
15
|
+
Right-click **Reset**; `resetToDefault()` on a ref. `propskit-slider` also double-click resets. Remaining attrs forward to the inner control. Rows are large by default; `propskit-group size="small"` applies compact sizing to children without an authored size.
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
const rowRef = useRef<HTMLElement>(null);
|
|
19
|
+
rowRef.current?.resetToDefault();
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Propskit
|
|
23
|
+
|
|
24
|
+
### `propskit-switch`
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
<propskit-switch
|
|
28
|
+
label="Visible"
|
|
29
|
+
checked={on ? "true" : undefined}
|
|
30
|
+
default="true"
|
|
31
|
+
onInput={onInput}
|
|
32
|
+
/>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- Inner: `fig-switch`. `checked` / `default` boolean.
|
|
36
|
+
|
|
37
|
+
### `propskit-color`
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
<propskit-color
|
|
41
|
+
label="Fill"
|
|
42
|
+
value="#0D99FF"
|
|
43
|
+
alpha="true"
|
|
44
|
+
onInput={onInput}
|
|
45
|
+
onChange={onChange}
|
|
46
|
+
/>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- Inner: `fig-fill-picker` + `fig-swatch`. Clicking the field opens the picker anchored to the host. Focus ring on the field, not the swatch.
|
|
50
|
+
|
|
51
|
+
### `propskit-fill`
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
<propskit-fill
|
|
55
|
+
label="Fill"
|
|
56
|
+
value='{"type":"solid","color":"#0D99FF"}'
|
|
57
|
+
onInput={onInput}
|
|
58
|
+
onChange={onChange}
|
|
59
|
+
>
|
|
60
|
+
<div slot="mode-shader" label="Shader">
|
|
61
|
+
Shader UI
|
|
62
|
+
</div>
|
|
63
|
+
</propskit-fill>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- Same chrome as color. Value may be fill JSON or a bare video URL. Forwards `mode-*` slots.
|
|
67
|
+
|
|
68
|
+
### `propskit-gradient`
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<propskit-gradient
|
|
72
|
+
label="Gradient"
|
|
73
|
+
value={gradientJson}
|
|
74
|
+
edit="picker"
|
|
75
|
+
onInput={onInput}
|
|
76
|
+
/>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- Inner: `fig-input-gradient`. Default `edit="picker"`. `mode="handle|tip"` for inline edit. Clicking the field opens the picker anchored to the host.
|
|
80
|
+
|
|
81
|
+
### `propskit-select`
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
<propskit-select
|
|
85
|
+
label="Blend"
|
|
86
|
+
value="multiply"
|
|
87
|
+
options="Normal,Multiply,Screen"
|
|
88
|
+
onChange={onChange}
|
|
89
|
+
/>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Rich options (requires editor):
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
<propskit-select label="Space" value="oklab" onChange={onChange}>
|
|
96
|
+
<fig-select-options slot="panel">
|
|
97
|
+
<fig-select-option value="srgb" label="Classic">
|
|
98
|
+
Classic
|
|
99
|
+
</fig-select-option>
|
|
100
|
+
</fig-select-options>
|
|
101
|
+
</propskit-select>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- Inner: `fig-select` when registered; otherwise a fallback. Authored `fig-select-options slot="panel"` wins. Options stay in light DOM.
|
|
105
|
+
|
|
106
|
+
### `propskit-text`
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
<propskit-text
|
|
110
|
+
label="Name"
|
|
111
|
+
value={name}
|
|
112
|
+
onInput={onInput}
|
|
113
|
+
onChange={onChange}
|
|
114
|
+
/>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- Inner: `fig-input-text`. `type`, `readonly`.
|
|
118
|
+
|
|
119
|
+
### `propskit-number`
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
<propskit-number
|
|
123
|
+
label="Size"
|
|
124
|
+
value="16"
|
|
125
|
+
min="0"
|
|
126
|
+
max="100"
|
|
127
|
+
step="1"
|
|
128
|
+
units="px"
|
|
129
|
+
steppers="true"
|
|
130
|
+
onInput={onInput}
|
|
131
|
+
/>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- Inner: `fig-input-number`.
|
|
135
|
+
|
|
136
|
+
### `propskit-slider`
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
<propskit-slider
|
|
140
|
+
label="Opacity"
|
|
141
|
+
direction="horizontal"
|
|
142
|
+
type="opacity"
|
|
143
|
+
value="100"
|
|
144
|
+
default="100"
|
|
145
|
+
min="0"
|
|
146
|
+
max="100"
|
|
147
|
+
units="%"
|
|
148
|
+
onInput={onInput}
|
|
149
|
+
onChange={onChange}
|
|
150
|
+
/>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- Inner: `fig-slider`. `type` range/hue/delta/stepper/opacity; `elastic` default true. Forward `min` / `max` / `step` / `value`.
|
|
154
|
+
|
|
155
|
+
### `propskit-wheel`
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
<propskit-wheel
|
|
159
|
+
label="Duration"
|
|
160
|
+
value="1.5"
|
|
161
|
+
units="seconds"
|
|
162
|
+
onInput={onInput}
|
|
163
|
+
/>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
- Inner: `fig-input-wheel` + optional `fig-input-number`. Attrs: `label`, `text`, `spin`, `elastic` (row stretch, default true), `precision`, `units`, `default`, `size`, `variant`. Units stay on the wrapper; effective step is applied to the wheel. `spin="false"` updates value without moving ticks.
|
|
167
|
+
|
|
168
|
+
### `propskit-position`
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
<propskit-position label="Position" x="50" y="50" units="percent" onInput={onInput} />
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
- Two numbers. Attrs: `x`, `y`, `units`.
|
|
175
|
+
|
|
176
|
+
### `propskit-color-point`
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
<propskit-color-point
|
|
180
|
+
label="Stop"
|
|
181
|
+
value={json}
|
|
182
|
+
collapsible
|
|
183
|
+
open
|
|
184
|
+
onInput={onInput}
|
|
185
|
+
/>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
- Color + position JSON. `collapsible` / `open` default true (string booleans).
|
|
189
|
+
|
|
190
|
+
### `propskit-point-radius`
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
<propskit-point-radius label="Spot" value='{"x":50,"y":50,"radius":60}' onInput={onInput} />
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### `propskit-point-radius-angle`
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
<propskit-point-radius-angle
|
|
200
|
+
label="Light"
|
|
201
|
+
value='{"x":50,"y":50,"radius":60,"angle":45}'
|
|
202
|
+
onInput={onInput}
|
|
203
|
+
/>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### `propskit-point-point`
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
<propskit-point-point
|
|
210
|
+
label="Line"
|
|
211
|
+
value='{"x":10,"y":10,"x2":90,"y2":90}'
|
|
212
|
+
onInput={onInput}
|
|
213
|
+
/>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### `propskit-group`
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
<propskit-group name="Appearance" open show-reset>
|
|
220
|
+
<propskit-slider label="Opacity" value="100" min="0" max="100" />
|
|
221
|
+
</propskit-group>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
- Attrs: `name`, `open`, `show-reset`, `size`. Children are React nodes.
|
|
225
|
+
|
|
226
|
+
### `propskit-oscillator`
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
<propskit-oscillator
|
|
230
|
+
label="Wave"
|
|
231
|
+
value={wavesJson}
|
|
232
|
+
edit
|
|
233
|
+
onInput={onInput}
|
|
234
|
+
/>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
- JSON `waves`. Attrs: `edit`, `precision`, `aspect-ratio`, `disabled`.
|
|
238
|
+
|
|
239
|
+
## Spatial
|
|
240
|
+
|
|
241
|
+
### `fig-canvas-control`
|
|
242
|
+
|
|
243
|
+
```tsx
|
|
244
|
+
<div style={{ position: "relative", aspectRatio: "1", width: "100%" }}>
|
|
245
|
+
<fig-canvas-control
|
|
246
|
+
type="point-radius-angle"
|
|
247
|
+
name="Position"
|
|
248
|
+
value='{"x":50,"y":50,"radius":60,"angle":45}'
|
|
249
|
+
snapping="modifier"
|
|
250
|
+
onInput={onInput}
|
|
251
|
+
onChange={onChange}
|
|
252
|
+
/>
|
|
253
|
+
</div>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
- Parent must be positioned. Types: `point`, `color`, `point-radius`, `point-radius-angle`, `point-point`.
|
|
257
|
+
- Attrs: `type`, `value` (JSON string), `color`, `name`, `tooltips`, `disabled`, `drag-surface`, `snapping` (`false` | `modifier` | `true`)
|
|
258
|
+
- React: JSON `value` as a string attr; do not remount during drag.
|
|
259
|
+
|
|
260
|
+
### `fig-input-angle`
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
<fig-input-angle
|
|
264
|
+
value={String(deg)}
|
|
265
|
+
text="true"
|
|
266
|
+
units="°"
|
|
267
|
+
onInput={onInput}
|
|
268
|
+
/>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
- Attrs: `value`, `precision`, `text`, `min`, `max`, `units`, `dial` (default true), `rotations`, `disabled`
|
|
272
|
+
|
|
273
|
+
### `fig-input-wheel`
|
|
274
|
+
|
|
275
|
+
```tsx
|
|
276
|
+
<fig-input-wheel value="50" min="0" max="100" step="1" onInput={onInput} />
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
- Standalone SVG tick + handle. Attrs: `value` (default `0`), `step` (default `1`), `min`, `max`, `spin` (default true), `disabled`. No `units` / `text` / `label` / reset — use `propskit-wheel` for those.
|
|
280
|
+
- Methods: `focus()`, `spinTo(value)`, `beginScrub()`, `updateScrub()`, `endScrub()`.
|
|
281
|
+
|
|
282
|
+
### `fig-reorder`
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
<fig-reorder axis="vertical" handle=".drag">
|
|
286
|
+
{items.map((item) => (
|
|
287
|
+
<div key={item.id} className="row">
|
|
288
|
+
<button className="drag" type="button" aria-label="Reorder" />
|
|
289
|
+
{item.label}
|
|
290
|
+
</div>
|
|
291
|
+
))}
|
|
292
|
+
</fig-reorder>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Listen for `reorder` on a ref (`onReorder` is not a React-mapped event):
|
|
296
|
+
|
|
297
|
+
```tsx
|
|
298
|
+
useEffect(() => {
|
|
299
|
+
const el = ref.current;
|
|
300
|
+
if (!el) return;
|
|
301
|
+
const handler = (event: Event) => {
|
|
302
|
+
const { oldIndex, newIndex, item } = (event as CustomEvent).detail;
|
|
303
|
+
onReorder({ oldIndex, newIndex, item });
|
|
304
|
+
};
|
|
305
|
+
el.addEventListener("reorder", handler);
|
|
306
|
+
return () => el.removeEventListener("reorder", handler);
|
|
307
|
+
}, [onReorder]);
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
- `display: contents`. Reorders **direct children**. `axis` `vertical` | `horizontal`. Omit `handle` to drag whole rows; set it when rows contain sliders/handles.
|
|
311
|
+
- Event `reorder`: `{ oldIndex, newIndex, item }`. Nested drag is ignored for sliders, handles, canvas, and most propskit spatial controls.
|
|
312
|
+
|
|
313
|
+
## AI composer
|
|
314
|
+
|
|
315
|
+
Layout shells. Wire behavior yourself. Children are React nodes.
|
|
316
|
+
|
|
317
|
+
### `fig-ai-prompt`
|
|
318
|
+
|
|
319
|
+
```tsx
|
|
320
|
+
<fig-ai-prompt>
|
|
321
|
+
<fig-input-text multiline placeholder="Describe a change" />
|
|
322
|
+
<fig-footer>
|
|
323
|
+
<fig-button>Send</fig-button>
|
|
324
|
+
</fig-footer>
|
|
325
|
+
</fig-ai-prompt>
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### `fig-ai-context`
|
|
329
|
+
|
|
330
|
+
```tsx
|
|
331
|
+
<fig-ai-context>
|
|
332
|
+
<fig-attachments>{attachments}</fig-attachments>
|
|
333
|
+
</fig-ai-context>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Open area above the prompt for attachments/status.
|
|
337
|
+
|
|
338
|
+
### `fig-chat-message`
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
<fig-chat-message from="user">
|
|
342
|
+
Create a settings panel.
|
|
343
|
+
<fig-attachments aria-label="Message attachments">
|
|
344
|
+
<fig-attachment
|
|
345
|
+
value="settings"
|
|
346
|
+
name="settings.png"
|
|
347
|
+
src={src}
|
|
348
|
+
removable="false"
|
|
349
|
+
/>
|
|
350
|
+
</fig-attachments>
|
|
351
|
+
<fig-avatar name="Rogie King" />
|
|
352
|
+
</fig-chat-message>
|
|
353
|
+
<fig-chat-message from="agent">
|
|
354
|
+
<fig-shimmer>
|
|
355
|
+
<span>Thinking…</span>
|
|
356
|
+
</fig-shimmer>
|
|
357
|
+
</fig-chat-message>
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
- Attrs: `from` (`user` | `agent`)
|
|
361
|
+
|
|
362
|
+
### `fig-attachments` / `fig-attachment`
|
|
363
|
+
|
|
364
|
+
```tsx
|
|
365
|
+
<fig-attachments>
|
|
366
|
+
<fig-attachment src={src} name="file.png" value="file" />
|
|
367
|
+
</fig-attachments>
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
- Attachment attrs: `src`, `name`, `value`, `removable` (default true), `disabled`
|
|
371
|
+
- Events: `remove` — listen natively if React does not map it.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# FigUI3 lab API reference
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React recipes: [components.md](components.md).
|
|
4
4
|
|
|
5
5
|
## Propskit reset
|
|
6
6
|
|
|
@@ -14,6 +14,8 @@ Playground: `/propskit/lab#{id}`. Rules: `playground/src/lib/attributeRules.ts`.
|
|
|
14
14
|
|
|
15
15
|
`variant="minimal"` is available on switch, color, fill, gradient, select, text, number, slider, position, and wheel controls. It removes vertical host padding, keeps the inner field transparent at rest, and restores the secondary field background on hover.
|
|
16
16
|
|
|
17
|
+
## Propskit sizes
|
|
18
|
+
|
|
17
19
|
PropsKit rows are large by default; explicit `size="large"` remains supported.
|
|
18
20
|
`propskit-group size="small"` applies `size="small"` to nested controls that do
|
|
19
21
|
not define their own size and removes generated sizes when the group returns to
|
|
@@ -29,7 +31,7 @@ Options attr: JSON array, comma, or newline. Authored `fig-select-options slot="
|
|
|
29
31
|
|
|
30
32
|
## `propskit-slider`
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
Attrs: `type` (`range`, `hue`, `delta`, `stepper`, `opacity`), `color`, `label`, `default`, `units`, `elastic` (default true), `size`, `steppers`, `disabled`.
|
|
33
35
|
|
|
34
36
|
Inner `fig-slider` still needs `min` / `max` / `step` / `value` as forwarded attrs.
|
|
35
37
|
|
|
@@ -75,7 +77,7 @@ Collapsible point groups: `collapsible` and `open` default true (string booleans
|
|
|
75
77
|
|
|
76
78
|
Observed: `type`, `value`, `color`, `name`, `tooltips`, `disabled`, `drag-surface`, `snapping`.
|
|
77
79
|
|
|
78
|
-
Parent must be `position: relative` (or similar) so the control can fill it.
|
|
80
|
+
Parent must be `position: relative` (or similar) so the control can fill it. Wrap in an aspect-ratio box.
|
|
79
81
|
|
|
80
82
|
Types: `point`, `color`, `point-radius`, `point-radius-angle`, `point-point`.
|
|
81
83
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: figui3
|
|
3
3
|
description: >-
|
|
4
|
-
Guides FigUI3 core (`fig.js` / `fig.css`) web components for Figma-style plugin UIs
|
|
5
|
-
Use when adding, using, or debugging fig-* elements from
|
|
6
|
-
fields, overlays, menus, sliders, color/fill inputs, media,
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
Guides FigUI3 core (`fig.js` / `fig.css`) web components for Figma-style plugin UIs,
|
|
5
|
+
including React JSX usage. Use when adding, using, or debugging fig-* elements from
|
|
6
|
+
the core bundle—buttons, fields, overlays, menus, sliders, color/fill inputs, media,
|
|
7
|
+
dialogs, popups, toasts. Not for fig-select or fig-fill-picker (fig-editor),
|
|
8
|
+
propskit-* / AI / canvas / angle / wheel / reorder (fig-lab), or fig-layer.
|
|
9
9
|
user-invocable: false
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -13,19 +13,13 @@ user-invocable: false
|
|
|
13
13
|
|
|
14
14
|
Zero-dependency web components for Figma UI3 plugin and widget UIs.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Public API: `README.md`. React: [react.md](react.md). Per-tag JSX: [components.md](components.md). Attrs: [reference.md](reference.md).
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
- Local: `npm run dev:playground` → `/figui3`
|
|
20
|
-
- Sections: `playground/src/data/figui3Sections.ts`
|
|
21
|
-
- Attribute inspector: `playground/src/lib/attributeRules.ts`
|
|
22
|
-
- Public API: `README.md`
|
|
23
|
-
|
|
24
|
-
Related skills: `fig-editor` (`fig-select`, `fig-fill-picker`), `fig-lab` (`propskit-*`, AI, canvas), `propkit` (`/propskit` field composition).
|
|
18
|
+
Related skills: `fig-editor` (`fig-select`, `fig-fill-picker`), `fig-lab` (`propskit-*`, AI, canvas), `propkit` (property-row composition).
|
|
25
19
|
|
|
26
20
|
## Bundles
|
|
27
21
|
|
|
28
|
-
Always import CSS with JS. Register before first render.
|
|
22
|
+
Always import CSS with JS. Register before first render. In React, see [react.md](react.md).
|
|
29
23
|
|
|
30
24
|
```js
|
|
31
25
|
import "@rogieking/figui3/fig.css";
|
|
@@ -34,14 +28,12 @@ import "@rogieking/figui3/fig.js";
|
|
|
34
28
|
|
|
35
29
|
| Bundle | CSS + JS | Components |
|
|
36
30
|
|---|---|---|
|
|
37
|
-
| **Core** (this skill) | `fig.css` + `fig.js` | All `fig-*`
|
|
31
|
+
| **Core** (this skill) | `fig.css` + `fig.js` | All `fig-*` in [components.md](components.md) |
|
|
38
32
|
| **Editor** | `fig-editor.css` + `fig-editor.js` | `fig-select*`, `fig-fill-picker`, `fig-interpolation-swatch` |
|
|
39
33
|
| **Lab** (unstable) | `fig-lab.css` + `fig-lab.js` | `propskit-*`, `fig-ai-*`, `fig-canvas-control`, `fig-input-angle`, `fig-input-wheel`, `fig-reorder` |
|
|
40
34
|
| **Layer** | `fig-layer.css` + `fig-layer.js` | `fig-layer` |
|
|
41
35
|
|
|
42
|
-
`fig-editor.js` also imports `fig.js` and `fig-lab.js`. Lab CSS is still separate. `fig-layer` is **not** registered by `fig-editor.js`.
|
|
43
|
-
|
|
44
|
-
Playground “Full editor” toggle reveals `#select`, `#fill-picker`, `#layer`, and `#toast`. That grouping is UI-only: toast is core; layer is `fig-layer.js`.
|
|
36
|
+
`fig-editor.js` also imports `fig.js` and `fig-lab.js`. Lab CSS is still separate. `fig-layer` is **not** registered by `fig-editor.js`. Toast is core; layer is `fig-layer.js`.
|
|
45
37
|
|
|
46
38
|
## Principles
|
|
47
39
|
|
|
@@ -49,25 +41,7 @@ Playground “Full editor” toggle reveals `#select`, `#fill-picker`, `#layer`,
|
|
|
49
41
|
2. Use design tokens (`--figma-color-*`, `--radius-*`, `--spacer-*`). Do not hardcode Figma colors.
|
|
50
42
|
3. Emit `input` while interacting and `change` on commit. Do not fire `input` from programmatic attribute writes.
|
|
51
43
|
4. Preserve a11y: labels, keyboard, ARIA, disabled. See the `a11y` skill.
|
|
52
|
-
5. Keep components framework-agnostic. No React internals.
|
|
53
|
-
|
|
54
|
-
## React + Vite
|
|
55
|
-
|
|
56
|
-
```tsx
|
|
57
|
-
import "@rogieking/figui3/fig.css";
|
|
58
|
-
|
|
59
|
-
const bootstrap = async () => {
|
|
60
|
-
await import("@rogieking/figui3/fig.js");
|
|
61
|
-
createRoot(document.getElementById("app")!).render(<App />);
|
|
62
|
-
};
|
|
63
|
-
bootstrap();
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
- Use DOM attrs (`text="true"`). Read values from `e.target` / `e.detail`.
|
|
67
|
-
- On `fig-*` and `<dialog is="fig-...">`, use `class` not `className`.
|
|
68
|
-
- Prefer refs + `addEventListener` for `input`/`change`.
|
|
69
|
-
|
|
70
|
-
Color picker modes: `fig-fill-picker` is optional editor. Do not use `picker` / `picker-anchor` on `fig-input-color`. `picker-*` attrs forward to the picker only when it is registered. See `fig-editor`.
|
|
44
|
+
5. Keep components framework-agnostic. No React internals in `fig.js`.
|
|
71
45
|
|
|
72
46
|
## Overlay rules
|
|
73
47
|
|
|
@@ -76,34 +50,28 @@ Color picker modes: `fig-fill-picker` is optional editor. Do not use `picker` /
|
|
|
76
50
|
- `<dialog is="fig-toast">` — call `showToast()`. `theme`, `duration`, `live`, `dismiss`, `icon`.
|
|
77
51
|
- `fig-menu` and `fig-select` use `popover="manual"` so lists escape filter-containing popups to the top layer. Nested menus inside popovers must keep that. `fig-menu` slots items (does not relocate them); triggers get `slot="trigger"`.
|
|
78
52
|
|
|
79
|
-
```
|
|
53
|
+
```tsx
|
|
80
54
|
<dialog is="fig-dialog" drag handle="fig-header">
|
|
81
55
|
<fig-header>
|
|
82
56
|
Title
|
|
83
57
|
<fig-button variant="ghost" icon close-dialog aria-label="Close">
|
|
84
|
-
<fig-icon name="close"
|
|
58
|
+
<fig-icon name="close" />
|
|
85
59
|
</fig-button>
|
|
86
60
|
</fig-header>
|
|
87
61
|
<fig-content>Body</fig-content>
|
|
88
62
|
</dialog>
|
|
89
|
-
|
|
90
|
-
<dialog is="fig-popup" anchor="#trigger" position="bottom left" offset="8 8">
|
|
91
|
-
Popup content
|
|
92
|
-
</dialog>
|
|
93
63
|
```
|
|
94
64
|
|
|
95
65
|
## Field composition
|
|
96
66
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
```html
|
|
67
|
+
```tsx
|
|
100
68
|
<fig-field direction="horizontal">
|
|
101
69
|
<label>Opacity</label>
|
|
102
|
-
<fig-slider value="75" min="0" max="100" text="true" units="%" full
|
|
70
|
+
<fig-slider value="75" min="0" max="100" text="true" units="%" full />
|
|
103
71
|
</fig-field>
|
|
104
72
|
```
|
|
105
73
|
|
|
106
|
-
Labeled property wrappers (`propskit-*`) are lab.
|
|
74
|
+
Labeled property wrappers (`propskit-*`) are lab. See the `propkit` and `fig-lab` skills.
|
|
107
75
|
|
|
108
76
|
## Select vs dropdown
|
|
109
77
|
|
|
@@ -115,100 +83,23 @@ Labeled property wrappers (`propskit-*`) are lab. For `/propskit` playground pat
|
|
|
115
83
|
|
|
116
84
|
Prefer `fig-select` for Figma-style menus. Use `fig-dropdown` only for a native select.
|
|
117
85
|
|
|
118
|
-
## Core catalog
|
|
119
|
-
|
|
120
|
-
Playground hashes: `/figui3#{id}`. Full attrs: [reference.md](reference.md).
|
|
121
|
-
|
|
122
|
-
### Buttons and inputs
|
|
123
|
-
|
|
124
|
-
| Tag | Playground | Notes |
|
|
125
|
-
|---|---|---|
|
|
126
|
-
| `fig-button` | `#button` | `variant`: secondary, ghost, link, destructive*, overlay, input. `type`: button, toggle, submit, select, upload. `size`, `icon`, `selected` |
|
|
127
|
-
| `fig-dropdown` | `#dropdown` | Native select. Options as `<option>` / `<optgroup>`. `variant="ghost"` |
|
|
128
|
-
| `fig-combo-input` | `#combo-input` | Text + suggestions (`options`) |
|
|
129
|
-
| `fig-input-text` | `#text-input` | `multiline` for textarea |
|
|
130
|
-
| `fig-input-number` | `#number-input` | `min`, `max`, `step`, `units`, `precision` |
|
|
131
|
-
| `fig-input-file` | `#file-input` | `accepts`, `multiple`, button `variant` |
|
|
132
|
-
| `fig-checkbox` / `fig-radio` / `fig-switch` | `#checkbox` `#radio` `#switch` | Switch supports `indeterminate` |
|
|
133
|
-
| `fig-slider` | `#slider` | `type`: range, opacity, hue, stepper, delta. `text`, `units`, `transform`, `variant="classic"` |
|
|
134
|
-
| `fig-options` | (propkit `#options`) | Option list helper; same option string formats as select |
|
|
135
|
-
|
|
136
|
-
### Color and fill (no picker dialog)
|
|
137
|
-
|
|
138
|
-
| Tag | Playground | Notes |
|
|
139
|
-
|---|---|---|
|
|
140
|
-
| `fig-input-color` | (propkit `#color`) | Solid color. `text`, `alpha`. Auto-detects `fig-fill-picker` |
|
|
141
|
-
| `fig-input-fill` | `#fill-input` | Solid/gradient/image/video/webcam/custom JSON `value`. Custom `mode-*` slots forward to the inner picker and use image-style chrome. Same `webcam` / `video.poster` shape as the picker. `webcam-mode`, `default-video`, `picker-*` forwarded if picker registered |
|
|
142
|
-
| `fig-input-palette` | (propkit `#palette`) | Multi-color. `fixed`, `open` |
|
|
143
|
-
| `fig-input-gradient` | (propkit `#gradient`) | Stops. `edit`, `mode="handle\|tip"` |
|
|
144
|
-
| `fig-swatch` | `#swatch` | `size`, `selected`, `alpha` |
|
|
145
|
-
| `fig-color-tip` | `#color-tip` | `control="color\|add\|remove"` |
|
|
146
|
-
| `fig-chit` | — | Alias-style color chip |
|
|
147
|
-
|
|
148
|
-
### Layout and chrome
|
|
149
|
-
|
|
150
|
-
| Tag | Playground | Notes |
|
|
151
|
-
|---|---|---|
|
|
152
|
-
| `fig-field` | `#field` | `direction="horizontal\|vertical"`, `label` |
|
|
153
|
-
| `fig-group` | (containers) | `name`, `collapsible`, `open`, `compact` |
|
|
154
|
-
| `fig-header` / `fig-footer` / `fig-content` | (containers) | Header: `borderless`, `compact`. Footer: `sticky` |
|
|
155
|
-
| `fig-tabs` / `fig-tab` | `#tabs` | Roving tabs. `content="#id"` for panels |
|
|
156
|
-
| `fig-segmented-control` / `fig-segment` | `#segmented-control` | Radio-group pattern |
|
|
157
|
-
| `fig-chooser` / `fig-choice` | `#chooser` | Listbox. Omit `value` to select first; `value=""` means none. |
|
|
158
|
-
| `fig-separator` / `fig-menu-separator` | `#separator` | Optional `label`, `sticky`, `borderless` |
|
|
159
|
-
| `fig-menu` / `fig-menu-item` | `#menu` | `fig-menu-trigger`, `trigger="contextmenu"`, `position`, `offset`. Item also works in `fig-popup` (sticky separators, nested row menus). |
|
|
160
|
-
| `fig-icon` | `#icon` | Token mask (`name`, `size="small"`, `color`) |
|
|
161
|
-
| `fig-avatar` | `#avatar` | `src` / `name`, `size="large"` |
|
|
162
|
-
| `fig-truncate` | `#truncate` | `position="right\|left\|middle"`, `tooltip`, `tail` |
|
|
163
|
-
|
|
164
|
-
### Overlays
|
|
165
|
-
|
|
166
|
-
| Tag | Playground | Notes |
|
|
167
|
-
|---|---|---|
|
|
168
|
-
| `dialog is="fig-dialog"` | `#dialog` | `modal`, `drag`, `resizable`, `autoresize`, `handle`, `closedby`, `position` |
|
|
169
|
-
| `dialog is="fig-popup"` | `#popup` | `anchor`, `position`, `offset`, `viewport-margin`, `variant`, `theme` |
|
|
170
|
-
| `dialog is="fig-toast"` | `#toast` | `showToast()`. `theme`, `duration`, `live`, `dismiss`, `icon` |
|
|
171
|
-
| `fig-tooltip` | `#tooltip` | `text`, `action="hover\|click\|manual"`, `delay`, `theme` |
|
|
172
|
-
|
|
173
|
-
### Media
|
|
174
|
-
|
|
175
|
-
| Tag | Playground | Notes |
|
|
176
|
-
|---|---|---|
|
|
177
|
-
| `fig-preview` | (propkit `#preview`) | `aspect-ratio`, `fit`, `full`, `checkerboard` |
|
|
178
|
-
| `fig-media` / `fig-image` / `fig-video` | `#media` `#image` `#video` | Upload via `upload`. Video controls below preview |
|
|
179
|
-
| `fig-card` | `#card` | Media + label + selection |
|
|
180
|
-
| `fig-media-controls` | `#media-controls` | Play/pause chrome |
|
|
181
|
-
| `fig-input-file` | `#file-input` | File picker button |
|
|
182
|
-
|
|
183
|
-
### Specialized
|
|
184
|
-
|
|
185
|
-
| Tag | Playground | Notes |
|
|
186
|
-
|---|---|---|
|
|
187
|
-
| `fig-easing-curve` | (propkit `#easing`) | Bezier/spring |
|
|
188
|
-
| `fig-3d-rotate` | (containers) | Cube rotate |
|
|
189
|
-
| `fig-origin-grid` | (propkit) | Transform origin |
|
|
190
|
-
| `fig-joystick` | (propkit `#joystick`) | 2D position |
|
|
191
|
-
| `fig-handle` | `#handle` | `type="default\|minimal\|color\|canvas"`, `drag`, `drag-snapping` |
|
|
192
|
-
| `fig-spinner` / `fig-shimmer` / `fig-skeleton` | `#spinner` `#shimmer` | Loading |
|
|
193
|
-
|
|
194
|
-
`fig-input-angle` and `fig-input-wheel` are **lab**, not core.
|
|
195
|
-
|
|
196
86
|
## Events
|
|
197
87
|
|
|
198
88
|
```txt
|
|
199
|
-
fig-slider input/change → e.
|
|
89
|
+
fig-slider input/change → e.currentTarget.value
|
|
200
90
|
fig-input-color input/change → detail { color, alpha, opacity } plus legacy value/hex/rgba
|
|
201
91
|
fig-input-fill input/change → fill payload in e.detail
|
|
202
92
|
fig-menu change → detail { value }
|
|
203
93
|
fig-dialog/popup native dialog close plus FigUI3 positioning attrs
|
|
204
94
|
```
|
|
205
95
|
|
|
96
|
+
`fig-input-angle` and `fig-input-wheel` are **lab**, not core.
|
|
97
|
+
|
|
206
98
|
## Maintainer workflow
|
|
207
99
|
|
|
208
100
|
1. Read `fig.js` + `components.css` before editing.
|
|
209
|
-
2.
|
|
210
|
-
3.
|
|
211
|
-
4.
|
|
212
|
-
5. Tests: `npm run test:components` (Playwright). Do not start a second playground if one is running.
|
|
101
|
+
2. Update `README.md` + `CHANGELOG.md` for public API changes.
|
|
102
|
+
3. `bun build` for dist.
|
|
103
|
+
4. Tests: `npm run test:components` (Playwright).
|
|
213
104
|
|
|
214
|
-
Primary files: `fig.js`, `components.css`, `base.css`, `README.md
|
|
105
|
+
Primary files: `fig.js`, `components.css`, `base.css`, `README.md`.
|