@rogieking/figui3 3.13.0 → 3.14.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/components.css +51 -27
- package/fig.js +385 -147
- package/package.json +1 -1
package/components.css
CHANGED
|
@@ -1204,10 +1204,8 @@ fig-chit {
|
|
|
1204
1204
|
box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
|
|
1205
1205
|
}
|
|
1206
1206
|
|
|
1207
|
+
&[size="medium"],
|
|
1207
1208
|
&[size="large"] {
|
|
1208
|
-
--size: 1.75rem;
|
|
1209
|
-
|
|
1210
|
-
/* Large size: swatch fills the whole area */
|
|
1211
1209
|
input[type="color"] {
|
|
1212
1210
|
padding: 0;
|
|
1213
1211
|
width: var(--size);
|
|
@@ -1233,7 +1231,6 @@ fig-chit {
|
|
|
1233
1231
|
inset 0 0 0 3px var(--figma-color-bg);
|
|
1234
1232
|
}
|
|
1235
1233
|
|
|
1236
|
-
/* Large gradient/image: also fill the area */
|
|
1237
1234
|
&[data-type="gradient"]::after,
|
|
1238
1235
|
&[data-type="image"]::after,
|
|
1239
1236
|
&[data-type="gradient"]::before,
|
|
@@ -1244,6 +1241,14 @@ fig-chit {
|
|
|
1244
1241
|
}
|
|
1245
1242
|
}
|
|
1246
1243
|
|
|
1244
|
+
&[size="medium"] {
|
|
1245
|
+
--size: 1.5rem;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
&[size="large"] {
|
|
1249
|
+
--size: 2rem;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1247
1252
|
&[disabled] {
|
|
1248
1253
|
pointer-events: none;
|
|
1249
1254
|
}
|
|
@@ -3174,14 +3179,12 @@ fig-input-gradient {
|
|
|
3174
3179
|
}
|
|
3175
3180
|
fig-chit {
|
|
3176
3181
|
flex: 1 1 auto;
|
|
3177
|
-
width: 100
|
|
3178
|
-
min-width: 0;
|
|
3182
|
+
width: 100% !important;
|
|
3183
|
+
min-width: 0 !important;
|
|
3179
3184
|
&::before,
|
|
3180
3185
|
&::after {
|
|
3181
|
-
width:
|
|
3182
|
-
height: auto;
|
|
3186
|
+
width: 100% !important;
|
|
3183
3187
|
place-self: stretch;
|
|
3184
|
-
border-radius: var(--radius-large) !important;
|
|
3185
3188
|
}
|
|
3186
3189
|
&[data-type="gradient"]::after {
|
|
3187
3190
|
width: calc(100% - 0.625rem);
|
|
@@ -3193,12 +3196,24 @@ fig-input-gradient {
|
|
|
3193
3196
|
|
|
3194
3197
|
.fig-input-gradient-track {
|
|
3195
3198
|
position: absolute;
|
|
3196
|
-
|
|
3199
|
+
display: flex;
|
|
3200
|
+
align-items: center;
|
|
3201
|
+
inset: 0;
|
|
3197
3202
|
pointer-events: auto;
|
|
3198
3203
|
|
|
3199
3204
|
fig-handle {
|
|
3200
3205
|
pointer-events: auto;
|
|
3201
3206
|
cursor: default;
|
|
3207
|
+
|
|
3208
|
+
&.dragging {
|
|
3209
|
+
fig-color-tip {
|
|
3210
|
+
display: none;
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
&:hover {
|
|
3215
|
+
z-index: 5;
|
|
3216
|
+
}
|
|
3202
3217
|
}
|
|
3203
3218
|
}
|
|
3204
3219
|
}
|
|
@@ -4244,12 +4259,6 @@ fig-preview {
|
|
|
4244
4259
|
}
|
|
4245
4260
|
|
|
4246
4261
|
.fig-fill-picker-color-area fig-handle {
|
|
4247
|
-
--width: 1rem;
|
|
4248
|
-
--height: 1rem;
|
|
4249
|
-
--border-radius: 50%;
|
|
4250
|
-
--box-shadow:
|
|
4251
|
-
inset 0 0 0 0.125rem var(--handle-color),
|
|
4252
|
-
0px 0 0 0.5px rgba(0, 0, 0, 0.1), var(--elevation-100-canvas);
|
|
4253
4262
|
z-index: 1;
|
|
4254
4263
|
}
|
|
4255
4264
|
|
|
@@ -4743,9 +4752,8 @@ fig-choice {
|
|
|
4743
4752
|
}
|
|
4744
4753
|
|
|
4745
4754
|
fig-handle {
|
|
4746
|
-
|
|
4747
|
-
--
|
|
4748
|
-
--height: 0.75rem;
|
|
4755
|
+
--width: 0.875rem;
|
|
4756
|
+
--height: 0.875rem;
|
|
4749
4757
|
--fill: var(--figma-color-bg-brand);
|
|
4750
4758
|
--border-radius: 50%;
|
|
4751
4759
|
--ring-width: 1.25px;
|
|
@@ -4755,15 +4763,27 @@ fig-handle {
|
|
|
4755
4763
|
--outline: none;
|
|
4756
4764
|
--border: none;
|
|
4757
4765
|
|
|
4758
|
-
display: inline-
|
|
4766
|
+
display: inline-grid;
|
|
4767
|
+
place-items: center;
|
|
4759
4768
|
width: var(--width);
|
|
4760
4769
|
height: var(--height);
|
|
4761
|
-
background: var(--
|
|
4770
|
+
background: var(--handle-color);
|
|
4762
4771
|
border-radius: var(--border-radius);
|
|
4763
4772
|
box-shadow: var(--box-shadow);
|
|
4764
4773
|
outline: var(--outline);
|
|
4765
4774
|
border: var(--border);
|
|
4766
4775
|
|
|
4776
|
+
&::before {
|
|
4777
|
+
content: "";
|
|
4778
|
+
color-scheme: light only;
|
|
4779
|
+
width: calc(var(--width) - 4px);
|
|
4780
|
+
height: calc(var(--height) - 4px);
|
|
4781
|
+
background: var(--fill);
|
|
4782
|
+
border-radius: var(--border-radius);
|
|
4783
|
+
box-shadow: inset 0 0 0 1px var(--figma-color-bordertranslucent);
|
|
4784
|
+
place-self: center;
|
|
4785
|
+
}
|
|
4786
|
+
|
|
4767
4787
|
&[size="small"] {
|
|
4768
4788
|
--width: 0.5625rem;
|
|
4769
4789
|
--height: 0.5625rem;
|
|
@@ -4773,10 +4793,10 @@ fig-handle {
|
|
|
4773
4793
|
position: absolute;
|
|
4774
4794
|
touch-action: none;
|
|
4775
4795
|
}
|
|
4776
|
-
|
|
4796
|
+
&:hover,
|
|
4777
4797
|
&[selected]:not([selected="false"]) {
|
|
4778
4798
|
outline: var(--ring-width) solid var(--figma-color-border-selected);
|
|
4779
|
-
outline-offset:
|
|
4799
|
+
outline-offset: 0;
|
|
4780
4800
|
}
|
|
4781
4801
|
|
|
4782
4802
|
&[disabled]:not([disabled="false"]),
|
|
@@ -4786,10 +4806,9 @@ fig-handle {
|
|
|
4786
4806
|
cursor: default;
|
|
4787
4807
|
}
|
|
4788
4808
|
|
|
4789
|
-
&[type="color"]
|
|
4790
|
-
|
|
4809
|
+
&[type="color"],
|
|
4810
|
+
&[control] {
|
|
4791
4811
|
overflow: visible;
|
|
4792
|
-
position: relative;
|
|
4793
4812
|
|
|
4794
4813
|
fig-color-tip {
|
|
4795
4814
|
position: absolute;
|
|
@@ -4812,7 +4831,7 @@ fig-color-tip {
|
|
|
4812
4831
|
place-items: center;
|
|
4813
4832
|
overflow: visible;
|
|
4814
4833
|
position: relative;
|
|
4815
|
-
color: var(--text
|
|
4834
|
+
color: var(--figma-color-text);
|
|
4816
4835
|
color-scheme: light only;
|
|
4817
4836
|
aspect-ratio: 1 / 1;
|
|
4818
4837
|
flex-shrink: 0;
|
|
@@ -4825,6 +4844,11 @@ fig-color-tip {
|
|
|
4825
4844
|
drop-shadow(0px 2.5px 6px rgba(0, 0, 0, 0.13))
|
|
4826
4845
|
drop-shadow(0px 0px 0.5px rgba(0, 0, 0, 0.15));
|
|
4827
4846
|
|
|
4847
|
+
&[control="add"],
|
|
4848
|
+
&[control="remove"] {
|
|
4849
|
+
cursor: pointer;
|
|
4850
|
+
}
|
|
4851
|
+
|
|
4828
4852
|
fig-chit {
|
|
4829
4853
|
input[type="color"] {
|
|
4830
4854
|
background: transparent;
|
package/fig.js
CHANGED
|
@@ -659,7 +659,12 @@ class FigTooltip extends HTMLElement {
|
|
|
659
659
|
};
|
|
660
660
|
}
|
|
661
661
|
|
|
662
|
+
get #showPersisted() {
|
|
663
|
+
return this.hasAttribute("show") && this.getAttribute("show") !== "false";
|
|
664
|
+
}
|
|
665
|
+
|
|
662
666
|
showDelayedPopup() {
|
|
667
|
+
if (this.#showPersisted) return;
|
|
663
668
|
this.render();
|
|
664
669
|
clearTimeout(this.timeout);
|
|
665
670
|
const warm =
|
|
@@ -669,10 +674,12 @@ class FigTooltip extends HTMLElement {
|
|
|
669
674
|
}
|
|
670
675
|
|
|
671
676
|
showPopup() {
|
|
677
|
+
if (!this.popup) this.render();
|
|
678
|
+
this.popup.style.display = "block";
|
|
679
|
+
this.popup.style.visibility = "hidden";
|
|
672
680
|
this.#repositionPopup();
|
|
673
681
|
this.popup.style.opacity = "1";
|
|
674
682
|
this.popup.style.visibility = "visible";
|
|
675
|
-
this.popup.style.display = "block";
|
|
676
683
|
this.popup.style.pointerEvents = "all";
|
|
677
684
|
this.popup.style.zIndex = figGetHighestZIndex() + 1;
|
|
678
685
|
|
|
@@ -725,6 +732,7 @@ class FigTooltip extends HTMLElement {
|
|
|
725
732
|
}
|
|
726
733
|
|
|
727
734
|
hidePopup() {
|
|
735
|
+
if (this.#showPersisted) return;
|
|
728
736
|
clearTimeout(this.timeout);
|
|
729
737
|
clearTimeout(this.#touchTimeout);
|
|
730
738
|
this.#stopObserving();
|
|
@@ -824,7 +832,28 @@ class FigTooltip extends HTMLElement {
|
|
|
824
832
|
}
|
|
825
833
|
|
|
826
834
|
static get observedAttributes() {
|
|
827
|
-
return ["action", "delay", "open"];
|
|
835
|
+
return ["action", "delay", "open", "show", "text"];
|
|
836
|
+
}
|
|
837
|
+
get text() {
|
|
838
|
+
return this.getAttribute("text") ?? "";
|
|
839
|
+
}
|
|
840
|
+
set text(value) {
|
|
841
|
+
this.setAttribute("text", value);
|
|
842
|
+
}
|
|
843
|
+
#updateText(value) {
|
|
844
|
+
if (!this.popup) return;
|
|
845
|
+
const content = this.popup.firstElementChild ?? this.popup.firstChild;
|
|
846
|
+
if (!content) return;
|
|
847
|
+
content.innerText = value;
|
|
848
|
+
content.style.width = "";
|
|
849
|
+
const textNode = content.childNodes[0];
|
|
850
|
+
if (textNode) {
|
|
851
|
+
const range = document.createRange();
|
|
852
|
+
range.setStartBefore(textNode);
|
|
853
|
+
range.setEndAfter(textNode);
|
|
854
|
+
content.style.width = `${range.getBoundingClientRect().width}px`;
|
|
855
|
+
}
|
|
856
|
+
if (this.isOpen) this.#repositionPopup();
|
|
828
857
|
}
|
|
829
858
|
get open() {
|
|
830
859
|
return this.hasAttribute("open") && this.getAttribute("open") === "true";
|
|
@@ -851,6 +880,17 @@ class FigTooltip extends HTMLElement {
|
|
|
851
880
|
});
|
|
852
881
|
}
|
|
853
882
|
}
|
|
883
|
+
if (name === "show") {
|
|
884
|
+
const on = newValue !== null && newValue !== "false";
|
|
885
|
+
if (on) {
|
|
886
|
+
this.showPopup();
|
|
887
|
+
} else {
|
|
888
|
+
this.hidePopup();
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (name === "text") {
|
|
892
|
+
this.#updateText(newValue ?? "");
|
|
893
|
+
}
|
|
854
894
|
}
|
|
855
895
|
|
|
856
896
|
#hideOnChromeOpen(e) {
|
|
@@ -5651,8 +5691,9 @@ customElements.define("fig-input-fill", FigInputFill);
|
|
|
5651
5691
|
* @fires change - When the gradient value is committed
|
|
5652
5692
|
*/
|
|
5653
5693
|
class FigInputGradient extends HTMLElement {
|
|
5654
|
-
#
|
|
5694
|
+
#chit;
|
|
5655
5695
|
#track;
|
|
5696
|
+
#handleDragging = false;
|
|
5656
5697
|
#colorObserver = null;
|
|
5657
5698
|
#gradient = {
|
|
5658
5699
|
type: "linear",
|
|
@@ -5670,14 +5711,46 @@ class FigInputGradient extends HTMLElement {
|
|
|
5670
5711
|
}
|
|
5671
5712
|
|
|
5672
5713
|
static get observedAttributes() {
|
|
5673
|
-
return ["value", "disabled"
|
|
5714
|
+
return ["value", "disabled"];
|
|
5674
5715
|
}
|
|
5675
5716
|
|
|
5676
5717
|
connectedCallback() {
|
|
5677
5718
|
this.#parseValue();
|
|
5678
5719
|
this.#render();
|
|
5720
|
+
document.addEventListener("keydown", this.#onKeyDown);
|
|
5721
|
+
}
|
|
5722
|
+
|
|
5723
|
+
disconnectedCallback() {
|
|
5724
|
+
document.removeEventListener("keydown", this.#onKeyDown);
|
|
5679
5725
|
}
|
|
5680
5726
|
|
|
5727
|
+
#onKeyDown = (e) => {
|
|
5728
|
+
if (e.key !== "Delete" && e.key !== "Backspace") return;
|
|
5729
|
+
const active = document.activeElement;
|
|
5730
|
+
if (
|
|
5731
|
+
active &&
|
|
5732
|
+
(active.tagName === "INPUT" ||
|
|
5733
|
+
active.tagName === "TEXTAREA" ||
|
|
5734
|
+
active.isContentEditable)
|
|
5735
|
+
)
|
|
5736
|
+
return;
|
|
5737
|
+
if (this.#gradient.stops.length <= 2) return;
|
|
5738
|
+
if (!this.#track) return;
|
|
5739
|
+
const selected = this.#track.querySelector(
|
|
5740
|
+
"fig-handle[selected]:not(.fig-input-gradient-ghost)",
|
|
5741
|
+
);
|
|
5742
|
+
if (!selected) return;
|
|
5743
|
+
const idx = parseInt(selected.dataset.stopIndex, 10);
|
|
5744
|
+
if (isNaN(idx) || !this.#gradient.stops[idx]) return;
|
|
5745
|
+
e.preventDefault();
|
|
5746
|
+
selected.removeAttribute("selected");
|
|
5747
|
+
this.#gradient.stops.splice(idx, 1);
|
|
5748
|
+
this.#syncHandles();
|
|
5749
|
+
this.#syncChit();
|
|
5750
|
+
this.#emitInput();
|
|
5751
|
+
this.#emitChange();
|
|
5752
|
+
};
|
|
5753
|
+
|
|
5681
5754
|
#parseValue() {
|
|
5682
5755
|
const valueAttr = this.getAttribute("value");
|
|
5683
5756
|
if (!valueAttr) return;
|
|
@@ -5701,19 +5774,12 @@ class FigInputGradient extends HTMLElement {
|
|
|
5701
5774
|
}
|
|
5702
5775
|
}
|
|
5703
5776
|
|
|
5704
|
-
#
|
|
5705
|
-
const
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
attrs[name.slice(7)] = value;
|
|
5711
|
-
}
|
|
5712
|
-
}
|
|
5713
|
-
if (!attrs["dialog-position"]) attrs["dialog-position"] = "left";
|
|
5714
|
-
return Object.entries(attrs)
|
|
5715
|
-
.map(([k, v]) => `${k}="${v}"`)
|
|
5716
|
-
.join(" ");
|
|
5777
|
+
#buildGradientCSS() {
|
|
5778
|
+
const sorted = [...this.#gradient.stops].sort(
|
|
5779
|
+
(a, b) => a.position - b.position,
|
|
5780
|
+
);
|
|
5781
|
+
const stops = sorted.map((s) => `${s.color} ${s.position}%`).join(", ");
|
|
5782
|
+
return `linear-gradient(${this.#gradient.angle}deg, ${stops})`;
|
|
5717
5783
|
}
|
|
5718
5784
|
|
|
5719
5785
|
#buildStopHandles() {
|
|
@@ -5721,23 +5787,19 @@ class FigInputGradient extends HTMLElement {
|
|
|
5721
5787
|
return this.#gradient.stops
|
|
5722
5788
|
.map(
|
|
5723
5789
|
(stop, i) =>
|
|
5724
|
-
`<fig-handle drag drag-axes="x" type="color" color="${stop.color}" value="${stop.position}% 50%" data-stop-index="${i}"${disabled ? " disabled" : ""}></fig-handle>`,
|
|
5790
|
+
`<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.color}" value="${stop.position}% 50%" data-stop-index="${i}"${disabled ? " disabled" : ""}></fig-handle></fig-tooltip>`,
|
|
5725
5791
|
)
|
|
5726
5792
|
.join("");
|
|
5727
5793
|
}
|
|
5728
5794
|
|
|
5729
5795
|
#ghostHandle = null;
|
|
5730
|
-
#ghostTooltip = null;
|
|
5731
5796
|
|
|
5732
5797
|
#render() {
|
|
5733
5798
|
const disabled = this.hasAttribute("disabled");
|
|
5734
|
-
const fillPickerValue = JSON.stringify(this.value);
|
|
5735
|
-
const fpAttrs = this.#buildFillPickerAttrs();
|
|
5736
5799
|
this.innerHTML = `
|
|
5737
|
-
<fig-
|
|
5738
|
-
disabled ? "disabled" : ""
|
|
5739
|
-
}></fig-fill-picker>
|
|
5800
|
+
<fig-chit size="medium" background="${this.#buildGradientCSS()}"${disabled ? " disabled" : ""}></fig-chit>
|
|
5740
5801
|
<div class="fig-input-gradient-track">${this.#buildStopHandles()}</div>`;
|
|
5802
|
+
this.#chit = this.querySelector("fig-chit");
|
|
5741
5803
|
this.#track = this.querySelector(".fig-input-gradient-track");
|
|
5742
5804
|
this.#setupGhostHandle();
|
|
5743
5805
|
this.#setupEventListeners();
|
|
@@ -5765,9 +5827,6 @@ class FigInputGradient extends HTMLElement {
|
|
|
5765
5827
|
|
|
5766
5828
|
#setupGhostHandle() {
|
|
5767
5829
|
if (!this.#track || this.hasAttribute("disabled")) return;
|
|
5768
|
-
const tooltip = document.createElement("fig-tooltip");
|
|
5769
|
-
tooltip.setAttribute("text", "Add color stop");
|
|
5770
|
-
tooltip.setAttribute("action", "manual");
|
|
5771
5830
|
|
|
5772
5831
|
const ghost = document.createElement("fig-handle");
|
|
5773
5832
|
ghost.classList.add("fig-input-gradient-ghost");
|
|
@@ -5777,34 +5836,39 @@ class FigInputGradient extends HTMLElement {
|
|
|
5777
5836
|
ghost.style.pointerEvents = "none";
|
|
5778
5837
|
ghost.style.opacity = "0";
|
|
5779
5838
|
ghost.style.transition = "opacity 0.15s";
|
|
5839
|
+
ghost.style.overflow = "visible";
|
|
5780
5840
|
|
|
5781
|
-
|
|
5782
|
-
|
|
5841
|
+
const tip = document.createElement("fig-color-tip");
|
|
5842
|
+
tip.setAttribute("control", "add");
|
|
5843
|
+
tip.style.position = "absolute";
|
|
5844
|
+
tip.style.bottom = "calc(100% + 6px)";
|
|
5845
|
+
tip.style.left = "50%";
|
|
5846
|
+
tip.style.transform = "translateX(-50%)";
|
|
5847
|
+
tip.style.zIndex = "10";
|
|
5848
|
+
ghost.appendChild(tip);
|
|
5849
|
+
|
|
5850
|
+
this.#track.appendChild(ghost);
|
|
5783
5851
|
this.#ghostHandle = ghost;
|
|
5784
|
-
this.#ghostTooltip = tooltip;
|
|
5785
5852
|
|
|
5786
5853
|
this.addEventListener("pointerenter", this.#onTrackEnter);
|
|
5787
5854
|
this.addEventListener("pointermove", this.#onTrackMove);
|
|
5788
5855
|
this.addEventListener("pointerleave", this.#onTrackLeave);
|
|
5789
5856
|
this.addEventListener("click", this.#onTrackClick);
|
|
5857
|
+
this.addEventListener("dblclick", this.#onTrackDblClick);
|
|
5790
5858
|
}
|
|
5791
5859
|
|
|
5792
5860
|
#showGhost() {
|
|
5793
5861
|
if (!this.#ghostHandle) return;
|
|
5794
|
-
this.#ghostHandle.style.opacity = "
|
|
5795
|
-
if (this.#ghostTooltip) {
|
|
5796
|
-
this.#ghostTooltip.render();
|
|
5797
|
-
this.#ghostTooltip.showPopup();
|
|
5798
|
-
}
|
|
5862
|
+
this.#ghostHandle.style.opacity = "1";
|
|
5799
5863
|
}
|
|
5800
5864
|
|
|
5801
5865
|
#hideGhost() {
|
|
5802
5866
|
if (!this.#ghostHandle) return;
|
|
5803
5867
|
this.#ghostHandle.style.opacity = "0";
|
|
5804
|
-
if (this.#ghostTooltip) this.#ghostTooltip.hidePopup();
|
|
5805
5868
|
}
|
|
5806
5869
|
|
|
5807
5870
|
#onTrackEnter = () => {
|
|
5871
|
+
if (this.#handleDragging) return;
|
|
5808
5872
|
this.#showGhost();
|
|
5809
5873
|
};
|
|
5810
5874
|
|
|
@@ -5813,6 +5877,10 @@ class FigInputGradient extends HTMLElement {
|
|
|
5813
5877
|
};
|
|
5814
5878
|
|
|
5815
5879
|
#onTrackMove = (e) => {
|
|
5880
|
+
if (this.#handleDragging) {
|
|
5881
|
+
this.#hideGhost();
|
|
5882
|
+
return;
|
|
5883
|
+
}
|
|
5816
5884
|
if (!this.#ghostHandle || !this.#track) return;
|
|
5817
5885
|
if (e.target.closest("fig-handle:not(.fig-input-gradient-ghost)")) {
|
|
5818
5886
|
this.#hideGhost();
|
|
@@ -5829,9 +5897,37 @@ class FigInputGradient extends HTMLElement {
|
|
|
5829
5897
|
this.#showGhost();
|
|
5830
5898
|
};
|
|
5831
5899
|
|
|
5900
|
+
#distributeStops() {
|
|
5901
|
+
const count = this.#gradient.stops.length;
|
|
5902
|
+
if (count < 2) return;
|
|
5903
|
+
for (let i = 0; i < count; i++) {
|
|
5904
|
+
this.#gradient.stops[i].position = Math.round((i / (count - 1)) * 100);
|
|
5905
|
+
}
|
|
5906
|
+
this.#syncHandles();
|
|
5907
|
+
this.#syncChit();
|
|
5908
|
+
this.#emitInput();
|
|
5909
|
+
this.#emitChange();
|
|
5910
|
+
this.#track?.querySelectorAll("fig-handle[selected]").forEach((h) => {
|
|
5911
|
+
h.removeAttribute("selected");
|
|
5912
|
+
});
|
|
5913
|
+
}
|
|
5914
|
+
|
|
5915
|
+
#onTrackDblClick = (e) => {
|
|
5916
|
+
if (!this.#track) return;
|
|
5917
|
+
if (!e.target.closest("fig-handle:not(.fig-input-gradient-ghost)")) return;
|
|
5918
|
+
this.#distributeStops();
|
|
5919
|
+
};
|
|
5920
|
+
|
|
5832
5921
|
#onTrackClick = (e) => {
|
|
5833
5922
|
if (!this.#track) return;
|
|
5834
|
-
if (
|
|
5923
|
+
if (this.#handleDragging) return;
|
|
5924
|
+
if (e.target.closest("fig-handle:not(.fig-input-gradient-ghost)")) {
|
|
5925
|
+
if (e.shiftKey) {
|
|
5926
|
+
this.#distributeStops();
|
|
5927
|
+
e.stopPropagation();
|
|
5928
|
+
}
|
|
5929
|
+
return;
|
|
5930
|
+
}
|
|
5835
5931
|
const trackRect = this.#track.getBoundingClientRect();
|
|
5836
5932
|
const pct = Math.max(
|
|
5837
5933
|
0,
|
|
@@ -5841,10 +5937,21 @@ class FigInputGradient extends HTMLElement {
|
|
|
5841
5937
|
const color = this.#sampleGradientColor(pct);
|
|
5842
5938
|
this.#gradient.stops.push({ position, color, opacity: 100 });
|
|
5843
5939
|
this.#gradient.stops.sort((a, b) => a.position - b.position);
|
|
5940
|
+
const newIndex = this.#gradient.stops.findIndex(
|
|
5941
|
+
(s) => s.position === position && s.color === color,
|
|
5942
|
+
);
|
|
5844
5943
|
this.#syncHandles();
|
|
5845
|
-
this.#
|
|
5944
|
+
this.#syncChit();
|
|
5846
5945
|
this.#emitInput();
|
|
5847
5946
|
this.#emitChange();
|
|
5947
|
+
|
|
5948
|
+
requestAnimationFrame(() => {
|
|
5949
|
+
const handles = this.#track.querySelectorAll(
|
|
5950
|
+
"fig-handle:not(.fig-input-gradient-ghost)",
|
|
5951
|
+
);
|
|
5952
|
+
const newHandle = handles[newIndex];
|
|
5953
|
+
if (newHandle) newHandle.click();
|
|
5954
|
+
});
|
|
5848
5955
|
};
|
|
5849
5956
|
|
|
5850
5957
|
#syncHandles() {
|
|
@@ -5855,9 +5962,9 @@ class FigInputGradient extends HTMLElement {
|
|
|
5855
5962
|
const stops = this.#gradient.stops;
|
|
5856
5963
|
|
|
5857
5964
|
if (handles.length !== stops.length) {
|
|
5858
|
-
const
|
|
5965
|
+
const ghost = this.#ghostHandle;
|
|
5859
5966
|
this.#track.innerHTML = this.#buildStopHandles();
|
|
5860
|
-
if (
|
|
5967
|
+
if (ghost) this.#track.appendChild(ghost);
|
|
5861
5968
|
this.#reobserveHandleColors();
|
|
5862
5969
|
return;
|
|
5863
5970
|
}
|
|
@@ -5867,6 +5974,8 @@ class FigInputGradient extends HTMLElement {
|
|
|
5867
5974
|
const stop = stops[i];
|
|
5868
5975
|
h.setAttribute("value", `${stop.position}% 50%`);
|
|
5869
5976
|
h.setAttribute("color", stop.color);
|
|
5977
|
+
const tip = h.closest("fig-tooltip");
|
|
5978
|
+
if (tip) tip.setAttribute("text", `${Math.round(stop.position)}%`);
|
|
5870
5979
|
}
|
|
5871
5980
|
}
|
|
5872
5981
|
|
|
@@ -5883,92 +5992,155 @@ class FigInputGradient extends HTMLElement {
|
|
|
5883
5992
|
});
|
|
5884
5993
|
}
|
|
5885
5994
|
|
|
5886
|
-
#
|
|
5887
|
-
if (!this.#
|
|
5888
|
-
this.#
|
|
5995
|
+
#syncStopIndices() {
|
|
5996
|
+
if (!this.#track) return;
|
|
5997
|
+
const handles = this.#track.querySelectorAll(
|
|
5998
|
+
"fig-handle:not(.fig-input-gradient-ghost)",
|
|
5999
|
+
);
|
|
6000
|
+
const stops = this.#gradient.stops;
|
|
6001
|
+
const used = new Set();
|
|
6002
|
+
handles.forEach((h) => {
|
|
6003
|
+
const pos = Math.round(parseFloat(h.getAttribute("value")) || 0);
|
|
6004
|
+
const color = (h.getAttribute("color") || "").toUpperCase();
|
|
6005
|
+
let best = -1;
|
|
6006
|
+
for (let i = 0; i < stops.length; i++) {
|
|
6007
|
+
if (used.has(i)) continue;
|
|
6008
|
+
if (
|
|
6009
|
+
stops[i].position === pos &&
|
|
6010
|
+
stops[i].color.toUpperCase() === color
|
|
6011
|
+
) {
|
|
6012
|
+
best = i;
|
|
6013
|
+
break;
|
|
6014
|
+
}
|
|
6015
|
+
}
|
|
6016
|
+
if (best === -1) {
|
|
6017
|
+
let minDist = Infinity;
|
|
6018
|
+
for (let i = 0; i < stops.length; i++) {
|
|
6019
|
+
if (used.has(i)) continue;
|
|
6020
|
+
const d = Math.abs(stops[i].position - pos);
|
|
6021
|
+
if (d < minDist) {
|
|
6022
|
+
minDist = d;
|
|
6023
|
+
best = i;
|
|
6024
|
+
}
|
|
6025
|
+
}
|
|
6026
|
+
}
|
|
6027
|
+
if (best !== -1) {
|
|
6028
|
+
used.add(best);
|
|
6029
|
+
h.dataset.stopIndex = best;
|
|
6030
|
+
}
|
|
6031
|
+
});
|
|
6032
|
+
}
|
|
6033
|
+
|
|
6034
|
+
#syncChit() {
|
|
6035
|
+
if (!this.#chit) return;
|
|
6036
|
+
this.#chit.setAttribute("background", this.#buildGradientCSS());
|
|
5889
6037
|
}
|
|
5890
6038
|
|
|
5891
6039
|
#setupEventListeners() {
|
|
5892
|
-
|
|
5893
|
-
this.#fillPicker = this.querySelector("fig-fill-picker");
|
|
5894
|
-
if (!this.#fillPicker) return;
|
|
6040
|
+
if (!this.#track) return;
|
|
5895
6041
|
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
6042
|
+
this.#track.addEventListener("input", (e) => {
|
|
6043
|
+
const handle = e.target.closest("fig-handle");
|
|
6044
|
+
if (!handle) return;
|
|
6045
|
+
e.stopPropagation();
|
|
6046
|
+
if (!this.#handleDragging) handle.style.zIndex = "5";
|
|
6047
|
+
this.#handleDragging = true;
|
|
6048
|
+
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
6049
|
+
if (isNaN(idx) || !this.#gradient.stops[idx]) return;
|
|
6050
|
+
const px = e.detail?.px ?? 0;
|
|
6051
|
+
const rawPosition = Math.round(px * 100);
|
|
6052
|
+
let position = rawPosition;
|
|
6053
|
+
const trackW = this.#track.getBoundingClientRect().width;
|
|
6054
|
+
if (e.detail?.shiftKey) {
|
|
6055
|
+
position = Math.round(position / 10) * 10;
|
|
5899
6056
|
} else {
|
|
5900
|
-
const
|
|
5901
|
-
|
|
6057
|
+
const snapPct = trackW > 0 ? (5 / trackW) * 100 : 0;
|
|
6058
|
+
for (let i = 0; i < this.#gradient.stops.length; i++) {
|
|
6059
|
+
if (i === idx) continue;
|
|
6060
|
+
if (
|
|
6061
|
+
Math.abs(this.#gradient.stops[i].position - position) <= snapPct
|
|
6062
|
+
) {
|
|
6063
|
+
position = this.#gradient.stops[i].position;
|
|
6064
|
+
break;
|
|
6065
|
+
}
|
|
6066
|
+
}
|
|
6067
|
+
}
|
|
6068
|
+
this.#gradient.stops[idx].position = position;
|
|
6069
|
+
if (position !== rawPosition) {
|
|
6070
|
+
handle.style.left = `${(position / 100) * trackW - handle.offsetWidth / 2}px`;
|
|
5902
6071
|
}
|
|
6072
|
+
const tooltip = handle.closest("fig-tooltip");
|
|
6073
|
+
if (tooltip) {
|
|
6074
|
+
tooltip.text = `${Math.round(position)}%`;
|
|
6075
|
+
if (!tooltip.hasAttribute("show")) tooltip.setAttribute("show", "true");
|
|
6076
|
+
}
|
|
6077
|
+
this.#syncChit();
|
|
6078
|
+
this.#emitInput();
|
|
6079
|
+
});
|
|
5903
6080
|
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
6081
|
+
this.#track.addEventListener("change", (e) => {
|
|
6082
|
+
const handle = e.target.closest("fig-handle");
|
|
6083
|
+
if (!handle) return;
|
|
6084
|
+
e.stopPropagation();
|
|
6085
|
+
handle.style.zIndex = "";
|
|
6086
|
+
const tooltip = handle.closest("fig-tooltip");
|
|
6087
|
+
if (tooltip) tooltip.removeAttribute("show");
|
|
6088
|
+
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
6089
|
+
if (isNaN(idx) || !this.#gradient.stops[idx]) return;
|
|
6090
|
+
const px = e.detail?.px ?? 0;
|
|
6091
|
+
let position = Math.round(px * 100);
|
|
6092
|
+
const trackW = this.#track.getBoundingClientRect().width;
|
|
6093
|
+
const snapPct = trackW > 0 ? (5 / trackW) * 100 : 0;
|
|
6094
|
+
for (let i = 0; i < this.#gradient.stops.length; i++) {
|
|
6095
|
+
if (i === idx) continue;
|
|
6096
|
+
if (Math.abs(this.#gradient.stops[i].position - position) <= snapPct) {
|
|
6097
|
+
position = this.#gradient.stops[i].position;
|
|
6098
|
+
break;
|
|
5914
6099
|
}
|
|
6100
|
+
}
|
|
6101
|
+
this.#gradient.stops[idx].position = position;
|
|
6102
|
+
handle.style.left = `${(position / 100) * trackW - handle.offsetWidth / 2}px`;
|
|
6103
|
+
this.#gradient.stops.sort((a, b) => a.position - b.position);
|
|
6104
|
+
this.#syncStopIndices();
|
|
6105
|
+
this.#syncChit();
|
|
6106
|
+
this.#emitChange();
|
|
6107
|
+
const swallow = (evt) => {
|
|
6108
|
+
evt.stopPropagation();
|
|
6109
|
+
evt.preventDefault();
|
|
6110
|
+
};
|
|
6111
|
+
this.#track.addEventListener("click", swallow, {
|
|
6112
|
+
capture: true,
|
|
6113
|
+
once: true,
|
|
5915
6114
|
});
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
this.#emitChange();
|
|
6115
|
+
requestAnimationFrame(() => {
|
|
6116
|
+
this.#handleDragging = false;
|
|
6117
|
+
this.#track.removeEventListener("click", swallow, { capture: true });
|
|
5920
6118
|
});
|
|
6119
|
+
});
|
|
5921
6120
|
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
this.#
|
|
6121
|
+
this.#colorObserver = new MutationObserver((mutations) => {
|
|
6122
|
+
for (const m of mutations) {
|
|
6123
|
+
if (m.attributeName !== "color") continue;
|
|
6124
|
+
const handle = m.target;
|
|
6125
|
+
if (handle.classList.contains("fig-input-gradient-ghost")) continue;
|
|
6126
|
+
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
6127
|
+
if (isNaN(idx) || !this.#gradient.stops[idx]) continue;
|
|
6128
|
+
const newColor = handle.getAttribute("color");
|
|
6129
|
+
if (newColor && newColor !== this.#gradient.stops[idx].color) {
|
|
6130
|
+
this.#gradient.stops[idx].color = newColor;
|
|
6131
|
+
this.#syncChit();
|
|
5932
6132
|
this.#emitInput();
|
|
5933
|
-
}
|
|
5934
|
-
|
|
5935
|
-
this.#track.addEventListener("change", (e) => {
|
|
5936
|
-
const handle = e.target.closest("fig-handle");
|
|
5937
|
-
if (!handle) return;
|
|
5938
|
-
e.stopPropagation();
|
|
5939
|
-
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
5940
|
-
if (isNaN(idx) || !this.#gradient.stops[idx]) return;
|
|
5941
|
-
const px = e.detail?.px ?? 0;
|
|
5942
|
-
this.#gradient.stops[idx].position = Math.round(px * 100);
|
|
5943
|
-
this.#syncFillPicker();
|
|
5944
|
-
this.#emitChange();
|
|
5945
|
-
});
|
|
5946
|
-
|
|
5947
|
-
this.#colorObserver = new MutationObserver((mutations) => {
|
|
5948
|
-
for (const m of mutations) {
|
|
5949
|
-
if (m.attributeName !== "color") continue;
|
|
5950
|
-
const handle = m.target;
|
|
5951
|
-
if (handle.classList.contains("fig-input-gradient-ghost")) continue;
|
|
5952
|
-
const idx = parseInt(handle.dataset.stopIndex, 10);
|
|
5953
|
-
if (isNaN(idx) || !this.#gradient.stops[idx]) continue;
|
|
5954
|
-
const newColor = handle.getAttribute("color");
|
|
5955
|
-
if (newColor && newColor !== this.#gradient.stops[idx].color) {
|
|
5956
|
-
this.#gradient.stops[idx].color = newColor;
|
|
5957
|
-
this.#syncFillPicker();
|
|
5958
|
-
this.#emitInput();
|
|
5959
|
-
}
|
|
5960
|
-
}
|
|
5961
|
-
});
|
|
5962
|
-
this.#track
|
|
5963
|
-
.querySelectorAll("fig-handle:not(.fig-input-gradient-ghost)")
|
|
5964
|
-
.forEach((h) => {
|
|
5965
|
-
this.#colorObserver.observe(h, {
|
|
5966
|
-
attributes: true,
|
|
5967
|
-
attributeFilter: ["color"],
|
|
5968
|
-
});
|
|
5969
|
-
});
|
|
6133
|
+
}
|
|
5970
6134
|
}
|
|
5971
6135
|
});
|
|
6136
|
+
this.#track
|
|
6137
|
+
.querySelectorAll("fig-handle:not(.fig-input-gradient-ghost)")
|
|
6138
|
+
.forEach((h) => {
|
|
6139
|
+
this.#colorObserver.observe(h, {
|
|
6140
|
+
attributes: true,
|
|
6141
|
+
attributeFilter: ["color"],
|
|
6142
|
+
});
|
|
6143
|
+
});
|
|
5972
6144
|
}
|
|
5973
6145
|
|
|
5974
6146
|
#emitInput() {
|
|
@@ -6009,15 +6181,11 @@ class FigInputGradient extends HTMLElement {
|
|
|
6009
6181
|
switch (name) {
|
|
6010
6182
|
case "value":
|
|
6011
6183
|
this.#parseValue();
|
|
6012
|
-
|
|
6013
|
-
this.#syncFillPicker();
|
|
6014
|
-
}
|
|
6184
|
+
this.#syncChit();
|
|
6015
6185
|
this.#syncHandles();
|
|
6016
6186
|
break;
|
|
6017
6187
|
case "disabled":
|
|
6018
|
-
|
|
6019
|
-
case "picker-anchor":
|
|
6020
|
-
if (this.#fillPicker) this.#render();
|
|
6188
|
+
this.#render();
|
|
6021
6189
|
break;
|
|
6022
6190
|
}
|
|
6023
6191
|
}
|
|
@@ -10292,6 +10460,7 @@ class FigFillPicker extends HTMLElement {
|
|
|
10292
10460
|
drag
|
|
10293
10461
|
drag-surface=".fig-fill-picker-color-area"
|
|
10294
10462
|
drag-axes="x,y"
|
|
10463
|
+
drag-snapping="modifier"
|
|
10295
10464
|
></fig-handle>
|
|
10296
10465
|
</fig-preview>
|
|
10297
10466
|
<div class="fig-fill-picker-sliders">
|
|
@@ -11879,7 +12048,11 @@ class FigColorTip extends HTMLElement {
|
|
|
11879
12048
|
#boundHandleChange = this.#handlePickerChange.bind(this);
|
|
11880
12049
|
|
|
11881
12050
|
static get observedAttributes() {
|
|
11882
|
-
return ["value", "selected", "disabled", "alpha"];
|
|
12051
|
+
return ["value", "selected", "disabled", "alpha", "control"];
|
|
12052
|
+
}
|
|
12053
|
+
|
|
12054
|
+
get #controlMode() {
|
|
12055
|
+
return this.getAttribute("control") || "color";
|
|
11883
12056
|
}
|
|
11884
12057
|
|
|
11885
12058
|
connectedCallback() {
|
|
@@ -11889,6 +12062,7 @@ class FigColorTip extends HTMLElement {
|
|
|
11889
12062
|
|
|
11890
12063
|
disconnectedCallback() {
|
|
11891
12064
|
this.#teardownListeners();
|
|
12065
|
+
this.removeEventListener("click", this.#handleControlClick);
|
|
11892
12066
|
}
|
|
11893
12067
|
|
|
11894
12068
|
#teardownListeners() {
|
|
@@ -11913,6 +12087,17 @@ class FigColorTip extends HTMLElement {
|
|
|
11913
12087
|
}
|
|
11914
12088
|
|
|
11915
12089
|
#render() {
|
|
12090
|
+
const mode = this.#controlMode;
|
|
12091
|
+
if (mode === "add" || mode === "remove") {
|
|
12092
|
+
const icon = mode === "add" ? "var(--icon-add)" : "var(--icon-minus)";
|
|
12093
|
+
this.innerHTML = `<fig-button icon variant="ghost"><span class="fig-mask-icon" style="--icon: ${icon}"></span></fig-button>`;
|
|
12094
|
+
this.#fillPicker = null;
|
|
12095
|
+
this.#chit = null;
|
|
12096
|
+
this.addEventListener("click", this.#handleControlClick);
|
|
12097
|
+
return;
|
|
12098
|
+
}
|
|
12099
|
+
this.removeEventListener("click", this.#handleControlClick);
|
|
12100
|
+
|
|
11916
12101
|
const color = this.#normalizeColor(this.getAttribute("value"));
|
|
11917
12102
|
const alphaAttr = this.#alphaEnabled ? "" : 'alpha="false"';
|
|
11918
12103
|
this.innerHTML = `
|
|
@@ -11931,6 +12116,13 @@ class FigColorTip extends HTMLElement {
|
|
|
11931
12116
|
});
|
|
11932
12117
|
}
|
|
11933
12118
|
|
|
12119
|
+
#handleControlClick = () => {
|
|
12120
|
+
const mode = this.#controlMode;
|
|
12121
|
+
this.dispatchEvent(
|
|
12122
|
+
new CustomEvent(mode, { bubbles: true, composed: true }),
|
|
12123
|
+
);
|
|
12124
|
+
};
|
|
12125
|
+
|
|
11934
12126
|
#normalizeHex(hex) {
|
|
11935
12127
|
if (!hex) return "#D9D9D9";
|
|
11936
12128
|
const raw = hex.replace("#", "").trim();
|
|
@@ -12059,6 +12251,9 @@ class FigColorTip extends HTMLElement {
|
|
|
12059
12251
|
if (!this.isConnected) return;
|
|
12060
12252
|
|
|
12061
12253
|
switch (name) {
|
|
12254
|
+
case "control":
|
|
12255
|
+
this.#render();
|
|
12256
|
+
break;
|
|
12062
12257
|
case "value":
|
|
12063
12258
|
case "selected":
|
|
12064
12259
|
case "disabled":
|
|
@@ -12668,6 +12863,7 @@ class FigHandle extends HTMLElement {
|
|
|
12668
12863
|
"drag-snapping",
|
|
12669
12864
|
"value",
|
|
12670
12865
|
"type",
|
|
12866
|
+
"control",
|
|
12671
12867
|
];
|
|
12672
12868
|
|
|
12673
12869
|
#isDragging = false;
|
|
@@ -12676,6 +12872,18 @@ class FigHandle extends HTMLElement {
|
|
|
12676
12872
|
#applyingValue = false;
|
|
12677
12873
|
#colorTip = null;
|
|
12678
12874
|
|
|
12875
|
+
get #controlMode() {
|
|
12876
|
+
return this.getAttribute("control") || null;
|
|
12877
|
+
}
|
|
12878
|
+
|
|
12879
|
+
get #hasControlMode() {
|
|
12880
|
+
return this.#controlMode === "add" || this.#controlMode === "remove";
|
|
12881
|
+
}
|
|
12882
|
+
|
|
12883
|
+
get #isGhost() {
|
|
12884
|
+
return this.classList.contains("fig-input-gradient-ghost");
|
|
12885
|
+
}
|
|
12886
|
+
|
|
12679
12887
|
get #dragEnabled() {
|
|
12680
12888
|
const v = this.getAttribute("drag");
|
|
12681
12889
|
return v !== null && v !== "false";
|
|
@@ -12806,6 +13014,7 @@ class FigHandle extends HTMLElement {
|
|
|
12806
13014
|
document.addEventListener("pointerdown", this.#handleDeselect);
|
|
12807
13015
|
const initial = this.getAttribute("value");
|
|
12808
13016
|
if (initial) this.#applyValue(initial);
|
|
13017
|
+
if (this.#hasControlMode && !this.#isGhost) this.#showColorTip();
|
|
12809
13018
|
}
|
|
12810
13019
|
|
|
12811
13020
|
disconnectedCallback() {
|
|
@@ -12817,6 +13026,7 @@ class FigHandle extends HTMLElement {
|
|
|
12817
13026
|
|
|
12818
13027
|
#handleSelect = (e) => {
|
|
12819
13028
|
if (this.hasAttribute("disabled")) return;
|
|
13029
|
+
if (this.#hasControlMode) return;
|
|
12820
13030
|
if (this.#didDrag) {
|
|
12821
13031
|
this.#didDrag = false;
|
|
12822
13032
|
return;
|
|
@@ -12826,6 +13036,7 @@ class FigHandle extends HTMLElement {
|
|
|
12826
13036
|
};
|
|
12827
13037
|
|
|
12828
13038
|
#handleDeselect = (e) => {
|
|
13039
|
+
if (this.#hasControlMode) return;
|
|
12829
13040
|
if (this.contains(e.target)) return;
|
|
12830
13041
|
if (this.#colorTip && e.target.closest?.("dialog, [popover]")) return;
|
|
12831
13042
|
this.removeAttribute("selected");
|
|
@@ -12834,7 +13045,7 @@ class FigHandle extends HTMLElement {
|
|
|
12834
13045
|
|
|
12835
13046
|
attributeChangedCallback(name, _old, value) {
|
|
12836
13047
|
if (name === "color") {
|
|
12837
|
-
if (!value || value === "false") {
|
|
13048
|
+
if (!value || value === "false" || value === "true") {
|
|
12838
13049
|
this.style.removeProperty("--fill");
|
|
12839
13050
|
} else {
|
|
12840
13051
|
this.style.setProperty("--fill", value);
|
|
@@ -12844,6 +13055,14 @@ class FigHandle extends HTMLElement {
|
|
|
12844
13055
|
if (name === "value" && !this.#applyingValue && !this.#isDragging) {
|
|
12845
13056
|
this.#applyValue(value);
|
|
12846
13057
|
}
|
|
13058
|
+
if (name === "control" && !this.#isGhost) {
|
|
13059
|
+
if (this.#hasControlMode) {
|
|
13060
|
+
this.#hideColorTip();
|
|
13061
|
+
this.#showColorTip();
|
|
13062
|
+
} else {
|
|
13063
|
+
this.#hideColorTip();
|
|
13064
|
+
}
|
|
13065
|
+
}
|
|
12847
13066
|
}
|
|
12848
13067
|
|
|
12849
13068
|
#syncDrag() {
|
|
@@ -12920,28 +13139,21 @@ class FigHandle extends HTMLElement {
|
|
|
12920
13139
|
}
|
|
12921
13140
|
};
|
|
12922
13141
|
|
|
12923
|
-
const isColorType = this.getAttribute("type") === "color";
|
|
12924
|
-
if (!isColorType) {
|
|
12925
|
-
clampAndApply(e.clientX, e.clientY, e.shiftKey);
|
|
12926
|
-
}
|
|
12927
|
-
this.style.cursor = "grabbing";
|
|
12928
|
-
if (!isColorType) {
|
|
12929
|
-
this.dispatchEvent(
|
|
12930
|
-
new CustomEvent("input", {
|
|
12931
|
-
bubbles: true,
|
|
12932
|
-
detail: this.#positionDetail(containerRect),
|
|
12933
|
-
}),
|
|
12934
|
-
);
|
|
12935
|
-
}
|
|
12936
|
-
|
|
12937
13142
|
const onMove = (e) => {
|
|
12938
13143
|
if (!this.#isDragging) return;
|
|
13144
|
+
if (!this.#didDrag) {
|
|
13145
|
+
this.classList.add("dragging");
|
|
13146
|
+
this.style.cursor = "grabbing";
|
|
13147
|
+
}
|
|
12939
13148
|
this.#didDrag = true;
|
|
12940
13149
|
clampAndApply(e.clientX, e.clientY, e.shiftKey);
|
|
12941
13150
|
this.dispatchEvent(
|
|
12942
13151
|
new CustomEvent("input", {
|
|
12943
13152
|
bubbles: true,
|
|
12944
|
-
detail:
|
|
13153
|
+
detail: {
|
|
13154
|
+
...this.#positionDetail(container.getBoundingClientRect()),
|
|
13155
|
+
shiftKey: e.shiftKey,
|
|
13156
|
+
},
|
|
12945
13157
|
}),
|
|
12946
13158
|
);
|
|
12947
13159
|
};
|
|
@@ -12949,18 +13161,30 @@ class FigHandle extends HTMLElement {
|
|
|
12949
13161
|
const onUp = (e) => {
|
|
12950
13162
|
this.#isDragging = false;
|
|
12951
13163
|
this.style.cursor = "";
|
|
13164
|
+
this.classList.remove("dragging");
|
|
12952
13165
|
window.removeEventListener("pointermove", onMove);
|
|
12953
13166
|
window.removeEventListener("pointerup", onUp);
|
|
12954
|
-
if (this.#didDrag
|
|
13167
|
+
if (this.#didDrag) {
|
|
12955
13168
|
clampAndApply(e.clientX, e.clientY, e.shiftKey);
|
|
13169
|
+
this.#syncValueAttribute();
|
|
13170
|
+
this.dispatchEvent(
|
|
13171
|
+
new CustomEvent("change", {
|
|
13172
|
+
bubbles: true,
|
|
13173
|
+
detail: this.#positionDetail(container.getBoundingClientRect()),
|
|
13174
|
+
}),
|
|
13175
|
+
);
|
|
13176
|
+
const swallowClick = (evt) => {
|
|
13177
|
+
evt.stopPropagation();
|
|
13178
|
+
evt.preventDefault();
|
|
13179
|
+
};
|
|
13180
|
+
this.addEventListener("click", swallowClick, {
|
|
13181
|
+
capture: true,
|
|
13182
|
+
once: true,
|
|
13183
|
+
});
|
|
13184
|
+
} else {
|
|
13185
|
+
this.#syncValueAttribute();
|
|
12956
13186
|
}
|
|
12957
|
-
this.#
|
|
12958
|
-
this.dispatchEvent(
|
|
12959
|
-
new CustomEvent("change", {
|
|
12960
|
-
bubbles: true,
|
|
12961
|
-
detail: this.#positionDetail(container.getBoundingClientRect()),
|
|
12962
|
-
}),
|
|
12963
|
-
);
|
|
13187
|
+
this.#didDrag = false;
|
|
12964
13188
|
};
|
|
12965
13189
|
|
|
12966
13190
|
window.addEventListener("pointermove", onMove);
|
|
@@ -12970,12 +13194,17 @@ class FigHandle extends HTMLElement {
|
|
|
12970
13194
|
#showColorTip() {
|
|
12971
13195
|
if (this.#colorTip) return;
|
|
12972
13196
|
const tip = document.createElement("fig-color-tip");
|
|
12973
|
-
|
|
12974
|
-
|
|
12975
|
-
|
|
12976
|
-
|
|
13197
|
+
if (this.#hasControlMode) {
|
|
13198
|
+
tip.setAttribute("control", this.#controlMode);
|
|
13199
|
+
} else {
|
|
13200
|
+
tip.setAttribute("value", this.getAttribute("color") || "#D9D9D9");
|
|
13201
|
+
tip.setAttribute("alpha", "true");
|
|
13202
|
+
tip.setAttribute("selected", "");
|
|
13203
|
+
}
|
|
12977
13204
|
tip.addEventListener("input", this.#handleColorTipInput);
|
|
12978
13205
|
tip.addEventListener("change", this.#handleColorTipChange);
|
|
13206
|
+
tip.addEventListener("add", this.#handleColorTipControl);
|
|
13207
|
+
tip.addEventListener("remove", this.#handleColorTipControl);
|
|
12979
13208
|
this.appendChild(tip);
|
|
12980
13209
|
this.#colorTip = tip;
|
|
12981
13210
|
}
|
|
@@ -12984,6 +13213,8 @@ class FigHandle extends HTMLElement {
|
|
|
12984
13213
|
if (!this.#colorTip) return;
|
|
12985
13214
|
this.#colorTip.removeEventListener("input", this.#handleColorTipInput);
|
|
12986
13215
|
this.#colorTip.removeEventListener("change", this.#handleColorTipChange);
|
|
13216
|
+
this.#colorTip.removeEventListener("add", this.#handleColorTipControl);
|
|
13217
|
+
this.#colorTip.removeEventListener("remove", this.#handleColorTipControl);
|
|
12987
13218
|
this.#colorTip.remove();
|
|
12988
13219
|
this.#colorTip = null;
|
|
12989
13220
|
}
|
|
@@ -12998,6 +13229,13 @@ class FigHandle extends HTMLElement {
|
|
|
12998
13229
|
if (e.detail?.color) this.setAttribute("color", e.detail.color);
|
|
12999
13230
|
};
|
|
13000
13231
|
|
|
13232
|
+
#handleColorTipControl = (e) => {
|
|
13233
|
+
e.stopPropagation();
|
|
13234
|
+
this.dispatchEvent(
|
|
13235
|
+
new CustomEvent(e.type, { bubbles: true, composed: true }),
|
|
13236
|
+
);
|
|
13237
|
+
};
|
|
13238
|
+
|
|
13001
13239
|
#positionDetail(containerRect) {
|
|
13002
13240
|
const hw = this.offsetWidth / 2;
|
|
13003
13241
|
const hh = this.offsetHeight / 2;
|
package/package.json
CHANGED