@rogieking/figui3 6.9.3 → 6.9.5

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
@@ -4887,6 +4887,7 @@ class FigSlider extends HTMLElement {
4887
4887
  #boundRangePointerUp;
4888
4888
  #lastSliderComplete = null;
4889
4889
  #lastSliderDefault = null;
4890
+ #lastSliderDeltaDirection = null;
4890
4891
  #lastSliderUnchanged = null;
4891
4892
 
4892
4893
  constructor() {
@@ -5259,6 +5260,7 @@ class FigSlider extends HTMLElement {
5259
5260
  #syncProperties() {
5260
5261
  const complete = this.#calculateNormal(this.value);
5261
5262
  const defaultValue = this.#calculateNormal(this.default);
5263
+ const deltaDirection = complete < defaultValue ? -1 : 1;
5262
5264
  const unchanged = complete === defaultValue ? 1 : 0;
5263
5265
 
5264
5266
  if (this.#lastSliderComplete !== complete) {
@@ -5269,6 +5271,10 @@ class FigSlider extends HTMLElement {
5269
5271
  this.style.setProperty("--default", defaultValue);
5270
5272
  this.#lastSliderDefault = defaultValue;
5271
5273
  }
5274
+ if (this.#lastSliderDeltaDirection !== deltaDirection) {
5275
+ this.style.setProperty("--slider-delta-direction", deltaDirection);
5276
+ this.#lastSliderDeltaDirection = deltaDirection;
5277
+ }
5272
5278
  if (this.#lastSliderUnchanged !== unchanged) {
5273
5279
  this.style.setProperty("--unchanged", unchanged);
5274
5280
  this.#lastSliderUnchanged = unchanged;
@@ -7040,12 +7046,12 @@ class FigInputColor extends HTMLElement {
7040
7046
  const showText = this.getAttribute("text") !== "false";
7041
7047
  return showText
7042
7048
  ? !!this.querySelector(":scope > .input-combo")
7043
- : !!this.querySelector(":scope > fig-chit");
7049
+ : !!this.querySelector(":scope > fig-swatch");
7044
7050
  }
7045
7051
 
7046
7052
  #refreshUI() {
7047
7053
  this.#setValues(this.getAttribute("value"));
7048
- this.#swatch = this.querySelector("fig-chit");
7054
+ this.#swatch = this.querySelector("fig-swatch");
7049
7055
  this.#fillPicker = this.querySelector("fig-fill-picker");
7050
7056
  this.#textInput = this.querySelector("fig-input-text:not([type=number])");
7051
7057
  this.#alphaInput = this.querySelector("fig-input-number");
@@ -7152,18 +7158,18 @@ class FigInputColor extends HTMLElement {
7152
7158
  }
7153
7159
 
7154
7160
  let swatchElement = "";
7155
- swatchElement = `<fig-chit background="${this.hexOpaque}" alpha="${this.rgba.a}"${disabledAttr}></fig-chit>`;
7161
+ swatchElement = `<fig-swatch background="${this.hexOpaque}" alpha="${this.rgba.a}"${disabledAttr}></fig-swatch>`;
7156
7162
 
7157
7163
  html = `<div class="input-combo">
7158
7164
  ${swatchElement}
7159
7165
  ${label}
7160
7166
  </div>`;
7161
7167
  } else {
7162
- html = `<fig-chit background="${this.hexOpaque}" alpha="${this.rgba.a}"${disabledAttr}></fig-chit>`;
7168
+ html = `<fig-swatch background="${this.hexOpaque}" alpha="${this.rgba.a}"${disabledAttr}></fig-swatch>`;
7163
7169
  }
7164
7170
  this.innerHTML = html;
7165
7171
 
7166
- this.#swatch = this.querySelector("fig-chit");
7172
+ this.#swatch = this.querySelector("fig-swatch");
7167
7173
  this.#fillPicker = this.querySelector("fig-fill-picker");
7168
7174
  this.#textInput = this.querySelector("fig-input-text:not([type=number])");
7169
7175
  this.#alphaInput = this.querySelector("fig-input-number");
@@ -8041,7 +8047,7 @@ class FigInputFill extends HTMLElement {
8041
8047
  .join(" ");
8042
8048
  }
8043
8049
 
8044
- #fillPickerChitBackground() {
8050
+ #fillPickerSwatchBackground() {
8045
8051
  switch (this.#fillType) {
8046
8052
  case "solid":
8047
8053
  return this.#solid.color;
@@ -8066,7 +8072,7 @@ class FigInputFill extends HTMLElement {
8066
8072
  }
8067
8073
  }
8068
8074
 
8069
- #fillPickerChitAlpha() {
8075
+ #fillPickerSwatchAlpha() {
8070
8076
  switch (this.#fillType) {
8071
8077
  case "solid":
8072
8078
  return this.#solid.alpha;
@@ -8187,7 +8193,7 @@ class FigInputFill extends HTMLElement {
8187
8193
  <fig-fill-picker ${fpAttrs} value='${fillPickerValue}' ${
8188
8194
  disabled ? "disabled" : ""
8189
8195
  }>
8190
- <fig-chit background="${this.#fillPickerChitBackground()}" alpha="${this.#fillPickerChitAlpha()}"${disabled ? " disabled" : ""}></fig-chit>
8196
+ <fig-swatch background="${this.#fillPickerSwatchBackground()}" alpha="${this.#fillPickerSwatchAlpha()}"${disabled ? " disabled" : ""}></fig-swatch>
8191
8197
  </fig-fill-picker>
8192
8198
  ${controlsHtml}
8193
8199
  </div>`;
@@ -8205,9 +8211,9 @@ class FigInputFill extends HTMLElement {
8205
8211
  // Label click triggers fill picker
8206
8212
  if (label && this.#fillPicker) {
8207
8213
  label.addEventListener("click", () => {
8208
- const chit = this.#fillPicker.querySelector("fig-chit");
8209
- if (chit) {
8210
- chit.click();
8214
+ const swatch = this.#fillPicker.querySelector("fig-swatch");
8215
+ if (swatch) {
8216
+ swatch.click();
8211
8217
  }
8212
8218
  });
8213
8219
  }
@@ -8307,8 +8313,8 @@ class FigInputFill extends HTMLElement {
8307
8313
  break;
8308
8314
  }
8309
8315
  this.#updateFillPicker();
8310
- // Update the chit's alpha
8311
- this.#updateChitAlpha(alpha);
8316
+ // Update the swatch's alpha
8317
+ this.#updateSwatchAlpha(alpha);
8312
8318
  this.#emitInput();
8313
8319
  });
8314
8320
  this.#opacityInput.addEventListener("change", (e) => {
@@ -8490,9 +8496,9 @@ class FigInputFill extends HTMLElement {
8490
8496
  // Label click triggers fill picker
8491
8497
  if (label && this.#fillPicker) {
8492
8498
  label.addEventListener("click", () => {
8493
- const chit = this.#fillPicker.querySelector("fig-chit");
8494
- if (chit) {
8495
- chit.click();
8499
+ const swatch = this.#fillPicker.querySelector("fig-swatch");
8500
+ if (swatch) {
8501
+ swatch.click();
8496
8502
  }
8497
8503
  });
8498
8504
  }
@@ -8536,7 +8542,7 @@ class FigInputFill extends HTMLElement {
8536
8542
  break;
8537
8543
  }
8538
8544
  this.#updateFillPicker();
8539
- this.#updateChitAlpha(alpha);
8545
+ this.#updateSwatchAlpha(alpha);
8540
8546
  this.#emitInput();
8541
8547
  });
8542
8548
  this.#opacityInput.addEventListener("change", (e) => {
@@ -8552,11 +8558,11 @@ class FigInputFill extends HTMLElement {
8552
8558
  }
8553
8559
  }
8554
8560
 
8555
- #updateChitAlpha(alpha) {
8561
+ #updateSwatchAlpha(alpha) {
8556
8562
  if (this.#fillPicker) {
8557
- const chit = this.#fillPicker.querySelector("fig-chit");
8558
- if (chit) {
8559
- chit.setAttribute("alpha", alpha);
8563
+ const swatch = this.#fillPicker.querySelector("fig-swatch");
8564
+ if (swatch) {
8565
+ swatch.setAttribute("alpha", alpha);
8560
8566
  }
8561
8567
  }
8562
8568
  }
@@ -9132,7 +9138,7 @@ customElements.define("fig-input-palette", FigInputPalette);
9132
9138
  */
9133
9139
  class FigInputGradient extends HTMLElement {
9134
9140
  static SHIFT_SNAP = 5;
9135
- #chit;
9141
+ #swatch;
9136
9142
  #track;
9137
9143
  #handleDragging = false;
9138
9144
  #arrowTooltipTimer = null;
@@ -9278,7 +9284,7 @@ class FigInputGradient extends HTMLElement {
9278
9284
  selected.showColorTip();
9279
9285
  }, 600);
9280
9286
  }
9281
- this.#syncChit();
9287
+ this.#syncSwatch();
9282
9288
  this.#emitInput();
9283
9289
  this.#emitChange();
9284
9290
  return;
@@ -9297,7 +9303,7 @@ class FigInputGradient extends HTMLElement {
9297
9303
  selected.removeAttribute("selected");
9298
9304
  this.#gradient.stops.splice(idx, 1);
9299
9305
  this.#syncHandles();
9300
- this.#syncChit();
9306
+ this.#syncSwatch();
9301
9307
  this.#emitInput();
9302
9308
  this.#emitChange();
9303
9309
  };
@@ -9385,9 +9391,9 @@ class FigInputGradient extends HTMLElement {
9385
9391
  const gradientValue = JSON.stringify(this.value);
9386
9392
  this.innerHTML = `
9387
9393
  <fig-fill-picker mode="gradient"${expAttr} value='${gradientValue}'${disabled ? " disabled" : ""}>
9388
- <fig-chit background="${this.#buildGradientCSS()}"${disabled ? " disabled" : ""}></fig-chit>
9394
+ <fig-swatch background="${this.#buildGradientCSS()}"${disabled ? " disabled" : ""}></fig-swatch>
9389
9395
  </fig-fill-picker>`;
9390
- this.#chit = this.querySelector("fig-chit");
9396
+ this.#swatch = this.querySelector("fig-swatch");
9391
9397
  this.#track = null;
9392
9398
  this.#setupPickerEvents();
9393
9399
  this.#syncFocusTarget();
@@ -9395,9 +9401,9 @@ class FigInputGradient extends HTMLElement {
9395
9401
  }
9396
9402
 
9397
9403
  this.innerHTML = `
9398
- <fig-chit background="${this.#buildGradientCSS()}"${disabled ? " disabled" : ""}></fig-chit>
9404
+ <fig-swatch background="${this.#buildGradientCSS()}"${disabled ? " disabled" : ""}></fig-swatch>
9399
9405
  ${mode === "true" || mode === "picker" ? `<div class="fig-input-gradient-track">${this.#buildStopHandles()}</div>` : ""}`;
9400
- this.#chit = this.querySelector("fig-chit");
9406
+ this.#swatch = this.querySelector("fig-swatch");
9401
9407
  this.#track = this.querySelector(".fig-input-gradient-track");
9402
9408
 
9403
9409
  if (mode === "true" || mode === "picker") {
@@ -9420,7 +9426,7 @@ class FigInputGradient extends HTMLElement {
9420
9426
  ...this.#gradient,
9421
9427
  ...detail.gradient,
9422
9428
  });
9423
- this.#syncChit();
9429
+ this.#syncSwatch();
9424
9430
  };
9425
9431
 
9426
9432
  picker.addEventListener("input", (e) => {
@@ -9514,7 +9520,7 @@ class FigInputGradient extends HTMLElement {
9514
9520
  this.#gradient.stops[i].position = Math.round((i / (count - 1)) * 100);
9515
9521
  }
9516
9522
  this.#syncHandles();
9517
- this.#syncChit();
9523
+ this.#syncSwatch();
9518
9524
  this.#emitInput();
9519
9525
  this.#emitChange();
9520
9526
  }
@@ -9565,7 +9571,7 @@ class FigInputGradient extends HTMLElement {
9565
9571
  (s) => s.position === position && s.color === color,
9566
9572
  );
9567
9573
  this.#syncHandles();
9568
- this.#syncChit();
9574
+ this.#syncSwatch();
9569
9575
  this.#emitInput();
9570
9576
  this.#emitChange();
9571
9577
 
@@ -9702,9 +9708,9 @@ class FigInputGradient extends HTMLElement {
9702
9708
  });
9703
9709
  }
9704
9710
 
9705
- #syncChit() {
9706
- if (!this.#chit) return;
9707
- this.#chit.setAttribute("background", this.#buildGradientCSS());
9711
+ #syncSwatch() {
9712
+ if (!this.#swatch) return;
9713
+ this.#swatch.setAttribute("background", this.#buildGradientCSS());
9708
9714
  }
9709
9715
 
9710
9716
  #setupEventListeners() {
@@ -9731,7 +9737,7 @@ class FigInputGradient extends HTMLElement {
9731
9737
  );
9732
9738
  this.#addedOnPointerDown = true;
9733
9739
  this.#syncHandles();
9734
- this.#syncChit();
9740
+ this.#syncSwatch();
9735
9741
  this.#emitInput();
9736
9742
  this.#hideGhost();
9737
9743
 
@@ -9775,7 +9781,7 @@ class FigInputGradient extends HTMLElement {
9775
9781
  "color",
9776
9782
  this.#stopColorCSS(this.#gradient.stops[idx]),
9777
9783
  );
9778
- this.#syncChit();
9784
+ this.#syncSwatch();
9779
9785
  this.#emitInput();
9780
9786
  }
9781
9787
  return;
@@ -9816,7 +9822,7 @@ class FigInputGradient extends HTMLElement {
9816
9822
  handle.hideColorTip();
9817
9823
  }
9818
9824
  }
9819
- this.#syncChit();
9825
+ this.#syncSwatch();
9820
9826
  this.#emitInput();
9821
9827
  });
9822
9828
 
@@ -9835,7 +9841,7 @@ class FigInputGradient extends HTMLElement {
9835
9841
  "color",
9836
9842
  this.#stopColorCSS(this.#gradient.stops[idx]),
9837
9843
  );
9838
- this.#syncChit();
9844
+ this.#syncSwatch();
9839
9845
  this.#emitChange();
9840
9846
  }
9841
9847
  return;
@@ -9861,7 +9867,7 @@ class FigInputGradient extends HTMLElement {
9861
9867
  handle.style.left = `${(position / 100) * trackW}px`;
9862
9868
  this.#gradient.stops.sort((a, b) => a.position - b.position);
9863
9869
  this.#syncStopIndices();
9864
- this.#syncChit();
9870
+ this.#syncSwatch();
9865
9871
  this.#emitChange();
9866
9872
  requestAnimationFrame(() => {
9867
9873
  this.#handleDragging = false;
@@ -9879,7 +9885,7 @@ class FigInputGradient extends HTMLElement {
9879
9885
  if (!newColor || !newColor.startsWith("#")) continue;
9880
9886
  if (newColor !== this.#gradient.stops[idx].color) {
9881
9887
  this.#gradient.stops[idx].color = newColor;
9882
- this.#syncChit();
9888
+ this.#syncSwatch();
9883
9889
  this.#emitInput();
9884
9890
  }
9885
9891
  }
@@ -9944,7 +9950,7 @@ class FigInputGradient extends HTMLElement {
9944
9950
  switch (name) {
9945
9951
  case "value":
9946
9952
  this.#parseValue();
9947
- this.#syncChit();
9953
+ this.#syncSwatch();
9948
9954
  this.#syncHandles();
9949
9955
  break;
9950
9956
  case "disabled":
@@ -9967,9 +9973,9 @@ class FigInputGradient extends HTMLElement {
9967
9973
  #syncDisabled() {
9968
9974
  const disabled = this.hasAttribute("disabled");
9969
9975
  this.#syncFocusTarget();
9970
- if (this.#chit) {
9971
- if (disabled) this.#chit.setAttribute("disabled", "");
9972
- else this.#chit.removeAttribute("disabled");
9976
+ if (this.#swatch) {
9977
+ if (disabled) this.#swatch.setAttribute("disabled", "");
9978
+ else this.#swatch.removeAttribute("disabled");
9973
9979
  }
9974
9980
  if (this.#track) {
9975
9981
  for (const handle of this.#track.querySelectorAll("fig-handle")) {
@@ -10507,7 +10513,7 @@ class FigComboInput extends HTMLElement {
10507
10513
  }
10508
10514
  customElements.define("fig-combo-input", FigComboInput);
10509
10515
 
10510
- /* Chit */
10516
+ /* Swatch */
10511
10517
  /**
10512
10518
  * A color/gradient/image swatch element.
10513
10519
  * @attr {string} background - Any CSS background value: color (#FF0000, rgba(...)), gradient (linear-gradient(...)), or image (url(...))
@@ -10516,7 +10522,7 @@ customElements.define("fig-combo-input", FigComboInput);
10516
10522
  * @attr {boolean} disabled - Whether the chip is disabled
10517
10523
  * @attr {number} alpha - Opacity value (0-1) to display the color with transparency
10518
10524
  */
10519
- class FigChit extends HTMLElement {
10525
+ class FigSwatch extends HTMLElement {
10520
10526
  #type = "color"; // 'color', 'gradient', 'image'
10521
10527
  #boundHandleInput = null;
10522
10528
  #internalUpdate = false; // Flag to prevent re-render during internal input
@@ -10627,7 +10633,7 @@ class FigChit extends HTMLElement {
10627
10633
  rawBg,
10628
10634
  );
10629
10635
  this.style.setProperty(
10630
- "--chit-background",
10636
+ "--swatch-background",
10631
10637
  isImage ? rawBg : `linear-gradient(${rawBg}, ${rawBg})`,
10632
10638
  );
10633
10639
  }
@@ -10691,7 +10697,7 @@ class FigChit extends HTMLElement {
10691
10697
  newValue,
10692
10698
  );
10693
10699
  this.style.setProperty(
10694
- "--chit-background",
10700
+ "--swatch-background",
10695
10701
  isImg ? newValue : `linear-gradient(${newValue}, ${newValue})`,
10696
10702
  );
10697
10703
  return;
@@ -10721,8 +10727,6 @@ class FigChit extends HTMLElement {
10721
10727
  }
10722
10728
  }
10723
10729
  }
10724
- customElements.define("fig-chit", FigChit);
10725
- class FigSwatch extends FigChit {}
10726
10730
  customElements.define("fig-swatch", FigSwatch);
10727
10731
 
10728
10732
  /* Media */
@@ -10860,7 +10864,7 @@ class FigMedia extends HTMLElement {
10860
10864
  this.style.setProperty("--fig-media-fit", fit);
10861
10865
  }
10862
10866
 
10863
- this.querySelectorAll("fig-chit[data-generated]").forEach((el) => el.remove());
10867
+ this.querySelectorAll("fig-swatch[data-generated]").forEach((el) => el.remove());
10864
10868
  this.#ensurePreviewElement();
10865
10869
  this.#ensureMediaElement();
10866
10870
  this.#syncGeneratedMediaElement();
@@ -14707,8 +14711,8 @@ customElements.define("fig-input-combo", FigInputCombo);
14707
14711
  */
14708
14712
  class FigColorTip extends HTMLElement {
14709
14713
  #fillPicker = null;
14710
- #chit = null;
14711
- #chitSelectedObserver = null;
14714
+ #swatch = null;
14715
+ #swatchSelectedObserver = null;
14712
14716
  #boundHandleInput = this.#handlePickerInput.bind(this);
14713
14717
  #boundHandleChange = this.#handlePickerChange.bind(this);
14714
14718
 
@@ -14744,33 +14748,33 @@ class FigColorTip extends HTMLElement {
14744
14748
  this.#fillPicker.removeEventListener("input", this.#boundHandleInput);
14745
14749
  this.#fillPicker.removeEventListener("change", this.#boundHandleChange);
14746
14750
  }
14747
- if (this.#chit) {
14748
- this.#chit.removeEventListener("input", this.#boundHandleInput);
14749
- this.#chit.removeEventListener("change", this.#boundHandleChange);
14751
+ if (this.#swatch) {
14752
+ this.#swatch.removeEventListener("input", this.#boundHandleInput);
14753
+ this.#swatch.removeEventListener("change", this.#boundHandleChange);
14750
14754
  }
14751
- if (this.#chitSelectedObserver) {
14752
- this.#chitSelectedObserver.disconnect();
14753
- this.#chitSelectedObserver = null;
14755
+ if (this.#swatchSelectedObserver) {
14756
+ this.#swatchSelectedObserver.disconnect();
14757
+ this.#swatchSelectedObserver = null;
14754
14758
  }
14755
14759
  }
14756
14760
 
14757
- #observeChitSelected() {
14758
- if (this.#chitSelectedObserver) {
14759
- this.#chitSelectedObserver.disconnect();
14760
- this.#chitSelectedObserver = null;
14761
+ #observeSwatchSelected() {
14762
+ if (this.#swatchSelectedObserver) {
14763
+ this.#swatchSelectedObserver.disconnect();
14764
+ this.#swatchSelectedObserver = null;
14761
14765
  }
14762
- if (!this.#chit) return;
14763
- this.#chitSelectedObserver = new MutationObserver(() => {
14764
- const chitSelected =
14765
- this.#chit?.hasAttribute("selected") &&
14766
- this.#chit.getAttribute("selected") !== "false";
14767
- if (chitSelected) {
14766
+ if (!this.#swatch) return;
14767
+ this.#swatchSelectedObserver = new MutationObserver(() => {
14768
+ const swatchSelected =
14769
+ this.#swatch?.hasAttribute("selected") &&
14770
+ this.#swatch.getAttribute("selected") !== "false";
14771
+ if (swatchSelected) {
14768
14772
  if (!this.hasAttribute("selected")) this.setAttribute("selected", "");
14769
14773
  } else if (this.hasAttribute("selected")) {
14770
14774
  this.removeAttribute("selected");
14771
14775
  }
14772
14776
  });
14773
- this.#chitSelectedObserver.observe(this.#chit, {
14777
+ this.#swatchSelectedObserver.observe(this.#swatch, {
14774
14778
  attributes: true,
14775
14779
  attributeFilter: ["selected"],
14776
14780
  });
@@ -14788,7 +14792,7 @@ class FigColorTip extends HTMLElement {
14788
14792
  const label = this.getAttribute("aria-label") || (mode === "add" ? "Add color stop" : "Remove color stop");
14789
14793
  this.innerHTML = `<fig-button icon variant="ghost" aria-label="${label}"><fig-icon name="${iconName}"></fig-icon></fig-button>`;
14790
14794
  this.#fillPicker = null;
14791
- this.#chit = null;
14795
+ this.#swatch = null;
14792
14796
  this.addEventListener("click", this.#handleControlClick);
14793
14797
  this.#syncA11y();
14794
14798
  return;
@@ -14807,23 +14811,23 @@ class FigColorTip extends HTMLElement {
14807
14811
  opacity: Math.round(alpha * 100),
14808
14812
  })
14809
14813
  : JSON.stringify({ type: "solid", color });
14810
- const chitAlphaAttr = alpha < 1 ? ` alpha="${alpha}"` : "";
14814
+ const swatchAlphaAttr = alpha < 1 ? ` alpha="${alpha}"` : "";
14811
14815
  this.innerHTML = hasFigFillPicker()
14812
14816
  ? `<fig-fill-picker mode="solid" ${alphaAttr} value='${pickerValue}'>
14813
- <fig-chit background="${color}"${chitAlphaAttr}></fig-chit>
14817
+ <fig-swatch background="${color}"${swatchAlphaAttr}></fig-swatch>
14814
14818
  </fig-fill-picker>`
14815
- : `<fig-chit background="${color}"${chitAlphaAttr}></fig-chit>`;
14819
+ : `<fig-swatch background="${color}"${swatchAlphaAttr}></fig-swatch>`;
14816
14820
 
14817
14821
  this.#fillPicker = this.querySelector("fig-fill-picker");
14818
- this.#chit = this.querySelector("fig-chit");
14822
+ this.#swatch = this.querySelector("fig-swatch");
14819
14823
  this.#teardownListeners();
14820
14824
  this.#fillPicker?.addEventListener("input", this.#boundHandleInput);
14821
14825
  this.#fillPicker?.addEventListener("change", this.#boundHandleChange);
14822
14826
  if (!this.#fillPicker) {
14823
- this.#chit?.addEventListener("input", this.#boundHandleInput);
14824
- this.#chit?.addEventListener("change", this.#boundHandleChange);
14827
+ this.#swatch?.addEventListener("input", this.#boundHandleInput);
14828
+ this.#swatch?.addEventListener("change", this.#boundHandleChange);
14825
14829
  }
14826
- this.#observeChitSelected();
14830
+ this.#observeSwatchSelected();
14827
14831
  this.#syncA11y();
14828
14832
  }
14829
14833
 
@@ -14938,18 +14942,18 @@ class FigColorTip extends HTMLElement {
14938
14942
  }
14939
14943
  }
14940
14944
 
14941
- if (this.#chit) {
14945
+ if (this.#swatch) {
14942
14946
  this.#syncA11y();
14943
- this.#chit.setAttribute("background", color);
14947
+ this.#swatch.setAttribute("background", color);
14944
14948
  if (alpha < 1) {
14945
- this.#chit.setAttribute("alpha", String(alpha));
14949
+ this.#swatch.setAttribute("alpha", String(alpha));
14946
14950
  } else {
14947
- this.#chit.removeAttribute("alpha");
14951
+ this.#swatch.removeAttribute("alpha");
14948
14952
  }
14949
14953
  if (this.hasAttribute("disabled")) {
14950
- this.#chit.setAttribute("disabled", "");
14954
+ this.#swatch.setAttribute("disabled", "");
14951
14955
  } else {
14952
- this.#chit.removeAttribute("disabled");
14956
+ this.#swatch.removeAttribute("disabled");
14953
14957
  }
14954
14958
  }
14955
14959
  }
@@ -14971,7 +14975,7 @@ class FigColorTip extends HTMLElement {
14971
14975
  return;
14972
14976
  }
14973
14977
 
14974
- const target = this.#fillPicker || this.#chit;
14978
+ const target = this.#fillPicker || this.#swatch;
14975
14979
  if (!target) return;
14976
14980
  const label = this.getAttribute("aria-label") || "Color stop";
14977
14981
  const labelledBy = this.getAttribute("aria-labelledby");
@@ -16706,20 +16710,23 @@ customElements.define("fig-menu-separator", FigMenuSeparator);
16706
16710
  class FigMenu extends HTMLElement {
16707
16711
  #popup = null;
16708
16712
  #trigger = null;
16713
+ #virtualAnchor = null;
16709
16714
  #observer = null;
16710
16715
  #boundTriggerClick;
16716
+ #boundTriggerContextMenu;
16711
16717
  #boundPopupClick;
16712
16718
  #boundMenuKeydown;
16713
16719
  #boundPopupClose;
16714
16720
  #focusedIndex = -1;
16715
16721
 
16716
16722
  static get observedAttributes() {
16717
- return ["position", "offset", "closedby", "disabled", "open"];
16723
+ return ["position", "offset", "closedby", "disabled", "open", "trigger"];
16718
16724
  }
16719
16725
 
16720
16726
  constructor() {
16721
16727
  super();
16722
16728
  this.#boundTriggerClick = this.#handleTriggerClick.bind(this);
16729
+ this.#boundTriggerContextMenu = this.#handleTriggerContextMenu.bind(this);
16723
16730
  this.#boundPopupClick = this.#handlePopupClick.bind(this);
16724
16731
  this.#boundMenuKeydown = this.#handleMenuKeydown.bind(this);
16725
16732
  this.#boundPopupClose = this.#handlePopupClose.bind(this);
@@ -16810,6 +16817,11 @@ class FigMenu extends HTMLElement {
16810
16817
  this.querySelector(":scope > :not(fig-menu-item):not(fig-menu-separator)");
16811
16818
  }
16812
16819
 
16820
+ #usesContextMenuTrigger() {
16821
+ const trigger = (this.getAttribute("trigger") || "").toLowerCase();
16822
+ return trigger === "contextmenu" || this.hasAttribute("contextmenu");
16823
+ }
16824
+
16813
16825
  #createPopup() {
16814
16826
  this.#popup = document.createElement("dialog", { is: "fig-popup" });
16815
16827
  this.#popup.setAttribute("is", "fig-popup");
@@ -16847,6 +16859,7 @@ class FigMenu extends HTMLElement {
16847
16859
  this.addEventListener("keydown", this.#boundMenuKeydown);
16848
16860
  if (this.#trigger) {
16849
16861
  this.#trigger.addEventListener("click", this.#boundTriggerClick);
16862
+ this.#trigger.addEventListener("contextmenu", this.#boundTriggerContextMenu);
16850
16863
  this.#trigger.setAttribute("aria-haspopup", "menu");
16851
16864
  this.#trigger.setAttribute("aria-expanded", "false");
16852
16865
  this.#trigger.setAttribute("aria-controls", this.#popup.getAttribute("id"));
@@ -16861,6 +16874,7 @@ class FigMenu extends HTMLElement {
16861
16874
  this.removeEventListener("keydown", this.#boundMenuKeydown);
16862
16875
  if (this.#trigger) {
16863
16876
  this.#trigger.removeEventListener("click", this.#boundTriggerClick);
16877
+ this.#trigger.removeEventListener("contextmenu", this.#boundTriggerContextMenu);
16864
16878
  }
16865
16879
  if (this.#popup) {
16866
16880
  this.#popup.removeEventListener("click", this.#boundPopupClick);
@@ -16882,6 +16896,7 @@ class FigMenu extends HTMLElement {
16882
16896
  this.#detectTrigger();
16883
16897
  if (this.#trigger) {
16884
16898
  this.#trigger.addEventListener("click", this.#boundTriggerClick);
16899
+ this.#trigger.addEventListener("contextmenu", this.#boundTriggerContextMenu);
16885
16900
  this.#trigger.setAttribute("aria-haspopup", "menu");
16886
16901
  this.#trigger.setAttribute("aria-expanded", "false");
16887
16902
  this.#trigger.setAttribute("aria-controls", this.#popup.getAttribute("id"));
@@ -16938,6 +16953,7 @@ class FigMenu extends HTMLElement {
16938
16953
  }
16939
16954
 
16940
16955
  #handleTriggerClick(e) {
16956
+ if (this.#usesContextMenuTrigger()) return;
16941
16957
  if (this.hasAttribute("disabled") && this.getAttribute("disabled") !== "false") return;
16942
16958
  e.stopPropagation();
16943
16959
  const popupShowing = this.#popup?.matches?.(":open") ?? false;
@@ -16948,10 +16964,40 @@ class FigMenu extends HTMLElement {
16948
16964
  if (effectiveOpen) {
16949
16965
  this.open = false;
16950
16966
  } else {
16967
+ if (this.#popup && this.#trigger) {
16968
+ this.#popup.anchor = this.#trigger;
16969
+ }
16951
16970
  this.open = true;
16952
16971
  }
16953
16972
  }
16954
16973
 
16974
+ #handleTriggerContextMenu(e) {
16975
+ if (!this.#usesContextMenuTrigger()) return;
16976
+ if (this.hasAttribute("disabled") && this.getAttribute("disabled") !== "false") return;
16977
+ e.preventDefault();
16978
+ e.stopPropagation();
16979
+ this.#showAtAfterPointerRelease(e.clientX, e.clientY);
16980
+ }
16981
+
16982
+ #showAtAfterPointerRelease(x, y) {
16983
+ let opened = false;
16984
+ let fallbackTimer = 0;
16985
+ const openMenu = () => {
16986
+ if (opened) return;
16987
+ opened = true;
16988
+ window.clearTimeout(fallbackTimer);
16989
+ window.removeEventListener("pointerup", openMenu, true);
16990
+ window.removeEventListener("pointercancel", openMenu, true);
16991
+ requestAnimationFrame(() => this.showAt(x, y));
16992
+ };
16993
+ window.addEventListener("pointerup", openMenu, { once: true, capture: true });
16994
+ window.addEventListener("pointercancel", openMenu, {
16995
+ once: true,
16996
+ capture: true,
16997
+ });
16998
+ fallbackTimer = window.setTimeout(openMenu, 180);
16999
+ }
17000
+
16955
17001
  #handlePopupClick(e) {
16956
17002
  const item = e.target.closest("fig-menu-item");
16957
17003
  if (!item) return;
@@ -16969,6 +17015,9 @@ class FigMenu extends HTMLElement {
16969
17015
  (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ")
16970
17016
  ) {
16971
17017
  e.preventDefault();
17018
+ if (this.#popup && this.#trigger) {
17019
+ this.#popup.anchor = this.#trigger;
17020
+ }
16972
17021
  this.open = true;
16973
17022
  requestAnimationFrame(() => this.#focusItemAt(0));
16974
17023
  }
@@ -17042,6 +17091,28 @@ class FigMenu extends HTMLElement {
17042
17091
  this.open = false;
17043
17092
  }
17044
17093
 
17094
+ showAt(x, y) {
17095
+ this.#virtualAnchor = {
17096
+ getBoundingClientRect: () => ({
17097
+ width: 0,
17098
+ height: 0,
17099
+ top: y,
17100
+ right: x,
17101
+ bottom: y,
17102
+ left: x,
17103
+ x,
17104
+ y,
17105
+ }),
17106
+ };
17107
+ if (this.#popup) {
17108
+ this.#popup.anchor = this.#virtualAnchor;
17109
+ }
17110
+ if (this.open) this.open = false;
17111
+ requestAnimationFrame(() => {
17112
+ this.open = true;
17113
+ });
17114
+ }
17115
+
17045
17116
  #openMenu() {
17046
17117
  if (!this.#popup) return;
17047
17118
  this.#popup.open = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "6.9.3",
3
+ "version": "6.9.5",
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",