@rogieking/figui3 3.7.0 → 3.8.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.
package/fig.js CHANGED
@@ -6694,6 +6694,8 @@ class FigEasingCurve extends HTMLElement {
6694
6694
  const size = 200;
6695
6695
  const dropdown = this.#getDropdownHTML();
6696
6696
 
6697
+ const hs = this.#bezierHandleRadius * 2;
6698
+
6697
6699
  if (this.#mode === "spring") {
6698
6700
  const targetY = 40;
6699
6701
  const startY = 180;
@@ -6702,8 +6704,8 @@ class FigEasingCurve extends HTMLElement {
6702
6704
  <line class="fig-easing-curve-target" x1="0" y1="${targetY}" x2="${size}" y2="${targetY}"/>
6703
6705
  <line class="fig-easing-curve-diagonal" x1="0" y1="${startY}" x2="0" y2="${startY}"/>
6704
6706
  <path class="fig-easing-curve-path"/>
6705
- <circle class="fig-easing-curve-handle" data-handle="bounce" r="${this.#springHandleRadius}"/>
6706
- <rect class="fig-easing-curve-duration-bar" data-handle="duration" width="${this.#durationBarWidth}" height="${this.#durationBarHeight}" rx="${this.#durationBarRadius}" ry="${this.#durationBarRadius}"/>
6707
+ <foreignObject class="fig-easing-curve-handle" data-handle="bounce" width="${hs}" height="${hs}"><fig-handle></fig-handle></foreignObject>
6708
+ <foreignObject class="fig-easing-curve-handle fig-easing-curve-duration-bar" data-handle="duration" width="${this.#durationBarWidth}" height="${this.#durationBarHeight}"><fig-handle></fig-handle></foreignObject>
6707
6709
  </svg></div>`;
6708
6710
  }
6709
6711
 
@@ -6715,8 +6717,8 @@ class FigEasingCurve extends HTMLElement {
6715
6717
  <path class="fig-easing-curve-path"/>
6716
6718
  <circle class="fig-easing-curve-endpoint" data-endpoint="start" r="${this.#bezierEndpointRadius}"/>
6717
6719
  <circle class="fig-easing-curve-endpoint" data-endpoint="end" r="${this.#bezierEndpointRadius}"/>
6718
- <circle class="fig-easing-curve-handle" data-handle="1" r="${this.#bezierHandleRadius}"/>
6719
- <circle class="fig-easing-curve-handle" data-handle="2" r="${this.#bezierHandleRadius}"/>
6720
+ <foreignObject class="fig-easing-curve-handle" data-handle="1" width="${hs}" height="${hs}"><fig-handle></fig-handle></foreignObject>
6721
+ <foreignObject class="fig-easing-curve-handle" data-handle="2" width="${hs}" height="${hs}"><fig-handle></fig-handle></foreignObject>
6720
6722
  </svg></div>`;
6721
6723
  }
6722
6724
 
@@ -6860,10 +6862,11 @@ class FigEasingCurve extends HTMLElement {
6860
6862
  this.#line2.setAttribute("y1", p3.y);
6861
6863
  this.#line2.setAttribute("x2", p2.x);
6862
6864
  this.#line2.setAttribute("y2", p2.y);
6863
- this.#handle1.setAttribute("cx", p1.x);
6864
- this.#handle1.setAttribute("cy", p1.y);
6865
- this.#handle2.setAttribute("cx", p2.x);
6866
- this.#handle2.setAttribute("cy", p2.y);
6865
+ const hr = this.#bezierHandleRadius;
6866
+ this.#handle1.setAttribute("x", p1.x - hr);
6867
+ this.#handle1.setAttribute("y", p1.y - hr);
6868
+ this.#handle2.setAttribute("x", p2.x - hr);
6869
+ this.#handle2.setAttribute("y", p2.y - hr);
6867
6870
  if (this.#bezierEndpointStart) {
6868
6871
  this.#bezierEndpointStart.setAttribute("cx", p0.x);
6869
6872
  this.#bezierEndpointStart.setAttribute("cy", p0.y);
@@ -6930,8 +6933,9 @@ class FigEasingCurve extends HTMLElement {
6930
6933
  const peak = this.#findPeakOvershoot(points);
6931
6934
  const peakNorm = (peak.t / totalTime) * durationNorm;
6932
6935
  const peakPt = this.#springToSVG(peakNorm, peak.value);
6933
- this.#handle1.setAttribute("cx", peakPt.x);
6934
- this.#handle1.setAttribute("cy", peakPt.y);
6936
+ const hr = this.#bezierHandleRadius;
6937
+ this.#handle1.setAttribute("x", peakPt.x - hr);
6938
+ this.#handle1.setAttribute("y", peakPt.y - hr);
6935
6939
 
6936
6940
  // Duration handle: on the target line
6937
6941
  const targetPt = this.#springToSVG(durationNorm, 1);
@@ -7023,8 +7027,7 @@ class FigEasingCurve extends HTMLElement {
7023
7027
  );
7024
7028
  if (bezierSurface) {
7025
7029
  bezierSurface.addEventListener("pointerdown", (e) => {
7026
- // Handles keep their own direct drag behavior.
7027
- if (e.target?.closest?.(".fig-easing-curve-handle")) return;
7030
+ if (e.target?.closest?.(".fig-easing-curve-handle, fig-handle")) return;
7028
7031
  this.#startBezierDrag(e, this.#bezierHandleForClientHalf(e));
7029
7032
  });
7030
7033
  }
@@ -7043,8 +7046,7 @@ class FigEasingCurve extends HTMLElement {
7043
7046
  );
7044
7047
  if (springSurface) {
7045
7048
  springSurface.addEventListener("pointerdown", (e) => {
7046
- // Bounce handle keeps its own drag mode/cursor.
7047
- if (e.target?.closest?.(".fig-easing-curve-handle")) return;
7049
+ if (e.target?.closest?.(".fig-easing-curve-handle, fig-handle")) return;
7048
7050
  this.#startSpringDrag(e, "duration");
7049
7051
  });
7050
7052
  }
@@ -7719,14 +7721,14 @@ class FigOriginGrid extends HTMLElement {
7719
7721
  this.innerHTML = `<div class="fig-origin-grid-surface">
7720
7722
  <div class="origin-grid" aria-label="Transform origin grid">
7721
7723
  <div class="origin-grid-cells">${cells}</div>
7722
- <span class="origin-grid-handle"></span>
7724
+ <fig-handle></fig-handle>
7723
7725
  </div>
7724
7726
  </div>
7725
7727
  ${fieldsMarkup}`;
7726
7728
 
7727
7729
  this.#grid = this.querySelector(".origin-grid");
7728
7730
  this.#cells = Array.from(this.querySelectorAll(".origin-grid-cell"));
7729
- this.#handle = this.querySelector(".origin-grid-handle");
7731
+ this.#handle = this.querySelector("fig-handle");
7730
7732
  this.#xInput = this.querySelector('fig-input-number[name="x"]');
7731
7733
  this.#yInput = this.querySelector('fig-input-number[name="y"]');
7732
7734
  this.#syncHandlePosition();
@@ -8030,18 +8032,19 @@ class FigInputJoystick extends HTMLElement {
8030
8032
  #boundXFocusOut = null;
8031
8033
  #boundYFocusOut = null;
8032
8034
  #isSyncingValueAttr = false;
8035
+ #defaultPosition = { x: 0.5, y: 0.5 };
8033
8036
 
8034
8037
  constructor() {
8035
8038
  super();
8036
8039
 
8037
- this.position = { x: 0.5, y: 0.5 }; // Internal position (0-1)
8040
+ this.position = { x: 0.5, y: 0.5 };
8038
8041
  this.isDragging = false;
8039
8042
  this.isShiftHeld = false;
8040
8043
  this.plane = null;
8041
8044
  this.cursor = null;
8042
8045
  this.xInput = null;
8043
8046
  this.yInput = null;
8044
- this.coordinates = "screen"; // "screen" (0,0 top-left) or "math" (0,0 bottom-left)
8047
+ this.coordinates = "screen";
8045
8048
  this.#initialized = false;
8046
8049
  this.#boundMouseDown = (e) => this.#handleMouseDown(e);
8047
8050
  this.#boundTouchStart = (e) => this.#handleTouchStart(e);
@@ -8072,6 +8075,7 @@ class FigInputJoystick extends HTMLElement {
8072
8075
  this.#setupListeners();
8073
8076
  this.#syncHandlePosition();
8074
8077
  this.#syncValueAttribute();
8078
+ this.#syncResetButton();
8075
8079
  this.#initialized = true;
8076
8080
  });
8077
8081
  }
@@ -8151,8 +8155,13 @@ class FigInputJoystick extends HTMLElement {
8151
8155
  ${labelsMarkup}
8152
8156
  <div class="fig-input-joystick-plane">
8153
8157
  <div class="fig-input-joystick-guides"></div>
8154
- <div class="fig-input-joystick-handle"></div>
8158
+ <fig-handle></fig-handle>
8155
8159
  </div>
8160
+ <fig-tooltip text="Reset">
8161
+ <fig-button variant="ghost" icon="true" class="fig-joystick-reset" aria-label="Reset to default">
8162
+ <span class="fig-mask-icon" style="--icon: var(--icon-reset)"></span>
8163
+ </fig-button>
8164
+ </fig-tooltip>
8156
8165
  </div>
8157
8166
  ${
8158
8167
  this.#fieldsEnabled
@@ -8183,13 +8192,17 @@ class FigInputJoystick extends HTMLElement {
8183
8192
 
8184
8193
  #setupListeners() {
8185
8194
  this.plane = this.querySelector(".fig-input-joystick-plane");
8186
- this.cursor = this.querySelector(".fig-input-joystick-handle");
8195
+ this.cursor = this.querySelector("fig-handle");
8187
8196
  this.xInput = this.querySelector("fig-input-number[name='x']");
8188
8197
  this.yInput = this.querySelector("fig-input-number[name='y']");
8189
8198
  this.plane.addEventListener("mousedown", this.#boundMouseDown);
8190
8199
  this.plane.addEventListener("touchstart", this.#boundTouchStart);
8191
8200
  window.addEventListener("keydown", this.#boundKeyDown);
8192
8201
  window.addEventListener("keyup", this.#boundKeyUp);
8202
+ const resetBtn = this.querySelector(".fig-joystick-reset");
8203
+ if (resetBtn) {
8204
+ resetBtn.addEventListener("click", () => this.#resetToDefault());
8205
+ }
8193
8206
  if (this.#fieldsEnabled && this.xInput && this.yInput) {
8194
8207
  this.xInput.addEventListener("input", this.#boundXInput);
8195
8208
  this.xInput.addEventListener("change", this.#boundXInput);
@@ -8318,13 +8331,33 @@ class FigInputJoystick extends HTMLElement {
8318
8331
 
8319
8332
  #syncValueAttribute() {
8320
8333
  const next = this.value;
8321
- if (this.getAttribute("value") === next) return;
8322
- this.#isSyncingValueAttr = true;
8323
- this.setAttribute("value", next);
8324
- this.#isSyncingValueAttr = false;
8334
+ if (this.getAttribute("value") !== next) {
8335
+ this.#isSyncingValueAttr = true;
8336
+ this.setAttribute("value", next);
8337
+ this.#isSyncingValueAttr = false;
8338
+ }
8339
+ this.#syncResetButton();
8340
+ }
8341
+
8342
+ #syncResetButton() {
8343
+ const d = this.#defaultPosition;
8344
+ const isDefault =
8345
+ Math.round(this.position.x * 100) === Math.round(d.x * 100) &&
8346
+ Math.round(this.position.y * 100) === Math.round(d.y * 100);
8347
+ this.toggleAttribute("default", isDefault);
8348
+ this.style.setProperty("--is-not-default", isDefault ? "0" : "1");
8349
+ }
8350
+
8351
+ #resetToDefault() {
8352
+ this.position = { ...this.#defaultPosition };
8353
+ this.#syncHandlePosition();
8354
+ this.#syncValueAttribute();
8355
+ this.#emitInputEvent();
8356
+ this.#emitChangeEvent();
8325
8357
  }
8326
8358
 
8327
8359
  #handleMouseDown(e) {
8360
+ if (e.target.closest(".fig-joystick-reset, fig-tooltip")) return;
8328
8361
  this.isDragging = true;
8329
8362
 
8330
8363
  this.#updatePosition(e);
@@ -8351,6 +8384,7 @@ class FigInputJoystick extends HTMLElement {
8351
8384
  }
8352
8385
 
8353
8386
  #handleTouchStart(e) {
8387
+ if (e.target.closest(".fig-joystick-reset, fig-tooltip")) return;
8354
8388
  e.preventDefault();
8355
8389
  this.isDragging = true;
8356
8390
  this.#updatePosition(e.touches[0]);
@@ -8419,6 +8453,7 @@ class FigInputJoystick extends HTMLElement {
8419
8453
  }
8420
8454
  if (this.#initialized) {
8421
8455
  this.#syncHandlePosition();
8456
+ this.#syncResetButton();
8422
8457
  }
8423
8458
  }
8424
8459
  attributeChangedCallback(name, oldValue, newValue) {
@@ -11310,3 +11345,11 @@ class FigChooser extends HTMLElement {
11310
11345
  }
11311
11346
  }
11312
11347
  customElements.define("fig-chooser", FigChooser);
11348
+
11349
+ /* Handle */
11350
+ class FigHandle extends HTMLElement {
11351
+ constructor() {
11352
+ super();
11353
+ }
11354
+ }
11355
+ customElements.define("fig-handle", FigHandle);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "3.7.0",
3
+ "version": "3.8.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",