@rogieking/figui3 3.21.0 → 3.21.2
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/components.css +61 -23
- package/dist/components.css +1 -1
- package/dist/fig.css +1 -1
- package/dist/fig.js +66 -64
- package/fig.js +91 -44
- package/package.json +1 -1
package/fig.js
CHANGED
|
@@ -5389,14 +5389,15 @@ class FigInputFill extends HTMLElement {
|
|
|
5389
5389
|
${opacityHtml(Math.round(this.#solid.alpha * 100))}`;
|
|
5390
5390
|
break;
|
|
5391
5391
|
|
|
5392
|
-
case "gradient":
|
|
5392
|
+
case "gradient": {
|
|
5393
5393
|
const gradientLabel =
|
|
5394
5394
|
this.#gradient.type.charAt(0).toUpperCase() +
|
|
5395
5395
|
this.#gradient.type.slice(1);
|
|
5396
5396
|
controlsHtml = `
|
|
5397
5397
|
<label class="fig-input-fill-label">${gradientLabel}</label>
|
|
5398
|
-
${opacityHtml(
|
|
5398
|
+
${opacityHtml(100)}`;
|
|
5399
5399
|
break;
|
|
5400
|
+
}
|
|
5400
5401
|
|
|
5401
5402
|
case "image":
|
|
5402
5403
|
controlsHtml = `
|
|
@@ -5529,10 +5530,6 @@ class FigInputFill extends HTMLElement {
|
|
|
5529
5530
|
this.#solid.alpha = alpha;
|
|
5530
5531
|
break;
|
|
5531
5532
|
case "gradient":
|
|
5532
|
-
// Apply to all stops
|
|
5533
|
-
this.#gradient.stops.forEach((stop) => {
|
|
5534
|
-
stop.opacity = opacity;
|
|
5535
|
-
});
|
|
5536
5533
|
break;
|
|
5537
5534
|
case "image":
|
|
5538
5535
|
this.#image.opacity = alpha;
|
|
@@ -5575,12 +5572,6 @@ class FigInputFill extends HTMLElement {
|
|
|
5575
5572
|
}
|
|
5576
5573
|
break;
|
|
5577
5574
|
case "gradient": {
|
|
5578
|
-
if (this.#opacityInput) {
|
|
5579
|
-
this.#opacityInput.setAttribute(
|
|
5580
|
-
"value",
|
|
5581
|
-
this.#gradient.stops[0]?.opacity ?? 100,
|
|
5582
|
-
);
|
|
5583
|
-
}
|
|
5584
5575
|
const label = this.querySelector(".fig-input-fill-label");
|
|
5585
5576
|
if (label) {
|
|
5586
5577
|
const newLabel =
|
|
@@ -5657,7 +5648,7 @@ class FigInputFill extends HTMLElement {
|
|
|
5657
5648
|
</fig-input-number>
|
|
5658
5649
|
</fig-tooltip>`;
|
|
5659
5650
|
break;
|
|
5660
|
-
case "gradient":
|
|
5651
|
+
case "gradient": {
|
|
5661
5652
|
const gradientLabel =
|
|
5662
5653
|
this.#gradient.type.charAt(0).toUpperCase() +
|
|
5663
5654
|
this.#gradient.type.slice(1);
|
|
@@ -5669,12 +5660,13 @@ class FigInputFill extends HTMLElement {
|
|
|
5669
5660
|
placeholder="##"
|
|
5670
5661
|
min="0"
|
|
5671
5662
|
max="100"
|
|
5672
|
-
value="
|
|
5663
|
+
value="100"
|
|
5673
5664
|
units="%"
|
|
5674
5665
|
${disabled ? "disabled" : ""}>
|
|
5675
5666
|
</fig-input-number>
|
|
5676
5667
|
</fig-tooltip>`;
|
|
5677
5668
|
break;
|
|
5669
|
+
}
|
|
5678
5670
|
case "image":
|
|
5679
5671
|
controlsHtml = `
|
|
5680
5672
|
<label class="fig-input-fill-label">Image</label>
|
|
@@ -5768,9 +5760,6 @@ class FigInputFill extends HTMLElement {
|
|
|
5768
5760
|
this.#solid.alpha = alpha;
|
|
5769
5761
|
break;
|
|
5770
5762
|
case "gradient":
|
|
5771
|
-
this.#gradient.stops.forEach((stop) => {
|
|
5772
|
-
stop.opacity = opacity;
|
|
5773
|
-
});
|
|
5774
5763
|
break;
|
|
5775
5764
|
case "image":
|
|
5776
5765
|
this.#image.opacity = alpha;
|
|
@@ -6375,6 +6364,8 @@ class FigInputGradient extends HTMLElement {
|
|
|
6375
6364
|
...this.#gradient,
|
|
6376
6365
|
...parsed.gradient,
|
|
6377
6366
|
});
|
|
6367
|
+
this.#gradient.type = "linear";
|
|
6368
|
+
this.#gradient.angle = 90;
|
|
6378
6369
|
return;
|
|
6379
6370
|
}
|
|
6380
6371
|
if (parsed?.gradient) {
|
|
@@ -6382,6 +6373,8 @@ class FigInputGradient extends HTMLElement {
|
|
|
6382
6373
|
...this.#gradient,
|
|
6383
6374
|
...parsed.gradient,
|
|
6384
6375
|
});
|
|
6376
|
+
this.#gradient.type = "linear";
|
|
6377
|
+
this.#gradient.angle = 90;
|
|
6385
6378
|
}
|
|
6386
6379
|
} catch (e) {
|
|
6387
6380
|
// Ignore invalid JSON and keep current/default gradient.
|
|
@@ -6392,17 +6385,31 @@ class FigInputGradient extends HTMLElement {
|
|
|
6392
6385
|
const sorted = [...this.#gradient.stops].sort(
|
|
6393
6386
|
(a, b) => a.position - b.position,
|
|
6394
6387
|
);
|
|
6395
|
-
const stops = sorted
|
|
6388
|
+
const stops = sorted
|
|
6389
|
+
.map((s) => {
|
|
6390
|
+
const alpha = (s.opacity ?? 100) / 100;
|
|
6391
|
+
if (alpha >= 1) return `${s.color} ${s.position}%`;
|
|
6392
|
+
const { r, g, b } = figHexToRGB(s.color);
|
|
6393
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha}) ${s.position}%`;
|
|
6394
|
+
})
|
|
6395
|
+
.join(", ");
|
|
6396
6396
|
const interp = gradientInterpolationClause(this.#gradient);
|
|
6397
6397
|
return `linear-gradient(${this.#gradient.angle}deg ${interp}, ${stops})`;
|
|
6398
6398
|
}
|
|
6399
6399
|
|
|
6400
|
+
#stopColorCSS(stop) {
|
|
6401
|
+
const alpha = (stop.opacity ?? 100) / 100;
|
|
6402
|
+
if (alpha >= 1) return stop.color;
|
|
6403
|
+
const { r, g, b } = figHexToRGB(stop.color);
|
|
6404
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
6405
|
+
}
|
|
6406
|
+
|
|
6400
6407
|
#buildStopHandles() {
|
|
6401
6408
|
const disabled = this.hasAttribute("disabled");
|
|
6402
6409
|
return this.#gradient.stops
|
|
6403
6410
|
.map(
|
|
6404
6411
|
(stop, i) =>
|
|
6405
|
-
`<fig-tooltip action="manual" text="${Math.round(stop.position)}%"><fig-handle drag drag-axes="x" drag-surface=".fig-input-gradient-track" type="color" color="${stop
|
|
6412
|
+
`<fig-tooltip action="manual" text="${Math.round(stop.position)}%"><fig-handle drag drag-axes="x" drag-surface=".fig-input-gradient-track" type="color" color="${this.#stopColorCSS(stop)}" value="${stop.position}% 50%" hit-area="4" data-stop-index="${i}"${disabled ? " disabled" : ""}></fig-handle></fig-tooltip>`,
|
|
6406
6413
|
)
|
|
6407
6414
|
.join("");
|
|
6408
6415
|
}
|
|
@@ -6643,7 +6650,7 @@ class FigInputGradient extends HTMLElement {
|
|
|
6643
6650
|
const stop = stops[i];
|
|
6644
6651
|
h.dataset.stopIndex = i;
|
|
6645
6652
|
h.setAttribute("value", `${stop.position}% 50%`);
|
|
6646
|
-
h.setAttribute("color", stop
|
|
6653
|
+
h.setAttribute("color", this.#stopColorCSS(stop));
|
|
6647
6654
|
const tip = h.closest("fig-tooltip");
|
|
6648
6655
|
if (tip) tip.setAttribute("text", `${Math.round(stop.position)}%`);
|
|
6649
6656
|
}
|
|
@@ -6760,6 +6767,10 @@ class FigInputGradient extends HTMLElement {
|
|
|
6760
6767
|
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
6761
6768
|
if (!isNaN(idx) && this.#gradient.stops[idx]) {
|
|
6762
6769
|
this.#gradient.stops[idx].color = e.detail.color;
|
|
6770
|
+
if (e.detail.opacity !== undefined) {
|
|
6771
|
+
this.#gradient.stops[idx].opacity = e.detail.opacity;
|
|
6772
|
+
}
|
|
6773
|
+
handle.setAttribute("color", this.#stopColorCSS(this.#gradient.stops[idx]));
|
|
6763
6774
|
this.#syncChit();
|
|
6764
6775
|
this.#emitInput();
|
|
6765
6776
|
}
|
|
@@ -6811,6 +6822,10 @@ class FigInputGradient extends HTMLElement {
|
|
|
6811
6822
|
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
6812
6823
|
if (!isNaN(idx) && this.#gradient.stops[idx]) {
|
|
6813
6824
|
this.#gradient.stops[idx].color = e.detail.color;
|
|
6825
|
+
if (e.detail.opacity !== undefined) {
|
|
6826
|
+
this.#gradient.stops[idx].opacity = e.detail.opacity;
|
|
6827
|
+
}
|
|
6828
|
+
handle.setAttribute("color", this.#stopColorCSS(this.#gradient.stops[idx]));
|
|
6814
6829
|
this.#syncChit();
|
|
6815
6830
|
this.#emitChange();
|
|
6816
6831
|
}
|
|
@@ -6852,7 +6867,8 @@ class FigInputGradient extends HTMLElement {
|
|
|
6852
6867
|
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
6853
6868
|
if (isNaN(idx) || !this.#gradient.stops[idx]) continue;
|
|
6854
6869
|
const newColor = handle.getAttribute("color");
|
|
6855
|
-
if (newColor
|
|
6870
|
+
if (!newColor || !newColor.startsWith("#")) continue;
|
|
6871
|
+
if (newColor !== this.#gradient.stops[idx].color) {
|
|
6856
6872
|
this.#gradient.stops[idx].color = newColor;
|
|
6857
6873
|
this.#syncChit();
|
|
6858
6874
|
this.#emitInput();
|
|
@@ -7578,8 +7594,8 @@ class FigChit extends HTMLElement {
|
|
|
7578
7594
|
}
|
|
7579
7595
|
}
|
|
7580
7596
|
|
|
7581
|
-
|
|
7582
|
-
this.style.setProperty("--chit-background", rawBg);
|
|
7597
|
+
const isImage = /^(linear-gradient|radial-gradient|conic-gradient|repeating-|url)\s*\(/i.test(rawBg);
|
|
7598
|
+
this.style.setProperty("--chit-background", isImage ? rawBg : `linear-gradient(${rawBg}, ${rawBg})`);
|
|
7583
7599
|
}
|
|
7584
7600
|
|
|
7585
7601
|
#handleInput(e) {
|
|
@@ -7605,9 +7621,9 @@ class FigChit extends HTMLElement {
|
|
|
7605
7621
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
7606
7622
|
if (oldValue === newValue) return;
|
|
7607
7623
|
if (name === "background") {
|
|
7608
|
-
// Skip full re-render if this was triggered by internal input
|
|
7609
7624
|
if (this.#internalUpdate) {
|
|
7610
|
-
|
|
7625
|
+
const isImg = /^(linear-gradient|radial-gradient|conic-gradient|repeating-|url)\s*\(/i.test(newValue);
|
|
7626
|
+
this.style.setProperty("--chit-background", isImg ? newValue : `linear-gradient(${newValue}, ${newValue})`);
|
|
7611
7627
|
return;
|
|
7612
7628
|
}
|
|
7613
7629
|
this.#render();
|
|
@@ -7629,6 +7645,10 @@ class FigChit extends HTMLElement {
|
|
|
7629
7645
|
}
|
|
7630
7646
|
}
|
|
7631
7647
|
customElements.define("fig-chit", FigChit);
|
|
7648
|
+
class FigSwatch extends FigChit{
|
|
7649
|
+
|
|
7650
|
+
}
|
|
7651
|
+
customElements.define("fig-swatch", FigSwatch);
|
|
7632
7652
|
|
|
7633
7653
|
/* Upload */
|
|
7634
7654
|
/**
|
|
@@ -10899,7 +10919,6 @@ class FigFillPicker extends HTMLElement {
|
|
|
10899
10919
|
this.#chit.style.setProperty("--chit-bg-size", bgSize);
|
|
10900
10920
|
this.#chit.style.setProperty("--chit-bg-position", bgPosition);
|
|
10901
10921
|
|
|
10902
|
-
// For solid colors, also update the alpha
|
|
10903
10922
|
if (this.#fillType === "solid") {
|
|
10904
10923
|
this.#chit.setAttribute("alpha", this.#color.a);
|
|
10905
10924
|
} else {
|
|
@@ -12017,10 +12036,10 @@ class FigFillPicker extends HTMLElement {
|
|
|
12017
12036
|
stopColor.addEventListener("input", (e) => {
|
|
12018
12037
|
this.#gradient.stops[index].color =
|
|
12019
12038
|
e.target.hexOpaque || e.target.value;
|
|
12020
|
-
const
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12039
|
+
const a = e.detail?.rgba?.a;
|
|
12040
|
+
if (a !== undefined) {
|
|
12041
|
+
this.#gradient.stops[index].opacity = Math.round(a * 100);
|
|
12042
|
+
}
|
|
12024
12043
|
this.#updateGradientPreview();
|
|
12025
12044
|
this.#emitInput();
|
|
12026
12045
|
});
|
|
@@ -12887,10 +12906,15 @@ class FigColorTip extends HTMLElement {
|
|
|
12887
12906
|
}
|
|
12888
12907
|
this.removeEventListener("click", this.#handleControlClick);
|
|
12889
12908
|
|
|
12890
|
-
const
|
|
12909
|
+
const rawValue = (this.getAttribute("value") || "").trim();
|
|
12910
|
+
const color = this.#normalizeColor(rawValue);
|
|
12911
|
+
const alpha = this.#extractAlpha(rawValue);
|
|
12891
12912
|
const alphaAttr = this.#alphaEnabled ? "" : 'alpha="false"';
|
|
12913
|
+
const pickerValue = alpha < 1
|
|
12914
|
+
? JSON.stringify({ type: "solid", color, opacity: Math.round(alpha * 100) })
|
|
12915
|
+
: JSON.stringify({ type: "solid", color });
|
|
12892
12916
|
this.innerHTML = `
|
|
12893
|
-
<fig-fill-picker mode="solid" ${alphaAttr} value='${
|
|
12917
|
+
<fig-fill-picker mode="solid" ${alphaAttr} value='${pickerValue}'>
|
|
12894
12918
|
<fig-chit background="${color}"></fig-chit>
|
|
12895
12919
|
</fig-fill-picker>`;
|
|
12896
12920
|
|
|
@@ -12925,6 +12949,17 @@ class FigColorTip extends HTMLElement {
|
|
|
12925
12949
|
return "#D9D9D9";
|
|
12926
12950
|
}
|
|
12927
12951
|
|
|
12952
|
+
#extractAlpha(colorValue) {
|
|
12953
|
+
if (!colorValue) return 1;
|
|
12954
|
+
const v = String(colorValue).trim();
|
|
12955
|
+
if (v.startsWith("#") && v.length === 9) {
|
|
12956
|
+
return parseInt(v.slice(7, 9), 16) / 255;
|
|
12957
|
+
}
|
|
12958
|
+
const rgbaMatch = v.match(/rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*([\d.]+)\s*\)/i);
|
|
12959
|
+
if (rgbaMatch) return parseFloat(rgbaMatch[1]);
|
|
12960
|
+
return 1;
|
|
12961
|
+
}
|
|
12962
|
+
|
|
12928
12963
|
#normalizeColor(colorValue) {
|
|
12929
12964
|
if (!colorValue) return "#D9D9D9";
|
|
12930
12965
|
const value = String(colorValue).trim();
|
|
@@ -12968,17 +13003,19 @@ class FigColorTip extends HTMLElement {
|
|
|
12968
13003
|
}
|
|
12969
13004
|
|
|
12970
13005
|
#syncFromAttributes() {
|
|
12971
|
-
const
|
|
12972
|
-
|
|
13006
|
+
const rawAttr = this.getAttribute("value");
|
|
13007
|
+
const color = this.#normalizeColor(rawAttr);
|
|
13008
|
+
const alpha = this.#extractAlpha(rawAttr);
|
|
13009
|
+
if (rawAttr !== color && alpha >= 1) {
|
|
12973
13010
|
this.setAttribute("value", color);
|
|
12974
13011
|
return;
|
|
12975
13012
|
}
|
|
12976
13013
|
|
|
12977
13014
|
if (this.#fillPicker) {
|
|
12978
|
-
|
|
12979
|
-
"
|
|
12980
|
-
|
|
12981
|
-
);
|
|
13015
|
+
const pickerVal = alpha < 1
|
|
13016
|
+
? { type: "solid", color, opacity: Math.round(alpha * 100) }
|
|
13017
|
+
: { type: "solid", color };
|
|
13018
|
+
this.#fillPicker.setAttribute("value", JSON.stringify(pickerVal));
|
|
12982
13019
|
if (this.#alphaEnabled) {
|
|
12983
13020
|
this.#fillPicker.removeAttribute("alpha");
|
|
12984
13021
|
} else {
|
|
@@ -13011,8 +13048,12 @@ class FigColorTip extends HTMLElement {
|
|
|
13011
13048
|
}
|
|
13012
13049
|
|
|
13013
13050
|
const eventDetail = { color: this.value };
|
|
13014
|
-
if (this.#alphaEnabled
|
|
13015
|
-
|
|
13051
|
+
if (this.#alphaEnabled) {
|
|
13052
|
+
if (detail?.opacity !== undefined) {
|
|
13053
|
+
eventDetail.opacity = detail.opacity;
|
|
13054
|
+
} else if (detail?.alpha !== undefined) {
|
|
13055
|
+
eventDetail.opacity = Math.round(detail.alpha * 100);
|
|
13056
|
+
}
|
|
13016
13057
|
}
|
|
13017
13058
|
|
|
13018
13059
|
this.dispatchEvent(
|
|
@@ -15005,19 +15046,25 @@ class FigHandle extends HTMLElement {
|
|
|
15005
15046
|
this.#colorTip = null;
|
|
15006
15047
|
}
|
|
15007
15048
|
|
|
15049
|
+
#colorWithOpacity(hex, opacity) {
|
|
15050
|
+
if (opacity === undefined || opacity >= 100) return hex;
|
|
15051
|
+
const { r, g, b } = figHexToRGB(hex);
|
|
15052
|
+
return `rgba(${r}, ${g}, ${b}, ${opacity / 100})`;
|
|
15053
|
+
}
|
|
15054
|
+
|
|
15008
15055
|
#handleColorTipInput = (e) => {
|
|
15009
15056
|
e.stopPropagation();
|
|
15010
15057
|
if (e.detail?.color) {
|
|
15011
|
-
this.setAttribute("color", e.detail.color);
|
|
15012
|
-
this.dispatchEvent(new CustomEvent("input", { bubbles: true, detail: { color: e.detail.color } }));
|
|
15058
|
+
this.setAttribute("color", this.#colorWithOpacity(e.detail.color, e.detail.opacity));
|
|
15059
|
+
this.dispatchEvent(new CustomEvent("input", { bubbles: true, detail: { color: e.detail.color, opacity: e.detail.opacity } }));
|
|
15013
15060
|
}
|
|
15014
15061
|
};
|
|
15015
15062
|
|
|
15016
15063
|
#handleColorTipChange = (e) => {
|
|
15017
15064
|
e.stopPropagation();
|
|
15018
15065
|
if (e.detail?.color) {
|
|
15019
|
-
this.setAttribute("color", e.detail.color);
|
|
15020
|
-
this.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: { color: e.detail.color } }));
|
|
15066
|
+
this.setAttribute("color", this.#colorWithOpacity(e.detail.color, e.detail.opacity));
|
|
15067
|
+
this.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: { color: e.detail.color, opacity: e.detail.opacity } }));
|
|
15021
15068
|
}
|
|
15022
15069
|
};
|
|
15023
15070
|
|
package/package.json
CHANGED