@rogieking/figui3 3.16.0 → 3.18.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/README.md CHANGED
@@ -5,851 +5,964 @@ A lightweight, zero-dependency web components library for building Figma plugin
5
5
  [![npm version](https://img.shields.io/npm/v/@rogieking/figui3.svg)](https://www.npmjs.com/package/@rogieking/figui3)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- ## Live Demo
9
-
10
- View the interactive component documentation at **[rogie.github.io/figui3](https://rogie.github.io/figui3/)**
11
-
12
- The docs page source is kept in this repo as `old.html` for reference and local testing.
8
+ **[Live Playground & Demos](https://rog.ie/figui3/)**
13
9
 
14
10
  ## Features
15
11
 
16
- - 🎨 Figma UI3 design system
17
- - 📦 Zero dependencies
18
- - 🚀 Lightweight (~50kb unminified)
19
- - 🎯 Built with Web Components
20
- - 🌗 Automatic light/dark theme support
21
- - Accessible with ARIA attributes and keyboard navigation
22
- - 🔧 Framework agnostic (works with React, Vue, Svelte, or vanilla JS)
12
+ - Figma UI3 design system
13
+ - Zero dependencies
14
+ - ~228 KB JS + ~102 KB CSS minified
15
+ - Built with Web Components
16
+ - Automatic light/dark theme support
17
+ - Accessible with ARIA attributes and keyboard navigation
18
+ - Framework agnostic (React, Vue, Svelte, or vanilla JS)
23
19
 
24
- ## Installation
20
+ ## Quick Start
25
21
 
26
- ### npm / yarn / bun / pnpm
22
+ Install:
27
23
 
28
24
  ```bash
29
25
  npm install @rogieking/figui3
30
- # or
31
- yarn add @rogieking/figui3
32
- # or
33
- bun add @rogieking/figui3
34
- # or
35
- pnpm add @rogieking/figui3
36
26
  ```
37
27
 
38
- Then import in your JavaScript/TypeScript:
28
+ Import:
39
29
 
40
30
  ```js
41
31
  import "@rogieking/figui3/fig.css";
42
32
  import "@rogieking/figui3/fig.js";
43
33
  ```
44
34
 
45
- ### CDN
35
+ Or use a CDN:
46
36
 
47
37
  ```html
48
- <link rel="stylesheet" href="https://unpkg.com/@rogieking/figui3@latest/fig.css" />
49
- <script type="module" src="https://unpkg.com/@rogieking/figui3@latest/fig.js"></script>
38
+ <link rel="stylesheet" href="https://unpkg.com/@rogieking/figui3@latest/dist/fig.css" />
39
+ <script type="module" src="https://unpkg.com/@rogieking/figui3@latest/dist/fig.js"></script>
50
40
  ```
51
41
 
52
- Or via esm.sh:
42
+ Minimal example:
53
43
 
54
44
  ```html
55
- <link rel="stylesheet" href="https://esm.sh/@rogieking/figui3@latest/fig.css" />
56
- <script type="module" src="https://esm.sh/@rogieking/figui3@latest/fig.js"></script>
57
- ```
58
-
59
- ### Development
60
-
61
- ```bash
62
- git clone https://github.com/rogie/figui3.git
63
- cd figui3
64
- bun install
65
- bun dev # Core component docs at http://localhost:3000
66
- npm run dev:playground # Interactive playground app (routes: /figui3, /propkit, /sandbox)
67
- npm run build:playground # Build playground app
68
- bun build # Build dist/fig.js
45
+ <fig-field direction="horizontal">
46
+ <label>Color</label>
47
+ <fig-input-color value="#FF5733" text="true" alpha="true"></fig-input-color>
48
+ </fig-field>
49
+ <fig-button variant="primary">Save</fig-button>
69
50
  ```
70
51
 
71
- ### Playground (`/figui3`, `/propkit`, and `/sandbox`)
72
-
73
- The playground app is the fastest way to author and validate component markup.
74
-
75
- - **`/figui3`**: component-focused examples and attribute controls for FigUI3 primitives.
76
- - **`/propkit`**: property-panel patterns composed from FigUI3 controls.
77
- - **`/sandbox`**: a styled React sample app for quick layout and interaction prototyping.
78
- - Live preview, attributes editing, and code view stay synchronized.
79
- - Attribute controls write real component markup and preserve internal-only playground metadata where needed.
80
-
81
- Open locally:
82
-
83
- ```bash
84
- npm run dev:playground
85
- # then visit http://localhost:5173/figui3, /propkit, or /sandbox
86
- ```
52
+ ---
87
53
 
88
- ## Quick Start
54
+ ## Components
89
55
 
90
- ```html
91
- <!DOCTYPE html>
92
- <html lang="en">
93
- <head>
94
- <link rel="stylesheet" href="https://unpkg.com/@rogieking/figui3@latest/fig.css" />
95
- <script src="https://unpkg.com/@rogieking/figui3@latest/fig.js"></script>
96
- </head>
97
- <body>
98
- <fig-field>
99
- <label>Color</label>
100
- <fig-input-color value="#FF5733" text="true" alpha="true"></fig-input-color>
101
- </fig-field>
102
-
103
- <fig-button variant="primary">Save</fig-button>
104
- </body>
105
- </html>
106
- ```
56
+ | Component | Tag | Description |
57
+ |---|---|---|
58
+ | [Button](#button) | `<fig-button>` | Buttons with variants, toggle, select, upload |
59
+ | [Dropdown](#dropdown) | `<fig-dropdown>` | Native select wrapper with Figma styling |
60
+ | [Combo Input](#combo-input) | `<fig-combo-input>` | Text input with dropdown suggestions |
61
+ | [Checkbox](#checkbox) | `<fig-checkbox>` | Checkbox with indeterminate state |
62
+ | [Radio](#radio) | `<fig-radio>` | Radio button |
63
+ | [Switch](#switch) | `<fig-switch>` | Toggle switch |
64
+ | [Slider](#slider) | `<fig-slider>` | Range, hue, opacity, delta, stepper |
65
+ | [Field Slider](#field-slider) | `<fig-field-slider>` | Labeled field + slider combo |
66
+ | [Text Input](#text-input) | `<fig-input-text>` | Styled text/textarea input |
67
+ | [Number Input](#number-input) | `<fig-input-number>` | Numeric input with units |
68
+ | [Input Angle](#input-angle) | `<fig-input-angle>` | Angle/rotation dial and text input |
69
+ | [Chit](#chit) | `<fig-chit>` | Color/gradient/image swatch |
70
+ | [Color Tip](#color-tip) | `<fig-color-tip>` | Compact color tip with picker |
71
+ | [Color Input](#color-input) | `<fig-input-color>` | Color picker with hex/alpha |
72
+ | [Input Palette](#input-palette) | `<fig-input-palette>` | Editable multi-color palette |
73
+ | [Gradient Input](#gradient-input) | `<fig-input-gradient>` | Gradient editor with stops |
74
+ | [Fill Input](#fill-input) | `<fig-input-fill>` | Solid, gradient, image, video fill |
75
+ | [Fill Picker](#fill-picker) | `<fig-fill-picker>` | Full fill picker dialog |
76
+ | [Tabs](#tabs) | `<fig-tabs>` / `<fig-tab>` | Tabbed navigation |
77
+ | [Segmented Control](#segmented-control) | `<fig-segmented-control>` / `<fig-segment>` | Segmented button group |
78
+ | [Chooser](#chooser) | `<fig-chooser>` / `<fig-choice>` | Selection list with drag scroll |
79
+ | [Field](#field) | `<fig-field>` | Form field wrapper with layout |
80
+ | [Joystick](#joystick) | `<fig-joystick>` | 2D position input |
81
+ | [Origin Grid](#origin-grid) | `<fig-origin-grid>` | Transform-origin grid |
82
+ | [Easing Curve](#easing-curve) | `<fig-easing-curve>` | Bezier/spring curve editor |
83
+ | [3D Rotate](#3d-rotate) | `<fig-3d-rotate>` | 3D cube rotation control |
84
+ | [Handle](#handle) | `<fig-handle>` | Draggable handle on a surface |
85
+ | [Canvas Point](#canvas-point) | `<fig-canvas-point>` | Point with optional radius & angle |
86
+ | [Dialog](#dialog) | `<fig-dialog>` | Modal/non-modal dialog |
87
+ | [Popup](#popup) | `<fig-popup>` | Anchored floating surface |
88
+ | [Toast](#toast) | `<fig-toast>` | Toast notification |
89
+ | [Tooltip](#tooltip) | `<fig-tooltip>` | Hover/click tooltip |
90
+ | [Header](#header) | `<fig-header>` | Section header |
91
+ | [Layer](#layer) | `<fig-layer>` | Collapsible layer list item |
92
+ | [Image](#image) | `<fig-image>` | Image display/upload |
93
+ | [Avatar](#avatar) | `<fig-avatar>` | Profile image or initials |
94
+ | [Spinner](#spinner) | `<fig-spinner>` | Loading spinner |
95
+ | [Shimmer](#shimmer) | `<fig-shimmer>` | Shimmer loading placeholder |
96
+ | [Skeleton](#skeleton) | `<fig-skeleton>` | Skeleton loading placeholder |
107
97
 
108
98
  ---
109
99
 
110
- ## Components
100
+ ### Form Controls
111
101
 
112
- ### Button (`<fig-button>`)
102
+ #### Button
113
103
 
114
- A versatile button component with multiple variants and types.
104
+ `<fig-button>` [demo](https://rog.ie/figui3/#button)
115
105
 
116
106
  | Attribute | Type | Default | Description |
117
- |-----------|------|---------|-------------|
118
- | `variant` | string | `"primary"` | Visual style: `"primary"`, `"secondary"`, `"ghost"`, `"link"` |
119
- | `type` | string | `"button"` | Button type: `"button"`, `"toggle"`, `"submit"`, `"select"`, `"upload"` |
120
- | `size` | string | — | Size variant: `"large"`, `"compact"` |
121
- | `selected` | boolean | `false` | Whether button is in selected state (for toggle type) |
122
- | `disabled` | boolean | `false` | Whether button is disabled |
123
- | `icon` | boolean | `false` | Icon-only button styling |
124
- | `href` | string | — | URL for link-style buttons |
125
- | `target` | string | — | Target window for links (e.g., `"_blank"`) |
107
+ |---|---|---|---|
108
+ | `variant` | string | `"primary"` | `"primary"`, `"secondary"`, `"ghost"`, `"link"` |
109
+ | `type` | string | `"button"` | `"button"`, `"toggle"`, `"submit"`, `"select"`, `"upload"` |
110
+ | `size` | string | — | `"large"`, `"compact"` |
111
+ | `selected` | boolean | `false` | Selected state (toggle type) |
112
+ | `disabled` | boolean | `false` | Disabled state |
113
+ | `icon` | boolean | `false` | Icon-only styling |
114
+ | `href` | string | — | URL for link buttons |
115
+ | `target` | string | — | Link target (e.g. `"_blank"`) |
126
116
 
127
117
  ```html
128
- <!-- Variants -->
129
118
  <fig-button>Primary</fig-button>
130
119
  <fig-button variant="secondary">Secondary</fig-button>
131
- <fig-button variant="ghost">Ghost</fig-button>
132
- <fig-button variant="link">Link</fig-button>
133
-
134
- <!-- Types -->
135
120
  <fig-button type="toggle" selected="true">Toggle</fig-button>
136
- <fig-button type="submit">Submit</fig-button>
137
-
138
- <!-- Icon button -->
139
121
  <fig-button variant="ghost" icon>
140
122
  <svg><!-- icon --></svg>
141
123
  </fig-button>
142
-
143
- <!-- Select button with dropdown -->
144
- <fig-button type="select">
145
- Select Option
146
- <fig-dropdown>
147
- <option value="1">Option 1</option>
148
- <option value="2">Option 2</option>
149
- </fig-dropdown>
150
- </fig-button>
151
-
152
- <!-- Upload button -->
153
- <fig-button type="upload">
154
- Upload File
155
- <input type="file" />
156
- </fig-button>
157
124
  ```
158
125
 
159
126
  ---
160
127
 
161
- ### Dropdown (`<fig-dropdown>`)
128
+ #### Dropdown
162
129
 
163
- A native select wrapper with Figma styling.
130
+ `<fig-dropdown>` [demo](https://rog.ie/figui3/#dropdown)
164
131
 
165
132
  | Attribute | Type | Default | Description |
166
- |-----------|------|---------|-------------|
167
- | `value` | string | — | Currently selected value |
168
- | `type` | string | `"select"` | Type: `"select"` or `"dropdown"` |
133
+ |---|---|---|---|
134
+ | `value` | string | — | Selected value |
135
+ | `type` | string | `"select"` | `"select"` or `"dropdown"` |
136
+ | `experimental` | string | — | Feature flags (e.g. `"modern"` for `appearance: base-select`) |
169
137
 
170
138
  ```html
171
139
  <fig-dropdown value="2">
172
140
  <option value="1">Option 1</option>
173
141
  <option value="2">Option 2</option>
174
- <option value="3">Option 3</option>
175
142
  </fig-dropdown>
176
143
  ```
177
144
 
178
145
  ---
179
146
 
180
- ### Tooltip (`<fig-tooltip>`)
147
+ #### Combo Input
181
148
 
182
- Displays contextual information on hover or click. The tooltip automatically repositions itself when its child element moves (e.g. during drag), using a MutationObserver to track attribute changes on the child.
149
+ `<fig-combo-input>` [demo](https://rog.ie/figui3/#combo-input)
183
150
 
184
151
  | Attribute | Type | Default | Description |
185
- |-----------|------|---------|-------------|
186
- | `text` | string | — | Tooltip text content |
187
- | `action` | string | `"hover"` | Trigger: `"hover"` or `"click"` |
188
- | `delay` | number | `500` | Delay in ms before showing |
189
- | `offset` | string | | Position offset: `"left,top,right,bottom"` |
190
- | `open` | boolean | `false` | Programmatically show/hide the tooltip |
152
+ |---|---|---|---|
153
+ | `options` | string | — | Comma-separated suggestion list |
154
+ | `placeholder` | string | | Placeholder text |
155
+ | `value` | string | | Current value |
156
+ | `disabled` | boolean | `false` | Disabled state |
191
157
 
192
158
  ```html
193
- <fig-tooltip text="This is helpful info" action="hover">
194
- <fig-button>Hover me</fig-button>
195
- </fig-tooltip>
196
-
197
- <fig-tooltip text="Click triggered" action="click" delay="0">
198
- <fig-button>Click me</fig-button>
199
- </fig-tooltip>
200
-
201
- <!-- Instant tooltip (no delay) -->
202
- <fig-tooltip text="Instant!" delay="0">
203
- <fig-button>No delay</fig-button>
204
- </fig-tooltip>
159
+ <fig-combo-input options="House, Apartment, Condo" placeholder="Residence type"></fig-combo-input>
205
160
  ```
206
161
 
207
- ### Dialog (`<fig-dialog>`)
162
+ ---
163
+
164
+ #### Checkbox
208
165
 
209
- A modal dialog component with drag support.
166
+ `<fig-checkbox>` [demo](https://rog.ie/figui3/#checkbox)
210
167
 
211
168
  | Attribute | Type | Default | Description |
212
- |-----------|------|---------|-------------|
213
- | `open` | boolean | `false` | Whether dialog is visible |
214
- | `modal` | boolean | `false` | Whether dialog is modal |
215
- | `drag` | boolean | `false` | Whether dialog is draggable |
216
- | `handle` | string | — | CSS selector for drag handle |
217
- | `position` | string | — | Position: `"center center"`, `"top left"`, etc. |
169
+ |---|---|---|---|
170
+ | `checked` | boolean | `false` | Whether checked |
171
+ | `indeterminate` | boolean | `false` | Indeterminate state |
172
+ | `disabled` | boolean | `false` | Disabled state |
173
+ | `name` | string | — | Form field name |
174
+ | `value` | string | — | Value when checked |
175
+ | `label` | string | — | Label text (alternative to slotted content) |
218
176
 
219
177
  ```html
220
- <fig-dialog id="myDialog" modal drag handle="fig-header">
221
- <fig-header>Dialog Title</fig-header>
222
- <div slot="content">
223
- <p>Dialog content goes here.</p>
224
- </div>
225
- <div slot="footer">
226
- <fig-button variant="secondary">Cancel</fig-button>
227
- <fig-button>Confirm</fig-button>
228
- </div>
229
- </fig-dialog>
230
-
231
- <script>
232
- document.getElementById('myDialog').showModal();
233
- </script>
178
+ <fig-checkbox>Accept terms</fig-checkbox>
179
+ <fig-checkbox checked>Selected</fig-checkbox>
180
+ <fig-checkbox indeterminate>Parent option</fig-checkbox>
234
181
  ```
235
182
 
236
183
  ---
237
184
 
238
- ### Popup (`<fig-popup>`)
185
+ #### Radio
239
186
 
240
- An anchored floating surface built on `<dialog>`, with collision-aware positioning and optional popover beak styling.
187
+ `<fig-radio>` [demo](https://rog.ie/figui3/#radio)
241
188
 
242
189
  | Attribute | Type | Default | Description |
243
- |-----------|------|---------|-------------|
244
- | `anchor` | string | | CSS selector for the anchor element |
245
- | `position` | string | `"top center"` | Placement (`"top"`, `"left"`, `"center right"`, etc.) |
246
- | `offset` | string | `"0 0"` | X/Y offset in px-like tokens (`"8 8"`) |
247
- | `viewport-margin` | string | `"8"` | Viewport safety margin (CSS shorthand style) |
248
- | `variant` | string | — | Use `"popover"` to render a beak |
249
- | `theme` | string | — | `"light"`, `"dark"`, or `"menu"` |
250
- | `closedby` | string | `"any"` | Dismiss behavior: `"any"`, `"closerequest"`, `"none"` |
251
- | `open` | boolean/string | `false` | Open when present and not `"false"` |
190
+ |---|---|---|---|
191
+ | `checked` | boolean | `false` | Whether selected |
192
+ | `disabled` | boolean | `false` | Disabled state |
193
+ | `name` | string | | Radio group name |
194
+ | `value` | string | | Value when selected |
252
195
 
253
196
  ```html
254
- <fig-button id="popup-anchor" onclick="const p=document.getElementById('demo-popup'); p.toggleAttribute('open');">
255
- Toggle popup
256
- </fig-button>
257
-
258
- <dialog
259
- id="demo-popup"
260
- is="fig-popup"
261
- anchor="#popup-anchor"
262
- position="center right"
263
- offset="8 8"
264
- viewport-margin="8"
265
- variant="popover"
266
- closedby="none"
267
- >
268
- <fig-header><h3>Popup</h3></fig-header>
269
- </dialog>
197
+ <fig-radio name="size" value="small">Small</fig-radio>
198
+ <fig-radio name="size" value="medium" checked>Medium</fig-radio>
199
+ <fig-radio name="size" value="large">Large</fig-radio>
270
200
  ```
271
201
 
272
202
  ---
273
203
 
274
- ### Tabs (`<fig-tabs>` / `<fig-tab>`)
204
+ #### Switch
275
205
 
276
- Tabbed navigation component.
206
+ `<fig-switch>` [demo](https://rog.ie/figui3/#switch)
277
207
 
278
208
  | Attribute | Type | Default | Description |
279
- |-----------|------|---------|-------------|
280
- | `value` | string | | Currently selected tab value |
281
- | `name` | string | | Tabs group identifier |
282
- | `disabled` | boolean | `false` | Disable all tabs |
209
+ |---|---|---|---|
210
+ | `checked` | boolean | `false` | Whether on |
211
+ | `disabled` | boolean | `false` | Disabled state |
212
+ | `name` | string | | Form field name |
213
+ | `value` | string | — | Value when on |
283
214
 
284
215
  ```html
285
- <fig-tabs value="tab1">
286
- <fig-tab value="tab1" label="General">
287
- <p>General settings content</p>
288
- </fig-tab>
289
- <fig-tab value="tab2" label="Advanced">
290
- <p>Advanced settings content</p>
291
- </fig-tab>
292
- </fig-tabs>
216
+ <fig-switch>Enable notifications</fig-switch>
217
+ <fig-switch checked>Active feature</fig-switch>
293
218
  ```
294
219
 
295
220
  ---
296
221
 
297
- ### Segmented Control (`<fig-segmented-control>` / `<fig-segment>`)
222
+ ### Inputs
223
+
224
+ #### Slider
298
225
 
299
- A segmented button group for exclusive selection.
226
+ `<fig-slider>` [demo](https://rog.ie/figui3/#slider)
300
227
 
301
228
  | Attribute | Type | Default | Description |
302
- |-----------|------|---------|-------------|
303
- | `name` | string | | Control group identifier |
304
- | `value` | string | — | Selected segment value (trimmed, case-sensitive match) |
305
- | `animated` | boolean | `false` | Enables animated segment indicator (`animated` or `animated="true"`); omit or set `animated="false"` to disable |
306
- | `sizing` | `"equal"` \| `"auto"` | `"equal"` | Segment width mode (`equal` = evenly distributed, `auto` = content width) |
307
-
308
- Selection behavior:
309
- - If `fig-segmented-control[value]` is set, it takes precedence and selects the first matching segment.
310
- - Segment match value resolves from `fig-segment[value]` when present and non-empty; otherwise it falls back to `fig-segment` text content (`textContent.trim()`).
311
- - If no segment matches the control `value`, current selection is preserved.
312
- - Animated indicator does not run on initial paint; it only animates subsequent selection changes when `animated` is enabled.
313
-
314
- Events:
315
- - Emits bubbling `input` and `change` events when user interaction changes selection.
316
- - Event `detail` contains the resolved selected value.
229
+ |---|---|---|---|
230
+ | `type` | string | `"range"` | `"range"`, `"hue"`, `"opacity"`, `"delta"`, `"stepper"` |
231
+ | `value` | number | — | Current value |
232
+ | `min` | number | `0` | Minimum |
233
+ | `max` | number | `100` | Maximum |
234
+ | `step` | number | `1` | Step increment |
235
+ | `default` | number | — | Default/reset value (shown as marker) |
236
+ | `text` | boolean | `false` | Show text input |
237
+ | `placeholder` | string | `"##"` | Text input placeholder |
238
+ | `units` | string | | Unit label (e.g. `"%"`, `"px"`) |
239
+ | `transform` | number | | Display value multiplier |
240
+ | `color` | string | — | Track color (opacity type) |
241
+ | `variant` | string | — | Visual variant (e.g. `"neue"`) |
242
+ | `precision` | number | | Decimal places for output |
243
+ | `disabled` | boolean | `false` | Disabled state |
317
244
 
318
- ```html
319
- <fig-segmented-control>
320
- <fig-segment value="left" selected="true">Left</fig-segment>
321
- <fig-segment value="center">Center</fig-segment>
322
- <fig-segment value="right">Right</fig-segment>
323
- </fig-segmented-control>
324
- ```
245
+ **Events:** `input` (continuous), `change` (on release).
325
246
 
326
247
  ```html
327
- <!-- Text fallback: no value attrs, value resolves from text -->
328
- <fig-segmented-control value="Center">
329
- <fig-segment>Left</fig-segment>
330
- <fig-segment>Center</fig-segment>
331
- <fig-segment>Right</fig-segment>
332
- </fig-segmented-control>
248
+ <fig-slider min="0" max="100" value="50" text="true" units="%"></fig-slider>
249
+ <fig-slider type="hue" value="180"></fig-slider>
250
+ <fig-slider type="opacity" value="75" color="#FF5733" text="true" units="%"></fig-slider>
333
251
  ```
334
252
 
335
253
  ---
336
254
 
337
- ### Slider (`<fig-slider>`)
255
+ #### Field Slider
338
256
 
339
- A range slider with multiple types and optional text input.
257
+ `<fig-field-slider>`
340
258
 
341
- | Attribute | Type | Default | Description |
342
- |-----------|------|---------|-------------|
343
- | `type` | string | `"range"` | Type: `"range"`, `"hue"`, `"opacity"`, `"delta"`, `"stepper"` |
344
- | `value` | number | — | Current value; missing/invalid values fall back to `min` (or `default` for `type="delta"`, then `0`) |
345
- | `min` | number | `0` | Minimum value |
346
- | `max` | number | `100` | Maximum value |
347
- | `step` | number | `1` | Step increment |
348
- | `default` | number | — | Default/reset value (shown as a marker on the track) |
349
- | `text` | boolean | `false` | Show text input |
350
- | `placeholder` | string | `"##"` | Placeholder for text input mode (`text="true"`) |
351
- | `units` | string | — | Unit label (e.g., `"%"`, `"px"`) |
352
- | `transform` | number | — | Multiplier for display value |
353
- | `color` | string | — | Track color (for opacity type) |
354
- | `disabled` | boolean | `false` | Disable slider |
355
-
356
- ```html
357
- <!-- Basic slider -->
358
- <fig-slider min="0" max="100" value="50"></fig-slider>
359
-
360
- <!-- With text input and units -->
361
- <fig-slider min="0" max="100" value="75" text="true" units="%"></fig-slider>
259
+ Wraps a `<fig-field>` and `<fig-slider>` into a single labeled control. All slider attributes (except `label`, `direction`) are forwarded to the inner slider.
362
260
 
363
- <!-- Hue slider -->
364
- <fig-slider type="hue" value="180"></fig-slider>
261
+ | Attribute | Type | Default | Description |
262
+ |---|---|---|---|
263
+ | `label` | string | — | Field label text |
264
+ | `direction` | string | `"column"` | Layout direction |
265
+ | *slider attrs* | — | — | All `<fig-slider>` attributes are forwarded |
365
266
 
366
- <!-- Opacity slider with color -->
367
- <fig-slider type="opacity" value="75" color="#FF5733" text="true" units="%"></fig-slider>
267
+ **Events:** `input`, `change` forwarded from the inner slider.
368
268
 
369
- <!-- Stepper with snap points -->
370
- <fig-slider type="stepper" value="50" step="25">
371
- <datalist>
372
- <option value="0"></option>
373
- <option value="25"></option>
374
- <option value="50"></option>
375
- <option value="75"></option>
376
- <option value="100"></option>
377
- </datalist>
378
- </fig-slider>
379
-
380
- <!-- Delta slider -->
381
- <fig-slider type="delta" value="0" min="-5" max="5" step="0.25">
382
- <datalist>
383
- <option value="0"></option>
384
- </datalist>
385
- </fig-slider>
269
+ ```html
270
+ <fig-field-slider label="Opacity" min="0" max="100" value="75" text="true" units="%"></fig-field-slider>
386
271
  ```
387
272
 
388
273
  ---
389
274
 
390
- ### Text Input (`<fig-input-text>`)
275
+ #### Text Input
391
276
 
392
- A styled text input with optional slots.
277
+ `<fig-input-text>` [demo](https://rog.ie/figui3/#text-input)
393
278
 
394
279
  | Attribute | Type | Default | Description |
395
- |-----------|------|---------|-------------|
280
+ |---|---|---|---|
396
281
  | `value` | string | — | Input value |
397
282
  | `placeholder` | string | — | Placeholder text |
398
- | `type` | string | `"text"` | Input type: `"text"` or `"number"` |
399
- | `disabled` | boolean | `false` | Disable input |
283
+ | `type` | string | `"text"` | `"text"` or `"number"` |
284
+ | `disabled` | boolean | `false` | Disabled state |
400
285
  | `multiline` | boolean | `false` | Use textarea |
401
- | `min` | number | — | Min value (number type) |
402
- | `max` | number | — | Max value (number type) |
286
+ | `min` | number | — | Min (number type) |
287
+ | `max` | number | — | Max (number type) |
403
288
  | `step` | number | — | Step (number type) |
404
289
  | `transform` | number | — | Display multiplier |
405
290
 
406
291
  ```html
407
- <!-- Basic text input -->
408
292
  <fig-input-text value="Hello" placeholder="Enter text..."></fig-input-text>
409
-
410
- <!-- With prepend/append slots -->
411
- <fig-input-text>
412
- <span slot="prepend">$</span>
413
- <span slot="append">.00</span>
414
- </fig-input-text>
415
-
416
- <!-- Multiline -->
417
293
  <fig-input-text multiline placeholder="Enter description..."></fig-input-text>
418
294
  ```
419
295
 
420
296
  ---
421
297
 
422
- ### Number Input (`<fig-input-number>`)
298
+ #### Number Input
423
299
 
424
- A numeric input with units support.
300
+ `<fig-input-number>` [demo](https://rog.ie/figui3/#number-input)
425
301
 
426
302
  | Attribute | Type | Default | Description |
427
- |-----------|------|---------|-------------|
303
+ |---|---|---|---|
428
304
  | `value` | string | — | Numeric value |
429
305
  | `placeholder` | string | — | Placeholder text |
430
- | `min` | number | — | Minimum value |
431
- | `max` | number | — | Maximum value |
306
+ | `min` | number | — | Minimum |
307
+ | `max` | number | — | Maximum |
432
308
  | `step` | number | — | Step increment |
433
- | `units` | string | — | Unit string (e.g., `"px"`, `"%"`) |
309
+ | `units` | string | — | Unit string (e.g. `"px"`, `"%"`) |
434
310
  | `unit-position` | string | `"suffix"` | `"suffix"` or `"prefix"` |
435
311
  | `transform` | number | — | Display multiplier |
436
- | `steppers` | boolean | `false` | Show native spin buttons (up/down arrows) |
437
- | `disabled` | boolean | `false` | Disable input |
312
+ | `steppers` | boolean | `false` | Show spin buttons |
313
+ | `disabled` | boolean | `false` | Disabled state |
438
314
 
439
315
  ```html
440
316
  <fig-input-number value="100" units="px"></fig-input-number>
441
317
  <fig-input-number value="50" units="%" min="0" max="100"></fig-input-number>
442
- <fig-input-number value="45" units="°" step="15"></fig-input-number>
318
+ ```
443
319
 
444
- <!-- With native stepper arrows -->
445
- <fig-input-number value="10" steppers="true" step="1"></fig-input-number>
320
+ ---
321
+
322
+ #### Input Angle
323
+
324
+ `<fig-input-angle>` — [demo](https://rog.ie/figui3/#angle-input)
325
+
326
+ Angle/rotation input with circular dial, optional text input, multi-unit support, and unbounded winding past 360deg. Accepts unit suffixes in text input (`90deg`, `3.14rad`, `0.5turn`).
327
+
328
+ | Attribute | Type | Default | Description |
329
+ |---|---|---|---|
330
+ | `value` | number | `0` | Angle value |
331
+ | `precision` | number | `1` | Decimal places |
332
+ | `text` | boolean | `false` | Show text input |
333
+ | `dial` | boolean | `true` | Show circular dial |
334
+ | `min` | number | — | Minimum (omit for unbounded) |
335
+ | `max` | number | — | Maximum (omit for unbounded) |
336
+ | `units` | string | `"°"` | `"°"` / `"deg"`, `"rad"`, `"turn"` |
337
+ | `rotations` | boolean | `false` | Show rotation counter |
338
+
339
+ **Events:** `input` (continuous), `change` (on release).
340
+
341
+ ```html
342
+ <fig-input-angle value="90" text="true"></fig-input-angle>
343
+ <fig-input-angle text="true" units="rad" value="3.14159"></fig-input-angle>
344
+ <fig-input-angle text="true" rotations value="1080"></fig-input-angle>
345
+ ```
346
+
347
+ ---
348
+
349
+ ### Color & Fill
350
+
351
+ #### Chit
352
+
353
+ `<fig-chit>` — [demo](https://rog.ie/figui3/#chit)
354
+
355
+ A color/gradient/image swatch element with checkerboard background for alpha.
356
+
357
+ | Attribute | Type | Default | Description |
358
+ |---|---|---|---|
359
+ | `background` | string | — | CSS background value |
360
+ | `size` | string | `"small"` | `"small"` or `"large"` |
361
+ | `selected` | boolean | `false` | Selection ring |
362
+ | `disabled` | boolean | `false` | Disabled state |
363
+ | `alpha` | number | — | Opacity (0-1) |
364
+
365
+ ```html
366
+ <fig-chit background="#FF5733"></fig-chit>
367
+ <fig-chit background="linear-gradient(90deg, #FF0000, #0000FF)" size="large"></fig-chit>
446
368
  ```
447
369
 
448
370
  ---
449
371
 
450
- ### Color Input (`<fig-input-color>`)
372
+ #### Color Tip
451
373
 
452
- A color picker with hex/alpha support.
374
+ `<fig-color-tip>` [demo](https://rog.ie/figui3/#color-tip)
375
+
376
+ A compact solid-color swatch that wraps `<fig-fill-picker>`. Used inside gradient handles and other controls.
453
377
 
454
378
  | Attribute | Type | Default | Description |
455
- |-----------|------|---------|-------------|
456
- | `value` | string | — | Hex color value (e.g., `"#FF5733"` or `"#FF573380"`) |
379
+ |---|---|---|---|
380
+ | `value` | string | — | Color string (hex/rgb/hsl/named) |
381
+ | `selected` | boolean | `false` | Selected state |
382
+ | `disabled` | boolean | `false` | Disabled state |
383
+ | `alpha` | boolean | `false` | Show alpha controls |
384
+ | `control` | string | — | `"add"` or `"remove"` for icon-only mode |
385
+
386
+ **Events:**
387
+
388
+ | Event | Detail |
389
+ |---|---|
390
+ | `input` | `{ color, opacity? }` — while editing |
391
+ | `change` | `{ color, opacity? }` — on commit |
392
+ | `add` | — (when `control="add"` is clicked) |
393
+ | `remove` | — (when `control="remove"` is clicked) |
394
+
395
+ ```html
396
+ <fig-color-tip value="#FF5733"></fig-color-tip>
397
+ <fig-color-tip value="#00AAFF" alpha="true"></fig-color-tip>
398
+ ```
399
+
400
+ ---
401
+
402
+ #### Color Input
403
+
404
+ `<fig-input-color>` — [demo](https://rog.ie/figui3/#color-input)
405
+
406
+ | Attribute | Type | Default | Description |
407
+ |---|---|---|---|
408
+ | `value` | string | — | Hex color (e.g. `"#FF5733"` or `"#FF573380"`) |
457
409
  | `text` | boolean | `false` | Show hex text input |
458
410
  | `alpha` | boolean | `false` | Show alpha slider |
459
- | `picker` | string | `"native"` | Picker type: `"native"`, `"figma"`, `"false"` |
460
- | `mode` | string | — | Color mode (e.g., `"hex"`, `"rgb"`, `"hsl"`) |
461
- | `disabled` | boolean | `false` | Disable input |
411
+ | `picker` | string | `"native"` | `"native"`, `"figma"`, `"false"` |
412
+ | `mode` | string | — | Color mode (`"hex"`, `"rgb"`, `"hsl"`) |
413
+ | `experimental` | string | | Feature flags |
414
+ | `disabled` | boolean | `false` | Disabled state |
462
415
 
463
- ```html
464
- <!-- Basic color picker -->
465
- <fig-input-color value="#FF5733"></fig-input-color>
416
+ **Events:**
466
417
 
467
- <!-- With text and alpha -->
468
- <fig-input-color value="#FF5733" text="true" alpha="true"></fig-input-color>
418
+ | Event | Detail |
419
+ |---|---|
420
+ | `input` | `{ color, alpha, hsv: { h, s, v, a } }` |
421
+ | `change` | `{ color, alpha, hsv: { h, s, v, a } }` |
469
422
 
470
- <!-- With Figma-style picker dialog -->
423
+ ```html
424
+ <fig-input-color value="#FF5733" text="true" alpha="true"></fig-input-color>
471
425
  <fig-input-color value="#FF5733" text="true" alpha="true" picker="figma"></fig-input-color>
472
426
  ```
473
427
 
474
428
  ---
475
429
 
476
- ### Fill Input (`<fig-input-fill>`)
430
+ #### Input Palette
477
431
 
478
- A comprehensive fill input supporting colors, gradients, images, and video.
432
+ `<fig-input-palette>`
433
+
434
+ An editable palette of solid colors, each rendered as a `<fig-input-color>` swatch with add/remove support.
479
435
 
480
436
  | Attribute | Type | Default | Description |
481
- |-----------|------|---------|-------------|
482
- | `value` | string | — | JSON fill data |
483
- | `disabled` | boolean | `false` | Disable input |
437
+ |---|---|---|---|
438
+ | `value` | string | — | JSON array of hex strings or `{color, alpha}` objects |
439
+ | `disabled` | boolean | `false` | Disabled state |
440
+ | `min` | number | `2` | Minimum number of colors |
441
+ | `max` | number | `8` | Maximum (add button hidden at max) |
442
+ | `expanded` | boolean | `false` | Show text + alpha inputs per color |
443
+ | `add` | boolean | `true` | Show add-color button (`add="false"` hides it) |
484
444
 
485
- ```html
486
- <!-- Solid color -->
487
- <fig-input-fill value='{"type":"solid","color":"#FF5733","opacity":100}'></fig-input-fill>
445
+ **Events:**
488
446
 
489
- <!-- Gradient -->
490
- <fig-input-fill value='{"type":"gradient","gradient":{"type":"linear","angle":90,"interpolationSpace":"oklab","stops":[{"position":0,"color":"#FF0000"},{"position":100,"color":"#0000FF"}]}}'></fig-input-fill>
447
+ | Event | Detail |
448
+ |---|---|
449
+ | `input` | Full color array (during editing) |
450
+ | `change` | Full color array (on commit or add) |
491
451
 
492
- <!-- Image -->
493
- <fig-input-fill value='{"type":"image","image":{"url":"path/to/image.jpg","scaleMode":"fill"}}'></fig-input-fill>
452
+ ```html
453
+ <fig-input-palette value='["#FF0000","#00FF00","#0000FF"]'></fig-input-palette>
454
+ <fig-input-palette value='[{"color":"#FF0000","alpha":0.5},{"color":"#00FF00","alpha":1}]' expanded="true"></fig-input-palette>
494
455
  ```
495
456
 
496
457
  ---
497
458
 
498
- ### Gradient Input (`<fig-input-gradient>`)
459
+ #### Gradient Input
460
+
461
+ `<fig-input-gradient>`
499
462
 
500
- A gradient-only fill input that opens the `fig-fill-picker` locked to gradient mode.
463
+ A gradient editor with draggable stops. Opens `<fig-fill-picker>` locked to gradient mode.
501
464
 
502
465
  | Attribute | Type | Default | Description |
503
- |-----------|------|---------|-------------|
504
- | `value` | string | — | JSON gradient fill data (`{ "type": "gradient", "gradient": ... }`) |
505
- | `disabled` | boolean | `false` | Disable input |
506
- | `experimental` | string | — | Optional picker feature flags (e.g. `"modern"`) |
507
- | `picker-*` | string | — | Optional passthrough picker attributes (except `picker-anchor`) |
508
- | `picker-anchor` | string | `"self"` | Anchor target selector or `"self"` |
466
+ |---|---|---|---|
467
+ | `value` | string | — | JSON gradient fill data |
468
+ | `disabled` | boolean | `false` | Disabled state |
469
+ | `experimental` | string | — | Picker feature flags |
470
+ | `picker-*` | string | — | Passthrough picker attributes |
471
+ | `picker-anchor` | string | `"self"` | Anchor selector or `"self"` |
472
+
473
+ Supported interpolation spaces: `srgb`, `srgb-linear`, `display-p3`, `oklab`, `oklch` (with `hueInterpolation`: `shorter`, `longer`, `increasing`, `decreasing`).
474
+
475
+ **Events:**
476
+
477
+ | Event | Detail |
478
+ |---|---|
479
+ | `input` | `{ type, gradient, css }` |
480
+ | `change` | `{ type, gradient, css }` |
509
481
 
510
482
  ```html
511
483
  <fig-input-gradient
512
- value='{"type":"gradient","gradient":{"type":"linear","angle":90,"interpolationSpace":"oklch","hueInterpolation":"shorter","stops":[{"position":0,"color":"#FF0000","opacity":100},{"position":100,"color":"#0000FF","opacity":100}]}}'
484
+ value='{"type":"gradient","gradient":{"type":"linear","angle":90,"interpolationSpace":"oklab","stops":[{"position":0,"color":"#FF0000","opacity":100},{"position":100,"color":"#0000FF","opacity":100}]}}'
513
485
  ></fig-input-gradient>
514
486
  ```
515
487
 
516
- Supported gradient interpolation spaces:
517
- - `srgb`
518
- - `srgb-linear`
519
- - `display-p3`
520
- - `oklab`
521
- - `oklch` (supports `hueInterpolation`: `shorter`, `longer`, `increasing`, `decreasing`)
488
+ ---
489
+
490
+ #### Fill Input
491
+
492
+ `<fig-input-fill>` — [demo](https://rog.ie/figui3/#fill-input)
493
+
494
+ A comprehensive fill input supporting solid, gradient, image, and video fills.
522
495
 
523
- Note: stop colors are currently authored/stored as hex (sRGB-origin). `display-p3` interpolation syntax is supported, but fully wide-gamut editing requires P3 stop-color storage.
496
+ | Attribute | Type | Default | Description |
497
+ |---|---|---|---|
498
+ | `value` | string | — | JSON fill data |
499
+ | `disabled` | boolean | `false` | Disabled state |
500
+ | `mode` | string | — | Lock to a fill mode |
501
+ | `experimental` | string | — | Feature flags |
502
+ | `alpha` | boolean | `true` | Show alpha controls |
503
+
504
+ **Events:**
505
+
506
+ | Event | Detail |
507
+ |---|---|
508
+ | `input` | `{ type, color?, gradient?, image?, video?, css }` |
509
+ | `change` | `{ type, color?, gradient?, image?, video?, css }` |
510
+
511
+ ```html
512
+ <fig-input-fill value='{"type":"solid","color":"#FF5733","opacity":100}'></fig-input-fill>
513
+ ```
524
514
 
525
515
  ---
526
516
 
527
- ### Fill Picker (`<fig-fill-picker>`)
517
+ #### Fill Picker
528
518
 
529
- A comprehensive fill picker dialog supporting solid colors, gradients, images, video, and webcam.
519
+ `<fig-fill-picker>` [demo](https://rog.ie/figui3/#fill-picker)
520
+
521
+ Full fill picker dialog supporting solid, gradient, image, video, and webcam. Wraps a trigger element (e.g. `<fig-chit>`).
530
522
 
531
523
  | Attribute | Type | Default | Description |
532
- |-----------|------|---------|-------------|
524
+ |---|---|---|---|
533
525
  | `value` | string | — | JSON fill value |
534
- | `disabled` | boolean | `false` | Disable picker |
526
+ | `disabled` | boolean | `false` | Disabled state |
535
527
  | `alpha` | boolean | `true` | Show alpha controls |
536
528
  | `mode` | string | — | Lock to mode: `"solid"`, `"gradient"`, `"image"`, `"video"`, `"webcam"` |
529
+ | `experimental` | string | — | Feature flags |
530
+
531
+ **Events:**
532
+
533
+ | Event | Detail |
534
+ |---|---|
535
+ | `input` | `{ type, gradient?, color?, css }` |
536
+ | `change` | `{ type, gradient?, color?, css }` |
537
537
 
538
538
  ```html
539
- <!-- Wraps a trigger element -->
540
539
  <fig-fill-picker value='{"type":"solid","color":"#FF5733"}'>
541
540
  <fig-chit></fig-chit>
542
541
  </fig-fill-picker>
543
-
544
- <!-- Lock to solid color mode -->
545
- <fig-fill-picker mode="solid" alpha="true">
546
- <fig-button>Pick Color</fig-button>
547
- </fig-fill-picker>
548
542
  ```
549
543
 
550
544
  ---
551
545
 
552
- ### Chit (`<fig-chit>`)
546
+ ### Selection
547
+
548
+ #### Tabs
553
549
 
554
- A color/gradient/image swatch element.
550
+ `<fig-tabs>` / `<fig-tab>` — [demo](https://rog.ie/figui3/#tabs)
555
551
 
556
552
  | Attribute | Type | Default | Description |
557
- |-----------|------|---------|-------------|
558
- | `background` | string | — | CSS background value |
559
- | `size` | string | `"small"` | Size: `"small"` or `"large"` |
560
- | `selected` | boolean | `false` | Show selection ring |
561
- | `disabled` | boolean | `false` | Disable interaction |
562
- | `alpha` | number | — | Opacity (0-1) |
553
+ |---|---|---|---|
554
+ | `value` | string | — | Selected tab value |
555
+ | `name` | string | | Tabs group identifier |
556
+ | `disabled` | boolean | `false` | Disable all tabs |
557
+
558
+ **Events:** `input`, `change` with selected tab value.
563
559
 
564
560
  ```html
565
- <fig-chit background="#FF5733"></fig-chit>
566
- <fig-chit background="linear-gradient(90deg, #FF0000, #0000FF)"></fig-chit>
567
- <fig-chit background="url(image.jpg)" size="large"></fig-chit>
568
- <fig-chit background="#FF5733" alpha="0.5"></fig-chit>
561
+ <fig-tabs value="tab1">
562
+ <fig-tab value="tab1">General</fig-tab>
563
+ <fig-tab value="tab2">Advanced</fig-tab>
564
+ </fig-tabs>
569
565
  ```
570
566
 
571
567
  ---
572
568
 
573
- ### Checkbox (`<fig-checkbox>`)
569
+ #### Segmented Control
574
570
 
575
- A checkbox input with indeterminate state support.
571
+ `<fig-segmented-control>` / `<fig-segment>` [demo](https://rog.ie/figui3/#segmented-control)
576
572
 
577
573
  | Attribute | Type | Default | Description |
578
- |-----------|------|---------|-------------|
579
- | `checked` | boolean | `false` | Whether checked |
580
- | `indeterminate` | boolean | `false` | Indeterminate state |
581
- | `disabled` | boolean | `false` | Disable checkbox |
582
- | `name` | string | | Form field name |
583
- | `value` | string | — | Value when checked |
584
- | `label` | string | | Programmatic label text (alternative to slotted content) |
574
+ |---|---|---|---|
575
+ | `name` | string | | Group identifier |
576
+ | `value` | string | | Selected segment value |
577
+ | `animated` | boolean | `false` | Animate indicator transitions |
578
+ | `sizing` | string | `"equal"` | `"equal"` or `"auto"` width mode |
579
+
580
+ **Events:** `input`, `change`detail contains the selected value.
585
581
 
586
582
  ```html
587
- <fig-checkbox>Accept terms</fig-checkbox>
588
- <fig-checkbox checked>Selected option</fig-checkbox>
589
- <fig-checkbox indeterminate>Parent option</fig-checkbox>
590
- <fig-checkbox label="Via attribute"></fig-checkbox>
583
+ <fig-segmented-control>
584
+ <fig-segment value="left" selected="true">Left</fig-segment>
585
+ <fig-segment value="center">Center</fig-segment>
586
+ <fig-segment value="right">Right</fig-segment>
587
+ </fig-segmented-control>
591
588
  ```
592
589
 
593
590
  ---
594
591
 
595
- ### Radio (`<fig-radio>`)
592
+ #### Chooser
593
+
594
+ `<fig-chooser>` / `<fig-choice>`
595
+
596
+ A selection list controller. `<fig-choice>` elements are selectable options within a `<fig-chooser>`.
596
597
 
597
- A radio button input.
598
+ **fig-chooser attributes:**
598
599
 
599
600
  | Attribute | Type | Default | Description |
600
- |-----------|------|---------|-------------|
601
- | `checked` | boolean | `false` | Whether selected |
602
- | `disabled` | boolean | `false` | Disable radio |
603
- | `name` | string | | Radio group name |
604
- | `value` | string | | Value when selected |
601
+ |---|---|---|---|
602
+ | `value` | string | | Selected choice value |
603
+ | `choice-element` | string | `"fig-choice"` | CSS selector for child choices |
604
+ | `layout` | string | `"vertical"` | `"vertical"`, `"horizontal"`, `"grid"` |
605
+ | `disabled` | boolean | `false` | Disabled state |
606
+ | `drag` | boolean | `false` | Enable drag-to-scroll |
607
+ | `overflow` | string | — | Overflow behavior |
608
+ | `loop` | boolean | `false` | Loop keyboard navigation |
609
+ | `padding` | boolean | `true` | Internal padding (`padding="false"` removes it) |
610
+
611
+ **fig-choice attributes:**
612
+
613
+ | Attribute | Type | Default | Description |
614
+ |---|---|---|---|
615
+ | `value` | string | — | Choice identifier |
616
+ | `selected` | boolean | `false` | Selected state |
617
+ | `disabled` | boolean | `false` | Disabled state |
618
+
619
+ **Events (on fig-chooser):** `input`, `change` — detail is the selected value string.
605
620
 
606
621
  ```html
607
- <fig-radio name="size" value="small">Small</fig-radio>
608
- <fig-radio name="size" value="medium" checked>Medium</fig-radio>
609
- <fig-radio name="size" value="large">Large</fig-radio>
622
+ <fig-chooser value="opt1">
623
+ <fig-choice value="opt1">Option 1</fig-choice>
624
+ <fig-choice value="opt2">Option 2</fig-choice>
625
+ <fig-choice value="opt3">Option 3</fig-choice>
626
+ </fig-chooser>
610
627
  ```
611
628
 
612
629
  ---
613
630
 
614
- ### Switch (`<fig-switch>`)
631
+ ### Spatial Controls
615
632
 
616
- A toggle switch component.
633
+ #### Joystick
634
+
635
+ `<fig-joystick>`
636
+
637
+ A 2D position input control with optional X/Y fields.
617
638
 
618
639
  | Attribute | Type | Default | Description |
619
- |-----------|------|---------|-------------|
620
- | `checked` | boolean | `false` | Whether on |
621
- | `disabled` | boolean | `false` | Disable switch |
622
- | `name` | string | — | Form field name |
623
- | `value` | string | | Value when on |
640
+ |---|---|---|---|
641
+ | `value` | string | `"50% 50%"` | Position as percentages |
642
+ | `precision` | number | | Decimal places |
643
+ | `transform` | number | — | Output scaling |
644
+ | `fields` | boolean | `false` | Show X/Y inputs |
645
+ | `coordinates` | string | `"screen"` | `"screen"` (0,0 top-left) or `"math"` (0,0 bottom-left) |
646
+ | `aspect-ratio` | string | `"1 / 1"` | Plane ratio |
647
+
648
+ **Events:**
649
+
650
+ | Event | Detail |
651
+ |---|---|
652
+ | `input` | `{ x, y, value }` — while dragging |
653
+ | `change` | `{ x, y, value }` — on release |
624
654
 
625
655
  ```html
626
- <fig-switch>Enable notifications</fig-switch>
627
- <fig-switch checked>Active feature</fig-switch>
656
+ <fig-joystick value="50% 50%" fields="true" precision="2"></fig-joystick>
628
657
  ```
629
658
 
630
659
  ---
631
660
 
632
- ### Field (`<fig-field>`)
661
+ #### Origin Grid
633
662
 
634
- A form field wrapper with flexible layout. Automatically links `<label>` elements to the first `fig-*` child for accessibility.
663
+ `<fig-origin-grid>`
664
+
665
+ A transform-origin grid control with a draggable handle and optional X/Y percentage fields.
635
666
 
636
667
  | Attribute | Type | Default | Description |
637
- |-----------|------|---------|-------------|
638
- | `direction` | string | `"column"` | Layout: `"column"`, `"row"`, `"horizontal"` |
639
- | `columns` | string | | Optional horizontal split preset: `"thirds"` or `"half"` |
640
- | `label` | string | — | Programmatically set the label text |
668
+ |---|---|---|---|
669
+ | `value` | string | `"50% 50%"` | CSS transform-origin pair |
670
+ | `precision` | number | `0` | Decimal places |
671
+ | `aspect-ratio` | string | — | Grid aspect ratio |
672
+ | `drag` | boolean | `true` | Enable handle dragging |
673
+ | `fields` | boolean | `false` | Show X/Y fields |
641
674
 
642
- ```html
643
- <!-- Vertical (default) -->
644
- <fig-field>
645
- <label>Username</label>
646
- <fig-input-text></fig-input-text>
647
- </fig-field>
675
+ **Events:**
648
676
 
649
- <!-- Horizontal -->
650
- <fig-field direction="horizontal">
651
- <label>Volume</label>
652
- <fig-slider min="0" max="100" value="50"></fig-slider>
653
- </fig-field>
677
+ | Event | Detail |
678
+ |---|---|
679
+ | `input` | `{ value, x, y }` — while dragging |
680
+ | `change` | `{ value, x, y }` — on release |
654
681
 
655
- <!-- Horizontal with 1/3 + 2/3 split -->
656
- <fig-field direction="horizontal" columns="thirds">
657
- <label>Opacity</label>
658
- <fig-slider value="50"></fig-slider>
659
- </fig-field>
682
+ ```html
683
+ <fig-origin-grid value="50% 50%" drag="true" fields="true"></fig-origin-grid>
660
684
  ```
661
685
 
662
686
  ---
663
687
 
664
- ### Combo Input (`<fig-combo-input>`)
688
+ #### Easing Curve
665
689
 
666
- A text input with dropdown suggestions.
690
+ `<fig-easing-curve>`
691
+
692
+ An interactive bezier or spring easing curve editor with draggable control points and an optional preset dropdown.
667
693
 
668
694
  | Attribute | Type | Default | Description |
669
- |-----------|------|---------|-------------|
670
- | `options` | string | — | Comma-separated options |
671
- | `placeholder` | string | | Placeholder text |
672
- | `value` | string | — | Current value |
673
- | `disabled` | boolean | `false` | Disable input |
695
+ |---|---|---|---|
696
+ | `value` | string | — | Bezier: `"0.42, 0, 0.58, 1"` or Spring: `"spring(200, 15, 1)"` |
697
+ | `precision` | number | `2` | Decimal places |
698
+ | `aspect-ratio` | string | — | Editor aspect ratio |
699
+ | `dropdown` | boolean | `false` | Show preset dropdown |
700
+
701
+ **Static:** `FigEasingCurve.PRESETS` — built-in preset array. `FigEasingCurve.curveIcon(value)` — SVG icon helper.
702
+
703
+ **Events:**
704
+
705
+ | Event | Detail |
706
+ |---|---|
707
+ | `input` | `{ mode, value, cssValue, preset }` — while dragging |
708
+ | `change` | `{ mode, value, cssValue, preset }` — on release |
674
709
 
675
710
  ```html
676
- <fig-combo-input
677
- options="House, Apartment, Condo, Other"
678
- placeholder="Type of residence">
679
- </fig-combo-input>
711
+ <fig-easing-curve value="0.42, 0, 0.58, 1" dropdown="true"></fig-easing-curve>
712
+ <fig-easing-curve value="spring(200, 15, 1)"></fig-easing-curve>
680
713
  ```
681
714
 
682
715
  ---
683
716
 
684
- ### Avatar (`<fig-avatar>`)
717
+ #### 3D Rotate
718
+
719
+ `<fig-3d-rotate>`
685
720
 
686
- Displays a user's profile image or initials.
721
+ An interactive 3D cube for setting rotation values. Supports drag interaction and optional X/Y/Z number fields.
687
722
 
688
723
  | Attribute | Type | Default | Description |
689
- |-----------|------|---------|-------------|
690
- | `src` | string | — | Image URL |
691
- | `name` | string | | Name for initials fallback |
692
- | `size` | string | — | Size: `"large"` |
724
+ |---|---|---|---|
725
+ | `value` | string | — | CSS transform, e.g. `"rotateX(20deg) rotateY(-35deg) rotateZ(0deg)"` |
726
+ | `precision` | number | `1` | Decimal places |
727
+ | `aspect-ratio` | string | — | Cube container ratio |
728
+ | `fields` | boolean | `false` | Show X/Y/Z number inputs |
729
+ | `perspective` | string | — | CSS perspective value |
730
+ | `perspective-origin` | string | — | CSS perspective-origin |
731
+ | `transform-origin` | string | — | CSS transform-origin |
732
+ | `selected` | string | — | Highlighted face |
733
+ | `drag` | boolean | `true` | Enable drag rotation |
734
+
735
+ **Events:**
736
+
737
+ | Event | Detail |
738
+ |---|---|
739
+ | `input` | `{ value, rotateX, rotateY, rotateZ }` — while dragging |
740
+ | `change` | `{ value, rotateX, rotateY, rotateZ }` — on release |
693
741
 
694
742
  ```html
695
- <fig-avatar src="https://example.com/photo.jpg" name="John Doe"></fig-avatar>
696
- <fig-avatar name="Jane Smith" size="large"></fig-avatar>
743
+ <fig-3d-rotate value="rotateX(20deg) rotateY(-35deg) rotateZ(0deg)" fields="true"></fig-3d-rotate>
697
744
  ```
698
745
 
699
746
  ---
700
747
 
701
- ### Image (`<fig-image>`)
748
+ #### Handle
749
+
750
+ `<fig-handle>`
702
751
 
703
- An image display or upload component.
752
+ A draggable handle element. Positioned on a `drag-surface` container with axis constraints and snapping. Used internally by gradient editors and spatial controls, but also available standalone.
704
753
 
705
754
  | Attribute | Type | Default | Description |
706
- |-----------|------|---------|-------------|
707
- | `src` | string | — | Image URL |
708
- | `upload` | boolean | `false` | Show upload button |
709
- | `label` | string | | Upload button label |
710
- | `size` | string | | Preview size |
755
+ |---|---|---|---|
756
+ | `value` | string | — | Position as `"X% Y%"` |
757
+ | `color` | string | | Handle color |
758
+ | `selected` | boolean | `false` | Selected state |
759
+ | `disabled` | boolean | `false` | Disabled state |
760
+ | `drag` | boolean | `false` | Enable dragging |
761
+ | `drag-surface` | string | — | CSS selector for drag container (defaults to parent) |
762
+ | `drag-axes` | string | `"xy"` | Constrain axes: `"x"`, `"y"`, `"xy"` |
763
+ | `drag-snapping` | string | — | Snapping behavior |
764
+ | `type` | string | — | `"color"` for color handle with `fig-color-tip` |
765
+ | `control` | string | — | `"add"` or `"remove"` delegated to color tip |
766
+ | `hit-area` | string | — | Expanded interaction zone (unitless px). `"8"`, `"8 12"` (v h), or `"8 circle"` |
767
+ | `hit-area-mode` | string | `"handle"` | `"handle"` proxies to handle drag/select; `"delegate"` emits `hitareadown` event |
768
+
769
+ **Events:**
770
+
771
+ | Event | Detail |
772
+ |---|---|
773
+ | `input` | `{ x, y, px, py, shiftKey }` — while dragging |
774
+ | `change` | `{ x, y, px, py }` — on release |
775
+ | `add` | — (when control="add") |
776
+ | `remove` | — (when control="remove") |
777
+ | `hitareadown` | `{ originalEvent }` — when `hit-area-mode="delegate"` and the hit area is clicked |
711
778
 
712
779
  ```html
713
- <fig-image src="photo.jpg"></fig-image>
714
- <fig-image upload label="Upload Image"></fig-image>
780
+ <div style="position: relative; width: 200px; height: 200px; background: #eee;">
781
+ <fig-handle drag="true" value="50% 50%"></fig-handle>
782
+ </div>
715
783
  ```
716
784
 
717
785
  ---
718
786
 
719
- ### Joystick (`<fig-joystick>`)
787
+ #### Canvas Point
720
788
 
721
- A 2D position input control.
789
+ `<fig-canvas-point>` [demo](https://rog.ie/figui3/#canvas-point)
790
+
791
+ A composite point control with optional radius circle and angle handle. Place inside a positioned container; the component uses `display: contents` and does not create its own box.
722
792
 
723
793
  | Attribute | Type | Default | Description |
724
- |-----------|------|---------|-------------|
725
- | `value` | string | `"50% 50%"` | Position as percentages (for example `"50% 50%"` or `"25% 80%"`) |
726
- | `precision` | number | — | Decimal places |
727
- | `transform` | number | — | Output scaling |
728
- | `fields` | boolean | `false` | Show X/Y inputs |
729
- | `coordinates` | string | `"screen"` | Coordinate system: `"screen"` (0,0 top-left) or `"math"` (0,0 bottom-left) |
730
- | `aspect-ratio` | string | `"1 / 1"` | Plane container ratio (for example `16 / 9`) |
794
+ |---|---|---|---|
795
+ | `type` | string | `"point"` | `"point"`, `"color"`, `"point-radius"`, `"point-radius-angle"` |
796
+ | `value` | JSON string | — | `{ "x": 50, "y": 50, "radius"?: 30, "angle"?: 45 }` — radius accepts unitless (px) or `"25%"` |
797
+ | `color` | string | — | Passthrough color for `type="color"` handle |
798
+ | `tooltips` | string | `"true"` | Show value tooltips on interaction |
799
+ | `disabled` | boolean | `false` | Disable all interaction |
800
+ | `drag-surface` | string | `"parent"` | Forwarded to inner `fig-handle`s |
801
+ | `snapping` | string | `"false"` | `"false"`, `"true"`, `"modifier"` — applies to point, radius, and angle |
802
+
803
+ **Events:**
804
+
805
+ | Event | Detail |
806
+ |---|---|
807
+ | `input` | `{ x, y, radius?, angle? }` — while dragging |
808
+ | `change` | `{ x, y, radius?, angle? }` — on release |
731
809
 
732
810
  ```html
733
- <fig-joystick value="50% 50%"></fig-joystick>
734
- <fig-joystick value="50% 50%" fields="true" precision="2"></fig-joystick>
735
-
736
- <!-- Math coordinates (Y-axis inverted: 0,0 at bottom-left) -->
737
- <fig-joystick value="50% 50%" coordinates="math" fields="true"></fig-joystick>
811
+ <div style="position: relative; width: 200px; height: 200px; background: #eee;">
812
+ <fig-canvas-point
813
+ type="point-radius-angle"
814
+ value='{"x":50,"y":50,"radius":"25%","angle":45}'
815
+ snapping="modifier"
816
+ ></fig-canvas-point>
817
+ </div>
738
818
  ```
739
819
 
740
820
  ---
741
821
 
742
- ### Input Angle (`<fig-input-angle>`)
822
+ ### Layout & Feedback
743
823
 
744
- An angle/rotation input control with optional min/max clamping, multi-unit support, and unbounded winding (values beyond 360°).
824
+ #### Field
745
825
 
746
- When `min` and `max` are omitted, the input is unbounded dragging continuously winds the angle past full revolutions (e.g. 720°, 1080°, or negative values). The text input also accepts values with unit suffixes (`90deg`, `3.14rad`, `0.5turn`) and converts them to the component's `units` format.
826
+ `<fig-field>`[demo](https://rog.ie/figui3/#field)
827
+
828
+ A form field wrapper with flexible layout. Automatically links `<label>` to the first `fig-*` child for accessibility.
747
829
 
748
830
  | Attribute | Type | Default | Description |
749
- |-----------|------|---------|-------------|
750
- | `value` | number | `0` | Angle value (in the unit specified by `units`) |
751
- | `precision` | number | `1` | Decimal places for display |
752
- | `text` | boolean | `false` | Show numeric text input alongside the dial |
753
- | `dial` | boolean | `true` | Show circular dial control (`dial="false"` hides it) |
754
- | `min` | number | — | Minimum angle (omit for unbounded) |
755
- | `max` | number | — | Maximum angle (omit for unbounded) |
756
- | `units` | string | `"°"` | Display unit: `"°"` (or `"deg"`), `"rad"`, `"turn"` |
757
- | `rotations` | boolean | `false` | Show a ×N rotation counter when angle exceeds 1 full rotation (`rotations` or `rotations="true"`) |
831
+ |---|---|---|---|
832
+ | `direction` | string | `"column"` | `"column"`, `"row"`, `"horizontal"` |
833
+ | `columns` | string | | Split preset: `"thirds"` or `"half"` |
834
+ | `label` | string | | Programmatic label text |
758
835
 
759
836
  ```html
760
- <!-- Basic dial -->
761
- <fig-input-angle value="45"></fig-input-angle>
837
+ <fig-field direction="horizontal" columns="thirds">
838
+ <label>Opacity</label>
839
+ <fig-slider value="50" text="true" units="%"></fig-slider>
840
+ </fig-field>
841
+ ```
762
842
 
763
- <!-- With text input -->
764
- <fig-input-angle value="90" text="true"></fig-input-angle>
843
+ ---
765
844
 
766
- <!-- Unbounded (supports winding past 360°) -->
767
- <fig-input-angle text="true" value="720"></fig-input-angle>
845
+ #### Dialog
768
846
 
769
- <!-- Clamped to a range -->
770
- <fig-input-angle text="true" value="90" min="0" max="180"></fig-input-angle>
847
+ `<fig-dialog>` [demo](https://rog.ie/figui3/#dialog)
771
848
 
772
- <!-- Radians -->
773
- <fig-input-angle text="true" units="rad" value="3.14159"></fig-input-angle>
849
+ A modal/non-modal dialog. Uses `is="fig-dialog"` on a native `<dialog>` element.
774
850
 
775
- <!-- Turns -->
776
- <fig-input-angle text="true" units="turn" value="0.5"></fig-input-angle>
851
+ | Attribute | Type | Default | Description |
852
+ |---|---|---|---|
853
+ | `open` | boolean | `false` | Visible state |
854
+ | `modal` | boolean | `false` | Modal mode |
855
+ | `drag` | boolean | `false` | Draggable |
856
+ | `handle` | string | — | CSS selector for drag handle |
857
+ | `position` | string | — | `"center center"`, `"top left"`, etc. |
777
858
 
778
- <!-- Show rotation count (×2 at 720°, ×3 at 1080°, etc.) -->
779
- <fig-input-angle text="true" rotations value="1080"></fig-input-angle>
859
+ ```html
860
+ <dialog is="fig-dialog" id="myDialog" modal drag handle="fig-header" position="center center">
861
+ <fig-header>Dialog Title</fig-header>
862
+ <fig-content><p>Content here.</p></fig-content>
863
+ </dialog>
864
+ ```
865
+
866
+ ---
867
+
868
+ #### Popup
869
+
870
+ `<fig-popup>` — [demo](https://rog.ie/figui3/#popup)
780
871
 
781
- <!-- Text-only mode (hide dial) -->
782
- <fig-input-angle text="true" dial="false" value="90"></fig-input-angle>
872
+ An anchored floating surface built on `<dialog>` with collision-aware positioning.
873
+
874
+ | Attribute | Type | Default | Description |
875
+ |---|---|---|---|
876
+ | `anchor` | string | — | CSS selector for anchor element |
877
+ | `position` | string | `"top center"` | Placement |
878
+ | `offset` | string | `"0 0"` | X/Y offset |
879
+ | `viewport-margin` | string | `"8"` | Viewport safety margin |
880
+ | `variant` | string | — | `"popover"` for beak styling |
881
+ | `theme` | string | — | `"light"`, `"dark"`, `"menu"` |
882
+ | `closedby` | string | `"any"` | `"any"`, `"closerequest"`, `"none"` |
883
+ | `open` | boolean | `false` | Open state |
884
+ | `drag` | boolean | `false` | Draggable |
885
+ | `handle` | string | — | CSS selector for drag handle |
886
+ | `autoresize` | boolean | `false` | Auto-resize to content |
887
+
888
+ ```html
889
+ <dialog is="fig-popup" anchor="#my-button" position="center right" variant="popover">
890
+ <fig-header><h3>Popup</h3></fig-header>
891
+ </dialog>
783
892
  ```
784
893
 
785
894
  ---
786
895
 
787
- ### Toast (`<fig-toast>`)
896
+ #### Toast
897
+
898
+ `<fig-toast>` — [demo](https://rog.ie/figui3/#toast)
788
899
 
789
- A toast notification component.
900
+ A toast notification. Uses `is="fig-toast"` on a native `<dialog>`.
790
901
 
791
902
  | Attribute | Type | Default | Description |
792
- |-----------|------|---------|-------------|
903
+ |---|---|---|---|
793
904
  | `duration` | number | `5000` | Auto-dismiss ms (0 = no dismiss) |
794
905
  | `offset` | number | `16` | Distance from bottom |
795
- | `theme` | string | `"dark"` | Theme: `"dark"`, `"light"`, `"danger"`, `"brand"` |
906
+ | `theme` | string | `"dark"` | `"dark"`, `"light"`, `"danger"`, `"brand"`, `"auto"` |
796
907
 
797
908
  ```html
798
- <fig-button onclick="document.getElementById('myToast').showToast()">Show toast</fig-button>
799
-
800
- <fig-toast id="myToast" theme="brand" duration="3000">
801
- Settings saved successfully!
802
- </fig-toast>
909
+ <dialog is="fig-toast" id="myToast" theme="brand" duration="3000">
910
+ Settings saved!
911
+ </dialog>
912
+ <fig-button onclick="document.getElementById('myToast').showToast()">Show</fig-button>
803
913
  ```
804
914
 
805
915
  ---
806
916
 
807
- ### Spinner (`<fig-spinner>`)
917
+ #### Tooltip
918
+
919
+ `<fig-tooltip>` — [demo](https://rog.ie/figui3/#tooltip)
920
+
921
+ Contextual tooltip on hover or click. Auto-repositions when the child element moves.
808
922
 
809
- A loading spinner indicator.
923
+ | Attribute | Type | Default | Description |
924
+ |---|---|---|---|
925
+ | `text` | string | — | Tooltip text |
926
+ | `action` | string | `"hover"` | `"hover"`, `"click"`, `"manual"` |
927
+ | `delay` | number | `500` | Show delay in ms |
928
+ | `offset` | string | — | `"left,top,right,bottom"` |
929
+ | `show` | boolean | `false` | Persistent show state |
930
+ | `open` | boolean | `false` | Programmatic show/hide |
810
931
 
811
932
  ```html
812
- <fig-spinner></fig-spinner>
933
+ <fig-tooltip text="Helpful info">
934
+ <fig-button>Hover me</fig-button>
935
+ </fig-tooltip>
813
936
  ```
814
937
 
815
938
  ---
816
939
 
817
- ### Shimmer (`<fig-shimmer>`)
940
+ #### Header
818
941
 
819
- A loading placeholder with shimmer animation.
942
+ `<fig-header>` [demo](https://rog.ie/figui3/#header)
820
943
 
821
- | Attribute | Type | Default | Description |
822
- |-----------|------|---------|-------------|
823
- | `duration` | string | `"1.5s"` | Animation cycle duration (CSS time value) |
824
- | `playing` | boolean | `true` | Whether the animation is running |
944
+ A section header component.
825
945
 
826
946
  ```html
827
- <fig-shimmer style="width: 200px; height: 20px;"></fig-shimmer>
828
- <fig-shimmer style="width: 100px; height: 14px;" duration="2s"></fig-shimmer>
947
+ <fig-header>Section Title</fig-header>
829
948
  ```
830
949
 
831
950
  ---
832
951
 
833
- ### Layer (`<fig-layer>`)
952
+ #### Layer
953
+
954
+ `<fig-layer>` — [demo](https://rog.ie/figui3/#layer)
834
955
 
835
- A layer list item component (for layer panels). Supports nesting, expand/collapse via chevron, and visibility toggling.
956
+ A collapsible layer list item with expand/collapse and visibility toggling. Supports nesting.
836
957
 
837
958
  | Attribute | Type | Default | Description |
838
- |-----------|------|---------|-------------|
839
- | `open` | boolean | `false` | Whether child layers are expanded |
959
+ |---|---|---|---|
960
+ | `open` | boolean | `false` | Whether children are expanded |
840
961
  | `visible` | boolean | `true` | Whether the layer is visible |
841
962
 
842
- **Events:** `openchange` (detail: `{ open }`) and `visibilitychange` (detail: `{ visible }`)
963
+ **Events:** `openchange` (detail: `{ open }`), `visibilitychange` (detail: `{ visible }`).
843
964
 
844
965
  ```html
845
- <fig-layer>
846
- <div class="fig-layer-row">
847
- <span class="fig-layer-icon"></span>
848
- <span class="fig-layer-name">Rectangle 1</span>
849
- </div>
850
- </fig-layer>
851
-
852
- <!-- Nested with children -->
853
966
  <fig-layer open="true">
854
967
  <div class="fig-layer-row">
855
968
  <span class="fig-layer-icon"></span>
@@ -866,42 +979,112 @@ A layer list item component (for layer panels). Supports nesting, expand/collaps
866
979
 
867
980
  ---
868
981
 
869
- ### Header (`<fig-header>`)
982
+ #### Image
870
983
 
871
- A section header component.
984
+ `<fig-image>` [demo](https://rog.ie/figui3/#image)
985
+
986
+ An image display component with optional upload, aspect ratio, and object-fit control.
987
+
988
+ | Attribute | Type | Default | Description |
989
+ |---|---|---|---|
990
+ | `src` | string | — | Image URL |
991
+ | `upload` | boolean | `false` | Show upload button |
992
+ | `download` | boolean | `false` | Show download button |
993
+ | `label` | string | — | Upload button label |
994
+ | `aspect-ratio` | string | — | CSS aspect-ratio (e.g. `"16 / 9"`) |
995
+ | `fit` | string | — | CSS object-fit (`"cover"`, `"contain"`, etc.) |
996
+ | `checkerboard` | boolean | `false` | Show checkerboard behind transparent images |
872
997
 
873
998
  ```html
874
- <fig-header>Section Title</fig-header>
999
+ <fig-image src="photo.jpg" aspect-ratio="16 / 9" fit="cover"></fig-image>
1000
+ <fig-image upload label="Upload Image"></fig-image>
1001
+ ```
1002
+
1003
+ ---
1004
+
1005
+ #### Avatar
1006
+
1007
+ `<fig-avatar>` — [demo](https://rog.ie/figui3/#avatar)
1008
+
1009
+ Profile image or initials fallback.
1010
+
1011
+ | Attribute | Type | Default | Description |
1012
+ |---|---|---|---|
1013
+ | `src` | string | — | Image URL |
1014
+ | `name` | string | — | Name for initials fallback |
1015
+ | `size` | string | — | `"large"` |
1016
+
1017
+ ```html
1018
+ <fig-avatar src="https://example.com/photo.jpg" name="John Doe"></fig-avatar>
1019
+ <fig-avatar name="Jane Smith" size="large"></fig-avatar>
875
1020
  ```
876
1021
 
877
1022
  ---
878
1023
 
879
- ## Events
1024
+ #### Spinner
880
1025
 
881
- All form components emit standard `input` and `change` events:
1026
+ `<fig-spinner>` [demo](https://rog.ie/figui3/#spinner)
882
1027
 
883
- - **`input`** - Fires continuously during interaction (dragging, typing)
884
- - **`change`** - Fires when interaction completes (mouse up, blur)
1028
+ A loading spinner.
885
1029
 
886
- Events include a `detail` object with component-specific data:
1030
+ ```html
1031
+ <fig-spinner></fig-spinner>
1032
+ ```
887
1033
 
888
- ```js
889
- // Color input events
890
- colorInput.addEventListener('input', (e) => {
891
- console.log(e.detail);
892
- // { color: "#FF5733", alpha: 0.8, hsv: { h: 14, s: 80, v: 100, a: 0.8 } }
893
- });
894
-
895
- // Fill picker events
896
- fillPicker.addEventListener('change', (e) => {
897
- console.log(e.detail);
898
- // { type: "gradient", gradient: { type: "linear", angle: 90, stops: [...] }, css: "linear-gradient(...)" }
899
- });
900
-
901
- // Slider events
902
- slider.addEventListener('input', (e) => {
903
- console.log(e.target.value); // "75"
904
- });
1034
+ ---
1035
+
1036
+ #### Shimmer
1037
+
1038
+ `<fig-shimmer>` [demo](https://rog.ie/figui3/#shimmer)
1039
+
1040
+ A shimmer loading placeholder.
1041
+
1042
+ | Attribute | Type | Default | Description |
1043
+ |---|---|---|---|
1044
+ | `duration` | string | `"1.5s"` | Animation cycle duration |
1045
+ | `playing` | boolean | `true` | Whether animating |
1046
+
1047
+ ```html
1048
+ <fig-shimmer style="width: 200px; height: 20px;"></fig-shimmer>
1049
+ ```
1050
+
1051
+ ---
1052
+
1053
+ #### Skeleton
1054
+
1055
+ `<fig-skeleton>`
1056
+
1057
+ Extends `<fig-shimmer>` with no additional attributes. Use for structured loading placeholders.
1058
+
1059
+ ```html
1060
+ <fig-skeleton style="width: 100%; height: 1rem; border-radius: 4px;"></fig-skeleton>
1061
+ ```
1062
+
1063
+ ---
1064
+
1065
+ ## Theming
1066
+
1067
+ FigUI3 adapts to light and dark themes via CSS custom properties using Figma's naming convention:
1068
+
1069
+ ```css
1070
+ --figma-color-bg
1071
+ --figma-color-bg-secondary
1072
+ --figma-color-bg-hover
1073
+ --figma-color-text
1074
+ --figma-color-text-secondary
1075
+ --figma-color-border
1076
+ --figma-color-icon
1077
+ /* ... and more */
1078
+ ```
1079
+
1080
+ In Figma plugins, these variables are provided automatically. For standalone usage, the library includes fallback values that respond to `prefers-color-scheme`.
1081
+
1082
+ Force a theme manually:
1083
+
1084
+ ```html
1085
+ <body style="color-scheme: dark;">
1086
+ <!-- Forces dark theme -->
1087
+ </body>
905
1088
  ```
906
1089
 
907
1090
  ---
@@ -910,8 +1093,6 @@ slider.addEventListener('input', (e) => {
910
1093
 
911
1094
  ### React
912
1095
 
913
- Web components work in React, but require some considerations:
914
-
915
1096
  ```jsx
916
1097
  import { useRef, useEffect } from 'react';
917
1098
  import '@rogieking/figui3/fig.css';
@@ -923,45 +1104,28 @@ function ColorPicker({ value, onChange }) {
923
1104
  useEffect(() => {
924
1105
  const el = ref.current;
925
1106
  if (!el) return;
926
-
927
1107
  const handleChange = (e) => onChange(e.detail);
928
1108
  el.addEventListener('change', handleChange);
929
1109
  return () => el.removeEventListener('change', handleChange);
930
1110
  }, [onChange]);
931
1111
 
932
- // Set initial value via ref to avoid infinite loops
933
1112
  useEffect(() => {
934
- if (ref.current) {
935
- ref.current.setAttribute('value', value);
936
- }
1113
+ if (ref.current) ref.current.setAttribute('value', value);
937
1114
  }, [value]);
938
1115
 
939
- return (
940
- <fig-input-color
941
- ref={ref}
942
- text="true"
943
- alpha="true"
944
- picker="figma"
945
- />
946
- );
1116
+ return <fig-input-color ref={ref} text="true" alpha="true" picker="figma" />;
947
1117
  }
948
1118
  ```
949
1119
 
950
- > **Note:** Avoid setting the `value` prop directly on web components in JSX during re-renders, as `attributeChangedCallback` may trigger events that cause infinite loops. Use refs to control updates.
1120
+ > **Note:** Avoid setting `value` directly in JSX during re-renders use refs to prevent infinite loops from `attributeChangedCallback`.
951
1121
  >
952
- > **SSR note (Next.js/Remix/Astro):** import `@rogieking/figui3/fig.js` only on the client (for example in a client-only entry/module). This keeps server rendering safe while still allowing FigUI3 to auto-load its WebKit/iOS customized built-in polyfill when needed.
1122
+ > **SSR (Next.js/Remix/Astro):** Import `fig.js` only on the client to keep server rendering safe.
953
1123
 
954
1124
  ### Vue
955
1125
 
956
1126
  ```vue
957
1127
  <template>
958
- <fig-input-color
959
- :value="color"
960
- text="true"
961
- alpha="true"
962
- @input="onInput"
963
- @change="onChange"
964
- />
1128
+ <fig-input-color :value="color" text="true" alpha="true" @input="onInput" @change="onChange" />
965
1129
  </template>
966
1130
 
967
1131
  <script setup>
@@ -970,14 +1134,8 @@ import '@rogieking/figui3/fig.css';
970
1134
  import '@rogieking/figui3/fig.js';
971
1135
 
972
1136
  const color = ref('#FF5733');
973
-
974
- const onInput = (e) => {
975
- color.value = e.detail.color;
976
- };
977
-
978
- const onChange = (e) => {
979
- console.log('Final color:', e.detail);
980
- };
1137
+ const onInput = (e) => { color.value = e.detail.color; };
1138
+ const onChange = (e) => { console.log('Final:', e.detail); };
981
1139
  </script>
982
1140
  ```
983
1141
 
@@ -987,101 +1145,64 @@ const onChange = (e) => {
987
1145
  <script>
988
1146
  import '@rogieking/figui3/fig.css';
989
1147
  import '@rogieking/figui3/fig.js';
990
-
991
1148
  let color = '#FF5733';
992
-
993
- function handleInput(e) {
994
- color = e.detail.color;
995
- }
996
1149
  </script>
997
1150
 
998
- <fig-input-color
999
- value={color}
1000
- text="true"
1001
- alpha="true"
1002
- on:input={handleInput}
1003
- on:change={(e) => console.log('Saved:', e.detail)}
1004
- />
1151
+ <fig-input-color value={color} text="true" alpha="true"
1152
+ on:input={(e) => color = e.detail.color}
1153
+ on:change={(e) => console.log('Saved:', e.detail)} />
1005
1154
  ```
1006
1155
 
1007
1156
  ---
1008
1157
 
1009
- ## Breaking Changes / Migration
1010
-
1011
- ### v2.15.0: Experimental Features
1158
+ ## Development
1012
1159
 
1013
- The `experimental` attribute now controls experimental CSS features instead of `variant="neue"`.
1014
-
1015
- **Before (deprecated):**
1016
- ```html
1017
- <fig-dropdown variant="neue">
1018
- <option>Option 1</option>
1019
- </fig-dropdown>
1020
- ```
1021
-
1022
- **After:**
1023
- ```html
1024
- <fig-dropdown experimental="modern">
1025
- <option>Option 1</option>
1026
- </fig-dropdown>
1160
+ ```bash
1161
+ git clone https://github.com/rogie/figui3.git
1162
+ cd figui3
1163
+ bun install
1164
+ bun dev # Component docs at http://localhost:3000
1165
+ npm run dev:playground # Playground at http://localhost:5173 (/figui3, /propkit, /sandbox)
1166
+ npm run build # Build minified dist/ (JS + CSS)
1167
+ npm run build:css # Build minified CSS only
1027
1168
  ```
1028
1169
 
1029
- The `experimental` attribute uses space-separated feature names for granular control:
1030
- - `experimental="modern"` - Enables the customizable select picker (`::picker(select)`, `appearance: base-select`)
1031
- - Future features can be added: `experimental="modern popover"`
1032
-
1033
- Note: `variant="neue"` on `fig-slider` continues to work for visual styling.
1170
+ ### Build Output
1034
1171
 
1035
- See [CHANGELOG.md](CHANGELOG.md) for full details.
1172
+ `npm run build` produces minified files in `dist/`:
1036
1173
 
1037
- ---
1038
-
1039
- ## Theming
1174
+ | Source | Minified | Tool |
1175
+ |---|---|---|
1176
+ | `fig.js` (416 KB) | `dist/fig.js` (228 KB) | Bun `--minify` |
1177
+ | `fig.css` (133 KB) | `dist/fig.css` (102 KB) | lightningcss `--minify --nesting --bundle` |
1178
+ | `base.css` (1.9 KB) | `dist/base.css` (1.5 KB) | lightningcss |
1179
+ | `components.css` (131 KB) | `dist/components.css` (100 KB) | lightningcss |
1040
1180
 
1041
- FigUI3 automatically adapts to light and dark themes using CSS custom properties. The library uses Figma's color variable naming convention:
1181
+ Default imports resolve to minified `dist/` files. Unminified source is available via `@rogieking/figui3/src/*`:
1042
1182
 
1043
- ```css
1044
- /* Colors automatically switch based on color-scheme */
1045
- --figma-color-bg
1046
- --figma-color-bg-secondary
1047
- --figma-color-bg-hover
1048
- --figma-color-text
1049
- --figma-color-text-secondary
1050
- --figma-color-border
1051
- --figma-color-icon
1052
- /* ... and more */
1183
+ ```js
1184
+ import "@rogieking/figui3/fig.css"; // minified (default)
1185
+ import "@rogieking/figui3/src/fig.css"; // unminified source
1053
1186
  ```
1054
1187
 
1055
- ### Using in Figma Plugins
1188
+ ### Playground
1056
1189
 
1057
- In Figma plugins, these variables are provided automatically. For standalone usage, the library includes fallback values that respond to `prefers-color-scheme`.
1058
-
1059
- ### Manual Theme Control
1190
+ The playground is the fastest way to explore and validate component markup:
1060
1191
 
1061
- ```html
1062
- <body style="color-scheme: dark;">
1063
- <!-- Forces dark theme -->
1064
- </body>
1065
- ```
1192
+ - **`/figui3`** — component examples with attribute controls
1193
+ - **`/propkit`** — property panel patterns
1194
+ - **`/sandbox`** styled React sample app
1066
1195
 
1067
1196
  ---
1068
1197
 
1069
1198
  ## Browser Support
1070
1199
 
1071
- FigUI3 supports all modern browsers with Web Components support:
1072
-
1073
1200
  - Chrome/Edge 67+
1074
1201
  - Firefox 63+
1075
1202
  - Safari 10.1+
1076
1203
 
1077
1204
  ---
1078
1205
 
1079
- ## Contributing
1080
-
1081
- Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) before submitting a pull request.
1082
-
1083
- ---
1084
-
1085
1206
  ## License
1086
1207
 
1087
- [MIT License](LICENSE) © Rogie King
1208
+ [MIT License](LICENSE) &copy; Rogie King