@aurodesignsystem/auro-formkit 2.2.1-beta.2 → 2.2.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +67 -67
  3. package/components/checkbox/README.md +1 -1
  4. package/components/checkbox/demo/readme.md +1 -1
  5. package/components/combobox/README.md +1 -1
  6. package/components/combobox/demo/api.min.js +352 -94
  7. package/components/combobox/demo/index.min.js +352 -94
  8. package/components/combobox/demo/readme.md +1 -1
  9. package/components/combobox/dist/index.js +352 -94
  10. package/components/combobox/dist/registered.js +352 -94
  11. package/components/counter/README.md +1 -1
  12. package/components/counter/demo/api.min.js +353 -95
  13. package/components/counter/demo/index.min.js +353 -95
  14. package/components/counter/demo/readme.md +1 -1
  15. package/components/counter/dist/index.js +353 -95
  16. package/components/counter/dist/registered.js +353 -95
  17. package/components/datepicker/README.md +1 -1
  18. package/components/datepicker/demo/api.min.js +466 -232
  19. package/components/datepicker/demo/index.min.js +466 -232
  20. package/components/datepicker/demo/readme.md +1 -1
  21. package/components/datepicker/dist/index.js +354 -114
  22. package/components/datepicker/dist/registered.js +354 -114
  23. package/components/dropdown/README.md +1 -1
  24. package/components/dropdown/demo/api.min.js +352 -94
  25. package/components/dropdown/demo/index.min.js +352 -94
  26. package/components/dropdown/demo/readme.md +1 -1
  27. package/components/dropdown/dist/auro-dropdown.d.ts +18 -0
  28. package/components/dropdown/dist/index.js +352 -94
  29. package/components/dropdown/dist/registered.js +352 -94
  30. package/components/form/README.md +1 -1
  31. package/components/form/demo/readme.md +1 -1
  32. package/components/input/README.md +1 -1
  33. package/components/input/demo/readme.md +1 -1
  34. package/components/menu/README.md +1 -1
  35. package/components/menu/demo/readme.md +1 -1
  36. package/components/radio/README.md +1 -1
  37. package/components/radio/demo/readme.md +1 -1
  38. package/components/select/README.md +1 -1
  39. package/components/select/demo/api.min.js +352 -94
  40. package/components/select/demo/index.min.js +352 -94
  41. package/components/select/demo/readme.md +1 -1
  42. package/components/select/dist/index.js +352 -94
  43. package/components/select/dist/registered.js +352 -94
  44. package/package.json +2 -2
@@ -1583,17 +1583,70 @@ const computePosition = (reference, floating, options) => {
1583
1583
  /* eslint-disable line-comment-position, no-inline-comments */
1584
1584
 
1585
1585
 
1586
+
1587
+ const MAX_CONFIGURATION_COUNT = 10;
1588
+
1586
1589
  class AuroFloatingUI {
1587
- constructor() {
1590
+
1591
+ /**
1592
+ * @private
1593
+ */
1594
+ static isMousePressed = false;
1595
+
1596
+ /**
1597
+ * @private
1598
+ */
1599
+ static isMousePressHandlerInitialized = false;
1600
+
1601
+ /**
1602
+ * @private
1603
+ */
1604
+ static setupMousePressChecker() {
1605
+ if (!AuroFloatingUI.isMousePressHandlerInitialized && window && window.addEventListener) {
1606
+ AuroFloatingUI.isMousePressHandlerInitialized = true;
1607
+
1608
+ const mouseEventGlobalHandler = (event) => {
1609
+ AuroFloatingUI.isMousePressed = event.type === 'mousedown';
1610
+ };
1611
+
1612
+ window.addEventListener('mousedown', mouseEventGlobalHandler);
1613
+ window.addEventListener('mouseup', mouseEventGlobalHandler);
1614
+ }
1615
+ }
1616
+
1617
+ constructor(element, behavior) {
1618
+ this.element = element;
1619
+ this.behavior = behavior;
1620
+
1588
1621
  // Store event listener references for cleanup
1589
1622
  this.focusHandler = null;
1590
1623
  this.clickHandler = null;
1591
1624
  this.keyDownHandler = null;
1592
-
1625
+
1626
+ /**
1627
+ * @private
1628
+ */
1629
+ this.configureTrial = 0;
1630
+
1593
1631
  /**
1594
1632
  * @private
1595
1633
  */
1596
1634
  this.eventPrefix = undefined;
1635
+
1636
+ /**
1637
+ * @private
1638
+ */
1639
+ this.id = undefined;
1640
+
1641
+ /**
1642
+ * @private
1643
+ */
1644
+ this.showing = false;
1645
+
1646
+ /**
1647
+ * @private
1648
+ */
1649
+ this.strategy = undefined;
1597
1650
  }
1598
1651
 
1599
1652
  /**
@@ -1621,29 +1674,48 @@ class AuroFloatingUI {
1621
1674
  * @private
1622
1675
  * Determines the positioning strategy based on the current viewport size and mobile breakpoint.
1623
1676
  *
1624
- * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
1677
+ * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
1625
1678
  * defined in the bib element. If it is, the strategy is set to 'fullscreen'; otherwise, it defaults to 'floating'.
1626
1679
  *
1627
- * @returns {String} The positioning strategy, either 'fullscreen' or 'floating'.
1680
+ * @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
1628
1681
  */
1629
1682
  getPositioningStrategy() {
1630
- let strategy = 'floating';
1631
- if (this.element.bib.mobileFullscreenBreakpoint) {
1632
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${this.element.bib.mobileFullscreenBreakpoint})`).matches;
1633
- if (smallerThanBreakpoint) {
1634
- strategy = 'fullscreen';
1635
- }
1683
+ const breakpoint = this.element.bib.mobileFullscreenBreakpoint || this.element.floaterConfig?.fullscreenBreakpoint;
1684
+ switch (this.behavior) {
1685
+ case "tooltip":
1686
+ return "floating";
1687
+ case "dialog":
1688
+ case "drawer":
1689
+ if (breakpoint) {
1690
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
1691
+
1692
+ this.element.expanded = smallerThanBreakpoint;
1693
+ }
1694
+ if (this.element.nested) {
1695
+ return "cover";
1696
+ }
1697
+ return 'fullscreen';
1698
+ case "dropdown":
1699
+ case undefined:
1700
+ case null:
1701
+ if (breakpoint) {
1702
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
1703
+ if (smallerThanBreakpoint) {
1704
+ return 'fullscreen';
1705
+ }
1706
+ }
1707
+ return "floating";
1708
+ default:
1709
+ return this.behavior;
1636
1710
  }
1637
-
1638
- return strategy;
1639
1711
  }
1640
1712
 
1641
1713
  /**
1642
1714
  * @private
1643
1715
  * Positions the bib element based on the current configuration and positioning strategy.
1644
1716
  *
1645
- * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
1646
- * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
1717
+ * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
1718
+ * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
1647
1719
  * and applies the calculated position to the bib's style.
1648
1720
  */
1649
1721
  position() {
@@ -1654,21 +1726,33 @@ class AuroFloatingUI {
1654
1726
  this.mirrorSize();
1655
1727
  // Define the middlware for the floater configuration
1656
1728
  const middleware = [
1657
- offset(this.element.floaterConfig.offset || 0),
1658
- ...(this.element.floaterConfig.flip ? [flip()] : []), // Add flip middleware if flip is enabled
1659
- ...(this.element.floaterConfig.autoPlacement ? [autoPlacement()] : []), // Add autoPlacement middleware if autoPlacement is enabled
1729
+ offset(this.element.floaterConfig?.offset || 0),
1730
+ ...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
1731
+ ...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
1660
1732
  ];
1661
1733
 
1662
1734
  // Compute the position of the bib
1663
1735
  computePosition(this.element.trigger, this.element.bib, {
1664
- placement: this.element.floaterConfig.placement || 'bottom',
1736
+ placement: this.element.floaterConfig?.placement,
1665
1737
  middleware: middleware || []
1666
- }).then(({x, y}) => { // eslint-disable-line id-length
1738
+ }).then(({ x, y }) => { // eslint-disable-line id-length
1667
1739
  Object.assign(this.element.bib.style, {
1668
1740
  left: `${x}px`,
1669
1741
  top: `${y}px`,
1670
1742
  });
1671
1743
  });
1744
+ } else if (strategy === 'cover') {
1745
+ // Compute the position of the bib
1746
+ computePosition(this.element.parentNode, this.element.bib, {
1747
+ placement: 'bottom-start'
1748
+ }).then(({ x, y }) => { // eslint-disable-line id-length
1749
+ Object.assign(this.element.bib.style, {
1750
+ left: `${x}px`,
1751
+ top: `${y - this.element.parentNode.offsetHeight}px`,
1752
+ width: `${this.element.parentNode.offsetWidth}px`,
1753
+ height: `${this.element.parentNode.offsetHeight}px`
1754
+ });
1755
+ });
1672
1756
  }
1673
1757
  }
1674
1758
 
@@ -1697,34 +1781,48 @@ class AuroFloatingUI {
1697
1781
  *
1698
1782
  * @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
1699
1783
  */
1700
- configureBibStrategy(strategy) {
1701
- const prevStrategy = this.element.isBibFullscreen ? 'fullscreen' : 'floating';
1702
- if (strategy === 'fullscreen') {
1784
+ configureBibStrategy(value) {
1785
+ if (value === 'fullscreen') {
1703
1786
  this.element.isBibFullscreen = true;
1704
1787
  // reset the prev position
1788
+ this.element.bib.setAttribute('isfullscreen', "");
1789
+ this.element.bib.style.position = 'fixed';
1705
1790
  this.element.bib.style.top = "0px";
1706
1791
  this.element.bib.style.left = "0px";
1792
+ this.element.bib.style.width = '';
1793
+ this.element.bib.style.height = '';
1707
1794
 
1708
1795
  // reset the size that was mirroring `size` css-part
1709
1796
  const bibContent = this.element.bib.shadowRoot.querySelector(".container");
1710
- bibContent.style.width = '';
1711
- bibContent.style.height = '';
1712
- bibContent.style.maxWidth = '';
1713
- bibContent.style.maxHeight = `${window.visualViewport.height}px`;
1797
+ if (bibContent) {
1798
+ bibContent.style.width = '';
1799
+ bibContent.style.height = '';
1800
+ bibContent.style.maxWidth = '';
1801
+ bibContent.style.maxHeight = `${window.visualViewport.height}px`;
1802
+ this.configureTrial = 0;
1803
+ } else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
1804
+ this.configureTrial += 1;
1805
+
1806
+ setTimeout(() => {
1807
+ this.configureBibStrategy(value);
1808
+ }, 0);
1809
+ }
1714
1810
 
1715
1811
  if (this.element.isPopoverVisible) {
1716
1812
  this.lockScroll(true);
1717
1813
  }
1718
1814
  } else {
1815
+ this.element.bib.style.position = '';
1816
+ this.element.bib.removeAttribute('isfullscreen');
1719
1817
  this.element.isBibFullscreen = false;
1720
-
1721
- this.lockScroll(false);
1722
1818
  }
1723
1819
 
1724
- if (prevStrategy !== strategy) {
1820
+ const isChanged = this.strategy && this.strategy !== value;
1821
+ this.strategy = value;
1822
+ if (isChanged) {
1725
1823
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-strategy-change` : 'strategy-change', {
1726
1824
  detail: {
1727
- strategy,
1825
+ value,
1728
1826
  },
1729
1827
  composed: true
1730
1828
  });
@@ -1735,18 +1833,6 @@ class AuroFloatingUI {
1735
1833
 
1736
1834
  updateState() {
1737
1835
  const isVisible = this.element.isPopoverVisible;
1738
-
1739
- // Refactor this to apply attribute to correct focusable element
1740
- // Reference Issue: https://github.com/AlaskaAirlines/auro-library/issues/105
1741
- //
1742
- // this.element.trigger.setAttribute('aria-expanded', isVisible);
1743
-
1744
- if (isVisible) {
1745
- this.element.bib.setAttribute('data-show', true);
1746
- } else {
1747
- this.element.bib.removeAttribute('data-show');
1748
- }
1749
-
1750
1836
  if (!isVisible) {
1751
1837
  this.cleanupHideHandlers();
1752
1838
  try {
@@ -1757,16 +1843,32 @@ class AuroFloatingUI {
1757
1843
  }
1758
1844
  }
1759
1845
 
1846
+ /**
1847
+ * @private
1848
+ * getting called on 'blur' in trigger or `focusin` in document
1849
+ *
1850
+ * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
1851
+ * This method checks if the currently active element is still within the trigger or bib.
1852
+ * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
1853
+ */
1760
1854
  handleFocusLoss() {
1761
- if (this.element.noHideOnThisFocusLoss ||
1762
- this.element.hasAttribute('noHideOnThisFocusLoss')) {
1855
+ // if mouse is being pressed, skip and let click event to handle the action
1856
+ if (AuroFloatingUI.isMousePressed) {
1857
+ return;
1858
+ }
1859
+
1860
+ if (this.element.noHideOnThisFocusLoss ||
1861
+ this.element.hasAttribute('noHideOnThisFocusLoss')) {
1763
1862
  return;
1764
1863
  }
1765
1864
 
1766
- const {activeElement} = document;
1767
- if (activeElement === document.querySelector('body') ||
1768
- this.element.contains(activeElement) ||
1769
- this.element.bibContent?.contains(activeElement)) {
1865
+ const { activeElement } = document;
1866
+ // if focus is still inside of trigger or bib, do not close
1867
+ if (this.element.contains(activeElement) || this.element.bib?.contains(activeElement)) {
1868
+ return;
1869
+ }
1870
+ // if fullscreen bib is still open and the focus is missing, do not close
1871
+ if (this.element.bib.hasAttribute('isfullscreen') && activeElement === document.body) {
1770
1872
  return;
1771
1873
  }
1772
1874
 
@@ -1774,31 +1876,66 @@ class AuroFloatingUI {
1774
1876
  }
1775
1877
 
1776
1878
  setupHideHandlers() {
1879
+ this.preventFocusLoseOnBibClick = (event) => {
1880
+ event.preventDefault();
1881
+ event.stopPropagation();
1882
+ };
1883
+ this.element.bib.addEventListener('mousedown', this.preventFocusLoseOnBibClick);
1884
+
1777
1885
  // Define handlers & store references
1778
1886
  this.focusHandler = () => this.handleFocusLoss();
1779
1887
 
1780
1888
  this.clickHandler = (evt) => {
1781
- if (!evt.composedPath().includes(this.element.trigger) &&
1782
- !evt.composedPath().includes(this.element.bibContent)) {
1783
- this.hideBib();
1889
+ if ((!evt.composedPath().includes(this.element.trigger) &&
1890
+ !evt.composedPath().includes(this.element.bib)) ||
1891
+ (this.element.bib.backdrop && evt.composedPath().includes(this.element.bib.backdrop))) {
1892
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
1893
+
1894
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI.element.isPopoverVisible) {
1895
+ // if something else is open, close that
1896
+ existedVisibleFloatingUI.hideBib();
1897
+ document.expandedAuroFormkitDropdown = null;
1898
+ document.expandedAuroFloater = this;
1899
+ } else {
1900
+ this.hideBib();
1901
+ }
1784
1902
  }
1785
1903
  };
1786
1904
 
1787
1905
  // ESC key handler
1788
1906
  this.keyDownHandler = (evt) => {
1789
1907
  if (evt.key === 'Escape' && this.element.isPopoverVisible) {
1908
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
1909
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this && existedVisibleFloatingUI.element.isPopoverVisible) {
1910
+ // if something else is open, let it handle itself
1911
+ return;
1912
+ }
1790
1913
  this.hideBib();
1791
1914
  }
1792
1915
  };
1793
1916
 
1794
- // Add event listeners using the stored references
1795
- document.addEventListener('focusin', this.focusHandler);
1796
- window.addEventListener('click', this.clickHandler);
1917
+ if (this.behavior !== 'drawer' && this.behavior !== 'dialog') {
1918
+ // Add event listeners using the stored references
1919
+ document.addEventListener('focusin', this.focusHandler);
1920
+ }
1921
+
1797
1922
  document.addEventListener('keydown', this.keyDownHandler);
1923
+
1924
+ // send this task to the end of queue to prevent conflicting
1925
+ // it conflicts if showBib gets call from a button that's not this.element.trigger
1926
+ setTimeout(() => {
1927
+ window.addEventListener('click', this.clickHandler);
1928
+ }, 0);
1798
1929
  }
1799
1930
 
1800
1931
  cleanupHideHandlers() {
1801
1932
  // Remove event listeners if they exist
1933
+
1934
+ if (this.preventFocusLoseOnBibClick) {
1935
+ this.element.bib.removeEventListener('mousedown', this.preventFocusLoseOnBibClick);
1936
+ delete this.preventFocusLoseOnBibClick;
1937
+ }
1938
+
1802
1939
  if (this.focusHandler) {
1803
1940
  document.removeEventListener('focusin', this.focusHandler);
1804
1941
  this.focusHandler = null;
@@ -1823,40 +1960,54 @@ class AuroFloatingUI {
1823
1960
 
1824
1961
  updateCurrentExpandedDropdown() {
1825
1962
  // Close any other dropdown that is already open
1826
- if (document.expandedAuroFormkitDropdown) {
1827
- document.expandedAuroFormkitDropdown.hide;
1963
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
1964
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
1965
+ existedVisibleFloatingUI.isPopoverVisible &&
1966
+ document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
1967
+ document.expandedAuroFloater.hideBib();
1828
1968
  }
1829
1969
 
1830
- document.expandedAuroFormkitDropdown = this;
1970
+ document.expandedAuroFloater = this;
1831
1971
  }
1832
1972
 
1833
1973
  showBib() {
1834
- if (!this.element.disabled && !this.element.isPopoverVisible) {
1974
+ if (!this.element.disabled && !this.showing) {
1835
1975
  this.updateCurrentExpandedDropdown();
1836
- this.element.isPopoverVisible = true;
1837
1976
  this.element.triggerChevron?.setAttribute('data-expanded', true);
1838
-
1839
- this.dispatchEventDropdownToggle();
1840
- this.position();
1841
-
1842
- // Clean up any existing handlers before setting up new ones
1843
- this.cleanupHideHandlers();
1844
- this.setupHideHandlers();
1977
+
1978
+ // prevent double showing: isPopovervisible gets first and showBib gets called later
1979
+ if (!this.showing) {
1980
+ if (!this.element.modal) {
1981
+ this.setupHideHandlers();
1982
+ }
1983
+ this.showing = true;
1984
+ this.element.isPopoverVisible = true;
1985
+ this.position();
1986
+ this.dispatchEventDropdownToggle();
1987
+ }
1845
1988
 
1846
1989
  // Setup auto update to handle resize and scroll
1847
- this.element.cleanup = autoUpdate(this.element.trigger, this.element.bib, () => {
1990
+ this.element.cleanup = autoUpdate(this.element.trigger || this.element.parentNode, this.element.bib, () => {
1848
1991
  this.position();
1849
1992
  });
1850
1993
  }
1851
1994
  }
1852
1995
 
1853
1996
  hideBib() {
1854
- if (this.element.isPopoverVisible && !this.element.disabled && !this.element.noToggle) {
1855
- this.element.isPopoverVisible = false;
1997
+ if (!this.element.disabled && !this.element.noToggle) {
1856
1998
  this.lockScroll(false);
1857
1999
  this.element.triggerChevron?.removeAttribute('data-expanded');
1858
- this.dispatchEventDropdownToggle();
2000
+
2001
+ if (this.element.isPopoverVisible) {
2002
+ this.element.isPopoverVisible = false;
2003
+ }
2004
+ if (this.showing) {
2005
+ this.cleanupHideHandlers();
2006
+ this.showing = false;
2007
+ this.dispatchEventDropdownToggle();
2008
+ }
1859
2009
  }
2010
+ document.expandedAuroFloater = null;
1860
2011
  }
1861
2012
 
1862
2013
  /**
@@ -1866,7 +2017,7 @@ class AuroFloatingUI {
1866
2017
  dispatchEventDropdownToggle() {
1867
2018
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-toggled` : 'toggled', {
1868
2019
  detail: {
1869
- expanded: this.element.isPopoverVisible,
2020
+ expanded: this.showing,
1870
2021
  },
1871
2022
  composed: true
1872
2023
  });
@@ -1914,15 +2065,18 @@ class AuroFloatingUI {
1914
2065
  break;
1915
2066
  case 'focus':
1916
2067
  if (this.element.focusShow) {
2068
+
1917
2069
  /*
1918
- This needs to better handle clicking that gives focus -
1919
- currently it shows and then immediately hides the bib
2070
+ This needs to better handle clicking that gives focus -
2071
+ currently it shows and then immediately hides the bib
1920
2072
  */
1921
2073
  this.showBib();
1922
2074
  }
1923
2075
  break;
1924
2076
  case 'blur':
1925
- this.handleFocusLoss();
2077
+ // send this task 100ms later queue to
2078
+ // wait a frame in case focus moves within the floating element/bib
2079
+ setTimeout(() => this.handleFocusLoss(), 0);
1926
2080
  break;
1927
2081
  case 'click':
1928
2082
  if (document.activeElement === document.body) {
@@ -1930,7 +2084,7 @@ class AuroFloatingUI {
1930
2084
  }
1931
2085
  this.handleClick();
1932
2086
  break;
1933
- // Do nothing
2087
+ // Do nothing
1934
2088
  }
1935
2089
  }
1936
2090
  }
@@ -1974,39 +2128,79 @@ class AuroFloatingUI {
1974
2128
  });
1975
2129
  }
1976
2130
 
2131
+ /**
2132
+ *
2133
+ * @param {*} eventPrefix
2134
+ */
2135
+ regenerateBibId() {
2136
+ this.id = this.element.getAttribute('id');
2137
+ if (!this.id) {
2138
+ this.id = window.crypto.randomUUID();
2139
+ this.element.setAttribute('id', this.id);
2140
+ }
2141
+
2142
+ this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
2143
+ }
2144
+
1977
2145
  configure(elem, eventPrefix) {
2146
+ AuroFloatingUI.setupMousePressChecker();
2147
+
1978
2148
  this.eventPrefix = eventPrefix;
1979
- this.element = elem;
1980
- this.element.trigger = this.element.shadowRoot.querySelector('#trigger');
1981
- this.element.bib = this.element.shadowRoot.querySelector('#bib');
2149
+ if (this.element !== elem) {
2150
+ this.element = elem;
2151
+ }
2152
+
2153
+ if (this.behavior !== this.element.behavior) {
2154
+ this.behavior = this.element.behavior;
2155
+ }
2156
+
2157
+ if (this.element.trigger) {
2158
+ this.disconnect();
2159
+ }
2160
+ this.element.trigger = this.element.triggerElement || this.element.shadowRoot.querySelector('#trigger') || this.element.trigger;
2161
+ this.element.bib = this.element.shadowRoot.querySelector('#bib') || this.element.bib;
1982
2162
  this.element.bibSizer = this.element.shadowRoot.querySelector('#bibSizer');
1983
2163
  this.element.triggerChevron = this.element.shadowRoot.querySelector('#showStateIcon');
1984
2164
 
2165
+
2166
+ if (this.element.floaterConfig) {
2167
+ this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
2168
+ }
2169
+
1985
2170
  document.body.append(this.element.bib);
1986
2171
 
2172
+ this.regenerateBibId();
1987
2173
  this.handleTriggerTabIndex();
1988
2174
 
1989
2175
  this.handleEvent = this.handleEvent.bind(this);
1990
- this.element.trigger.addEventListener('keydown', this.handleEvent);
1991
- this.element.trigger.addEventListener('click', this.handleEvent);
1992
- this.element.trigger.addEventListener('mouseenter', this.handleEvent);
1993
- this.element.trigger.addEventListener('mouseleave', this.handleEvent);
1994
- this.element.trigger.addEventListener('focus', this.handleEvent);
1995
- this.element.trigger.addEventListener('blur', this.handleEvent);
2176
+ if (this.element.trigger) {
2177
+ this.element.trigger.addEventListener('keydown', this.handleEvent);
2178
+ this.element.trigger.addEventListener('click', this.handleEvent);
2179
+ this.element.trigger.addEventListener('mouseenter', this.handleEvent);
2180
+ this.element.trigger.addEventListener('mouseleave', this.handleEvent);
2181
+ this.element.trigger.addEventListener('focus', this.handleEvent);
2182
+ this.element.trigger.addEventListener('blur', this.handleEvent);
2183
+ }
1996
2184
  }
1997
2185
 
1998
2186
  disconnect() {
1999
2187
  this.cleanupHideHandlers();
2000
- this.element.cleanup?.();
2001
-
2002
- // Remove event & keyboard listeners
2003
- if (this.element?.trigger) {
2004
- this.element.trigger.removeEventListener('keydown', this.handleEvent);
2005
- this.element.trigger.removeEventListener('click', this.handleEvent);
2006
- this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2007
- this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2008
- this.element.trigger.removeEventListener('focus', this.handleEvent);
2009
- this.element.trigger.removeEventListener('blur', this.handleEvent);
2188
+ if (this.element) {
2189
+ this.element.cleanup?.();
2190
+
2191
+ if (this.element.bib) {
2192
+ this.element.shadowRoot.append(this.element.bib);
2193
+ }
2194
+
2195
+ // Remove event & keyboard listeners
2196
+ if (this.element?.trigger) {
2197
+ this.element.trigger.removeEventListener('keydown', this.handleEvent);
2198
+ this.element.trigger.removeEventListener('click', this.handleEvent);
2199
+ this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2200
+ this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2201
+ this.element.trigger.removeEventListener('focus', this.handleEvent);
2202
+ this.element.trigger.removeEventListener('blur', this.handleEvent);
2203
+ }
2010
2204
  }
2011
2205
  }
2012
2206
  }
@@ -2969,6 +3163,11 @@ class AuroDropdown extends LitElement {
2969
3163
  * @private
2970
3164
  */
2971
3165
  this.helpTextTag = versioning.generateTag('auro-formkit-dropdown-helptext', helpTextVersion, AuroHelpText);
3166
+
3167
+ /**
3168
+ * @private
3169
+ */
3170
+ this.bindFocusEventToTrigger = this.bindFocusEventToTrigger.bind(this);
2972
3171
  }
2973
3172
 
2974
3173
  /**
@@ -3237,6 +3436,7 @@ class AuroDropdown extends LitElement {
3237
3436
  disconnectedCallback() {
3238
3437
  super.disconnectedCallback();
3239
3438
  this.floater.disconnect();
3439
+ this.clearTriggerFocusEventBinding();
3240
3440
  }
3241
3441
 
3242
3442
  updated(changedProperties) {
@@ -3351,6 +3551,62 @@ class AuroDropdown extends LitElement {
3351
3551
  return result;
3352
3552
  }
3353
3553
 
3554
+ /**
3555
+ * @private
3556
+ * Creates and dispatches a duplicate focus event on the trigger element.
3557
+ * @param {Event} event - The original focus event.
3558
+ */
3559
+ bindFocusEventToTrigger(event) {
3560
+ const dupEvent = new FocusEvent(event.type, {
3561
+ bubbles: false,
3562
+ cancelable: false,
3563
+ composed: true,
3564
+ });
3565
+ this.trigger.dispatchEvent(dupEvent);
3566
+ }
3567
+
3568
+ /**
3569
+ * @private
3570
+ * Sets up event listeners to deliver focus and blur events from nested Auro components within the trigger slot to trigger.
3571
+ * This ensures that focus/blur events originating from within these components are propagated to the trigger element itself.
3572
+ */
3573
+ setupTriggerFocusEventBinding() {
3574
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
3575
+ return;
3576
+ }
3577
+
3578
+ this.triggerContentSlot.forEach((node) => {
3579
+ if (node.querySelectorAll) {
3580
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
3581
+ auroElements.forEach((auroEl) => {
3582
+ auroEl.addEventListener('focus', this.bindFocusEventToTrigger);
3583
+ auroEl.addEventListener('blur', this.bindFocusEventToTrigger);
3584
+ });
3585
+ }
3586
+ });
3587
+ }
3588
+
3589
+ /**
3590
+ * Clears focus and blur event listeners from nested Auro components within the trigger slot.
3591
+ * @private
3592
+ * @returns {void}
3593
+ */
3594
+ clearTriggerFocusEventBinding() {
3595
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
3596
+ return;
3597
+ }
3598
+
3599
+ this.triggerContentSlot.forEach((node) => {
3600
+ if (node.querySelectorAll) {
3601
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
3602
+ auroElements.forEach((auroEl) => {
3603
+ auroEl.removeEventListener('focus', this.bindFocusEventToTrigger);
3604
+ auroEl.removeEventListener('blur', this.bindFocusEventToTrigger);
3605
+ });
3606
+ }
3607
+ });
3608
+ }
3609
+
3354
3610
  /**
3355
3611
  * Handles changes to the trigger content slot and updates related properties.
3356
3612
  *
@@ -3398,6 +3654,7 @@ class AuroDropdown extends LitElement {
3398
3654
  }
3399
3655
 
3400
3656
  if (this.triggerContentSlot) {
3657
+ this.setupTriggerFocusEventBinding();
3401
3658
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
3402
3659
  if (slot.textContent.trim()) {
3403
3660
  return true;
@@ -3503,6 +3760,7 @@ class AuroDropdown extends LitElement {
3503
3760
  <${this.dropdownBibTag}
3504
3761
  id="bib"
3505
3762
  role="tooltip"
3763
+ ?data-show="${this.isPopoverVisible}"
3506
3764
  ?isfullscreen="${this.isBibFullscreen}"
3507
3765
  ?common="${this.common}"
3508
3766
  ?rounded="${this.common || this.rounded}"
@@ -109,7 +109,7 @@ The use of any Auro custom element has a dependency on the [Auro Design Tokens](
109
109
  In cases where the project is not able to process JS assets, there are pre-processed assets available for use. Legacy browsers such as IE11 are no longer supported.
110
110
 
111
111
  ```html
112
- <script type="module" src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-formkit@2.2.1-beta.1/auro-form/+esm"></script>
112
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-formkit@2.2.1-beta.3/auro-form/+esm"></script>
113
113
  ```
114
114
  <!-- AURO-GENERATED-CONTENT:END -->
115
115