@rogieking/figui3 3.21.2 → 3.22.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/.cursor/skills/propkit/SKILL.md +2 -3
- package/README.md +1 -1
- package/components.css +109 -70
- package/fig.js +647 -147
- package/package.json +1 -1
package/fig.js
CHANGED
|
@@ -947,6 +947,78 @@ class FigTooltip extends HTMLElement {
|
|
|
947
947
|
this.hidePopup();
|
|
948
948
|
}
|
|
949
949
|
}
|
|
950
|
+
|
|
951
|
+
static #programmatic = new WeakMap();
|
|
952
|
+
|
|
953
|
+
static show(anchor, text, options = {}) {
|
|
954
|
+
FigTooltip.hide(anchor);
|
|
955
|
+
const delay = options.delay ?? 500;
|
|
956
|
+
const warm =
|
|
957
|
+
Date.now() - FigTooltip.#lastShownAt < FigTooltip.#warmupWindow;
|
|
958
|
+
const effectiveDelay = warm ? 0 : delay;
|
|
959
|
+
|
|
960
|
+
const state = { timeout: null, popup: null };
|
|
961
|
+
FigTooltip.#programmatic.set(anchor, state);
|
|
962
|
+
|
|
963
|
+
state.timeout = setTimeout(() => {
|
|
964
|
+
const popup = document.createElement("span");
|
|
965
|
+
popup.setAttribute("class", "fig-tooltip");
|
|
966
|
+
popup.setAttribute("role", "tooltip");
|
|
967
|
+
popup.style.position = "fixed";
|
|
968
|
+
popup.style.pointerEvents = "none";
|
|
969
|
+
const content = document.createElement("span");
|
|
970
|
+
content.innerText = text;
|
|
971
|
+
popup.append(content);
|
|
972
|
+
|
|
973
|
+
const parentDialog = anchor.closest("dialog");
|
|
974
|
+
if (parentDialog && parentDialog.open) {
|
|
975
|
+
parentDialog.append(popup);
|
|
976
|
+
} else {
|
|
977
|
+
document.body.append(popup);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
const rect = anchor.getBoundingClientRect();
|
|
981
|
+
const popupRect = popup.getBoundingClientRect();
|
|
982
|
+
const container = popup.parentElement;
|
|
983
|
+
const containerRect =
|
|
984
|
+
container && container !== document.body
|
|
985
|
+
? container.getBoundingClientRect()
|
|
986
|
+
: { left: 0, top: 0 };
|
|
987
|
+
|
|
988
|
+
let top = rect.top - popupRect.height - 4 - containerRect.top;
|
|
989
|
+
let left =
|
|
990
|
+
rect.left + (rect.width - popupRect.width) / 2 - containerRect.left;
|
|
991
|
+
popup.setAttribute("position", "top");
|
|
992
|
+
|
|
993
|
+
if (top + containerRect.top < 0) {
|
|
994
|
+
popup.setAttribute("position", "bottom");
|
|
995
|
+
top = rect.bottom + 4 - containerRect.top;
|
|
996
|
+
}
|
|
997
|
+
if (left + containerRect.left < 8) {
|
|
998
|
+
left = 8 - containerRect.left;
|
|
999
|
+
}
|
|
1000
|
+
if (left + popupRect.width + containerRect.left > window.innerWidth - 8) {
|
|
1001
|
+
left = window.innerWidth - popupRect.width - 8 - containerRect.left;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
const targetCenter = rect.left - containerRect.left + rect.width / 2;
|
|
1005
|
+
popup.style.setProperty("--beak-offset", `${targetCenter - left}px`);
|
|
1006
|
+
popup.style.top = `${top}px`;
|
|
1007
|
+
popup.style.left = `${left}px`;
|
|
1008
|
+
popup.style.zIndex = figGetHighestZIndex() + 1;
|
|
1009
|
+
|
|
1010
|
+
state.popup = popup;
|
|
1011
|
+
FigTooltip.#lastShownAt = Date.now();
|
|
1012
|
+
}, effectiveDelay);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
static hide(anchor) {
|
|
1016
|
+
const state = FigTooltip.#programmatic.get(anchor);
|
|
1017
|
+
if (!state) return;
|
|
1018
|
+
clearTimeout(state.timeout);
|
|
1019
|
+
if (state.popup) state.popup.remove();
|
|
1020
|
+
FigTooltip.#programmatic.delete(anchor);
|
|
1021
|
+
}
|
|
950
1022
|
}
|
|
951
1023
|
|
|
952
1024
|
customElements.define("fig-tooltip", FigTooltip);
|
|
@@ -3533,8 +3605,12 @@ class FigInputText extends HTMLElement {
|
|
|
3533
3605
|
valueTransformed = this.#formatNumber(valueTransformed);
|
|
3534
3606
|
this.value = value;
|
|
3535
3607
|
this.input.value = valueTransformed;
|
|
3536
|
-
this.dispatchEvent(
|
|
3537
|
-
|
|
3608
|
+
this.dispatchEvent(
|
|
3609
|
+
new CustomEvent("input", { detail: this.value, bubbles: true }),
|
|
3610
|
+
);
|
|
3611
|
+
this.dispatchEvent(
|
|
3612
|
+
new CustomEvent("change", { detail: this.value, bubbles: true }),
|
|
3613
|
+
);
|
|
3538
3614
|
}
|
|
3539
3615
|
#handleMouseDown(e) {
|
|
3540
3616
|
if (this.type !== "number") return;
|
|
@@ -4023,8 +4099,12 @@ class FigInputNumber extends HTMLElement {
|
|
|
4023
4099
|
value = this.#sanitizeInput(value, false);
|
|
4024
4100
|
this.value = value;
|
|
4025
4101
|
this.input.value = this.#formatWithUnit(this.value);
|
|
4026
|
-
this.dispatchEvent(
|
|
4027
|
-
|
|
4102
|
+
this.dispatchEvent(
|
|
4103
|
+
new CustomEvent("input", { detail: this.value, bubbles: true }),
|
|
4104
|
+
);
|
|
4105
|
+
this.dispatchEvent(
|
|
4106
|
+
new CustomEvent("change", { detail: this.value, bubbles: true }),
|
|
4107
|
+
);
|
|
4028
4108
|
}
|
|
4029
4109
|
|
|
4030
4110
|
#handleMouseDown(e) {
|
|
@@ -4209,6 +4289,10 @@ customElements.define("fig-avatar", FigAvatar);
|
|
|
4209
4289
|
|
|
4210
4290
|
/* Form Field */
|
|
4211
4291
|
class FigField extends HTMLElement {
|
|
4292
|
+
#toggleable = false;
|
|
4293
|
+
#chevron = null;
|
|
4294
|
+
#boundToggle = null;
|
|
4295
|
+
|
|
4212
4296
|
constructor() {
|
|
4213
4297
|
super();
|
|
4214
4298
|
}
|
|
@@ -4223,15 +4307,65 @@ class FigField extends HTMLElement {
|
|
|
4223
4307
|
this.input = Array.from(this.childNodes).find((node) =>
|
|
4224
4308
|
node.nodeName.toLowerCase().startsWith("fig-"),
|
|
4225
4309
|
);
|
|
4226
|
-
|
|
4310
|
+
|
|
4311
|
+
this.#toggleable = !!(this.input && "open" in this.input);
|
|
4312
|
+
|
|
4313
|
+
if (this.#toggleable && this.label) {
|
|
4314
|
+
this.#chevron = document.createElement("span");
|
|
4315
|
+
this.#chevron.className = "fig-mask-icon fig-field-chevron";
|
|
4316
|
+
this.insertBefore(this.#chevron, this.label);
|
|
4317
|
+
|
|
4318
|
+
this.#boundToggle = (e) => {
|
|
4319
|
+
e.preventDefault();
|
|
4320
|
+
e.stopPropagation();
|
|
4321
|
+
if (this.input && typeof this.input.open !== "undefined") {
|
|
4322
|
+
this.input.open = !this.input.open;
|
|
4323
|
+
}
|
|
4324
|
+
};
|
|
4325
|
+
this.#chevron.addEventListener("click", this.#boundToggle);
|
|
4326
|
+
this.label.addEventListener("click", this.#boundToggle);
|
|
4327
|
+
} else if (this.input && this.label) {
|
|
4227
4328
|
this.label.addEventListener("click", this.focus.bind(this));
|
|
4329
|
+
}
|
|
4330
|
+
|
|
4331
|
+
if (this.input && this.label && !this.#toggleable) {
|
|
4228
4332
|
let inputId = this.input.getAttribute("id") || figUniqueId();
|
|
4229
4333
|
this.input.setAttribute("id", inputId);
|
|
4230
4334
|
this.label.setAttribute("for", inputId);
|
|
4231
4335
|
}
|
|
4336
|
+
|
|
4337
|
+
if (this.label) {
|
|
4338
|
+
this.label.addEventListener(
|
|
4339
|
+
"pointerenter",
|
|
4340
|
+
this.#onLabelEnter.bind(this),
|
|
4341
|
+
);
|
|
4342
|
+
this.label.addEventListener(
|
|
4343
|
+
"pointerleave",
|
|
4344
|
+
this.#onLabelLeave.bind(this),
|
|
4345
|
+
);
|
|
4346
|
+
}
|
|
4232
4347
|
});
|
|
4233
4348
|
}
|
|
4234
4349
|
|
|
4350
|
+
disconnectedCallback() {
|
|
4351
|
+
if (this.label) FigTooltip.hide(this.label);
|
|
4352
|
+
if (this.label && this.#boundToggle) {
|
|
4353
|
+
this.label.removeEventListener("click", this.#boundToggle);
|
|
4354
|
+
}
|
|
4355
|
+
if (this.#chevron && this.#boundToggle) {
|
|
4356
|
+
this.#chevron.removeEventListener("click", this.#boundToggle);
|
|
4357
|
+
}
|
|
4358
|
+
}
|
|
4359
|
+
|
|
4360
|
+
#onLabelEnter() {
|
|
4361
|
+
if (!this.label || this.label.scrollWidth <= this.label.clientWidth) return;
|
|
4362
|
+
FigTooltip.show(this.label, this.label.textContent.trim());
|
|
4363
|
+
}
|
|
4364
|
+
|
|
4365
|
+
#onLabelLeave() {
|
|
4366
|
+
if (this.label) FigTooltip.hide(this.label);
|
|
4367
|
+
}
|
|
4368
|
+
|
|
4235
4369
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
4236
4370
|
switch (name) {
|
|
4237
4371
|
case "label":
|
|
@@ -4243,7 +4377,18 @@ class FigField extends HTMLElement {
|
|
|
4243
4377
|
}
|
|
4244
4378
|
|
|
4245
4379
|
focus() {
|
|
4246
|
-
this.input
|
|
4380
|
+
if (!this.input) return;
|
|
4381
|
+
if (this.input.contains(document.activeElement)) return;
|
|
4382
|
+
const nativeInputs = this.input.querySelectorAll("input, select, textarea");
|
|
4383
|
+
if (nativeInputs.length === 1) {
|
|
4384
|
+
nativeInputs[0].focus();
|
|
4385
|
+
nativeInputs[0].click();
|
|
4386
|
+
} else {
|
|
4387
|
+
this.input.focus();
|
|
4388
|
+
if (nativeInputs.length === 0) {
|
|
4389
|
+
this.input.click();
|
|
4390
|
+
}
|
|
4391
|
+
}
|
|
4247
4392
|
}
|
|
4248
4393
|
}
|
|
4249
4394
|
customElements.define("fig-field", FigField);
|
|
@@ -4578,7 +4723,7 @@ class FigInputColor extends HTMLElement {
|
|
|
4578
4723
|
const disabledAttr = disabled ? " disabled" : "";
|
|
4579
4724
|
|
|
4580
4725
|
let html = ``;
|
|
4581
|
-
const showText = this.getAttribute("text")
|
|
4726
|
+
const showText = this.getAttribute("text") !== "false";
|
|
4582
4727
|
if (showText) {
|
|
4583
4728
|
let label = `<fig-input-text
|
|
4584
4729
|
type="text"
|
|
@@ -4801,22 +4946,35 @@ class FigInputColor extends HTMLElement {
|
|
|
4801
4946
|
}
|
|
4802
4947
|
|
|
4803
4948
|
#emitInputEvent() {
|
|
4804
|
-
this.dispatchEvent(
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4949
|
+
this.dispatchEvent(
|
|
4950
|
+
new CustomEvent("input", {
|
|
4951
|
+
bubbles: true,
|
|
4952
|
+
cancelable: true,
|
|
4953
|
+
detail: { value: this.value, hex: this.hex, rgba: this.rgba },
|
|
4954
|
+
}),
|
|
4955
|
+
);
|
|
4809
4956
|
}
|
|
4810
4957
|
#emitChangeEvent() {
|
|
4811
|
-
this.dispatchEvent(
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4958
|
+
this.dispatchEvent(
|
|
4959
|
+
new CustomEvent("change", {
|
|
4960
|
+
bubbles: true,
|
|
4961
|
+
cancelable: true,
|
|
4962
|
+
detail: { value: this.value, hex: this.hex, rgba: this.rgba },
|
|
4963
|
+
}),
|
|
4964
|
+
);
|
|
4816
4965
|
}
|
|
4817
4966
|
|
|
4818
4967
|
static get observedAttributes() {
|
|
4819
|
-
return [
|
|
4968
|
+
return [
|
|
4969
|
+
"value",
|
|
4970
|
+
"style",
|
|
4971
|
+
"mode",
|
|
4972
|
+
"picker",
|
|
4973
|
+
"experimental",
|
|
4974
|
+
"alpha",
|
|
4975
|
+
"text",
|
|
4976
|
+
"disabled",
|
|
4977
|
+
];
|
|
4820
4978
|
}
|
|
4821
4979
|
|
|
4822
4980
|
get mode() {
|
|
@@ -4877,7 +5035,9 @@ class FigInputColor extends HTMLElement {
|
|
|
4877
5035
|
}
|
|
4878
5036
|
|
|
4879
5037
|
get #disabled() {
|
|
4880
|
-
return
|
|
5038
|
+
return (
|
|
5039
|
+
this.hasAttribute("disabled") && this.getAttribute("disabled") !== "false"
|
|
5040
|
+
);
|
|
4881
5041
|
}
|
|
4882
5042
|
|
|
4883
5043
|
#syncDisabled() {
|
|
@@ -5076,9 +5236,15 @@ function figRGBToOklab(r, g, b) {
|
|
|
5076
5236
|
const lr = figRGBToLinear(r);
|
|
5077
5237
|
const lg = figRGBToLinear(g);
|
|
5078
5238
|
const lb = figRGBToLinear(b);
|
|
5079
|
-
const l_ = Math.cbrt(
|
|
5080
|
-
|
|
5081
|
-
|
|
5239
|
+
const l_ = Math.cbrt(
|
|
5240
|
+
0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb,
|
|
5241
|
+
);
|
|
5242
|
+
const m_ = Math.cbrt(
|
|
5243
|
+
0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb,
|
|
5244
|
+
);
|
|
5245
|
+
const s_ = Math.cbrt(
|
|
5246
|
+
0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb,
|
|
5247
|
+
);
|
|
5082
5248
|
return {
|
|
5083
5249
|
l: 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,
|
|
5084
5250
|
a: 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,
|
|
@@ -5101,7 +5267,11 @@ function figOklabToRGB(L, a, b) {
|
|
|
5101
5267
|
}
|
|
5102
5268
|
|
|
5103
5269
|
function figOklabToOklch(L, a, b) {
|
|
5104
|
-
return {
|
|
5270
|
+
return {
|
|
5271
|
+
l: L,
|
|
5272
|
+
c: Math.sqrt(a * a + b * b),
|
|
5273
|
+
h: (Math.atan2(b, a) * 180) / Math.PI,
|
|
5274
|
+
};
|
|
5105
5275
|
}
|
|
5106
5276
|
|
|
5107
5277
|
function figOklchToOklab(l, c, h) {
|
|
@@ -5130,15 +5300,21 @@ function figInterpolateHue(h1, h2, t, mode) {
|
|
|
5130
5300
|
else if (diff < -180) diff += 360;
|
|
5131
5301
|
break;
|
|
5132
5302
|
}
|
|
5133
|
-
return ((a + diff * t) % 360 + 360) % 360;
|
|
5303
|
+
return (((a + diff * t) % 360) + 360) % 360;
|
|
5134
5304
|
}
|
|
5135
5305
|
|
|
5136
|
-
function figSampleGradientAt(
|
|
5306
|
+
function figSampleGradientAt(
|
|
5307
|
+
stops,
|
|
5308
|
+
position,
|
|
5309
|
+
interpolationSpace,
|
|
5310
|
+
hueInterpolation,
|
|
5311
|
+
) {
|
|
5137
5312
|
const sorted = [...stops].sort((a, b) => a.position - b.position);
|
|
5138
5313
|
const pos = position * 100;
|
|
5139
5314
|
if (sorted.length === 0) return "#888888";
|
|
5140
5315
|
if (pos <= sorted[0].position) return sorted[0].color;
|
|
5141
|
-
if (pos >= sorted[sorted.length - 1].position)
|
|
5316
|
+
if (pos >= sorted[sorted.length - 1].position)
|
|
5317
|
+
return sorted[sorted.length - 1].color;
|
|
5142
5318
|
|
|
5143
5319
|
let i = 0;
|
|
5144
5320
|
while (i < sorted.length - 1 && sorted[i + 1].position < pos) i++;
|
|
@@ -5154,8 +5330,12 @@ function figSampleGradientAt(stops, position, interpolationSpace, hueInterpolati
|
|
|
5154
5330
|
const space = interpolationSpace || "oklab";
|
|
5155
5331
|
|
|
5156
5332
|
if (space === "srgb-linear") {
|
|
5157
|
-
const lr1 = figRGBToLinear(c1.r),
|
|
5158
|
-
|
|
5333
|
+
const lr1 = figRGBToLinear(c1.r),
|
|
5334
|
+
lg1 = figRGBToLinear(c1.g),
|
|
5335
|
+
lb1 = figRGBToLinear(c1.b);
|
|
5336
|
+
const lr2 = figRGBToLinear(c2.r),
|
|
5337
|
+
lg2 = figRGBToLinear(c2.g),
|
|
5338
|
+
lb2 = figRGBToLinear(c2.b);
|
|
5159
5339
|
r = figLinearToSRGB(lr1 + (lr2 - lr1) * t);
|
|
5160
5340
|
g = figLinearToSRGB(lg1 + (lg2 - lg1) * t);
|
|
5161
5341
|
b = figLinearToSRGB(lb1 + (lb2 - lb1) * t);
|
|
@@ -5166,10 +5346,17 @@ function figSampleGradientAt(stops, position, interpolationSpace, hueInterpolati
|
|
|
5166
5346
|
const lch2 = figOklabToOklch(lab2.l, lab2.a, lab2.b);
|
|
5167
5347
|
const L = lch1.l + (lch2.l - lch1.l) * t;
|
|
5168
5348
|
const C = lch1.c + (lch2.c - lch1.c) * t;
|
|
5169
|
-
const H = figInterpolateHue(
|
|
5349
|
+
const H = figInterpolateHue(
|
|
5350
|
+
lch1.h,
|
|
5351
|
+
lch2.h,
|
|
5352
|
+
t,
|
|
5353
|
+
hueInterpolation || "shorter",
|
|
5354
|
+
);
|
|
5170
5355
|
const lab = figOklchToOklab(L, C, H);
|
|
5171
5356
|
const rgb = figOklabToRGB(lab.l, lab.a, lab.b);
|
|
5172
|
-
r = rgb.r;
|
|
5357
|
+
r = rgb.r;
|
|
5358
|
+
g = rgb.g;
|
|
5359
|
+
b = rgb.b;
|
|
5173
5360
|
} else {
|
|
5174
5361
|
const lab1 = figRGBToOklab(c1.r, c1.g, c1.b);
|
|
5175
5362
|
const lab2 = figRGBToOklab(c2.r, c2.g, c2.b);
|
|
@@ -5177,7 +5364,9 @@ function figSampleGradientAt(stops, position, interpolationSpace, hueInterpolati
|
|
|
5177
5364
|
const a = lab1.a + (lab2.a - lab1.a) * t;
|
|
5178
5365
|
const bv = lab1.b + (lab2.b - lab1.b) * t;
|
|
5179
5366
|
const rgb = figOklabToRGB(L, a, bv);
|
|
5180
|
-
r = rgb.r;
|
|
5367
|
+
r = rgb.r;
|
|
5368
|
+
g = rgb.g;
|
|
5369
|
+
b = rgb.b;
|
|
5181
5370
|
}
|
|
5182
5371
|
|
|
5183
5372
|
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`.toUpperCase();
|
|
@@ -5347,7 +5536,11 @@ class FigInputFill extends HTMLElement {
|
|
|
5347
5536
|
|
|
5348
5537
|
#syncDisabled() {
|
|
5349
5538
|
const disabled = this.hasAttribute("disabled");
|
|
5350
|
-
for (const child of [
|
|
5539
|
+
for (const child of [
|
|
5540
|
+
this.#fillPicker,
|
|
5541
|
+
this.#opacityInput,
|
|
5542
|
+
this.#hexInput,
|
|
5543
|
+
]) {
|
|
5351
5544
|
if (!child) continue;
|
|
5352
5545
|
if (disabled) child.setAttribute("disabled", "");
|
|
5353
5546
|
else child.removeAttribute("disabled");
|
|
@@ -5911,11 +6104,28 @@ class FigInputPalette extends HTMLElement {
|
|
|
5911
6104
|
#renderRAF = null;
|
|
5912
6105
|
|
|
5913
6106
|
static get observedAttributes() {
|
|
5914
|
-
return ["value", "disabled", "min", "max", "
|
|
6107
|
+
return ["value", "disabled", "min", "max", "open", "add"];
|
|
6108
|
+
}
|
|
6109
|
+
|
|
6110
|
+
get open() {
|
|
6111
|
+
return this.hasAttribute("open") && this.getAttribute("open") !== "false";
|
|
5915
6112
|
}
|
|
5916
6113
|
|
|
5917
|
-
|
|
5918
|
-
|
|
6114
|
+
set open(value) {
|
|
6115
|
+
const was = this.open;
|
|
6116
|
+
if (value) {
|
|
6117
|
+
this.setAttribute("open", "");
|
|
6118
|
+
} else {
|
|
6119
|
+
this.removeAttribute("open");
|
|
6120
|
+
}
|
|
6121
|
+
if (was !== !!value) {
|
|
6122
|
+
this.dispatchEvent(
|
|
6123
|
+
new CustomEvent("openchange", {
|
|
6124
|
+
detail: { open: !!value },
|
|
6125
|
+
bubbles: true,
|
|
6126
|
+
}),
|
|
6127
|
+
);
|
|
6128
|
+
}
|
|
5919
6129
|
}
|
|
5920
6130
|
|
|
5921
6131
|
get #showAdd() {
|
|
@@ -5933,6 +6143,7 @@ class FigInputPalette extends HTMLElement {
|
|
|
5933
6143
|
}
|
|
5934
6144
|
|
|
5935
6145
|
connectedCallback() {
|
|
6146
|
+
if (!this.hasAttribute("tabindex")) this.setAttribute("tabindex", "0");
|
|
5936
6147
|
if (this.#renderRAF) cancelAnimationFrame(this.#renderRAF);
|
|
5937
6148
|
this.#renderRAF = requestAnimationFrame(() => {
|
|
5938
6149
|
this.#renderRAF = null;
|
|
@@ -5963,7 +6174,7 @@ class FigInputPalette extends HTMLElement {
|
|
|
5963
6174
|
break;
|
|
5964
6175
|
case "min":
|
|
5965
6176
|
case "max":
|
|
5966
|
-
case "
|
|
6177
|
+
case "open":
|
|
5967
6178
|
case "add":
|
|
5968
6179
|
this.#render();
|
|
5969
6180
|
break;
|
|
@@ -5985,12 +6196,21 @@ class FigInputPalette extends HTMLElement {
|
|
|
5985
6196
|
if (Array.isArray(parsed)) {
|
|
5986
6197
|
this.#colors = parsed.map((entry) => {
|
|
5987
6198
|
if (typeof entry === "string") {
|
|
5988
|
-
return {
|
|
6199
|
+
return {
|
|
6200
|
+
color: entry.slice(0, 7),
|
|
6201
|
+
alpha:
|
|
6202
|
+
entry.length > 7 ? parseInt(entry.slice(7, 9), 16) / 255 : 1,
|
|
6203
|
+
};
|
|
5989
6204
|
}
|
|
5990
6205
|
if (entry && typeof entry === "object") {
|
|
5991
6206
|
return {
|
|
5992
6207
|
color: entry.color || "#D9D9D9",
|
|
5993
|
-
alpha:
|
|
6208
|
+
alpha:
|
|
6209
|
+
entry.alpha !== undefined
|
|
6210
|
+
? entry.alpha
|
|
6211
|
+
: entry.opacity !== undefined
|
|
6212
|
+
? entry.opacity / 100
|
|
6213
|
+
: 1,
|
|
5994
6214
|
};
|
|
5995
6215
|
}
|
|
5996
6216
|
return { color: "#D9D9D9", alpha: 1 };
|
|
@@ -6015,10 +6235,13 @@ class FigInputPalette extends HTMLElement {
|
|
|
6015
6235
|
|
|
6016
6236
|
// Single hex
|
|
6017
6237
|
if (trimmed.startsWith("#")) {
|
|
6018
|
-
this.#colors = [
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6238
|
+
this.#colors = [
|
|
6239
|
+
{
|
|
6240
|
+
color: trimmed.slice(0, 7),
|
|
6241
|
+
alpha:
|
|
6242
|
+
trimmed.length > 7 ? parseInt(trimmed.slice(7, 9), 16) / 255 : 1,
|
|
6243
|
+
},
|
|
6244
|
+
];
|
|
6022
6245
|
return;
|
|
6023
6246
|
}
|
|
6024
6247
|
|
|
@@ -6038,7 +6261,9 @@ class FigInputPalette extends HTMLElement {
|
|
|
6038
6261
|
}
|
|
6039
6262
|
|
|
6040
6263
|
#render() {
|
|
6041
|
-
const disabled =
|
|
6264
|
+
const disabled =
|
|
6265
|
+
this.hasAttribute("disabled") &&
|
|
6266
|
+
this.getAttribute("disabled") !== "false";
|
|
6042
6267
|
|
|
6043
6268
|
this.innerHTML = "";
|
|
6044
6269
|
this.#inlinePickers = [];
|
|
@@ -6050,7 +6275,9 @@ class FigInputPalette extends HTMLElement {
|
|
|
6050
6275
|
const wrap = document.createElement("div");
|
|
6051
6276
|
wrap.className = "palette-colors";
|
|
6052
6277
|
this.#colors.forEach((entry, i) => {
|
|
6053
|
-
wrap.appendChild(
|
|
6278
|
+
wrap.appendChild(
|
|
6279
|
+
this.#createPicker(entry, i, disabled, { inline: true }),
|
|
6280
|
+
);
|
|
6054
6281
|
});
|
|
6055
6282
|
inlineWrap.appendChild(wrap);
|
|
6056
6283
|
|
|
@@ -6066,9 +6293,13 @@ class FigInputPalette extends HTMLElement {
|
|
|
6066
6293
|
}
|
|
6067
6294
|
|
|
6068
6295
|
#createPicker(entry, index, disabled, { inline = false } = {}) {
|
|
6069
|
-
const hexAlpha =
|
|
6070
|
-
|
|
6071
|
-
|
|
6296
|
+
const hexAlpha =
|
|
6297
|
+
entry.alpha < 1
|
|
6298
|
+
? entry.color +
|
|
6299
|
+
Math.round(entry.alpha * 255)
|
|
6300
|
+
.toString(16)
|
|
6301
|
+
.padStart(2, "0")
|
|
6302
|
+
: entry.color;
|
|
6072
6303
|
const ic = document.createElement("fig-input-color");
|
|
6073
6304
|
ic.setAttribute("value", hexAlpha);
|
|
6074
6305
|
ic.setAttribute("picker", "figma");
|
|
@@ -6095,9 +6326,13 @@ class FigInputPalette extends HTMLElement {
|
|
|
6095
6326
|
const sibling = siblingList[index];
|
|
6096
6327
|
if (sibling) {
|
|
6097
6328
|
const entry = this.#colors[index];
|
|
6098
|
-
const hex =
|
|
6099
|
-
|
|
6100
|
-
|
|
6329
|
+
const hex =
|
|
6330
|
+
entry.alpha < 1
|
|
6331
|
+
? entry.color +
|
|
6332
|
+
Math.round(entry.alpha * 255)
|
|
6333
|
+
.toString(16)
|
|
6334
|
+
.padStart(2, "0")
|
|
6335
|
+
: entry.color;
|
|
6101
6336
|
sibling.setAttribute("value", hex);
|
|
6102
6337
|
}
|
|
6103
6338
|
};
|
|
@@ -6120,14 +6355,18 @@ class FigInputPalette extends HTMLElement {
|
|
|
6120
6355
|
#createAddButton(disabled, parent = this) {
|
|
6121
6356
|
const atMax = this.#colors.length >= this.#max;
|
|
6122
6357
|
const addBtn = document.createElement("fig-button");
|
|
6123
|
-
addBtn.setAttribute("variant", "
|
|
6358
|
+
addBtn.setAttribute("variant", "input");
|
|
6124
6359
|
addBtn.setAttribute("icon", "true");
|
|
6125
6360
|
addBtn.setAttribute("aria-label", "Add color");
|
|
6126
6361
|
addBtn.className = "palette-add-btn";
|
|
6127
6362
|
if (disabled || atMax) addBtn.setAttribute("disabled", "");
|
|
6128
6363
|
addBtn.innerHTML = `<span class="fig-mask-icon" style="--icon: var(--icon-add)"></span>`;
|
|
6129
6364
|
addBtn.addEventListener("click", () => {
|
|
6130
|
-
if (
|
|
6365
|
+
if (
|
|
6366
|
+
this.hasAttribute("disabled") &&
|
|
6367
|
+
this.getAttribute("disabled") !== "false"
|
|
6368
|
+
)
|
|
6369
|
+
return;
|
|
6131
6370
|
if (this.#colors.length >= this.#max) return;
|
|
6132
6371
|
this.#addColor({ color: "#D9D9D9", alpha: 1 });
|
|
6133
6372
|
});
|
|
@@ -6139,10 +6378,14 @@ class FigInputPalette extends HTMLElement {
|
|
|
6139
6378
|
|
|
6140
6379
|
#addColor(entry) {
|
|
6141
6380
|
this.#colors.push(entry);
|
|
6142
|
-
const disabled =
|
|
6381
|
+
const disabled =
|
|
6382
|
+
this.hasAttribute("disabled") &&
|
|
6383
|
+
this.getAttribute("disabled") !== "false";
|
|
6143
6384
|
const index = this.#colors.length - 1;
|
|
6144
6385
|
|
|
6145
|
-
const inlineIc = this.#createPicker(entry, index, disabled, {
|
|
6386
|
+
const inlineIc = this.#createPicker(entry, index, disabled, {
|
|
6387
|
+
inline: true,
|
|
6388
|
+
});
|
|
6146
6389
|
const wrap = this.querySelector(".palette-colors");
|
|
6147
6390
|
if (wrap) wrap.appendChild(inlineIc);
|
|
6148
6391
|
|
|
@@ -6160,9 +6403,13 @@ class FigInputPalette extends HTMLElement {
|
|
|
6160
6403
|
#updateChit(index) {
|
|
6161
6404
|
const entry = this.#colors[index];
|
|
6162
6405
|
if (!entry) return;
|
|
6163
|
-
const hexAlpha =
|
|
6164
|
-
|
|
6165
|
-
|
|
6406
|
+
const hexAlpha =
|
|
6407
|
+
entry.alpha < 1
|
|
6408
|
+
? entry.color +
|
|
6409
|
+
Math.round(entry.alpha * 255)
|
|
6410
|
+
.toString(16)
|
|
6411
|
+
.padStart(2, "0")
|
|
6412
|
+
: entry.color;
|
|
6166
6413
|
const inl = this.#inlinePickers[index];
|
|
6167
6414
|
if (inl) inl.setAttribute("value", hexAlpha);
|
|
6168
6415
|
const exp = this.#expandedPickers[index];
|
|
@@ -6180,7 +6427,9 @@ class FigInputPalette extends HTMLElement {
|
|
|
6180
6427
|
}
|
|
6181
6428
|
|
|
6182
6429
|
#syncDisabled() {
|
|
6183
|
-
const disabled =
|
|
6430
|
+
const disabled =
|
|
6431
|
+
this.hasAttribute("disabled") &&
|
|
6432
|
+
this.getAttribute("disabled") !== "false";
|
|
6184
6433
|
[...this.#inlinePickers, ...this.#expandedPickers].forEach((fp) => {
|
|
6185
6434
|
if (disabled) fp.setAttribute("disabled", "");
|
|
6186
6435
|
else fp.removeAttribute("disabled");
|
|
@@ -6314,7 +6563,9 @@ class FigInputGradient extends HTMLElement {
|
|
|
6314
6563
|
const idx = parseInt(selected.dataset.stopIndex, 10);
|
|
6315
6564
|
if (isNaN(idx) || !this.#gradient.stops[idx]) return;
|
|
6316
6565
|
e.preventDefault();
|
|
6317
|
-
const delta =
|
|
6566
|
+
const delta =
|
|
6567
|
+
(e.key === "ArrowRight" ? 1 : -1) *
|
|
6568
|
+
(e.shiftKey ? FigInputGradient.SHIFT_SNAP : 1);
|
|
6318
6569
|
const stop = this.#gradient.stops[idx];
|
|
6319
6570
|
stop.position = Math.max(0, Math.min(100, stop.position + delta));
|
|
6320
6571
|
selected.setAttribute("value", `${stop.position}% 50%`);
|
|
@@ -6582,10 +6833,12 @@ class FigInputGradient extends HTMLElement {
|
|
|
6582
6833
|
const stopIdx = parseInt(clickedHandle?.dataset.stopIndex, 10);
|
|
6583
6834
|
this.#distributeStops();
|
|
6584
6835
|
if (!isNaN(stopIdx)) {
|
|
6585
|
-
this.#track
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6836
|
+
this.#track
|
|
6837
|
+
.querySelectorAll("fig-handle:not(.fig-input-gradient-ghost)")
|
|
6838
|
+
.forEach((h) => {
|
|
6839
|
+
if (parseInt(h.dataset.stopIndex, 10) === stopIdx) h.select();
|
|
6840
|
+
else h.deselect();
|
|
6841
|
+
});
|
|
6589
6842
|
}
|
|
6590
6843
|
e.stopPropagation();
|
|
6591
6844
|
}
|
|
@@ -6724,7 +6977,10 @@ class FigInputGradient extends HTMLElement {
|
|
|
6724
6977
|
e.stopPropagation();
|
|
6725
6978
|
|
|
6726
6979
|
const trackRect = this.#track.getBoundingClientRect();
|
|
6727
|
-
const pct = Math.max(
|
|
6980
|
+
const pct = Math.max(
|
|
6981
|
+
0,
|
|
6982
|
+
Math.min(1, (e.clientX - trackRect.left) / trackRect.width),
|
|
6983
|
+
);
|
|
6728
6984
|
const position = Math.round(pct * 100);
|
|
6729
6985
|
const color = this.#sampleGradientColor(pct);
|
|
6730
6986
|
this.#gradient.stops.push({ position, color, opacity: 100 });
|
|
@@ -6743,19 +6999,23 @@ class FigInputGradient extends HTMLElement {
|
|
|
6743
6999
|
);
|
|
6744
7000
|
const newHandle = handles[newIndex];
|
|
6745
7001
|
if (newHandle) {
|
|
6746
|
-
this.#track
|
|
6747
|
-
|
|
6748
|
-
|
|
7002
|
+
this.#track
|
|
7003
|
+
.querySelectorAll("fig-handle:not(.fig-input-gradient-ghost)")
|
|
7004
|
+
.forEach((h) => {
|
|
7005
|
+
if (h !== newHandle) h.deselect();
|
|
7006
|
+
});
|
|
6749
7007
|
newHandle.select();
|
|
6750
|
-
newHandle.dispatchEvent(
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
7008
|
+
newHandle.dispatchEvent(
|
|
7009
|
+
new PointerEvent("pointerdown", {
|
|
7010
|
+
bubbles: true,
|
|
7011
|
+
clientX: e.clientX,
|
|
7012
|
+
clientY: e.clientY,
|
|
7013
|
+
pointerId: e.pointerId,
|
|
7014
|
+
pointerType: e.pointerType,
|
|
7015
|
+
button: e.button,
|
|
7016
|
+
buttons: e.buttons,
|
|
7017
|
+
}),
|
|
7018
|
+
);
|
|
6759
7019
|
}
|
|
6760
7020
|
});
|
|
6761
7021
|
|
|
@@ -6770,7 +7030,10 @@ class FigInputGradient extends HTMLElement {
|
|
|
6770
7030
|
if (e.detail.opacity !== undefined) {
|
|
6771
7031
|
this.#gradient.stops[idx].opacity = e.detail.opacity;
|
|
6772
7032
|
}
|
|
6773
|
-
handle.setAttribute(
|
|
7033
|
+
handle.setAttribute(
|
|
7034
|
+
"color",
|
|
7035
|
+
this.#stopColorCSS(this.#gradient.stops[idx]),
|
|
7036
|
+
);
|
|
6774
7037
|
this.#syncChit();
|
|
6775
7038
|
this.#emitInput();
|
|
6776
7039
|
}
|
|
@@ -6785,7 +7048,9 @@ class FigInputGradient extends HTMLElement {
|
|
|
6785
7048
|
let position = rawPosition;
|
|
6786
7049
|
const trackW = this.#track.getBoundingClientRect().width;
|
|
6787
7050
|
if (e.detail?.shiftKey) {
|
|
6788
|
-
position =
|
|
7051
|
+
position =
|
|
7052
|
+
Math.round(position / FigInputGradient.SHIFT_SNAP) *
|
|
7053
|
+
FigInputGradient.SHIFT_SNAP;
|
|
6789
7054
|
} else {
|
|
6790
7055
|
const snapPct = trackW > 0 ? (5 / trackW) * 100 : 0;
|
|
6791
7056
|
for (let i = 0; i < this.#gradient.stops.length; i++) {
|
|
@@ -6825,7 +7090,10 @@ class FigInputGradient extends HTMLElement {
|
|
|
6825
7090
|
if (e.detail.opacity !== undefined) {
|
|
6826
7091
|
this.#gradient.stops[idx].opacity = e.detail.opacity;
|
|
6827
7092
|
}
|
|
6828
|
-
handle.setAttribute(
|
|
7093
|
+
handle.setAttribute(
|
|
7094
|
+
"color",
|
|
7095
|
+
this.#stopColorCSS(this.#gradient.stops[idx]),
|
|
7096
|
+
);
|
|
6829
7097
|
this.#syncChit();
|
|
6830
7098
|
this.#emitChange();
|
|
6831
7099
|
}
|
|
@@ -7578,13 +7846,13 @@ class FigChit extends HTMLElement {
|
|
|
7578
7846
|
|
|
7579
7847
|
if (this.#type === "color") {
|
|
7580
7848
|
const hex = this.#toHex(bg);
|
|
7581
|
-
this.innerHTML = `<input type="color" value="${hex}" />`;
|
|
7849
|
+
this.innerHTML = `<div></div><input type="color" value="${hex}" />`;
|
|
7582
7850
|
this.input = this.querySelector("input");
|
|
7583
7851
|
if (!isVar) {
|
|
7584
7852
|
this.input.addEventListener("input", this.#boundHandleInput);
|
|
7585
7853
|
}
|
|
7586
7854
|
} else {
|
|
7587
|
-
this.innerHTML = "";
|
|
7855
|
+
this.innerHTML = "<div></div>";
|
|
7588
7856
|
this.input = null;
|
|
7589
7857
|
}
|
|
7590
7858
|
} else if (this.#type === "color" && this.input) {
|
|
@@ -7594,8 +7862,14 @@ class FigChit extends HTMLElement {
|
|
|
7594
7862
|
}
|
|
7595
7863
|
}
|
|
7596
7864
|
|
|
7597
|
-
const isImage =
|
|
7598
|
-
|
|
7865
|
+
const isImage =
|
|
7866
|
+
/^(linear-gradient|radial-gradient|conic-gradient|repeating-|url)\s*\(/i.test(
|
|
7867
|
+
rawBg,
|
|
7868
|
+
);
|
|
7869
|
+
this.style.setProperty(
|
|
7870
|
+
"--chit-background",
|
|
7871
|
+
isImage ? rawBg : `linear-gradient(${rawBg}, ${rawBg})`,
|
|
7872
|
+
);
|
|
7599
7873
|
}
|
|
7600
7874
|
|
|
7601
7875
|
#handleInput(e) {
|
|
@@ -7622,8 +7896,14 @@ class FigChit extends HTMLElement {
|
|
|
7622
7896
|
if (oldValue === newValue) return;
|
|
7623
7897
|
if (name === "background") {
|
|
7624
7898
|
if (this.#internalUpdate) {
|
|
7625
|
-
const isImg =
|
|
7626
|
-
|
|
7899
|
+
const isImg =
|
|
7900
|
+
/^(linear-gradient|radial-gradient|conic-gradient|repeating-|url)\s*\(/i.test(
|
|
7901
|
+
newValue,
|
|
7902
|
+
);
|
|
7903
|
+
this.style.setProperty(
|
|
7904
|
+
"--chit-background",
|
|
7905
|
+
isImg ? newValue : `linear-gradient(${newValue}, ${newValue})`,
|
|
7906
|
+
);
|
|
7627
7907
|
return;
|
|
7628
7908
|
}
|
|
7629
7909
|
this.#render();
|
|
@@ -7645,9 +7925,7 @@ class FigChit extends HTMLElement {
|
|
|
7645
7925
|
}
|
|
7646
7926
|
}
|
|
7647
7927
|
customElements.define("fig-chit", FigChit);
|
|
7648
|
-
class FigSwatch extends FigChit{
|
|
7649
|
-
|
|
7650
|
-
}
|
|
7928
|
+
class FigSwatch extends FigChit {}
|
|
7651
7929
|
customElements.define("fig-swatch", FigSwatch);
|
|
7652
7930
|
|
|
7653
7931
|
/* Upload */
|
|
@@ -8828,7 +9106,11 @@ class Fig3DRotate extends HTMLElement {
|
|
|
8828
9106
|
this.#precision = parseInt(this.getAttribute("precision") || "1");
|
|
8829
9107
|
figSyncCssVar(this, "--aspect-ratio", this.getAttribute("aspect-ratio"));
|
|
8830
9108
|
figSyncCssVar(this, "--perspective", this.getAttribute("perspective"));
|
|
8831
|
-
figSyncCssVar(
|
|
9109
|
+
figSyncCssVar(
|
|
9110
|
+
this,
|
|
9111
|
+
"--perspective-origin",
|
|
9112
|
+
this.getAttribute("perspective-origin"),
|
|
9113
|
+
);
|
|
8832
9114
|
this.#syncTransformOrigin(this.getAttribute("transform-origin"));
|
|
8833
9115
|
this.#parseFields(this.getAttribute("fields"));
|
|
8834
9116
|
const val = this.getAttribute("value");
|
|
@@ -8846,8 +9128,6 @@ class Fig3DRotate extends HTMLElement {
|
|
|
8846
9128
|
}
|
|
8847
9129
|
}
|
|
8848
9130
|
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
9131
|
#syncTransformOrigin(value) {
|
|
8852
9132
|
if (!value || !value.trim()) {
|
|
8853
9133
|
this.style.removeProperty("--transform-origin");
|
|
@@ -10682,6 +10962,117 @@ class FigLayer extends HTMLElement {
|
|
|
10682
10962
|
}
|
|
10683
10963
|
customElements.define("fig-layer", FigLayer);
|
|
10684
10964
|
|
|
10965
|
+
// FigGroup
|
|
10966
|
+
class FigGroup extends HTMLElement {
|
|
10967
|
+
static observedAttributes = ["name", "collapsible"];
|
|
10968
|
+
|
|
10969
|
+
#header = null;
|
|
10970
|
+
#chevron = null;
|
|
10971
|
+
|
|
10972
|
+
connectedCallback() {
|
|
10973
|
+
requestAnimationFrame(() => this.#render());
|
|
10974
|
+
}
|
|
10975
|
+
|
|
10976
|
+
disconnectedCallback() {
|
|
10977
|
+
if (this.#chevron) {
|
|
10978
|
+
this.#chevron.removeEventListener("click", this.#handleToggle);
|
|
10979
|
+
}
|
|
10980
|
+
if (this.#header) {
|
|
10981
|
+
this.#header.removeEventListener("click", this.#handleToggle);
|
|
10982
|
+
}
|
|
10983
|
+
}
|
|
10984
|
+
|
|
10985
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
10986
|
+
if (oldValue === newValue) return;
|
|
10987
|
+
this.#render();
|
|
10988
|
+
}
|
|
10989
|
+
|
|
10990
|
+
get open() {
|
|
10991
|
+
const attr = this.getAttribute("open");
|
|
10992
|
+
return attr !== null && attr !== "false";
|
|
10993
|
+
}
|
|
10994
|
+
|
|
10995
|
+
set open(value) {
|
|
10996
|
+
const was = this.open;
|
|
10997
|
+
if (value) {
|
|
10998
|
+
this.setAttribute("open", "true");
|
|
10999
|
+
} else {
|
|
11000
|
+
this.setAttribute("open", "false");
|
|
11001
|
+
}
|
|
11002
|
+
if (was !== !!value) {
|
|
11003
|
+
this.dispatchEvent(
|
|
11004
|
+
new CustomEvent("openchange", {
|
|
11005
|
+
detail: { open: !!value },
|
|
11006
|
+
bubbles: true,
|
|
11007
|
+
}),
|
|
11008
|
+
);
|
|
11009
|
+
}
|
|
11010
|
+
}
|
|
11011
|
+
|
|
11012
|
+
#handleToggle = (e) => {
|
|
11013
|
+
e.stopPropagation();
|
|
11014
|
+
this.open = !this.open;
|
|
11015
|
+
};
|
|
11016
|
+
|
|
11017
|
+
#render() {
|
|
11018
|
+
const isCollapsible = this.hasAttribute("collapsible");
|
|
11019
|
+
const nameAttr = this.getAttribute("name");
|
|
11020
|
+
const label = nameAttr || (isCollapsible ? "Group" : null);
|
|
11021
|
+
|
|
11022
|
+
// Check if user supplied their own fig-header
|
|
11023
|
+
const userHeader = this.querySelector(":scope > fig-header");
|
|
11024
|
+
|
|
11025
|
+
if (!label && !isCollapsible && !userHeader) {
|
|
11026
|
+
if (this.#header && this.#header.dataset.generated) {
|
|
11027
|
+
this.#header.remove();
|
|
11028
|
+
this.#header = null;
|
|
11029
|
+
this.#chevron = null;
|
|
11030
|
+
}
|
|
11031
|
+
return;
|
|
11032
|
+
}
|
|
11033
|
+
|
|
11034
|
+
if (userHeader) {
|
|
11035
|
+
this.#header = userHeader;
|
|
11036
|
+
} else if (!this.#header || !this.#header.dataset.generated) {
|
|
11037
|
+
this.#header = document.createElement("fig-header");
|
|
11038
|
+
this.#header.setAttribute("borderless", "");
|
|
11039
|
+
this.#header.dataset.generated = "true";
|
|
11040
|
+
this.prepend(this.#header);
|
|
11041
|
+
}
|
|
11042
|
+
|
|
11043
|
+
// Ensure h3 exists inside header
|
|
11044
|
+
let h3 = this.#header.querySelector("h3");
|
|
11045
|
+
if (!h3) {
|
|
11046
|
+
h3 = document.createElement("h3");
|
|
11047
|
+
this.#header.prepend(h3);
|
|
11048
|
+
}
|
|
11049
|
+
if (this.#header.dataset.generated) {
|
|
11050
|
+
h3.textContent = label;
|
|
11051
|
+
}
|
|
11052
|
+
|
|
11053
|
+
if (isCollapsible) {
|
|
11054
|
+
if (!h3.querySelector(".fig-group-chevron")) {
|
|
11055
|
+
const chevron = document.createElement("span");
|
|
11056
|
+
chevron.className = "fig-mask-icon fig-group-chevron";
|
|
11057
|
+
h3.prepend(chevron);
|
|
11058
|
+
}
|
|
11059
|
+
this.#chevron = h3.querySelector(".fig-group-chevron");
|
|
11060
|
+
h3.addEventListener("click", this.#handleToggle);
|
|
11061
|
+
|
|
11062
|
+
if (!this.hasAttribute("open")) {
|
|
11063
|
+
this.setAttribute("open", "false");
|
|
11064
|
+
}
|
|
11065
|
+
} else {
|
|
11066
|
+
if (this.#chevron) {
|
|
11067
|
+
this.#chevron.remove();
|
|
11068
|
+
this.#chevron = null;
|
|
11069
|
+
}
|
|
11070
|
+
this.removeAttribute("open");
|
|
11071
|
+
}
|
|
11072
|
+
}
|
|
11073
|
+
}
|
|
11074
|
+
customElements.define("fig-group", FigGroup);
|
|
11075
|
+
|
|
10685
11076
|
// FigFillPicker
|
|
10686
11077
|
/**
|
|
10687
11078
|
* A comprehensive fill picker component supporting solid colors, gradients, images, video, and webcam.
|
|
@@ -11114,10 +11505,15 @@ class FigFillPicker extends HTMLElement {
|
|
|
11114
11505
|
this.#dialog.addEventListener("close", onDialogClose);
|
|
11115
11506
|
|
|
11116
11507
|
this.#dialogOpenObserver = new MutationObserver(() => {
|
|
11117
|
-
const isOpen =
|
|
11508
|
+
const isOpen =
|
|
11509
|
+
this.#dialog.hasAttribute("open") &&
|
|
11510
|
+
this.#dialog.getAttribute("open") !== "false";
|
|
11118
11511
|
if (!isOpen) onDialogClose();
|
|
11119
11512
|
});
|
|
11120
|
-
this.#dialogOpenObserver.observe(this.#dialog, {
|
|
11513
|
+
this.#dialogOpenObserver.observe(this.#dialog, {
|
|
11514
|
+
attributes: true,
|
|
11515
|
+
attributeFilter: ["open"],
|
|
11516
|
+
});
|
|
11121
11517
|
|
|
11122
11518
|
// Initialize built-in tabs (skip any overridden by custom slots)
|
|
11123
11519
|
const builtinInits = {
|
|
@@ -11213,6 +11609,8 @@ class FigFillPicker extends HTMLElement {
|
|
|
11213
11609
|
<fig-preview class="fig-fill-picker-color-area">
|
|
11214
11610
|
<canvas width="200" height="200"></canvas>
|
|
11215
11611
|
<fig-handle
|
|
11612
|
+
type="color"
|
|
11613
|
+
color="${this.#hsvToHex({ ...this.#color, a: 1 })}"
|
|
11216
11614
|
drag
|
|
11217
11615
|
drag-surface=".fig-fill-picker-color-area"
|
|
11218
11616
|
drag-axes="x,y"
|
|
@@ -11875,7 +12273,9 @@ class FigFillPicker extends HTMLElement {
|
|
|
11875
12273
|
});
|
|
11876
12274
|
|
|
11877
12275
|
// Embedded gradient bar input
|
|
11878
|
-
const gradientBarInput = container.querySelector(
|
|
12276
|
+
const gradientBarInput = container.querySelector(
|
|
12277
|
+
".fig-fill-picker-gradient-bar-input",
|
|
12278
|
+
);
|
|
11879
12279
|
if (gradientBarInput) {
|
|
11880
12280
|
const syncFromBarInput = (e) => {
|
|
11881
12281
|
e.stopPropagation();
|
|
@@ -11948,7 +12348,10 @@ class FigFillPicker extends HTMLElement {
|
|
|
11948
12348
|
if (barInput) {
|
|
11949
12349
|
barInput.setAttribute(
|
|
11950
12350
|
"value",
|
|
11951
|
-
JSON.stringify({
|
|
12351
|
+
JSON.stringify({
|
|
12352
|
+
type: "gradient",
|
|
12353
|
+
gradient: gradientToValueShape(this.#gradient),
|
|
12354
|
+
}),
|
|
11952
12355
|
);
|
|
11953
12356
|
}
|
|
11954
12357
|
|
|
@@ -11977,7 +12380,8 @@ class FigFillPicker extends HTMLElement {
|
|
|
11977
12380
|
if (colorInput) colorInput.setAttribute("value", stop.color);
|
|
11978
12381
|
const removeBtn = row.querySelector(".fig-fill-picker-stop-remove");
|
|
11979
12382
|
if (removeBtn) {
|
|
11980
|
-
if (this.#gradient.stops.length <= 2)
|
|
12383
|
+
if (this.#gradient.stops.length <= 2)
|
|
12384
|
+
removeBtn.setAttribute("disabled", "");
|
|
11981
12385
|
else removeBtn.removeAttribute("disabled");
|
|
11982
12386
|
}
|
|
11983
12387
|
});
|
|
@@ -12910,9 +13314,14 @@ class FigColorTip extends HTMLElement {
|
|
|
12910
13314
|
const color = this.#normalizeColor(rawValue);
|
|
12911
13315
|
const alpha = this.#extractAlpha(rawValue);
|
|
12912
13316
|
const alphaAttr = this.#alphaEnabled ? "" : 'alpha="false"';
|
|
12913
|
-
const pickerValue =
|
|
12914
|
-
|
|
12915
|
-
|
|
13317
|
+
const pickerValue =
|
|
13318
|
+
alpha < 1
|
|
13319
|
+
? JSON.stringify({
|
|
13320
|
+
type: "solid",
|
|
13321
|
+
color,
|
|
13322
|
+
opacity: Math.round(alpha * 100),
|
|
13323
|
+
})
|
|
13324
|
+
: JSON.stringify({ type: "solid", color });
|
|
12916
13325
|
this.innerHTML = `
|
|
12917
13326
|
<fig-fill-picker mode="solid" ${alphaAttr} value='${pickerValue}'>
|
|
12918
13327
|
<fig-chit background="${color}"></fig-chit>
|
|
@@ -12955,7 +13364,9 @@ class FigColorTip extends HTMLElement {
|
|
|
12955
13364
|
if (v.startsWith("#") && v.length === 9) {
|
|
12956
13365
|
return parseInt(v.slice(7, 9), 16) / 255;
|
|
12957
13366
|
}
|
|
12958
|
-
const rgbaMatch = v.match(
|
|
13367
|
+
const rgbaMatch = v.match(
|
|
13368
|
+
/rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*([\d.]+)\s*\)/i,
|
|
13369
|
+
);
|
|
12959
13370
|
if (rgbaMatch) return parseFloat(rgbaMatch[1]);
|
|
12960
13371
|
return 1;
|
|
12961
13372
|
}
|
|
@@ -13012,9 +13423,10 @@ class FigColorTip extends HTMLElement {
|
|
|
13012
13423
|
}
|
|
13013
13424
|
|
|
13014
13425
|
if (this.#fillPicker) {
|
|
13015
|
-
const pickerVal =
|
|
13016
|
-
|
|
13017
|
-
|
|
13426
|
+
const pickerVal =
|
|
13427
|
+
alpha < 1
|
|
13428
|
+
? { type: "solid", color, opacity: Math.round(alpha * 100) }
|
|
13429
|
+
: { type: "solid", color };
|
|
13018
13430
|
this.#fillPicker.setAttribute("value", JSON.stringify(pickerVal));
|
|
13019
13431
|
if (this.#alphaEnabled) {
|
|
13020
13432
|
this.#fillPicker.removeAttribute("alpha");
|
|
@@ -13192,7 +13604,15 @@ class FigChooser extends HTMLElement {
|
|
|
13192
13604
|
}
|
|
13193
13605
|
|
|
13194
13606
|
static get observedAttributes() {
|
|
13195
|
-
return [
|
|
13607
|
+
return [
|
|
13608
|
+
"value",
|
|
13609
|
+
"disabled",
|
|
13610
|
+
"choice-element",
|
|
13611
|
+
"drag",
|
|
13612
|
+
"overflow",
|
|
13613
|
+
"loop",
|
|
13614
|
+
"padding",
|
|
13615
|
+
];
|
|
13196
13616
|
}
|
|
13197
13617
|
|
|
13198
13618
|
get #overflowMode() {
|
|
@@ -13818,7 +14238,13 @@ class FigCanvasControl extends HTMLElement {
|
|
|
13818
14238
|
|
|
13819
14239
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
13820
14240
|
if (oldVal === newVal) return;
|
|
13821
|
-
if (
|
|
14241
|
+
if (
|
|
14242
|
+
name === "value" &&
|
|
14243
|
+
!this.#isDragging &&
|
|
14244
|
+
!this.#isSecondDragging &&
|
|
14245
|
+
!this.#isRadiusDragging &&
|
|
14246
|
+
!this.#isAngleDragging
|
|
14247
|
+
) {
|
|
13822
14248
|
this.#parseValue();
|
|
13823
14249
|
if (this.#pointHandle) this.#syncPositions();
|
|
13824
14250
|
else this.#render();
|
|
@@ -13839,11 +14265,14 @@ class FigCanvasControl extends HTMLElement {
|
|
|
13839
14265
|
}
|
|
13840
14266
|
if (name === "snapping" && this.#pointHandle) {
|
|
13841
14267
|
this.#pointHandle.setAttribute("drag-snapping", newVal || "false");
|
|
13842
|
-
if (this.#secondHandle)
|
|
14268
|
+
if (this.#secondHandle)
|
|
14269
|
+
this.#secondHandle.setAttribute("drag-snapping", newVal || "false");
|
|
13843
14270
|
}
|
|
13844
14271
|
if (name === "name") {
|
|
13845
|
-
if (this.#pointTooltip)
|
|
13846
|
-
|
|
14272
|
+
if (this.#pointTooltip)
|
|
14273
|
+
this.#pointTooltip.setAttribute("text", this.#pointTipText);
|
|
14274
|
+
if (this.#secondTooltip)
|
|
14275
|
+
this.#secondTooltip.setAttribute("text", this.#secondTipText);
|
|
13847
14276
|
}
|
|
13848
14277
|
}
|
|
13849
14278
|
|
|
@@ -13868,13 +14297,16 @@ class FigCanvasControl extends HTMLElement {
|
|
|
13868
14297
|
if (typeof v.angle === "number") this.#angle = v.angle;
|
|
13869
14298
|
if (typeof v.x2 === "number") this.#x2 = v.x2;
|
|
13870
14299
|
if (typeof v.y2 === "number") this.#y2 = v.y2;
|
|
13871
|
-
} catch {
|
|
14300
|
+
} catch {
|
|
14301
|
+
/* ignore */
|
|
14302
|
+
}
|
|
13872
14303
|
}
|
|
13873
14304
|
|
|
13874
14305
|
get value() {
|
|
13875
14306
|
const v = { x: this.#x, y: this.#y };
|
|
13876
14307
|
if (this.#type === "color") {
|
|
13877
|
-
const color =
|
|
14308
|
+
const color =
|
|
14309
|
+
this.getAttribute("color") || this.#pointHandle?.getAttribute("color");
|
|
13878
14310
|
if (color) v.color = color;
|
|
13879
14311
|
}
|
|
13880
14312
|
if (this.#hasRadius) {
|
|
@@ -14175,11 +14607,15 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14175
14607
|
}
|
|
14176
14608
|
|
|
14177
14609
|
#emitInput() {
|
|
14178
|
-
this.dispatchEvent(
|
|
14610
|
+
this.dispatchEvent(
|
|
14611
|
+
new CustomEvent("input", { bubbles: true, detail: this.value }),
|
|
14612
|
+
);
|
|
14179
14613
|
}
|
|
14180
14614
|
|
|
14181
14615
|
#emitChange() {
|
|
14182
|
-
this.dispatchEvent(
|
|
14616
|
+
this.dispatchEvent(
|
|
14617
|
+
new CustomEvent("change", { bubbles: true, detail: this.value }),
|
|
14618
|
+
);
|
|
14183
14619
|
}
|
|
14184
14620
|
|
|
14185
14621
|
#syncValueAttribute() {
|
|
@@ -14211,7 +14647,9 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14211
14647
|
}
|
|
14212
14648
|
this.#syncPositions();
|
|
14213
14649
|
if (this.#hasSecondPoint) {
|
|
14214
|
-
document.body.style.cursor = this.#resizeCursorSvg(
|
|
14650
|
+
document.body.style.cursor = this.#resizeCursorSvg(
|
|
14651
|
+
this.#pointPointLineDeg(),
|
|
14652
|
+
);
|
|
14215
14653
|
}
|
|
14216
14654
|
this.#emitInput();
|
|
14217
14655
|
});
|
|
@@ -14227,14 +14665,17 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14227
14665
|
const py = e.detail?.py ?? this.#y / 100;
|
|
14228
14666
|
this.#x = Math.round(Math.max(0, Math.min(100, px * 100)));
|
|
14229
14667
|
this.#y = Math.round(Math.max(0, Math.min(100, py * 100)));
|
|
14230
|
-
if (this.#pointTooltip && this.#type !== "color")
|
|
14668
|
+
if (this.#pointTooltip && this.#type !== "color")
|
|
14669
|
+
this.#pointTooltip.removeAttribute("show");
|
|
14231
14670
|
if (this.#hasSecondPoint) {
|
|
14232
14671
|
document.body.style.cursor = this.#prevBodyCursor ?? "";
|
|
14233
14672
|
}
|
|
14234
14673
|
this.#syncPositions();
|
|
14235
14674
|
this.#syncValueAttribute();
|
|
14236
14675
|
this.#emitChange();
|
|
14237
|
-
requestAnimationFrame(() => {
|
|
14676
|
+
requestAnimationFrame(() => {
|
|
14677
|
+
this.#isDragging = false;
|
|
14678
|
+
});
|
|
14238
14679
|
});
|
|
14239
14680
|
|
|
14240
14681
|
if (this.#angleHandle) {
|
|
@@ -14251,8 +14692,8 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14251
14692
|
const hy = e.detail?.y ?? 0;
|
|
14252
14693
|
const hw = this.#angleHandle.offsetWidth / 2;
|
|
14253
14694
|
const hh = this.#angleHandle.offsetHeight / 2;
|
|
14254
|
-
const dx =
|
|
14255
|
-
const dy =
|
|
14695
|
+
const dx = hx + hw - cx;
|
|
14696
|
+
const dy = hy + hh - cy;
|
|
14256
14697
|
let angle = (Math.atan2(dy, dx) * 180) / Math.PI;
|
|
14257
14698
|
if (this.#shouldSnap(e.detail?.shiftKey)) {
|
|
14258
14699
|
angle = Math.round(angle / 15) * 15;
|
|
@@ -14277,7 +14718,10 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14277
14718
|
}
|
|
14278
14719
|
|
|
14279
14720
|
if (this.#angleTooltip) {
|
|
14280
|
-
this.#angleTooltip.setAttribute(
|
|
14721
|
+
this.#angleTooltip.setAttribute(
|
|
14722
|
+
"text",
|
|
14723
|
+
`Angle ${Math.round(this.#angle)}°`,
|
|
14724
|
+
);
|
|
14281
14725
|
this.#angleTooltip.setAttribute("show", "true");
|
|
14282
14726
|
this.#angleTooltip.showPopup?.();
|
|
14283
14727
|
}
|
|
@@ -14292,7 +14736,9 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14292
14736
|
this.#syncPositions();
|
|
14293
14737
|
this.#syncValueAttribute();
|
|
14294
14738
|
this.#emitChange();
|
|
14295
|
-
requestAnimationFrame(() => {
|
|
14739
|
+
requestAnimationFrame(() => {
|
|
14740
|
+
this.#isAngleDragging = false;
|
|
14741
|
+
});
|
|
14296
14742
|
});
|
|
14297
14743
|
|
|
14298
14744
|
this.#angleHandle.addEventListener("hitareadown", (e) => {
|
|
@@ -14325,7 +14771,11 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14325
14771
|
angle = Math.round(angle / 15) * 15;
|
|
14326
14772
|
}
|
|
14327
14773
|
this.#angle = angle;
|
|
14328
|
-
if (this.#angleTooltip)
|
|
14774
|
+
if (this.#angleTooltip)
|
|
14775
|
+
this.#angleTooltip.setAttribute(
|
|
14776
|
+
"text",
|
|
14777
|
+
`Angle ${Math.round(angle)}°`,
|
|
14778
|
+
);
|
|
14329
14779
|
this.#syncPositions();
|
|
14330
14780
|
const curDeg = Math.round(angle);
|
|
14331
14781
|
if (curDeg !== lastCursorDeg) {
|
|
@@ -14368,7 +14818,9 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14368
14818
|
this.#secondTooltip.showPopup?.();
|
|
14369
14819
|
}
|
|
14370
14820
|
this.#syncPositions();
|
|
14371
|
-
document.body.style.cursor = this.#resizeCursorSvg(
|
|
14821
|
+
document.body.style.cursor = this.#resizeCursorSvg(
|
|
14822
|
+
this.#pointPointLineDeg(),
|
|
14823
|
+
);
|
|
14372
14824
|
this.#emitInput();
|
|
14373
14825
|
});
|
|
14374
14826
|
|
|
@@ -14379,7 +14831,9 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14379
14831
|
this.#syncPositions();
|
|
14380
14832
|
this.#syncValueAttribute();
|
|
14381
14833
|
this.#emitChange();
|
|
14382
|
-
requestAnimationFrame(() => {
|
|
14834
|
+
requestAnimationFrame(() => {
|
|
14835
|
+
this.#isSecondDragging = false;
|
|
14836
|
+
});
|
|
14383
14837
|
});
|
|
14384
14838
|
|
|
14385
14839
|
this.#setupPointPointHitArea(this.#pointHandle, true);
|
|
@@ -14443,7 +14897,9 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14443
14897
|
this.#y2 = newPctY;
|
|
14444
14898
|
}
|
|
14445
14899
|
this.#syncPositions();
|
|
14446
|
-
const curDeg = Math.round(
|
|
14900
|
+
const curDeg = Math.round(
|
|
14901
|
+
isFirst ? this.#pointPointLineDeg() + 180 : this.#pointPointLineDeg(),
|
|
14902
|
+
);
|
|
14447
14903
|
if (curDeg !== lastCursorDeg) {
|
|
14448
14904
|
lastCursorDeg = curDeg;
|
|
14449
14905
|
document.body.style.cursor = this.#rotateCursorSvg(curDeg);
|
|
@@ -14475,7 +14931,10 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14475
14931
|
const rect = container.getBoundingClientRect();
|
|
14476
14932
|
const cx = (this.#x / 100) * rect.width;
|
|
14477
14933
|
const cy = (this.#y / 100) * rect.height;
|
|
14478
|
-
const deg =
|
|
14934
|
+
const deg =
|
|
14935
|
+
(Math.atan2(e.clientY - rect.top - cy, e.clientX - rect.left - cx) *
|
|
14936
|
+
180) /
|
|
14937
|
+
Math.PI;
|
|
14479
14938
|
circle.style.cursor = this.#resizeCursorSvg(deg);
|
|
14480
14939
|
});
|
|
14481
14940
|
const onDown = (e) => {
|
|
@@ -14497,7 +14956,10 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14497
14956
|
const rect0 = container.getBoundingClientRect();
|
|
14498
14957
|
const cx0 = (this.#x / 100) * rect0.width;
|
|
14499
14958
|
const cy0 = (this.#y / 100) * rect0.height;
|
|
14500
|
-
const initDeg =
|
|
14959
|
+
const initDeg =
|
|
14960
|
+
(Math.atan2(e.clientY - rect0.top - cy0, e.clientX - rect0.left - cx0) *
|
|
14961
|
+
180) /
|
|
14962
|
+
Math.PI;
|
|
14501
14963
|
let lastCursorDeg = Math.round(initDeg);
|
|
14502
14964
|
document.body.style.cursor = this.#resizeCursorSvg(lastCursorDeg);
|
|
14503
14965
|
|
|
@@ -14528,7 +14990,8 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14528
14990
|
} else {
|
|
14529
14991
|
this.#radius = Math.max(0, dist);
|
|
14530
14992
|
}
|
|
14531
|
-
if (this.#radiusTooltip)
|
|
14993
|
+
if (this.#radiusTooltip)
|
|
14994
|
+
this.#radiusTooltip.setAttribute("text", this.#formatRadius());
|
|
14532
14995
|
this.#syncPositions();
|
|
14533
14996
|
this.#emitInput();
|
|
14534
14997
|
};
|
|
@@ -14549,7 +15012,8 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14549
15012
|
window.addEventListener("pointerup", onUp);
|
|
14550
15013
|
};
|
|
14551
15014
|
circle.addEventListener("pointerdown", onDown);
|
|
14552
|
-
this._radiusDragCleanup = () =>
|
|
15015
|
+
this._radiusDragCleanup = () =>
|
|
15016
|
+
circle.removeEventListener("pointerdown", onDown);
|
|
14553
15017
|
}
|
|
14554
15018
|
|
|
14555
15019
|
#teardownRadiusDrag() {
|
|
@@ -14711,8 +15175,10 @@ class FigHandle extends HTMLElement {
|
|
|
14711
15175
|
};
|
|
14712
15176
|
|
|
14713
15177
|
const axes = this.#axes;
|
|
14714
|
-
if (axes.x)
|
|
14715
|
-
|
|
15178
|
+
if (axes.x)
|
|
15179
|
+
this.style.left = `${Math.round(resolve(xToken, rect.width, hw))}px`;
|
|
15180
|
+
if (axes.y)
|
|
15181
|
+
this.style.top = `${Math.round(resolve(yToken, rect.height, hh))}px`;
|
|
14716
15182
|
}
|
|
14717
15183
|
|
|
14718
15184
|
#syncValueAttribute() {
|
|
@@ -14729,16 +15195,25 @@ class FigHandle extends HTMLElement {
|
|
|
14729
15195
|
const raw = this.getAttribute("hit-area");
|
|
14730
15196
|
if (!raw) return null;
|
|
14731
15197
|
const tokens = raw.trim().split(/\s+/);
|
|
14732
|
-
let vPad = 0,
|
|
15198
|
+
let vPad = 0,
|
|
15199
|
+
hPad = 0,
|
|
15200
|
+
circle = false;
|
|
14733
15201
|
const nums = [];
|
|
14734
15202
|
for (const t of tokens) {
|
|
14735
|
-
if (t === "circle") {
|
|
15203
|
+
if (t === "circle") {
|
|
15204
|
+
circle = true;
|
|
15205
|
+
continue;
|
|
15206
|
+
}
|
|
14736
15207
|
const n = parseFloat(t);
|
|
14737
15208
|
if (Number.isFinite(n)) nums.push(n);
|
|
14738
15209
|
}
|
|
14739
|
-
if (nums.length >= 2) {
|
|
14740
|
-
|
|
14741
|
-
|
|
15210
|
+
if (nums.length >= 2) {
|
|
15211
|
+
vPad = nums[0];
|
|
15212
|
+
hPad = nums[1];
|
|
15213
|
+
} else if (nums.length === 1) {
|
|
15214
|
+
vPad = nums[0];
|
|
15215
|
+
hPad = nums[0];
|
|
15216
|
+
} else return null;
|
|
14742
15217
|
return { vPad, hPad, circle };
|
|
14743
15218
|
}
|
|
14744
15219
|
|
|
@@ -14759,7 +15234,10 @@ class FigHandle extends HTMLElement {
|
|
|
14759
15234
|
this.prepend(el);
|
|
14760
15235
|
this.#hitAreaEl = el;
|
|
14761
15236
|
}
|
|
14762
|
-
this.style.setProperty(
|
|
15237
|
+
this.style.setProperty(
|
|
15238
|
+
"--fig-handle-hit-area-size",
|
|
15239
|
+
String(parsed.hPad * 2),
|
|
15240
|
+
);
|
|
14763
15241
|
if (parsed.circle) {
|
|
14764
15242
|
this.#hitAreaEl.style.borderRadius = "50%";
|
|
14765
15243
|
} else {
|
|
@@ -14773,10 +15251,12 @@ class FigHandle extends HTMLElement {
|
|
|
14773
15251
|
if (this.#hitAreaMode === "delegate") {
|
|
14774
15252
|
e.preventDefault();
|
|
14775
15253
|
e.stopPropagation();
|
|
14776
|
-
this.dispatchEvent(
|
|
14777
|
-
|
|
14778
|
-
|
|
14779
|
-
|
|
15254
|
+
this.dispatchEvent(
|
|
15255
|
+
new CustomEvent("hitareadown", {
|
|
15256
|
+
bubbles: true,
|
|
15257
|
+
detail: { originalEvent: e },
|
|
15258
|
+
}),
|
|
15259
|
+
);
|
|
14780
15260
|
} else {
|
|
14781
15261
|
this.#onPointerDown(e);
|
|
14782
15262
|
}
|
|
@@ -14796,7 +15276,10 @@ class FigHandle extends HTMLElement {
|
|
|
14796
15276
|
disconnectedCallback() {
|
|
14797
15277
|
this.#teardownDrag();
|
|
14798
15278
|
this.#hideColorTip();
|
|
14799
|
-
if (this.#hitAreaEl) {
|
|
15279
|
+
if (this.#hitAreaEl) {
|
|
15280
|
+
this.#hitAreaEl.remove();
|
|
15281
|
+
this.#hitAreaEl = null;
|
|
15282
|
+
}
|
|
14800
15283
|
this.removeEventListener("click", this.#handleSelect);
|
|
14801
15284
|
document.removeEventListener("pointerdown", this.#handleDeselect);
|
|
14802
15285
|
document.removeEventListener("keydown", this.#handleKeyDown);
|
|
@@ -14805,7 +15288,8 @@ class FigHandle extends HTMLElement {
|
|
|
14805
15288
|
select() {
|
|
14806
15289
|
if (this.hasAttribute("disabled")) return;
|
|
14807
15290
|
this.setAttribute("selected", "");
|
|
14808
|
-
if (this.getAttribute("type") === "color" && !this.#isDragging)
|
|
15291
|
+
if (this.getAttribute("type") === "color" && !this.#isDragging)
|
|
15292
|
+
this.#showColorTip();
|
|
14809
15293
|
}
|
|
14810
15294
|
|
|
14811
15295
|
deselect() {
|
|
@@ -14908,8 +15392,8 @@ class FigHandle extends HTMLElement {
|
|
|
14908
15392
|
lastRect = rect;
|
|
14909
15393
|
const currentLeft = parseFloat(this.style.left) || 0;
|
|
14910
15394
|
const currentTop = parseFloat(this.style.top) || 0;
|
|
14911
|
-
const rawX =
|
|
14912
|
-
const rawY =
|
|
15395
|
+
const rawX = clientX - offsetX - rect.left - handleW / 2;
|
|
15396
|
+
const rawY = clientY - offsetY - rect.top - handleH / 2;
|
|
14913
15397
|
|
|
14914
15398
|
const clampedX = Math.max(
|
|
14915
15399
|
-handleW / 2,
|
|
@@ -15055,16 +15539,32 @@ class FigHandle extends HTMLElement {
|
|
|
15055
15539
|
#handleColorTipInput = (e) => {
|
|
15056
15540
|
e.stopPropagation();
|
|
15057
15541
|
if (e.detail?.color) {
|
|
15058
|
-
this.setAttribute(
|
|
15059
|
-
|
|
15542
|
+
this.setAttribute(
|
|
15543
|
+
"color",
|
|
15544
|
+
this.#colorWithOpacity(e.detail.color, e.detail.opacity),
|
|
15545
|
+
);
|
|
15546
|
+
this.dispatchEvent(
|
|
15547
|
+
new CustomEvent("input", {
|
|
15548
|
+
bubbles: true,
|
|
15549
|
+
detail: { color: e.detail.color, opacity: e.detail.opacity },
|
|
15550
|
+
}),
|
|
15551
|
+
);
|
|
15060
15552
|
}
|
|
15061
15553
|
};
|
|
15062
15554
|
|
|
15063
15555
|
#handleColorTipChange = (e) => {
|
|
15064
15556
|
e.stopPropagation();
|
|
15065
15557
|
if (e.detail?.color) {
|
|
15066
|
-
this.setAttribute(
|
|
15067
|
-
|
|
15558
|
+
this.setAttribute(
|
|
15559
|
+
"color",
|
|
15560
|
+
this.#colorWithOpacity(e.detail.color, e.detail.opacity),
|
|
15561
|
+
);
|
|
15562
|
+
this.dispatchEvent(
|
|
15563
|
+
new CustomEvent("change", {
|
|
15564
|
+
bubbles: true,
|
|
15565
|
+
detail: { color: e.detail.color, opacity: e.detail.opacity },
|
|
15566
|
+
}),
|
|
15567
|
+
);
|
|
15068
15568
|
}
|
|
15069
15569
|
};
|
|
15070
15570
|
|