@rogieking/figui3 8.9.10 → 8.9.11

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.
@@ -1,242 +1,214 @@
1
1
  ---
2
2
  name: figui3
3
- description: Guides development and maintenance of the FigUI3 web components library for Figma-style plugin UIs. Applies when adding or modifying `fig-*` custom elements, updating docs/demo pages, adjusting theme tokens, improving accessibility, or debugging component behavior in `fig.js`, `components.css`, `index.html`, and `README.md`.
3
+ description: >-
4
+ Guides FigUI3 core (`fig.js` / `fig.css`) web components for Figma-style plugin UIs.
5
+ Use when adding, using, or debugging fig-* elements from the core bundle—buttons,
6
+ fields, overlays, menus, sliders, color/fill inputs, media, dialogs, popups, toasts—or
7
+ when working in the /figui3 playground. Not for fig-select or fig-fill-picker
8
+ (fig-editor), propskit-* / AI / canvas / angle / reorder (fig-lab), or fig-layer.
4
9
  user-invocable: false
5
10
  ---
6
11
 
7
- # FigUI3
12
+ # FigUI3 core (`fig.js`)
8
13
 
9
- A lightweight web components library for Figma UI3-style plugin and widget interfaces.
14
+ Zero-dependency web components for Figma UI3 plugin and widget UIs.
10
15
 
11
- > IMPORTANT: Prefer the project's native scripts and structure. Use `bun dev` for local docs/demo work and `bun build` for production output.
16
+ Canonical examples live in the **playground**, not `index.html`.
12
17
 
13
- ## Current Project Context
18
+ - Live: https://rog.ie/figui3/
19
+ - Local: `npm run dev:playground` → `/figui3`
20
+ - Sections: `playground/src/data/figui3Sections.ts`
21
+ - Attribute inspector: `playground/src/lib/attributeRules.ts`
22
+ - Public API: `README.md`
14
23
 
15
- ```json
16
- !`node -e "const p=require('./package.json'); console.log(JSON.stringify({name:p.name,version:p.version,scripts:p.scripts,exports:p.exports},null,2))" 2>/dev/null || echo '{"error":"package.json not found"}'`
24
+ Related skills: `fig-editor` (`fig-select`, `fig-fill-picker`), `fig-lab` (`propskit-*`, AI, canvas), `propkit` (`/propskit` field composition).
25
+
26
+ ## Bundles
27
+
28
+ Always import CSS with JS. Register before first render.
29
+
30
+ ```js
31
+ import "@rogieking/figui3/fig.css";
32
+ import "@rogieking/figui3/fig.js";
17
33
  ```
18
34
 
19
- The JSON above is the source of truth for package name, build commands, and exported files.
35
+ | Bundle | CSS + JS | Components |
36
+ |---|---|---|
37
+ | **Core** (this skill) | `fig.css` + `fig.js` | All `fig-*` below |
38
+ | **Editor** | `fig-editor.css` + `fig-editor.js` | `fig-select*`, `fig-fill-picker`, `fig-interpolation-swatch` |
39
+ | **Lab** (unstable) | `fig-lab.css` + `fig-lab.js` | `propskit-*`, `fig-ai-*`, `fig-canvas-control`, `fig-input-angle`, `fig-reorder` |
40
+ | **Layer** | `fig-layer.css` + `fig-layer.js` | `fig-layer` |
20
41
 
21
- ## Principles
42
+ `fig-editor.js` also imports `fig.js` and `fig-lab.js`. Lab CSS is still separate. `fig-layer` is **not** registered by `fig-editor.js`.
22
43
 
23
- 1. **Preserve native Web Components patterns.** Keep components framework-agnostic and rooted in custom elements.
24
- 2. **Prefer existing `fig-*` components over one-off markup.** Compose from current primitives before inventing new ones.
25
- 3. **Keep Figma UI3 visual consistency.** Use existing CSS variables and spacing/radius conventions.
26
- 4. **Honor interaction semantics.** Emit `input` while interacting and `change` on committed value changes.
27
- 5. **Treat accessibility as required behavior.** Preserve labels, keyboard support, ARIA attributes, and disabled states.
44
+ Playground “Full editor” toggle reveals `#select`, `#fill-picker`, `#layer`, and `#toast`. That grouping is UI-only: toast is core; layer is `fig-layer.js`.
28
45
 
29
- ## React + Vite Integration
46
+ ## Principles
30
47
 
31
- ### Install and bootstrap in React
48
+ 1. Prefer existing `fig-*` tags over one-off markup.
49
+ 2. Use design tokens (`--figma-color-*`, `--radius-*`, `--spacer-*`). Do not hardcode Figma colors.
50
+ 3. Emit `input` while interacting and `change` on commit. Do not fire `input` from programmatic attribute writes.
51
+ 4. Preserve a11y: labels, keyboard, ARIA, disabled. See the `a11y` skill.
52
+ 5. Keep components framework-agnostic. No React internals.
32
53
 
33
- - Install package: `npm i @rogieking/figui3` (or `pnpm add` / `bun add`).
34
- - Import CSS once in app entry (`main.tsx` / `main.jsx`): `import "@rogieking/figui3/fig.css";`
35
- - Register custom elements before first render. In Vite/React, prefer an explicit bootstrap:
54
+ ## React + Vite
36
55
 
37
56
  ```tsx
38
57
  import "@rogieking/figui3/fig.css";
39
58
 
40
59
  const bootstrap = async () => {
41
- // Prevent production tree-shaking from dropping registration side effects.
42
60
  await import("@rogieking/figui3/fig.js");
43
61
  createRoot(document.getElementById("app")!).render(<App />);
44
62
  };
45
-
46
63
  bootstrap();
47
64
  ```
48
65
 
49
- ### Vite config guidance
50
-
51
- - Standard React Vite config is usually enough:
52
-
53
- ```ts
54
- import { defineConfig } from "vite";
55
- import react from "@vitejs/plugin-react";
56
-
57
- export default defineConfig({
58
- plugins: [react()],
59
- });
60
- ```
61
-
62
- - Keep FigUI3 registration import at the top-level app bootstrap (not inside leaf components).
63
- - If a production build appears to tree-shake element registration, use the explicit dynamic import pattern above.
64
-
65
- ### React usage rules for web components
66
-
67
- - Use DOM attrs on custom elements (`<fig-slider text="true" />`) and read values from `e.target` / `e.detail`.
68
- - In React, use `class` (not `className`) for all FigUI3 web components (`fig-*` and `<dialog is="fig-...">`) to keep attribute behavior consistent.
69
- - Prefer refs + `addEventListener` when wiring complex `input`/`change` behavior.
70
-
71
- ### React + color picker modes (`fig-input-color` / `fig-fill-picker`)
72
-
73
- - `fig-fill-picker` is optional. Import `fig-editor.js` and `fig-editor.css` when full picker behavior is needed.
74
- - Do not use `picker` or `picker-anchor` on `fig-input-color`; components auto-detect `fig-fill-picker` at interaction time.
75
- - `picker-*` attrs on `fig-input-color` are forwarded to `fig-fill-picker` only when the optional picker is registered.
76
- - Example: `picker-dialog-position`.
77
- - For React custom modes, use `fig-fill-picker` + slot API:
78
- - Add a child with `slot="mode-<name>"` (and optional `label`).
79
- - Include `<name>` in the `mode` attribute (e.g. `mode="solid,react-demo"`).
80
- - Listen for `modeready` and render into `e.detail.container`.
81
- - Do not reparent React-owned DOM into the picker after render; use the provided `modeready` container as mount target.
82
- - Keep React lifecycle cleanup explicit for custom mode mounts:
83
- - keep one `root` per mode container
84
- - call `root.unmount()` when the host component unmounts
85
- - remove `modeready` listeners in cleanup to avoid duplicate mounts
86
- - Custom mode content must dispatch `input` / `change` with `detail` payload so picker can store mode data and propagate events.
87
- - Preserve value shape expectations:
88
- - `fig-input-color` expects solid color data (`detail.color`, optional `detail.alpha`) from the picker.
89
- - `fig-fill-picker` custom modes use JSON with `type` set to mode name and remaining data in payload.
90
- - Direct color events expose additive `{ color, alpha, opacity }` aliases: opaque `#RRGGBB`, `0–1`, and `0–100`, respectively.
91
- - Keep `fig-input-color`'s legacy `value`, `hex`, and `rgba` event-detail fields unchanged; consume the aliases for a shared contract.
92
-
93
- ## Critical Rules
94
-
95
- ### Overlay Components (`fig-dialog`, `fig-popup`)
96
-
97
- - Choose the overlay primitive intentionally:
98
- - **`<dialog is="fig-dialog">`** for modal/light-dismiss dialog workflows.
99
- - **`<dialog is="fig-popup">`** for anchored floating surfaces (menus, contextual panels, nested popups).
100
- - Keep overlay semantics stable:
101
- - `fig-dialog` should remain dialog-first (title/header/footer patterns, modal semantics).
102
- - `fig-popup` should remain anchor/position-first (offset, collision handling, viewport margins).
103
- - Preserve drag and positioning behavior on both `fig-dialog` and `fig-popup`; do not regress manual placement rules.
104
- - For popup chains, maintain containment and dismissal logic across descendant popups.
105
- - Document any overlay behavior change in demos and changelog with a concrete before/after note.
106
-
107
- ### Component Architecture
108
-
109
- - Extend `HTMLElement` and implement lifecycle cleanup in `disconnectedCallback`.
110
- - Use `observedAttributes` + `attributeChangedCallback` for attribute-driven reactivity.
111
- - Keep attribute names and behavior backward-compatible unless explicitly doing a breaking change.
112
- - Support `disabled` behavior wherever interaction is possible.
113
- - Avoid introducing framework-specific assumptions in component internals.
66
+ - Use DOM attrs (`text="true"`). Read values from `e.target` / `e.detail`.
67
+ - On `fig-*` and `<dialog is="fig-...">`, use `class` not `className`.
68
+ - Prefer refs + `addEventListener` for `input`/`change`.
114
69
 
115
- ### Events and Data Contracts
70
+ Color picker modes: `fig-fill-picker` is optional editor. Do not use `picker` / `picker-anchor` on `fig-input-color`. `picker-*` attrs forward to the picker only when it is registered. See `fig-editor`.
116
71
 
117
- - Emit standard `input` and `change` events for form-like controls.
118
- - Put rich payloads in `event.detail` when needed; keep names stable.
119
- - Do not silently change event payload shape for existing components.
120
- - When adding new events, document trigger timing and payload fields.
72
+ ## Overlay rules
121
73
 
122
- ### Styling and Theming
123
-
124
- - Reuse established design tokens and CSS variables before adding new ones.
125
- - Keep light/dark compatibility working with `color-scheme` and current token strategy.
126
- - Avoid ad-hoc hardcoded colors when semantic tokens already exist.
127
- - Preserve current sizing, spacing, and radius rhythm unless intentionally refactoring system-wide.
128
-
129
- ### Documentation and Demos
130
-
131
- - Update `README.md` component docs when public API or behavior changes.
132
- - Update demo surfaces (`index.html` and `playground/` routes where relevant) for visible behavior changes.
133
- - Prefer realistic examples that mirror plugin/property panel usage.
134
-
135
- ### Compatibility and Safety
136
-
137
- - Keep browser support expectations aligned with current README claims.
138
- - Use progressive enhancement for bleeding-edge CSS features.
139
- - Avoid regressions in existing attributes, defaults, and emitted events.
140
-
141
- ### Color Picker Mode Extensibility
142
-
143
- - Treat custom modes as a `fig-fill-picker` concern, not a standalone `fig-input-color` concern.
144
- - When adding a new mode, update demos/docs with both:
145
- - vanilla slot usage (`slot="mode-*"`)
146
- - React `modeready` usage
147
- - Do not emit `input` from programmatic attribute writes (`value` updates); preserve current loop-avoidance behavior for React.
148
-
149
- ## Key Patterns
74
+ - `<dialog is="fig-dialog">` — modal/task dialog. `position` is viewport placement. No `anchor`.
75
+ - `<dialog is="fig-popup">` — anchored float (`anchor`, `position`, `offset`, `viewport-margin`). `variant="popover"` uses CSS `filter` (containing block for `position: fixed`).
76
+ - `<dialog is="fig-toast">` call `showToast()`. `theme`, `duration`, `live`, `dismiss`, `icon`.
77
+ - `fig-menu` and `fig-select` use `popover="manual"` so lists escape filter-containing popups to the top layer. Nested menus inside popovers must keep that.
150
78
 
151
79
  ```html
152
- <!-- Modal/dialog content container -->
153
- <dialog is="fig-dialog" drag="true" handle="fig-header">
80
+ <dialog is="fig-dialog" drag handle="fig-header">
154
81
  <fig-header>
155
- Dialog Title
156
- <fig-button variant="ghost" icon close-dialog aria-label="Close dialog">
82
+ Title
83
+ <fig-button variant="ghost" icon close-dialog aria-label="Close">
157
84
  <fig-icon name="close"></fig-icon>
158
85
  </fig-button>
159
86
  </fig-header>
160
- <div>Dialog body</div>
87
+ <fig-content>Body</fig-content>
161
88
  </dialog>
162
89
 
163
- <!-- Anchored popup surface -->
164
90
  <dialog is="fig-popup" anchor="#trigger" position="bottom left" offset="8 8">
165
- <div>Popup content</div>
91
+ Popup content
166
92
  </dialog>
167
93
  ```
168
94
 
169
- ```js
170
- // Event contract pattern: continuous + committed updates.
171
- this.dispatchEvent(new CustomEvent("input", { detail, bubbles: true }));
172
- this.dispatchEvent(new CustomEvent("change", { detail, bubbles: true }));
173
-
174
- // Attribute-driven updates.
175
- static get observedAttributes() { return ["value", "disabled"]; }
176
- attributeChangedCallback(name, oldValue, newValue) {
177
- if (oldValue === newValue) return;
178
- // sync internal UI state
179
- }
180
- ```
95
+ ## Field composition
181
96
 
182
- ```txt
183
- Event contract quick map:
184
- - fig-slider: input/change -> current value on e.target.value
185
- - fig-input-color: input/change -> legacy value/hex/rgba plus color/alpha/opacity aliases in e.detail
186
- - fig-input-fill / fig-fill-picker: input/change -> fill payload in e.detail
187
- ```
97
+ Default property row:
188
98
 
189
99
  ```html
190
- <!-- Typical field composition -->
191
100
  <fig-field direction="horizontal">
192
101
  <label>Opacity</label>
193
- <fig-slider value="75" min="0" max="100" text="true" units="%"></fig-slider>
102
+ <fig-slider value="75" min="0" max="100" text="true" units="%" full></fig-slider>
194
103
  </fig-field>
195
104
  ```
196
105
 
197
- ## `fig-popup` vs `fig-dialog`
198
-
199
- - **Use `fig-dialog` when the UI is a dialog.**
200
- - Best for modal or primary task flows.
201
- - Works well with explicit dialog structure and close policies.
202
- - **Use `fig-popup` when you need low-level floating control.**
203
- - Best for anchored contextual surfaces and advanced positioning behavior.
204
- - Prefer this when you need explicit anchor/position/offset/viewport tuning.
205
-
206
- Rule of thumb: `fig-dialog` = dialog UX, `fig-popup` = popup primitive.
207
-
208
- ## Workflow
209
-
210
- 1. **Read existing implementation first.** Check `fig.js`, `components.css`, and related demo usage before editing.
211
- 2. **Confirm API surface impact.** Identify affected attributes, events, and slots.
212
- 3. **Implement with compatibility in mind.** Preserve defaults and old usage unless explicitly changed.
213
- 4. **Update docs/demo in same pass.** Keep examples and behavior synchronized.
214
- 5. **Run project checks.** Use `bun build` for output sanity. Never kill the playground/dev server when running tests, building, or updating code; treat existing `npm run dev:playground`, Vite, `bun dev`, and local preview servers as user-owned long-running processes. Only start a dev server if none is already running.
215
- 6. **Verify accessibility and theming.** Check keyboard flow, labels, disabled states, and both light/dark appearance.
216
-
217
- ## Release-Ready Checklist
106
+ Labeled property wrappers (`propskit-*`) are lab. For `/propskit` playground patterns, use the `propkit` skill.
107
+
108
+ ## Select vs dropdown
109
+
110
+ | Tag | Bundle | Use |
111
+ |---|---|---|
112
+ | `fig-dropdown` | core | Native `<select>` wrapper. `type="select\|dropdown"`, `variant="ghost"` |
113
+ | `fig-select` | editor | Custom listbox: groups, overflow chevrons, sticky separators, rich options |
114
+ | `propskit-select` | lab | Full-surface labeled field around `fig-select` |
115
+
116
+ Prefer `fig-select` for Figma-style menus. Use `fig-dropdown` only for a native select.
117
+
118
+ ## Core catalog
119
+
120
+ Playground hashes: `/figui3#{id}`. Full attrs: [reference.md](reference.md).
121
+
122
+ ### Buttons and inputs
123
+
124
+ | Tag | Playground | Notes |
125
+ |---|---|---|
126
+ | `fig-button` | `#button` | `variant`: secondary, ghost, link, destructive*, overlay, input. `type`: button, toggle, submit, select, upload. `size`, `icon`, `selected` |
127
+ | `fig-dropdown` | `#dropdown` | Native select. Options as `<option>` / `<optgroup>`. `variant="ghost"` |
128
+ | `fig-combo-input` | `#combo-input` | Text + suggestions (`options`) |
129
+ | `fig-input-text` | `#text-input` | `multiline` for textarea |
130
+ | `fig-input-number` | `#number-input` | `min`, `max`, `step`, `units`, `precision` |
131
+ | `fig-input-file` | `#file-input` | `accepts`, `multiple`, button `variant` |
132
+ | `fig-checkbox` / `fig-radio` / `fig-switch` | `#checkbox` `#radio` `#switch` | Switch supports `indeterminate` |
133
+ | `fig-slider` | `#slider` | `type`: range, opacity, hue, stepper, delta. `text`, `units`, `transform`, `variant="classic"` |
134
+ | `fig-options` | (propkit `#options`) | Option list helper; same option string formats as select |
135
+
136
+ ### Color and fill (no picker dialog)
137
+
138
+ | Tag | Playground | Notes |
139
+ |---|---|---|
140
+ | `fig-input-color` | (propkit `#color`) | Solid color. `text`, `alpha`. Auto-detects `fig-fill-picker` |
141
+ | `fig-input-fill` | `#fill-input` | Solid/gradient/image/video JSON `value`. `picker-*` forwarded if picker registered |
142
+ | `fig-input-palette` | (propkit `#palette`) | Multi-color. `fixed`, `open` |
143
+ | `fig-input-gradient` | (propkit `#gradient`) | Stops. `edit`, `mode="handle\|tip"` |
144
+ | `fig-swatch` | `#swatch` | `size`, `selected`, `alpha` |
145
+ | `fig-color-tip` | `#color-tip` | `control="color\|add\|remove"` |
146
+ | `fig-chit` | — | Alias-style color chip |
147
+
148
+ ### Layout and chrome
149
+
150
+ | Tag | Playground | Notes |
151
+ |---|---|---|
152
+ | `fig-field` | `#field` | `direction="horizontal\|vertical"`, `label` |
153
+ | `fig-group` | (containers) | `name`, `collapsible`, `open`, `compact` |
154
+ | `fig-header` / `fig-footer` / `fig-content` | (containers) | Header: `borderless`, `compact`. Footer: `sticky` |
155
+ | `fig-tabs` / `fig-tab` | `#tabs` | Roving tabs. `content="#id"` for panels |
156
+ | `fig-segmented-control` / `fig-segment` | `#segmented-control` | Radio-group pattern |
157
+ | `fig-chooser` / `fig-choice` | (containers) | Listbox selection |
158
+ | `fig-separator` / `fig-menu-separator` | `#separator` | Optional `label`, `sticky`, `borderless` |
159
+ | `fig-menu` / `fig-menu-item` | `#menu` | `fig-menu-trigger`, `trigger="contextmenu"`, `position`, `offset` |
160
+ | `fig-icon` | `#icon` | Token mask (`name`, `size="small"`, `color`) |
161
+ | `fig-avatar` | `#avatar` | `src` / `name`, `size="large"` |
162
+ | `fig-truncate` | `#truncate` | `position="right\|left\|middle"`, `tooltip`, `tail` |
163
+
164
+ ### Overlays
165
+
166
+ | Tag | Playground | Notes |
167
+ |---|---|---|
168
+ | `dialog is="fig-dialog"` | `#dialog` | `modal`, `drag`, `resizable`, `autoresize`, `handle`, `closedby`, `position` |
169
+ | `dialog is="fig-popup"` | `#popup` | `anchor`, `position`, `offset`, `viewport-margin`, `variant`, `theme` |
170
+ | `dialog is="fig-toast"` | `#toast` | `showToast()`. `theme`, `duration`, `live`, `dismiss`, `icon` |
171
+ | `fig-tooltip` | `#tooltip` | `text`, `action="hover\|click\|manual"`, `delay`, `theme` |
172
+
173
+ ### Media
174
+
175
+ | Tag | Playground | Notes |
176
+ |---|---|---|
177
+ | `fig-preview` | (propkit `#preview`) | `aspect-ratio`, `fit`, `full`, `checkerboard` |
178
+ | `fig-media` / `fig-image` / `fig-video` | `#media` `#image` `#video` | Upload via `upload`. Video controls below preview |
179
+ | `fig-card` | `#card` | Media + label + selection |
180
+ | `fig-media-controls` | `#media-controls` | Play/pause chrome |
181
+ | `fig-input-file` | `#file-input` | File picker button |
182
+
183
+ ### Specialized
184
+
185
+ | Tag | Playground | Notes |
186
+ |---|---|---|
187
+ | `fig-easing-curve` | (propkit `#easing`) | Bezier/spring |
188
+ | `fig-3d-rotate` | (containers) | Cube rotate |
189
+ | `fig-origin-grid` | (propkit) | Transform origin |
190
+ | `fig-joystick` | (propkit `#joystick`) | 2D position |
191
+ | `fig-handle` | `#handle` | `type="default\|minimal\|color\|canvas"`, `drag`, `drag-snapping` |
192
+ | `fig-spinner` / `fig-shimmer` / `fig-skeleton` | `#spinner` `#shimmer` | Loading |
193
+
194
+ `fig-input-angle` is **lab**, not core.
195
+
196
+ ## Events
218
197
 
219
- - Validate in a production build (`bun build`) and confirm custom elements are registered at runtime.
220
- - Verify `input` vs `change` behavior for touched controls in both vanilla usage and React integration.
221
- - Verify light/dark themes and keyboard navigation for any changed component.
222
- - Verify overlay behavior (`fig-dialog`, `fig-popup`) including close/dismiss and drag behavior when applicable.
223
- - Update `README.md`, demos, and `CHANGELOG.md` for any public API or behavior change.
224
-
225
- ## Quick Reference
226
-
227
- ```bash
228
- # Start docs/demo server
229
- bun dev
230
-
231
- # Build distributable files
232
- bun build
198
+ ```txt
199
+ fig-slider input/change e.target.value
200
+ fig-input-color input/change detail { color, alpha, opacity } plus legacy value/hex/rgba
201
+ fig-input-fill input/change fill payload in e.detail
202
+ fig-menu change detail { value }
203
+ fig-dialog/popup native dialog close plus FigUI3 positioning attrs
233
204
  ```
234
205
 
235
- ## Primary Files
206
+ ## Maintainer workflow
207
+
208
+ 1. Read `fig.js` + `components.css` before editing.
209
+ 2. Mirror playground examples in `figui3Sections.ts` and `attributeRules.ts`.
210
+ 3. Update `README.md` + `CHANGELOG.md` for public API changes.
211
+ 4. `bun build` for dist. Never kill `npm run dev:playground`.
212
+ 5. Tests: `npm run test:components` (Playwright). Do not start a second playground if one is running.
236
213
 
237
- - `fig.js` - component implementations and behavior
238
- - `components.css` - component-level styling and states
239
- - `base.css` - foundational styles and variables
240
- - `index.html` - main interactive docs/demo
241
- - `README.md` - public API and usage documentation
242
- - `CHANGELOG.md` - release history and migration notes
214
+ Primary files: `fig.js`, `components.css`, `base.css`, `README.md`, `playground/src/data/figui3Sections.ts`.
@@ -0,0 +1,90 @@
1
+ # FigUI3 core API reference
2
+
3
+ Source of truth for live attrs: `playground/src/lib/attributeRules.ts` and `README.md`.
4
+ Playground: `/figui3#{section}`.
5
+
6
+ ## Option string formats
7
+
8
+ Shared by `fig-dropdown`/`fig-options`/`fig-select`/`propskit-select` `options`:
9
+
10
+ - Comma-separated: `Left,Center,Right`
11
+ - Newline-delimited
12
+ - JSON array: `["Left","Center"]` or `[{"value":"left","label":"Left"}]`
13
+
14
+ ## `fig-button`
15
+
16
+ - `variant`: `""` (primary), `secondary`, `destructive`, `destructiveSecondary`, `destructiveGhost`, `destructiveLink`, `ghost`, `link`, `input`, `overlay`
17
+ - `type`: `button`, `toggle`, `submit`, `select`, `upload`
18
+ - `size`: `""`, `large`, `compact`
19
+ - `selected`, `disabled`, `icon` (presence)
20
+
21
+ ## `fig-dropdown`
22
+
23
+ - `value`, `type="select|dropdown"`, `variant="ghost"`, `full`, `disabled`
24
+ - Children: native `<option>` / `<optgroup>`
25
+
26
+ ## `fig-slider`
27
+
28
+ - `type`: `range` (default), `opacity`, `hue`, `stepper`, `delta`
29
+ - `text` default true; `text="false"` hides the number field
30
+ - Always set `min`, `max`, `step`; `units` when displayed
31
+ - `transform` when internal scale ≠ UI scale
32
+ - `variant="classic"` for the older appearance
33
+ - Opacity: set `color` and usually `units="%"`
34
+ - Delta: include `default` and typically symmetric min/max
35
+ - Stepper: include a `<datalist>` of stops
36
+
37
+ ## `fig-field`
38
+
39
+ - `direction="horizontal|vertical"`
40
+ - `label` or a child `<label>`
41
+
42
+ ## `fig-popup` vs `fig-dialog`
43
+
44
+ Dialog: `modal`, `drag`, `resizable`, `autoresize`, `handle`, `closedby="any|closerequest|none"`, `position` (viewport: `top left` … `bottom right`).
45
+
46
+ Popup: `anchor` (selector or element), `position` (side or corner), `offset="8 8"`, `viewport-margin`, `theme="default|light|dark|menu"`, `variant="popover|tooltip"`.
47
+
48
+ Toast: `theme`, `duration`, `offset`, `dismiss`, `live="polite|assertive"`, `icon`. Method: `showToast()`.
49
+
50
+ ## `fig-menu`
51
+
52
+ - Trigger: child with `fig-menu-trigger`, or `trigger="contextmenu"`
53
+ - `position`, `offset`, `closedby="auto|any|none"`, `open`
54
+ - Items: `fig-menu-item` (`value`, `disabled`, `subtle`)
55
+ - Dividers: `fig-separator` / `fig-menu-separator` (`label`, `sticky`, `borderless`)
56
+ - Popup uses `popover="manual"` (top layer)
57
+
58
+ ## Color / fill values
59
+
60
+ `fig-input-color` events: `{ color, alpha, opacity }` aliases (opaque `#RRGGBB`, `0–1`, `0–100`) plus legacy `value` / `hex` / `rgba`.
61
+
62
+ `fig-input-fill` value JSON:
63
+
64
+ ```json
65
+ {"type":"solid","color":"#FF5733","opacity":100}
66
+ {"type":"gradient","gradient":{}}
67
+ {"type":"image","image":{"url":"...","scaleMode":"fill"}}
68
+ ```
69
+
70
+ Without `fig-fill-picker`, fill/color render a preview. With the picker registered, click opens the editor dialog.
71
+
72
+ ## Media
73
+
74
+ - Surface lives in `fig-preview`
75
+ - `fig-image` / `fig-video`: `upload`, `fit`, `aspect-ratio`, `checkerboard`, `loading-indicator`
76
+ - Video controls render **below** the preview, not as an overlay
77
+ - Slotted image overlays stay in light DOM
78
+
79
+ ## `fig-layer` (separate bundle)
80
+
81
+ ```js
82
+ import "@rogieking/figui3/fig-layer.css";
83
+ import "@rogieking/figui3/fig-layer.js";
84
+ ```
85
+
86
+ Attrs: `open`, `visible`, `disabled`. Markup: child `.fig-layer-row` plus nested `fig-layer`. Events: `openchange`, `visibilitychange`. Playground: `/figui3#layer` (behind Full editor).
87
+
88
+ ## Native elements
89
+
90
+ `/figui3` also demos styled native `button`, `select`, `input`, `textarea`, `checkbox`, `.switch`, `radio`, `color`, `progress`, `fieldset`, `details`, `hr` under group “Native elements”. Use these when a custom element is unnecessary.