@rogieking/figui3 8.9.18 → 8.9.20

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.js CHANGED
@@ -8979,6 +8979,7 @@ class FigInputFill extends HTMLElement {
8979
8979
  scale: 50,
8980
8980
  opacity: 1,
8981
8981
  };
8982
+ #custom = {};
8982
8983
 
8983
8984
  constructor() {
8984
8985
  super();
@@ -9054,8 +9055,11 @@ class FigInputFill extends HTMLElement {
9054
9055
  break;
9055
9056
  case "webcam":
9056
9057
  if (parsed.webcam && typeof parsed.webcam === "object") {
9057
- const { stream: _ignored, ...rest } = parsed.webcam;
9058
+ const { stream: _ignored, snapshot, ...rest } = parsed.webcam;
9058
9059
  this.#webcam = { ...this.#webcam, ...rest };
9060
+ if (typeof snapshot === "string" && snapshot) {
9061
+ this.#webcam.snapshot = snapshot;
9062
+ }
9059
9063
  } else if (parsed.image?.url) {
9060
9064
  this.#webcam.snapshot = parsed.image.url;
9061
9065
  if (parsed.image.scaleMode)
@@ -9066,6 +9070,11 @@ class FigInputFill extends HTMLElement {
9066
9070
  if (parsed.opacity !== undefined)
9067
9071
  this.#webcam.opacity = parsed.opacity;
9068
9072
  break;
9073
+ default: {
9074
+ const { type: _type, ...rest } = parsed;
9075
+ this.#custom = rest;
9076
+ break;
9077
+ }
9069
9078
  }
9070
9079
  } catch (e) {
9071
9080
  // If not JSON, treat as hex color
@@ -9139,12 +9148,14 @@ class FigInputFill extends HTMLElement {
9139
9148
  return this.#image.url ? figCssUrl(this.#image.url) : "#D9D9D9";
9140
9149
  case "video":
9141
9150
  return this.#video.poster ? figCssUrl(this.#video.poster) : "#D9D9D9";
9142
- case "webcam":
9143
- return this.#webcam.snapshot
9144
- ? figCssUrl(this.#webcam.snapshot)
9145
- : "#D9D9D9";
9151
+ case "webcam": {
9152
+ const snapshot =
9153
+ this.#webcam.snapshot ||
9154
+ this.#fillPicker?.value?.webcam?.snapshot;
9155
+ return snapshot ? figCssUrl(snapshot) : "";
9156
+ }
9146
9157
  default:
9147
- return "#D9D9D9";
9158
+ return this.#customSwatchBackground();
9148
9159
  }
9149
9160
  }
9150
9161
 
@@ -9173,7 +9184,38 @@ class FigInputFill extends HTMLElement {
9173
9184
  case "webcam":
9174
9185
  return this.#webcam.opacity ?? 1;
9175
9186
  default:
9176
- return 1;
9187
+ return this.#normalizeFillOpacity(
9188
+ this.#custom.opacity ?? this.#custom.alpha,
9189
+ 1,
9190
+ );
9191
+ }
9192
+ }
9193
+
9194
+ #customModeSlot() {
9195
+ return this.querySelector(`[slot="mode-${this.#fillType}"]`);
9196
+ }
9197
+
9198
+ #customTypeLabel() {
9199
+ const slotLabel = this.#customModeSlot()?.getAttribute("label");
9200
+ if (slotLabel) return slotLabel;
9201
+ if (!this.#fillType) return "Fill";
9202
+ return this.#fillType.charAt(0).toUpperCase() + this.#fillType.slice(1);
9203
+ }
9204
+
9205
+ #customSwatchBackground() {
9206
+ return (
9207
+ this.#custom.swatchBackground ||
9208
+ this.#custom.background ||
9209
+ this.#custom.css ||
9210
+ this.#customModeSlot()?.getAttribute("swatch-background") ||
9211
+ ""
9212
+ );
9213
+ }
9214
+
9215
+ #adoptModeSlots() {
9216
+ if (!this.#fillPicker) return;
9217
+ for (const slot of [...this.querySelectorAll(":scope > [slot^='mode-']")]) {
9218
+ this.#fillPicker.append(slot);
9177
9219
  }
9178
9220
  }
9179
9221
 
@@ -9268,6 +9310,13 @@ class FigInputFill extends HTMLElement {
9268
9310
  label = "Webcam";
9269
9311
  opacity = this.#webcam.opacity ?? 1;
9270
9312
  break;
9313
+ default:
9314
+ label = this.#customTypeLabel();
9315
+ opacity = this.#normalizeFillOpacity(
9316
+ this.#custom.opacity ?? this.#custom.alpha,
9317
+ 1,
9318
+ );
9319
+ break;
9271
9320
  }
9272
9321
 
9273
9322
  return [
@@ -9290,6 +9339,7 @@ class FigInputFill extends HTMLElement {
9290
9339
  alpha: this.#fillPickerSwatchAlpha(),
9291
9340
  disabled,
9292
9341
  });
9342
+ const modeSlots = [...this.querySelectorAll("[slot^='mode-']")];
9293
9343
  const picker = figCreateElement(
9294
9344
  "fig-fill-picker",
9295
9345
  {
@@ -9297,7 +9347,7 @@ class FigInputFill extends HTMLElement {
9297
9347
  disabled,
9298
9348
  ...fpAttrs,
9299
9349
  },
9300
- swatch,
9350
+ [swatch, ...modeSlots],
9301
9351
  );
9302
9352
  const combo = figCreateElement(
9303
9353
  "div",
@@ -9307,6 +9357,11 @@ class FigInputFill extends HTMLElement {
9307
9357
  this.replaceChildren(combo);
9308
9358
 
9309
9359
  this.#setupEventListeners();
9360
+ queueMicrotask(() => {
9361
+ this.#adoptModeSlots();
9362
+ this.#syncSwatch();
9363
+ this.#updateControls();
9364
+ });
9310
9365
  }
9311
9366
 
9312
9367
  #setupEventListeners() {
@@ -9369,12 +9424,24 @@ class FigInputFill extends HTMLElement {
9369
9424
  break;
9370
9425
  case "webcam":
9371
9426
  if (detail.webcam) {
9372
- const { stream: _ignored, ...rest } = detail.webcam;
9427
+ const { stream: _ignored, snapshot, ...rest } = detail.webcam;
9373
9428
  this.#webcam = { ...this.#webcam, ...rest };
9429
+ if (typeof snapshot === "string" && snapshot) {
9430
+ this.#webcam.snapshot = snapshot;
9431
+ }
9374
9432
  } else if (detail.image?.url) {
9375
9433
  this.#webcam.snapshot = detail.image.url;
9376
9434
  }
9435
+ if (!this.#webcam.snapshot) {
9436
+ const fromPicker = this.#fillPicker?.value?.webcam?.snapshot;
9437
+ if (fromPicker) this.#webcam.snapshot = fromPicker;
9438
+ }
9439
+ break;
9440
+ default: {
9441
+ const { type: _type, colorSpace: _colorSpace, ...rest } = detail;
9442
+ this.#custom = rest;
9377
9443
  break;
9444
+ }
9378
9445
  }
9379
9446
  // Update controls (don't re-render to keep dialog open)
9380
9447
  if (typeChanged) {
@@ -9441,6 +9508,9 @@ class FigInputFill extends HTMLElement {
9441
9508
  case "webcam":
9442
9509
  this.#webcam.opacity = alpha;
9443
9510
  break;
9511
+ default:
9512
+ this.#custom.opacity = alpha;
9513
+ break;
9444
9514
  }
9445
9515
  this.#updateFillPicker();
9446
9516
  this.#syncSwatch();
@@ -9510,6 +9580,22 @@ class FigInputFill extends HTMLElement {
9510
9580
  );
9511
9581
  }
9512
9582
  break;
9583
+ default: {
9584
+ const label = this.querySelector(".fig-input-fill-label");
9585
+ if (label) label.textContent = this.#customTypeLabel();
9586
+ if (this.#opacityInput) {
9587
+ this.#opacityInput.setAttribute(
9588
+ "value",
9589
+ Math.round(
9590
+ this.#normalizeFillOpacity(
9591
+ this.#custom.opacity ?? this.#custom.alpha,
9592
+ 1,
9593
+ ) * 100,
9594
+ ),
9595
+ );
9596
+ }
9597
+ break;
9598
+ }
9513
9599
  }
9514
9600
  }
9515
9601
 
@@ -9587,6 +9673,9 @@ class FigInputFill extends HTMLElement {
9587
9673
  case "webcam":
9588
9674
  this.#webcam.opacity = alpha;
9589
9675
  break;
9676
+ default:
9677
+ this.#custom.opacity = alpha;
9678
+ break;
9590
9679
  }
9591
9680
  this.#updateFillPicker();
9592
9681
  this.#updateSwatchAlpha(alpha);
@@ -9609,7 +9698,15 @@ class FigInputFill extends HTMLElement {
9609
9698
  #syncSwatch() {
9610
9699
  const swatch = this.#fillPicker?.querySelector("fig-swatch");
9611
9700
  if (!swatch) return;
9612
- swatch.setAttribute("background", this.#fillPickerSwatchBackground());
9701
+ const background = this.#fillPickerSwatchBackground();
9702
+ if (this.#fillType === "webcam" && !background) {
9703
+ const current = swatch.getAttribute("background") || "";
9704
+ if (current.startsWith("url(")) {
9705
+ swatch.setAttribute("alpha", this.#fillPickerSwatchAlpha());
9706
+ return;
9707
+ }
9708
+ }
9709
+ swatch.setAttribute("background", background);
9613
9710
  swatch.setAttribute("alpha", this.#fillPickerSwatchAlpha());
9614
9711
  }
9615
9712
 
@@ -9703,7 +9800,7 @@ class FigInputFill extends HTMLElement {
9703
9800
  webcam: this.#webcamValue(),
9704
9801
  };
9705
9802
  default:
9706
- return { type: this.#fillType };
9803
+ return { type: this.#fillType, ...this.#custom };
9707
9804
  }
9708
9805
  }
9709
9806
 
@@ -11886,7 +11983,24 @@ class FigSwatch extends HTMLElement {
11886
11983
  }
11887
11984
 
11888
11985
  #render() {
11889
- const rawBg = this.getAttribute("background") || "#D9D9D9";
11986
+ const rawAttr = this.getAttribute("background");
11987
+ const emptyMedia = this.hasAttribute("background") && !rawAttr?.trim();
11988
+ if (emptyMedia) {
11989
+ if (this.#type !== "image" || this.input) {
11990
+ this.#type = "image";
11991
+ this.setAttribute("data-type", "image");
11992
+ if (this.input) {
11993
+ this.input.removeEventListener("input", this.#boundHandleInput);
11994
+ }
11995
+ this.replaceChildren(document.createElement("div"));
11996
+ this.input = null;
11997
+ this.#syncA11y();
11998
+ }
11999
+ this.style.setProperty("--swatch-background", "none");
12000
+ return;
12001
+ }
12002
+
12003
+ const rawBg = rawAttr || "#D9D9D9";
11890
12004
  const isVar = rawBg.includes("var(");
11891
12005
  const bg = isVar ? this.#resolveBackground(rawBg) : rawBg;
11892
12006
  const newType = this.#detectType(bg);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "8.9.18",
3
+ "version": "8.9.20",
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",