@rogieking/figui3 2.30.1 → 2.31.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.
Files changed (3) hide show
  1. package/components.css +15 -6
  2. package/fig.js +99 -9
  3. package/package.json +1 -1
package/components.css CHANGED
@@ -542,7 +542,7 @@ input[type="text"][list] {
542
542
  position: relative;
543
543
  padding: 0 var(--spacer-1) 0 calc(var(--spacer-1) * 2 + var(--spacer-1));
544
544
  font-weight: var(--body-medium-fontWeight);
545
- &[label] {
545
+ &[label]:not([label=""]) {
546
546
  padding-top: var(--spacer-2);
547
547
  option:first-child {
548
548
  margin-top: var(--spacer-2);
@@ -3149,14 +3149,23 @@ fig-layer {
3149
3149
  user-select: none;
3150
3150
  border-radius: var(--radius-medium);
3151
3151
 
3152
- /* Show chevron when layer has children */
3153
- &:has(fig-layer) > .fig-layer-row > .fig-layer-chevron {
3154
- visibility: visible;
3152
+ /* When layer has children */
3153
+ &:has(fig-layer) {
3154
+ & > .fig-layer-row {
3155
+ & > .fig-layer-chevron {
3156
+ visibility: visible;
3157
+ }
3158
+ }
3159
+ }
3160
+ &:not(:has(fig-layer)):not(:has(.fig-layer-icon)) {
3161
+ & > .fig-layer-row {
3162
+ padding-left: var(--spacer-3);
3163
+ }
3155
3164
  }
3156
3165
 
3157
3166
  &:not(:has(.fig-layer-icon)) {
3158
3167
  & > .fig-layer-row {
3159
- padding-left: var(--spacer-3);
3168
+ padding-left: var(--spacer-4);
3160
3169
  }
3161
3170
  }
3162
3171
 
@@ -3165,7 +3174,7 @@ fig-layer {
3165
3174
  align-items: center;
3166
3175
  gap: var(--spacer-1);
3167
3176
  padding: var(--spacer-1) var(--spacer-2);
3168
- margin-left: var(--spacer-2);
3177
+ margin-left: 0;
3169
3178
  border-radius: var(--radius-medium);
3170
3179
  position: relative;
3171
3180
 
package/fig.js CHANGED
@@ -2400,7 +2400,8 @@ class FigSlider extends HTMLElement {
2400
2400
  #regenerateInnerHTML() {
2401
2401
  this.value = Number(this.getAttribute("value") || 0);
2402
2402
  this.type = this.getAttribute("type") || "range";
2403
- this.text = this.getAttribute("text") || false;
2403
+ this.text =
2404
+ this.hasAttribute("text") && this.getAttribute("text") !== "false";
2404
2405
  this.units = this.getAttribute("units") || "";
2405
2406
  this.transform = Number(this.getAttribute("transform") || 1);
2406
2407
  this.disabled = this.getAttribute("disabled") ? true : false;
@@ -2681,11 +2682,14 @@ class FigSlider extends HTMLElement {
2681
2682
  case "max":
2682
2683
  case "step":
2683
2684
  case "type":
2684
- case "text":
2685
2685
  case "units":
2686
2686
  this[name] = newValue;
2687
2687
  this.#regenerateInnerHTML();
2688
2688
  break;
2689
+ case "text":
2690
+ this.text = newValue !== null && newValue !== "false";
2691
+ this.#regenerateInnerHTML();
2692
+ break;
2689
2693
  default:
2690
2694
  this[name] = this.input[name] = newValue;
2691
2695
  this.#syncValue();
@@ -2738,6 +2742,16 @@ class FigInputText extends HTMLElement {
2738
2742
  if (this.getAttribute("step")) {
2739
2743
  this.step = Number(this.getAttribute("step"));
2740
2744
  }
2745
+
2746
+ if (this.getAttribute("min")) {
2747
+ this.input.setAttribute("min", String(this.min));
2748
+ }
2749
+ if (this.getAttribute("max")) {
2750
+ this.input.setAttribute("max", String(this.max));
2751
+ }
2752
+ if (this.getAttribute("step")) {
2753
+ this.input.setAttribute("step", String(this.step));
2754
+ }
2741
2755
  if (this.getAttribute("min")) {
2742
2756
  this.min = Number(this.getAttribute("min"));
2743
2757
  }
@@ -2997,6 +3011,21 @@ class FigInputNumber extends HTMLElement {
2997
3011
  #precision;
2998
3012
  #isInteracting = false;
2999
3013
 
3014
+ #syncNativeNumberAttributes() {
3015
+ if (!this.input || this.input.type !== "number") return;
3016
+
3017
+ ["min", "max", "step"].forEach((name) => {
3018
+ const attrValue = this.getAttribute(name);
3019
+ if (attrValue === null || attrValue === "") {
3020
+ this.input.removeAttribute(name);
3021
+ this.input[name] = "";
3022
+ return;
3023
+ }
3024
+ this.input.setAttribute(name, attrValue);
3025
+ this.input[name] = attrValue;
3026
+ });
3027
+ }
3028
+
3000
3029
  constructor() {
3001
3030
  super();
3002
3031
  // Pre-bind the event handlers once
@@ -3052,13 +3081,16 @@ class FigInputNumber extends HTMLElement {
3052
3081
  // Use type="number" when steppers are enabled (for native spin buttons)
3053
3082
  const inputType = hasSteppers ? "number" : "text";
3054
3083
  const inputMode = hasSteppers ? "" : 'inputmode="decimal"';
3084
+ const inputValue = hasSteppers
3085
+ ? this.#transformNumber(this.value)
3086
+ : this.#formatWithUnit(this.value);
3055
3087
 
3056
3088
  let html = `<input
3057
3089
  type="${inputType}"
3058
3090
  ${inputMode}
3059
3091
  ${this.name ? `name="${this.name}"` : ""}
3060
3092
  placeholder="${this.placeholder}"
3061
- value="${this.#formatWithUnit(this.value)}" />`;
3093
+ value="${inputValue}" />`;
3062
3094
 
3063
3095
  //child nodes hack
3064
3096
  requestAnimationFrame(() => {
@@ -3087,6 +3119,7 @@ class FigInputNumber extends HTMLElement {
3087
3119
  if (this.getAttribute("step")) {
3088
3120
  this.step = Number(this.getAttribute("step"));
3089
3121
  }
3122
+ this.#syncNativeNumberAttributes();
3090
3123
 
3091
3124
  // Set disabled state if present
3092
3125
  if (this.hasAttribute("disabled")) {
@@ -3355,15 +3388,24 @@ class FigInputNumber extends HTMLElement {
3355
3388
  break;
3356
3389
  case "units":
3357
3390
  this.#units = newValue || "";
3358
- this.input.value = this.#formatWithUnit(this.value);
3391
+ this.input.value =
3392
+ this.input.type === "number"
3393
+ ? this.#transformNumber(this.value)
3394
+ : this.#formatWithUnit(this.value);
3359
3395
  break;
3360
3396
  case "unit-position":
3361
3397
  this.#unitPosition = newValue || "suffix";
3362
- this.input.value = this.#formatWithUnit(this.value);
3398
+ this.input.value =
3399
+ this.input.type === "number"
3400
+ ? this.#transformNumber(this.value)
3401
+ : this.#formatWithUnit(this.value);
3363
3402
  break;
3364
3403
  case "transform":
3365
3404
  this.transform = Number(newValue) || 1;
3366
- this.input.value = this.#formatWithUnit(this.value);
3405
+ this.input.value =
3406
+ this.input.type === "number"
3407
+ ? this.#transformNumber(this.value)
3408
+ : this.#formatWithUnit(this.value);
3367
3409
  break;
3368
3410
  case "value":
3369
3411
  if (this.#isInteracting) break;
@@ -3373,16 +3415,41 @@ class FigInputNumber extends HTMLElement {
3373
3415
  value = this.#sanitizeInput(value, false);
3374
3416
  }
3375
3417
  this.value = value;
3376
- this.input.value = this.#formatWithUnit(this.value);
3418
+ this.input.value =
3419
+ this.input.type === "number"
3420
+ ? this.#transformNumber(this.value)
3421
+ : this.#formatWithUnit(this.value);
3377
3422
  break;
3378
3423
  case "min":
3379
3424
  case "max":
3380
3425
  case "step":
3426
+ if (newValue === null || newValue === "") {
3427
+ this[name] = undefined;
3428
+ this.#syncNativeNumberAttributes();
3429
+ break;
3430
+ }
3381
3431
  this[name] = Number(newValue);
3432
+ this.#syncNativeNumberAttributes();
3433
+ break;
3434
+ case "steppers": {
3435
+ const hasSteppers = newValue !== null && newValue !== "false";
3436
+ this.input.type = hasSteppers ? "number" : "text";
3437
+ if (hasSteppers) {
3438
+ this.input.removeAttribute("inputmode");
3439
+ this.#syncNativeNumberAttributes();
3440
+ this.input.value = this.#transformNumber(this.value);
3441
+ } else {
3442
+ this.input.setAttribute("inputmode", "decimal");
3443
+ this.input.value = this.#formatWithUnit(this.value);
3444
+ }
3382
3445
  break;
3446
+ }
3383
3447
  case "precision":
3384
3448
  this.#precision = newValue !== null ? Number(newValue) : 2;
3385
- this.input.value = this.#formatWithUnit(this.value);
3449
+ this.input.value =
3450
+ this.input.type === "number"
3451
+ ? this.#transformNumber(this.value)
3452
+ : this.#formatWithUnit(this.value);
3386
3453
  break;
3387
3454
  case "name":
3388
3455
  this[name] = this.input[name] = newValue;
@@ -4633,7 +4700,7 @@ class FigCheckbox extends HTMLElement {
4633
4700
  this.render();
4634
4701
  }
4635
4702
  static get observedAttributes() {
4636
- return ["disabled", "label", "checked", "name", "value"];
4703
+ return ["disabled", "label", "checked", "name", "value", "indeterminate"];
4637
4704
  }
4638
4705
 
4639
4706
  #createLabel() {
@@ -4699,6 +4766,29 @@ class FigCheckbox extends HTMLElement {
4699
4766
  this.input.checked =
4700
4767
  this.hasAttribute("checked") &&
4701
4768
  this.getAttribute("checked") !== "false";
4769
+ if (this.input.checked && this.hasAttribute("indeterminate")) {
4770
+ this.removeAttribute("indeterminate");
4771
+ }
4772
+ this.input.indeterminate =
4773
+ this.hasAttribute("indeterminate") &&
4774
+ this.getAttribute("indeterminate") !== "false" &&
4775
+ !this.input.checked;
4776
+ if (this.input.indeterminate) {
4777
+ this.input.setAttribute("indeterminate", "true");
4778
+ } else {
4779
+ this.input.removeAttribute("indeterminate");
4780
+ }
4781
+ break;
4782
+ case "indeterminate":
4783
+ this.input.indeterminate =
4784
+ this.hasAttribute("indeterminate") &&
4785
+ this.getAttribute("indeterminate") !== "false" &&
4786
+ !this.input.checked;
4787
+ if (this.input.indeterminate) {
4788
+ this.input.setAttribute("indeterminate", "true");
4789
+ } else {
4790
+ this.input.removeAttribute("indeterminate");
4791
+ }
4702
4792
  break;
4703
4793
  case "value":
4704
4794
  this.input.value = newValue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "2.30.1",
3
+ "version": "2.31.0",
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",