@rogieking/figui3 9.4.0 → 9.4.2

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
@@ -1934,31 +1934,58 @@ figDefineElement("fig-tooltip", FigTooltip);
1934
1934
 
1935
1935
  /* Text Truncation */
1936
1936
  class FigTruncate extends HTMLElement {
1937
- static observedAttributes = ["position", "tail"];
1937
+ static observedAttributes = ["position", "tail", "tooltip"];
1938
1938
 
1939
1939
  #originalText = null;
1940
1940
  #boundEnter = null;
1941
1941
  #boundLeave = null;
1942
+ #observer = null;
1942
1943
 
1943
1944
  connectedCallback() {
1944
1945
  this.#originalText = this.textContent;
1946
+ this.#observer ??= new MutationObserver(() => {
1947
+ this.#originalText = this.textContent;
1948
+ this.#render();
1949
+ });
1950
+ this.#observe();
1945
1951
  figNextFrame(this, () => {
1946
1952
  this.#render();
1953
+ this.#teardownTooltip();
1947
1954
  this.#setupTooltip();
1948
1955
  });
1949
1956
  }
1950
1957
 
1951
1958
  disconnectedCallback() {
1959
+ this.#observer?.disconnect();
1952
1960
  this.#teardownTooltip();
1953
1961
  }
1954
1962
 
1955
1963
  attributeChangedCallback(name, oldValue, newValue) {
1956
1964
  if (oldValue === newValue) return;
1957
1965
  if (this.#originalText === null) return;
1966
+ if (name === "tooltip") {
1967
+ this.#teardownTooltip();
1968
+ if (this.isConnected) this.#setupTooltip();
1969
+ return;
1970
+ }
1958
1971
  this.#render();
1959
1972
  }
1960
1973
 
1974
+ #observe() {
1975
+ this.#observer?.observe(this, {
1976
+ childList: true,
1977
+ characterData: true,
1978
+ subtree: true,
1979
+ });
1980
+ }
1981
+
1961
1982
  #render() {
1983
+ this.#observer?.disconnect();
1984
+ this.#renderContent();
1985
+ if (this.isConnected) this.#observe();
1986
+ }
1987
+
1988
+ #renderContent() {
1962
1989
  const position = this.getAttribute("position") || "right";
1963
1990
  const text = this.#originalText || "";
1964
1991
  if (position === "middle") {
@@ -1991,7 +2018,7 @@ class FigTruncate extends HTMLElement {
1991
2018
  )
1992
2019
  return;
1993
2020
  this.#boundEnter = () => {
1994
- if (this.scrollWidth <= this.clientWidth) return;
2021
+ if (!this.#isTruncated()) return;
1995
2022
  FigTooltip.show(this, this.#originalText);
1996
2023
  };
1997
2024
  this.#boundLeave = () => {
@@ -2001,11 +2028,21 @@ class FigTruncate extends HTMLElement {
2001
2028
  this.addEventListener("pointerleave", this.#boundLeave);
2002
2029
  }
2003
2030
 
2031
+ #isTruncated() {
2032
+ const overflows = (el) => el.scrollWidth > el.clientWidth;
2033
+ if (overflows(this)) return true;
2034
+ return [...this.querySelectorAll(":scope > .start, :scope > .end")].some(
2035
+ overflows,
2036
+ );
2037
+ }
2038
+
2004
2039
  #teardownTooltip() {
2005
2040
  if (this.#boundEnter)
2006
2041
  this.removeEventListener("pointerenter", this.#boundEnter);
2007
2042
  if (this.#boundLeave)
2008
2043
  this.removeEventListener("pointerleave", this.#boundLeave);
2044
+ this.#boundEnter = null;
2045
+ this.#boundLeave = null;
2009
2046
  FigTooltip.hide(this);
2010
2047
  }
2011
2048
  }
@@ -18698,23 +18735,29 @@ figDefineElement("fig-skeleton", FigSkeleton);
18698
18735
 
18699
18736
  // FigGroup
18700
18737
  class FigGroup extends HTMLElement {
18701
- static observedAttributes = ["name", "collapsible", "open"];
18738
+ static observedAttributes = ["name", "collapsible", "open", "compact"];
18702
18739
 
18703
18740
  #header = null;
18704
18741
  #chevron = null;
18742
+ #toggle = null;
18743
+ #compactHeader = null;
18744
+ #compactHeaderValue = null;
18705
18745
 
18706
18746
  connectedCallback() {
18707
18747
  this.#render();
18708
18748
  }
18709
18749
 
18710
18750
  disconnectedCallback() {
18711
- if (this.#chevron) {
18712
- this.#chevron.removeEventListener("click", this.#handleToggle);
18713
- }
18751
+ this.#removeToggleListeners();
18752
+ }
18753
+
18754
+ #removeToggleListeners() {
18755
+ this.#chevron?.removeEventListener("click", this.#handleToggle);
18756
+ this.#toggle?.removeEventListener("click", this.#handleToggle);
18757
+ this.#toggle?.removeEventListener("keydown", this.#handleToggleKeyDown);
18714
18758
  if (this.#header) {
18715
18759
  this.#header.removeEventListener("click", this.#handleToggle);
18716
- this.#header.removeEventListener("keydown", this.#handleHeaderKeyDown);
18717
- this.#header.querySelector("h3")?.removeEventListener("click", this.#handleToggle);
18760
+ this.#header.removeEventListener("keydown", this.#handleToggleKeyDown);
18718
18761
  }
18719
18762
  }
18720
18763
 
@@ -18722,7 +18765,7 @@ class FigGroup extends HTMLElement {
18722
18765
  if (oldValue === newValue) return;
18723
18766
  if (!this.isConnected) return;
18724
18767
  if (name === "open") {
18725
- this.#header?.setAttribute("aria-expanded", String(this.open));
18768
+ this.#syncExpanded();
18726
18769
  return;
18727
18770
  }
18728
18771
  this.#render();
@@ -18740,7 +18783,7 @@ class FigGroup extends HTMLElement {
18740
18783
  } else {
18741
18784
  this.setAttribute("open", "false");
18742
18785
  }
18743
- this.#header?.setAttribute("aria-expanded", String(!!value));
18786
+ this.#syncExpanded();
18744
18787
  if (was !== !!value) {
18745
18788
  this.dispatchEvent(
18746
18789
  new CustomEvent("openchange", {
@@ -18751,12 +18794,46 @@ class FigGroup extends HTMLElement {
18751
18794
  }
18752
18795
  }
18753
18796
 
18797
+ #syncExpanded() {
18798
+ if (this.hasAttribute("collapsible")) {
18799
+ this.#toggle?.setAttribute("aria-expanded", String(this.open));
18800
+ } else {
18801
+ this.#toggle?.removeAttribute("aria-expanded");
18802
+ }
18803
+ }
18804
+
18805
+ #restoreHeaderCompact() {
18806
+ if (!this.#compactHeader) return;
18807
+ if (this.#compactHeaderValue === null) {
18808
+ this.#compactHeader.removeAttribute("compact");
18809
+ } else {
18810
+ this.#compactHeader.setAttribute("compact", this.#compactHeaderValue);
18811
+ }
18812
+ this.#compactHeader = null;
18813
+ this.#compactHeaderValue = null;
18814
+ }
18815
+
18816
+ #syncHeaderCompact() {
18817
+ const compact =
18818
+ this.hasAttribute("compact") && this.getAttribute("compact") !== "false";
18819
+ if (!compact) {
18820
+ this.#restoreHeaderCompact();
18821
+ return;
18822
+ }
18823
+ if (this.#compactHeader !== this.#header) {
18824
+ this.#restoreHeaderCompact();
18825
+ this.#compactHeader = this.#header;
18826
+ this.#compactHeaderValue = this.#header?.getAttribute("compact") ?? null;
18827
+ }
18828
+ this.#header?.setAttribute("compact", "");
18829
+ }
18830
+
18754
18831
  #handleToggle = (e) => {
18755
18832
  e.stopPropagation();
18756
18833
  this.open = !this.open;
18757
18834
  };
18758
18835
 
18759
- #handleHeaderKeyDown = (e) => {
18836
+ #handleToggleKeyDown = (e) => {
18760
18837
  if (e.key !== "Enter" && e.key !== " ") return;
18761
18838
  e.preventDefault();
18762
18839
  e.stopPropagation();
@@ -18764,6 +18841,7 @@ class FigGroup extends HTMLElement {
18764
18841
  };
18765
18842
 
18766
18843
  #render() {
18844
+ this.#removeToggleListeners();
18767
18845
  const isCollapsible = this.hasAttribute("collapsible");
18768
18846
  const nameAttr = this.getAttribute("name");
18769
18847
  const label = nameAttr || (isCollapsible ? "Group" : null);
@@ -18775,9 +18853,11 @@ class FigGroup extends HTMLElement {
18775
18853
 
18776
18854
  if (!label && !isCollapsible && !userHeader) {
18777
18855
  if (this.#header && this.#header.dataset.generated) {
18856
+ this.#restoreHeaderCompact();
18778
18857
  this.#header.remove();
18779
18858
  this.#header = null;
18780
18859
  this.#chevron = null;
18860
+ this.#toggle = null;
18781
18861
  }
18782
18862
  return;
18783
18863
  }
@@ -18793,6 +18873,7 @@ class FigGroup extends HTMLElement {
18793
18873
  this.#header.dataset.generated = "true";
18794
18874
  this.prepend(this.#header);
18795
18875
  }
18876
+ this.#syncHeaderCompact();
18796
18877
 
18797
18878
  // Ensure h3 exists inside header
18798
18879
  let h3 = this.#header.querySelector("h3");
@@ -18800,6 +18881,7 @@ class FigGroup extends HTMLElement {
18800
18881
  h3 = document.createElement("h3");
18801
18882
  this.#header.prepend(h3);
18802
18883
  }
18884
+ this.#toggle = h3;
18803
18885
  if (!h3.id) h3.id = figUniqueId();
18804
18886
  if (this.#header.dataset.generated) {
18805
18887
  h3.textContent = label;
@@ -18819,26 +18901,27 @@ class FigGroup extends HTMLElement {
18819
18901
  }
18820
18902
  this.#header.insertBefore(chevron, h3);
18821
18903
  this.#chevron = chevron;
18822
- h3.removeEventListener("click", this.#handleToggle);
18823
- this.#header.removeEventListener("click", this.#handleToggle);
18824
- this.#header.addEventListener("click", this.#handleToggle);
18825
- this.#header.setAttribute("role", "button");
18826
- this.#header.setAttribute("tabindex", "0");
18827
- this.#header.setAttribute("aria-expanded", String(this.open));
18828
- this.#header.removeEventListener("keydown", this.#handleHeaderKeyDown);
18829
- this.#header.addEventListener("keydown", this.#handleHeaderKeyDown);
18904
+ this.#header.removeAttribute("role");
18905
+ this.#header.removeAttribute("tabindex");
18906
+ this.#header.removeAttribute("aria-expanded");
18907
+ h3.setAttribute("role", "button");
18908
+ h3.setAttribute("tabindex", "0");
18909
+ h3.setAttribute("aria-expanded", String(this.open));
18910
+ h3.addEventListener("click", this.#handleToggle);
18911
+ h3.addEventListener("keydown", this.#handleToggleKeyDown);
18912
+ chevron.addEventListener("click", this.#handleToggle);
18830
18913
 
18831
18914
  if (!this.hasAttribute("open")) {
18832
18915
  this.setAttribute("open", "false");
18833
- this.#header.setAttribute("aria-expanded", "false");
18916
+ h3.setAttribute("aria-expanded", "false");
18834
18917
  }
18835
18918
  } else {
18836
- h3.removeEventListener("click", this.#handleToggle);
18837
- this.#header.removeEventListener("click", this.#handleToggle);
18919
+ h3.removeAttribute("role");
18920
+ h3.removeAttribute("tabindex");
18921
+ h3.removeAttribute("aria-expanded");
18838
18922
  this.#header.removeAttribute("role");
18839
18923
  this.#header.removeAttribute("tabindex");
18840
18924
  this.#header.removeAttribute("aria-expanded");
18841
- this.#header.removeEventListener("keydown", this.#handleHeaderKeyDown);
18842
18925
  if (this.#chevron) {
18843
18926
  this.#chevron.remove();
18844
18927
  this.#chevron = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "9.4.0",
3
+ "version": "9.4.2",
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",