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