@rogieking/figui3 6.6.5 → 6.6.6

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/dist/fig.js +20 -20
  2. package/fig.js +92 -34
  3. package/package.json +1 -1
package/fig.js CHANGED
@@ -747,7 +747,9 @@ customElements.define("fig-dropdown", FigDropdown);
747
747
  */
748
748
  class FigTooltip extends HTMLElement {
749
749
  static #lastShownAt = 0;
750
+ static #lastShownInstance = null;
750
751
  static #warmupWindow = 500;
752
+ static #hoverOpen = null;
751
753
 
752
754
  #boundHideOnChromeOpen;
753
755
  #boundHidePopupOutsideClick;
@@ -760,6 +762,8 @@ class FigTooltip extends HTMLElement {
760
762
  #boundHandleDialogClose;
761
763
  #boundHandleEscape;
762
764
  #parentDialog = null;
765
+ #triggerEl = null;
766
+ #childObserver = null;
763
767
  #touchTimeout;
764
768
  #isTouching = false;
765
769
  constructor() {
@@ -785,6 +789,7 @@ class FigTooltip extends HTMLElement {
785
789
  }
786
790
  connectedCallback() {
787
791
  this.setup();
792
+ this.#bindTriggerListeners();
788
793
  this.setupEventListeners();
789
794
  this.#parentDialog = this.closest("dialog");
790
795
  if (this.#parentDialog) {
@@ -795,6 +800,8 @@ class FigTooltip extends HTMLElement {
795
800
  disconnectedCallback() {
796
801
  clearTimeout(this.timeout);
797
802
  this.destroy();
803
+ this.#unbindTriggerListeners();
804
+ this.#teardownChildObserver();
798
805
  document.removeEventListener(
799
806
  "mousedown",
800
807
  this.#boundHideOnChromeOpen,
@@ -814,17 +821,77 @@ class FigTooltip extends HTMLElement {
814
821
  }
815
822
 
816
823
  clearTimeout(this.#touchTimeout);
824
+ if (FigTooltip.#hoverOpen === this) FigTooltip.#hoverOpen = null;
825
+ }
826
+
827
+ #getTrigger() {
828
+ return this.firstElementChild;
829
+ }
830
+
831
+ #teardownChildObserver() {
832
+ this.#childObserver?.disconnect();
833
+ this.#childObserver = null;
834
+ }
835
+
836
+ #bindTriggerListeners() {
837
+ this.#unbindTriggerListeners();
838
+ if (this.action === "manual") return;
839
+
840
+ const trigger = this.#getTrigger();
841
+ if (!trigger) {
842
+ if (!this.#childObserver && typeof MutationObserver !== "undefined") {
843
+ this.#childObserver = new MutationObserver(() => {
844
+ if (this.#getTrigger()) {
845
+ this.#teardownChildObserver();
846
+ this.#bindTriggerListeners();
847
+ }
848
+ });
849
+ this.#childObserver.observe(this, { childList: true });
850
+ }
851
+ return;
852
+ }
853
+
854
+ this.#triggerEl = trigger;
855
+ if (this.action === "hover") {
856
+ if (!this.isTouchDevice()) {
857
+ trigger.addEventListener("pointerenter", this.#boundShowDelayedPopup);
858
+ trigger.addEventListener("pointerleave", this.#boundHandlePointerLeave);
859
+ }
860
+ trigger.addEventListener("touchstart", this.#boundHandleTouchStart, {
861
+ passive: true,
862
+ });
863
+ trigger.addEventListener("touchmove", this.#boundHandleTouchMove, {
864
+ passive: true,
865
+ });
866
+ trigger.addEventListener("touchend", this.#boundHandleTouchEnd, {
867
+ passive: true,
868
+ });
869
+ trigger.addEventListener("touchcancel", this.#boundHandleTouchCancel, {
870
+ passive: true,
871
+ });
872
+ } else if (this.action === "click") {
873
+ trigger.addEventListener("click", this.#boundShowDelayedPopup);
874
+ trigger.addEventListener("touchstart", this.#boundShowDelayedPopup, {
875
+ passive: true,
876
+ });
877
+ }
878
+ }
879
+
880
+ #unbindTriggerListeners() {
881
+ const trigger = this.#triggerEl;
882
+ if (!trigger) return;
817
883
  if (this.action === "hover") {
818
- this.removeEventListener("pointerenter", this.#boundShowDelayedPopup);
819
- this.removeEventListener("pointerleave", this.#boundHandlePointerLeave);
820
- this.removeEventListener("touchstart", this.#boundHandleTouchStart);
821
- this.removeEventListener("touchmove", this.#boundHandleTouchMove);
822
- this.removeEventListener("touchend", this.#boundHandleTouchEnd);
823
- this.removeEventListener("touchcancel", this.#boundHandleTouchCancel);
884
+ trigger.removeEventListener("pointerenter", this.#boundShowDelayedPopup);
885
+ trigger.removeEventListener("pointerleave", this.#boundHandlePointerLeave);
886
+ trigger.removeEventListener("touchstart", this.#boundHandleTouchStart);
887
+ trigger.removeEventListener("touchmove", this.#boundHandleTouchMove);
888
+ trigger.removeEventListener("touchend", this.#boundHandleTouchEnd);
889
+ trigger.removeEventListener("touchcancel", this.#boundHandleTouchCancel);
824
890
  } else if (this.action === "click") {
825
- this.removeEventListener("click", this.#boundShowDelayedPopup);
826
- this.removeEventListener("touchstart", this.#boundShowDelayedPopup);
891
+ trigger.removeEventListener("click", this.#boundShowDelayedPopup);
892
+ trigger.removeEventListener("touchstart", this.#boundShowDelayedPopup);
827
893
  }
894
+ this.#triggerEl = null;
828
895
  }
829
896
 
830
897
  setup() {
@@ -889,6 +956,7 @@ class FigTooltip extends HTMLElement {
889
956
 
890
957
  destroy() {
891
958
  if (this.popup) {
959
+ this.popup.hidePopup?.();
892
960
  this.popup.remove();
893
961
  this.popup = null;
894
962
  }
@@ -909,30 +977,8 @@ class FigTooltip extends HTMLElement {
909
977
  }
910
978
 
911
979
  setupEventListeners() {
912
- if (this.action === "manual") return;
913
- if (this.action === "hover") {
914
- if (!this.isTouchDevice()) {
915
- this.addEventListener("pointerenter", this.#boundShowDelayedPopup);
916
- this.addEventListener("pointerleave", this.#boundHandlePointerLeave);
917
- }
918
- this.addEventListener("touchstart", this.#boundHandleTouchStart, {
919
- passive: true,
920
- });
921
- this.addEventListener("touchmove", this.#boundHandleTouchMove, {
922
- passive: true,
923
- });
924
- this.addEventListener("touchend", this.#boundHandleTouchEnd, {
925
- passive: true,
926
- });
927
- this.addEventListener("touchcancel", this.#boundHandleTouchCancel, {
928
- passive: true,
929
- });
930
- } else if (this.action === "click") {
931
- this.addEventListener("click", this.#boundShowDelayedPopup);
980
+ if (this.action === "click") {
932
981
  document.body.addEventListener("click", this.#boundHidePopupOutsideClick);
933
- this.addEventListener("touchstart", this.#boundShowDelayedPopup, {
934
- passive: true,
935
- });
936
982
  }
937
983
 
938
984
  document.addEventListener("mousedown", this.#boundHideOnChromeOpen, true);
@@ -945,17 +991,27 @@ class FigTooltip extends HTMLElement {
945
991
 
946
992
  showDelayedPopup() {
947
993
  if (this.#showPersisted) return;
948
- this.render();
949
994
  clearTimeout(this.timeout);
950
995
  const warm =
996
+ FigTooltip.#lastShownInstance === this &&
951
997
  Date.now() - FigTooltip.#lastShownAt < FigTooltip.#warmupWindow;
952
998
  const effectiveDelay = warm ? 0 : this.delay;
953
- this.timeout = setTimeout(this.showPopup.bind(this), effectiveDelay);
999
+ this.timeout = setTimeout(() => {
1000
+ this.render();
1001
+ this.showPopup();
1002
+ }, effectiveDelay);
954
1003
  }
955
1004
 
956
1005
  showPopup() {
957
1006
  if (this.#parentDialog && !this.#parentDialog.open) return;
958
1007
  if (!this.firstElementChild) return;
1008
+ if (
1009
+ this.action === "hover" &&
1010
+ FigTooltip.#hoverOpen &&
1011
+ FigTooltip.#hoverOpen !== this
1012
+ ) {
1013
+ FigTooltip.#hoverOpen.hidePopup();
1014
+ }
959
1015
  if (!this.popup) this.render();
960
1016
  // Keep anchor in sync in case the trigger child was swapped between
961
1017
  // creation and show.
@@ -963,7 +1019,9 @@ class FigTooltip extends HTMLElement {
963
1019
  this.popup.open = true;
964
1020
 
965
1021
  this.isOpen = true;
1022
+ if (this.action === "hover") FigTooltip.#hoverOpen = this;
966
1023
  FigTooltip.#lastShownAt = Date.now();
1024
+ FigTooltip.#lastShownInstance = this;
967
1025
  }
968
1026
 
969
1027
  hidePopup() {
@@ -975,7 +1033,7 @@ class FigTooltip extends HTMLElement {
975
1033
  }
976
1034
 
977
1035
  this.isOpen = false;
978
- FigTooltip.#lastShownAt = Date.now();
1036
+ if (FigTooltip.#hoverOpen === this) FigTooltip.#hoverOpen = null;
979
1037
  }
980
1038
 
981
1039
  hidePopupOutsideClick(event) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "6.6.5",
3
+ "version": "6.6.6",
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",