@rogieking/figui3 2.14.0 → 2.15.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 +30 -0
- package/components.css +6 -2
- package/fig.js +48 -11
- package/index.html +67 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -911,6 +911,36 @@ const onChange = (e) => {
|
|
|
911
911
|
|
|
912
912
|
---
|
|
913
913
|
|
|
914
|
+
## Breaking Changes / Migration
|
|
915
|
+
|
|
916
|
+
### v2.15.0: Experimental Features
|
|
917
|
+
|
|
918
|
+
The `experimental` attribute now controls experimental CSS features instead of `variant="neue"`.
|
|
919
|
+
|
|
920
|
+
**Before (deprecated):**
|
|
921
|
+
```html
|
|
922
|
+
<fig-dropdown variant="neue">
|
|
923
|
+
<option>Option 1</option>
|
|
924
|
+
</fig-dropdown>
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
**After:**
|
|
928
|
+
```html
|
|
929
|
+
<fig-dropdown experimental="modern">
|
|
930
|
+
<option>Option 1</option>
|
|
931
|
+
</fig-dropdown>
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
The `experimental` attribute uses space-separated feature names for granular control:
|
|
935
|
+
- `experimental="modern"` - Enables the customizable select picker (`::picker(select)`, `appearance: base-select`)
|
|
936
|
+
- Future features can be added: `experimental="modern popover"`
|
|
937
|
+
|
|
938
|
+
Note: `variant="neue"` on `fig-slider` continues to work for visual styling.
|
|
939
|
+
|
|
940
|
+
See [CHANGELOG.md](CHANGELOG.md) for full details.
|
|
941
|
+
|
|
942
|
+
---
|
|
943
|
+
|
|
914
944
|
## Theming
|
|
915
945
|
|
|
916
946
|
FigUI3 automatically adapts to light and dark themes using CSS custom properties. The library uses Figma's color variable naming convention:
|
package/components.css
CHANGED
|
@@ -478,7 +478,7 @@ input[type="text"][list] {
|
|
|
478
478
|
}
|
|
479
479
|
|
|
480
480
|
@supports (appearance: base-select) {
|
|
481
|
-
fig-dropdown[
|
|
481
|
+
fig-dropdown[experimental~="modern"] {
|
|
482
482
|
&[type="dropdown"] {
|
|
483
483
|
select:before {
|
|
484
484
|
content: attr(aria-label);
|
|
@@ -517,11 +517,14 @@ input[type="text"][list] {
|
|
|
517
517
|
|
|
518
518
|
option {
|
|
519
519
|
display: flex;
|
|
520
|
-
gap: var(--spacer-
|
|
520
|
+
gap: var(--spacer-2);
|
|
521
521
|
padding: 0 var(--spacer-4) 0 calc(var(--spacer-1) * 2 + var(--spacer-1));
|
|
522
522
|
font-weight: var(--body-medium-fontWeight);
|
|
523
523
|
color: var(--figma-color-text-menu);
|
|
524
524
|
position: relative;
|
|
525
|
+
& * {
|
|
526
|
+
color: inherit;
|
|
527
|
+
}
|
|
525
528
|
&[hidden] {
|
|
526
529
|
display: none;
|
|
527
530
|
}
|
|
@@ -598,6 +601,7 @@ input[type="text"][list] {
|
|
|
598
601
|
/* https://codepen.io/editor/argyleink/pen/019c1f28-bbc2-7bac-ad4a-a7e41d3730f1 */
|
|
599
602
|
::picker(select) {
|
|
600
603
|
appearance: base-select;
|
|
604
|
+
color-scheme: dark;
|
|
601
605
|
|
|
602
606
|
/* Appearance/style */
|
|
603
607
|
scrollbar-width: thin;
|
package/fig.js
CHANGED
|
@@ -2538,6 +2538,8 @@ class FigInputColor extends HTMLElement {
|
|
|
2538
2538
|
const useFigmaPicker = this.picker === "figma";
|
|
2539
2539
|
const hidePicker = this.picker === "false";
|
|
2540
2540
|
const showAlpha = this.getAttribute("alpha") === "true";
|
|
2541
|
+
const experimental = this.getAttribute("experimental");
|
|
2542
|
+
const expAttr = experimental ? `experimental="${experimental}"` : "";
|
|
2541
2543
|
|
|
2542
2544
|
let html = ``;
|
|
2543
2545
|
if (this.getAttribute("text")) {
|
|
@@ -2562,7 +2564,7 @@ class FigInputColor extends HTMLElement {
|
|
|
2562
2564
|
let swatchElement = "";
|
|
2563
2565
|
if (!hidePicker) {
|
|
2564
2566
|
swatchElement = useFigmaPicker
|
|
2565
|
-
? `<fig-fill-picker mode="solid" ${
|
|
2567
|
+
? `<fig-fill-picker mode="solid" ${expAttr} ${
|
|
2566
2568
|
showAlpha ? "" : 'alpha="false"'
|
|
2567
2569
|
} value='{"type":"solid","color":"${this.hexOpaque}","opacity":${
|
|
2568
2570
|
this.alpha
|
|
@@ -2580,7 +2582,7 @@ class FigInputColor extends HTMLElement {
|
|
|
2580
2582
|
html = ``;
|
|
2581
2583
|
} else {
|
|
2582
2584
|
html = useFigmaPicker
|
|
2583
|
-
? `<fig-fill-picker mode="solid" ${
|
|
2585
|
+
? `<fig-fill-picker mode="solid" ${expAttr} ${
|
|
2584
2586
|
showAlpha ? "" : 'alpha="false"'
|
|
2585
2587
|
} value='{"type":"solid","color":"${this.hexOpaque}","opacity":${
|
|
2586
2588
|
this.alpha
|
|
@@ -2772,7 +2774,7 @@ class FigInputColor extends HTMLElement {
|
|
|
2772
2774
|
}
|
|
2773
2775
|
|
|
2774
2776
|
static get observedAttributes() {
|
|
2775
|
-
return ["value", "style", "mode", "picker"];
|
|
2777
|
+
return ["value", "style", "mode", "picker", "experimental"];
|
|
2776
2778
|
}
|
|
2777
2779
|
|
|
2778
2780
|
get mode() {
|
|
@@ -2954,7 +2956,7 @@ class FigInputFill extends HTMLElement {
|
|
|
2954
2956
|
}
|
|
2955
2957
|
|
|
2956
2958
|
static get observedAttributes() {
|
|
2957
|
-
return ["value", "disabled", "mode"];
|
|
2959
|
+
return ["value", "disabled", "mode", "experimental"];
|
|
2958
2960
|
}
|
|
2959
2961
|
|
|
2960
2962
|
connectedCallback() {
|
|
@@ -3105,11 +3107,12 @@ class FigInputFill extends HTMLElement {
|
|
|
3105
3107
|
}
|
|
3106
3108
|
|
|
3107
3109
|
const modeAttr = this.getAttribute("mode");
|
|
3110
|
+
const experimentalAttr = this.getAttribute("experimental");
|
|
3108
3111
|
this.innerHTML = `
|
|
3109
3112
|
<div class="input-combo">
|
|
3110
3113
|
<fig-fill-picker value='${fillPickerValue}' ${
|
|
3111
3114
|
disabled ? "disabled" : ""
|
|
3112
|
-
} ${modeAttr ? `mode="${modeAttr}"` : ""}></fig-fill-picker>
|
|
3115
|
+
} ${modeAttr ? `mode="${modeAttr}"` : ""} ${experimentalAttr ? `experimental="${experimentalAttr}"` : ""}></fig-fill-picker>
|
|
3113
3116
|
${controlsHtml}
|
|
3114
3117
|
</div>`;
|
|
3115
3118
|
|
|
@@ -3551,6 +3554,17 @@ class FigInputFill extends HTMLElement {
|
|
|
3551
3554
|
this.#render();
|
|
3552
3555
|
}
|
|
3553
3556
|
break;
|
|
3557
|
+
case "mode":
|
|
3558
|
+
case "experimental":
|
|
3559
|
+
// Pass through to internal fill picker
|
|
3560
|
+
if (this.#fillPicker) {
|
|
3561
|
+
if (newValue) {
|
|
3562
|
+
this.#fillPicker.setAttribute(name, newValue);
|
|
3563
|
+
} else {
|
|
3564
|
+
this.#fillPicker.removeAttribute(name);
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
break;
|
|
3554
3568
|
}
|
|
3555
3569
|
}
|
|
3556
3570
|
}
|
|
@@ -3896,6 +3910,8 @@ class FigComboInput extends HTMLElement {
|
|
|
3896
3910
|
this.options = this.getOptionsFromAttribute();
|
|
3897
3911
|
this.placeholder = this.getAttribute("placeholder") || "";
|
|
3898
3912
|
this.value = this.getAttribute("value") || "";
|
|
3913
|
+
const experimental = this.getAttribute("experimental");
|
|
3914
|
+
const expAttr = experimental ? `experimental="${experimental}"` : "";
|
|
3899
3915
|
this.innerHTML = `<div class="input-combo">
|
|
3900
3916
|
<fig-input-text placeholder="${this.placeholder}">
|
|
3901
3917
|
</fig-input-text>
|
|
@@ -3903,7 +3919,7 @@ class FigComboInput extends HTMLElement {
|
|
|
3903
3919
|
<svg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
|
3904
3920
|
<path d='M5.87868 7.12132L8 9.24264L10.1213 7.12132' stroke='currentColor' stroke-opacity="0.9" stroke-linecap='round'/>
|
|
3905
3921
|
</svg>
|
|
3906
|
-
<fig-dropdown type="dropdown">
|
|
3922
|
+
<fig-dropdown type="dropdown" ${expAttr}>
|
|
3907
3923
|
${this.options
|
|
3908
3924
|
.map((option) => `<option>${option}</option>`)
|
|
3909
3925
|
.join("")}
|
|
@@ -3932,7 +3948,7 @@ class FigComboInput extends HTMLElement {
|
|
|
3932
3948
|
this.value = this.input.value;
|
|
3933
3949
|
}
|
|
3934
3950
|
static get observedAttributes() {
|
|
3935
|
-
return ["options", "placeholder", "value", "disabled"];
|
|
3951
|
+
return ["options", "placeholder", "value", "disabled", "experimental"];
|
|
3936
3952
|
}
|
|
3937
3953
|
focus() {
|
|
3938
3954
|
this.input.focus();
|
|
@@ -3979,6 +3995,15 @@ class FigComboInput extends HTMLElement {
|
|
|
3979
3995
|
case "disabled":
|
|
3980
3996
|
this.#applyDisabled(newValue !== null && newValue !== "false");
|
|
3981
3997
|
break;
|
|
3998
|
+
case "experimental":
|
|
3999
|
+
if (this.dropdown) {
|
|
4000
|
+
if (newValue) {
|
|
4001
|
+
this.dropdown.setAttribute("experimental", newValue);
|
|
4002
|
+
} else {
|
|
4003
|
+
this.dropdown.removeAttribute("experimental");
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
4006
|
+
break;
|
|
3982
4007
|
}
|
|
3983
4008
|
}
|
|
3984
4009
|
}
|
|
@@ -5323,7 +5348,7 @@ class FigFillPicker extends HTMLElement {
|
|
|
5323
5348
|
}
|
|
5324
5349
|
|
|
5325
5350
|
static get observedAttributes() {
|
|
5326
|
-
return ["value", "disabled", "alpha", "mode"];
|
|
5351
|
+
return ["value", "disabled", "alpha", "mode", "experimental"];
|
|
5327
5352
|
}
|
|
5328
5353
|
|
|
5329
5354
|
connectedCallback() {
|
|
@@ -5607,6 +5632,9 @@ class FigFillPicker extends HTMLElement {
|
|
|
5607
5632
|
}
|
|
5608
5633
|
|
|
5609
5634
|
// Build header content - label if single mode, dropdown if multiple
|
|
5635
|
+
const experimental = this.getAttribute("experimental");
|
|
5636
|
+
const expAttr = experimental ? `experimental="${experimental}"` : "";
|
|
5637
|
+
|
|
5610
5638
|
let headerContent;
|
|
5611
5639
|
if (allowedModes.length === 1) {
|
|
5612
5640
|
headerContent = `<span class="fig-fill-picker-type-label">${modeLabels[allowedModes[0]]}</span>`;
|
|
@@ -5614,7 +5642,7 @@ class FigFillPicker extends HTMLElement {
|
|
|
5614
5642
|
const options = allowedModes
|
|
5615
5643
|
.map((m) => `<option value="${m}">${modeLabels[m]}</option>`)
|
|
5616
5644
|
.join("\n ");
|
|
5617
|
-
headerContent = `<fig-dropdown class="fig-fill-picker-type"
|
|
5645
|
+
headerContent = `<fig-dropdown class="fig-fill-picker-type" ${expAttr} value="${this.#fillType}">
|
|
5618
5646
|
${options}
|
|
5619
5647
|
</fig-dropdown>`;
|
|
5620
5648
|
}
|
|
@@ -5853,10 +5881,17 @@ class FigFillPicker extends HTMLElement {
|
|
|
5853
5881
|
ctx.fillRect(0, 0, width, height);
|
|
5854
5882
|
}
|
|
5855
5883
|
|
|
5856
|
-
#updateHandlePosition() {
|
|
5884
|
+
#updateHandlePosition(retryCount = 0) {
|
|
5857
5885
|
if (!this.#colorAreaHandle || !this.#colorArea) return;
|
|
5858
5886
|
|
|
5859
5887
|
const rect = this.#colorArea.getBoundingClientRect();
|
|
5888
|
+
|
|
5889
|
+
// If the canvas isn't visible yet (0 dimensions), schedule a retry (max 5 attempts)
|
|
5890
|
+
if ((rect.width === 0 || rect.height === 0) && retryCount < 5) {
|
|
5891
|
+
requestAnimationFrame(() => this.#updateHandlePosition(retryCount + 1));
|
|
5892
|
+
return;
|
|
5893
|
+
}
|
|
5894
|
+
|
|
5860
5895
|
const x = (this.#color.s / 100) * rect.width;
|
|
5861
5896
|
const y = ((100 - this.#color.v) / 100) * rect.height;
|
|
5862
5897
|
|
|
@@ -5943,10 +5978,12 @@ class FigFillPicker extends HTMLElement {
|
|
|
5943
5978
|
// ============ GRADIENT TAB ============
|
|
5944
5979
|
#initGradientTab() {
|
|
5945
5980
|
const container = this.#dialog.querySelector('[data-tab="gradient"]');
|
|
5981
|
+
const experimental = this.getAttribute("experimental");
|
|
5982
|
+
const expAttr = experimental ? `experimental="${experimental}"` : "";
|
|
5946
5983
|
|
|
5947
5984
|
container.innerHTML = `
|
|
5948
5985
|
<div class="fig-fill-picker-gradient-header">
|
|
5949
|
-
<fig-dropdown class="fig-fill-picker-gradient-type"
|
|
5986
|
+
<fig-dropdown class="fig-fill-picker-gradient-type" ${expAttr} value="${
|
|
5950
5987
|
this.#gradient.type
|
|
5951
5988
|
}">
|
|
5952
5989
|
<option value="linear" selected>Linear</option>
|
package/index.html
CHANGED
|
@@ -654,6 +654,12 @@
|
|
|
654
654
|
<fig-combo-input options="Red, Green, Blue, Yellow, Purple"
|
|
655
655
|
value="Blue"
|
|
656
656
|
placeholder="Select a color"></fig-combo-input>
|
|
657
|
+
|
|
658
|
+
<h3>Experimental Modern</h3>
|
|
659
|
+
<p class="description">Uses the modern CSS picker styling for the dropdown.</p>
|
|
660
|
+
<fig-combo-input options="House, Apartment, Condo, Townhouse, Other"
|
|
661
|
+
experimental="modern"
|
|
662
|
+
placeholder="Type of residence"></fig-combo-input>
|
|
657
663
|
</section>
|
|
658
664
|
<hr>
|
|
659
665
|
|
|
@@ -840,7 +846,7 @@
|
|
|
840
846
|
<p class="description">A select dropdown menu with options.</p>
|
|
841
847
|
|
|
842
848
|
<h3>Default</h3>
|
|
843
|
-
<fig-dropdown
|
|
849
|
+
<fig-dropdown>
|
|
844
850
|
<optgroup label="Numbers">
|
|
845
851
|
<option>One</option>
|
|
846
852
|
<option>Two</option>
|
|
@@ -854,8 +860,7 @@
|
|
|
854
860
|
</fig-dropdown>
|
|
855
861
|
|
|
856
862
|
<h3>Full Width</h3>
|
|
857
|
-
<fig-dropdown full
|
|
858
|
-
variant="neue">
|
|
863
|
+
<fig-dropdown full>
|
|
859
864
|
<option>Full Width Dropdown</option>
|
|
860
865
|
<option>Option Two</option>
|
|
861
866
|
<option>Option Three</option>
|
|
@@ -865,8 +870,7 @@
|
|
|
865
870
|
<p style="font-size: 12px; color: var(--figma-color-text-secondary); margin-bottom: 8px;">
|
|
866
871
|
Uses <code>field-sizing: content</code> to resize based on selected option.
|
|
867
872
|
</p>
|
|
868
|
-
<fig-dropdown autoresize
|
|
869
|
-
variant="neue">
|
|
873
|
+
<fig-dropdown autoresize>
|
|
870
874
|
<option>XS</option>
|
|
871
875
|
<option>Small</option>
|
|
872
876
|
<option>Medium</option>
|
|
@@ -875,8 +879,27 @@
|
|
|
875
879
|
<option>XXL Super Extended Option</option>
|
|
876
880
|
</fig-dropdown>
|
|
877
881
|
|
|
878
|
-
<h3>
|
|
879
|
-
<
|
|
882
|
+
<h3>Experimental Modern</h3>
|
|
883
|
+
<p class="description">
|
|
884
|
+
Use <code>experimental="modern"</code> to enable the customizable select picker using
|
|
885
|
+
<code>::picker(select)</code> and <code>appearance: base-select</code>. This is a progressive
|
|
886
|
+
enhancement that falls back to native select on unsupported browsers.
|
|
887
|
+
</p>
|
|
888
|
+
<fig-dropdown experimental="modern">
|
|
889
|
+
<optgroup label="Numbers">
|
|
890
|
+
<option>One</option>
|
|
891
|
+
<option>Two</option>
|
|
892
|
+
<option>Three</option>
|
|
893
|
+
</optgroup>
|
|
894
|
+
<optgroup label="Fruits">
|
|
895
|
+
<option>Apple</option>
|
|
896
|
+
<option>Banana</option>
|
|
897
|
+
<option>Cherry</option>
|
|
898
|
+
</optgroup>
|
|
899
|
+
</fig-dropdown>
|
|
900
|
+
|
|
901
|
+
<h3>Experimental Modern - Dropdown Type (with many options)</h3>
|
|
902
|
+
<fig-dropdown experimental="modern"
|
|
880
903
|
type="dropdown"
|
|
881
904
|
label="Choose">
|
|
882
905
|
<optgroup label="North America">
|
|
@@ -1007,9 +1030,9 @@
|
|
|
1007
1030
|
</optgroup>
|
|
1008
1031
|
</fig-dropdown>
|
|
1009
1032
|
|
|
1010
|
-
<h3>Select
|
|
1033
|
+
<h3>Experimental Modern - Select Type (with many options)</h3>
|
|
1011
1034
|
|
|
1012
|
-
<fig-dropdown
|
|
1035
|
+
<fig-dropdown experimental="modern">
|
|
1013
1036
|
<optgroup label="North America">
|
|
1014
1037
|
<option value="us">United States</option>
|
|
1015
1038
|
<option value="ca">Canada</option>
|
|
@@ -1137,6 +1160,41 @@
|
|
|
1137
1160
|
<option value="zeplin">Zeplin</option>
|
|
1138
1161
|
</optgroup>
|
|
1139
1162
|
</fig-dropdown>
|
|
1163
|
+
|
|
1164
|
+
<h3>Experimental Modern - With Icons (Bleeding Edge)</h3>
|
|
1165
|
+
<p class="description">
|
|
1166
|
+
Using icons inside options requires <code>appearance: base-select</code> support.
|
|
1167
|
+
This is bleeding edge and may not work in all browsers.
|
|
1168
|
+
</p>
|
|
1169
|
+
<fig-dropdown experimental="modern">
|
|
1170
|
+
<option value="home">
|
|
1171
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
1172
|
+
<path d="M2 6.5L8 2L14 6.5V13.5C14 14 13.5 14.5 13 14.5H3C2.5 14.5 2 14 2 13.5V6.5Z" stroke="currentColor" stroke-opacity="0.9" fill="none"/>
|
|
1173
|
+
</svg>
|
|
1174
|
+
<label>Home</label>
|
|
1175
|
+
</option>
|
|
1176
|
+
<option value="settings">
|
|
1177
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
1178
|
+
<circle cx="8" cy="8" r="2" stroke="currentColor" stroke-opacity="0.9" fill="none"/>
|
|
1179
|
+
<path d="M8 1V3M8 13V15M1 8H3M13 8H15M2.5 2.5L4 4M12 12L13.5 13.5M2.5 13.5L4 12M12 4L13.5 2.5" stroke="currentColor" stroke-opacity="0.9"/>
|
|
1180
|
+
</svg>
|
|
1181
|
+
<label>Settings</label>
|
|
1182
|
+
</option>
|
|
1183
|
+
<option value="user">
|
|
1184
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
1185
|
+
<circle cx="8" cy="5" r="3" stroke="currentColor" stroke-opacity="0.9" fill="none"/>
|
|
1186
|
+
<path d="M2 14C2 11 4.5 9 8 9C11.5 9 14 11 14 14" stroke="currentColor" stroke-opacity="0.9" fill="none"/>
|
|
1187
|
+
</svg>
|
|
1188
|
+
<label>User Profile</label>
|
|
1189
|
+
</option>
|
|
1190
|
+
<option value="search">
|
|
1191
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
1192
|
+
<circle cx="6.5" cy="6.5" r="4" stroke="currentColor" stroke-opacity="0.9" fill="none"/>
|
|
1193
|
+
<path d="M10 10L14 14" stroke="currentColor" stroke-opacity="0.9"/>
|
|
1194
|
+
</svg>
|
|
1195
|
+
<label>Search</label>
|
|
1196
|
+
</option>
|
|
1197
|
+
</fig-dropdown>
|
|
1140
1198
|
</section>
|
|
1141
1199
|
<hr>
|
|
1142
1200
|
|
package/package.json
CHANGED