@rogieking/figui3 6.6.6 → 6.7.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/components.css +27 -1
- package/dist/components.css +1 -1
- package/dist/fig.css +1 -1
- package/dist/fig.js +61 -61
- package/fig.js +107 -8
- package/package.json +1 -1
package/fig.js
CHANGED
|
@@ -747,9 +747,10 @@ customElements.define("fig-dropdown", FigDropdown);
|
|
|
747
747
|
*/
|
|
748
748
|
class FigTooltip extends HTMLElement {
|
|
749
749
|
static #lastShownAt = 0;
|
|
750
|
-
static #
|
|
751
|
-
static #warmupWindow =
|
|
750
|
+
static #lastHiddenAt = 0;
|
|
751
|
+
static #warmupWindow = 1000;
|
|
752
752
|
static #hoverOpen = null;
|
|
753
|
+
static #documentExitListenersReady = false;
|
|
753
754
|
|
|
754
755
|
#boundHideOnChromeOpen;
|
|
755
756
|
#boundHidePopupOutsideClick;
|
|
@@ -788,6 +789,7 @@ class FigTooltip extends HTMLElement {
|
|
|
788
789
|
};
|
|
789
790
|
}
|
|
790
791
|
connectedCallback() {
|
|
792
|
+
FigTooltip.#ensureDocumentExitListeners();
|
|
791
793
|
this.setup();
|
|
792
794
|
this.#bindTriggerListeners();
|
|
793
795
|
this.setupEventListeners();
|
|
@@ -989,17 +991,29 @@ class FigTooltip extends HTMLElement {
|
|
|
989
991
|
return this.hasAttribute("show") && this.getAttribute("show") !== "false";
|
|
990
992
|
}
|
|
991
993
|
|
|
994
|
+
#isWarmSession() {
|
|
995
|
+
const now = Date.now();
|
|
996
|
+
const windowMs = FigTooltip.#warmupWindow;
|
|
997
|
+
if (this.action === "hover" && FigTooltip.#hoverOpen) return true;
|
|
998
|
+
if (FigTooltip.#lastShownAt && now - FigTooltip.#lastShownAt < windowMs)
|
|
999
|
+
return true;
|
|
1000
|
+
if (FigTooltip.#lastHiddenAt && now - FigTooltip.#lastHiddenAt < windowMs)
|
|
1001
|
+
return true;
|
|
1002
|
+
return false;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
992
1005
|
showDelayedPopup() {
|
|
993
1006
|
if (this.#showPersisted) return;
|
|
994
1007
|
clearTimeout(this.timeout);
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1008
|
+
if (this.#isWarmSession()) {
|
|
1009
|
+
this.render();
|
|
1010
|
+
this.showPopup();
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
999
1013
|
this.timeout = setTimeout(() => {
|
|
1000
1014
|
this.render();
|
|
1001
1015
|
this.showPopup();
|
|
1002
|
-
},
|
|
1016
|
+
}, this.delay);
|
|
1003
1017
|
}
|
|
1004
1018
|
|
|
1005
1019
|
showPopup() {
|
|
@@ -1021,19 +1035,20 @@ class FigTooltip extends HTMLElement {
|
|
|
1021
1035
|
this.isOpen = true;
|
|
1022
1036
|
if (this.action === "hover") FigTooltip.#hoverOpen = this;
|
|
1023
1037
|
FigTooltip.#lastShownAt = Date.now();
|
|
1024
|
-
FigTooltip.#lastShownInstance = this;
|
|
1025
1038
|
}
|
|
1026
1039
|
|
|
1027
1040
|
hidePopup() {
|
|
1028
1041
|
if (this.#showPersisted) return;
|
|
1029
1042
|
clearTimeout(this.timeout);
|
|
1030
1043
|
clearTimeout(this.#touchTimeout);
|
|
1044
|
+
const wasShowing = this.isOpen;
|
|
1031
1045
|
if (this.popup) {
|
|
1032
1046
|
this.destroy();
|
|
1033
1047
|
}
|
|
1034
1048
|
|
|
1035
1049
|
this.isOpen = false;
|
|
1036
1050
|
if (FigTooltip.#hoverOpen === this) FigTooltip.#hoverOpen = null;
|
|
1051
|
+
if (wasShowing) FigTooltip.#lastHiddenAt = Date.now();
|
|
1037
1052
|
}
|
|
1038
1053
|
|
|
1039
1054
|
hidePopupOutsideClick(event) {
|
|
@@ -1184,6 +1199,48 @@ class FigTooltip extends HTMLElement {
|
|
|
1184
1199
|
}
|
|
1185
1200
|
}
|
|
1186
1201
|
|
|
1202
|
+
static #ensureDocumentExitListeners() {
|
|
1203
|
+
if (FigTooltip.#documentExitListenersReady) return;
|
|
1204
|
+
FigTooltip.#documentExitListenersReady = true;
|
|
1205
|
+
|
|
1206
|
+
const handlePointerLeftDocument = () => {
|
|
1207
|
+
FigTooltip.#dismissHoverTooltipsOnDocumentExit();
|
|
1208
|
+
};
|
|
1209
|
+
|
|
1210
|
+
document.documentElement.addEventListener(
|
|
1211
|
+
"mouseleave",
|
|
1212
|
+
handlePointerLeftDocument,
|
|
1213
|
+
);
|
|
1214
|
+
document.addEventListener("mouseout", (event) => {
|
|
1215
|
+
if (event.relatedTarget) return;
|
|
1216
|
+
handlePointerLeftDocument();
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
// Same-origin embed: leaving the iframe element (e.g. into a parent dialog).
|
|
1220
|
+
try {
|
|
1221
|
+
const frame = window.frameElement;
|
|
1222
|
+
if (frame) {
|
|
1223
|
+
frame.addEventListener("mouseleave", handlePointerLeftDocument);
|
|
1224
|
+
}
|
|
1225
|
+
} catch {}
|
|
1226
|
+
|
|
1227
|
+
window.addEventListener("message", (event) => {
|
|
1228
|
+
if (event?.data?.type !== "figui:dismiss-tooltips") return;
|
|
1229
|
+
if (window.parent !== window && event.source !== window.parent) return;
|
|
1230
|
+
handlePointerLeftDocument();
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
static #dismissHoverTooltipsOnDocumentExit() {
|
|
1235
|
+
for (const node of document.querySelectorAll("fig-tooltip")) {
|
|
1236
|
+
if (!(node instanceof FigTooltip)) continue;
|
|
1237
|
+
if (node.action !== "hover") continue;
|
|
1238
|
+
if (node.hasAttribute("show") && node.getAttribute("show") !== "false")
|
|
1239
|
+
continue;
|
|
1240
|
+
if (node.isOpen || node.timeout) node.hidePopup();
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1187
1244
|
static #programmatic = new WeakMap();
|
|
1188
1245
|
|
|
1189
1246
|
static show(anchor, text, options = {}) {
|
|
@@ -1363,6 +1420,8 @@ class FigDialog extends HTMLDialogElement {
|
|
|
1363
1420
|
this._boundContentMutation = this._scheduleAutoResize.bind(this);
|
|
1364
1421
|
this._boundContentResize = this._scheduleAutoResize.bind(this);
|
|
1365
1422
|
this._boundRestoreFocus = this._restoreFocus.bind(this);
|
|
1423
|
+
this._boundIframeMouseLeave = this._handleIframeMouseLeave.bind(this);
|
|
1424
|
+
this._iframeDismissMutationObserver = null;
|
|
1366
1425
|
this._previousFocus = null;
|
|
1367
1426
|
}
|
|
1368
1427
|
|
|
@@ -1389,6 +1448,7 @@ class FigDialog extends HTMLDialogElement {
|
|
|
1389
1448
|
this._setupDragListeners();
|
|
1390
1449
|
this._applyPosition();
|
|
1391
1450
|
this._syncAutoResize();
|
|
1451
|
+
this._setupIframeDismissListeners();
|
|
1392
1452
|
this._syncA11y();
|
|
1393
1453
|
});
|
|
1394
1454
|
|
|
@@ -1403,6 +1463,7 @@ class FigDialog extends HTMLDialogElement {
|
|
|
1403
1463
|
});
|
|
1404
1464
|
window.removeEventListener("message", this._boundIframeMessage);
|
|
1405
1465
|
this._teardownAutoResize();
|
|
1466
|
+
this._teardownIframeDismissListeners();
|
|
1406
1467
|
this.removeEventListener("close", this._boundRestoreFocus);
|
|
1407
1468
|
}
|
|
1408
1469
|
|
|
@@ -1435,6 +1496,44 @@ class FigDialog extends HTMLDialogElement {
|
|
|
1435
1496
|
return super.showModal();
|
|
1436
1497
|
}
|
|
1437
1498
|
|
|
1499
|
+
_handleIframeMouseLeave(event) {
|
|
1500
|
+
const iframe = event?.currentTarget;
|
|
1501
|
+
if (!(iframe instanceof HTMLIFrameElement)) return;
|
|
1502
|
+
try {
|
|
1503
|
+
iframe.contentWindow?.postMessage({ type: "figui:dismiss-tooltips" }, "*");
|
|
1504
|
+
} catch {}
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
_syncIframeDismissListeners() {
|
|
1508
|
+
for (const iframe of this.querySelectorAll(":scope > iframe")) {
|
|
1509
|
+
if (!(iframe instanceof HTMLIFrameElement)) continue;
|
|
1510
|
+
if (iframe.dataset.figuiDismissBound === "true") continue;
|
|
1511
|
+
iframe.dataset.figuiDismissBound = "true";
|
|
1512
|
+
iframe.addEventListener("mouseleave", this._boundIframeMouseLeave);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
_setupIframeDismissListeners() {
|
|
1517
|
+
this._syncIframeDismissListeners();
|
|
1518
|
+
if (this._iframeDismissMutationObserver) return;
|
|
1519
|
+
this._iframeDismissMutationObserver = new MutationObserver(() => {
|
|
1520
|
+
this._syncIframeDismissListeners();
|
|
1521
|
+
});
|
|
1522
|
+
this._iframeDismissMutationObserver.observe(this, {
|
|
1523
|
+
childList: true,
|
|
1524
|
+
subtree: false,
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
_teardownIframeDismissListeners() {
|
|
1529
|
+
this._iframeDismissMutationObserver?.disconnect();
|
|
1530
|
+
this._iframeDismissMutationObserver = null;
|
|
1531
|
+
for (const iframe of this.querySelectorAll(":scope > iframe")) {
|
|
1532
|
+
iframe.removeEventListener("mouseleave", this._boundIframeMouseLeave);
|
|
1533
|
+
delete iframe.dataset.figuiDismissBound;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1438
1537
|
_handleIframeMessage(event) {
|
|
1439
1538
|
if (!this.autoresize) return;
|
|
1440
1539
|
const data = event?.data;
|
package/package.json
CHANGED