@rogieking/figui3 8.1.0 → 8.2.1

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/fig-lab.css CHANGED
@@ -92,6 +92,7 @@ fig-attachment {
92
92
  display: block;
93
93
  flex: 0 0 var(--fig-attachment-size);
94
94
  width: var(--fig-attachment-size);
95
+ height: var(--fig-attachment-size);
95
96
  min-width: 0;
96
97
 
97
98
  fig-image {
@@ -315,6 +316,28 @@ fig-content:has(> propskit-group[name]:last-child) {
315
316
  padding-bottom: 0;
316
317
  }
317
318
 
319
+ /* Disabled PropsKit text and number inputs should render without input chrome. */
320
+ :is(
321
+ propskit-switch,
322
+ propskit-color,
323
+ propskit-gradient,
324
+ propskit-select,
325
+ propskit-text,
326
+ propskit-number,
327
+ propskit-position,
328
+ propskit-color-point,
329
+ propskit-point-radius,
330
+ propskit-point-radius-angle,
331
+ propskit-point-point,
332
+ propskit-group,
333
+ propskit-slider,
334
+ propskit-oscillator
335
+ ) :is(fig-input-text, fig-input-number)[disabled]:not([disabled="false"]) {
336
+ border: 0;
337
+ background: transparent;
338
+ box-shadow: none;
339
+ }
340
+
318
341
  /* Large size: more left field padding; nudge trailing controls in from
319
342
  the right. propskit-select uses shared label padding instead. */
320
343
  :is(
@@ -1387,10 +1410,6 @@ propskit-position {
1387
1410
  .propskit-position-row > label {
1388
1411
  color: var(--figma-color-text-disabled);
1389
1412
  }
1390
-
1391
- .propskit-position-row > [data-propskit-position-axis] {
1392
- opacity: 0.5;
1393
- }
1394
1413
  }
1395
1414
 
1396
1415
  .propskit-position-row {
package/fig-lab.js CHANGED
@@ -18,6 +18,13 @@ function figLabBooleanAttribute(element, name) {
18
18
  return element.hasAttribute(name) && element.getAttribute(name) !== "false";
19
19
  }
20
20
 
21
+ function figLabSyncDisabledControls(host, controls) {
22
+ const disabled = figLabBooleanAttribute(host, "disabled");
23
+ for (const control of controls) {
24
+ control?.toggleAttribute("disabled", disabled);
25
+ }
26
+ }
27
+
21
28
  function figLabColorEventAliases(color, alpha, opacity) {
22
29
  const numericAlpha = Number(alpha);
23
30
  const numericOpacity = Number(opacity);
@@ -566,6 +573,7 @@ class PropskitSwitch extends HTMLElement {
566
573
 
567
574
  #forwardSwitchEvent(type, event) {
568
575
  event.stopImmediatePropagation();
576
+ if (figLabBooleanAttribute(this, "disabled")) return;
569
577
  const checked = this.#switch?.value === "on";
570
578
  this.toggleAttribute("checked", checked);
571
579
  const detail = {
@@ -583,6 +591,7 @@ class PropskitSwitch extends HTMLElement {
583
591
  }
584
592
 
585
593
  #handleClick(event) {
594
+ if (figLabBooleanAttribute(this, "disabled")) return;
586
595
  if (
587
596
  event.target instanceof Element &&
588
597
  event.target.closest("fig-segmented-control, fig-menu")
@@ -845,6 +854,7 @@ class PropskitColor extends HTMLElement {
845
854
 
846
855
  #forwardInputEvent(type, event) {
847
856
  event.stopImmediatePropagation();
857
+ if (figLabBooleanAttribute(this, "disabled")) return;
848
858
  const value = this.#valueFromColorEvent(event);
849
859
  this.setAttribute("value", value);
850
860
  if (this.#input && this.#input.getAttribute("value") !== value) {
@@ -865,6 +875,7 @@ class PropskitColor extends HTMLElement {
865
875
  }
866
876
 
867
877
  #handleClick(event) {
878
+ if (figLabBooleanAttribute(this, "disabled")) return;
868
879
  if (
869
880
  event.target instanceof Element &&
870
881
  event.target.closest("fig-input-color, fig-menu")
@@ -1131,6 +1142,7 @@ class PropskitGradient extends HTMLElement {
1131
1142
 
1132
1143
  #forwardInputEvent(type, event) {
1133
1144
  event.stopImmediatePropagation();
1145
+ if (figLabBooleanAttribute(this, "disabled")) return;
1134
1146
  const value = this.#valueFromGradientEvent(event);
1135
1147
  this.setAttribute("value", value);
1136
1148
  const detail =
@@ -1148,6 +1160,7 @@ class PropskitGradient extends HTMLElement {
1148
1160
  }
1149
1161
 
1150
1162
  #handleClick(event) {
1163
+ if (figLabBooleanAttribute(this, "disabled")) return;
1151
1164
  if (
1152
1165
  event.target instanceof Element &&
1153
1166
  event.target.closest("fig-input-gradient, fig-menu")
@@ -1481,6 +1494,7 @@ class PropskitSelect extends HTMLElement {
1481
1494
  #forwardSelectEvent(type, event) {
1482
1495
  if (event.target !== this.#select) return;
1483
1496
  event.stopImmediatePropagation();
1497
+ if (figLabBooleanAttribute(this, "disabled")) return;
1484
1498
  const value = this.#select?.value ?? "";
1485
1499
  if (type !== "optionhover") this.setAttribute("value", String(value));
1486
1500
  const detail =
@@ -1520,6 +1534,7 @@ class PropskitSelect extends HTMLElement {
1520
1534
  }
1521
1535
 
1522
1536
  #handleClick(event) {
1537
+ if (figLabBooleanAttribute(this, "disabled")) return;
1523
1538
  if (event.target instanceof Element && event.target.closest("fig-menu")) {
1524
1539
  return;
1525
1540
  }
@@ -1753,6 +1768,7 @@ class PropskitText extends HTMLElement {
1753
1768
 
1754
1769
  #forwardInputEvent(type, event) {
1755
1770
  event.stopImmediatePropagation();
1771
+ if (figLabBooleanAttribute(this, "disabled")) return;
1756
1772
  const value = this.#input?.value ?? "";
1757
1773
  this.setAttribute("value", String(value));
1758
1774
  const detail =
@@ -1770,6 +1786,7 @@ class PropskitText extends HTMLElement {
1770
1786
  }
1771
1787
 
1772
1788
  #handleClick(event) {
1789
+ if (figLabBooleanAttribute(this, "disabled")) return;
1773
1790
  if (
1774
1791
  event.target instanceof Element &&
1775
1792
  event.target.closest("fig-input-text, fig-menu")
@@ -1978,6 +1995,7 @@ class PropskitNumber extends HTMLElement {
1978
1995
 
1979
1996
  #forwardInputEvent(type, event) {
1980
1997
  event.stopImmediatePropagation();
1998
+ if (figLabBooleanAttribute(this, "disabled")) return;
1981
1999
  const detail =
1982
2000
  event instanceof CustomEvent && event.detail !== undefined
1983
2001
  ? event.detail
@@ -1996,6 +2014,7 @@ class PropskitNumber extends HTMLElement {
1996
2014
  }
1997
2015
 
1998
2016
  #handleClick(event) {
2017
+ if (figLabBooleanAttribute(this, "disabled")) return;
1999
2018
  if (
2000
2019
  event.target instanceof Element &&
2001
2020
  event.target.closest("fig-input-number, fig-menu")
@@ -2251,6 +2270,7 @@ class PropskitPosition extends HTMLElement {
2251
2270
  }
2252
2271
 
2253
2272
  #handleClick(event) {
2273
+ if (figLabBooleanAttribute(this, "disabled")) return;
2254
2274
  if (
2255
2275
  event.target instanceof Element &&
2256
2276
  event.target.closest("fig-input-number, fig-menu")
@@ -2329,6 +2349,7 @@ figLabDefineElement("propskit-position", PropskitPosition);
2329
2349
  * @attr {boolean|string} collapsible - Internal group collapsibility; defaults true.
2330
2350
  * @attr {boolean|string} open - Internal group expanded state; defaults true.
2331
2351
  * @attr {string} size - Passed to both internal PropsKit controls.
2352
+ * @attr {boolean|string} disabled - Disables both internal controls.
2332
2353
  * @attr {string} value - JSON object with x, y, and color.
2333
2354
  * @fires input - Composed event with { x, y, color }.
2334
2355
  * @fires change - Composed event with { x, y, color }.
@@ -2340,6 +2361,7 @@ class PropskitColorPoint extends HTMLElement {
2340
2361
  "collapsible",
2341
2362
  "open",
2342
2363
  "size",
2364
+ "disabled",
2343
2365
  "value",
2344
2366
  ];
2345
2367
 
@@ -2361,6 +2383,7 @@ class PropskitColorPoint extends HTMLElement {
2361
2383
  if (!this.#group) this.#render();
2362
2384
  this.#syncGroupAttributes();
2363
2385
  this.#syncSize();
2386
+ this.#syncDisabled();
2364
2387
  this.#syncControls(this.#readValue());
2365
2388
  this.removeEventListener("input", this.#boundHandleInput);
2366
2389
  this.addEventListener("input", this.#boundHandleInput);
@@ -2389,6 +2412,10 @@ class PropskitColorPoint extends HTMLElement {
2389
2412
  this.#syncSize();
2390
2413
  return;
2391
2414
  }
2415
+ if (name === "disabled") {
2416
+ this.#syncDisabled();
2417
+ return;
2418
+ }
2392
2419
  this.#syncGroupAttributes();
2393
2420
  }
2394
2421
 
@@ -2452,6 +2479,7 @@ class PropskitColorPoint extends HTMLElement {
2452
2479
  this.#positionControl = position;
2453
2480
  this.#syncGroupAttributes();
2454
2481
  this.#syncSize();
2482
+ this.#syncDisabled();
2455
2483
  group.append(color, position);
2456
2484
  this.replaceChildren(group);
2457
2485
  }
@@ -2479,6 +2507,13 @@ class PropskitColorPoint extends HTMLElement {
2479
2507
  }
2480
2508
  }
2481
2509
 
2510
+ #syncDisabled() {
2511
+ figLabSyncDisabledControls(this, [
2512
+ this.#colorControl,
2513
+ this.#positionControl,
2514
+ ]);
2515
+ }
2516
+
2482
2517
  #syncControls(value) {
2483
2518
  const normalized = this.#normalizeValue(value);
2484
2519
  if (this.#colorControl) this.#colorControl.value = normalized.color;
@@ -2497,6 +2532,7 @@ class PropskitColorPoint extends HTMLElement {
2497
2532
  );
2498
2533
  if (!control || !this.contains(control)) return;
2499
2534
  event.stopImmediatePropagation();
2535
+ if (figLabBooleanAttribute(this, "disabled")) return;
2500
2536
  const value = this.value;
2501
2537
  const kind = control.getAttribute("data-propskit-color-point-control");
2502
2538
  if (kind === "color") {
@@ -2575,6 +2611,7 @@ figLabDefineElement("propskit-color-point", PropskitColorPoint);
2575
2611
  * @attr {boolean|string} open - Internal group expanded state; defaults true.
2576
2612
  * @attr {string} size - Passed to both internal PropsKit controls.
2577
2613
  * @attr {string} units - Passed to the internal position and radius controls.
2614
+ * @attr {boolean|string} disabled - Disables both internal controls.
2578
2615
  * @attr {string} value - JSON object with x, y, and radius.
2579
2616
  * @fires input - Composed event with { x, y, radius }.
2580
2617
  * @fires change - Composed event with { x, y, radius }.
@@ -2587,6 +2624,7 @@ class PropskitPointRadius extends HTMLElement {
2587
2624
  "open",
2588
2625
  "size",
2589
2626
  "units",
2627
+ "disabled",
2590
2628
  "value",
2591
2629
  ];
2592
2630
 
@@ -2609,6 +2647,7 @@ class PropskitPointRadius extends HTMLElement {
2609
2647
  this.#syncGroupAttributes();
2610
2648
  this.#syncSize();
2611
2649
  this.#syncUnits();
2650
+ this.#syncDisabled();
2612
2651
  this.#syncControls(this.#readValue());
2613
2652
  this.removeEventListener("input", this.#boundHandleInput);
2614
2653
  this.addEventListener("input", this.#boundHandleInput);
@@ -2641,6 +2680,10 @@ class PropskitPointRadius extends HTMLElement {
2641
2680
  this.#syncUnits();
2642
2681
  return;
2643
2682
  }
2683
+ if (name === "disabled") {
2684
+ this.#syncDisabled();
2685
+ return;
2686
+ }
2644
2687
  this.#syncGroupAttributes();
2645
2688
  }
2646
2689
 
@@ -2723,6 +2766,7 @@ class PropskitPointRadius extends HTMLElement {
2723
2766
  this.#radiusControl = radius;
2724
2767
  this.#syncGroupAttributes();
2725
2768
  this.#syncSize();
2769
+ this.#syncDisabled();
2726
2770
  group.append(position, radius);
2727
2771
  this.replaceChildren(group);
2728
2772
  }
@@ -2763,6 +2807,13 @@ class PropskitPointRadius extends HTMLElement {
2763
2807
  }
2764
2808
  }
2765
2809
 
2810
+ #syncDisabled() {
2811
+ figLabSyncDisabledControls(this, [
2812
+ this.#positionControl,
2813
+ this.#radiusControl,
2814
+ ]);
2815
+ }
2816
+
2766
2817
  #syncControls(value) {
2767
2818
  const normalized = this.#normalizeValue(value);
2768
2819
  if (this.#positionControl) {
@@ -2793,6 +2844,7 @@ class PropskitPointRadius extends HTMLElement {
2793
2844
  );
2794
2845
  if (!control || !this.contains(control)) return;
2795
2846
  event.stopImmediatePropagation();
2847
+ if (figLabBooleanAttribute(this, "disabled")) return;
2796
2848
  const value = this.value;
2797
2849
  const kind = control.getAttribute("data-propskit-point-radius-control");
2798
2850
  if (kind === "position") {
@@ -2888,6 +2940,7 @@ figLabDefineElement("propskit-point-radius", PropskitPointRadius);
2888
2940
  * @attr {boolean|string} open - Internal group expanded state; defaults true.
2889
2941
  * @attr {string} size - Passed to every internal PropsKit control.
2890
2942
  * @attr {string} units - Passed to the internal position and radius controls.
2943
+ * @attr {boolean|string} disabled - Disables every internal control.
2891
2944
  * @attr {string} value - JSON object with x, y, radius, and angle.
2892
2945
  * @fires input - Composed event with { x, y, radius, angle }.
2893
2946
  * @fires change - Composed event with { x, y, radius, angle }.
@@ -2900,6 +2953,7 @@ class PropskitPointRadiusAngle extends HTMLElement {
2900
2953
  "open",
2901
2954
  "size",
2902
2955
  "units",
2956
+ "disabled",
2903
2957
  "value",
2904
2958
  ];
2905
2959
 
@@ -2923,6 +2977,7 @@ class PropskitPointRadiusAngle extends HTMLElement {
2923
2977
  this.#syncGroupAttributes();
2924
2978
  this.#syncSize();
2925
2979
  this.#syncUnits();
2980
+ this.#syncDisabled();
2926
2981
  this.#syncControls(this.#readValue());
2927
2982
  this.removeEventListener("input", this.#boundHandleInput);
2928
2983
  this.addEventListener("input", this.#boundHandleInput);
@@ -2955,6 +3010,10 @@ class PropskitPointRadiusAngle extends HTMLElement {
2955
3010
  this.#syncUnits();
2956
3011
  return;
2957
3012
  }
3013
+ if (name === "disabled") {
3014
+ this.#syncDisabled();
3015
+ return;
3016
+ }
2958
3017
  this.#syncGroupAttributes();
2959
3018
  }
2960
3019
 
@@ -3049,6 +3108,7 @@ class PropskitPointRadiusAngle extends HTMLElement {
3049
3108
  this.#angleControl = angle;
3050
3109
  this.#syncGroupAttributes();
3051
3110
  this.#syncSize();
3111
+ this.#syncDisabled();
3052
3112
  group.append(position, radius, angle);
3053
3113
  this.replaceChildren(group);
3054
3114
  }
@@ -3093,6 +3153,14 @@ class PropskitPointRadiusAngle extends HTMLElement {
3093
3153
  }
3094
3154
  }
3095
3155
 
3156
+ #syncDisabled() {
3157
+ figLabSyncDisabledControls(this, [
3158
+ this.#positionControl,
3159
+ this.#radiusControl,
3160
+ this.#angleControl,
3161
+ ]);
3162
+ }
3163
+
3096
3164
  #syncControls(value) {
3097
3165
  const normalized = this.#normalizeValue(value);
3098
3166
  if (this.#positionControl) {
@@ -3126,6 +3194,7 @@ class PropskitPointRadiusAngle extends HTMLElement {
3126
3194
  );
3127
3195
  if (!control || !this.contains(control)) return;
3128
3196
  event.stopImmediatePropagation();
3197
+ if (figLabBooleanAttribute(this, "disabled")) return;
3129
3198
  const value = this.value;
3130
3199
  const kind = control.getAttribute(
3131
3200
  "data-propskit-point-radius-angle-control",
@@ -3228,6 +3297,7 @@ figLabDefineElement(
3228
3297
  * @attr {boolean|string} open - Internal group expanded state; defaults true.
3229
3298
  * @attr {string} size - Passed to both internal position controls.
3230
3299
  * @attr {string} units - Passed to both internal position controls.
3300
+ * @attr {boolean|string} disabled - Disables both internal position controls.
3231
3301
  * @attr {string} value - JSON object with x, y, x2, and y2.
3232
3302
  * @fires input - Composed event with { x, y, x2, y2 }.
3233
3303
  * @fires change - Composed event with { x, y, x2, y2 }.
@@ -3240,6 +3310,7 @@ class PropskitPointPoint extends HTMLElement {
3240
3310
  "open",
3241
3311
  "size",
3242
3312
  "units",
3313
+ "disabled",
3243
3314
  "value",
3244
3315
  ];
3245
3316
 
@@ -3262,6 +3333,7 @@ class PropskitPointPoint extends HTMLElement {
3262
3333
  this.#syncGroupAttributes();
3263
3334
  this.#syncSize();
3264
3335
  this.#syncUnits();
3336
+ this.#syncDisabled();
3265
3337
  this.#syncControls(this.#readValue());
3266
3338
  this.removeEventListener("input", this.#boundHandleInput);
3267
3339
  this.addEventListener("input", this.#boundHandleInput);
@@ -3294,6 +3366,10 @@ class PropskitPointPoint extends HTMLElement {
3294
3366
  this.#syncUnits();
3295
3367
  return;
3296
3368
  }
3369
+ if (name === "disabled") {
3370
+ this.#syncDisabled();
3371
+ return;
3372
+ }
3297
3373
  this.#syncGroupAttributes();
3298
3374
  }
3299
3375
 
@@ -3357,6 +3433,7 @@ class PropskitPointPoint extends HTMLElement {
3357
3433
  this.#endControl = end;
3358
3434
  this.#syncGroupAttributes();
3359
3435
  this.#syncSize();
3436
+ this.#syncDisabled();
3360
3437
  group.append(start, end);
3361
3438
  this.replaceChildren(group);
3362
3439
  }
@@ -3392,6 +3469,13 @@ class PropskitPointPoint extends HTMLElement {
3392
3469
  }
3393
3470
  }
3394
3471
 
3472
+ #syncDisabled() {
3473
+ figLabSyncDisabledControls(this, [
3474
+ this.#startControl,
3475
+ this.#endControl,
3476
+ ]);
3477
+ }
3478
+
3395
3479
  #syncControls(value) {
3396
3480
  const normalized = this.#normalizeValue(value);
3397
3481
  if (this.#startControl) {
@@ -3415,6 +3499,7 @@ class PropskitPointPoint extends HTMLElement {
3415
3499
  );
3416
3500
  if (!control || !this.contains(control)) return;
3417
3501
  event.stopImmediatePropagation();
3502
+ if (figLabBooleanAttribute(this, "disabled")) return;
3418
3503
  const value = this.value;
3419
3504
  const point = control.value;
3420
3505
  const role = control.getAttribute("data-propskit-point-point-control");
@@ -3502,13 +3587,17 @@ figLabDefineElement("propskit-point-point", PropskitPointPoint);
3502
3587
 
3503
3588
  /* Collapsible property group — always collapsible (no collapsible attr). */
3504
3589
  class PropskitGroup extends HTMLElement {
3505
- static observedAttributes = ["name", "open", "show-reset"];
3590
+ static observedAttributes = ["name", "open", "show-reset", "disabled"];
3506
3591
 
3507
3592
  static #CONTROL_SELECTOR = [
3508
3593
  "propskit-color",
3509
3594
  "propskit-gradient",
3510
3595
  "propskit-number",
3511
3596
  "propskit-position",
3597
+ "propskit-color-point",
3598
+ "propskit-point-radius",
3599
+ "propskit-point-radius-angle",
3600
+ "propskit-point-point",
3512
3601
  "propskit-select",
3513
3602
  "propskit-slider",
3514
3603
  "propskit-switch",
@@ -3525,6 +3614,7 @@ class PropskitGroup extends HTMLElement {
3525
3614
 
3526
3615
  connectedCallback() {
3527
3616
  this.#render();
3617
+ this.#syncDisabled();
3528
3618
  this.#bindDirtyListeners();
3529
3619
  requestAnimationFrame(() => {
3530
3620
  this.#syncDirtyState();
@@ -3554,6 +3644,10 @@ class PropskitGroup extends HTMLElement {
3554
3644
  this.#syncDirtyState();
3555
3645
  return;
3556
3646
  }
3647
+ if (name === "disabled") {
3648
+ this.#syncDisabled();
3649
+ return;
3650
+ }
3557
3651
  this.#render();
3558
3652
  }
3559
3653
 
@@ -3609,6 +3703,7 @@ class PropskitGroup extends HTMLElement {
3609
3703
 
3610
3704
  if (!this.#childObserver) {
3611
3705
  this.#childObserver = new MutationObserver(() => {
3706
+ this.#syncDisabled();
3612
3707
  this.#queueDirtySync();
3613
3708
  });
3614
3709
  }
@@ -3647,12 +3742,14 @@ class PropskitGroup extends HTMLElement {
3647
3742
  }
3648
3743
 
3649
3744
  #handleToggle = (e) => {
3745
+ if (figLabBooleanAttribute(this, "disabled")) return;
3650
3746
  if (this.#isResetTarget(e.target)) return;
3651
3747
  e.stopPropagation();
3652
3748
  this.open = !this.open;
3653
3749
  };
3654
3750
 
3655
3751
  #handleHeaderKeyDown = (e) => {
3752
+ if (figLabBooleanAttribute(this, "disabled")) return;
3656
3753
  if (this.#isResetTarget(e.target)) return;
3657
3754
  if (e.key !== "Enter" && e.key !== " ") return;
3658
3755
  e.preventDefault();
@@ -3663,6 +3760,7 @@ class PropskitGroup extends HTMLElement {
3663
3760
  #handleReset = (e) => {
3664
3761
  e.preventDefault();
3665
3762
  e.stopPropagation();
3763
+ if (figLabBooleanAttribute(this, "disabled")) return;
3666
3764
  this.#resetControls();
3667
3765
  };
3668
3766
 
@@ -3676,6 +3774,26 @@ class PropskitGroup extends HTMLElement {
3676
3774
  );
3677
3775
  }
3678
3776
 
3777
+ #syncDisabled() {
3778
+ const disabled = figLabBooleanAttribute(this, "disabled");
3779
+ for (const control of this.#controls()) {
3780
+ if (disabled) {
3781
+ if (!figLabBooleanAttribute(control, "disabled")) {
3782
+ control.setAttribute("disabled", "");
3783
+ control.setAttribute("data-propskit-group-disabled", "");
3784
+ }
3785
+ } else if (control.hasAttribute("data-propskit-group-disabled")) {
3786
+ control.removeAttribute("disabled");
3787
+ control.removeAttribute("data-propskit-group-disabled");
3788
+ }
3789
+ }
3790
+ this.#header?.setAttribute("aria-disabled", String(disabled));
3791
+ this.#header?.setAttribute("tabindex", disabled ? "-1" : "0");
3792
+ this.#resetTooltip
3793
+ ?.querySelector("fig-button")
3794
+ ?.toggleAttribute("disabled", disabled);
3795
+ }
3796
+
3679
3797
  #controlIsDirty(el) {
3680
3798
  return el.isDefault === false;
3681
3799
  }
@@ -3813,7 +3931,7 @@ class PropskitGroup extends HTMLElement {
3813
3931
  this.#chevron = h3.querySelector(".propskit-group-chevron");
3814
3932
  this.#syncResetButton();
3815
3933
  this.#header.setAttribute("role", "button");
3816
- this.#header.setAttribute("tabindex", "0");
3934
+ this.#syncDisabled();
3817
3935
  this.#header.setAttribute("aria-expanded", String(this.open));
3818
3936
  this.#header.removeEventListener("click", this.#handleToggle);
3819
3937
  this.#header.addEventListener("click", this.#handleToggle);
@@ -4149,7 +4267,7 @@ class PropskitSlider extends HTMLElement {
4149
4267
  }
4150
4268
 
4151
4269
  #pushExternalValueToSlider() {
4152
- if (!this.#slider) return;
4270
+ if (!this.#slider || !this.hasAttribute("value")) return;
4153
4271
  const next = this.getAttribute("value") ?? "";
4154
4272
  if (String(this.#slider.value) !== next) {
4155
4273
  this.#slider.value = next;
@@ -4626,6 +4744,7 @@ class PropskitSlider extends HTMLElement {
4626
4744
 
4627
4745
  #forwardSliderEvent(type, event) {
4628
4746
  event.stopImmediatePropagation();
4747
+ if (figLabBooleanAttribute(this, "disabled")) return;
4629
4748
  if (type === "change") {
4630
4749
  this.#resetElasticPull();
4631
4750
  }
@@ -6364,7 +6483,7 @@ class PropskitOscillator extends HTMLElement {
6364
6483
  this.#syncViewportSize();
6365
6484
  this.#updateWaveform();
6366
6485
  this.#setupEvents();
6367
- this.#startPlayhead();
6486
+ if (!this.#isDisabled()) this.#startPlayhead();
6368
6487
  figLabConnectPropskitResetMenu(this);
6369
6488
  }
6370
6489
 
@@ -6414,6 +6533,7 @@ class PropskitOscillator extends HTMLElement {
6414
6533
  }
6415
6534
 
6416
6535
  #getWaveTypeMenuHTML(disabled, index) {
6536
+ const disabledAttr = disabled ? " disabled" : "";
6417
6537
  const items = PropskitOscillator.TYPES.map((type) => {
6418
6538
  return `<fig-menu-item value="${type.value}">
6419
6539
  ${PropskitOscillator.waveIcon(type.value, 24)}
@@ -6421,9 +6541,9 @@ class PropskitOscillator extends HTMLElement {
6421
6541
  </fig-menu-item>`;
6422
6542
  }).join("");
6423
6543
  const indexAttr = ` data-wave-index="${PropskitOscillator.#escapeAttribute(String(index))}"`;
6424
- return `<fig-menu class="propskit-oscillator-add-type" position="bottom right"${indexAttr}${disabled}>
6544
+ return `<fig-menu class="propskit-oscillator-add-type" position="bottom right"${indexAttr}${disabledAttr}>
6425
6545
  <fig-tooltip text="Add form">
6426
- <fig-button class="propskit-oscillator-add-type-button" variant="ghost" icon fig-menu-trigger aria-label="Add form"><fig-icon name="plus"></fig-icon></fig-button>
6546
+ <fig-button class="propskit-oscillator-add-type-button" variant="ghost" icon fig-menu-trigger aria-label="Add form"${disabledAttr}><fig-icon name="plus"></fig-icon></fig-button>
6427
6547
  </fig-tooltip>
6428
6548
  ${items}
6429
6549
  </fig-menu>`;
package/fig.js CHANGED
@@ -5173,7 +5173,6 @@ figDefineElement("fig-options", FigOptions);
5173
5173
  class FigSlider extends HTMLElement {
5174
5174
  #isInteracting = false;
5175
5175
  #pendingRegeneration = false;
5176
- #showEmptyTextValue = false;
5177
5176
  #isSyncingValueAttribute = false;
5178
5177
  #value = "";
5179
5178
  #a11yAttributes = [
@@ -5278,10 +5277,6 @@ class FigSlider extends HTMLElement {
5278
5277
  : this.type === "delta"
5279
5278
  ? 0
5280
5279
  : this.min;
5281
- this.#showEmptyTextValue =
5282
- this.type !== "range" &&
5283
- (rawValue === null ||
5284
- (typeof rawValue === "string" && rawValue.trim() === ""));
5285
5280
  this.value = this.#normalizeSliderValue(rawValue);
5286
5281
  }
5287
5282
 
@@ -5321,10 +5316,7 @@ class FigSlider extends HTMLElement {
5321
5316
  this.figInputNumber.setAttribute("max", String(this.max));
5322
5317
  this.figInputNumber.setAttribute("transform", String(this.transform));
5323
5318
  this.figInputNumber.setAttribute("step", String(this.step));
5324
- this.figInputNumber.setAttribute(
5325
- "value",
5326
- this.#showEmptyTextValue ? "" : String(this.value),
5327
- );
5319
+ this.figInputNumber.setAttribute("value", String(this.value));
5328
5320
  if (this.units) this.figInputNumber.setAttribute("units", this.units);
5329
5321
  else this.figInputNumber.removeAttribute("units");
5330
5322
  if (this.precision !== null) {
@@ -5411,7 +5403,7 @@ class FigSlider extends HTMLElement {
5411
5403
  max="${this.max}"
5412
5404
  transform="${this.transform}"
5413
5405
  step="${this.step}"
5414
- value="${this.#showEmptyTextValue ? "" : this.value}"
5406
+ value="${this.value}"
5415
5407
  ${this.units ? `units="${figEscapeAttribute(this.units)}"` : ""}
5416
5408
  ${this.precision !== null ? `precision="${this.precision}"` : ""}>
5417
5409
  </fig-input-number>`;
@@ -5487,8 +5479,6 @@ class FigSlider extends HTMLElement {
5487
5479
 
5488
5480
  set value(value) {
5489
5481
  const rawValue = value === null || value === undefined ? "" : String(value);
5490
- this.#showEmptyTextValue =
5491
- this.type !== "range" && rawValue.trim() === "";
5492
5482
  const hasParsedBounds = this.min !== undefined || this.max !== undefined;
5493
5483
  const normalized = hasParsedBounds
5494
5484
  ? String(this.#normalizeSliderValue(rawValue))
@@ -5504,10 +5494,7 @@ class FigSlider extends HTMLElement {
5504
5494
  this.input.setAttribute("aria-valuenow", normalized);
5505
5495
  }
5506
5496
  if (this.figInputNumber) {
5507
- this.figInputNumber.setAttribute(
5508
- "value",
5509
- this.#showEmptyTextValue ? "" : normalized,
5510
- );
5497
+ this.figInputNumber.setAttribute("value", normalized);
5511
5498
  }
5512
5499
  if (this.input) this.#syncProperties();
5513
5500
  }
@@ -5537,10 +5524,6 @@ class FigSlider extends HTMLElement {
5537
5524
  #handleTextInput() {
5538
5525
  if (this.figInputNumber) {
5539
5526
  const rawTextValue = this.figInputNumber.value;
5540
- this.#showEmptyTextValue =
5541
- rawTextValue === null ||
5542
- rawTextValue === undefined ||
5543
- (typeof rawTextValue === "string" && rawTextValue.trim() === "");
5544
5527
  const normalized = this.#normalizeSliderValue(rawTextValue);
5545
5528
  this.value = normalized;
5546
5529
  this.input.value = String(normalized);
@@ -5624,10 +5607,7 @@ class FigSlider extends HTMLElement {
5624
5607
  // Update ARIA value
5625
5608
  this.input.setAttribute("aria-valuenow", val);
5626
5609
  if (this.figInputNumber) {
5627
- this.figInputNumber.setAttribute(
5628
- "value",
5629
- this.#showEmptyTextValue ? "" : val,
5630
- );
5610
+ this.figInputNumber.setAttribute("value", val);
5631
5611
  }
5632
5612
  }
5633
5613
  #syncInputA11yAttributes() {
@@ -5665,7 +5645,6 @@ class FigSlider extends HTMLElement {
5665
5645
  }
5666
5646
 
5667
5647
  #handleInput() {
5668
- this.#showEmptyTextValue = false;
5669
5648
  this.#syncValue();
5670
5649
  this.dispatchEvent(
5671
5650
  new CustomEvent("input", { detail: this.value, bubbles: true }),
@@ -5674,7 +5653,6 @@ class FigSlider extends HTMLElement {
5674
5653
 
5675
5654
  #handleChange() {
5676
5655
  this.#isInteracting = false;
5677
- this.#showEmptyTextValue = false;
5678
5656
  this.#syncValue();
5679
5657
  this.dispatchEvent(
5680
5658
  new CustomEvent("change", { detail: this.value, bubbles: true }),
@@ -5690,7 +5668,6 @@ class FigSlider extends HTMLElement {
5690
5668
  }
5691
5669
 
5692
5670
  event.preventDefault();
5693
- this.#showEmptyTextValue = false;
5694
5671
 
5695
5672
  const direction =
5696
5673
  event.key === "ArrowRight" || event.key === "ArrowUp" ? 1 : -1;
@@ -5712,10 +5689,6 @@ class FigSlider extends HTMLElement {
5712
5689
  #handleTextChange() {
5713
5690
  if (this.figInputNumber) {
5714
5691
  const rawTextValue = this.figInputNumber.value;
5715
- this.#showEmptyTextValue =
5716
- rawTextValue === null ||
5717
- rawTextValue === undefined ||
5718
- (typeof rawTextValue === "string" && rawTextValue.trim() === "");
5719
5692
  const normalized = this.#normalizeSliderValue(rawTextValue);
5720
5693
  this.value = normalized;
5721
5694
  this.input.value = String(normalized);
@@ -11787,6 +11760,7 @@ class FigMedia extends HTMLElement {
11787
11760
  spinner.setAttribute("data-generated", "");
11788
11761
  spinner.setAttribute("data-loading-indicator", "");
11789
11762
  spinner.setAttribute("slot", "overlay");
11763
+ spinner.setAttribute("size", "small");
11790
11764
  spinner.setAttribute("aria-hidden", "true");
11791
11765
  this.append(spinner);
11792
11766
  this.#loadingSpinner = spinner;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "8.1.0",
3
+ "version": "8.2.1",
4
4
  "description": "A lightweight web components library for building Figma plugin and widget UIs with native look and feel",
5
5
  "author": "Rogie King",
6
6
  "license": "MIT",