@rogieking/figui3 3.14.0 → 3.14.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 +0 -6
  2. package/fig.js +89 -20
  3. package/package.json +1 -1
package/components.css CHANGED
@@ -3205,12 +3205,6 @@ fig-input-gradient {
3205
3205
  pointer-events: auto;
3206
3206
  cursor: default;
3207
3207
 
3208
- &.dragging {
3209
- fig-color-tip {
3210
- display: none;
3211
- }
3212
- }
3213
-
3214
3208
  &:hover {
3215
3209
  z-index: 5;
3216
3210
  }
package/fig.js CHANGED
@@ -591,6 +591,7 @@ class FigTooltip extends HTMLElement {
591
591
  this.#stopObserving();
592
592
  if (this.popup) {
593
593
  this.popup.remove();
594
+ this.popup = null;
594
595
  }
595
596
  // Remove the click outside listener if it was added
596
597
  if (this.action === "click") {
@@ -5694,6 +5695,7 @@ class FigInputGradient extends HTMLElement {
5694
5695
  #chit;
5695
5696
  #track;
5696
5697
  #handleDragging = false;
5698
+ #arrowTooltipTimer = null;
5697
5699
  #colorObserver = null;
5698
5700
  #gradient = {
5699
5701
  type: "linear",
@@ -5725,17 +5727,67 @@ class FigInputGradient extends HTMLElement {
5725
5727
  }
5726
5728
 
5727
5729
  #onKeyDown = (e) => {
5728
- if (e.key !== "Delete" && e.key !== "Backspace") return;
5729
5730
  const active = document.activeElement;
5730
- if (
5731
+ const isTyping =
5731
5732
  active &&
5732
5733
  (active.tagName === "INPUT" ||
5733
5734
  active.tagName === "TEXTAREA" ||
5734
- active.isContentEditable)
5735
- )
5735
+ active.isContentEditable);
5736
+ if (!this.#track) return;
5737
+
5738
+ if (e.key === "Tab" && !isTyping) {
5739
+ const selected = this.#track.querySelector(
5740
+ "fig-handle[selected]:not(.fig-input-gradient-ghost)",
5741
+ );
5742
+ if (!selected) return;
5743
+ e.preventDefault();
5744
+ const handles = [
5745
+ ...this.#track.querySelectorAll(
5746
+ "fig-handle:not(.fig-input-gradient-ghost)",
5747
+ ),
5748
+ ];
5749
+ const curIdx = handles.indexOf(selected);
5750
+ const next = e.shiftKey
5751
+ ? (curIdx - 1 + handles.length) % handles.length
5752
+ : (curIdx + 1) % handles.length;
5753
+ selected.deselect();
5754
+ handles[next].select();
5755
+ return;
5756
+ }
5757
+
5758
+ if ((e.key === "ArrowLeft" || e.key === "ArrowRight") && !isTyping) {
5759
+ const selected = this.#track.querySelector(
5760
+ "fig-handle[selected]:not(.fig-input-gradient-ghost)",
5761
+ );
5762
+ if (!selected) return;
5763
+ const idx = parseInt(selected.dataset.stopIndex, 10);
5764
+ if (isNaN(idx) || !this.#gradient.stops[idx]) return;
5765
+ e.preventDefault();
5766
+ const delta = (e.key === "ArrowRight" ? 1 : -1) * (e.shiftKey ? 10 : 1);
5767
+ const stop = this.#gradient.stops[idx];
5768
+ stop.position = Math.max(0, Math.min(100, stop.position + delta));
5769
+ selected.setAttribute("value", `${stop.position}% 50%`);
5770
+ const tip = selected.closest("fig-tooltip");
5771
+ if (tip) {
5772
+ tip.text = `${Math.round(stop.position)}%`;
5773
+ tip.setAttribute("show", "true");
5774
+ tip.showPopup();
5775
+ selected.hideColorTip();
5776
+ clearTimeout(this.#arrowTooltipTimer);
5777
+ this.#arrowTooltipTimer = setTimeout(() => {
5778
+ tip.removeAttribute("show");
5779
+ selected.showColorTip();
5780
+ }, 600);
5781
+ }
5782
+ this.#syncChit();
5783
+ this.#emitInput();
5784
+ this.#emitChange();
5736
5785
  return;
5786
+ }
5787
+
5788
+ if (e.key !== "Delete" && e.key !== "Backspace") return;
5789
+ if (isTyping) return;
5737
5790
  if (this.#gradient.stops.length <= 2) return;
5738
- if (!this.#track) return;
5739
5791
  const selected = this.#track.querySelector(
5740
5792
  "fig-handle[selected]:not(.fig-input-gradient-ghost)",
5741
5793
  );
@@ -6072,7 +6124,10 @@ class FigInputGradient extends HTMLElement {
6072
6124
  const tooltip = handle.closest("fig-tooltip");
6073
6125
  if (tooltip) {
6074
6126
  tooltip.text = `${Math.round(position)}%`;
6075
- if (!tooltip.hasAttribute("show")) tooltip.setAttribute("show", "true");
6127
+ if (!tooltip.hasAttribute("show")) {
6128
+ tooltip.setAttribute("show", "true");
6129
+ handle.hideColorTip();
6130
+ }
6076
6131
  }
6077
6132
  this.#syncChit();
6078
6133
  this.#emitInput();
@@ -6085,6 +6140,7 @@ class FigInputGradient extends HTMLElement {
6085
6140
  handle.style.zIndex = "";
6086
6141
  const tooltip = handle.closest("fig-tooltip");
6087
6142
  if (tooltip) tooltip.removeAttribute("show");
6143
+ handle.showColorTip();
6088
6144
  const idx = parseInt(handle.dataset.stopIndex, 10);
6089
6145
  if (isNaN(idx) || !this.#gradient.stops[idx]) return;
6090
6146
  const px = e.detail?.px ?? 0;
@@ -6104,17 +6160,8 @@ class FigInputGradient extends HTMLElement {
6104
6160
  this.#syncStopIndices();
6105
6161
  this.#syncChit();
6106
6162
  this.#emitChange();
6107
- const swallow = (evt) => {
6108
- evt.stopPropagation();
6109
- evt.preventDefault();
6110
- };
6111
- this.#track.addEventListener("click", swallow, {
6112
- capture: true,
6113
- once: true,
6114
- });
6115
6163
  requestAnimationFrame(() => {
6116
6164
  this.#handleDragging = false;
6117
- this.#track.removeEventListener("click", swallow, { capture: true });
6118
6165
  });
6119
6166
  });
6120
6167
 
@@ -13024,23 +13071,31 @@ class FigHandle extends HTMLElement {
13024
13071
  document.removeEventListener("pointerdown", this.#handleDeselect);
13025
13072
  }
13026
13073
 
13027
- #handleSelect = (e) => {
13074
+ select() {
13028
13075
  if (this.hasAttribute("disabled")) return;
13076
+ this.setAttribute("selected", "");
13077
+ if (this.getAttribute("type") === "color") this.#showColorTip();
13078
+ }
13079
+
13080
+ deselect() {
13081
+ this.removeAttribute("selected");
13082
+ this.#hideColorTip();
13083
+ }
13084
+
13085
+ #handleSelect = (e) => {
13029
13086
  if (this.#hasControlMode) return;
13030
13087
  if (this.#didDrag) {
13031
13088
  this.#didDrag = false;
13032
13089
  return;
13033
13090
  }
13034
- this.setAttribute("selected", "");
13035
- if (this.getAttribute("type") === "color") this.#showColorTip();
13091
+ this.select();
13036
13092
  };
13037
13093
 
13038
13094
  #handleDeselect = (e) => {
13039
13095
  if (this.#hasControlMode) return;
13040
13096
  if (this.contains(e.target)) return;
13041
13097
  if (this.#colorTip && e.target.closest?.("dialog, [popover]")) return;
13042
- this.removeAttribute("selected");
13043
- this.#hideColorTip();
13098
+ this.deselect();
13044
13099
  };
13045
13100
 
13046
13101
  attributeChangedCallback(name, _old, value) {
@@ -13144,6 +13199,7 @@ class FigHandle extends HTMLElement {
13144
13199
  if (!this.#didDrag) {
13145
13200
  this.classList.add("dragging");
13146
13201
  this.style.cursor = "grabbing";
13202
+ if (!this.hasAttribute("selected")) this.select();
13147
13203
  }
13148
13204
  this.#didDrag = true;
13149
13205
  clampAndApply(e.clientX, e.clientY, e.shiftKey);
@@ -13191,6 +13247,19 @@ class FigHandle extends HTMLElement {
13191
13247
  window.addEventListener("pointerup", onUp);
13192
13248
  }
13193
13249
 
13250
+ showColorTip() {
13251
+ if (this.#colorTip) {
13252
+ this.#colorTip.style.display = "";
13253
+ return;
13254
+ }
13255
+ this.#showColorTip();
13256
+ }
13257
+
13258
+ hideColorTip() {
13259
+ if (!this.#colorTip) return;
13260
+ this.#colorTip.style.display = "none";
13261
+ }
13262
+
13194
13263
  #showColorTip() {
13195
13264
  if (this.#colorTip) return;
13196
13265
  const tip = document.createElement("fig-color-tip");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "3.14.0",
3
+ "version": "3.14.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",