@rogieking/figui3 8.9.46 → 8.9.47

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-editor.js CHANGED
@@ -391,6 +391,7 @@ class FigSelectOptions extends HTMLElement {
391
391
  #navStart = null;
392
392
  #navEnd = null;
393
393
  #resizeObserver = null;
394
+ #mutationObserver = null;
394
395
  #boundSyncOverflow = this.syncOverflow.bind(this);
395
396
 
396
397
  connectedCallback() {
@@ -402,6 +403,13 @@ class FigSelectOptions extends HTMLElement {
402
403
  this.#resizeObserver?.disconnect();
403
404
  this.#resizeObserver = new ResizeObserver(() => this.syncOverflow());
404
405
  this.#resizeObserver.observe(this);
406
+ this.#mutationObserver?.disconnect();
407
+ this.#mutationObserver = new MutationObserver(() => {
408
+ if (!this.isConnected) return;
409
+ this.#ensureNavButtons();
410
+ this.syncOverflow();
411
+ });
412
+ this.#mutationObserver.observe(this, { childList: true });
405
413
  requestAnimationFrame(() => this.syncOverflow());
406
414
  }
407
415
 
@@ -409,6 +417,8 @@ class FigSelectOptions extends HTMLElement {
409
417
  this.removeEventListener("scroll", this.#boundSyncOverflow);
410
418
  this.#resizeObserver?.disconnect();
411
419
  this.#resizeObserver = null;
420
+ this.#mutationObserver?.disconnect();
421
+ this.#mutationObserver = null;
412
422
  this.#removeNavButtons();
413
423
  }
414
424
 
@@ -446,6 +456,7 @@ class FigSelectOptions extends HTMLElement {
446
456
  this.contains(this.#navStart) &&
447
457
  this.contains(this.#navEnd)
448
458
  ) {
459
+ this.#positionNavButtons();
449
460
  return;
450
461
  }
451
462
  this.#removeNavButtons();
@@ -458,8 +469,16 @@ class FigSelectOptions extends HTMLElement {
458
469
  });
459
470
  this.#navStart = buttons.start;
460
471
  this.#navEnd = buttons.end;
461
- this.prepend(this.#navStart);
462
- this.append(this.#navEnd);
472
+ this.#positionNavButtons();
473
+ }
474
+
475
+ #positionNavButtons() {
476
+ if (this.firstElementChild !== this.#navStart) {
477
+ this.prepend(this.#navStart);
478
+ }
479
+ if (this.lastElementChild !== this.#navEnd) {
480
+ this.append(this.#navEnd);
481
+ }
463
482
  }
464
483
 
465
484
  #removeNavButtons() {
package/fig.js CHANGED
@@ -4522,6 +4522,7 @@ class FigTabs extends HTMLElement {
4522
4522
  this.contains(this.#navStart) &&
4523
4523
  this.contains(this.#navEnd)
4524
4524
  ) {
4525
+ this.#positionNavButtons();
4525
4526
  return;
4526
4527
  }
4527
4528
 
@@ -4535,8 +4536,16 @@ class FigTabs extends HTMLElement {
4535
4536
  });
4536
4537
  this.#navStart = buttons.start;
4537
4538
  this.#navEnd = buttons.end;
4538
- this.prepend(this.#navStart);
4539
- this.append(this.#navEnd);
4539
+ this.#positionNavButtons();
4540
+ }
4541
+
4542
+ #positionNavButtons() {
4543
+ if (this.firstElementChild !== this.#navStart) {
4544
+ this.prepend(this.#navStart);
4545
+ }
4546
+ if (this.lastElementChild !== this.#navEnd) {
4547
+ this.append(this.#navEnd);
4548
+ }
4540
4549
  }
4541
4550
 
4542
4551
  #handleKeyDown(event) {
@@ -18261,6 +18270,7 @@ class FigChooser extends HTMLElement {
18261
18270
  this.contains(this.#navStart) &&
18262
18271
  this.contains(this.#navEnd)
18263
18272
  ) {
18273
+ this.#positionNavButtons();
18264
18274
  return;
18265
18275
  }
18266
18276
 
@@ -18279,9 +18289,16 @@ class FigChooser extends HTMLElement {
18279
18289
  });
18280
18290
  this.#navStart = buttons.start;
18281
18291
  this.#navEnd = buttons.end;
18292
+ this.#positionNavButtons();
18293
+ }
18282
18294
 
18283
- this.prepend(this.#navStart);
18284
- this.append(this.#navEnd);
18295
+ #positionNavButtons() {
18296
+ if (this.firstElementChild !== this.#navStart) {
18297
+ this.prepend(this.#navStart);
18298
+ }
18299
+ if (this.lastElementChild !== this.#navEnd) {
18300
+ this.append(this.#navEnd);
18301
+ }
18285
18302
  }
18286
18303
 
18287
18304
  #scrollByPage(direction) {
@@ -18403,6 +18420,10 @@ class FigChooser extends HTMLElement {
18403
18420
  figDefineElement("fig-chooser", FigChooser);
18404
18421
 
18405
18422
  /* Handle */
18423
+ /**
18424
+ * A draggable handle positioned within a drag surface.
18425
+ * @attr {number} precision - Decimal places for position values and pixel dragging (default 2).
18426
+ */
18406
18427
  class FigHandle extends HTMLElement {
18407
18428
  static observedAttributes = [
18408
18429
  "color",
@@ -18413,6 +18434,7 @@ class FigHandle extends HTMLElement {
18413
18434
  "drag-axes",
18414
18435
  "drag-snapping",
18415
18436
  "value",
18437
+ "precision",
18416
18438
  "type",
18417
18439
  "tip",
18418
18440
  "hit-area",
@@ -18495,13 +18517,37 @@ class FigHandle extends HTMLElement {
18495
18517
  const container = this.#getContainer();
18496
18518
  if (!container) return "0% 0%";
18497
18519
  const { px, py } = this.#positionDetail(container.getBoundingClientRect());
18498
- return `${Math.round(px * 100)}% ${Math.round(py * 100)}%`;
18520
+ return `${(px * 100).toFixed(this.precision)}% ${(py * 100).toFixed(this.precision)}%`;
18499
18521
  }
18500
18522
 
18501
18523
  set value(v) {
18502
18524
  this.setAttribute("value", v ?? "0% 0%");
18503
18525
  }
18504
18526
 
18527
+ get precision() {
18528
+ const parsed = Number(this.getAttribute("precision") ?? 2);
18529
+ if (!Number.isFinite(parsed)) return 2;
18530
+ return Math.max(0, Math.min(10, Math.trunc(parsed)));
18531
+ }
18532
+
18533
+ set precision(value) {
18534
+ if (value === null || value === undefined || value === "") {
18535
+ this.removeAttribute("precision");
18536
+ } else {
18537
+ const parsed = Number(value);
18538
+ const precision = Number.isFinite(parsed)
18539
+ ? Math.max(0, Math.min(10, Math.trunc(parsed)))
18540
+ : 2;
18541
+ this.setAttribute("precision", String(precision));
18542
+ }
18543
+ }
18544
+
18545
+ #roundCoordinate(value) {
18546
+ const factor = 10 ** this.precision;
18547
+ const rounded = Math.round(value * factor) / factor;
18548
+ return Object.is(rounded, -0) ? 0 : rounded;
18549
+ }
18550
+
18505
18551
  #parseValue(str) {
18506
18552
  const normalized = str == null ? "" : String(str).trim();
18507
18553
  if (!normalized) return { xPct: 0, yPct: 0 };
@@ -18541,7 +18587,7 @@ class FigHandle extends HTMLElement {
18541
18587
 
18542
18588
  const resolveResponsive = (token) => {
18543
18589
  const pct = typeof token === "number" ? token : 0;
18544
- return `${pct}%`;
18590
+ return `${this.#roundCoordinate(pct)}%`;
18545
18591
  };
18546
18592
 
18547
18593
  const axes = this.#axes;
@@ -18549,12 +18595,16 @@ class FigHandle extends HTMLElement {
18549
18595
  if (axes.x) {
18550
18596
  const xPx = resolvePx(xToken, rect.width);
18551
18597
  this.style.left =
18552
- xPx === null ? resolveResponsive(xToken) : `${Math.round(xPx)}px`;
18598
+ xPx === null
18599
+ ? resolveResponsive(xToken)
18600
+ : `${this.#roundCoordinate(xPx)}px`;
18553
18601
  }
18554
18602
  if (axes.y) {
18555
18603
  const yPx = resolvePx(yToken, rect.height);
18556
18604
  this.style.top =
18557
- yPx === null ? resolveResponsive(yToken) : `${Math.round(yPx)}px`;
18605
+ yPx === null
18606
+ ? resolveResponsive(yToken)
18607
+ : `${this.#roundCoordinate(yPx)}px`;
18558
18608
  }
18559
18609
  }
18560
18610
 
@@ -18783,8 +18833,12 @@ class FigHandle extends HTMLElement {
18783
18833
  px = Math.max(0, Math.min(1, px));
18784
18834
  py = Math.max(0, Math.min(1, py));
18785
18835
  this.#syncPositionTranslate(axes);
18786
- if (axes.x) this.style.left = `${Math.round(px * rect.width)}px`;
18787
- if (axes.y) this.style.top = `${Math.round(py * rect.height)}px`;
18836
+ if (axes.x) {
18837
+ this.style.left = `${this.#roundCoordinate(px * rect.width)}px`;
18838
+ }
18839
+ if (axes.y) {
18840
+ this.style.top = `${this.#roundCoordinate(py * rect.height)}px`;
18841
+ }
18788
18842
  this.#syncValueAttribute();
18789
18843
  const detail = {
18790
18844
  ...this.#positionDetail(rect),
@@ -18824,6 +18878,15 @@ class FigHandle extends HTMLElement {
18824
18878
  if (name === "value" && !this.#applyingValue && !this.#isDragging) {
18825
18879
  this.#applyValue(value);
18826
18880
  }
18881
+ if (
18882
+ name === "precision" &&
18883
+ this.isConnected &&
18884
+ !this.#isDragging &&
18885
+ this.hasAttribute("value")
18886
+ ) {
18887
+ this.#applyValue(this.getAttribute("value"));
18888
+ this.#syncValueAttribute();
18889
+ }
18827
18890
  if (name === "tip") {
18828
18891
  this.#hideColorTip();
18829
18892
  if (this.#tipMode) {
@@ -18926,10 +18989,14 @@ class FigHandle extends HTMLElement {
18926
18989
 
18927
18990
  this.#syncPositionTranslate(axes);
18928
18991
  if (axes.x) {
18929
- this.style.left = `${Math.round(Math.max(0, Math.min(rect.width, centerX * rect.width)))}px`;
18992
+ this.style.left = `${this.#roundCoordinate(
18993
+ Math.max(0, Math.min(rect.width, centerX * rect.width)),
18994
+ )}px`;
18930
18995
  }
18931
18996
  if (axes.y) {
18932
- this.style.top = `${Math.round(Math.max(0, Math.min(rect.height, centerY * rect.height)))}px`;
18997
+ this.style.top = `${this.#roundCoordinate(
18998
+ Math.max(0, Math.min(rect.height, centerY * rect.height)),
18999
+ )}px`;
18933
19000
  }
18934
19001
  };
18935
19002
 
@@ -19360,7 +19427,12 @@ class FigHandle extends HTMLElement {
19360
19427
  const centerY = y + hh;
19361
19428
  const px = rect.width > 0 ? centerX / rect.width : 0;
19362
19429
  const py = rect.height > 0 ? centerY / rect.height : 0;
19363
- return { x, y, px, py };
19430
+ return {
19431
+ x: this.#roundCoordinate(x),
19432
+ y: this.#roundCoordinate(y),
19433
+ px,
19434
+ py,
19435
+ };
19364
19436
  }
19365
19437
  }
19366
19438
  figDefineElement("fig-handle", FigHandle);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "8.9.46",
3
+ "version": "8.9.47",
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": "SEE LICENSE IN LICENSE",