@rogieking/figui3 2.32.0 → 2.33.1
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/.cursor/skills/figui3/SKILL.md +1 -1
- package/.cursor/skills/propkit/SKILL.md +4 -4
- package/README.md +66 -7
- package/components.css +33 -12
- package/fig.js +13 -6
- package/package.json +4 -7
- package/index.html +0 -5040
- package/propkit.html +0 -1642
|
@@ -143,7 +143,7 @@ export default defineConfig({
|
|
|
143
143
|
### Documentation and Demos
|
|
144
144
|
|
|
145
145
|
- Update `README.md` component docs when public API or behavior changes.
|
|
146
|
-
- Update demo
|
|
146
|
+
- Update demo surfaces (`index.html` and `playground/` routes where relevant) for visible behavior changes.
|
|
147
147
|
- Prefer realistic examples that mirror plugin/property panel usage.
|
|
148
148
|
- If introducing an experimental feature, document activation and fallback behavior clearly.
|
|
149
149
|
|
|
@@ -1,6 +1,6 @@
|
|
|
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 `
|
|
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.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ Patterns for composing clean, production-ready Figma property panels with FigUI3
|
|
|
13
13
|
## Current Project Context
|
|
14
14
|
|
|
15
15
|
```json
|
|
16
|
-
!`node -e "const fs=require('fs'); const ok=fs.existsSync('
|
|
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
17
|
```
|
|
18
18
|
|
|
19
19
|
## Principles
|
|
@@ -199,7 +199,7 @@ Use a horizontal fig-field, with a fig-slider, min=0 max=100 text=true units=%.
|
|
|
199
199
|
- Confirm control choice matches intent (continuous vs discrete vs boolean vs exact numeric entry).
|
|
200
200
|
- Verify row density and panel width feel consistent with existing PropKit sections.
|
|
201
201
|
- Verify keyboard navigation and label association for every field row.
|
|
202
|
-
- Verify changes in `
|
|
202
|
+
- Verify changes in `playground/src/data/sections.ts` still mirror recommended patterns in this skill.
|
|
203
203
|
|
|
204
204
|
## Quick Reference
|
|
205
205
|
|
|
@@ -218,7 +218,7 @@ Common PropKit controls:
|
|
|
218
218
|
|
|
219
219
|
## Primary Files
|
|
220
220
|
|
|
221
|
-
- `
|
|
221
|
+
- `playground/src/data/sections.ts` - canonical PropKit examples and prompt-copy behavior
|
|
222
222
|
- `fig.js` - control behavior and emitted events
|
|
223
223
|
- `components.css` - visual treatment and layout constraints
|
|
224
224
|
- `README.md` - component API details and usage
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ A lightweight, zero-dependency web components library for building Figma plugin
|
|
|
9
9
|
|
|
10
10
|
View the interactive component documentation at **[rogie.github.io/figui3](https://rogie.github.io/figui3/)**
|
|
11
11
|
|
|
12
|
-
The
|
|
12
|
+
The docs page source is kept in this repo as `old.html` for reference and local testing.
|
|
13
13
|
|
|
14
14
|
## Features
|
|
15
15
|
|
|
@@ -62,7 +62,26 @@ Or via esm.sh:
|
|
|
62
62
|
git clone https://github.com/rogie/figui3.git
|
|
63
63
|
cd figui3
|
|
64
64
|
bun install
|
|
65
|
-
bun dev
|
|
65
|
+
bun dev # Core component docs at http://localhost:3000
|
|
66
|
+
npm run dev:playground # Interactive playground app (routes: /figui3, /propkit)
|
|
67
|
+
npm run build:playground # Build playground app
|
|
68
|
+
bun build # Build dist/fig.js
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Playground (`/figui3` and `/propkit`)
|
|
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
|
+
- Live preview, attributes editing, and code view stay synchronized.
|
|
78
|
+
- Attribute controls write real component markup and preserve internal-only playground metadata where needed.
|
|
79
|
+
|
|
80
|
+
Open locally:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm run dev:playground
|
|
84
|
+
# then visit http://localhost:5173/figui3 or http://localhost:5173/propkit
|
|
66
85
|
```
|
|
67
86
|
|
|
68
87
|
## Quick Start
|
|
@@ -215,6 +234,42 @@ A modal dialog component with drag support.
|
|
|
215
234
|
|
|
216
235
|
---
|
|
217
236
|
|
|
237
|
+
### Popup (`<fig-popup>`)
|
|
238
|
+
|
|
239
|
+
An anchored floating surface built on `<dialog>`, with collision-aware positioning and optional popover beak styling.
|
|
240
|
+
|
|
241
|
+
| Attribute | Type | Default | Description |
|
|
242
|
+
|-----------|------|---------|-------------|
|
|
243
|
+
| `anchor` | string | — | CSS selector for the anchor element |
|
|
244
|
+
| `position` | string | `"top center"` | Placement (`"top"`, `"left"`, `"center right"`, etc.) |
|
|
245
|
+
| `offset` | string | `"0 0"` | X/Y offset in px-like tokens (`"8 8"`) |
|
|
246
|
+
| `viewport-margin` | string | `"8"` | Viewport safety margin (CSS shorthand style) |
|
|
247
|
+
| `variant` | string | — | Use `"popover"` to render a beak |
|
|
248
|
+
| `theme` | string | — | `"light"`, `"dark"`, or `"menu"` |
|
|
249
|
+
| `closedby` | string | `"any"` | Dismiss behavior: `"any"`, `"closerequest"`, `"none"` |
|
|
250
|
+
| `open` | boolean/string | `false` | Open when present and not `"false"` |
|
|
251
|
+
|
|
252
|
+
```html
|
|
253
|
+
<fig-button id="popup-anchor" onclick="const p=document.getElementById('demo-popup'); p.toggleAttribute('open');">
|
|
254
|
+
Toggle popup
|
|
255
|
+
</fig-button>
|
|
256
|
+
|
|
257
|
+
<dialog
|
|
258
|
+
id="demo-popup"
|
|
259
|
+
is="fig-popup"
|
|
260
|
+
anchor="#popup-anchor"
|
|
261
|
+
position="center right"
|
|
262
|
+
offset="8 8"
|
|
263
|
+
viewport-margin="8"
|
|
264
|
+
variant="popover"
|
|
265
|
+
closedby="none"
|
|
266
|
+
>
|
|
267
|
+
<fig-header><h3>Popup</h3></fig-header>
|
|
268
|
+
</dialog>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
218
273
|
### Tabs (`<fig-tabs>` / `<fig-tab>`)
|
|
219
274
|
|
|
220
275
|
Tabbed navigation component.
|
|
@@ -529,6 +584,7 @@ A form field wrapper with flexible layout. Automatically links `<label>` element
|
|
|
529
584
|
| Attribute | Type | Default | Description |
|
|
530
585
|
|-----------|------|---------|-------------|
|
|
531
586
|
| `direction` | string | `"column"` | Layout: `"column"`, `"row"`, `"horizontal"` |
|
|
587
|
+
| `columns` | string | — | Optional horizontal split preset: `"thirds"` or `"half"` |
|
|
532
588
|
| `label` | string | — | Programmatically set the label text |
|
|
533
589
|
|
|
534
590
|
```html
|
|
@@ -543,6 +599,12 @@ A form field wrapper with flexible layout. Automatically links `<label>` element
|
|
|
543
599
|
<label>Volume</label>
|
|
544
600
|
<fig-slider min="0" max="100" value="50"></fig-slider>
|
|
545
601
|
</fig-field>
|
|
602
|
+
|
|
603
|
+
<!-- Horizontal with 1/3 + 2/3 split -->
|
|
604
|
+
<fig-field direction="horizontal" columns="thirds">
|
|
605
|
+
<label>Opacity</label>
|
|
606
|
+
<fig-slider value="50"></fig-slider>
|
|
607
|
+
</fig-field>
|
|
546
608
|
```
|
|
547
609
|
|
|
548
610
|
---
|
|
@@ -674,16 +736,13 @@ A toast notification component.
|
|
|
674
736
|
| `duration` | number | `5000` | Auto-dismiss ms (0 = no dismiss) |
|
|
675
737
|
| `offset` | number | `16` | Distance from bottom |
|
|
676
738
|
| `theme` | string | `"dark"` | Theme: `"dark"`, `"light"`, `"danger"`, `"brand"` |
|
|
677
|
-
| `open` | boolean | `false` | Whether visible |
|
|
678
739
|
|
|
679
740
|
```html
|
|
741
|
+
<fig-button onclick="document.getElementById('myToast').showToast()">Show toast</fig-button>
|
|
742
|
+
|
|
680
743
|
<fig-toast id="myToast" theme="brand" duration="3000">
|
|
681
744
|
Settings saved successfully!
|
|
682
745
|
</fig-toast>
|
|
683
|
-
|
|
684
|
-
<script>
|
|
685
|
-
document.getElementById('myToast').show();
|
|
686
|
-
</script>
|
|
687
746
|
```
|
|
688
747
|
|
|
689
748
|
---
|
package/components.css
CHANGED
|
@@ -1212,8 +1212,6 @@ fig-chit {
|
|
|
1212
1212
|
background-repeat: no-repeat;
|
|
1213
1213
|
border-radius: 0.125rem;
|
|
1214
1214
|
box-shadow: inset 0 0 0 1px var(--figma-color-bordertranslucent);
|
|
1215
|
-
}
|
|
1216
|
-
&[data-type="image"]::after {
|
|
1217
1215
|
mask-image: linear-gradient(
|
|
1218
1216
|
to right,
|
|
1219
1217
|
black 0%,
|
|
@@ -2355,6 +2353,7 @@ dialog[is="fig-dialog"] {
|
|
|
2355
2353
|
|
|
2356
2354
|
dialog[is="fig-popup"] {
|
|
2357
2355
|
--z-index: 999999;
|
|
2356
|
+
--beak-offset: 1px;
|
|
2358
2357
|
z-index: var(--z-index);
|
|
2359
2358
|
position: fixed;
|
|
2360
2359
|
margin: 0;
|
|
@@ -2419,13 +2418,13 @@ dialog[is="fig-popup"] {
|
|
|
2419
2418
|
}
|
|
2420
2419
|
|
|
2421
2420
|
&[data-beak-side="left"]:after {
|
|
2422
|
-
left:
|
|
2421
|
+
left: 6px;
|
|
2423
2422
|
top: var(--beak-offset, 50%);
|
|
2424
2423
|
transform: translate(-100%, -50%) rotate(90deg);
|
|
2425
2424
|
}
|
|
2426
2425
|
|
|
2427
2426
|
&[data-beak-side="right"]:after {
|
|
2428
|
-
left: calc(100% -
|
|
2427
|
+
left: calc(100% - 6px);
|
|
2429
2428
|
top: var(--beak-offset, 50%);
|
|
2430
2429
|
transform: translate(0, -50%) rotate(-90deg);
|
|
2431
2430
|
}
|
|
@@ -2894,11 +2893,36 @@ fig-field,
|
|
|
2894
2893
|
gap: var(--spacer-2);
|
|
2895
2894
|
align-items: start;
|
|
2896
2895
|
flex-direction: row;
|
|
2897
|
-
width: auto;
|
|
2898
2896
|
|
|
2899
2897
|
& > label {
|
|
2900
2898
|
min-width: 4rem;
|
|
2901
2899
|
}
|
|
2900
|
+
&[columns="thirds"] {
|
|
2901
|
+
display: grid;
|
|
2902
|
+
grid-template-columns: repeat(3, 1fr);
|
|
2903
|
+
gap: var(--spacer-2);
|
|
2904
|
+
|
|
2905
|
+
& > label {
|
|
2906
|
+
grid-column: 1;
|
|
2907
|
+
}
|
|
2908
|
+
|
|
2909
|
+
& > label ~ * {
|
|
2910
|
+
grid-column: 2 / span 2;
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
&[columns="half"] {
|
|
2914
|
+
display: grid;
|
|
2915
|
+
grid-template-columns: repeat(2, 1fr);
|
|
2916
|
+
gap: var(--spacer-2);
|
|
2917
|
+
|
|
2918
|
+
& > label {
|
|
2919
|
+
grid-column: 1;
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
& > label ~ * {
|
|
2923
|
+
grid-column: 2 / span 2;
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2902
2926
|
}
|
|
2903
2927
|
}
|
|
2904
2928
|
|
|
@@ -3142,7 +3166,7 @@ fig-input-angle {
|
|
|
3142
3166
|
|
|
3143
3167
|
/* Layer */
|
|
3144
3168
|
fig-layer {
|
|
3145
|
-
--indent: var(--spacer-
|
|
3169
|
+
--indent: var(--spacer-2);
|
|
3146
3170
|
display: block;
|
|
3147
3171
|
color: var(--figma-color-text);
|
|
3148
3172
|
position: relative;
|
|
@@ -3154,14 +3178,11 @@ fig-layer {
|
|
|
3154
3178
|
& > .fig-layer-row {
|
|
3155
3179
|
& > .fig-layer-chevron {
|
|
3156
3180
|
visibility: visible;
|
|
3181
|
+
margin-left: calc(-1 * (var(--spacer-3) + var(--spacer-3) + 6px));
|
|
3182
|
+
margin-right: 0;
|
|
3157
3183
|
}
|
|
3158
3184
|
}
|
|
3159
3185
|
}
|
|
3160
|
-
&:not(:has(fig-layer)):not(:has(.fig-layer-icon)) {
|
|
3161
|
-
& > .fig-layer-row {
|
|
3162
|
-
padding-left: var(--spacer-3);
|
|
3163
|
-
}
|
|
3164
|
-
}
|
|
3165
3186
|
|
|
3166
3187
|
&:not(:has(.fig-layer-icon)) {
|
|
3167
3188
|
& > .fig-layer-row {
|
|
@@ -3186,7 +3207,7 @@ fig-layer {
|
|
|
3186
3207
|
mask-position: center;
|
|
3187
3208
|
display: flex;
|
|
3188
3209
|
visibility: hidden;
|
|
3189
|
-
margin-left: calc(-1 * (var(--spacer-3) + var(--spacer-
|
|
3210
|
+
margin-left: calc(-1 * (var(--spacer-3) + var(--spacer-3)));
|
|
3190
3211
|
margin-right: calc(-1 * (var(--spacer-1) + 2px));
|
|
3191
3212
|
background: var(--figma-color-text-tertiary);
|
|
3192
3213
|
width: var(--spacer-3);
|
package/fig.js
CHANGED
|
@@ -1813,17 +1813,24 @@ class FigPopup extends HTMLDialogElement {
|
|
|
1813
1813
|
|
|
1814
1814
|
const anchorCenterX = anchorRect.left + anchorRect.width / 2;
|
|
1815
1815
|
const anchorCenterY = anchorRect.top + anchorRect.height / 2;
|
|
1816
|
+
const measuredRect = this.getBoundingClientRect();
|
|
1817
|
+
const rect =
|
|
1818
|
+
measuredRect.width > 0 && measuredRect.height > 0 ? measuredRect : popupRect;
|
|
1819
|
+
// Always use the rendered popup rect so beak alignment matches real final placement.
|
|
1820
|
+
const resolvedLeft = rect.left;
|
|
1821
|
+
const resolvedTop = rect.top;
|
|
1822
|
+
const edgeInset = 10;
|
|
1816
1823
|
|
|
1817
1824
|
let beakOffset;
|
|
1818
1825
|
if (beakSide === "top" || beakSide === "bottom") {
|
|
1819
|
-
beakOffset = anchorCenterX -
|
|
1820
|
-
const min =
|
|
1821
|
-
const max = Math.max(min,
|
|
1826
|
+
beakOffset = anchorCenterX - resolvedLeft;
|
|
1827
|
+
const min = edgeInset;
|
|
1828
|
+
const max = Math.max(min, rect.width - edgeInset);
|
|
1822
1829
|
beakOffset = Math.min(max, Math.max(min, beakOffset));
|
|
1823
1830
|
} else {
|
|
1824
|
-
beakOffset = anchorCenterY -
|
|
1825
|
-
const min =
|
|
1826
|
-
const max = Math.max(min,
|
|
1831
|
+
beakOffset = anchorCenterY - resolvedTop;
|
|
1832
|
+
const min = edgeInset;
|
|
1833
|
+
const max = Math.max(min, rect.height - edgeInset);
|
|
1827
1834
|
beakOffset = Math.min(max, Math.max(min, beakOffset));
|
|
1828
1835
|
}
|
|
1829
1836
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rogieking/figui3",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.33.1",
|
|
4
4
|
"description": "A lightweight web components library for building Figma plugin and widget UIs with native look and feel",
|
|
5
5
|
"author": "Rogie King",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,16 +12,13 @@
|
|
|
12
12
|
"./fig.js": "./fig.js",
|
|
13
13
|
"./fig.css": "./fig.css",
|
|
14
14
|
"./base.css": "./base.css",
|
|
15
|
-
"./components.css": "./components.css"
|
|
16
|
-
"./propkit.html": "./propkit.html"
|
|
15
|
+
"./components.css": "./components.css"
|
|
17
16
|
},
|
|
18
17
|
"files": [
|
|
19
18
|
"fig.js",
|
|
20
19
|
"fig.css",
|
|
21
20
|
"base.css",
|
|
22
21
|
"components.css",
|
|
23
|
-
"index.html",
|
|
24
|
-
"propkit.html",
|
|
25
22
|
"dist/",
|
|
26
23
|
".cursor/skills/",
|
|
27
24
|
"README.md",
|
|
@@ -33,8 +30,8 @@
|
|
|
33
30
|
"scripts": {
|
|
34
31
|
"dev": "bun --hot server.ts",
|
|
35
32
|
"build": "bun build fig.js --minify --outdir dist",
|
|
36
|
-
"dev:
|
|
37
|
-
"build:
|
|
33
|
+
"dev:playground": "cd playground && npm run dev",
|
|
34
|
+
"build:playground": "cd playground && npm run build"
|
|
38
35
|
},
|
|
39
36
|
"repository": {
|
|
40
37
|
"type": "git",
|