@rogieking/figui3 6.6.4 → 6.6.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
@@ -164,6 +164,19 @@ function figUniqueId() {
164
164
  return Date.now().toString(36) + Math.random().toString(36).substring(2);
165
165
  }
166
166
 
167
+ /** Zero-size portal for fixed overlays so they never affect body layout metrics. */
168
+ function figGetOverlayRoot() {
169
+ if (!document.body) return null;
170
+ const attr = "data-figui-overlay-root";
171
+ let root = document.body.querySelector(`:scope > [${attr}]`);
172
+ if (!root) {
173
+ root = document.createElement("div");
174
+ root.setAttribute(attr, "");
175
+ document.body.append(root);
176
+ }
177
+ return root;
178
+ }
179
+
167
180
  let _figZCounter = 10000;
168
181
  function figGetHighestZIndex() {
169
182
  return _figZCounter++;
@@ -859,13 +872,13 @@ class FigTooltip extends HTMLElement {
859
872
  // - Without popover support, fall back to today's behavior: nearest open
860
873
  // <dialog> ancestor if present, else document.body.
861
874
  if (supportsPopover) {
862
- document.body.append(this.popup);
875
+ (figGetOverlayRoot() ?? document.body).append(this.popup);
863
876
  } else {
864
877
  const parentDialog = this.closest("dialog");
865
878
  if (parentDialog && parentDialog.open) {
866
879
  parentDialog.append(this.popup);
867
880
  } else {
868
- document.body.append(this.popup);
881
+ (figGetOverlayRoot() ?? document.body).append(this.popup);
869
882
  }
870
883
  }
871
884
 
@@ -1142,13 +1155,13 @@ class FigTooltip extends HTMLElement {
1142
1155
  popup.append(content);
1143
1156
 
1144
1157
  if (supportsPopover) {
1145
- document.body.append(popup);
1158
+ (figGetOverlayRoot() ?? document.body).append(popup);
1146
1159
  } else {
1147
1160
  const parentDialog = anchor.closest?.("dialog");
1148
1161
  if (parentDialog && parentDialog.open) {
1149
1162
  parentDialog.append(popup);
1150
1163
  } else {
1151
- document.body.append(popup);
1164
+ (figGetOverlayRoot() ?? document.body).append(popup);
1152
1165
  }
1153
1166
  }
1154
1167
 
@@ -3026,23 +3039,6 @@ class FigPopup extends HTMLDialogElement {
3026
3039
  );
3027
3040
  }
3028
3041
 
3029
- updatePointerVisibility(anchorRect, popupRect, left, top, placementSide) {
3030
- if (!this.tracksAnchorBeak()) return;
3031
- if (this.getAttribute("pointer") === "false") return;
3032
-
3033
- if (
3034
- anchorRect &&
3035
- !this.canPointAtAnchor(anchorRect, popupRect, left, top, placementSide)
3036
- ) {
3037
- this.setAttribute("pointer", "false");
3038
- return;
3039
- }
3040
-
3041
- if (this.hasAttribute("pointer")) {
3042
- this.removeAttribute("pointer");
3043
- }
3044
- }
3045
-
3046
3042
  updatePopoverBeak(anchorRect, popupRect, left, top, placementSide) {
3047
3043
  if (!this.tracksAnchorBeak() || !anchorRect) {
3048
3044
  this.style.removeProperty("--fig-popup-beak-offset");
@@ -3110,6 +3106,23 @@ class FigPopup extends HTMLDialogElement {
3110
3106
  return this.clampToViewport(coords, popupRect, m);
3111
3107
  }
3112
3108
 
3109
+ primaryAxisOverflowPenalty(coords, popupRect, m, placementSide) {
3110
+ const bounds = this.getViewportBounds(m);
3111
+ let overflow = 0;
3112
+
3113
+ if (placementSide === "top") {
3114
+ overflow = Math.max(0, bounds.minTop - coords.top);
3115
+ } else if (placementSide === "bottom") {
3116
+ overflow = Math.max(0, coords.top + popupRect.height - bounds.maxBottom);
3117
+ } else if (placementSide === "left") {
3118
+ overflow = Math.max(0, bounds.minLeft - coords.left);
3119
+ } else if (placementSide === "right") {
3120
+ overflow = Math.max(0, coords.left + popupRect.width - bounds.maxRight);
3121
+ }
3122
+
3123
+ return overflow > 0 ? 1000 + overflow : 0;
3124
+ }
3125
+
3113
3126
  placementScore(anchorRect, popupRect, coords, placementSide, m) {
3114
3127
  const resolved = this.resolveCoordsAtViewport(
3115
3128
  anchorRect,
@@ -3119,6 +3132,12 @@ class FigPopup extends HTMLDialogElement {
3119
3132
  m,
3120
3133
  );
3121
3134
  let score = this.overflowScore(resolved, popupRect, m);
3135
+ score += this.primaryAxisOverflowPenalty(
3136
+ coords,
3137
+ popupRect,
3138
+ m,
3139
+ placementSide,
3140
+ );
3122
3141
  if (
3123
3142
  anchorRect &&
3124
3143
  !this.canPointAtAnchor(
@@ -3150,13 +3169,6 @@ class FigPopup extends HTMLDialogElement {
3150
3169
  );
3151
3170
  this.style.left = `${resolved.left}px`;
3152
3171
  this.style.top = `${resolved.top}px`;
3153
- this.updatePointerVisibility(
3154
- anchorRect,
3155
- popupRect,
3156
- resolved.left,
3157
- resolved.top,
3158
- placementSide,
3159
- );
3160
3172
  this.updatePopoverBeak(
3161
3173
  anchorRect,
3162
3174
  popupRect,
@@ -3167,7 +3179,7 @@ class FigPopup extends HTMLDialogElement {
3167
3179
  }
3168
3180
 
3169
3181
  positionPopup() {
3170
- if (!this.open || !this.matches?.(":open")) return;
3182
+ if (!this.open) return;
3171
3183
 
3172
3184
  const popupRect = this.getBoundingClientRect();
3173
3185
  const offset = this.parseOffset();
@@ -3259,7 +3271,9 @@ class FigPopup extends HTMLDialogElement {
3259
3271
  }
3260
3272
 
3261
3273
  queueReposition() {
3262
- if (!this.open || !this.shouldAutoReposition()) return;
3274
+ if (!this.open || !this.isPopupDisplayed() || !this.shouldAutoReposition()) {
3275
+ return;
3276
+ }
3263
3277
  if (this._rafId !== null) return;
3264
3278
 
3265
3279
  this._rafId = requestAnimationFrame(() => {
@@ -3272,6 +3286,14 @@ class FigPopup extends HTMLDialogElement {
3272
3286
  if (!(this.drag && this._wasDragged)) return true;
3273
3287
  return !this.resolveAnchor();
3274
3288
  }
3289
+
3290
+ isPopupDisplayed() {
3291
+ return Boolean(
3292
+ this._isPopupActive ||
3293
+ this.matches?.(":open") ||
3294
+ this.matches?.(":popover-open"),
3295
+ );
3296
+ }
3275
3297
  }
3276
3298
  figDefineCustomizedBuiltIn("fig-popup", FigPopup, { extends: "dialog" });
3277
3299
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "6.6.4",
3
+ "version": "6.6.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",