@rogieking/figui3 3.15.0 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +725 -643
- package/components.css +92 -79
- package/dist/base.css +1 -99
- package/dist/components.css +1 -3978
- package/dist/fig.css +1 -2
- package/dist/fig.js +80 -78
- package/fig.js +381 -226
- package/package.json +14 -9
package/fig.js
CHANGED
|
@@ -75,24 +75,31 @@ function figUniqueId() {
|
|
|
75
75
|
return Date.now().toString(36) + Math.random().toString(36).substring(2);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
* Gets the highest z-index currently in use on the page
|
|
80
|
-
* @returns {number} The highest z-index found, minimum of 1000
|
|
81
|
-
*/
|
|
78
|
+
let _figZCounter = 10000;
|
|
82
79
|
function figGetHighestZIndex() {
|
|
83
|
-
|
|
80
|
+
return _figZCounter++;
|
|
81
|
+
}
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
highest = zIndex;
|
|
91
|
-
}
|
|
83
|
+
function figSyncCssVar(el, prop, value) {
|
|
84
|
+
if (value && value.trim()) {
|
|
85
|
+
el.style.setProperty(prop, value.trim());
|
|
86
|
+
} else {
|
|
87
|
+
el.style.removeProperty(prop);
|
|
92
88
|
}
|
|
89
|
+
}
|
|
93
90
|
|
|
94
|
-
|
|
91
|
+
let _figSharedCanvas = null;
|
|
92
|
+
let _figSharedCtx = null;
|
|
93
|
+
function figGetSharedCanvas(width = 1, height = 1) {
|
|
94
|
+
if (!_figSharedCanvas) {
|
|
95
|
+
_figSharedCanvas = document.createElement("canvas");
|
|
96
|
+
_figSharedCtx = _figSharedCanvas.getContext("2d");
|
|
97
|
+
}
|
|
98
|
+
if (_figSharedCanvas.width !== width) _figSharedCanvas.width = width;
|
|
99
|
+
if (_figSharedCanvas.height !== height) _figSharedCanvas.height = height;
|
|
100
|
+
return { canvas: _figSharedCanvas, ctx: _figSharedCtx };
|
|
95
101
|
}
|
|
102
|
+
|
|
96
103
|
/**
|
|
97
104
|
* Checks if the browser supports the native popover API
|
|
98
105
|
* @returns {boolean} True if popover is supported
|
|
@@ -253,6 +260,7 @@ class FigDropdown extends HTMLElement {
|
|
|
253
260
|
set label(value) {
|
|
254
261
|
this.#label = value;
|
|
255
262
|
}
|
|
263
|
+
#boundSlotChange;
|
|
256
264
|
constructor() {
|
|
257
265
|
super();
|
|
258
266
|
this.select = document.createElement("select");
|
|
@@ -260,6 +268,7 @@ class FigDropdown extends HTMLElement {
|
|
|
260
268
|
this.attachShadow({ mode: "open" });
|
|
261
269
|
this.#boundHandleSelectInput = this.#handleSelectInput.bind(this);
|
|
262
270
|
this.#boundHandleSelectChange = this.#handleSelectChange.bind(this);
|
|
271
|
+
this.#boundSlotChange = this.slotChange.bind(this);
|
|
263
272
|
}
|
|
264
273
|
|
|
265
274
|
#supportsSelectedContent() {
|
|
@@ -342,7 +351,7 @@ class FigDropdown extends HTMLElement {
|
|
|
342
351
|
this.appendChild(this.select);
|
|
343
352
|
this.shadowRoot.appendChild(this.optionsSlot);
|
|
344
353
|
|
|
345
|
-
this.optionsSlot.addEventListener("slotchange", this
|
|
354
|
+
this.optionsSlot.addEventListener("slotchange", this.#boundSlotChange);
|
|
346
355
|
|
|
347
356
|
this.#addEventListeners();
|
|
348
357
|
}
|
|
@@ -478,6 +487,12 @@ class FigDropdown extends HTMLElement {
|
|
|
478
487
|
this.select.setAttribute("aria-label", this.#label);
|
|
479
488
|
}
|
|
480
489
|
}
|
|
490
|
+
|
|
491
|
+
disconnectedCallback() {
|
|
492
|
+
this.optionsSlot.removeEventListener("slotchange", this.#boundSlotChange);
|
|
493
|
+
this.select.removeEventListener("input", this.#boundHandleSelectInput);
|
|
494
|
+
this.select.removeEventListener("change", this.#boundHandleSelectChange);
|
|
495
|
+
}
|
|
481
496
|
}
|
|
482
497
|
|
|
483
498
|
customElements.define("fig-dropdown", FigDropdown);
|
|
@@ -496,6 +511,12 @@ class FigTooltip extends HTMLElement {
|
|
|
496
511
|
|
|
497
512
|
#boundHideOnChromeOpen;
|
|
498
513
|
#boundHidePopupOutsideClick;
|
|
514
|
+
#boundShowDelayedPopup;
|
|
515
|
+
#boundHandlePointerLeave;
|
|
516
|
+
#boundHandleTouchStart;
|
|
517
|
+
#boundHandleTouchMove;
|
|
518
|
+
#boundHandleTouchEnd;
|
|
519
|
+
#boundHandleTouchCancel;
|
|
499
520
|
#touchTimeout;
|
|
500
521
|
#isTouching = false;
|
|
501
522
|
#observer = null;
|
|
@@ -506,9 +527,14 @@ class FigTooltip extends HTMLElement {
|
|
|
506
527
|
let delay = parseInt(this.getAttribute("delay"));
|
|
507
528
|
this.delay = !isNaN(delay) ? delay : 500;
|
|
508
529
|
|
|
509
|
-
// Bind methods that will be used as event listeners
|
|
510
530
|
this.#boundHideOnChromeOpen = this.#hideOnChromeOpen.bind(this);
|
|
511
531
|
this.#boundHidePopupOutsideClick = this.hidePopupOutsideClick.bind(this);
|
|
532
|
+
this.#boundShowDelayedPopup = this.showDelayedPopup.bind(this);
|
|
533
|
+
this.#boundHandlePointerLeave = this.#handlePointerLeave.bind(this);
|
|
534
|
+
this.#boundHandleTouchStart = this.#handleTouchStart.bind(this);
|
|
535
|
+
this.#boundHandleTouchMove = this.#handleTouchMove.bind(this);
|
|
536
|
+
this.#boundHandleTouchEnd = this.#handleTouchEnd.bind(this);
|
|
537
|
+
this.#boundHandleTouchCancel = this.#handleTouchCancel.bind(this);
|
|
512
538
|
}
|
|
513
539
|
connectedCallback() {
|
|
514
540
|
this.setup();
|
|
@@ -517,16 +543,13 @@ class FigTooltip extends HTMLElement {
|
|
|
517
543
|
|
|
518
544
|
disconnectedCallback() {
|
|
519
545
|
this.destroy();
|
|
520
|
-
// Remove global listeners
|
|
521
546
|
document.removeEventListener(
|
|
522
547
|
"mousedown",
|
|
523
548
|
this.#boundHideOnChromeOpen,
|
|
524
549
|
true,
|
|
525
550
|
);
|
|
526
|
-
// Disconnect mutation observer
|
|
527
551
|
this.#stopObserving();
|
|
528
552
|
|
|
529
|
-
// Remove click outside listener for click action
|
|
530
553
|
if (this.action === "click") {
|
|
531
554
|
document.body.removeEventListener(
|
|
532
555
|
"click",
|
|
@@ -534,15 +557,17 @@ class FigTooltip extends HTMLElement {
|
|
|
534
557
|
);
|
|
535
558
|
}
|
|
536
559
|
|
|
537
|
-
// Clean up touch-related timers and listeners
|
|
538
560
|
clearTimeout(this.#touchTimeout);
|
|
539
561
|
if (this.action === "hover") {
|
|
540
|
-
this.removeEventListener("
|
|
541
|
-
this.removeEventListener("
|
|
542
|
-
this.removeEventListener("
|
|
543
|
-
this.removeEventListener("
|
|
562
|
+
this.removeEventListener("pointerenter", this.#boundShowDelayedPopup);
|
|
563
|
+
this.removeEventListener("pointerleave", this.#boundHandlePointerLeave);
|
|
564
|
+
this.removeEventListener("touchstart", this.#boundHandleTouchStart);
|
|
565
|
+
this.removeEventListener("touchmove", this.#boundHandleTouchMove);
|
|
566
|
+
this.removeEventListener("touchend", this.#boundHandleTouchEnd);
|
|
567
|
+
this.removeEventListener("touchcancel", this.#boundHandleTouchCancel);
|
|
544
568
|
} else if (this.action === "click") {
|
|
545
|
-
this.removeEventListener("
|
|
569
|
+
this.removeEventListener("click", this.#boundShowDelayedPopup);
|
|
570
|
+
this.removeEventListener("touchstart", this.#boundShowDelayedPopup);
|
|
546
571
|
}
|
|
547
572
|
}
|
|
548
573
|
|
|
@@ -613,36 +638,29 @@ class FigTooltip extends HTMLElement {
|
|
|
613
638
|
if (this.action === "manual") return;
|
|
614
639
|
if (this.action === "hover") {
|
|
615
640
|
if (!this.isTouchDevice()) {
|
|
616
|
-
this.addEventListener("pointerenter", this
|
|
617
|
-
this.addEventListener(
|
|
618
|
-
"pointerleave",
|
|
619
|
-
this.#handlePointerLeave.bind(this),
|
|
620
|
-
);
|
|
641
|
+
this.addEventListener("pointerenter", this.#boundShowDelayedPopup);
|
|
642
|
+
this.addEventListener("pointerleave", this.#boundHandlePointerLeave);
|
|
621
643
|
}
|
|
622
|
-
|
|
623
|
-
this.addEventListener("touchstart", this.#handleTouchStart.bind(this), {
|
|
644
|
+
this.addEventListener("touchstart", this.#boundHandleTouchStart, {
|
|
624
645
|
passive: true,
|
|
625
646
|
});
|
|
626
|
-
this.addEventListener("touchmove", this.#
|
|
647
|
+
this.addEventListener("touchmove", this.#boundHandleTouchMove, {
|
|
627
648
|
passive: true,
|
|
628
649
|
});
|
|
629
|
-
this.addEventListener("touchend", this.#
|
|
650
|
+
this.addEventListener("touchend", this.#boundHandleTouchEnd, {
|
|
630
651
|
passive: true,
|
|
631
652
|
});
|
|
632
|
-
this.addEventListener("touchcancel", this.#
|
|
653
|
+
this.addEventListener("touchcancel", this.#boundHandleTouchCancel, {
|
|
633
654
|
passive: true,
|
|
634
655
|
});
|
|
635
656
|
} else if (this.action === "click") {
|
|
636
|
-
this.addEventListener("click", this
|
|
657
|
+
this.addEventListener("click", this.#boundShowDelayedPopup);
|
|
637
658
|
document.body.addEventListener("click", this.#boundHidePopupOutsideClick);
|
|
638
|
-
|
|
639
|
-
// Touch support for better mobile responsiveness
|
|
640
|
-
this.addEventListener("touchstart", this.showDelayedPopup.bind(this), {
|
|
659
|
+
this.addEventListener("touchstart", this.#boundShowDelayedPopup, {
|
|
641
660
|
passive: true,
|
|
642
661
|
});
|
|
643
662
|
}
|
|
644
663
|
|
|
645
|
-
// Add listener for chrome interactions
|
|
646
664
|
document.addEventListener("mousedown", this.#boundHideOnChromeOpen, true);
|
|
647
665
|
}
|
|
648
666
|
|
|
@@ -934,6 +952,7 @@ class FigDialog extends HTMLDialogElement {
|
|
|
934
952
|
#boundPointerDown;
|
|
935
953
|
#boundPointerMove;
|
|
936
954
|
#boundPointerUp;
|
|
955
|
+
#boundClose;
|
|
937
956
|
#offset = 16; // 1rem in pixels
|
|
938
957
|
#positionInitialized = false;
|
|
939
958
|
#dragThreshold = 3; // pixels before drag starts
|
|
@@ -943,6 +962,7 @@ class FigDialog extends HTMLDialogElement {
|
|
|
943
962
|
this.#boundPointerDown = this.#handlePointerDown.bind(this);
|
|
944
963
|
this.#boundPointerMove = this.#handlePointerMove.bind(this);
|
|
945
964
|
this.#boundPointerUp = this.#handlePointerUp.bind(this);
|
|
965
|
+
this.#boundClose = this.close.bind(this);
|
|
946
966
|
}
|
|
947
967
|
|
|
948
968
|
connectedCallback() {
|
|
@@ -962,12 +982,15 @@ class FigDialog extends HTMLDialogElement {
|
|
|
962
982
|
|
|
963
983
|
disconnectedCallback() {
|
|
964
984
|
this.#removeDragListeners();
|
|
985
|
+
this.querySelectorAll("fig-button[close-dialog]").forEach((button) => {
|
|
986
|
+
button.removeEventListener("click", this.#boundClose);
|
|
987
|
+
});
|
|
965
988
|
}
|
|
966
989
|
|
|
967
990
|
#addCloseListeners() {
|
|
968
991
|
this.querySelectorAll("fig-button[close-dialog]").forEach((button) => {
|
|
969
|
-
button.removeEventListener("click", this
|
|
970
|
-
button.addEventListener("click", this
|
|
992
|
+
button.removeEventListener("click", this.#boundClose);
|
|
993
|
+
button.addEventListener("click", this.#boundClose);
|
|
971
994
|
});
|
|
972
995
|
}
|
|
973
996
|
|
|
@@ -2242,16 +2265,18 @@ figDefineCustomizedBuiltIn("fig-popup", FigPopup, { extends: "dialog" });
|
|
|
2242
2265
|
*/
|
|
2243
2266
|
class FigTab extends HTMLElement {
|
|
2244
2267
|
#selected;
|
|
2268
|
+
#boundHandleClick;
|
|
2245
2269
|
constructor() {
|
|
2246
2270
|
super();
|
|
2247
2271
|
this.content = null;
|
|
2248
2272
|
this.#selected = false;
|
|
2273
|
+
this.#boundHandleClick = this.handleClick.bind(this);
|
|
2249
2274
|
}
|
|
2250
2275
|
connectedCallback() {
|
|
2251
2276
|
this.setAttribute("label", this.innerText);
|
|
2252
2277
|
this.setAttribute("role", "tab");
|
|
2253
2278
|
this.setAttribute("tabindex", "0");
|
|
2254
|
-
this.addEventListener("click", this
|
|
2279
|
+
this.addEventListener("click", this.#boundHandleClick);
|
|
2255
2280
|
|
|
2256
2281
|
requestAnimationFrame(() => {
|
|
2257
2282
|
if (typeof this.getAttribute("content") === "string") {
|
|
@@ -2276,7 +2301,7 @@ class FigTab extends HTMLElement {
|
|
|
2276
2301
|
this.setAttribute("selected", value ? "true" : "false");
|
|
2277
2302
|
}
|
|
2278
2303
|
disconnectedCallback() {
|
|
2279
|
-
this.removeEventListener("click", this
|
|
2304
|
+
this.removeEventListener("click", this.#boundHandleClick);
|
|
2280
2305
|
}
|
|
2281
2306
|
handleClick() {
|
|
2282
2307
|
this.selected = true;
|
|
@@ -2305,8 +2330,12 @@ customElements.define("fig-tab", FigTab);
|
|
|
2305
2330
|
* @attr {string} name - Identifier for the tabs group
|
|
2306
2331
|
*/
|
|
2307
2332
|
class FigTabs extends HTMLElement {
|
|
2333
|
+
#boundHandleClick;
|
|
2334
|
+
#boundHandleKeyDown;
|
|
2308
2335
|
constructor() {
|
|
2309
2336
|
super();
|
|
2337
|
+
this.#boundHandleClick = this.handleClick.bind(this);
|
|
2338
|
+
this.#boundHandleKeyDown = this.#handleKeyDown.bind(this);
|
|
2310
2339
|
}
|
|
2311
2340
|
|
|
2312
2341
|
static get observedAttributes() {
|
|
@@ -2316,8 +2345,8 @@ class FigTabs extends HTMLElement {
|
|
|
2316
2345
|
connectedCallback() {
|
|
2317
2346
|
this.name = this.getAttribute("name") || "tabs";
|
|
2318
2347
|
this.setAttribute("role", "tablist");
|
|
2319
|
-
this.addEventListener("click", this
|
|
2320
|
-
this.addEventListener("keydown", this.#
|
|
2348
|
+
this.addEventListener("click", this.#boundHandleClick);
|
|
2349
|
+
this.addEventListener("keydown", this.#boundHandleKeyDown);
|
|
2321
2350
|
requestAnimationFrame(() => {
|
|
2322
2351
|
const value = this.getAttribute("value");
|
|
2323
2352
|
if (value) {
|
|
@@ -2345,8 +2374,8 @@ class FigTabs extends HTMLElement {
|
|
|
2345
2374
|
}
|
|
2346
2375
|
|
|
2347
2376
|
disconnectedCallback() {
|
|
2348
|
-
this.removeEventListener("click", this
|
|
2349
|
-
this.removeEventListener("keydown", this.#
|
|
2377
|
+
this.removeEventListener("click", this.#boundHandleClick);
|
|
2378
|
+
this.removeEventListener("keydown", this.#boundHandleKeyDown);
|
|
2350
2379
|
}
|
|
2351
2380
|
|
|
2352
2381
|
#handleKeyDown(event) {
|
|
@@ -2446,14 +2475,16 @@ customElements.define("fig-tabs", FigTabs);
|
|
|
2446
2475
|
class FigSegment extends HTMLElement {
|
|
2447
2476
|
#value;
|
|
2448
2477
|
#selected;
|
|
2478
|
+
#boundHandleClick;
|
|
2449
2479
|
constructor() {
|
|
2450
2480
|
super();
|
|
2481
|
+
this.#boundHandleClick = this.handleClick.bind(this);
|
|
2451
2482
|
}
|
|
2452
2483
|
connectedCallback() {
|
|
2453
|
-
this.addEventListener("click", this
|
|
2484
|
+
this.addEventListener("click", this.#boundHandleClick);
|
|
2454
2485
|
}
|
|
2455
2486
|
disconnectedCallback() {
|
|
2456
|
-
this.removeEventListener("click", this
|
|
2487
|
+
this.removeEventListener("click", this.#boundHandleClick);
|
|
2457
2488
|
}
|
|
2458
2489
|
handleClick() {
|
|
2459
2490
|
const parentControl = this.closest("fig-segmented-control");
|
|
@@ -4519,6 +4550,8 @@ class FigInputColor extends HTMLElement {
|
|
|
4519
4550
|
const hidePicker = this.picker === "false";
|
|
4520
4551
|
const showAlpha = this.getAttribute("alpha") === "true";
|
|
4521
4552
|
const fpAttrs = this.#buildFillPickerAttrs();
|
|
4553
|
+
const disabled = this.#disabled;
|
|
4554
|
+
const disabledAttr = disabled ? " disabled" : "";
|
|
4522
4555
|
|
|
4523
4556
|
let html = ``;
|
|
4524
4557
|
const showText = this.getAttribute("text") === "true";
|
|
@@ -4526,7 +4559,7 @@ class FigInputColor extends HTMLElement {
|
|
|
4526
4559
|
let label = `<fig-input-text
|
|
4527
4560
|
type="text"
|
|
4528
4561
|
placeholder="000000"
|
|
4529
|
-
value="${this.hexOpaque.slice(1).toUpperCase()}">
|
|
4562
|
+
value="${this.hexOpaque.slice(1).toUpperCase()}"${disabledAttr}>
|
|
4530
4563
|
</fig-input-text>`;
|
|
4531
4564
|
if (showAlpha) {
|
|
4532
4565
|
label += `<fig-tooltip text="Opacity">
|
|
@@ -4535,7 +4568,7 @@ class FigInputColor extends HTMLElement {
|
|
|
4535
4568
|
min="0"
|
|
4536
4569
|
max="100"
|
|
4537
4570
|
value="${this.#alphaPercent}"
|
|
4538
|
-
units="%">
|
|
4571
|
+
units="%"${disabledAttr}>
|
|
4539
4572
|
</fig-input-number>
|
|
4540
4573
|
</fig-tooltip>`;
|
|
4541
4574
|
}
|
|
@@ -4547,8 +4580,8 @@ class FigInputColor extends HTMLElement {
|
|
|
4547
4580
|
showAlpha ? "" : 'alpha="false"'
|
|
4548
4581
|
} value='{"type":"solid","color":"${this.hexOpaque}","opacity":${
|
|
4549
4582
|
this.#alphaPercent
|
|
4550
|
-
}}'></fig-fill-picker>`
|
|
4551
|
-
: `<fig-chit background="${this.hexOpaque}" alpha="${this.rgba.a}"></fig-chit>`;
|
|
4583
|
+
}}'${disabledAttr}></fig-fill-picker>`
|
|
4584
|
+
: `<fig-chit background="${this.hexOpaque}" alpha="${this.rgba.a}"${disabledAttr}></fig-chit>`;
|
|
4552
4585
|
}
|
|
4553
4586
|
|
|
4554
4587
|
html = `<div class="input-combo">
|
|
@@ -4564,8 +4597,8 @@ class FigInputColor extends HTMLElement {
|
|
|
4564
4597
|
showAlpha ? "" : 'alpha="false"'
|
|
4565
4598
|
} value='{"type":"solid","color":"${this.hexOpaque}","opacity":${
|
|
4566
4599
|
this.#alphaPercent
|
|
4567
|
-
}}'></fig-fill-picker>`
|
|
4568
|
-
: `<fig-chit background="${this.hexOpaque}" alpha="${this.rgba.a}"></fig-chit>`;
|
|
4600
|
+
}}'${disabledAttr}></fig-fill-picker>`
|
|
4601
|
+
: `<fig-chit background="${this.hexOpaque}" alpha="${this.rgba.a}"${disabledAttr}></fig-chit>`;
|
|
4569
4602
|
}
|
|
4570
4603
|
}
|
|
4571
4604
|
this.innerHTML = html;
|
|
@@ -4759,7 +4792,7 @@ class FigInputColor extends HTMLElement {
|
|
|
4759
4792
|
}
|
|
4760
4793
|
|
|
4761
4794
|
static get observedAttributes() {
|
|
4762
|
-
return ["value", "style", "mode", "picker", "experimental", "alpha", "text"];
|
|
4795
|
+
return ["value", "style", "mode", "picker", "experimental", "alpha", "text", "disabled"];
|
|
4763
4796
|
}
|
|
4764
4797
|
|
|
4765
4798
|
get mode() {
|
|
@@ -4813,6 +4846,26 @@ class FigInputColor extends HTMLElement {
|
|
|
4813
4846
|
case "text":
|
|
4814
4847
|
if (this.isConnected) this.#buildUI();
|
|
4815
4848
|
break;
|
|
4849
|
+
case "disabled":
|
|
4850
|
+
this.#syncDisabled();
|
|
4851
|
+
break;
|
|
4852
|
+
}
|
|
4853
|
+
}
|
|
4854
|
+
|
|
4855
|
+
get #disabled() {
|
|
4856
|
+
return this.hasAttribute("disabled") && this.getAttribute("disabled") !== "false";
|
|
4857
|
+
}
|
|
4858
|
+
|
|
4859
|
+
#syncDisabled() {
|
|
4860
|
+
const disabled = this.#disabled;
|
|
4861
|
+
for (const child of [this.#swatch, this.#textInput, this.#alphaInput]) {
|
|
4862
|
+
if (!child) continue;
|
|
4863
|
+
if (disabled) child.setAttribute("disabled", "");
|
|
4864
|
+
else child.removeAttribute("disabled");
|
|
4865
|
+
}
|
|
4866
|
+
if (this.#fillPicker) {
|
|
4867
|
+
if (disabled) this.#fillPicker.setAttribute("disabled", "");
|
|
4868
|
+
else this.#fillPicker.removeAttribute("disabled");
|
|
4816
4869
|
}
|
|
4817
4870
|
}
|
|
4818
4871
|
|
|
@@ -5062,6 +5115,12 @@ class FigInputFill extends HTMLElement {
|
|
|
5062
5115
|
this.#render();
|
|
5063
5116
|
}
|
|
5064
5117
|
|
|
5118
|
+
disconnectedCallback() {
|
|
5119
|
+
this.#fillPicker = null;
|
|
5120
|
+
this.#opacityInput = null;
|
|
5121
|
+
this.#hexInput = null;
|
|
5122
|
+
}
|
|
5123
|
+
|
|
5065
5124
|
#parseValue() {
|
|
5066
5125
|
const valueAttr = this.getAttribute("value");
|
|
5067
5126
|
if (!valueAttr) return;
|
|
@@ -5132,6 +5191,15 @@ class FigInputFill extends HTMLElement {
|
|
|
5132
5191
|
.join(" ");
|
|
5133
5192
|
}
|
|
5134
5193
|
|
|
5194
|
+
#syncDisabled() {
|
|
5195
|
+
const disabled = this.hasAttribute("disabled");
|
|
5196
|
+
for (const child of [this.#fillPicker, this.#opacityInput, this.#hexInput]) {
|
|
5197
|
+
if (!child) continue;
|
|
5198
|
+
if (disabled) child.setAttribute("disabled", "");
|
|
5199
|
+
else child.removeAttribute("disabled");
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
5202
|
+
|
|
5135
5203
|
#render() {
|
|
5136
5204
|
const disabled = this.hasAttribute("disabled");
|
|
5137
5205
|
const fillPickerValue = JSON.stringify(this.value);
|
|
@@ -5664,10 +5732,7 @@ class FigInputFill extends HTMLElement {
|
|
|
5664
5732
|
}
|
|
5665
5733
|
break;
|
|
5666
5734
|
case "disabled":
|
|
5667
|
-
|
|
5668
|
-
if (this.#fillPicker) {
|
|
5669
|
-
this.#render();
|
|
5670
|
-
}
|
|
5735
|
+
this.#syncDisabled();
|
|
5671
5736
|
break;
|
|
5672
5737
|
case "mode":
|
|
5673
5738
|
case "experimental":
|
|
@@ -5698,17 +5763,22 @@ customElements.define("fig-input-fill", FigInputFill);
|
|
|
5698
5763
|
*/
|
|
5699
5764
|
class FigInputPalette extends HTMLElement {
|
|
5700
5765
|
#colors = [];
|
|
5701
|
-
#
|
|
5766
|
+
#inlinePickers = [];
|
|
5767
|
+
#expandedPickers = [];
|
|
5702
5768
|
#renderRAF = null;
|
|
5703
5769
|
|
|
5704
5770
|
static get observedAttributes() {
|
|
5705
|
-
return ["value", "disabled", "min", "max", "expanded"];
|
|
5771
|
+
return ["value", "disabled", "min", "max", "expanded", "add"];
|
|
5706
5772
|
}
|
|
5707
5773
|
|
|
5708
5774
|
get #expanded() {
|
|
5709
5775
|
return this.hasAttribute("expanded") && this.getAttribute("expanded") !== "false";
|
|
5710
5776
|
}
|
|
5711
5777
|
|
|
5778
|
+
get #showAdd() {
|
|
5779
|
+
return !this.hasAttribute("add") || this.getAttribute("add") !== "false";
|
|
5780
|
+
}
|
|
5781
|
+
|
|
5712
5782
|
get #min() {
|
|
5713
5783
|
const v = parseInt(this.getAttribute("min"));
|
|
5714
5784
|
return isNaN(v) ? 2 : v;
|
|
@@ -5733,7 +5803,8 @@ class FigInputPalette extends HTMLElement {
|
|
|
5733
5803
|
cancelAnimationFrame(this.#renderRAF);
|
|
5734
5804
|
this.#renderRAF = null;
|
|
5735
5805
|
}
|
|
5736
|
-
this.#
|
|
5806
|
+
this.#inlinePickers = [];
|
|
5807
|
+
this.#expandedPickers = [];
|
|
5737
5808
|
}
|
|
5738
5809
|
|
|
5739
5810
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
@@ -5750,6 +5821,7 @@ class FigInputPalette extends HTMLElement {
|
|
|
5750
5821
|
case "min":
|
|
5751
5822
|
case "max":
|
|
5752
5823
|
case "expanded":
|
|
5824
|
+
case "add":
|
|
5753
5825
|
this.#render();
|
|
5754
5826
|
break;
|
|
5755
5827
|
}
|
|
@@ -5826,32 +5898,50 @@ class FigInputPalette extends HTMLElement {
|
|
|
5826
5898
|
const disabled = this.hasAttribute("disabled") && this.getAttribute("disabled") !== "false";
|
|
5827
5899
|
|
|
5828
5900
|
this.innerHTML = "";
|
|
5829
|
-
this.#
|
|
5901
|
+
this.#inlinePickers = [];
|
|
5902
|
+
this.#expandedPickers = [];
|
|
5903
|
+
|
|
5904
|
+
const inlineWrap = document.createElement("div");
|
|
5905
|
+
inlineWrap.className = "palette-colors-inline";
|
|
5830
5906
|
|
|
5831
5907
|
const wrap = document.createElement("div");
|
|
5832
5908
|
wrap.className = "palette-colors";
|
|
5833
5909
|
this.#colors.forEach((entry, i) => {
|
|
5834
|
-
wrap.appendChild(this.#createPicker(entry, i, disabled));
|
|
5910
|
+
wrap.appendChild(this.#createPicker(entry, i, disabled, { inline: true }));
|
|
5835
5911
|
});
|
|
5836
|
-
|
|
5912
|
+
inlineWrap.appendChild(wrap);
|
|
5913
|
+
|
|
5914
|
+
if (this.#showAdd) this.#createAddButton(disabled, inlineWrap);
|
|
5915
|
+
this.appendChild(inlineWrap);
|
|
5837
5916
|
|
|
5838
|
-
|
|
5917
|
+
const expandedWrap = document.createElement("div");
|
|
5918
|
+
expandedWrap.className = "palette-colors-expanded";
|
|
5919
|
+
this.#colors.forEach((entry, i) => {
|
|
5920
|
+
expandedWrap.appendChild(this.#createPicker(entry, i, disabled));
|
|
5921
|
+
});
|
|
5922
|
+
this.appendChild(expandedWrap);
|
|
5839
5923
|
}
|
|
5840
5924
|
|
|
5841
|
-
#createPicker(entry, index, disabled) {
|
|
5925
|
+
#createPicker(entry, index, disabled, { inline = false } = {}) {
|
|
5842
5926
|
const hexAlpha = entry.alpha < 1
|
|
5843
5927
|
? entry.color + Math.round(entry.alpha * 255).toString(16).padStart(2, "0")
|
|
5844
5928
|
: entry.color;
|
|
5845
|
-
const expanded = this.#expanded;
|
|
5846
5929
|
const ic = document.createElement("fig-input-color");
|
|
5847
5930
|
ic.setAttribute("value", hexAlpha);
|
|
5848
|
-
ic.setAttribute("text", expanded ? "true" : "false");
|
|
5849
5931
|
ic.setAttribute("picker", "figma");
|
|
5850
|
-
ic.setAttribute("alpha", "true");
|
|
5851
5932
|
ic.setAttribute("picker-anchor", "self");
|
|
5852
|
-
if (
|
|
5933
|
+
if (inline) {
|
|
5934
|
+
ic.setAttribute("text", "false");
|
|
5935
|
+
ic.setAttribute("alpha", "true");
|
|
5936
|
+
} else {
|
|
5937
|
+
ic.setAttribute("text", "true");
|
|
5938
|
+
ic.setAttribute("alpha", "true");
|
|
5939
|
+
ic.setAttribute("full", "");
|
|
5940
|
+
}
|
|
5853
5941
|
if (disabled) ic.setAttribute("disabled", "");
|
|
5854
5942
|
|
|
5943
|
+
const siblingList = inline ? this.#expandedPickers : this.#inlinePickers;
|
|
5944
|
+
|
|
5855
5945
|
const updateFromPicker = (e) => {
|
|
5856
5946
|
e.stopPropagation();
|
|
5857
5947
|
const el = e.currentTarget;
|
|
@@ -5859,6 +5949,14 @@ class FigInputPalette extends HTMLElement {
|
|
|
5859
5949
|
color: el.hexOpaque || this.#colors[index].color,
|
|
5860
5950
|
alpha: el.rgba ? el.rgba.a : this.#colors[index].alpha,
|
|
5861
5951
|
};
|
|
5952
|
+
const sibling = siblingList[index];
|
|
5953
|
+
if (sibling) {
|
|
5954
|
+
const entry = this.#colors[index];
|
|
5955
|
+
const hex = entry.alpha < 1
|
|
5956
|
+
? entry.color + Math.round(entry.alpha * 255).toString(16).padStart(2, "0")
|
|
5957
|
+
: entry.color;
|
|
5958
|
+
sibling.setAttribute("value", hex);
|
|
5959
|
+
}
|
|
5862
5960
|
};
|
|
5863
5961
|
|
|
5864
5962
|
ic.addEventListener("input", (e) => {
|
|
@@ -5871,11 +5969,12 @@ class FigInputPalette extends HTMLElement {
|
|
|
5871
5969
|
this.#emitChange();
|
|
5872
5970
|
});
|
|
5873
5971
|
|
|
5874
|
-
this.#
|
|
5972
|
+
if (inline) this.#inlinePickers.push(ic);
|
|
5973
|
+
else this.#expandedPickers.push(ic);
|
|
5875
5974
|
return ic;
|
|
5876
5975
|
}
|
|
5877
5976
|
|
|
5878
|
-
#createAddButton(disabled) {
|
|
5977
|
+
#createAddButton(disabled, parent = this) {
|
|
5879
5978
|
const atMax = this.#colors.length >= this.#max;
|
|
5880
5979
|
const addBtn = document.createElement("fig-button");
|
|
5881
5980
|
addBtn.setAttribute("variant", "ghost");
|
|
@@ -5892,19 +5991,21 @@ class FigInputPalette extends HTMLElement {
|
|
|
5892
5991
|
const tooltip = document.createElement("fig-tooltip");
|
|
5893
5992
|
tooltip.setAttribute("text", "Add color");
|
|
5894
5993
|
tooltip.appendChild(addBtn);
|
|
5895
|
-
|
|
5994
|
+
parent.appendChild(tooltip);
|
|
5896
5995
|
}
|
|
5897
5996
|
|
|
5898
5997
|
#addColor(entry) {
|
|
5899
5998
|
this.#colors.push(entry);
|
|
5900
5999
|
const disabled = this.hasAttribute("disabled") && this.getAttribute("disabled") !== "false";
|
|
5901
|
-
const
|
|
6000
|
+
const index = this.#colors.length - 1;
|
|
6001
|
+
|
|
6002
|
+
const inlineIc = this.#createPicker(entry, index, disabled, { inline: true });
|
|
5902
6003
|
const wrap = this.querySelector(".palette-colors");
|
|
5903
|
-
if (wrap)
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
6004
|
+
if (wrap) wrap.appendChild(inlineIc);
|
|
6005
|
+
|
|
6006
|
+
const expandedIc = this.#createPicker(entry, index, disabled);
|
|
6007
|
+
const expandedWrap = this.querySelector(".palette-colors-expanded");
|
|
6008
|
+
if (expandedWrap) expandedWrap.appendChild(expandedIc);
|
|
5908
6009
|
|
|
5909
6010
|
if (this.#colors.length >= this.#max) {
|
|
5910
6011
|
const addBtn = this.querySelector(".palette-add-btn");
|
|
@@ -5914,17 +6015,19 @@ class FigInputPalette extends HTMLElement {
|
|
|
5914
6015
|
}
|
|
5915
6016
|
|
|
5916
6017
|
#updateChit(index) {
|
|
5917
|
-
const ic = this.#pickers[index];
|
|
5918
|
-
if (!ic) return;
|
|
5919
6018
|
const entry = this.#colors[index];
|
|
6019
|
+
if (!entry) return;
|
|
5920
6020
|
const hexAlpha = entry.alpha < 1
|
|
5921
6021
|
? entry.color + Math.round(entry.alpha * 255).toString(16).padStart(2, "0")
|
|
5922
6022
|
: entry.color;
|
|
5923
|
-
|
|
6023
|
+
const inl = this.#inlinePickers[index];
|
|
6024
|
+
if (inl) inl.setAttribute("value", hexAlpha);
|
|
6025
|
+
const exp = this.#expandedPickers[index];
|
|
6026
|
+
if (exp) exp.setAttribute("value", hexAlpha);
|
|
5924
6027
|
}
|
|
5925
6028
|
|
|
5926
6029
|
#syncPickers() {
|
|
5927
|
-
if (this.#
|
|
6030
|
+
if (this.#inlinePickers.length !== this.#colors.length) {
|
|
5928
6031
|
this.#render();
|
|
5929
6032
|
return;
|
|
5930
6033
|
}
|
|
@@ -5935,7 +6038,7 @@ class FigInputPalette extends HTMLElement {
|
|
|
5935
6038
|
|
|
5936
6039
|
#syncDisabled() {
|
|
5937
6040
|
const disabled = this.hasAttribute("disabled") && this.getAttribute("disabled") !== "false";
|
|
5938
|
-
this.#
|
|
6041
|
+
[...this.#inlinePickers, ...this.#expandedPickers].forEach((fp) => {
|
|
5939
6042
|
if (disabled) fp.setAttribute("disabled", "");
|
|
5940
6043
|
else fp.removeAttribute("disabled");
|
|
5941
6044
|
});
|
|
@@ -5975,6 +6078,7 @@ customElements.define("fig-input-palette", FigInputPalette);
|
|
|
5975
6078
|
* @fires change - When the gradient value is committed
|
|
5976
6079
|
*/
|
|
5977
6080
|
class FigInputGradient extends HTMLElement {
|
|
6081
|
+
static SHIFT_SNAP = 5;
|
|
5978
6082
|
#chit;
|
|
5979
6083
|
#track;
|
|
5980
6084
|
#handleDragging = false;
|
|
@@ -6007,6 +6111,16 @@ class FigInputGradient extends HTMLElement {
|
|
|
6007
6111
|
|
|
6008
6112
|
disconnectedCallback() {
|
|
6009
6113
|
document.removeEventListener("keydown", this.#onKeyDown);
|
|
6114
|
+
if (this.#colorObserver) {
|
|
6115
|
+
this.#colorObserver.disconnect();
|
|
6116
|
+
this.#colorObserver = null;
|
|
6117
|
+
}
|
|
6118
|
+
clearTimeout(this.#arrowTooltipTimer);
|
|
6119
|
+
this.removeEventListener("pointerenter", this.#onTrackEnter);
|
|
6120
|
+
this.removeEventListener("pointermove", this.#onTrackMove);
|
|
6121
|
+
this.removeEventListener("pointerleave", this.#onTrackLeave);
|
|
6122
|
+
this.removeEventListener("click", this.#onTrackClick);
|
|
6123
|
+
this.removeEventListener("dblclick", this.#onTrackDblClick);
|
|
6010
6124
|
}
|
|
6011
6125
|
|
|
6012
6126
|
#onKeyDown = (e) => {
|
|
@@ -6046,7 +6160,7 @@ class FigInputGradient extends HTMLElement {
|
|
|
6046
6160
|
const idx = parseInt(selected.dataset.stopIndex, 10);
|
|
6047
6161
|
if (isNaN(idx) || !this.#gradient.stops[idx]) return;
|
|
6048
6162
|
e.preventDefault();
|
|
6049
|
-
const delta = (e.key === "ArrowRight" ? 1 : -1) * (e.shiftKey ?
|
|
6163
|
+
const delta = (e.key === "ArrowRight" ? 1 : -1) * (e.shiftKey ? FigInputGradient.SHIFT_SNAP : 1);
|
|
6050
6164
|
const stop = this.#gradient.stops[idx];
|
|
6051
6165
|
stop.position = Math.max(0, Math.min(100, stop.position + delta));
|
|
6052
6166
|
selected.setAttribute("value", `${stop.position}% 50%`);
|
|
@@ -6141,10 +6255,8 @@ class FigInputGradient extends HTMLElement {
|
|
|
6141
6255
|
}
|
|
6142
6256
|
|
|
6143
6257
|
#sampleGradientColor(position) {
|
|
6144
|
-
const
|
|
6145
|
-
|
|
6146
|
-
canvas.height = 1;
|
|
6147
|
-
const ctx = canvas.getContext("2d");
|
|
6258
|
+
const { ctx } = figGetSharedCanvas(256, 1);
|
|
6259
|
+
ctx.clearRect(0, 0, 256, 1);
|
|
6148
6260
|
const grad = ctx.createLinearGradient(0, 0, 256, 0);
|
|
6149
6261
|
for (const stop of this.#gradient.stops) {
|
|
6150
6262
|
try {
|
|
@@ -6242,15 +6354,15 @@ class FigInputGradient extends HTMLElement {
|
|
|
6242
6354
|
this.#syncChit();
|
|
6243
6355
|
this.#emitInput();
|
|
6244
6356
|
this.#emitChange();
|
|
6245
|
-
this.#track?.querySelectorAll("fig-handle[selected]").forEach((h) => {
|
|
6246
|
-
h.removeAttribute("selected");
|
|
6247
|
-
});
|
|
6248
6357
|
}
|
|
6249
6358
|
|
|
6250
6359
|
#onTrackDblClick = (e) => {
|
|
6251
6360
|
if (!this.#track) return;
|
|
6252
6361
|
if (!e.target.closest("fig-handle:not(.fig-input-gradient-ghost)")) return;
|
|
6253
6362
|
this.#distributeStops();
|
|
6363
|
+
this.#track.querySelectorAll("fig-handle[selected]").forEach((h) => {
|
|
6364
|
+
h.removeAttribute("selected");
|
|
6365
|
+
});
|
|
6254
6366
|
};
|
|
6255
6367
|
|
|
6256
6368
|
#onTrackClick = (e) => {
|
|
@@ -6258,7 +6370,15 @@ class FigInputGradient extends HTMLElement {
|
|
|
6258
6370
|
if (this.#handleDragging) return;
|
|
6259
6371
|
if (e.target.closest("fig-handle:not(.fig-input-gradient-ghost)")) {
|
|
6260
6372
|
if (e.shiftKey) {
|
|
6373
|
+
const clickedHandle = e.target.closest("fig-handle");
|
|
6374
|
+
const stopIdx = parseInt(clickedHandle?.dataset.stopIndex, 10);
|
|
6261
6375
|
this.#distributeStops();
|
|
6376
|
+
if (!isNaN(stopIdx)) {
|
|
6377
|
+
this.#track.querySelectorAll("fig-handle:not(.fig-input-gradient-ghost)").forEach((h) => {
|
|
6378
|
+
if (parseInt(h.dataset.stopIndex, 10) === stopIdx) h.select();
|
|
6379
|
+
else h.deselect();
|
|
6380
|
+
});
|
|
6381
|
+
}
|
|
6262
6382
|
e.stopPropagation();
|
|
6263
6383
|
}
|
|
6264
6384
|
return;
|
|
@@ -6307,6 +6427,7 @@ class FigInputGradient extends HTMLElement {
|
|
|
6307
6427
|
for (let i = 0; i < stops.length; i++) {
|
|
6308
6428
|
const h = handles[i];
|
|
6309
6429
|
const stop = stops[i];
|
|
6430
|
+
h.dataset.stopIndex = i;
|
|
6310
6431
|
h.setAttribute("value", `${stop.position}% 50%`);
|
|
6311
6432
|
h.setAttribute("color", stop.color);
|
|
6312
6433
|
const tip = h.closest("fig-tooltip");
|
|
@@ -6374,6 +6495,44 @@ class FigInputGradient extends HTMLElement {
|
|
|
6374
6495
|
#setupEventListeners() {
|
|
6375
6496
|
if (!this.#track) return;
|
|
6376
6497
|
|
|
6498
|
+
this.#track.addEventListener("pointerdown", (e) => {
|
|
6499
|
+
if (this.hasAttribute("disabled")) return;
|
|
6500
|
+
if (e.target.closest("fig-handle:not(.fig-input-gradient-ghost)")) return;
|
|
6501
|
+
if (e.button !== 0) return;
|
|
6502
|
+
e.preventDefault();
|
|
6503
|
+
|
|
6504
|
+
const trackRect = this.#track.getBoundingClientRect();
|
|
6505
|
+
const pct = Math.max(0, Math.min(1, (e.clientX - trackRect.left) / trackRect.width));
|
|
6506
|
+
const position = Math.round(pct * 100);
|
|
6507
|
+
const color = this.#sampleGradientColor(pct);
|
|
6508
|
+
this.#gradient.stops.push({ position, color, opacity: 100 });
|
|
6509
|
+
this.#gradient.stops.sort((a, b) => a.position - b.position);
|
|
6510
|
+
const newIndex = this.#gradient.stops.findIndex(
|
|
6511
|
+
(s) => s.position === position && s.color === color,
|
|
6512
|
+
);
|
|
6513
|
+
this.#syncHandles();
|
|
6514
|
+
this.#syncChit();
|
|
6515
|
+
this.#emitInput();
|
|
6516
|
+
this.#hideGhost();
|
|
6517
|
+
|
|
6518
|
+
const handles = this.#track.querySelectorAll(
|
|
6519
|
+
"fig-handle:not(.fig-input-gradient-ghost)",
|
|
6520
|
+
);
|
|
6521
|
+
const newHandle = handles[newIndex];
|
|
6522
|
+
if (newHandle) {
|
|
6523
|
+
newHandle.select();
|
|
6524
|
+
newHandle.dispatchEvent(new PointerEvent("pointerdown", {
|
|
6525
|
+
bubbles: true,
|
|
6526
|
+
clientX: e.clientX,
|
|
6527
|
+
clientY: e.clientY,
|
|
6528
|
+
pointerId: e.pointerId,
|
|
6529
|
+
pointerType: e.pointerType,
|
|
6530
|
+
button: e.button,
|
|
6531
|
+
buttons: e.buttons,
|
|
6532
|
+
}));
|
|
6533
|
+
}
|
|
6534
|
+
});
|
|
6535
|
+
|
|
6377
6536
|
this.#track.addEventListener("input", (e) => {
|
|
6378
6537
|
const handle = e.target.closest("fig-handle");
|
|
6379
6538
|
if (!handle) return;
|
|
@@ -6387,7 +6546,7 @@ class FigInputGradient extends HTMLElement {
|
|
|
6387
6546
|
let position = rawPosition;
|
|
6388
6547
|
const trackW = this.#track.getBoundingClientRect().width;
|
|
6389
6548
|
if (e.detail?.shiftKey) {
|
|
6390
|
-
position = Math.round(position /
|
|
6549
|
+
position = Math.round(position / FigInputGradient.SHIFT_SNAP) * FigInputGradient.SHIFT_SNAP;
|
|
6391
6550
|
} else {
|
|
6392
6551
|
const snapPct = trackW > 0 ? (5 / trackW) * 100 : 0;
|
|
6393
6552
|
for (let i = 0; i < this.#gradient.stops.length; i++) {
|
|
@@ -6515,10 +6674,24 @@ class FigInputGradient extends HTMLElement {
|
|
|
6515
6674
|
this.#syncHandles();
|
|
6516
6675
|
break;
|
|
6517
6676
|
case "disabled":
|
|
6518
|
-
this.#
|
|
6677
|
+
this.#syncDisabled();
|
|
6519
6678
|
break;
|
|
6520
6679
|
}
|
|
6521
6680
|
}
|
|
6681
|
+
|
|
6682
|
+
#syncDisabled() {
|
|
6683
|
+
const disabled = this.hasAttribute("disabled");
|
|
6684
|
+
if (this.#chit) {
|
|
6685
|
+
if (disabled) this.#chit.setAttribute("disabled", "");
|
|
6686
|
+
else this.#chit.removeAttribute("disabled");
|
|
6687
|
+
}
|
|
6688
|
+
if (this.#track) {
|
|
6689
|
+
for (const handle of this.#track.querySelectorAll("fig-handle")) {
|
|
6690
|
+
if (disabled) handle.setAttribute("disabled", "");
|
|
6691
|
+
else handle.removeAttribute("disabled");
|
|
6692
|
+
}
|
|
6693
|
+
}
|
|
6694
|
+
}
|
|
6522
6695
|
}
|
|
6523
6696
|
customElements.define("fig-input-gradient", FigInputGradient);
|
|
6524
6697
|
|
|
@@ -6761,9 +6934,11 @@ customElements.define("fig-switch", FigSwitch);
|
|
|
6761
6934
|
class FigToast extends HTMLDialogElement {
|
|
6762
6935
|
_defaultOffset = 16; // 1rem in pixels
|
|
6763
6936
|
_autoCloseTimer = null;
|
|
6937
|
+
#boundHandleClose;
|
|
6764
6938
|
|
|
6765
6939
|
constructor() {
|
|
6766
6940
|
super();
|
|
6941
|
+
this.#boundHandleClose = this.handleClose.bind(this);
|
|
6767
6942
|
}
|
|
6768
6943
|
|
|
6769
6944
|
getOffset() {
|
|
@@ -6813,8 +6988,8 @@ class FigToast extends HTMLDialogElement {
|
|
|
6813
6988
|
|
|
6814
6989
|
addCloseListeners() {
|
|
6815
6990
|
this.querySelectorAll("[close-toast]").forEach((button) => {
|
|
6816
|
-
button.removeEventListener("click", this
|
|
6817
|
-
button.addEventListener("click", this
|
|
6991
|
+
button.removeEventListener("click", this.#boundHandleClose);
|
|
6992
|
+
button.addEventListener("click", this.#boundHandleClose);
|
|
6818
6993
|
});
|
|
6819
6994
|
}
|
|
6820
6995
|
|
|
@@ -7101,12 +7276,10 @@ class FigChit extends HTMLElement {
|
|
|
7101
7276
|
}
|
|
7102
7277
|
|
|
7103
7278
|
#toHex(color) {
|
|
7104
|
-
// Convert color to hex for the native input
|
|
7105
7279
|
if (!color) return "#D9D9D9";
|
|
7106
7280
|
if (color.startsWith("#")) return color.slice(0, 7);
|
|
7107
|
-
// Use canvas to convert rgba/named colors to hex
|
|
7108
7281
|
try {
|
|
7109
|
-
const ctx =
|
|
7282
|
+
const { ctx } = figGetSharedCanvas(1, 1);
|
|
7110
7283
|
ctx.fillStyle = color;
|
|
7111
7284
|
return ctx.fillStyle;
|
|
7112
7285
|
} catch {
|
|
@@ -7497,11 +7670,10 @@ class FigEasingCurve extends HTMLElement {
|
|
|
7497
7670
|
#bounds = null;
|
|
7498
7671
|
#diagonal = null;
|
|
7499
7672
|
#resizeObserver = null;
|
|
7500
|
-
#bezierHandleRadius =
|
|
7673
|
+
#bezierHandleRadius = 5;
|
|
7501
7674
|
#bezierEndpointRadius = 2;
|
|
7502
|
-
#
|
|
7503
|
-
#
|
|
7504
|
-
#durationBarHeight = 16;
|
|
7675
|
+
#durationBarWidth = 10;
|
|
7676
|
+
#durationBarHeight = 10;
|
|
7505
7677
|
#durationBarRadius = 3;
|
|
7506
7678
|
|
|
7507
7679
|
static PRESETS = [
|
|
@@ -7576,7 +7748,7 @@ class FigEasingCurve extends HTMLElement {
|
|
|
7576
7748
|
|
|
7577
7749
|
connectedCallback() {
|
|
7578
7750
|
this.#precision = parseInt(this.getAttribute("precision") || "2");
|
|
7579
|
-
|
|
7751
|
+
figSyncCssVar(this, "--aspect-ratio", this.getAttribute("aspect-ratio"));
|
|
7580
7752
|
const val = this.getAttribute("value");
|
|
7581
7753
|
if (val) this.#parseValue(val);
|
|
7582
7754
|
this.#presetName = this.#matchPreset();
|
|
@@ -7592,17 +7764,9 @@ class FigEasingCurve extends HTMLElement {
|
|
|
7592
7764
|
}
|
|
7593
7765
|
}
|
|
7594
7766
|
|
|
7595
|
-
#syncAspectRatioVar(value) {
|
|
7596
|
-
if (value && value.trim()) {
|
|
7597
|
-
this.style.setProperty("--aspect-ratio", value.trim());
|
|
7598
|
-
} else {
|
|
7599
|
-
this.style.removeProperty("--aspect-ratio");
|
|
7600
|
-
}
|
|
7601
|
-
}
|
|
7602
|
-
|
|
7603
7767
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
7604
7768
|
if (name === "aspect-ratio") {
|
|
7605
|
-
this
|
|
7769
|
+
figSyncCssVar(this, "--aspect-ratio", newValue);
|
|
7606
7770
|
if (this.#svg) {
|
|
7607
7771
|
this.#syncViewportSize();
|
|
7608
7772
|
this.#updatePaths();
|
|
@@ -7818,6 +7982,7 @@ class FigEasingCurve extends HTMLElement {
|
|
|
7818
7982
|
this.#syncMetricsFromCSS();
|
|
7819
7983
|
this.innerHTML = this.#getInnerHTML();
|
|
7820
7984
|
this.#cacheRefs();
|
|
7985
|
+
this.#syncHandleSizes();
|
|
7821
7986
|
this.#syncViewportSize();
|
|
7822
7987
|
this.#updatePaths();
|
|
7823
7988
|
this.#setupEvents();
|
|
@@ -7857,8 +8022,6 @@ class FigEasingCurve extends HTMLElement {
|
|
|
7857
8022
|
const size = 200;
|
|
7858
8023
|
const dropdown = this.#getDropdownHTML();
|
|
7859
8024
|
|
|
7860
|
-
const hs = this.#bezierHandleRadius * 2;
|
|
7861
|
-
|
|
7862
8025
|
if (this.#mode === "spring") {
|
|
7863
8026
|
const targetY = 40;
|
|
7864
8027
|
const startY = 180;
|
|
@@ -7867,8 +8030,8 @@ class FigEasingCurve extends HTMLElement {
|
|
|
7867
8030
|
<line class="fig-easing-curve-target" x1="0" y1="${targetY}" x2="${size}" y2="${targetY}"/>
|
|
7868
8031
|
<line class="fig-easing-curve-diagonal" x1="0" y1="${startY}" x2="0" y2="${startY}"/>
|
|
7869
8032
|
<path class="fig-easing-curve-path"/>
|
|
7870
|
-
<foreignObject class="fig-easing-curve-handle" data-handle="bounce" width="
|
|
7871
|
-
<foreignObject class="fig-easing-curve-handle fig-easing-curve-duration-bar" data-handle="duration" width="
|
|
8033
|
+
<foreignObject class="fig-easing-curve-handle" data-handle="bounce" width="20" height="20"><fig-handle size="small"></fig-handle></foreignObject>
|
|
8034
|
+
<foreignObject class="fig-easing-curve-handle fig-easing-curve-duration-bar" data-handle="duration" width="20" height="20"><fig-handle size="small"></fig-handle></foreignObject>
|
|
7872
8035
|
</svg></div>`;
|
|
7873
8036
|
}
|
|
7874
8037
|
|
|
@@ -7880,8 +8043,8 @@ class FigEasingCurve extends HTMLElement {
|
|
|
7880
8043
|
<path class="fig-easing-curve-path"/>
|
|
7881
8044
|
<circle class="fig-easing-curve-endpoint" data-endpoint="start" r="${this.#bezierEndpointRadius}"/>
|
|
7882
8045
|
<circle class="fig-easing-curve-endpoint" data-endpoint="end" r="${this.#bezierEndpointRadius}"/>
|
|
7883
|
-
<foreignObject class="fig-easing-curve-handle" data-handle="1" width="
|
|
7884
|
-
<foreignObject class="fig-easing-curve-handle" data-handle="2" width="
|
|
8046
|
+
<foreignObject class="fig-easing-curve-handle" data-handle="1" width="20" height="20"><fig-handle size="small"></fig-handle></foreignObject>
|
|
8047
|
+
<foreignObject class="fig-easing-curve-handle" data-handle="2" width="20" height="20"><fig-handle size="small"></fig-handle></foreignObject>
|
|
7885
8048
|
</svg></div>`;
|
|
7886
8049
|
}
|
|
7887
8050
|
|
|
@@ -7893,26 +8056,10 @@ class FigEasingCurve extends HTMLElement {
|
|
|
7893
8056
|
}
|
|
7894
8057
|
|
|
7895
8058
|
#syncMetricsFromCSS() {
|
|
7896
|
-
this.#bezierHandleRadius = this.#readCssNumber(
|
|
7897
|
-
"--easing-bezier-handle-radius",
|
|
7898
|
-
this.#bezierHandleRadius,
|
|
7899
|
-
);
|
|
7900
8059
|
this.#bezierEndpointRadius = this.#readCssNumber(
|
|
7901
8060
|
"--easing-bezier-endpoint-radius",
|
|
7902
8061
|
this.#bezierEndpointRadius,
|
|
7903
8062
|
);
|
|
7904
|
-
this.#springHandleRadius = this.#readCssNumber(
|
|
7905
|
-
"--easing-spring-handle-radius",
|
|
7906
|
-
this.#springHandleRadius,
|
|
7907
|
-
);
|
|
7908
|
-
this.#durationBarWidth = this.#readCssNumber(
|
|
7909
|
-
"--easing-duration-bar-width",
|
|
7910
|
-
this.#durationBarWidth,
|
|
7911
|
-
);
|
|
7912
|
-
this.#durationBarHeight = this.#readCssNumber(
|
|
7913
|
-
"--easing-duration-bar-height",
|
|
7914
|
-
this.#durationBarHeight,
|
|
7915
|
-
);
|
|
7916
8063
|
this.#durationBarRadius = this.#readCssNumber(
|
|
7917
8064
|
"--easing-duration-bar-radius",
|
|
7918
8065
|
this.#durationBarRadius,
|
|
@@ -7938,6 +8085,28 @@ class FigEasingCurve extends HTMLElement {
|
|
|
7938
8085
|
this.#diagonal = this.querySelector(".fig-easing-curve-diagonal");
|
|
7939
8086
|
}
|
|
7940
8087
|
|
|
8088
|
+
#syncHandleSizes() {
|
|
8089
|
+
const h1El = this.#handle1?.querySelector("fig-handle");
|
|
8090
|
+
const h2El = this.#handle2?.querySelector("fig-handle");
|
|
8091
|
+
if (h1El) {
|
|
8092
|
+
const w = h1El.offsetWidth || this.#bezierHandleRadius * 2;
|
|
8093
|
+
const h = h1El.offsetHeight || this.#bezierHandleRadius * 2;
|
|
8094
|
+
this.#bezierHandleRadius = Math.max(w, h) / 2;
|
|
8095
|
+
this.#handle1.setAttribute("width", w);
|
|
8096
|
+
this.#handle1.setAttribute("height", h);
|
|
8097
|
+
}
|
|
8098
|
+
if (h2El) {
|
|
8099
|
+
const w = h2El.offsetWidth || this.#durationBarWidth;
|
|
8100
|
+
const h = h2El.offsetHeight || this.#durationBarHeight;
|
|
8101
|
+
if (this.#mode === "spring") {
|
|
8102
|
+
this.#durationBarWidth = w;
|
|
8103
|
+
this.#durationBarHeight = h;
|
|
8104
|
+
}
|
|
8105
|
+
this.#handle2.setAttribute("width", w);
|
|
8106
|
+
this.#handle2.setAttribute("height", h);
|
|
8107
|
+
}
|
|
8108
|
+
}
|
|
8109
|
+
|
|
7941
8110
|
#setupResizeObserver() {
|
|
7942
8111
|
if (this.#resizeObserver || !window.ResizeObserver) return;
|
|
7943
8112
|
this.#resizeObserver = new ResizeObserver(() => {
|
|
@@ -8392,12 +8561,9 @@ class Fig3DRotate extends HTMLElement {
|
|
|
8392
8561
|
|
|
8393
8562
|
connectedCallback() {
|
|
8394
8563
|
this.#precision = parseInt(this.getAttribute("precision") || "1");
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
this
|
|
8398
|
-
"--perspective-origin",
|
|
8399
|
-
this.getAttribute("perspective-origin"),
|
|
8400
|
-
);
|
|
8564
|
+
figSyncCssVar(this, "--aspect-ratio", this.getAttribute("aspect-ratio"));
|
|
8565
|
+
figSyncCssVar(this, "--perspective", this.getAttribute("perspective"));
|
|
8566
|
+
figSyncCssVar(this, "--perspective-origin", this.getAttribute("perspective-origin"));
|
|
8401
8567
|
this.#syncTransformOrigin(this.getAttribute("transform-origin"));
|
|
8402
8568
|
this.#parseFields(this.getAttribute("fields"));
|
|
8403
8569
|
const val = this.getAttribute("value");
|
|
@@ -8415,29 +8581,7 @@ class Fig3DRotate extends HTMLElement {
|
|
|
8415
8581
|
}
|
|
8416
8582
|
}
|
|
8417
8583
|
|
|
8418
|
-
|
|
8419
|
-
if (value && value.trim()) {
|
|
8420
|
-
this.style.setProperty("--aspect-ratio", value.trim());
|
|
8421
|
-
} else {
|
|
8422
|
-
this.style.removeProperty("--aspect-ratio");
|
|
8423
|
-
}
|
|
8424
|
-
}
|
|
8425
|
-
|
|
8426
|
-
#syncPerspectiveVar(value) {
|
|
8427
|
-
if (value && value.trim()) {
|
|
8428
|
-
this.style.setProperty("--perspective", value.trim());
|
|
8429
|
-
} else {
|
|
8430
|
-
this.style.removeProperty("--perspective");
|
|
8431
|
-
}
|
|
8432
|
-
}
|
|
8433
|
-
|
|
8434
|
-
#syncCSSVar(prop, value) {
|
|
8435
|
-
if (value && value.trim()) {
|
|
8436
|
-
this.style.setProperty(prop, value.trim());
|
|
8437
|
-
} else {
|
|
8438
|
-
this.style.removeProperty(prop);
|
|
8439
|
-
}
|
|
8440
|
-
}
|
|
8584
|
+
|
|
8441
8585
|
|
|
8442
8586
|
#syncTransformOrigin(value) {
|
|
8443
8587
|
if (!value || !value.trim()) {
|
|
@@ -8486,15 +8630,15 @@ class Fig3DRotate extends HTMLElement {
|
|
|
8486
8630
|
|
|
8487
8631
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
8488
8632
|
if (name === "aspect-ratio") {
|
|
8489
|
-
this
|
|
8633
|
+
figSyncCssVar(this, "--aspect-ratio", newValue);
|
|
8490
8634
|
return;
|
|
8491
8635
|
}
|
|
8492
8636
|
if (name === "perspective") {
|
|
8493
|
-
this
|
|
8637
|
+
figSyncCssVar(this, "--perspective", newValue);
|
|
8494
8638
|
return;
|
|
8495
8639
|
}
|
|
8496
8640
|
if (name === "perspective-origin") {
|
|
8497
|
-
this
|
|
8641
|
+
figSyncCssVar(this, "--perspective-origin", newValue);
|
|
8498
8642
|
return;
|
|
8499
8643
|
}
|
|
8500
8644
|
if (name === "transform-origin") {
|
|
@@ -8744,7 +8888,7 @@ class FigOriginGrid extends HTMLElement {
|
|
|
8744
8888
|
|
|
8745
8889
|
connectedCallback() {
|
|
8746
8890
|
this.#precision = parseInt(this.getAttribute("precision") || "0");
|
|
8747
|
-
|
|
8891
|
+
figSyncCssVar(this, "--aspect-ratio", this.getAttribute("aspect-ratio"));
|
|
8748
8892
|
this.#applyIncomingValue(this.getAttribute("value"));
|
|
8749
8893
|
|
|
8750
8894
|
this.#render();
|
|
@@ -8768,7 +8912,7 @@ class FigOriginGrid extends HTMLElement {
|
|
|
8768
8912
|
|
|
8769
8913
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
8770
8914
|
if (name === "aspect-ratio") {
|
|
8771
|
-
this
|
|
8915
|
+
figSyncCssVar(this, "--aspect-ratio", newValue);
|
|
8772
8916
|
return;
|
|
8773
8917
|
}
|
|
8774
8918
|
if (name === "drag") {
|
|
@@ -8807,14 +8951,6 @@ class FigOriginGrid extends HTMLElement {
|
|
|
8807
8951
|
return attr.toLowerCase() !== "false";
|
|
8808
8952
|
}
|
|
8809
8953
|
|
|
8810
|
-
#syncAspectRatioVar(value) {
|
|
8811
|
-
if (value && value.trim()) {
|
|
8812
|
-
this.style.setProperty("--aspect-ratio", value.trim());
|
|
8813
|
-
} else {
|
|
8814
|
-
this.style.removeProperty("--aspect-ratio");
|
|
8815
|
-
}
|
|
8816
|
-
}
|
|
8817
|
-
|
|
8818
8954
|
#syncDragState() {
|
|
8819
8955
|
if (!this.#grid) return;
|
|
8820
8956
|
this.#grid.classList.toggle("drag-disabled", !this.#dragEnabled);
|
|
@@ -9198,6 +9334,7 @@ class FigInputJoystick extends HTMLElement {
|
|
|
9198
9334
|
#boundYFocusOut = null;
|
|
9199
9335
|
#isSyncingValueAttr = false;
|
|
9200
9336
|
#defaultPosition = { x: 0.5, y: 0.5 };
|
|
9337
|
+
#initialized = false;
|
|
9201
9338
|
|
|
9202
9339
|
constructor() {
|
|
9203
9340
|
super();
|
|
@@ -9209,7 +9346,6 @@ class FigInputJoystick extends HTMLElement {
|
|
|
9209
9346
|
this.xInput = null;
|
|
9210
9347
|
this.yInput = null;
|
|
9211
9348
|
this.coordinates = "screen";
|
|
9212
|
-
this.#initialized = false;
|
|
9213
9349
|
this.#boundPlanePointerDown = (e) => this.#handlePlanePointerDown(e);
|
|
9214
9350
|
this.#boundHandlePointerDown = () => {
|
|
9215
9351
|
this.isDragging = true;
|
|
@@ -9223,8 +9359,6 @@ class FigInputJoystick extends HTMLElement {
|
|
|
9223
9359
|
this.#boundYFocusOut = () => this.#handleFieldFocusOut();
|
|
9224
9360
|
}
|
|
9225
9361
|
|
|
9226
|
-
#initialized = false;
|
|
9227
|
-
|
|
9228
9362
|
connectedCallback() {
|
|
9229
9363
|
// Initialize position
|
|
9230
9364
|
requestAnimationFrame(() => {
|
|
@@ -9233,7 +9367,7 @@ class FigInputJoystick extends HTMLElement {
|
|
|
9233
9367
|
this.transform = this.getAttribute("transform") || 1;
|
|
9234
9368
|
this.transform = Number(this.transform);
|
|
9235
9369
|
this.coordinates = this.getAttribute("coordinates") || "screen";
|
|
9236
|
-
|
|
9370
|
+
figSyncCssVar(this, "--aspect-ratio", this.getAttribute("aspect-ratio"));
|
|
9237
9371
|
if (!this.hasAttribute("value")) {
|
|
9238
9372
|
this.setAttribute("value", "50% 50%");
|
|
9239
9373
|
}
|
|
@@ -9252,14 +9386,6 @@ class FigInputJoystick extends HTMLElement {
|
|
|
9252
9386
|
return this.coordinates === "math" ? 1 - y : y;
|
|
9253
9387
|
}
|
|
9254
9388
|
|
|
9255
|
-
#syncAspectRatioVar(value) {
|
|
9256
|
-
if (value && value.trim()) {
|
|
9257
|
-
this.style.setProperty("--aspect-ratio", value.trim());
|
|
9258
|
-
} else {
|
|
9259
|
-
this.style.removeProperty("--aspect-ratio");
|
|
9260
|
-
}
|
|
9261
|
-
}
|
|
9262
|
-
|
|
9263
9389
|
disconnectedCallback() {
|
|
9264
9390
|
this.#cleanupListeners();
|
|
9265
9391
|
}
|
|
@@ -9561,7 +9687,7 @@ class FigInputJoystick extends HTMLElement {
|
|
|
9561
9687
|
}
|
|
9562
9688
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
9563
9689
|
if (name === "aspect-ratio") {
|
|
9564
|
-
this
|
|
9690
|
+
figSyncCssVar(this, "--aspect-ratio", newValue);
|
|
9565
9691
|
return;
|
|
9566
9692
|
}
|
|
9567
9693
|
if (name === "value") {
|
|
@@ -9611,6 +9737,11 @@ class FigInputAngle extends HTMLElement {
|
|
|
9611
9737
|
#opposite;
|
|
9612
9738
|
#prevRawAngle = null;
|
|
9613
9739
|
#boundHandleRawChange;
|
|
9740
|
+
#boundHandleMouseDown;
|
|
9741
|
+
#boundHandleTouchStart;
|
|
9742
|
+
#boundHandleKeyDown;
|
|
9743
|
+
#boundHandleKeyUp;
|
|
9744
|
+
#boundHandleAngleInput;
|
|
9614
9745
|
|
|
9615
9746
|
constructor() {
|
|
9616
9747
|
super();
|
|
@@ -9631,6 +9762,11 @@ class FigInputAngle extends HTMLElement {
|
|
|
9631
9762
|
this.rotationSpan = null;
|
|
9632
9763
|
|
|
9633
9764
|
this.#boundHandleRawChange = this.#handleRawChange.bind(this);
|
|
9765
|
+
this.#boundHandleMouseDown = this.#handleMouseDown.bind(this);
|
|
9766
|
+
this.#boundHandleTouchStart = this.#handleTouchStart.bind(this);
|
|
9767
|
+
this.#boundHandleKeyDown = this.#handleKeyDown.bind(this);
|
|
9768
|
+
this.#boundHandleKeyUp = this.#handleKeyUp.bind(this);
|
|
9769
|
+
this.#boundHandleAngleInput = this.#handleAngleInput.bind(this);
|
|
9634
9770
|
}
|
|
9635
9771
|
|
|
9636
9772
|
connectedCallback() {
|
|
@@ -9805,30 +9941,23 @@ class FigInputAngle extends HTMLElement {
|
|
|
9805
9941
|
this.angleInput = this.querySelector("fig-input-number[name='angle']");
|
|
9806
9942
|
this.rotationSpan = this.querySelector(".fig-input-angle-rotations");
|
|
9807
9943
|
this.#updateRotationDisplay();
|
|
9808
|
-
this.plane?.addEventListener("mousedown", this.#
|
|
9809
|
-
this.plane?.addEventListener(
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
);
|
|
9813
|
-
window.addEventListener("keydown", this.#handleKeyDown.bind(this));
|
|
9814
|
-
window.addEventListener("keyup", this.#handleKeyUp.bind(this));
|
|
9944
|
+
this.plane?.addEventListener("mousedown", this.#boundHandleMouseDown);
|
|
9945
|
+
this.plane?.addEventListener("touchstart", this.#boundHandleTouchStart);
|
|
9946
|
+
window.addEventListener("keydown", this.#boundHandleKeyDown);
|
|
9947
|
+
window.addEventListener("keyup", this.#boundHandleKeyUp);
|
|
9815
9948
|
if (this.text && this.angleInput) {
|
|
9816
|
-
this.angleInput.addEventListener(
|
|
9817
|
-
"input",
|
|
9818
|
-
this.#handleAngleInput.bind(this),
|
|
9819
|
-
);
|
|
9949
|
+
this.angleInput.addEventListener("input", this.#boundHandleAngleInput);
|
|
9820
9950
|
}
|
|
9821
|
-
// Capture-phase listener for unit suffix parsing
|
|
9822
9951
|
this.addEventListener("change", this.#boundHandleRawChange, true);
|
|
9823
9952
|
}
|
|
9824
9953
|
|
|
9825
9954
|
#cleanupListeners() {
|
|
9826
|
-
this.plane?.removeEventListener("mousedown", this.#
|
|
9827
|
-
this.plane?.removeEventListener("touchstart", this.#
|
|
9828
|
-
window.removeEventListener("keydown", this.#
|
|
9829
|
-
window.removeEventListener("keyup", this.#
|
|
9955
|
+
this.plane?.removeEventListener("mousedown", this.#boundHandleMouseDown);
|
|
9956
|
+
this.plane?.removeEventListener("touchstart", this.#boundHandleTouchStart);
|
|
9957
|
+
window.removeEventListener("keydown", this.#boundHandleKeyDown);
|
|
9958
|
+
window.removeEventListener("keyup", this.#boundHandleKeyUp);
|
|
9830
9959
|
if (this.text && this.angleInput) {
|
|
9831
|
-
this.angleInput.removeEventListener("input", this.#
|
|
9960
|
+
this.angleInput.removeEventListener("input", this.#boundHandleAngleInput);
|
|
9832
9961
|
}
|
|
9833
9962
|
this.removeEventListener("change", this.#boundHandleRawChange, true);
|
|
9834
9963
|
}
|
|
@@ -10333,6 +10462,8 @@ class FigFillPicker extends HTMLElement {
|
|
|
10333
10462
|
#opacitySlider = null;
|
|
10334
10463
|
#isDraggingColor = false;
|
|
10335
10464
|
#teardownColorAreaEvents = null;
|
|
10465
|
+
#dialogOpenObserver = null;
|
|
10466
|
+
#webcamTabObserver = null;
|
|
10336
10467
|
|
|
10337
10468
|
constructor() {
|
|
10338
10469
|
super();
|
|
@@ -10358,10 +10489,26 @@ class FigFillPicker extends HTMLElement {
|
|
|
10358
10489
|
this.#teardownColorAreaEvents();
|
|
10359
10490
|
this.#teardownColorAreaEvents = null;
|
|
10360
10491
|
}
|
|
10492
|
+
if (this.#dialogOpenObserver) {
|
|
10493
|
+
this.#dialogOpenObserver.disconnect();
|
|
10494
|
+
this.#dialogOpenObserver = null;
|
|
10495
|
+
}
|
|
10496
|
+
if (this.#webcamTabObserver) {
|
|
10497
|
+
this.#webcamTabObserver.disconnect();
|
|
10498
|
+
this.#webcamTabObserver = null;
|
|
10499
|
+
}
|
|
10500
|
+
if (this.#webcam.stream) {
|
|
10501
|
+
this.#webcam.stream.getTracks().forEach((track) => track.stop());
|
|
10502
|
+
this.#webcam.stream = null;
|
|
10503
|
+
}
|
|
10504
|
+
if (this.#video.url && this.#video.url.startsWith("blob:")) {
|
|
10505
|
+
URL.revokeObjectURL(this.#video.url);
|
|
10506
|
+
}
|
|
10361
10507
|
if (this.#chit) this.#chit.removeAttribute("selected");
|
|
10362
10508
|
if (this.#dialog) {
|
|
10363
10509
|
this.#dialog.close();
|
|
10364
10510
|
this.#dialog.remove();
|
|
10511
|
+
this.#dialog = null;
|
|
10365
10512
|
}
|
|
10366
10513
|
}
|
|
10367
10514
|
|
|
@@ -10698,11 +10845,11 @@ class FigFillPicker extends HTMLElement {
|
|
|
10698
10845
|
};
|
|
10699
10846
|
this.#dialog.addEventListener("close", onDialogClose);
|
|
10700
10847
|
|
|
10701
|
-
|
|
10848
|
+
this.#dialogOpenObserver = new MutationObserver(() => {
|
|
10702
10849
|
const isOpen = this.#dialog.hasAttribute("open") && this.#dialog.getAttribute("open") !== "false";
|
|
10703
10850
|
if (!isOpen) onDialogClose();
|
|
10704
10851
|
});
|
|
10705
|
-
|
|
10852
|
+
this.#dialogOpenObserver.observe(this.#dialog, { attributes: true, attributeFilter: ["open"] });
|
|
10706
10853
|
|
|
10707
10854
|
// Initialize built-in tabs (skip any overridden by custom slots)
|
|
10708
10855
|
const builtinInits = {
|
|
@@ -11624,10 +11771,15 @@ class FigFillPicker extends HTMLElement {
|
|
|
11624
11771
|
}
|
|
11625
11772
|
}
|
|
11626
11773
|
|
|
11774
|
+
static #gradientSupportCache = new Map();
|
|
11627
11775
|
#testGradientSupport(css) {
|
|
11776
|
+
const cached = FigFillPicker.#gradientSupportCache.get(css);
|
|
11777
|
+
if (cached !== undefined) return cached;
|
|
11628
11778
|
const el = document.createElement("div");
|
|
11629
11779
|
el.style.background = css;
|
|
11630
|
-
|
|
11780
|
+
const result = !!el.style.background;
|
|
11781
|
+
FigFillPicker.#gradientSupportCache.set(css, result);
|
|
11782
|
+
return result;
|
|
11631
11783
|
}
|
|
11632
11784
|
|
|
11633
11785
|
#getGradientCSS() {
|
|
@@ -11972,13 +12124,12 @@ class FigFillPicker extends HTMLElement {
|
|
|
11972
12124
|
}
|
|
11973
12125
|
};
|
|
11974
12126
|
|
|
11975
|
-
|
|
11976
|
-
const observer = new MutationObserver(() => {
|
|
12127
|
+
this.#webcamTabObserver = new MutationObserver(() => {
|
|
11977
12128
|
if (container.style.display !== "none" && !this.#webcam.stream) {
|
|
11978
12129
|
startWebcam();
|
|
11979
12130
|
}
|
|
11980
12131
|
});
|
|
11981
|
-
|
|
12132
|
+
this.#webcamTabObserver.observe(container, {
|
|
11982
12133
|
attributes: true,
|
|
11983
12134
|
attributeFilter: ["style"],
|
|
11984
12135
|
});
|
|
@@ -12497,8 +12648,8 @@ class FigColorTip extends HTMLElement {
|
|
|
12497
12648
|
}
|
|
12498
12649
|
|
|
12499
12650
|
try {
|
|
12500
|
-
const ctx =
|
|
12501
|
-
|
|
12651
|
+
const { ctx } = figGetSharedCanvas(1, 1);
|
|
12652
|
+
ctx.fillStyle = "#000000";
|
|
12502
12653
|
ctx.fillStyle = value;
|
|
12503
12654
|
const resolved = ctx.fillStyle;
|
|
12504
12655
|
if (resolved.startsWith("#")) {
|
|
@@ -12703,7 +12854,7 @@ class FigChooser extends HTMLElement {
|
|
|
12703
12854
|
}
|
|
12704
12855
|
|
|
12705
12856
|
static get observedAttributes() {
|
|
12706
|
-
return ["value", "disabled", "choice-element", "drag", "overflow", "loop"];
|
|
12857
|
+
return ["value", "disabled", "choice-element", "drag", "overflow", "loop", "padding"];
|
|
12707
12858
|
}
|
|
12708
12859
|
|
|
12709
12860
|
get #overflowMode() {
|
|
@@ -13339,8 +13490,8 @@ class FigHandle extends HTMLElement {
|
|
|
13339
13490
|
};
|
|
13340
13491
|
|
|
13341
13492
|
const axes = this.#axes;
|
|
13342
|
-
if (axes.x) this.style.left = `${resolve(xToken, rect.width, hw)}px`;
|
|
13343
|
-
if (axes.y) this.style.top = `${resolve(yToken, rect.height, hh)}px`;
|
|
13493
|
+
if (axes.x) this.style.left = `${Math.round(resolve(xToken, rect.width, hw))}px`;
|
|
13494
|
+
if (axes.y) this.style.top = `${Math.round(resolve(yToken, rect.height, hh))}px`;
|
|
13344
13495
|
}
|
|
13345
13496
|
|
|
13346
13497
|
#syncValueAttribute() {
|
|
@@ -13370,7 +13521,7 @@ class FigHandle extends HTMLElement {
|
|
|
13370
13521
|
select() {
|
|
13371
13522
|
if (this.hasAttribute("disabled")) return;
|
|
13372
13523
|
this.setAttribute("selected", "");
|
|
13373
|
-
if (this.getAttribute("type") === "color") this.#showColorTip();
|
|
13524
|
+
if (this.getAttribute("type") === "color" && !this.#isDragging) this.#showColorTip();
|
|
13374
13525
|
}
|
|
13375
13526
|
|
|
13376
13527
|
deselect() {
|
|
@@ -13410,6 +13561,9 @@ class FigHandle extends HTMLElement {
|
|
|
13410
13561
|
} else {
|
|
13411
13562
|
this.style.setProperty("--fill", value);
|
|
13412
13563
|
}
|
|
13564
|
+
if (this.#colorTip && value) {
|
|
13565
|
+
this.#colorTip.setAttribute("value", value);
|
|
13566
|
+
}
|
|
13413
13567
|
}
|
|
13414
13568
|
if (name === "drag") this.#syncDrag();
|
|
13415
13569
|
if (name === "value" && !this.#applyingValue && !this.#isDragging) {
|
|
@@ -13450,12 +13604,13 @@ class FigHandle extends HTMLElement {
|
|
|
13450
13604
|
|
|
13451
13605
|
this.#isDragging = true;
|
|
13452
13606
|
const axes = this.#axes;
|
|
13453
|
-
const containerRect = container.getBoundingClientRect();
|
|
13454
13607
|
const handleW = this.offsetWidth;
|
|
13455
13608
|
const handleH = this.offsetHeight;
|
|
13609
|
+
let lastRect = null;
|
|
13456
13610
|
|
|
13457
13611
|
const clampAndApply = (clientX, clientY, shiftKey = false) => {
|
|
13458
13612
|
const rect = container.getBoundingClientRect();
|
|
13613
|
+
lastRect = rect;
|
|
13459
13614
|
const currentLeft = parseFloat(this.style.left) || 0;
|
|
13460
13615
|
const currentTop = parseFloat(this.style.top) || 0;
|
|
13461
13616
|
const rawX = clientX - rect.left - handleW / 2;
|
|
@@ -13491,11 +13646,11 @@ class FigHandle extends HTMLElement {
|
|
|
13491
13646
|
|
|
13492
13647
|
if (axes.x) {
|
|
13493
13648
|
const left = centerX * rect.width - handleW / 2;
|
|
13494
|
-
this.style.left = `${Math.max(-handleW / 2, Math.min(rect.width - handleW / 2, left))}px`;
|
|
13649
|
+
this.style.left = `${Math.round(Math.max(-handleW / 2, Math.min(rect.width - handleW / 2, left)))}px`;
|
|
13495
13650
|
}
|
|
13496
13651
|
if (axes.y) {
|
|
13497
13652
|
const top = centerY * rect.height - handleH / 2;
|
|
13498
|
-
this.style.top = `${Math.max(-handleH / 2, Math.min(rect.height - handleH / 2, top))}px`;
|
|
13653
|
+
this.style.top = `${Math.round(Math.max(-handleH / 2, Math.min(rect.height - handleH / 2, top)))}px`;
|
|
13499
13654
|
}
|
|
13500
13655
|
};
|
|
13501
13656
|
|
|
@@ -13512,7 +13667,7 @@ class FigHandle extends HTMLElement {
|
|
|
13512
13667
|
new CustomEvent("input", {
|
|
13513
13668
|
bubbles: true,
|
|
13514
13669
|
detail: {
|
|
13515
|
-
...this.#positionDetail(
|
|
13670
|
+
...this.#positionDetail(lastRect),
|
|
13516
13671
|
shiftKey: e.shiftKey,
|
|
13517
13672
|
},
|
|
13518
13673
|
}),
|
|
@@ -13531,7 +13686,7 @@ class FigHandle extends HTMLElement {
|
|
|
13531
13686
|
this.dispatchEvent(
|
|
13532
13687
|
new CustomEvent("change", {
|
|
13533
13688
|
bubbles: true,
|
|
13534
|
-
detail: this.#positionDetail(
|
|
13689
|
+
detail: this.#positionDetail(lastRect),
|
|
13535
13690
|
}),
|
|
13536
13691
|
);
|
|
13537
13692
|
const swallowClick = (evt) => {
|