@rogieking/figui3 8.9.9 → 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,54 +1,34 @@
1
1
  ---
2
2
  name: propkit
3
- description: Guides creation and refinement of Figma-style property panel patterns ("PropKit") using FigUI3 components. Applies when building or modifying property fields in the playground app (`/propkit` route), generating consistent field prompts, composing horizontal `fig-field` rows, or tuning panel UX for controls like image, color, fill, slider, switch, dropdown, segmented control, easing, and angle.
3
+ description: >-
4
+ Guides Figma-style property panel composition in the /propskit playground using
5
+ fig-field rows and FigUI3 controls. Use when building or editing
6
+ playground/src/data/sections.ts, generating field prompts, or choosing between
7
+ raw fig-* rows and propskit-* wrappers (fig-lab).
4
8
  user-invocable: false
5
9
  ---
6
10
 
7
11
  # PropKit
8
12
 
9
- Patterns for composing clean, production-ready Figma property panels with FigUI3.
13
+ Patterns for Figma property panels. Two layers:
10
14
 
11
- > IMPORTANT: Favor composition and consistency over custom one-off controls. Build panels from existing `fig-*` elements first.
15
+ | Surface | Route | What to use |
16
+ |---|---|---|
17
+ | **PropsKit playground** | `/propskit` | Horizontal `fig-field` + core `fig-*` |
18
+ | **Lab wrappers** | `/propskit/lab` | `propskit-*` (see `fig-lab` skill) |
12
19
 
13
- ## Current Project Context
14
-
15
- ```json
16
- !`node -e "const fs=require('fs'); const ok=fs.existsSync('playground/src/main.tsx'); console.log(JSON.stringify({playground:ok, route:'/propkit', example:'horizontal fig-field + label + fig-* control'},null,2))" 2>/dev/null || echo '{"error":"context unavailable"}'`
17
- ```
20
+ Canonical `/propskit` examples: `playground/src/data/sections.ts`.
21
+ Core control APIs: `figui3` skill. Select/fill picker: `fig-editor`. Labeled wrappers: `fig-lab`.
18
22
 
19
23
  ## Principles
20
24
 
21
- 1. **Use horizontal property rows by default.** PropKit fields are primarily `fig-field direction="horizontal"`.
22
- 2. **One clear label per control.** Keep labels concise and aligned with Figma property language.
23
- 3. **Prefer native FigUI3 controls.** Use `fig-input-fill`, `fig-slider`, `fig-dropdown`, `fig-switch`, etc.
24
- 4. **Use realistic panel widths and spacing.** Match the property panel feel (`~240px` panel blocks in demos).
25
- 5. **Keep prompts and examples deterministic.** Prompt text should describe exact structure and key attributes.
26
-
27
- ## React + Vite PropKit Usage
28
-
29
- ### Include FigUI3 in React projects
30
-
31
- - Import once in app bootstrap:
32
- - `import "@rogieking/figui3/fig.css";`
33
- - `await import("@rogieking/figui3/fig.js");`
34
- - Register components before first React render to avoid undefined custom elements.
35
- - Keep this setup in entry files (`main.tsx` / `main.jsx`), not scattered across feature components.
36
-
37
- ### Vite setup and tree-shaking behavior
25
+ 1. Default to horizontal `fig-field` rows.
26
+ 2. One concise label per control.
27
+ 3. For new labeled property controls in lab, prefer `propskit-*` over duplicating field chrome.
28
+ 4. In `/propskit` demos, keep composing from `fig-*` so examples stay core-only unless the section needs lab.
29
+ 5. Panel width ~240px. Match existing section density.
38
30
 
39
- - Base Vite React config is sufficient in most cases:
40
-
41
- ```ts
42
- import { defineConfig } from "vite";
43
- import react from "@vitejs/plugin-react";
44
-
45
- export default defineConfig({
46
- plugins: [react()],
47
- });
48
- ```
49
-
50
- - In production, FigUI3 side-effect registration can be tree-shaken if only imported for side effects.
51
- - Preferred pattern (from `webgpu-effects`) is explicit async bootstrap:
31
+ ## React bootstrap
52
32
 
53
33
  ```tsx
54
34
  import "@rogieking/figui3/fig.css";
@@ -57,169 +37,70 @@ const bootstrap = async () => {
57
37
  await import("@rogieking/figui3/fig.js");
58
38
  createRoot(document.getElementById("app")!).render(<App />);
59
39
  };
60
-
61
40
  bootstrap();
62
41
  ```
63
42
 
64
- ### React composition conventions for PropKit rows
65
-
66
- - Continue using canonical row shape in JSX:
67
- - `<fig-field direction="horizontal">` + `<label>` + one primary `fig-*` control.
68
- - For customized built-ins in React (`<dialog is="fig-popup">` / `<dialog is="fig-dialog">`), use `class`, not `className`.
69
- - Use refs and native event listeners (`input`, `change`) for reliable control updates.
70
-
71
- ## Critical Rules
72
-
73
- ### Field Composition
74
-
75
- - Default pattern: label + single primary control inside one horizontal `fig-field`.
76
- - Keep control-specific options on the component itself (not hidden wrapper logic).
77
- - Use `full` where property controls should stretch within row constraints.
78
- - Avoid mixing unrelated controls in a single field row unless intentionally grouped.
79
-
80
- ### Prompt Generation Style
81
-
82
- - Write prompts as imperative build instructions.
83
- - Include field direction, control tag, and meaningful attrs.
84
- - Prefer short explicit phrasing over vague prose.
85
- - Keep wording consistent:
86
- - `Use a horizontal fig-field...`
87
- - `With a label of ...`
88
- - Include concrete defaults when relevant (value, min/max, step, units, mode, variant) so generated fields are deterministic.
89
- - Avoid placeholder-only prompts for numeric controls; always specify range semantics.
90
-
91
- ### Control Guidance
92
-
93
- - **Image:** prefer `fig-image` with `upload`, `fit`, and `aspect-ratio` where needed.
94
- - **Color:** use `fig-input-color` with `text="true"` and optional `alpha`.
95
- - **Fill:** use `fig-input-fill` for multi-mode fills; keep value JSON valid.
96
- - **Slider:** choose proper type (`range`, `opacity`, `hue`, `stepper`, `delta`) and include units/transform intentionally.
97
- - **Dropdown:** use `fig-dropdown`; include sensible default options.
98
- - **Boolean:** use `fig-switch`; avoid using dropdowns for true/false.
99
- - **Discrete choices:** use `fig-segmented-control` + `fig-segment`.
100
- - **Motion easing:** use `fig-easing-curve` with/without presets depending on context.
101
- - **Angle:** use `fig-input-angle` with `text="true"` for precision workflows.
102
-
103
- ### Slider Types and Variants
104
-
105
- - Default to `type="range"` for generic numeric properties (opacity %, size, spacing, intensity).
106
- - Use `type="opacity"` when color context is needed (set `color` and usually `units="%"`).
107
- - Use `type="hue"` only for hue selection workflows.
108
- - Use `type="stepper"` for discrete snap points (include a `datalist` with valid stops).
109
- - Use `type="delta"` for offset/relative adjustments around a neutral point (typically include `default`, and often symmetric min/max).
110
- - Text input is shown by default; use `text="false"` only for compact/simplified rows.
111
- - Use `transform` when internal value scale differs from UI display (example: internal `0..1`, display `0..100%`).
112
- - Variants:
113
- - Default variant for most property panels.
114
- - `variant="classic"` only when the previous slider appearance is needed.
115
- - Always set explicit `min`, `max`, and `step` (and `units` where applicable) to keep behavior predictable.
116
- - Set `default` on PropsKit value controls when reset behavior should differ from the initial value.
117
- - PropsKit value controls support `resetToDefault()` and a right-click **Reset** menu; `propskit-slider` also supports double-click reset.
118
-
119
- ### Control Selection Heuristics
120
-
121
- - Use `fig-slider` for scrub-friendly continuous values (opacity, intensity, scale, blur amount).
122
- - Use `fig-input-number` for precise direct entry (sizes, coordinates, exact typed values).
123
- - Use slider + text (`text="true"`) when users need both quick scrubbing and precise adjustment.
124
- - Use `fig-segmented-control` for small discrete sets (2-5 fixed options).
125
- - Use `fig-dropdown` for larger or less frequently switched option sets.
126
- - Use `fig-switch` for binary state, never slider/dropdown for pure on/off.
127
-
128
- ### UX Consistency
129
-
130
- - Keep panel patterns visually consistent across sections.
131
- - Preserve theme behavior (light/dark) and avoid non-token color overrides.
132
- - Ensure labels and controls remain keyboard and screen-reader usable.
133
-
134
- ## Key Patterns
43
+ Add `fig-editor` when using `fig-select` / fill picker. Add `fig-lab` when using `propskit-*`.
44
+
45
+ On `fig-*` and `<dialog is="fig-...">`, use `class` not `className`.
46
+
47
+ ## Field composition
135
48
 
136
49
  ```html
137
- <!-- Canonical PropKit row -->
138
50
  <fig-field direction="horizontal">
139
51
  <label>Opacity</label>
140
52
  <fig-slider value="75" min="0" max="100" text="true" units="%" full></fig-slider>
141
53
  </fig-field>
142
54
  ```
143
55
 
144
- ```html
145
- <!-- Non-horizontal (stacked/default column) field -->
146
- <fig-field>
147
- <label>Opacity</label>
148
- <fig-slider value="75" min="0" max="100" text="true" units="%"></fig-slider>
149
- </fig-field>
150
- ```
151
-
152
- ```html
153
- <!-- Fill + blend pair -->
154
- <fig-field direction="horizontal">
155
- <label>Fill</label>
156
- <fig-input-fill value='{"type":"solid","color":"#667eea"}'></fig-input-fill>
157
- </fig-field>
158
- <fig-field direction="horizontal">
159
- <label>Blend</label>
160
- <fig-dropdown full>
161
- <option selected>Normal</option>
162
- <option>Multiply</option>
163
- </fig-dropdown>
164
- </fig-field>
165
- ```
56
+ - Put control attrs on the control, not a wrapper.
57
+ - Use `full` when the control should stretch.
58
+ - Do not mix unrelated controls in one row unless grouped on purpose.
59
+
60
+ ## Control heuristics
61
+
62
+ | Intent | `/propskit` (core) | Lab wrapper |
63
+ |---|---|---|
64
+ | Boolean | `fig-switch` | `propskit-switch` |
65
+ | Continuous number | `fig-slider` | `propskit-slider` |
66
+ | Exact number | `fig-input-number` | `propskit-number` |
67
+ | Text | `fig-input-text` | `propskit-text` |
68
+ | Small discrete set (2–5) | `fig-segmented-control` | — |
69
+ | Larger / rich list | `fig-select` (editor) | `propskit-select` |
70
+ | Native select only | `fig-dropdown` | — |
71
+ | Color | `fig-input-color` `text="true"` | `propskit-color` |
72
+ | Fill | `fig-input-fill` | — |
73
+ | Gradient | `fig-input-gradient` | `propskit-gradient` |
74
+ | Image | `fig-image` `upload` | — |
75
+ | Easing | `fig-easing-curve` | — |
76
+ | Angle | `fig-input-angle` (**lab**) | — |
77
+ | X/Y | `fig-joystick` or two numbers | `propskit-position` |
78
+
79
+ Do not use dropdown/slider for pure on/off. Do not use `fig-dropdown` for Figma-style property selects when `fig-select` is available.
80
+
81
+ ## Slider rules
82
+
83
+ - Default `type="range"`. Always set `min`, `max`, `step`.
84
+ - `opacity`: set `color`, usually `units="%"`
85
+ - `hue`: hue workflows only
86
+ - `stepper`: include a datalist of stops
87
+ - `delta`: include `default`, often symmetric min/max
88
+ - Text field on by default; `text="false"` for compact rows
89
+ - `transform` when internal scale ≠ display scale
90
+ - `variant="classic"` only when the old look is required
91
+
92
+ Prompt style: imperative, include direction, tag, and behavior-critical attrs.
166
93
 
167
94
  ```txt
168
- Prompt pattern:
169
95
  Use a horizontal fig-field, with a fig-slider, min=0 max=100 text=true units=%. With a label of Opacity.
170
96
  ```
171
97
 
172
- ```html
173
- <!-- Slider type/variant examples -->
174
- <fig-field direction="horizontal">
175
- <label>Opacity</label>
176
- <fig-slider type="opacity" value="0.75" color="#0D99FF" units="%" text="true" full></fig-slider>
177
- </fig-field>
178
- <fig-field direction="horizontal">
179
- <label>Hue</label>
180
- <fig-slider type="hue" value="180" text="true" full></fig-slider>
181
- </fig-field>
182
- <fig-field direction="horizontal">
183
- <label>Offset</label>
184
- <fig-slider type="delta" value="0" default="0" min="-5" max="5" step="0.25" text="true" full></fig-slider>
185
- </fig-field>
186
- ```
187
-
188
98
  ## Workflow
189
99
 
190
- 1. **Identify property intent.** Determine if control is boolean, discrete choice, continuous numeric, color/fill, media, or motion.
191
- 2. **Pick the canonical FigUI3 control.** Avoid custom alternatives unless required.
192
- 3. **Compose row structure.** Use horizontal `fig-field`, then label + control.
193
- 4. **Set defaults and attrs explicitly.** Include values/ranges/units so behavior is deterministic.
194
- 5. **Verify panel consistency.** Check row spacing, width, and theme parity against existing PropKit sections.
195
- 6. **Validate events and interactions.** Ensure controls emit usable `input`/`change` and behave well in keyboard workflows.
196
-
197
- ## Delivery Checklist
198
-
199
- - Confirm prompts include all behavior-critical attrs (`value`, `min`, `max`, `step`, `units`, `type`, `variant` as needed).
200
- - Confirm control choice matches intent (continuous vs discrete vs boolean vs exact numeric entry).
201
- - Verify row density and panel width feel consistent with existing PropKit sections.
202
- - Verify keyboard navigation and label association for every field row.
203
- - Verify changes in `playground/src/data/sections.ts` still mirror recommended patterns in this skill.
204
-
205
- ## Quick Reference
206
-
207
- ```txt
208
- Common PropKit controls:
209
- - fig-image
210
- - fig-input-color
211
- - fig-input-fill
212
- - fig-slider
213
- - fig-switch
214
- - fig-dropdown
215
- - fig-segmented-control
216
- - fig-easing-curve
217
- - fig-input-angle
218
- ```
219
-
220
- ## Primary Files
100
+ 1. Identify intent (boolean, discrete, continuous, color/fill, media, motion).
101
+ 2. Pick core vs lab wrapper.
102
+ 3. Compose the row; set defaults explicitly.
103
+ 4. Check `/propskit` or `/propskit/lab` for an existing example before inventing markup.
104
+ 5. Verify `input`/`change` and keyboard.
221
105
 
222
- - `playground/src/data/sections.ts` - canonical PropKit examples and prompt-copy behavior
223
- - `fig.js` - control behavior and emitted events
224
- - `components.css` - visual treatment and layout constraints
225
- - `README.md` - component API details and usage
106
+ Primary files: `playground/src/data/sections.ts`, `playground/src/data/labSections.ts`, `fig.js`, `fig-lab.js`.
package/README.md CHANGED
@@ -72,6 +72,13 @@ Or use a CDN:
72
72
  <script type="module" src="https://unpkg.com/@rogieking/figui3@latest/dist/fig.js"></script>
73
73
  ```
74
74
 
75
+ Agent skills ship in `.cursor/skills/` (included in the npm package):
76
+
77
+ - `figui3` — core `fig.js` components
78
+ - `fig-editor` — `fig-select` and `fig-fill-picker`
79
+ - `fig-lab` — experimental `propskit-*`, canvas, AI, angle, reorder
80
+ - `propkit` — `/propskit` property-row composition
81
+
75
82
  Minimal example:
76
83
 
77
84
  ```html
@@ -90,6 +97,7 @@ Minimal example:
90
97
  |---|---|---|
91
98
  | [Button](#button) | `<fig-button>` | Buttons with variants, toggle, select, upload |
92
99
  | [Dropdown](#dropdown) | `<fig-dropdown>` | Native select wrapper with Figma styling |
100
+ | [Select](#select) | `<fig-select>` | Custom listbox select (requires `fig-editor.js`) |
93
101
  | [Combo Input](#combo-input) | `<fig-combo-input>` | Text input with dropdown suggestions |
94
102
  | [Checkbox](#checkbox) | `<fig-checkbox>` | Checkbox with indeterminate state |
95
103
  | [Radio](#radio) | `<fig-radio>` | Radio button |
@@ -192,6 +200,7 @@ Minimal example:
192
200
  | `value` | string | — | Selected value |
193
201
  | `type` | string | `"select"` | `"select"` or `"dropdown"` |
194
202
  | `label` | string | — | Accessible label for the generated native `<select>` |
203
+ | `variant` | string | — | `"ghost"` for a borderless control with secondary hover fill |
195
204
  | `disabled` | boolean | `false` | Disabled state |
196
205
 
197
206
  ```html
@@ -205,6 +214,38 @@ Keyboard activation follows the native select pattern. Enter opens the closed pi
205
214
 
206
215
  ---
207
216
 
217
+ #### Select
218
+
219
+ `<fig-select>` — [demo](https://rog.ie/figui3/#select)
220
+
221
+ Custom listbox select with overflow chevrons, grouped options, and sticky separators. Import `fig-editor.js` and `fig-editor.css`. Prefer this over `fig-dropdown` for Figma-style menus.
222
+
223
+ | Attribute | Type | Default | Description |
224
+ |---|---|---|---|
225
+ | `value` | string | — | Selected option value |
226
+ | `label` | string | — | Closed-state / accessible label |
227
+ | `options` | string | — | Comma, newline, or JSON options if no authored `fig-select-option` children |
228
+ | `variant` | string | — | `"ghost"` for a borderless control with secondary hover fill |
229
+ | `full` | boolean | `false` | Stretch to available width |
230
+ | `position` | string | `"bottom left"` | Popup position |
231
+ | `disabled` | boolean | `false` | Disabled state |
232
+
233
+ Author options in `<fig-select-options>`, or pass `options`. Use `label` on `<fig-select-option>` when the option content is rich. `fig-separator` with `sticky` pins group labels while scrolling.
234
+
235
+ ```html
236
+ <fig-select value="center" label="Align">
237
+ <fig-select-options>
238
+ <fig-select-option value="left">Left</fig-select-option>
239
+ <fig-select-option value="center">Center</fig-select-option>
240
+ <fig-select-option value="right">Right</fig-select-option>
241
+ </fig-select-options>
242
+ </fig-select>
243
+ ```
244
+
245
+ **Events:** `input`, `change`, `optionhover` (`detail` is the hovered option value).
246
+
247
+ ---
248
+
208
249
  #### Combo Input
209
250
 
210
251
  `<fig-combo-input>` — [demo](https://rog.ie/figui3/#combo-input)
@@ -1456,7 +1497,7 @@ A section header component.
1456
1497
  `<fig-layer>` — [demo](https://rog.ie/figui3/#layer)
1457
1498
 
1458
1499
  A collapsible layer list item with expand/collapse and visibility toggling. Supports nesting and exposes `role="treeitem"`, `aria-expanded`, `aria-hidden`, `aria-disabled`, and a keyboard-toggleable chevron button.
1459
- Import `fig-layer.js` and `fig-layer.css` to register and style it. `fig-editor.js` also includes the layer registration.
1500
+ Import `fig-layer.js` and `fig-layer.css` to register and style it.
1460
1501
 
1461
1502
  | Attribute | Type | Default | Description |
1462
1503
  |---|---|---|---|
package/components.css CHANGED
@@ -3346,6 +3346,20 @@ fig-dropdown {
3346
3346
  display: flex;
3347
3347
  width: 100%;
3348
3348
  }
3349
+
3350
+ &[variant="ghost"] {
3351
+ border-radius: var(--radius-medium);
3352
+ background: transparent;
3353
+
3354
+ > select {
3355
+ box-shadow: none;
3356
+ background: transparent;
3357
+ }
3358
+
3359
+ &:hover:not([disabled]):not([disabled="false"]) {
3360
+ background-color: var(--figma-color-bg-secondary);
3361
+ }
3362
+ }
3349
3363
  }
3350
3364
 
3351
3365
  fig-checkbox,
@@ -5639,6 +5653,23 @@ fig-menu-item {
5639
5653
  line-height: var(--spacer-4);
5640
5654
  min-height: var(--spacer-4);
5641
5655
  }
5656
+
5657
+ &:first-child{
5658
+ &::before {
5659
+ display: none;
5660
+ }
5661
+ }
5662
+
5663
+ &[sticky]:not([sticky="false"]) {
5664
+ position: sticky;
5665
+ top: 0;
5666
+ z-index: 1;
5667
+ background: var(--fig-popup-bg-color, var(--figma-color-bg));
5668
+
5669
+ :is(fig-select-options, .fig-menu-options).overflow-start > & {
5670
+ top: var(--fig-vertical-overflow-size, var(--spacer-4));
5671
+ }
5672
+ }
5642
5673
  }
5643
5674
  }
5644
5675