@rogieking/figui3 4.2.0 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components.css +35 -2
- package/fig.js +368 -14
- package/package.json +1 -1
package/components.css
CHANGED
|
@@ -1045,11 +1045,18 @@ fig-tab,
|
|
|
1045
1045
|
&:hover {
|
|
1046
1046
|
background-color: var(--figma-color-bg-secondary);
|
|
1047
1047
|
}
|
|
1048
|
+
|
|
1049
|
+
&[disabled]:not([disabled="false"]) {
|
|
1050
|
+
opacity: 0.4;
|
|
1051
|
+
pointer-events: none;
|
|
1052
|
+
cursor: default;
|
|
1053
|
+
}
|
|
1048
1054
|
}
|
|
1049
1055
|
|
|
1050
1056
|
fig-tabs,
|
|
1051
1057
|
.tabs {
|
|
1052
1058
|
display: flex;
|
|
1059
|
+
width: 100%;
|
|
1053
1060
|
gap: var(--spacer-1);
|
|
1054
1061
|
padding: var(--spacer-1) var(--spacer-2);
|
|
1055
1062
|
}
|
|
@@ -1057,6 +1064,7 @@ fig-tabs,
|
|
|
1057
1064
|
fig-tab-content,
|
|
1058
1065
|
.fig-tab-content {
|
|
1059
1066
|
display: none;
|
|
1067
|
+
width: 100%;
|
|
1060
1068
|
}
|
|
1061
1069
|
|
|
1062
1070
|
/* Avatar */
|
|
@@ -3415,7 +3423,7 @@ fig-input-palette {
|
|
|
3415
3423
|
}
|
|
3416
3424
|
&[open]:not([open="false"]):not([edit="false"]) {
|
|
3417
3425
|
.palette-colors-expanded {
|
|
3418
|
-
display:
|
|
3426
|
+
display: grid;
|
|
3419
3427
|
}
|
|
3420
3428
|
}
|
|
3421
3429
|
&[add="false"] {
|
|
@@ -3426,7 +3434,7 @@ fig-input-palette {
|
|
|
3426
3434
|
}
|
|
3427
3435
|
.palette-colors-expanded {
|
|
3428
3436
|
display: none;
|
|
3429
|
-
|
|
3437
|
+
grid-template-columns: [input] 1fr [button] 1.5rem;
|
|
3430
3438
|
overflow: visible;
|
|
3431
3439
|
border-radius: 0;
|
|
3432
3440
|
gap: var(--spacer-2);
|
|
@@ -3434,6 +3442,16 @@ fig-input-palette {
|
|
|
3434
3442
|
|
|
3435
3443
|
> fig-input-color {
|
|
3436
3444
|
min-width: 0;
|
|
3445
|
+
grid-column: input / -1;
|
|
3446
|
+
|
|
3447
|
+
&:has(+ fig-button) {
|
|
3448
|
+
grid-column: input;
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
|
|
3452
|
+
> fig-button,
|
|
3453
|
+
> button {
|
|
3454
|
+
grid-column: button;
|
|
3437
3455
|
}
|
|
3438
3456
|
|
|
3439
3457
|
fig-chit {
|
|
@@ -3678,6 +3696,21 @@ fig-segmented-control {
|
|
|
3678
3696
|
}
|
|
3679
3697
|
}
|
|
3680
3698
|
|
|
3699
|
+
/* Options */
|
|
3700
|
+
fig-options {
|
|
3701
|
+
display: flex;
|
|
3702
|
+
width: 100%;
|
|
3703
|
+
|
|
3704
|
+
& > fig-segmented-control {
|
|
3705
|
+
flex: 1;
|
|
3706
|
+
min-width: 0;
|
|
3707
|
+
}
|
|
3708
|
+
|
|
3709
|
+
& > fig-dropdown {
|
|
3710
|
+
flex: 1;
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3681
3714
|
fig-joystick {
|
|
3682
3715
|
--size: 100%;
|
|
3683
3716
|
--aspect-ratio: 1 / 1;
|
package/fig.js
CHANGED
|
@@ -517,6 +517,8 @@ class FigTooltip extends HTMLElement {
|
|
|
517
517
|
#boundHandleTouchMove;
|
|
518
518
|
#boundHandleTouchEnd;
|
|
519
519
|
#boundHandleTouchCancel;
|
|
520
|
+
#boundHandleDialogClose;
|
|
521
|
+
#parentDialog = null;
|
|
520
522
|
#touchTimeout;
|
|
521
523
|
#isTouching = false;
|
|
522
524
|
#observer = null;
|
|
@@ -535,13 +537,23 @@ class FigTooltip extends HTMLElement {
|
|
|
535
537
|
this.#boundHandleTouchMove = this.#handleTouchMove.bind(this);
|
|
536
538
|
this.#boundHandleTouchEnd = this.#handleTouchEnd.bind(this);
|
|
537
539
|
this.#boundHandleTouchCancel = this.#handleTouchCancel.bind(this);
|
|
540
|
+
this.#boundHandleDialogClose = () => {
|
|
541
|
+
clearTimeout(this.timeout);
|
|
542
|
+
this.destroy();
|
|
543
|
+
this.isOpen = false;
|
|
544
|
+
};
|
|
538
545
|
}
|
|
539
546
|
connectedCallback() {
|
|
540
547
|
this.setup();
|
|
541
548
|
this.setupEventListeners();
|
|
549
|
+
this.#parentDialog = this.closest("dialog");
|
|
550
|
+
if (this.#parentDialog) {
|
|
551
|
+
this.#parentDialog.addEventListener("close", this.#boundHandleDialogClose);
|
|
552
|
+
}
|
|
542
553
|
}
|
|
543
554
|
|
|
544
555
|
disconnectedCallback() {
|
|
556
|
+
clearTimeout(this.timeout);
|
|
545
557
|
this.destroy();
|
|
546
558
|
document.removeEventListener(
|
|
547
559
|
"mousedown",
|
|
@@ -549,6 +561,10 @@ class FigTooltip extends HTMLElement {
|
|
|
549
561
|
true,
|
|
550
562
|
);
|
|
551
563
|
this.#stopObserving();
|
|
564
|
+
if (this.#parentDialog) {
|
|
565
|
+
this.#parentDialog.removeEventListener("close", this.#boundHandleDialogClose);
|
|
566
|
+
this.#parentDialog = null;
|
|
567
|
+
}
|
|
552
568
|
|
|
553
569
|
if (this.action === "click") {
|
|
554
570
|
document.body.removeEventListener(
|
|
@@ -697,6 +713,7 @@ class FigTooltip extends HTMLElement {
|
|
|
697
713
|
}
|
|
698
714
|
|
|
699
715
|
showPopup() {
|
|
716
|
+
if (this.#parentDialog && !this.#parentDialog.open) return;
|
|
700
717
|
if (!this.popup) this.render();
|
|
701
718
|
this.popup.style.display = "block";
|
|
702
719
|
this.popup.style.visibility = "hidden";
|
|
@@ -1112,6 +1129,7 @@ customElements.define("fig-truncate", FigTruncate);
|
|
|
1112
1129
|
* @attr {string} position - Position of the dialog (e.g., "bottom right", "top left", "center center")
|
|
1113
1130
|
* @attr {string} title - Title text for the auto-generated header. If no fig-header[dialog-header] exists, one is prepended with this title and a close button.
|
|
1114
1131
|
* @attr {boolean} resizable - Whether the dialog can be manually resized by the user (default: false)
|
|
1132
|
+
* @attr {string} closedby - Controls how the dialog can be dismissed: "any" (default, Escape + light dismiss), "closerequest" (Escape only), "none" (programmatic only)
|
|
1115
1133
|
*/
|
|
1116
1134
|
class FigDialog extends HTMLDialogElement {
|
|
1117
1135
|
#isDragging = false;
|
|
@@ -1397,7 +1415,7 @@ class FigDialog extends HTMLDialogElement {
|
|
|
1397
1415
|
}
|
|
1398
1416
|
|
|
1399
1417
|
static get observedAttributes() {
|
|
1400
|
-
return ["modal", "drag", "position", "handle", "title", "resizable"];
|
|
1418
|
+
return ["modal", "drag", "position", "handle", "title", "resizable", "closedby"];
|
|
1401
1419
|
}
|
|
1402
1420
|
|
|
1403
1421
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
@@ -1419,6 +1437,20 @@ class FigDialog extends HTMLDialogElement {
|
|
|
1419
1437
|
this.#applyPosition();
|
|
1420
1438
|
}
|
|
1421
1439
|
|
|
1440
|
+
if (name === "modal") {
|
|
1441
|
+
const wasModal = this.modal;
|
|
1442
|
+
this.modal = newValue !== null && newValue !== "false";
|
|
1443
|
+
if (this.open && wasModal !== this.modal) {
|
|
1444
|
+
this.close();
|
|
1445
|
+
if (this.modal) this.showModal();
|
|
1446
|
+
else this.show();
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
if (name === "closedby") {
|
|
1451
|
+
this.closedby = newValue || "any";
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1422
1454
|
if (name === "title") {
|
|
1423
1455
|
const autoHeader = this.querySelector("fig-header[data-auto] h3");
|
|
1424
1456
|
if (autoHeader) {
|
|
@@ -2505,6 +2537,7 @@ class FigTab extends HTMLElement {
|
|
|
2505
2537
|
this.removeEventListener("click", this.#boundHandleClick);
|
|
2506
2538
|
}
|
|
2507
2539
|
handleClick() {
|
|
2540
|
+
if (this.hasAttribute("disabled")) return;
|
|
2508
2541
|
this.selected = true;
|
|
2509
2542
|
if (this.content) {
|
|
2510
2543
|
this.content.style.display = "block";
|
|
@@ -2610,7 +2643,9 @@ class FigTabs extends HTMLElement {
|
|
|
2610
2643
|
if (newIndex !== currentIndex && tabs[newIndex]) {
|
|
2611
2644
|
tabs.forEach((tab) => tab.removeAttribute("selected"));
|
|
2612
2645
|
this.selectedTab = tabs[newIndex];
|
|
2613
|
-
|
|
2646
|
+
tabs[newIndex].setAttribute("selected", "true");
|
|
2647
|
+
const val = tabs[newIndex].getAttribute("value");
|
|
2648
|
+
if (val) this.setAttribute("value", val);
|
|
2614
2649
|
tabs[newIndex].focus();
|
|
2615
2650
|
}
|
|
2616
2651
|
}
|
|
@@ -2650,19 +2685,19 @@ class FigTabs extends HTMLElement {
|
|
|
2650
2685
|
|
|
2651
2686
|
handleClick(event) {
|
|
2652
2687
|
if (this.hasAttribute("disabled")) return;
|
|
2653
|
-
const target = event.target;
|
|
2654
|
-
if (target.
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
tab.removeAttribute("selected");
|
|
2663
|
-
}
|
|
2688
|
+
const target = event.target.closest("fig-tab");
|
|
2689
|
+
if (!target || !this.contains(target)) return;
|
|
2690
|
+
const tabs = this.querySelectorAll("fig-tab");
|
|
2691
|
+
for (const tab of tabs) {
|
|
2692
|
+
if (tab === target) {
|
|
2693
|
+
this.selectedTab = tab;
|
|
2694
|
+
tab.setAttribute("selected", "true");
|
|
2695
|
+
} else {
|
|
2696
|
+
tab.removeAttribute("selected");
|
|
2664
2697
|
}
|
|
2665
2698
|
}
|
|
2699
|
+
const val = target.getAttribute("value");
|
|
2700
|
+
if (val) this.setAttribute("value", val);
|
|
2666
2701
|
}
|
|
2667
2702
|
}
|
|
2668
2703
|
customElements.define("fig-tabs", FigTabs);
|
|
@@ -3105,6 +3140,277 @@ class FigSegmentedControl extends HTMLElement {
|
|
|
3105
3140
|
}
|
|
3106
3141
|
customElements.define("fig-segmented-control", FigSegmentedControl);
|
|
3107
3142
|
|
|
3143
|
+
/* Options */
|
|
3144
|
+
/**
|
|
3145
|
+
* A responsive option picker that renders as a segmented control by default,
|
|
3146
|
+
* automatically swapping to a dropdown when any label overflows.
|
|
3147
|
+
* @attr {string} options - Comma-separated list of option labels
|
|
3148
|
+
* @attr {string} value - Currently selected value
|
|
3149
|
+
* @attr {boolean} disabled - Disables the control
|
|
3150
|
+
* @attr {boolean} full - Full-width segmented control
|
|
3151
|
+
* @attr {string} sizing - Segment sizing mode: "equal" (default) or "auto"
|
|
3152
|
+
*/
|
|
3153
|
+
class FigOptions extends HTMLElement {
|
|
3154
|
+
static get observedAttributes() {
|
|
3155
|
+
return ["options", "value", "disabled", "full", "sizing"];
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
#currentMode = "segments"; // "segments" | "dropdown"
|
|
3159
|
+
#naturalWidth = 0;
|
|
3160
|
+
#resizeObserver = null;
|
|
3161
|
+
#parsedOptions = [];
|
|
3162
|
+
#childControl = null;
|
|
3163
|
+
#suppressEvents = false;
|
|
3164
|
+
|
|
3165
|
+
connectedCallback() {
|
|
3166
|
+
this.#parseOptions();
|
|
3167
|
+
this.#renderSegments();
|
|
3168
|
+
this.#startResizeObserver();
|
|
3169
|
+
requestAnimationFrame(() => {
|
|
3170
|
+
requestAnimationFrame(() => this.#checkOverflow());
|
|
3171
|
+
});
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
disconnectedCallback() {
|
|
3175
|
+
this.#resizeObserver?.disconnect();
|
|
3176
|
+
this.#resizeObserver = null;
|
|
3177
|
+
}
|
|
3178
|
+
|
|
3179
|
+
get value() {
|
|
3180
|
+
return this.getAttribute("value") || "";
|
|
3181
|
+
}
|
|
3182
|
+
|
|
3183
|
+
set value(val) {
|
|
3184
|
+
if (val === null || val === undefined) {
|
|
3185
|
+
this.removeAttribute("value");
|
|
3186
|
+
} else {
|
|
3187
|
+
this.setAttribute("value", String(val));
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
|
|
3191
|
+
get options() {
|
|
3192
|
+
return this.#parsedOptions.slice();
|
|
3193
|
+
}
|
|
3194
|
+
|
|
3195
|
+
set options(val) {
|
|
3196
|
+
if (Array.isArray(val)) {
|
|
3197
|
+
const hasComma = val.some((v) => String(v).includes(","));
|
|
3198
|
+
const str = hasComma ? JSON.stringify(val) : val.join(",");
|
|
3199
|
+
this.setAttribute("options", str);
|
|
3200
|
+
} else {
|
|
3201
|
+
this.setAttribute("options", String(val || ""));
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
3206
|
+
if (oldValue === newValue) return;
|
|
3207
|
+
|
|
3208
|
+
if (name === "options") {
|
|
3209
|
+
this.#parseOptions();
|
|
3210
|
+
this.#rebuildCurrentControl();
|
|
3211
|
+
return;
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
if (name === "value") {
|
|
3215
|
+
this.#syncValueToChild();
|
|
3216
|
+
return;
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
if (name === "disabled") {
|
|
3220
|
+
this.#syncAttrToChild("disabled");
|
|
3221
|
+
return;
|
|
3222
|
+
}
|
|
3223
|
+
|
|
3224
|
+
if (name === "full") {
|
|
3225
|
+
this.#syncAttrToChild("full");
|
|
3226
|
+
return;
|
|
3227
|
+
}
|
|
3228
|
+
|
|
3229
|
+
if (name === "sizing") {
|
|
3230
|
+
this.#syncAttrToChild("sizing");
|
|
3231
|
+
this.#rebuildCurrentControl();
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
|
|
3235
|
+
#parseOptions() {
|
|
3236
|
+
const raw = this.getAttribute("options") || "";
|
|
3237
|
+
if (raw.startsWith("[")) {
|
|
3238
|
+
try { this.#parsedOptions = JSON.parse(raw); return; } catch {}
|
|
3239
|
+
}
|
|
3240
|
+
const delimiter = raw.includes("\n") ? "\n" : ",";
|
|
3241
|
+
this.#parsedOptions = raw.split(delimiter).map((s) => s.trim()).filter(Boolean);
|
|
3242
|
+
}
|
|
3243
|
+
|
|
3244
|
+
#renderSegments() {
|
|
3245
|
+
this.innerHTML = "";
|
|
3246
|
+
if (this.#parsedOptions.length === 0) return;
|
|
3247
|
+
|
|
3248
|
+
const sc = document.createElement("fig-segmented-control");
|
|
3249
|
+
sc.setAttribute("sizing", this.getAttribute("sizing") || "equal");
|
|
3250
|
+
|
|
3251
|
+
if (this.hasAttribute("disabled")) sc.setAttribute("disabled", "");
|
|
3252
|
+
if (this.hasAttribute("full")) sc.setAttribute("full", "");
|
|
3253
|
+
|
|
3254
|
+
const currentValue = this.getAttribute("value");
|
|
3255
|
+
let hasSelection = false;
|
|
3256
|
+
|
|
3257
|
+
for (const opt of this.#parsedOptions) {
|
|
3258
|
+
const seg = document.createElement("fig-segment");
|
|
3259
|
+
seg.setAttribute("value", opt);
|
|
3260
|
+
seg.textContent = opt;
|
|
3261
|
+
if (currentValue === opt) {
|
|
3262
|
+
seg.setAttribute("selected", "true");
|
|
3263
|
+
hasSelection = true;
|
|
3264
|
+
}
|
|
3265
|
+
sc.appendChild(seg);
|
|
3266
|
+
}
|
|
3267
|
+
|
|
3268
|
+
if (currentValue) sc.setAttribute("value", currentValue);
|
|
3269
|
+
|
|
3270
|
+
sc.addEventListener("input", (e) => {
|
|
3271
|
+
if (this.#suppressEvents) return;
|
|
3272
|
+
this.#suppressEvents = true;
|
|
3273
|
+
this.setAttribute("value", e.detail);
|
|
3274
|
+
this.#suppressEvents = false;
|
|
3275
|
+
this.dispatchEvent(
|
|
3276
|
+
new CustomEvent("input", { detail: e.detail, bubbles: true }),
|
|
3277
|
+
);
|
|
3278
|
+
});
|
|
3279
|
+
sc.addEventListener("change", (e) => {
|
|
3280
|
+
if (this.#suppressEvents) return;
|
|
3281
|
+
this.dispatchEvent(
|
|
3282
|
+
new CustomEvent("change", { detail: e.detail, bubbles: true }),
|
|
3283
|
+
);
|
|
3284
|
+
});
|
|
3285
|
+
|
|
3286
|
+
this.appendChild(sc);
|
|
3287
|
+
this.#childControl = sc;
|
|
3288
|
+
this.#currentMode = "segments";
|
|
3289
|
+
}
|
|
3290
|
+
|
|
3291
|
+
#renderDropdown() {
|
|
3292
|
+
this.innerHTML = "";
|
|
3293
|
+
if (this.#parsedOptions.length === 0) return;
|
|
3294
|
+
|
|
3295
|
+
const dd = document.createElement("fig-dropdown");
|
|
3296
|
+
if (this.hasAttribute("disabled")) dd.setAttribute("disabled", "");
|
|
3297
|
+
|
|
3298
|
+
const currentValue = this.getAttribute("value");
|
|
3299
|
+
|
|
3300
|
+
for (const opt of this.#parsedOptions) {
|
|
3301
|
+
const option = document.createElement("option");
|
|
3302
|
+
option.value = opt;
|
|
3303
|
+
option.textContent = opt;
|
|
3304
|
+
if (currentValue === opt) option.selected = true;
|
|
3305
|
+
dd.appendChild(option);
|
|
3306
|
+
}
|
|
3307
|
+
|
|
3308
|
+
if (currentValue) dd.setAttribute("value", currentValue);
|
|
3309
|
+
|
|
3310
|
+
dd.addEventListener("input", (e) => {
|
|
3311
|
+
if (this.#suppressEvents) return;
|
|
3312
|
+
this.#suppressEvents = true;
|
|
3313
|
+
this.setAttribute("value", e.detail);
|
|
3314
|
+
this.#suppressEvents = false;
|
|
3315
|
+
this.dispatchEvent(
|
|
3316
|
+
new CustomEvent("input", { detail: e.detail, bubbles: true }),
|
|
3317
|
+
);
|
|
3318
|
+
});
|
|
3319
|
+
dd.addEventListener("change", (e) => {
|
|
3320
|
+
if (this.#suppressEvents) return;
|
|
3321
|
+
this.dispatchEvent(
|
|
3322
|
+
new CustomEvent("change", { detail: e.detail, bubbles: true }),
|
|
3323
|
+
);
|
|
3324
|
+
});
|
|
3325
|
+
|
|
3326
|
+
this.appendChild(dd);
|
|
3327
|
+
this.#childControl = dd;
|
|
3328
|
+
this.#currentMode = "dropdown";
|
|
3329
|
+
}
|
|
3330
|
+
|
|
3331
|
+
#rebuildCurrentControl() {
|
|
3332
|
+
if (this.#currentMode === "segments") {
|
|
3333
|
+
this.#renderSegments();
|
|
3334
|
+
requestAnimationFrame(() => {
|
|
3335
|
+
requestAnimationFrame(() => this.#checkOverflow());
|
|
3336
|
+
});
|
|
3337
|
+
} else {
|
|
3338
|
+
this.#renderDropdown();
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3342
|
+
#syncValueToChild() {
|
|
3343
|
+
if (!this.#childControl || this.#suppressEvents) return;
|
|
3344
|
+
const val = this.getAttribute("value") || "";
|
|
3345
|
+
this.#childControl.value = val;
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
#syncAttrToChild(attr) {
|
|
3349
|
+
if (!this.#childControl) return;
|
|
3350
|
+
if (this.hasAttribute(attr)) {
|
|
3351
|
+
this.#childControl.setAttribute(attr, this.getAttribute(attr) || "");
|
|
3352
|
+
} else {
|
|
3353
|
+
this.#childControl.removeAttribute(attr);
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
|
|
3357
|
+
#startResizeObserver() {
|
|
3358
|
+
this.#resizeObserver?.disconnect();
|
|
3359
|
+
this.#resizeObserver = new ResizeObserver(() => {
|
|
3360
|
+
this.#checkOverflow();
|
|
3361
|
+
});
|
|
3362
|
+
this.#resizeObserver.observe(this);
|
|
3363
|
+
}
|
|
3364
|
+
|
|
3365
|
+
#isSegmentTruncated(seg) {
|
|
3366
|
+
const range = document.createRange();
|
|
3367
|
+
range.selectNodeContents(seg);
|
|
3368
|
+
const textWidth = range.getBoundingClientRect().width;
|
|
3369
|
+
const segRect = seg.getBoundingClientRect();
|
|
3370
|
+
const segWidth = segRect.width;
|
|
3371
|
+
const cs = getComputedStyle(seg);
|
|
3372
|
+
const padL = parseFloat(cs.paddingLeft) || 0;
|
|
3373
|
+
const padR = parseFloat(cs.paddingRight) || 0;
|
|
3374
|
+
const contentWidth = segWidth - padL - padR;
|
|
3375
|
+
return textWidth > contentWidth + 0.5;
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
#anySegmentTruncated() {
|
|
3379
|
+
const segments = this.querySelectorAll("fig-segment");
|
|
3380
|
+
for (const seg of segments) {
|
|
3381
|
+
if (this.#isSegmentTruncated(seg)) return true;
|
|
3382
|
+
}
|
|
3383
|
+
return false;
|
|
3384
|
+
}
|
|
3385
|
+
|
|
3386
|
+
#checkOverflow() {
|
|
3387
|
+
if (this.#parsedOptions.length <= 1) return;
|
|
3388
|
+
|
|
3389
|
+
if (this.#currentMode === "segments") {
|
|
3390
|
+
const sc = this.#childControl;
|
|
3391
|
+
const containerOverflow = sc && sc.scrollWidth > sc.clientWidth + 1;
|
|
3392
|
+
if (containerOverflow || this.#anySegmentTruncated()) {
|
|
3393
|
+
this.#naturalWidth = this.clientWidth;
|
|
3394
|
+
this.#renderDropdown();
|
|
3395
|
+
}
|
|
3396
|
+
} else {
|
|
3397
|
+
if (this.#naturalWidth > 0 && this.clientWidth >= this.#naturalWidth) {
|
|
3398
|
+
this.#renderSegments();
|
|
3399
|
+
requestAnimationFrame(() => {
|
|
3400
|
+
requestAnimationFrame(() => {
|
|
3401
|
+
const sc = this.#childControl;
|
|
3402
|
+
const containerOverflow = sc && sc.scrollWidth > sc.clientWidth + 1;
|
|
3403
|
+
if (containerOverflow || this.#anySegmentTruncated()) {
|
|
3404
|
+
this.#renderDropdown();
|
|
3405
|
+
}
|
|
3406
|
+
});
|
|
3407
|
+
});
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3412
|
+
customElements.define("fig-options", FigOptions);
|
|
3413
|
+
|
|
3108
3414
|
/* Slider */
|
|
3109
3415
|
/**
|
|
3110
3416
|
* A custom slider input element.
|
|
@@ -6139,6 +6445,7 @@ class FigInputPalette extends HTMLElement {
|
|
|
6139
6445
|
expandedWrap.className = "palette-colors-expanded";
|
|
6140
6446
|
this.#colors.forEach((entry, i) => {
|
|
6141
6447
|
expandedWrap.appendChild(this.#createPicker(entry, i, disabled));
|
|
6448
|
+
expandedWrap.appendChild(this.#createRemoveButton(i, disabled));
|
|
6142
6449
|
});
|
|
6143
6450
|
this.appendChild(expandedWrap);
|
|
6144
6451
|
}
|
|
@@ -6203,6 +6510,31 @@ class FigInputPalette extends HTMLElement {
|
|
|
6203
6510
|
return ic;
|
|
6204
6511
|
}
|
|
6205
6512
|
|
|
6513
|
+
#createRemoveButton(index, disabled) {
|
|
6514
|
+
const btn = document.createElement("fig-button");
|
|
6515
|
+
btn.setAttribute("variant", "ghost");
|
|
6516
|
+
btn.setAttribute("icon", "true");
|
|
6517
|
+
btn.setAttribute("aria-label", "Remove color");
|
|
6518
|
+
btn.className = "palette-remove-btn";
|
|
6519
|
+
if (disabled || this.#colors.length <= this.#min) btn.setAttribute("disabled", "");
|
|
6520
|
+
btn.innerHTML = `<span class="fig-mask-icon" style="--icon: var(--icon-minus)"></span>`;
|
|
6521
|
+
btn.addEventListener("click", () => {
|
|
6522
|
+
if (this.hasAttribute("disabled") && this.getAttribute("disabled") !== "false") return;
|
|
6523
|
+
this.#removeColor(index);
|
|
6524
|
+
});
|
|
6525
|
+
return btn;
|
|
6526
|
+
}
|
|
6527
|
+
|
|
6528
|
+
#removeColor(index) {
|
|
6529
|
+
if (index < 0 || index >= this.#colors.length) return;
|
|
6530
|
+
if (this.#colors.length <= this.#min) return;
|
|
6531
|
+
this.#colors.splice(index, 1);
|
|
6532
|
+
this.#inlinePickers = [];
|
|
6533
|
+
this.#expandedPickers = [];
|
|
6534
|
+
this.#render();
|
|
6535
|
+
this.#emitChange();
|
|
6536
|
+
}
|
|
6537
|
+
|
|
6206
6538
|
#createAddButton(disabled, parent = this) {
|
|
6207
6539
|
const atMax = this.#colors.length >= this.#max;
|
|
6208
6540
|
const addBtn = document.createElement("fig-button");
|
|
@@ -6242,7 +6574,10 @@ class FigInputPalette extends HTMLElement {
|
|
|
6242
6574
|
|
|
6243
6575
|
const expandedIc = this.#createPicker(entry, index, disabled);
|
|
6244
6576
|
const expandedWrap = this.querySelector(".palette-colors-expanded");
|
|
6245
|
-
if (expandedWrap)
|
|
6577
|
+
if (expandedWrap) {
|
|
6578
|
+
expandedWrap.appendChild(expandedIc);
|
|
6579
|
+
expandedWrap.appendChild(this.#createRemoveButton(index, disabled));
|
|
6580
|
+
}
|
|
6246
6581
|
|
|
6247
6582
|
if (this.#colors.length >= this.#max) {
|
|
6248
6583
|
const addBtn = this.querySelector(".palette-add-btn");
|
|
@@ -10704,6 +11039,25 @@ customElements.define("fig-header", FigHeader);
|
|
|
10704
11039
|
class FigFooter extends HTMLElement {}
|
|
10705
11040
|
customElements.define("fig-footer", FigFooter);
|
|
10706
11041
|
|
|
11042
|
+
/* Presentational elements (CSS-only, no behavior) */
|
|
11043
|
+
class FigSpinner extends HTMLElement {}
|
|
11044
|
+
customElements.define("fig-spinner", FigSpinner);
|
|
11045
|
+
|
|
11046
|
+
class FigIcon extends HTMLElement {}
|
|
11047
|
+
customElements.define("fig-icon", FigIcon);
|
|
11048
|
+
|
|
11049
|
+
class FigContent extends HTMLElement {}
|
|
11050
|
+
customElements.define("fig-content", FigContent);
|
|
11051
|
+
|
|
11052
|
+
class FigTabContent extends HTMLElement {}
|
|
11053
|
+
customElements.define("fig-tab-content", FigTabContent);
|
|
11054
|
+
|
|
11055
|
+
class FigButtonCombo extends HTMLElement {}
|
|
11056
|
+
customElements.define("fig-button-combo", FigButtonCombo);
|
|
11057
|
+
|
|
11058
|
+
class FigInputCombo extends HTMLElement {}
|
|
11059
|
+
customElements.define("fig-input-combo", FigInputCombo);
|
|
11060
|
+
|
|
10707
11061
|
// FigFillPicker
|
|
10708
11062
|
/**
|
|
10709
11063
|
* A comprehensive fill picker component supporting solid colors, gradients, images, video, and webcam.
|
package/package.json
CHANGED