@rogieking/figui3 8.11.0 → 9.0.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.
@@ -15,7 +15,6 @@ Custom select and full fill-picker. Not in core `fig.js`.
15
15
 
16
16
  React: [../figui3/react.md](../figui3/react.md). Per-tag JSX: [components.md](components.md). Attrs: [reference.md](reference.md).
17
17
 
18
- See also: `figui3` (core), `fig-lab` (`propskit-select` wraps this select).
19
18
 
20
19
  ## Install
21
20
 
@@ -38,11 +37,9 @@ Registered tags:
38
37
  | `fig-fill-picker` | Full fill editor dialog (solid, gradient, image, video, webcam, custom modes) |
39
38
  | `fig-interpolation-swatch` | Gradient interpolation preview swatch |
40
39
 
41
- ## `fig-select` vs `fig-dropdown` vs `propskit-select`
42
40
 
43
41
  - `fig-dropdown` (core): native `<select>`.
44
42
  - `fig-select` (this skill): custom listbox. Use this for Figma-style menus.
45
- - `propskit-select` (lab): labeled horizontal surface that always renders `fig-select`; this editor bundle is required to register and style it.
46
43
 
47
44
  Author options as React children, or pass `options`. Do not `stopPropagation` on option click. `optionhover` is a native listener.
48
45
 
@@ -35,7 +35,6 @@ Data-driven (no authored options):
35
35
  - Internal popup uses `popover="manual"` so the list works inside `fig-popup variant="popover"`.
36
36
  - List `min-width` matches the trigger; `max-width` is `min(20rem, calc(100vw - 1rem))`. Overflow: chevron buttons, not a native scrollbar.
37
37
 
38
- `fig-dropdown` (core) is a native `<select>`. `propskit-select` (lab) wraps this select.
39
38
 
40
39
  ## `fig-select-options`
41
40
 
@@ -1,11 +1,8 @@
1
1
  ---
2
2
  name: fig-lab
3
3
  description: >-
4
- Guides FigUI3 lab bundle (`fig-lab.js` / `fig-lab.css`): experimental propskit-*
5
- property controls, fig-canvas-control, fig-input-angle, fig-input-wheel, fig-reorder,
6
- and AI composer components (fig-ai-prompt, fig-ai-context, fig-chat-message,
7
- fig-attachment), including React JSX usage. Use when building labeled property
8
- panels, canvas handles, oscillators, scrubbers, reorder lists, or AI chat UIs.
4
+ Guides FigUI3 experimental Lab components: fig-canvas-control, fig-input-angle,
5
+ fig-input-wheel, fig-reorder, and AI composer components, including React JSX usage.
9
6
  APIs are unstable.
10
7
  user-invocable: false
11
8
  ---
@@ -16,8 +13,6 @@ Experimental components. May change or be removed without notice.
16
13
 
17
14
  React: [../figui3/react.md](../figui3/react.md). Per-tag JSX: [components.md](components.md). Attrs: [reference.md](reference.md).
18
15
 
19
- Raw `fig-field` rows are the `propkit` skill, not this one.
20
-
21
16
  ## Install
22
17
 
23
18
  ```js
@@ -27,53 +22,4 @@ import "@rogieking/figui3/fig-lab.css";
27
22
  import "@rogieking/figui3/fig-lab.js";
28
23
  ```
29
24
 
30
- `propskit-select` and `propskit-palette` render `fig-select`; import `fig-editor.js` + `fig-editor.css` to register and style them.
31
-
32
- `fig-editor.js` already imports `fig-lab.js`; lab **CSS** is still required for lab visuals.
33
-
34
- ## Shared propskit
35
-
36
- - Plain labeled component surfaces; joystick, origin, easing, spring, and image
37
- use a vertical label-above-control layout. Editable select is intentionally
38
- label-free with separate edit and add actions.
39
- - `label` (omitted renders `"Label"`; `label=""` hides it), `disabled`
40
- - Optional `name` reflects to the host and appears in event details only when non-empty
41
- - `default` — reset target (may differ from initial `value`)
42
- - Right-click **Reset** menu; `resetToDefault()` on a ref
43
- - `propskit-slider` also double-click resets
44
- - Forward remaining attrs to the inner control except where a component note says otherwise
45
- - `input` / `change`: `{ control, value, name? }`, dispatched from the outer host; `event.target.value === event.detail.value`. Select `optionhover` uses the same envelope
46
- - Switch values are boolean; numeric number/slider/wheel values are finite numbers or `null`; structured and serialized values exactly match the host `.value`
47
- - Shared style variables use `--propskit-{padding-block,padding-inline,background,border,color,hover-background,hover-border,hover-color,label-inline-size,input-inline-size}`; use a tag prefix such as `--propskit-select-background` for one control
48
-
49
- ## Control choice
50
-
51
- | Intent | Use |
52
- |---|---|
53
- | Labeled boolean | `propskit-switch` (`fig-switch` by default; `variant="segmented-control"` for Off/On choices) |
54
- | Labeled continuous number | `propskit-slider` |
55
- | Standalone scrubbable number | `fig-input-wheel` |
56
- | Labeled scrubbable number or time | `propskit-wheel` |
57
- | Labeled exact number | `propskit-number` |
58
- | Labeled text | `propskit-text` |
59
- | Labeled discrete list | `propskit-select` (not `fig-dropdown`) |
60
- | Editable / removable discrete list | `propskit-editable-select` |
61
- | Labeled palette choice | `propskit-palette` |
62
- | Labeled image choice/upload | `propskit-image` |
63
- | Labeled color / fill / gradient | `propskit-color` / `propskit-fill` / `propskit-gradient` |
64
- | X/Y | `propskit-position` |
65
- | Interactive X/Y plane | `propskit-joystick` |
66
- | Transform origin | `propskit-origin` |
67
- | Cubic-bezier easing | `propskit-easing` |
68
- | Spring motion | `propskit-spring` |
69
- | Spatial on a canvas | `fig-canvas-control` |
70
- | Angle | `fig-input-angle` |
71
- | Section of props | `propskit-group` or core `fig-group` |
72
- | Reorder rows | `fig-reorder` |
73
-
74
- Raw `fig-field` + core control is still valid (see `propkit` skill).
75
-
76
- ## Maintainer notes
77
-
78
- - Implementation: `fig-lab.js`, styles: `fig-lab.css`
79
- - Keep lab out of `fig.js`
25
+ Use Lab for canvas handles, angle/wheel inputs, reorder behavior, and AI composition surfaces. Keep Lab out of `fig.js`.
@@ -2,373 +2,9 @@
2
2
 
3
3
  Experimental. APIs may change. React contract: [../figui3/react.md](../figui3/react.md). Attrs: [reference.md](reference.md).
4
4
 
5
- Install `fig-lab.css` + `fig-lab.js`. `propskit-select` and `propskit-palette` use `fig-select`, so also import `fig-editor.js` + `fig-editor.css`. `fig-editor.js` already imports `fig-lab.js`; lab **CSS** is still required.
6
5
 
7
6
  Handlers below assume `onInput` / `onChange` from the React contract.
8
7
 
9
- ## Shared propskit
10
-
11
- Plain labeled component surfaces. Most are horizontal; spatial, curve, and
12
- image controls are vertical. Prefer these over hand-rolled label+control rows.
13
-
14
- Shared attrs: `label` (omitted renders `"Label"`; `label=""` hides it), optional `name`, `disabled`, `default` (reset target, may differ from initial `value`).
15
-
16
- Right-click **Reset**; `resetToDefault()` on a ref. `propskit-slider` also double-click resets. Remaining attrs forward to the inner control.
17
-
18
- `input` and `change` dispatch from the outer host with `{ control, value, name? }`; `event.target.value` matches `detail.value`. `optionhover` uses the same envelope. Numeric number/slider/wheel values are finite numbers or `null`.
19
-
20
- Shared CSS variables: `--propskit-padding-block`, `--propskit-padding-inline`, `--propskit-background`, `--propskit-border`, `--propskit-color`, `--propskit-hover-background`, `--propskit-hover-border`, `--propskit-hover-color`, `--propskit-label-inline-size`, and `--propskit-input-inline-size`. Prefix the control name for one row, for example `--propskit-select-background`.
21
-
22
- ```tsx
23
- const rowRef = useRef<HTMLElement>(null);
24
- rowRef.current?.resetToDefault();
25
- ```
26
-
27
- ## Propskit
28
-
29
- ### `propskit-switch`
30
-
31
- ```tsx
32
- <propskit-switch
33
- label="Visible"
34
- variant="switch"
35
- checked={on ? "true" : undefined}
36
- default="true"
37
- onInput={onInput}
38
- />
39
- ```
40
-
41
- - Inner: `fig-switch` by default. `variant="segmented-control"` renders the Off/On `fig-segmented-control`. The full surface toggles either control. `checked`, `default`, `.value`, and event values are boolean.
42
-
43
- ### `propskit-color`
44
-
45
- ```tsx
46
- <propskit-color
47
- label="Fill"
48
- value="#0D99FF"
49
- alpha="true"
50
- onInput={onInput}
51
- onChange={onChange}
52
- />
53
- ```
54
-
55
- - Inner: `fig-fill-picker` + `fig-swatch`. Clicking the surface opens the picker anchored to the host. Focus ring on the surface, not the swatch.
56
-
57
- ### `propskit-fill`
58
-
59
- ```tsx
60
- <propskit-fill
61
- label="Fill"
62
- value='{"type":"solid","color":"#0D99FF"}'
63
- onInput={onInput}
64
- onChange={onChange}
65
- >
66
- <div slot="mode-shader" label="Shader">
67
- Shader UI
68
- </div>
69
- </propskit-fill>
70
- ```
71
-
72
- - Same chrome as color. Value may be fill JSON or a bare video URL. Forwards `mode-*` slots.
73
-
74
- ### `propskit-gradient`
75
-
76
- ```tsx
77
- <propskit-gradient
78
- label="Gradient"
79
- value={gradientJson}
80
- edit="picker"
81
- onInput={onInput}
82
- />
83
- ```
84
-
85
- - Inner: `fig-input-gradient`. Default `edit="picker"`. `mode="handle|tip"` for inline edit. Clicking the surface opens the picker anchored to the host.
86
-
87
- ### `propskit-palette`
88
-
89
- ```tsx
90
- <propskit-palette
91
- label="Palette"
92
- options='[["#0D99FF","#14AE5C"],[{"color":"#FFCD29","alpha":0.5},"#F24822"]]'
93
- onInput={onInput}
94
- onChange={onChange}
95
- />
96
- ```
97
-
98
- - Inner: `fig-select` with fixed, disabled `fig-input-palette` previews. Requires the editor bundle.
99
- - `options` is an array of palette arrays. Public and event values are typed `{ color, alpha }[]`; omission of `value` selects the first palette.
100
- - Supports `optionhover`, typed `defaultValue`, `isDefault`, and `resetToDefault()`.
101
-
102
- ### `propskit-image`
103
-
104
- ```tsx
105
- <propskit-image
106
- label="Image"
107
- options='["/images/one.webp","/images/two.webp"]'
108
- default="/images/one.webp"
109
- onInput={onInput}
110
- onChange={onChange}
111
- />
112
- ```
113
-
114
- - Inner: a permanent ghost icon upload button plus a conditional
115
- `fig-chooser layout="grid" columns="2"`.
116
- - Every `fig-choice` contains a square, cover-fit `fig-image` with an
117
- attachment-style remove control. Delete and Backspace remove a focused choice.
118
- - `options` and `.options` are URL arrays; `.value`, `defaultValue`, and event
119
- values are the selected URL. Omitted or unmatched values select the first.
120
- - File selection appends local object URLs and selects the first new image.
121
- Removing a choice updates `options` and revokes its object URL when needed;
122
- removing the selection falls back to the first remaining image.
123
-
124
- ### `propskit-select`
125
-
126
- ```tsx
127
- <propskit-select
128
- label="Blend"
129
- value="multiply"
130
- options="Normal,Multiply,Screen"
131
- onChange={onChange}
132
- />
133
- ```
134
-
135
- Rich options (requires editor):
136
-
137
- ```tsx
138
- <propskit-select label="Space" value="oklab" onChange={onChange}>
139
- <fig-select-options slot="panel">
140
- <fig-select-option value="srgb" label="Classic">
141
- Classic
142
- </fig-select-option>
143
- </fig-select-options>
144
- </propskit-select>
145
- ```
146
-
147
- - Inner: always `fig-select`; editor registration is required. Authored `fig-select-options slot="panel"` wins. Options stay in light DOM.
148
-
149
- ### `propskit-editable-select`
150
-
151
- ```tsx
152
- <propskit-editable-select
153
- aria-label="Layer style"
154
- name="style"
155
- value="primary"
156
- options='[{"value":"primary","label":"Primary"},{"value":"secondary","label":"Secondary"}]'
157
- onInput={onInput}
158
- onChange={onChange}
159
- />
160
- ```
161
-
162
- - Label-free, always-subtle, content-width `fig-select` on the left in one
163
- full-row PropsKit surface with default-size secondary edit and add buttons on
164
- the right.
165
- - The entire host opens the select except for the edit and add actions.
166
- - The options menu aligns to and spans the full PropsKit row.
167
- - Add creates and selects an `item-{index}` value using its zero-based array
168
- index with the label `"New item"`, then enters rename mode.
169
- - Edit swaps in a default-size, full-width `fig-input-text`; checkmark, Enter,
170
- or moving focus outside the input saves, while Escape cancels.
171
- - Each option has an appended ghost trash action. Delete or Backspace removes
172
- the focused option from the keyboard.
173
- - Edit/save, add, and trash icon buttons include descriptive tooltips.
174
- - The select and trash action disable at one remaining item; edit and add stay
175
- available.
176
- - `.options` is normalized `{ value, label }[]`. Renaming changes the label
177
- while preserving its stable value.
178
- - `input`, `change`, and `optionhover` detail includes both the stable `value`
179
- and current `label`.
180
-
181
- ### `propskit-text`
182
-
183
- ```tsx
184
- <propskit-text
185
- label="Name"
186
- value={name}
187
- onInput={onInput}
188
- onChange={onChange}
189
- />
190
- ```
191
-
192
- - Inner: `fig-input-text` with `multiline` and `autoresize` enabled by default.
193
- It starts at one line and grows through four lines. Use `"false"` to disable
194
- either default. The inner control is always `type="text"`; the host `type`
195
- attribute is not forwarded. `readonly` is forwarded.
196
-
197
- ### `propskit-number`
198
-
199
- ```tsx
200
- <propskit-number
201
- label="Size"
202
- value="16"
203
- min="0"
204
- max="100"
205
- step="1"
206
- units="px"
207
- steppers="true"
208
- onInput={onInput}
209
- />
210
- ```
211
-
212
- - Inner: `fig-input-number`.
213
-
214
- ### `propskit-slider`
215
-
216
- ```tsx
217
- <propskit-slider
218
- label="Opacity"
219
- type="opacity"
220
- value="100"
221
- default="100"
222
- min="0"
223
- max="100"
224
- units="%"
225
- onInput={onInput}
226
- onChange={onChange}
227
- />
228
- ```
229
-
230
- - Inner: `fig-slider`. `type` range/hue/delta/stepper/opacity; `elastic` default true. Forward `min` / `max` / `step` / `value`.
231
-
232
- ### `propskit-wheel`
233
-
234
- ```tsx
235
- <propskit-wheel
236
- label="Duration"
237
- value="1.5"
238
- units="seconds"
239
- onInput={onInput}
240
- />
241
- ```
242
-
243
- - Inner: `fig-input-wheel` + optional `fig-input-number`. Attrs: `label`, `text`, `spin`, `elastic` (row stretch, default true), `precision`, `units`, `default`. Units stay on the wrapper; effective step is applied to the wheel. `spin="false"` updates value without moving ticks.
244
-
245
- ### `propskit-position`
246
-
247
- ```tsx
248
- <propskit-position label="Position" x="50" y="50" units="percent" onInput={onInput} />
249
- ```
250
-
251
- - Two numbers. Attrs: `x`, `y`, `units`.
252
-
253
- ### `propskit-joystick`
254
-
255
- ```tsx
256
- <propskit-joystick
257
- label="Position"
258
- value='{"x":35,"y":65}'
259
- default='{"x":50,"y":50}'
260
- axis-labels="X Y"
261
- onInput={onInput}
262
- onChange={onChange}
263
- />
264
- ```
265
-
266
- - Inner: `fig-joystick` with forced `fields="true"` and `aspect-ratio="1 / 1"`.
267
- - `.value`, `defaultValue`, and event values are typed `{ x, y }` percentage objects.
268
-
269
- ### `propskit-origin`
270
-
271
- ```tsx
272
- <propskit-origin
273
- label="Transform origin"
274
- value='{"x":50,"y":50}'
275
- default='{"x":50,"y":50}'
276
- onInput={onInput}
277
- />
278
- ```
279
-
280
- - Inner: `fig-origin-grid` with forced `fields="true"` and `aspect-ratio="1 / 1"`.
281
- - `.value`, `defaultValue`, and event values are typed `{ x, y }` percentage objects.
282
-
283
- ### `propskit-easing`
284
-
285
- ```tsx
286
- <propskit-easing
287
- label="Easing"
288
- value='{"x1":0.42,"y1":0,"x2":0.58,"y2":1}'
289
- onChange={onChange}
290
- />
291
- ```
292
-
293
- - Inner: `fig-easing-curve` constrained to bezier mode.
294
- - Typed value: `{ x1, y1, x2, y2 }`.
295
-
296
- ### `propskit-spring`
297
-
298
- ```tsx
299
- <propskit-spring
300
- label="Spring"
301
- value='{"stiffness":200,"damping":15,"mass":1}'
302
- onChange={onChange}
303
- />
304
- ```
305
-
306
- - Inner: `fig-easing-curve` constrained to spring mode.
307
- - Typed value: `{ stiffness, damping, mass }`.
308
-
309
- ### `propskit-color-point`
310
-
311
- ```tsx
312
- <propskit-color-point
313
- label="Stop"
314
- value={json}
315
- collapsible
316
- open
317
- onInput={onInput}
318
- />
319
- ```
320
-
321
- - Color + position JSON. `collapsible` / `open` default true (string booleans).
322
-
323
- ### `propskit-point-radius`
324
-
325
- ```tsx
326
- <propskit-point-radius label="Spot" value='{"x":50,"y":50,"radius":60}' onInput={onInput} />
327
- ```
328
-
329
- ### `propskit-point-radius-angle`
330
-
331
- ```tsx
332
- <propskit-point-radius-angle
333
- label="Light"
334
- value='{"x":50,"y":50,"radius":60,"angle":45}'
335
- onInput={onInput}
336
- />
337
- ```
338
-
339
- ### `propskit-point-point`
340
-
341
- ```tsx
342
- <propskit-point-point
343
- label="Line"
344
- value='{"x":10,"y":10,"x2":90,"y2":90}'
345
- onInput={onInput}
346
- />
347
- ```
348
-
349
- ### `propskit-group`
350
-
351
- ```tsx
352
- <propskit-group name="Appearance" open show-reset>
353
- <propskit-slider label="Opacity" value="100" min="0" max="100" />
354
- </propskit-group>
355
- ```
356
-
357
- - Attrs: `name`, `open`, `show-reset`. Children are React nodes.
358
-
359
- ### `propskit-oscillator`
360
-
361
- ```tsx
362
- <propskit-oscillator
363
- label="Wave"
364
- value={wavesJson}
365
- edit
366
- onInput={onInput}
367
- />
368
- ```
369
-
370
- - JSON `waves`. Attrs: `edit`, `precision`, `aspect-ratio`, `disabled`.
371
-
372
8
  ## Spatial
373
9
 
374
10
  ### `fig-canvas-control`
@@ -409,7 +45,6 @@ Rich options (requires editor):
409
45
  <fig-input-wheel value="50" min="0" max="100" step="1" onInput={onInput} />
410
46
  ```
411
47
 
412
- - 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.
413
48
  - Methods: `focus()`, `spinTo(value)`, `beginScrub()`, `updateScrub()`, `endScrub()`.
414
49
 
415
50
  ### `fig-reorder`
@@ -441,7 +76,7 @@ useEffect(() => {
441
76
  ```
442
77
 
443
78
  - `display: contents`. Reorders **direct children**. `axis` `vertical` | `horizontal`. Omit `handle` to drag whole rows; set it when rows contain sliders/handles.
444
- - Event `reorder`: `{ oldIndex, newIndex, item }`. Nested drag is ignored for sliders, handles, canvas, and most propskit spatial controls.
79
+ - Event `reorder`: `{ oldIndex, newIndex, item }`. Nested drag is ignored for sliders, handles, and canvas controls.
445
80
 
446
81
  ## AI composer
447
82