@rogieking/figui3 3.21.1 → 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 +158 -89
- package/dist/components.css +1 -1
- package/dist/fig.css +1 -1
- package/dist/fig.js +31 -31
- package/fig.js +670 -148
- 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"];
|
|
5915
6108
|
}
|
|
5916
6109
|
|
|
5917
|
-
get
|
|
5918
|
-
return this.hasAttribute("
|
|
6110
|
+
get open() {
|
|
6111
|
+
return this.hasAttribute("open") && this.getAttribute("open") !== "false";
|
|
6112
|
+
}
|
|
6113
|
+
|
|
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%`);
|
|
@@ -6364,6 +6615,8 @@ class FigInputGradient extends HTMLElement {
|
|
|
6364
6615
|
...this.#gradient,
|
|
6365
6616
|
...parsed.gradient,
|
|
6366
6617
|
});
|
|
6618
|
+
this.#gradient.type = "linear";
|
|
6619
|
+
this.#gradient.angle = 90;
|
|
6367
6620
|
return;
|
|
6368
6621
|
}
|
|
6369
6622
|
if (parsed?.gradient) {
|
|
@@ -6371,6 +6624,8 @@ class FigInputGradient extends HTMLElement {
|
|
|
6371
6624
|
...this.#gradient,
|
|
6372
6625
|
...parsed.gradient,
|
|
6373
6626
|
});
|
|
6627
|
+
this.#gradient.type = "linear";
|
|
6628
|
+
this.#gradient.angle = 90;
|
|
6374
6629
|
}
|
|
6375
6630
|
} catch (e) {
|
|
6376
6631
|
// Ignore invalid JSON and keep current/default gradient.
|
|
@@ -6578,10 +6833,12 @@ class FigInputGradient extends HTMLElement {
|
|
|
6578
6833
|
const stopIdx = parseInt(clickedHandle?.dataset.stopIndex, 10);
|
|
6579
6834
|
this.#distributeStops();
|
|
6580
6835
|
if (!isNaN(stopIdx)) {
|
|
6581
|
-
this.#track
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
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
|
+
});
|
|
6585
6842
|
}
|
|
6586
6843
|
e.stopPropagation();
|
|
6587
6844
|
}
|
|
@@ -6720,7 +6977,10 @@ class FigInputGradient extends HTMLElement {
|
|
|
6720
6977
|
e.stopPropagation();
|
|
6721
6978
|
|
|
6722
6979
|
const trackRect = this.#track.getBoundingClientRect();
|
|
6723
|
-
const pct = Math.max(
|
|
6980
|
+
const pct = Math.max(
|
|
6981
|
+
0,
|
|
6982
|
+
Math.min(1, (e.clientX - trackRect.left) / trackRect.width),
|
|
6983
|
+
);
|
|
6724
6984
|
const position = Math.round(pct * 100);
|
|
6725
6985
|
const color = this.#sampleGradientColor(pct);
|
|
6726
6986
|
this.#gradient.stops.push({ position, color, opacity: 100 });
|
|
@@ -6739,19 +6999,23 @@ class FigInputGradient extends HTMLElement {
|
|
|
6739
6999
|
);
|
|
6740
7000
|
const newHandle = handles[newIndex];
|
|
6741
7001
|
if (newHandle) {
|
|
6742
|
-
this.#track
|
|
6743
|
-
|
|
6744
|
-
|
|
7002
|
+
this.#track
|
|
7003
|
+
.querySelectorAll("fig-handle:not(.fig-input-gradient-ghost)")
|
|
7004
|
+
.forEach((h) => {
|
|
7005
|
+
if (h !== newHandle) h.deselect();
|
|
7006
|
+
});
|
|
6745
7007
|
newHandle.select();
|
|
6746
|
-
newHandle.dispatchEvent(
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
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
|
+
);
|
|
6755
7019
|
}
|
|
6756
7020
|
});
|
|
6757
7021
|
|
|
@@ -6766,7 +7030,10 @@ class FigInputGradient extends HTMLElement {
|
|
|
6766
7030
|
if (e.detail.opacity !== undefined) {
|
|
6767
7031
|
this.#gradient.stops[idx].opacity = e.detail.opacity;
|
|
6768
7032
|
}
|
|
6769
|
-
handle.setAttribute(
|
|
7033
|
+
handle.setAttribute(
|
|
7034
|
+
"color",
|
|
7035
|
+
this.#stopColorCSS(this.#gradient.stops[idx]),
|
|
7036
|
+
);
|
|
6770
7037
|
this.#syncChit();
|
|
6771
7038
|
this.#emitInput();
|
|
6772
7039
|
}
|
|
@@ -6781,7 +7048,9 @@ class FigInputGradient extends HTMLElement {
|
|
|
6781
7048
|
let position = rawPosition;
|
|
6782
7049
|
const trackW = this.#track.getBoundingClientRect().width;
|
|
6783
7050
|
if (e.detail?.shiftKey) {
|
|
6784
|
-
position =
|
|
7051
|
+
position =
|
|
7052
|
+
Math.round(position / FigInputGradient.SHIFT_SNAP) *
|
|
7053
|
+
FigInputGradient.SHIFT_SNAP;
|
|
6785
7054
|
} else {
|
|
6786
7055
|
const snapPct = trackW > 0 ? (5 / trackW) * 100 : 0;
|
|
6787
7056
|
for (let i = 0; i < this.#gradient.stops.length; i++) {
|
|
@@ -6821,7 +7090,10 @@ class FigInputGradient extends HTMLElement {
|
|
|
6821
7090
|
if (e.detail.opacity !== undefined) {
|
|
6822
7091
|
this.#gradient.stops[idx].opacity = e.detail.opacity;
|
|
6823
7092
|
}
|
|
6824
|
-
handle.setAttribute(
|
|
7093
|
+
handle.setAttribute(
|
|
7094
|
+
"color",
|
|
7095
|
+
this.#stopColorCSS(this.#gradient.stops[idx]),
|
|
7096
|
+
);
|
|
6825
7097
|
this.#syncChit();
|
|
6826
7098
|
this.#emitChange();
|
|
6827
7099
|
}
|
|
@@ -7574,13 +7846,13 @@ class FigChit extends HTMLElement {
|
|
|
7574
7846
|
|
|
7575
7847
|
if (this.#type === "color") {
|
|
7576
7848
|
const hex = this.#toHex(bg);
|
|
7577
|
-
this.innerHTML = `<input type="color" value="${hex}" />`;
|
|
7849
|
+
this.innerHTML = `<div></div><input type="color" value="${hex}" />`;
|
|
7578
7850
|
this.input = this.querySelector("input");
|
|
7579
7851
|
if (!isVar) {
|
|
7580
7852
|
this.input.addEventListener("input", this.#boundHandleInput);
|
|
7581
7853
|
}
|
|
7582
7854
|
} else {
|
|
7583
|
-
this.innerHTML = "";
|
|
7855
|
+
this.innerHTML = "<div></div>";
|
|
7584
7856
|
this.input = null;
|
|
7585
7857
|
}
|
|
7586
7858
|
} else if (this.#type === "color" && this.input) {
|
|
@@ -7590,8 +7862,14 @@ class FigChit extends HTMLElement {
|
|
|
7590
7862
|
}
|
|
7591
7863
|
}
|
|
7592
7864
|
|
|
7593
|
-
const isImage =
|
|
7594
|
-
|
|
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
|
+
);
|
|
7595
7873
|
}
|
|
7596
7874
|
|
|
7597
7875
|
#handleInput(e) {
|
|
@@ -7618,8 +7896,14 @@ class FigChit extends HTMLElement {
|
|
|
7618
7896
|
if (oldValue === newValue) return;
|
|
7619
7897
|
if (name === "background") {
|
|
7620
7898
|
if (this.#internalUpdate) {
|
|
7621
|
-
const isImg =
|
|
7622
|
-
|
|
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
|
+
);
|
|
7623
7907
|
return;
|
|
7624
7908
|
}
|
|
7625
7909
|
this.#render();
|
|
@@ -7641,9 +7925,7 @@ class FigChit extends HTMLElement {
|
|
|
7641
7925
|
}
|
|
7642
7926
|
}
|
|
7643
7927
|
customElements.define("fig-chit", FigChit);
|
|
7644
|
-
class FigSwatch extends FigChit{
|
|
7645
|
-
|
|
7646
|
-
}
|
|
7928
|
+
class FigSwatch extends FigChit {}
|
|
7647
7929
|
customElements.define("fig-swatch", FigSwatch);
|
|
7648
7930
|
|
|
7649
7931
|
/* Upload */
|
|
@@ -8824,7 +9106,11 @@ class Fig3DRotate extends HTMLElement {
|
|
|
8824
9106
|
this.#precision = parseInt(this.getAttribute("precision") || "1");
|
|
8825
9107
|
figSyncCssVar(this, "--aspect-ratio", this.getAttribute("aspect-ratio"));
|
|
8826
9108
|
figSyncCssVar(this, "--perspective", this.getAttribute("perspective"));
|
|
8827
|
-
figSyncCssVar(
|
|
9109
|
+
figSyncCssVar(
|
|
9110
|
+
this,
|
|
9111
|
+
"--perspective-origin",
|
|
9112
|
+
this.getAttribute("perspective-origin"),
|
|
9113
|
+
);
|
|
8828
9114
|
this.#syncTransformOrigin(this.getAttribute("transform-origin"));
|
|
8829
9115
|
this.#parseFields(this.getAttribute("fields"));
|
|
8830
9116
|
const val = this.getAttribute("value");
|
|
@@ -8842,8 +9128,6 @@ class Fig3DRotate extends HTMLElement {
|
|
|
8842
9128
|
}
|
|
8843
9129
|
}
|
|
8844
9130
|
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
9131
|
#syncTransformOrigin(value) {
|
|
8848
9132
|
if (!value || !value.trim()) {
|
|
8849
9133
|
this.style.removeProperty("--transform-origin");
|
|
@@ -10678,6 +10962,117 @@ class FigLayer extends HTMLElement {
|
|
|
10678
10962
|
}
|
|
10679
10963
|
customElements.define("fig-layer", FigLayer);
|
|
10680
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
|
+
|
|
10681
11076
|
// FigFillPicker
|
|
10682
11077
|
/**
|
|
10683
11078
|
* A comprehensive fill picker component supporting solid colors, gradients, images, video, and webcam.
|
|
@@ -11110,10 +11505,15 @@ class FigFillPicker extends HTMLElement {
|
|
|
11110
11505
|
this.#dialog.addEventListener("close", onDialogClose);
|
|
11111
11506
|
|
|
11112
11507
|
this.#dialogOpenObserver = new MutationObserver(() => {
|
|
11113
|
-
const isOpen =
|
|
11508
|
+
const isOpen =
|
|
11509
|
+
this.#dialog.hasAttribute("open") &&
|
|
11510
|
+
this.#dialog.getAttribute("open") !== "false";
|
|
11114
11511
|
if (!isOpen) onDialogClose();
|
|
11115
11512
|
});
|
|
11116
|
-
this.#dialogOpenObserver.observe(this.#dialog, {
|
|
11513
|
+
this.#dialogOpenObserver.observe(this.#dialog, {
|
|
11514
|
+
attributes: true,
|
|
11515
|
+
attributeFilter: ["open"],
|
|
11516
|
+
});
|
|
11117
11517
|
|
|
11118
11518
|
// Initialize built-in tabs (skip any overridden by custom slots)
|
|
11119
11519
|
const builtinInits = {
|
|
@@ -11209,6 +11609,8 @@ class FigFillPicker extends HTMLElement {
|
|
|
11209
11609
|
<fig-preview class="fig-fill-picker-color-area">
|
|
11210
11610
|
<canvas width="200" height="200"></canvas>
|
|
11211
11611
|
<fig-handle
|
|
11612
|
+
type="color"
|
|
11613
|
+
color="${this.#hsvToHex({ ...this.#color, a: 1 })}"
|
|
11212
11614
|
drag
|
|
11213
11615
|
drag-surface=".fig-fill-picker-color-area"
|
|
11214
11616
|
drag-axes="x,y"
|
|
@@ -11871,7 +12273,9 @@ class FigFillPicker extends HTMLElement {
|
|
|
11871
12273
|
});
|
|
11872
12274
|
|
|
11873
12275
|
// Embedded gradient bar input
|
|
11874
|
-
const gradientBarInput = container.querySelector(
|
|
12276
|
+
const gradientBarInput = container.querySelector(
|
|
12277
|
+
".fig-fill-picker-gradient-bar-input",
|
|
12278
|
+
);
|
|
11875
12279
|
if (gradientBarInput) {
|
|
11876
12280
|
const syncFromBarInput = (e) => {
|
|
11877
12281
|
e.stopPropagation();
|
|
@@ -11944,7 +12348,10 @@ class FigFillPicker extends HTMLElement {
|
|
|
11944
12348
|
if (barInput) {
|
|
11945
12349
|
barInput.setAttribute(
|
|
11946
12350
|
"value",
|
|
11947
|
-
JSON.stringify({
|
|
12351
|
+
JSON.stringify({
|
|
12352
|
+
type: "gradient",
|
|
12353
|
+
gradient: gradientToValueShape(this.#gradient),
|
|
12354
|
+
}),
|
|
11948
12355
|
);
|
|
11949
12356
|
}
|
|
11950
12357
|
|
|
@@ -11973,7 +12380,8 @@ class FigFillPicker extends HTMLElement {
|
|
|
11973
12380
|
if (colorInput) colorInput.setAttribute("value", stop.color);
|
|
11974
12381
|
const removeBtn = row.querySelector(".fig-fill-picker-stop-remove");
|
|
11975
12382
|
if (removeBtn) {
|
|
11976
|
-
if (this.#gradient.stops.length <= 2)
|
|
12383
|
+
if (this.#gradient.stops.length <= 2)
|
|
12384
|
+
removeBtn.setAttribute("disabled", "");
|
|
11977
12385
|
else removeBtn.removeAttribute("disabled");
|
|
11978
12386
|
}
|
|
11979
12387
|
});
|
|
@@ -12902,10 +13310,20 @@ class FigColorTip extends HTMLElement {
|
|
|
12902
13310
|
}
|
|
12903
13311
|
this.removeEventListener("click", this.#handleControlClick);
|
|
12904
13312
|
|
|
12905
|
-
const
|
|
13313
|
+
const rawValue = (this.getAttribute("value") || "").trim();
|
|
13314
|
+
const color = this.#normalizeColor(rawValue);
|
|
13315
|
+
const alpha = this.#extractAlpha(rawValue);
|
|
12906
13316
|
const alphaAttr = this.#alphaEnabled ? "" : 'alpha="false"';
|
|
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 });
|
|
12907
13325
|
this.innerHTML = `
|
|
12908
|
-
<fig-fill-picker mode="solid" ${alphaAttr} value='${
|
|
13326
|
+
<fig-fill-picker mode="solid" ${alphaAttr} value='${pickerValue}'>
|
|
12909
13327
|
<fig-chit background="${color}"></fig-chit>
|
|
12910
13328
|
</fig-fill-picker>`;
|
|
12911
13329
|
|
|
@@ -12940,6 +13358,19 @@ class FigColorTip extends HTMLElement {
|
|
|
12940
13358
|
return "#D9D9D9";
|
|
12941
13359
|
}
|
|
12942
13360
|
|
|
13361
|
+
#extractAlpha(colorValue) {
|
|
13362
|
+
if (!colorValue) return 1;
|
|
13363
|
+
const v = String(colorValue).trim();
|
|
13364
|
+
if (v.startsWith("#") && v.length === 9) {
|
|
13365
|
+
return parseInt(v.slice(7, 9), 16) / 255;
|
|
13366
|
+
}
|
|
13367
|
+
const rgbaMatch = v.match(
|
|
13368
|
+
/rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*([\d.]+)\s*\)/i,
|
|
13369
|
+
);
|
|
13370
|
+
if (rgbaMatch) return parseFloat(rgbaMatch[1]);
|
|
13371
|
+
return 1;
|
|
13372
|
+
}
|
|
13373
|
+
|
|
12943
13374
|
#normalizeColor(colorValue) {
|
|
12944
13375
|
if (!colorValue) return "#D9D9D9";
|
|
12945
13376
|
const value = String(colorValue).trim();
|
|
@@ -12983,17 +13414,20 @@ class FigColorTip extends HTMLElement {
|
|
|
12983
13414
|
}
|
|
12984
13415
|
|
|
12985
13416
|
#syncFromAttributes() {
|
|
12986
|
-
const
|
|
12987
|
-
|
|
13417
|
+
const rawAttr = this.getAttribute("value");
|
|
13418
|
+
const color = this.#normalizeColor(rawAttr);
|
|
13419
|
+
const alpha = this.#extractAlpha(rawAttr);
|
|
13420
|
+
if (rawAttr !== color && alpha >= 1) {
|
|
12988
13421
|
this.setAttribute("value", color);
|
|
12989
13422
|
return;
|
|
12990
13423
|
}
|
|
12991
13424
|
|
|
12992
13425
|
if (this.#fillPicker) {
|
|
12993
|
-
|
|
12994
|
-
|
|
12995
|
-
|
|
12996
|
-
|
|
13426
|
+
const pickerVal =
|
|
13427
|
+
alpha < 1
|
|
13428
|
+
? { type: "solid", color, opacity: Math.round(alpha * 100) }
|
|
13429
|
+
: { type: "solid", color };
|
|
13430
|
+
this.#fillPicker.setAttribute("value", JSON.stringify(pickerVal));
|
|
12997
13431
|
if (this.#alphaEnabled) {
|
|
12998
13432
|
this.#fillPicker.removeAttribute("alpha");
|
|
12999
13433
|
} else {
|
|
@@ -13170,7 +13604,15 @@ class FigChooser extends HTMLElement {
|
|
|
13170
13604
|
}
|
|
13171
13605
|
|
|
13172
13606
|
static get observedAttributes() {
|
|
13173
|
-
return [
|
|
13607
|
+
return [
|
|
13608
|
+
"value",
|
|
13609
|
+
"disabled",
|
|
13610
|
+
"choice-element",
|
|
13611
|
+
"drag",
|
|
13612
|
+
"overflow",
|
|
13613
|
+
"loop",
|
|
13614
|
+
"padding",
|
|
13615
|
+
];
|
|
13174
13616
|
}
|
|
13175
13617
|
|
|
13176
13618
|
get #overflowMode() {
|
|
@@ -13796,7 +14238,13 @@ class FigCanvasControl extends HTMLElement {
|
|
|
13796
14238
|
|
|
13797
14239
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
13798
14240
|
if (oldVal === newVal) return;
|
|
13799
|
-
if (
|
|
14241
|
+
if (
|
|
14242
|
+
name === "value" &&
|
|
14243
|
+
!this.#isDragging &&
|
|
14244
|
+
!this.#isSecondDragging &&
|
|
14245
|
+
!this.#isRadiusDragging &&
|
|
14246
|
+
!this.#isAngleDragging
|
|
14247
|
+
) {
|
|
13800
14248
|
this.#parseValue();
|
|
13801
14249
|
if (this.#pointHandle) this.#syncPositions();
|
|
13802
14250
|
else this.#render();
|
|
@@ -13817,11 +14265,14 @@ class FigCanvasControl extends HTMLElement {
|
|
|
13817
14265
|
}
|
|
13818
14266
|
if (name === "snapping" && this.#pointHandle) {
|
|
13819
14267
|
this.#pointHandle.setAttribute("drag-snapping", newVal || "false");
|
|
13820
|
-
if (this.#secondHandle)
|
|
14268
|
+
if (this.#secondHandle)
|
|
14269
|
+
this.#secondHandle.setAttribute("drag-snapping", newVal || "false");
|
|
13821
14270
|
}
|
|
13822
14271
|
if (name === "name") {
|
|
13823
|
-
if (this.#pointTooltip)
|
|
13824
|
-
|
|
14272
|
+
if (this.#pointTooltip)
|
|
14273
|
+
this.#pointTooltip.setAttribute("text", this.#pointTipText);
|
|
14274
|
+
if (this.#secondTooltip)
|
|
14275
|
+
this.#secondTooltip.setAttribute("text", this.#secondTipText);
|
|
13825
14276
|
}
|
|
13826
14277
|
}
|
|
13827
14278
|
|
|
@@ -13846,13 +14297,16 @@ class FigCanvasControl extends HTMLElement {
|
|
|
13846
14297
|
if (typeof v.angle === "number") this.#angle = v.angle;
|
|
13847
14298
|
if (typeof v.x2 === "number") this.#x2 = v.x2;
|
|
13848
14299
|
if (typeof v.y2 === "number") this.#y2 = v.y2;
|
|
13849
|
-
} catch {
|
|
14300
|
+
} catch {
|
|
14301
|
+
/* ignore */
|
|
14302
|
+
}
|
|
13850
14303
|
}
|
|
13851
14304
|
|
|
13852
14305
|
get value() {
|
|
13853
14306
|
const v = { x: this.#x, y: this.#y };
|
|
13854
14307
|
if (this.#type === "color") {
|
|
13855
|
-
const color =
|
|
14308
|
+
const color =
|
|
14309
|
+
this.getAttribute("color") || this.#pointHandle?.getAttribute("color");
|
|
13856
14310
|
if (color) v.color = color;
|
|
13857
14311
|
}
|
|
13858
14312
|
if (this.#hasRadius) {
|
|
@@ -14153,11 +14607,15 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14153
14607
|
}
|
|
14154
14608
|
|
|
14155
14609
|
#emitInput() {
|
|
14156
|
-
this.dispatchEvent(
|
|
14610
|
+
this.dispatchEvent(
|
|
14611
|
+
new CustomEvent("input", { bubbles: true, detail: this.value }),
|
|
14612
|
+
);
|
|
14157
14613
|
}
|
|
14158
14614
|
|
|
14159
14615
|
#emitChange() {
|
|
14160
|
-
this.dispatchEvent(
|
|
14616
|
+
this.dispatchEvent(
|
|
14617
|
+
new CustomEvent("change", { bubbles: true, detail: this.value }),
|
|
14618
|
+
);
|
|
14161
14619
|
}
|
|
14162
14620
|
|
|
14163
14621
|
#syncValueAttribute() {
|
|
@@ -14189,7 +14647,9 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14189
14647
|
}
|
|
14190
14648
|
this.#syncPositions();
|
|
14191
14649
|
if (this.#hasSecondPoint) {
|
|
14192
|
-
document.body.style.cursor = this.#resizeCursorSvg(
|
|
14650
|
+
document.body.style.cursor = this.#resizeCursorSvg(
|
|
14651
|
+
this.#pointPointLineDeg(),
|
|
14652
|
+
);
|
|
14193
14653
|
}
|
|
14194
14654
|
this.#emitInput();
|
|
14195
14655
|
});
|
|
@@ -14205,14 +14665,17 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14205
14665
|
const py = e.detail?.py ?? this.#y / 100;
|
|
14206
14666
|
this.#x = Math.round(Math.max(0, Math.min(100, px * 100)));
|
|
14207
14667
|
this.#y = Math.round(Math.max(0, Math.min(100, py * 100)));
|
|
14208
|
-
if (this.#pointTooltip && this.#type !== "color")
|
|
14668
|
+
if (this.#pointTooltip && this.#type !== "color")
|
|
14669
|
+
this.#pointTooltip.removeAttribute("show");
|
|
14209
14670
|
if (this.#hasSecondPoint) {
|
|
14210
14671
|
document.body.style.cursor = this.#prevBodyCursor ?? "";
|
|
14211
14672
|
}
|
|
14212
14673
|
this.#syncPositions();
|
|
14213
14674
|
this.#syncValueAttribute();
|
|
14214
14675
|
this.#emitChange();
|
|
14215
|
-
requestAnimationFrame(() => {
|
|
14676
|
+
requestAnimationFrame(() => {
|
|
14677
|
+
this.#isDragging = false;
|
|
14678
|
+
});
|
|
14216
14679
|
});
|
|
14217
14680
|
|
|
14218
14681
|
if (this.#angleHandle) {
|
|
@@ -14229,8 +14692,8 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14229
14692
|
const hy = e.detail?.y ?? 0;
|
|
14230
14693
|
const hw = this.#angleHandle.offsetWidth / 2;
|
|
14231
14694
|
const hh = this.#angleHandle.offsetHeight / 2;
|
|
14232
|
-
const dx =
|
|
14233
|
-
const dy =
|
|
14695
|
+
const dx = hx + hw - cx;
|
|
14696
|
+
const dy = hy + hh - cy;
|
|
14234
14697
|
let angle = (Math.atan2(dy, dx) * 180) / Math.PI;
|
|
14235
14698
|
if (this.#shouldSnap(e.detail?.shiftKey)) {
|
|
14236
14699
|
angle = Math.round(angle / 15) * 15;
|
|
@@ -14255,7 +14718,10 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14255
14718
|
}
|
|
14256
14719
|
|
|
14257
14720
|
if (this.#angleTooltip) {
|
|
14258
|
-
this.#angleTooltip.setAttribute(
|
|
14721
|
+
this.#angleTooltip.setAttribute(
|
|
14722
|
+
"text",
|
|
14723
|
+
`Angle ${Math.round(this.#angle)}°`,
|
|
14724
|
+
);
|
|
14259
14725
|
this.#angleTooltip.setAttribute("show", "true");
|
|
14260
14726
|
this.#angleTooltip.showPopup?.();
|
|
14261
14727
|
}
|
|
@@ -14270,7 +14736,9 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14270
14736
|
this.#syncPositions();
|
|
14271
14737
|
this.#syncValueAttribute();
|
|
14272
14738
|
this.#emitChange();
|
|
14273
|
-
requestAnimationFrame(() => {
|
|
14739
|
+
requestAnimationFrame(() => {
|
|
14740
|
+
this.#isAngleDragging = false;
|
|
14741
|
+
});
|
|
14274
14742
|
});
|
|
14275
14743
|
|
|
14276
14744
|
this.#angleHandle.addEventListener("hitareadown", (e) => {
|
|
@@ -14303,7 +14771,11 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14303
14771
|
angle = Math.round(angle / 15) * 15;
|
|
14304
14772
|
}
|
|
14305
14773
|
this.#angle = angle;
|
|
14306
|
-
if (this.#angleTooltip)
|
|
14774
|
+
if (this.#angleTooltip)
|
|
14775
|
+
this.#angleTooltip.setAttribute(
|
|
14776
|
+
"text",
|
|
14777
|
+
`Angle ${Math.round(angle)}°`,
|
|
14778
|
+
);
|
|
14307
14779
|
this.#syncPositions();
|
|
14308
14780
|
const curDeg = Math.round(angle);
|
|
14309
14781
|
if (curDeg !== lastCursorDeg) {
|
|
@@ -14346,7 +14818,9 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14346
14818
|
this.#secondTooltip.showPopup?.();
|
|
14347
14819
|
}
|
|
14348
14820
|
this.#syncPositions();
|
|
14349
|
-
document.body.style.cursor = this.#resizeCursorSvg(
|
|
14821
|
+
document.body.style.cursor = this.#resizeCursorSvg(
|
|
14822
|
+
this.#pointPointLineDeg(),
|
|
14823
|
+
);
|
|
14350
14824
|
this.#emitInput();
|
|
14351
14825
|
});
|
|
14352
14826
|
|
|
@@ -14357,7 +14831,9 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14357
14831
|
this.#syncPositions();
|
|
14358
14832
|
this.#syncValueAttribute();
|
|
14359
14833
|
this.#emitChange();
|
|
14360
|
-
requestAnimationFrame(() => {
|
|
14834
|
+
requestAnimationFrame(() => {
|
|
14835
|
+
this.#isSecondDragging = false;
|
|
14836
|
+
});
|
|
14361
14837
|
});
|
|
14362
14838
|
|
|
14363
14839
|
this.#setupPointPointHitArea(this.#pointHandle, true);
|
|
@@ -14421,7 +14897,9 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14421
14897
|
this.#y2 = newPctY;
|
|
14422
14898
|
}
|
|
14423
14899
|
this.#syncPositions();
|
|
14424
|
-
const curDeg = Math.round(
|
|
14900
|
+
const curDeg = Math.round(
|
|
14901
|
+
isFirst ? this.#pointPointLineDeg() + 180 : this.#pointPointLineDeg(),
|
|
14902
|
+
);
|
|
14425
14903
|
if (curDeg !== lastCursorDeg) {
|
|
14426
14904
|
lastCursorDeg = curDeg;
|
|
14427
14905
|
document.body.style.cursor = this.#rotateCursorSvg(curDeg);
|
|
@@ -14453,7 +14931,10 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14453
14931
|
const rect = container.getBoundingClientRect();
|
|
14454
14932
|
const cx = (this.#x / 100) * rect.width;
|
|
14455
14933
|
const cy = (this.#y / 100) * rect.height;
|
|
14456
|
-
const deg =
|
|
14934
|
+
const deg =
|
|
14935
|
+
(Math.atan2(e.clientY - rect.top - cy, e.clientX - rect.left - cx) *
|
|
14936
|
+
180) /
|
|
14937
|
+
Math.PI;
|
|
14457
14938
|
circle.style.cursor = this.#resizeCursorSvg(deg);
|
|
14458
14939
|
});
|
|
14459
14940
|
const onDown = (e) => {
|
|
@@ -14475,7 +14956,10 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14475
14956
|
const rect0 = container.getBoundingClientRect();
|
|
14476
14957
|
const cx0 = (this.#x / 100) * rect0.width;
|
|
14477
14958
|
const cy0 = (this.#y / 100) * rect0.height;
|
|
14478
|
-
const initDeg =
|
|
14959
|
+
const initDeg =
|
|
14960
|
+
(Math.atan2(e.clientY - rect0.top - cy0, e.clientX - rect0.left - cx0) *
|
|
14961
|
+
180) /
|
|
14962
|
+
Math.PI;
|
|
14479
14963
|
let lastCursorDeg = Math.round(initDeg);
|
|
14480
14964
|
document.body.style.cursor = this.#resizeCursorSvg(lastCursorDeg);
|
|
14481
14965
|
|
|
@@ -14506,7 +14990,8 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14506
14990
|
} else {
|
|
14507
14991
|
this.#radius = Math.max(0, dist);
|
|
14508
14992
|
}
|
|
14509
|
-
if (this.#radiusTooltip)
|
|
14993
|
+
if (this.#radiusTooltip)
|
|
14994
|
+
this.#radiusTooltip.setAttribute("text", this.#formatRadius());
|
|
14510
14995
|
this.#syncPositions();
|
|
14511
14996
|
this.#emitInput();
|
|
14512
14997
|
};
|
|
@@ -14527,7 +15012,8 @@ class FigCanvasControl extends HTMLElement {
|
|
|
14527
15012
|
window.addEventListener("pointerup", onUp);
|
|
14528
15013
|
};
|
|
14529
15014
|
circle.addEventListener("pointerdown", onDown);
|
|
14530
|
-
this._radiusDragCleanup = () =>
|
|
15015
|
+
this._radiusDragCleanup = () =>
|
|
15016
|
+
circle.removeEventListener("pointerdown", onDown);
|
|
14531
15017
|
}
|
|
14532
15018
|
|
|
14533
15019
|
#teardownRadiusDrag() {
|
|
@@ -14689,8 +15175,10 @@ class FigHandle extends HTMLElement {
|
|
|
14689
15175
|
};
|
|
14690
15176
|
|
|
14691
15177
|
const axes = this.#axes;
|
|
14692
|
-
if (axes.x)
|
|
14693
|
-
|
|
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`;
|
|
14694
15182
|
}
|
|
14695
15183
|
|
|
14696
15184
|
#syncValueAttribute() {
|
|
@@ -14707,16 +15195,25 @@ class FigHandle extends HTMLElement {
|
|
|
14707
15195
|
const raw = this.getAttribute("hit-area");
|
|
14708
15196
|
if (!raw) return null;
|
|
14709
15197
|
const tokens = raw.trim().split(/\s+/);
|
|
14710
|
-
let vPad = 0,
|
|
15198
|
+
let vPad = 0,
|
|
15199
|
+
hPad = 0,
|
|
15200
|
+
circle = false;
|
|
14711
15201
|
const nums = [];
|
|
14712
15202
|
for (const t of tokens) {
|
|
14713
|
-
if (t === "circle") {
|
|
15203
|
+
if (t === "circle") {
|
|
15204
|
+
circle = true;
|
|
15205
|
+
continue;
|
|
15206
|
+
}
|
|
14714
15207
|
const n = parseFloat(t);
|
|
14715
15208
|
if (Number.isFinite(n)) nums.push(n);
|
|
14716
15209
|
}
|
|
14717
|
-
if (nums.length >= 2) {
|
|
14718
|
-
|
|
14719
|
-
|
|
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;
|
|
14720
15217
|
return { vPad, hPad, circle };
|
|
14721
15218
|
}
|
|
14722
15219
|
|
|
@@ -14737,7 +15234,10 @@ class FigHandle extends HTMLElement {
|
|
|
14737
15234
|
this.prepend(el);
|
|
14738
15235
|
this.#hitAreaEl = el;
|
|
14739
15236
|
}
|
|
14740
|
-
this.style.setProperty(
|
|
15237
|
+
this.style.setProperty(
|
|
15238
|
+
"--fig-handle-hit-area-size",
|
|
15239
|
+
String(parsed.hPad * 2),
|
|
15240
|
+
);
|
|
14741
15241
|
if (parsed.circle) {
|
|
14742
15242
|
this.#hitAreaEl.style.borderRadius = "50%";
|
|
14743
15243
|
} else {
|
|
@@ -14751,10 +15251,12 @@ class FigHandle extends HTMLElement {
|
|
|
14751
15251
|
if (this.#hitAreaMode === "delegate") {
|
|
14752
15252
|
e.preventDefault();
|
|
14753
15253
|
e.stopPropagation();
|
|
14754
|
-
this.dispatchEvent(
|
|
14755
|
-
|
|
14756
|
-
|
|
14757
|
-
|
|
15254
|
+
this.dispatchEvent(
|
|
15255
|
+
new CustomEvent("hitareadown", {
|
|
15256
|
+
bubbles: true,
|
|
15257
|
+
detail: { originalEvent: e },
|
|
15258
|
+
}),
|
|
15259
|
+
);
|
|
14758
15260
|
} else {
|
|
14759
15261
|
this.#onPointerDown(e);
|
|
14760
15262
|
}
|
|
@@ -14774,7 +15276,10 @@ class FigHandle extends HTMLElement {
|
|
|
14774
15276
|
disconnectedCallback() {
|
|
14775
15277
|
this.#teardownDrag();
|
|
14776
15278
|
this.#hideColorTip();
|
|
14777
|
-
if (this.#hitAreaEl) {
|
|
15279
|
+
if (this.#hitAreaEl) {
|
|
15280
|
+
this.#hitAreaEl.remove();
|
|
15281
|
+
this.#hitAreaEl = null;
|
|
15282
|
+
}
|
|
14778
15283
|
this.removeEventListener("click", this.#handleSelect);
|
|
14779
15284
|
document.removeEventListener("pointerdown", this.#handleDeselect);
|
|
14780
15285
|
document.removeEventListener("keydown", this.#handleKeyDown);
|
|
@@ -14783,7 +15288,8 @@ class FigHandle extends HTMLElement {
|
|
|
14783
15288
|
select() {
|
|
14784
15289
|
if (this.hasAttribute("disabled")) return;
|
|
14785
15290
|
this.setAttribute("selected", "");
|
|
14786
|
-
if (this.getAttribute("type") === "color" && !this.#isDragging)
|
|
15291
|
+
if (this.getAttribute("type") === "color" && !this.#isDragging)
|
|
15292
|
+
this.#showColorTip();
|
|
14787
15293
|
}
|
|
14788
15294
|
|
|
14789
15295
|
deselect() {
|
|
@@ -14886,8 +15392,8 @@ class FigHandle extends HTMLElement {
|
|
|
14886
15392
|
lastRect = rect;
|
|
14887
15393
|
const currentLeft = parseFloat(this.style.left) || 0;
|
|
14888
15394
|
const currentTop = parseFloat(this.style.top) || 0;
|
|
14889
|
-
const rawX =
|
|
14890
|
-
const rawY =
|
|
15395
|
+
const rawX = clientX - offsetX - rect.left - handleW / 2;
|
|
15396
|
+
const rawY = clientY - offsetY - rect.top - handleH / 2;
|
|
14891
15397
|
|
|
14892
15398
|
const clampedX = Math.max(
|
|
14893
15399
|
-handleW / 2,
|
|
@@ -15033,16 +15539,32 @@ class FigHandle extends HTMLElement {
|
|
|
15033
15539
|
#handleColorTipInput = (e) => {
|
|
15034
15540
|
e.stopPropagation();
|
|
15035
15541
|
if (e.detail?.color) {
|
|
15036
|
-
this.setAttribute(
|
|
15037
|
-
|
|
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
|
+
);
|
|
15038
15552
|
}
|
|
15039
15553
|
};
|
|
15040
15554
|
|
|
15041
15555
|
#handleColorTipChange = (e) => {
|
|
15042
15556
|
e.stopPropagation();
|
|
15043
15557
|
if (e.detail?.color) {
|
|
15044
|
-
this.setAttribute(
|
|
15045
|
-
|
|
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
|
+
);
|
|
15046
15568
|
}
|
|
15047
15569
|
};
|
|
15048
15570
|
|