@rogieking/figui3 3.13.0 → 3.13.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.
Files changed (3) hide show
  1. package/components.css +3 -5
  2. package/fig.js +73 -18
  3. package/package.json +1 -1
package/components.css CHANGED
@@ -4743,7 +4743,6 @@ fig-choice {
4743
4743
  }
4744
4744
 
4745
4745
  fig-handle {
4746
- contain: strict;
4747
4746
  --width: 0.75rem;
4748
4747
  --height: 0.75rem;
4749
4748
  --fill: var(--figma-color-bg-brand);
@@ -4786,10 +4785,9 @@ fig-handle {
4786
4785
  cursor: default;
4787
4786
  }
4788
4787
 
4789
- &[type="color"] {
4790
- contain: layout style;
4788
+ &[type="color"],
4789
+ &[add]:not([add="false"]) {
4791
4790
  overflow: visible;
4792
- position: relative;
4793
4791
 
4794
4792
  fig-color-tip {
4795
4793
  position: absolute;
@@ -4812,7 +4810,7 @@ fig-color-tip {
4812
4810
  place-items: center;
4813
4811
  overflow: visible;
4814
4812
  position: relative;
4815
- color: var(--text-primary);
4813
+ color: var(--figma-color-text);
4816
4814
  color-scheme: light only;
4817
4815
  aspect-ratio: 1 / 1;
4818
4816
  flex-shrink: 0;
package/fig.js CHANGED
@@ -5765,12 +5765,10 @@ class FigInputGradient extends HTMLElement {
5765
5765
 
5766
5766
  #setupGhostHandle() {
5767
5767
  if (!this.#track || this.hasAttribute("disabled")) return;
5768
- const tooltip = document.createElement("fig-tooltip");
5769
- tooltip.setAttribute("text", "Add color stop");
5770
- tooltip.setAttribute("action", "manual");
5771
5768
 
5772
5769
  const ghost = document.createElement("fig-handle");
5773
5770
  ghost.classList.add("fig-input-gradient-ghost");
5771
+ ghost.setAttribute("add", "");
5774
5772
  ghost.style.position = "absolute";
5775
5773
  ghost.style.top = "50%";
5776
5774
  ghost.style.transform = "translate(-50%, -50%)";
@@ -5778,10 +5776,9 @@ class FigInputGradient extends HTMLElement {
5778
5776
  ghost.style.opacity = "0";
5779
5777
  ghost.style.transition = "opacity 0.15s";
5780
5778
 
5781
- tooltip.appendChild(ghost);
5782
- this.#track.appendChild(tooltip);
5779
+ this.#track.appendChild(ghost);
5783
5780
  this.#ghostHandle = ghost;
5784
- this.#ghostTooltip = tooltip;
5781
+ this.#ghostTooltip = null;
5785
5782
 
5786
5783
  this.addEventListener("pointerenter", this.#onTrackEnter);
5787
5784
  this.addEventListener("pointermove", this.#onTrackMove);
@@ -5791,17 +5788,12 @@ class FigInputGradient extends HTMLElement {
5791
5788
 
5792
5789
  #showGhost() {
5793
5790
  if (!this.#ghostHandle) return;
5794
- this.#ghostHandle.style.opacity = "0.5";
5795
- if (this.#ghostTooltip) {
5796
- this.#ghostTooltip.render();
5797
- this.#ghostTooltip.showPopup();
5798
- }
5791
+ this.#ghostHandle.style.opacity = "1";
5799
5792
  }
5800
5793
 
5801
5794
  #hideGhost() {
5802
5795
  if (!this.#ghostHandle) return;
5803
5796
  this.#ghostHandle.style.opacity = "0";
5804
- if (this.#ghostTooltip) this.#ghostTooltip.hidePopup();
5805
5797
  }
5806
5798
 
5807
5799
  #onTrackEnter = () => {
@@ -5841,10 +5833,21 @@ class FigInputGradient extends HTMLElement {
5841
5833
  const color = this.#sampleGradientColor(pct);
5842
5834
  this.#gradient.stops.push({ position, color, opacity: 100 });
5843
5835
  this.#gradient.stops.sort((a, b) => a.position - b.position);
5836
+ const newIndex = this.#gradient.stops.findIndex(
5837
+ (s) => s.position === position && s.color === color,
5838
+ );
5844
5839
  this.#syncHandles();
5845
5840
  this.#syncFillPicker();
5846
5841
  this.#emitInput();
5847
5842
  this.#emitChange();
5843
+
5844
+ requestAnimationFrame(() => {
5845
+ const handles = this.#track.querySelectorAll(
5846
+ "fig-handle:not(.fig-input-gradient-ghost)",
5847
+ );
5848
+ const newHandle = handles[newIndex];
5849
+ if (newHandle) newHandle.click();
5850
+ });
5848
5851
  };
5849
5852
 
5850
5853
  #syncHandles() {
@@ -5855,9 +5858,9 @@ class FigInputGradient extends HTMLElement {
5855
5858
  const stops = this.#gradient.stops;
5856
5859
 
5857
5860
  if (handles.length !== stops.length) {
5858
- const wrapper = this.#ghostTooltip;
5861
+ const ghost = this.#ghostHandle;
5859
5862
  this.#track.innerHTML = this.#buildStopHandles();
5860
- if (wrapper) this.#track.appendChild(wrapper);
5863
+ if (ghost) this.#track.appendChild(ghost);
5861
5864
  this.#reobserveHandleColors();
5862
5865
  return;
5863
5866
  }
@@ -11879,7 +11882,12 @@ class FigColorTip extends HTMLElement {
11879
11882
  #boundHandleChange = this.#handlePickerChange.bind(this);
11880
11883
 
11881
11884
  static get observedAttributes() {
11882
- return ["value", "selected", "disabled", "alpha"];
11885
+ return ["value", "selected", "disabled", "alpha", "add"];
11886
+ }
11887
+
11888
+ get #isAddMode() {
11889
+ const v = this.getAttribute("add");
11890
+ return v !== null && v !== "false";
11883
11891
  }
11884
11892
 
11885
11893
  connectedCallback() {
@@ -11889,6 +11897,7 @@ class FigColorTip extends HTMLElement {
11889
11897
 
11890
11898
  disconnectedCallback() {
11891
11899
  this.#teardownListeners();
11900
+ this.removeEventListener("click", this.#handleAddClick);
11892
11901
  }
11893
11902
 
11894
11903
  #teardownListeners() {
@@ -11913,6 +11922,15 @@ class FigColorTip extends HTMLElement {
11913
11922
  }
11914
11923
 
11915
11924
  #render() {
11925
+ if (this.#isAddMode) {
11926
+ this.innerHTML = `<span class="fig-mask-icon" style="--icon: var(--icon-add)"></span>`;
11927
+ this.#fillPicker = null;
11928
+ this.#chit = null;
11929
+ this.addEventListener("click", this.#handleAddClick);
11930
+ return;
11931
+ }
11932
+ this.removeEventListener("click", this.#handleAddClick);
11933
+
11916
11934
  const color = this.#normalizeColor(this.getAttribute("value"));
11917
11935
  const alphaAttr = this.#alphaEnabled ? "" : 'alpha="false"';
11918
11936
  this.innerHTML = `
@@ -11931,6 +11949,12 @@ class FigColorTip extends HTMLElement {
11931
11949
  });
11932
11950
  }
11933
11951
 
11952
+ #handleAddClick = () => {
11953
+ this.dispatchEvent(
11954
+ new CustomEvent("add", { bubbles: true, composed: true }),
11955
+ );
11956
+ };
11957
+
11934
11958
  #normalizeHex(hex) {
11935
11959
  if (!hex) return "#D9D9D9";
11936
11960
  const raw = hex.replace("#", "").trim();
@@ -12059,6 +12083,9 @@ class FigColorTip extends HTMLElement {
12059
12083
  if (!this.isConnected) return;
12060
12084
 
12061
12085
  switch (name) {
12086
+ case "add":
12087
+ this.#render();
12088
+ break;
12062
12089
  case "value":
12063
12090
  case "selected":
12064
12091
  case "disabled":
@@ -12668,6 +12695,7 @@ class FigHandle extends HTMLElement {
12668
12695
  "drag-snapping",
12669
12696
  "value",
12670
12697
  "type",
12698
+ "add",
12671
12699
  ];
12672
12700
 
12673
12701
  #isDragging = false;
@@ -12676,6 +12704,10 @@ class FigHandle extends HTMLElement {
12676
12704
  #applyingValue = false;
12677
12705
  #colorTip = null;
12678
12706
 
12707
+ get #isAddMode() {
12708
+ return this.hasAttribute("add") && this.getAttribute("add") !== "false";
12709
+ }
12710
+
12679
12711
  get #dragEnabled() {
12680
12712
  const v = this.getAttribute("drag");
12681
12713
  return v !== null && v !== "false";
@@ -12806,6 +12838,7 @@ class FigHandle extends HTMLElement {
12806
12838
  document.addEventListener("pointerdown", this.#handleDeselect);
12807
12839
  const initial = this.getAttribute("value");
12808
12840
  if (initial) this.#applyValue(initial);
12841
+ if (this.#isAddMode) this.#showColorTip();
12809
12842
  }
12810
12843
 
12811
12844
  disconnectedCallback() {
@@ -12817,6 +12850,7 @@ class FigHandle extends HTMLElement {
12817
12850
 
12818
12851
  #handleSelect = (e) => {
12819
12852
  if (this.hasAttribute("disabled")) return;
12853
+ if (this.#isAddMode) return;
12820
12854
  if (this.#didDrag) {
12821
12855
  this.#didDrag = false;
12822
12856
  return;
@@ -12826,6 +12860,7 @@ class FigHandle extends HTMLElement {
12826
12860
  };
12827
12861
 
12828
12862
  #handleDeselect = (e) => {
12863
+ if (this.#isAddMode) return;
12829
12864
  if (this.contains(e.target)) return;
12830
12865
  if (this.#colorTip && e.target.closest?.("dialog, [popover]")) return;
12831
12866
  this.removeAttribute("selected");
@@ -12844,6 +12879,13 @@ class FigHandle extends HTMLElement {
12844
12879
  if (name === "value" && !this.#applyingValue && !this.#isDragging) {
12845
12880
  this.#applyValue(value);
12846
12881
  }
12882
+ if (name === "add") {
12883
+ if (this.#isAddMode) {
12884
+ this.#showColorTip();
12885
+ } else {
12886
+ this.#hideColorTip();
12887
+ }
12888
+ }
12847
12889
  }
12848
12890
 
12849
12891
  #syncDrag() {
@@ -12970,12 +13012,17 @@ class FigHandle extends HTMLElement {
12970
13012
  #showColorTip() {
12971
13013
  if (this.#colorTip) return;
12972
13014
  const tip = document.createElement("fig-color-tip");
12973
- tip.setAttribute("value", this.getAttribute("color") || "#D9D9D9");
12974
- tip.setAttribute("selected", "");
12975
- tip.setAttribute("alpha", "true");
13015
+ if (this.#isAddMode) {
13016
+ tip.setAttribute("add", "");
13017
+ } else {
13018
+ tip.setAttribute("value", this.getAttribute("color") || "#D9D9D9");
13019
+ tip.setAttribute("alpha", "true");
13020
+ tip.setAttribute("selected", "");
13021
+ }
12976
13022
  tip.addEventListener("pointerdown", (e) => e.stopPropagation());
12977
13023
  tip.addEventListener("input", this.#handleColorTipInput);
12978
13024
  tip.addEventListener("change", this.#handleColorTipChange);
13025
+ tip.addEventListener("add", this.#handleColorTipAdd);
12979
13026
  this.appendChild(tip);
12980
13027
  this.#colorTip = tip;
12981
13028
  }
@@ -12984,6 +13031,7 @@ class FigHandle extends HTMLElement {
12984
13031
  if (!this.#colorTip) return;
12985
13032
  this.#colorTip.removeEventListener("input", this.#handleColorTipInput);
12986
13033
  this.#colorTip.removeEventListener("change", this.#handleColorTipChange);
13034
+ this.#colorTip.removeEventListener("add", this.#handleColorTipAdd);
12987
13035
  this.#colorTip.remove();
12988
13036
  this.#colorTip = null;
12989
13037
  }
@@ -12998,6 +13046,13 @@ class FigHandle extends HTMLElement {
12998
13046
  if (e.detail?.color) this.setAttribute("color", e.detail.color);
12999
13047
  };
13000
13048
 
13049
+ #handleColorTipAdd = (e) => {
13050
+ e.stopPropagation();
13051
+ this.dispatchEvent(
13052
+ new CustomEvent("add", { bubbles: true, composed: true }),
13053
+ );
13054
+ };
13055
+
13001
13056
  #positionDetail(containerRect) {
13002
13057
  const hw = this.offsetWidth / 2;
13003
13058
  const hh = this.offsetHeight / 2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "3.13.0",
3
+ "version": "3.13.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",