@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
@@ -1611,17 +1611,70 @@ const computePosition = (reference, floating, options) => {
1611
1611
  /* eslint-disable line-comment-position, no-inline-comments */
1612
1612
 
1613
1613
 
1614
+
1615
+ const MAX_CONFIGURATION_COUNT = 10;
1616
+
1614
1617
  class AuroFloatingUI {
1615
- constructor() {
1618
+
1619
+ /**
1620
+ * @private
1621
+ */
1622
+ static isMousePressed = false;
1623
+
1624
+ /**
1625
+ * @private
1626
+ */
1627
+ static isMousePressHandlerInitialized = false;
1628
+
1629
+ /**
1630
+ * @private
1631
+ */
1632
+ static setupMousePressChecker() {
1633
+ if (!AuroFloatingUI.isMousePressHandlerInitialized && window && window.addEventListener) {
1634
+ AuroFloatingUI.isMousePressHandlerInitialized = true;
1635
+
1636
+ const mouseEventGlobalHandler = (event) => {
1637
+ AuroFloatingUI.isMousePressed = event.type === 'mousedown';
1638
+ };
1639
+
1640
+ window.addEventListener('mousedown', mouseEventGlobalHandler);
1641
+ window.addEventListener('mouseup', mouseEventGlobalHandler);
1642
+ }
1643
+ }
1644
+
1645
+ constructor(element, behavior) {
1646
+ this.element = element;
1647
+ this.behavior = behavior;
1648
+
1616
1649
  // Store event listener references for cleanup
1617
1650
  this.focusHandler = null;
1618
1651
  this.clickHandler = null;
1619
1652
  this.keyDownHandler = null;
1620
-
1653
+
1654
+ /**
1655
+ * @private
1656
+ */
1657
+ this.configureTrial = 0;
1658
+
1621
1659
  /**
1622
1660
  * @private
1623
1661
  */
1624
1662
  this.eventPrefix = undefined;
1663
+
1664
+ /**
1665
+ * @private
1666
+ */
1667
+ this.id = undefined;
1668
+
1669
+ /**
1670
+ * @private
1671
+ */
1672
+ this.showing = false;
1673
+
1674
+ /**
1675
+ * @private
1676
+ */
1677
+ this.strategy = undefined;
1625
1678
  }
1626
1679
 
1627
1680
  /**
@@ -1649,29 +1702,48 @@ class AuroFloatingUI {
1649
1702
  * @private
1650
1703
  * Determines the positioning strategy based on the current viewport size and mobile breakpoint.
1651
1704
  *
1652
- * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
1705
+ * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
1653
1706
  * defined in the bib element. If it is, the strategy is set to 'fullscreen'; otherwise, it defaults to 'floating'.
1654
1707
  *
1655
- * @returns {String} The positioning strategy, either 'fullscreen' or 'floating'.
1708
+ * @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
1656
1709
  */
1657
1710
  getPositioningStrategy() {
1658
- let strategy = 'floating';
1659
- if (this.element.bib.mobileFullscreenBreakpoint) {
1660
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${this.element.bib.mobileFullscreenBreakpoint})`).matches;
1661
- if (smallerThanBreakpoint) {
1662
- strategy = 'fullscreen';
1663
- }
1711
+ const breakpoint = this.element.bib.mobileFullscreenBreakpoint || this.element.floaterConfig?.fullscreenBreakpoint;
1712
+ switch (this.behavior) {
1713
+ case "tooltip":
1714
+ return "floating";
1715
+ case "dialog":
1716
+ case "drawer":
1717
+ if (breakpoint) {
1718
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
1719
+
1720
+ this.element.expanded = smallerThanBreakpoint;
1721
+ }
1722
+ if (this.element.nested) {
1723
+ return "cover";
1724
+ }
1725
+ return 'fullscreen';
1726
+ case "dropdown":
1727
+ case undefined:
1728
+ case null:
1729
+ if (breakpoint) {
1730
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
1731
+ if (smallerThanBreakpoint) {
1732
+ return 'fullscreen';
1733
+ }
1734
+ }
1735
+ return "floating";
1736
+ default:
1737
+ return this.behavior;
1664
1738
  }
1665
-
1666
- return strategy;
1667
1739
  }
1668
1740
 
1669
1741
  /**
1670
1742
  * @private
1671
1743
  * Positions the bib element based on the current configuration and positioning strategy.
1672
1744
  *
1673
- * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
1674
- * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
1745
+ * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
1746
+ * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
1675
1747
  * and applies the calculated position to the bib's style.
1676
1748
  */
1677
1749
  position() {
@@ -1682,21 +1754,33 @@ class AuroFloatingUI {
1682
1754
  this.mirrorSize();
1683
1755
  // Define the middlware for the floater configuration
1684
1756
  const middleware = [
1685
- offset(this.element.floaterConfig.offset || 0),
1686
- ...(this.element.floaterConfig.flip ? [flip()] : []), // Add flip middleware if flip is enabled
1687
- ...(this.element.floaterConfig.autoPlacement ? [autoPlacement()] : []), // Add autoPlacement middleware if autoPlacement is enabled
1757
+ offset(this.element.floaterConfig?.offset || 0),
1758
+ ...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
1759
+ ...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
1688
1760
  ];
1689
1761
 
1690
1762
  // Compute the position of the bib
1691
1763
  computePosition(this.element.trigger, this.element.bib, {
1692
- placement: this.element.floaterConfig.placement || 'bottom',
1764
+ placement: this.element.floaterConfig?.placement,
1693
1765
  middleware: middleware || []
1694
- }).then(({x, y}) => { // eslint-disable-line id-length
1766
+ }).then(({ x, y }) => { // eslint-disable-line id-length
1695
1767
  Object.assign(this.element.bib.style, {
1696
1768
  left: `${x}px`,
1697
1769
  top: `${y}px`,
1698
1770
  });
1699
1771
  });
1772
+ } else if (strategy === 'cover') {
1773
+ // Compute the position of the bib
1774
+ computePosition(this.element.parentNode, this.element.bib, {
1775
+ placement: 'bottom-start'
1776
+ }).then(({ x, y }) => { // eslint-disable-line id-length
1777
+ Object.assign(this.element.bib.style, {
1778
+ left: `${x}px`,
1779
+ top: `${y - this.element.parentNode.offsetHeight}px`,
1780
+ width: `${this.element.parentNode.offsetWidth}px`,
1781
+ height: `${this.element.parentNode.offsetHeight}px`
1782
+ });
1783
+ });
1700
1784
  }
1701
1785
  }
1702
1786
 
@@ -1725,34 +1809,48 @@ class AuroFloatingUI {
1725
1809
  *
1726
1810
  * @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
1727
1811
  */
1728
- configureBibStrategy(strategy) {
1729
- const prevStrategy = this.element.isBibFullscreen ? 'fullscreen' : 'floating';
1730
- if (strategy === 'fullscreen') {
1812
+ configureBibStrategy(value) {
1813
+ if (value === 'fullscreen') {
1731
1814
  this.element.isBibFullscreen = true;
1732
1815
  // reset the prev position
1816
+ this.element.bib.setAttribute('isfullscreen', "");
1817
+ this.element.bib.style.position = 'fixed';
1733
1818
  this.element.bib.style.top = "0px";
1734
1819
  this.element.bib.style.left = "0px";
1820
+ this.element.bib.style.width = '';
1821
+ this.element.bib.style.height = '';
1735
1822
 
1736
1823
  // reset the size that was mirroring `size` css-part
1737
1824
  const bibContent = this.element.bib.shadowRoot.querySelector(".container");
1738
- bibContent.style.width = '';
1739
- bibContent.style.height = '';
1740
- bibContent.style.maxWidth = '';
1741
- bibContent.style.maxHeight = `${window.visualViewport.height}px`;
1825
+ if (bibContent) {
1826
+ bibContent.style.width = '';
1827
+ bibContent.style.height = '';
1828
+ bibContent.style.maxWidth = '';
1829
+ bibContent.style.maxHeight = `${window.visualViewport.height}px`;
1830
+ this.configureTrial = 0;
1831
+ } else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
1832
+ this.configureTrial += 1;
1833
+
1834
+ setTimeout(() => {
1835
+ this.configureBibStrategy(value);
1836
+ }, 0);
1837
+ }
1742
1838
 
1743
1839
  if (this.element.isPopoverVisible) {
1744
1840
  this.lockScroll(true);
1745
1841
  }
1746
1842
  } else {
1843
+ this.element.bib.style.position = '';
1844
+ this.element.bib.removeAttribute('isfullscreen');
1747
1845
  this.element.isBibFullscreen = false;
1748
-
1749
- this.lockScroll(false);
1750
1846
  }
1751
1847
 
1752
- if (prevStrategy !== strategy) {
1848
+ const isChanged = this.strategy && this.strategy !== value;
1849
+ this.strategy = value;
1850
+ if (isChanged) {
1753
1851
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-strategy-change` : 'strategy-change', {
1754
1852
  detail: {
1755
- strategy,
1853
+ value,
1756
1854
  },
1757
1855
  composed: true
1758
1856
  });
@@ -1763,18 +1861,6 @@ class AuroFloatingUI {
1763
1861
 
1764
1862
  updateState() {
1765
1863
  const isVisible = this.element.isPopoverVisible;
1766
-
1767
- // Refactor this to apply attribute to correct focusable element
1768
- // Reference Issue: https://github.com/AlaskaAirlines/auro-library/issues/105
1769
- //
1770
- // this.element.trigger.setAttribute('aria-expanded', isVisible);
1771
-
1772
- if (isVisible) {
1773
- this.element.bib.setAttribute('data-show', true);
1774
- } else {
1775
- this.element.bib.removeAttribute('data-show');
1776
- }
1777
-
1778
1864
  if (!isVisible) {
1779
1865
  this.cleanupHideHandlers();
1780
1866
  try {
@@ -1785,16 +1871,32 @@ class AuroFloatingUI {
1785
1871
  }
1786
1872
  }
1787
1873
 
1874
+ /**
1875
+ * @private
1876
+ * getting called on 'blur' in trigger or `focusin` in document
1877
+ *
1878
+ * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
1879
+ * This method checks if the currently active element is still within the trigger or bib.
1880
+ * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
1881
+ */
1788
1882
  handleFocusLoss() {
1789
- if (this.element.noHideOnThisFocusLoss ||
1790
- this.element.hasAttribute('noHideOnThisFocusLoss')) {
1883
+ // if mouse is being pressed, skip and let click event to handle the action
1884
+ if (AuroFloatingUI.isMousePressed) {
1885
+ return;
1886
+ }
1887
+
1888
+ if (this.element.noHideOnThisFocusLoss ||
1889
+ this.element.hasAttribute('noHideOnThisFocusLoss')) {
1791
1890
  return;
1792
1891
  }
1793
1892
 
1794
- const {activeElement} = document;
1795
- if (activeElement === document.querySelector('body') ||
1796
- this.element.contains(activeElement) ||
1797
- this.element.bibContent?.contains(activeElement)) {
1893
+ const { activeElement } = document;
1894
+ // if focus is still inside of trigger or bib, do not close
1895
+ if (this.element.contains(activeElement) || this.element.bib?.contains(activeElement)) {
1896
+ return;
1897
+ }
1898
+ // if fullscreen bib is still open and the focus is missing, do not close
1899
+ if (this.element.bib.hasAttribute('isfullscreen') && activeElement === document.body) {
1798
1900
  return;
1799
1901
  }
1800
1902
 
@@ -1802,31 +1904,66 @@ class AuroFloatingUI {
1802
1904
  }
1803
1905
 
1804
1906
  setupHideHandlers() {
1907
+ this.preventFocusLoseOnBibClick = (event) => {
1908
+ event.preventDefault();
1909
+ event.stopPropagation();
1910
+ };
1911
+ this.element.bib.addEventListener('mousedown', this.preventFocusLoseOnBibClick);
1912
+
1805
1913
  // Define handlers & store references
1806
1914
  this.focusHandler = () => this.handleFocusLoss();
1807
1915
 
1808
1916
  this.clickHandler = (evt) => {
1809
- if (!evt.composedPath().includes(this.element.trigger) &&
1810
- !evt.composedPath().includes(this.element.bibContent)) {
1811
- this.hideBib();
1917
+ if ((!evt.composedPath().includes(this.element.trigger) &&
1918
+ !evt.composedPath().includes(this.element.bib)) ||
1919
+ (this.element.bib.backdrop && evt.composedPath().includes(this.element.bib.backdrop))) {
1920
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
1921
+
1922
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI.element.isPopoverVisible) {
1923
+ // if something else is open, close that
1924
+ existedVisibleFloatingUI.hideBib();
1925
+ document.expandedAuroFormkitDropdown = null;
1926
+ document.expandedAuroFloater = this;
1927
+ } else {
1928
+ this.hideBib();
1929
+ }
1812
1930
  }
1813
1931
  };
1814
1932
 
1815
1933
  // ESC key handler
1816
1934
  this.keyDownHandler = (evt) => {
1817
1935
  if (evt.key === 'Escape' && this.element.isPopoverVisible) {
1936
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
1937
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this && existedVisibleFloatingUI.element.isPopoverVisible) {
1938
+ // if something else is open, let it handle itself
1939
+ return;
1940
+ }
1818
1941
  this.hideBib();
1819
1942
  }
1820
1943
  };
1821
1944
 
1822
- // Add event listeners using the stored references
1823
- document.addEventListener('focusin', this.focusHandler);
1824
- window.addEventListener('click', this.clickHandler);
1945
+ if (this.behavior !== 'drawer' && this.behavior !== 'dialog') {
1946
+ // Add event listeners using the stored references
1947
+ document.addEventListener('focusin', this.focusHandler);
1948
+ }
1949
+
1825
1950
  document.addEventListener('keydown', this.keyDownHandler);
1951
+
1952
+ // send this task to the end of queue to prevent conflicting
1953
+ // it conflicts if showBib gets call from a button that's not this.element.trigger
1954
+ setTimeout(() => {
1955
+ window.addEventListener('click', this.clickHandler);
1956
+ }, 0);
1826
1957
  }
1827
1958
 
1828
1959
  cleanupHideHandlers() {
1829
1960
  // Remove event listeners if they exist
1961
+
1962
+ if (this.preventFocusLoseOnBibClick) {
1963
+ this.element.bib.removeEventListener('mousedown', this.preventFocusLoseOnBibClick);
1964
+ delete this.preventFocusLoseOnBibClick;
1965
+ }
1966
+
1830
1967
  if (this.focusHandler) {
1831
1968
  document.removeEventListener('focusin', this.focusHandler);
1832
1969
  this.focusHandler = null;
@@ -1851,40 +1988,54 @@ class AuroFloatingUI {
1851
1988
 
1852
1989
  updateCurrentExpandedDropdown() {
1853
1990
  // Close any other dropdown that is already open
1854
- if (document.expandedAuroFormkitDropdown) {
1855
- document.expandedAuroFormkitDropdown.hide;
1991
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
1992
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
1993
+ existedVisibleFloatingUI.isPopoverVisible &&
1994
+ document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
1995
+ document.expandedAuroFloater.hideBib();
1856
1996
  }
1857
1997
 
1858
- document.expandedAuroFormkitDropdown = this;
1998
+ document.expandedAuroFloater = this;
1859
1999
  }
1860
2000
 
1861
2001
  showBib() {
1862
- if (!this.element.disabled && !this.element.isPopoverVisible) {
2002
+ if (!this.element.disabled && !this.showing) {
1863
2003
  this.updateCurrentExpandedDropdown();
1864
- this.element.isPopoverVisible = true;
1865
2004
  this.element.triggerChevron?.setAttribute('data-expanded', true);
1866
-
1867
- this.dispatchEventDropdownToggle();
1868
- this.position();
1869
-
1870
- // Clean up any existing handlers before setting up new ones
1871
- this.cleanupHideHandlers();
1872
- this.setupHideHandlers();
2005
+
2006
+ // prevent double showing: isPopovervisible gets first and showBib gets called later
2007
+ if (!this.showing) {
2008
+ if (!this.element.modal) {
2009
+ this.setupHideHandlers();
2010
+ }
2011
+ this.showing = true;
2012
+ this.element.isPopoverVisible = true;
2013
+ this.position();
2014
+ this.dispatchEventDropdownToggle();
2015
+ }
1873
2016
 
1874
2017
  // Setup auto update to handle resize and scroll
1875
- this.element.cleanup = autoUpdate(this.element.trigger, this.element.bib, () => {
2018
+ this.element.cleanup = autoUpdate(this.element.trigger || this.element.parentNode, this.element.bib, () => {
1876
2019
  this.position();
1877
2020
  });
1878
2021
  }
1879
2022
  }
1880
2023
 
1881
2024
  hideBib() {
1882
- if (this.element.isPopoverVisible && !this.element.disabled && !this.element.noToggle) {
1883
- this.element.isPopoverVisible = false;
2025
+ if (!this.element.disabled && !this.element.noToggle) {
1884
2026
  this.lockScroll(false);
1885
2027
  this.element.triggerChevron?.removeAttribute('data-expanded');
1886
- this.dispatchEventDropdownToggle();
2028
+
2029
+ if (this.element.isPopoverVisible) {
2030
+ this.element.isPopoverVisible = false;
2031
+ }
2032
+ if (this.showing) {
2033
+ this.cleanupHideHandlers();
2034
+ this.showing = false;
2035
+ this.dispatchEventDropdownToggle();
2036
+ }
1887
2037
  }
2038
+ document.expandedAuroFloater = null;
1888
2039
  }
1889
2040
 
1890
2041
  /**
@@ -1894,7 +2045,7 @@ class AuroFloatingUI {
1894
2045
  dispatchEventDropdownToggle() {
1895
2046
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-toggled` : 'toggled', {
1896
2047
  detail: {
1897
- expanded: this.element.isPopoverVisible,
2048
+ expanded: this.showing,
1898
2049
  },
1899
2050
  composed: true
1900
2051
  });
@@ -1942,15 +2093,18 @@ class AuroFloatingUI {
1942
2093
  break;
1943
2094
  case 'focus':
1944
2095
  if (this.element.focusShow) {
2096
+
1945
2097
  /*
1946
- This needs to better handle clicking that gives focus -
1947
- currently it shows and then immediately hides the bib
2098
+ This needs to better handle clicking that gives focus -
2099
+ currently it shows and then immediately hides the bib
1948
2100
  */
1949
2101
  this.showBib();
1950
2102
  }
1951
2103
  break;
1952
2104
  case 'blur':
1953
- this.handleFocusLoss();
2105
+ // send this task 100ms later queue to
2106
+ // wait a frame in case focus moves within the floating element/bib
2107
+ setTimeout(() => this.handleFocusLoss(), 0);
1954
2108
  break;
1955
2109
  case 'click':
1956
2110
  if (document.activeElement === document.body) {
@@ -1958,7 +2112,7 @@ class AuroFloatingUI {
1958
2112
  }
1959
2113
  this.handleClick();
1960
2114
  break;
1961
- // Do nothing
2115
+ // Do nothing
1962
2116
  }
1963
2117
  }
1964
2118
  }
@@ -2002,39 +2156,79 @@ class AuroFloatingUI {
2002
2156
  });
2003
2157
  }
2004
2158
 
2159
+ /**
2160
+ *
2161
+ * @param {*} eventPrefix
2162
+ */
2163
+ regenerateBibId() {
2164
+ this.id = this.element.getAttribute('id');
2165
+ if (!this.id) {
2166
+ this.id = window.crypto.randomUUID();
2167
+ this.element.setAttribute('id', this.id);
2168
+ }
2169
+
2170
+ this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
2171
+ }
2172
+
2005
2173
  configure(elem, eventPrefix) {
2174
+ AuroFloatingUI.setupMousePressChecker();
2175
+
2006
2176
  this.eventPrefix = eventPrefix;
2007
- this.element = elem;
2008
- this.element.trigger = this.element.shadowRoot.querySelector('#trigger');
2009
- this.element.bib = this.element.shadowRoot.querySelector('#bib');
2177
+ if (this.element !== elem) {
2178
+ this.element = elem;
2179
+ }
2180
+
2181
+ if (this.behavior !== this.element.behavior) {
2182
+ this.behavior = this.element.behavior;
2183
+ }
2184
+
2185
+ if (this.element.trigger) {
2186
+ this.disconnect();
2187
+ }
2188
+ this.element.trigger = this.element.triggerElement || this.element.shadowRoot.querySelector('#trigger') || this.element.trigger;
2189
+ this.element.bib = this.element.shadowRoot.querySelector('#bib') || this.element.bib;
2010
2190
  this.element.bibSizer = this.element.shadowRoot.querySelector('#bibSizer');
2011
2191
  this.element.triggerChevron = this.element.shadowRoot.querySelector('#showStateIcon');
2012
2192
 
2193
+
2194
+ if (this.element.floaterConfig) {
2195
+ this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
2196
+ }
2197
+
2013
2198
  document.body.append(this.element.bib);
2014
2199
 
2200
+ this.regenerateBibId();
2015
2201
  this.handleTriggerTabIndex();
2016
2202
 
2017
2203
  this.handleEvent = this.handleEvent.bind(this);
2018
- this.element.trigger.addEventListener('keydown', this.handleEvent);
2019
- this.element.trigger.addEventListener('click', this.handleEvent);
2020
- this.element.trigger.addEventListener('mouseenter', this.handleEvent);
2021
- this.element.trigger.addEventListener('mouseleave', this.handleEvent);
2022
- this.element.trigger.addEventListener('focus', this.handleEvent);
2023
- this.element.trigger.addEventListener('blur', this.handleEvent);
2204
+ if (this.element.trigger) {
2205
+ this.element.trigger.addEventListener('keydown', this.handleEvent);
2206
+ this.element.trigger.addEventListener('click', this.handleEvent);
2207
+ this.element.trigger.addEventListener('mouseenter', this.handleEvent);
2208
+ this.element.trigger.addEventListener('mouseleave', this.handleEvent);
2209
+ this.element.trigger.addEventListener('focus', this.handleEvent);
2210
+ this.element.trigger.addEventListener('blur', this.handleEvent);
2211
+ }
2024
2212
  }
2025
2213
 
2026
2214
  disconnect() {
2027
2215
  this.cleanupHideHandlers();
2028
- this.element.cleanup?.();
2029
-
2030
- // Remove event & keyboard listeners
2031
- if (this.element?.trigger) {
2032
- this.element.trigger.removeEventListener('keydown', this.handleEvent);
2033
- this.element.trigger.removeEventListener('click', this.handleEvent);
2034
- this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2035
- this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2036
- this.element.trigger.removeEventListener('focus', this.handleEvent);
2037
- this.element.trigger.removeEventListener('blur', this.handleEvent);
2216
+ if (this.element) {
2217
+ this.element.cleanup?.();
2218
+
2219
+ if (this.element.bib) {
2220
+ this.element.shadowRoot.append(this.element.bib);
2221
+ }
2222
+
2223
+ // Remove event & keyboard listeners
2224
+ if (this.element?.trigger) {
2225
+ this.element.trigger.removeEventListener('keydown', this.handleEvent);
2226
+ this.element.trigger.removeEventListener('click', this.handleEvent);
2227
+ this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2228
+ this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2229
+ this.element.trigger.removeEventListener('focus', this.handleEvent);
2230
+ this.element.trigger.removeEventListener('blur', this.handleEvent);
2231
+ }
2038
2232
  }
2039
2233
  }
2040
2234
  }
@@ -3016,6 +3210,11 @@ class AuroDropdown extends r {
3016
3210
  * @private
3017
3211
  */
3018
3212
  this.helpTextTag = versioning.generateTag('auro-formkit-dropdown-helptext', helpTextVersion, AuroHelpText);
3213
+
3214
+ /**
3215
+ * @private
3216
+ */
3217
+ this.bindFocusEventToTrigger = this.bindFocusEventToTrigger.bind(this);
3019
3218
  }
3020
3219
 
3021
3220
  /**
@@ -3284,6 +3483,7 @@ class AuroDropdown extends r {
3284
3483
  disconnectedCallback() {
3285
3484
  super.disconnectedCallback();
3286
3485
  this.floater.disconnect();
3486
+ this.clearTriggerFocusEventBinding();
3287
3487
  }
3288
3488
 
3289
3489
  updated(changedProperties) {
@@ -3398,6 +3598,62 @@ class AuroDropdown extends r {
3398
3598
  return result;
3399
3599
  }
3400
3600
 
3601
+ /**
3602
+ * @private
3603
+ * Creates and dispatches a duplicate focus event on the trigger element.
3604
+ * @param {Event} event - The original focus event.
3605
+ */
3606
+ bindFocusEventToTrigger(event) {
3607
+ const dupEvent = new FocusEvent(event.type, {
3608
+ bubbles: false,
3609
+ cancelable: false,
3610
+ composed: true,
3611
+ });
3612
+ this.trigger.dispatchEvent(dupEvent);
3613
+ }
3614
+
3615
+ /**
3616
+ * @private
3617
+ * Sets up event listeners to deliver focus and blur events from nested Auro components within the trigger slot to trigger.
3618
+ * This ensures that focus/blur events originating from within these components are propagated to the trigger element itself.
3619
+ */
3620
+ setupTriggerFocusEventBinding() {
3621
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
3622
+ return;
3623
+ }
3624
+
3625
+ this.triggerContentSlot.forEach((node) => {
3626
+ if (node.querySelectorAll) {
3627
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
3628
+ auroElements.forEach((auroEl) => {
3629
+ auroEl.addEventListener('focus', this.bindFocusEventToTrigger);
3630
+ auroEl.addEventListener('blur', this.bindFocusEventToTrigger);
3631
+ });
3632
+ }
3633
+ });
3634
+ }
3635
+
3636
+ /**
3637
+ * Clears focus and blur event listeners from nested Auro components within the trigger slot.
3638
+ * @private
3639
+ * @returns {void}
3640
+ */
3641
+ clearTriggerFocusEventBinding() {
3642
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
3643
+ return;
3644
+ }
3645
+
3646
+ this.triggerContentSlot.forEach((node) => {
3647
+ if (node.querySelectorAll) {
3648
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
3649
+ auroElements.forEach((auroEl) => {
3650
+ auroEl.removeEventListener('focus', this.bindFocusEventToTrigger);
3651
+ auroEl.removeEventListener('blur', this.bindFocusEventToTrigger);
3652
+ });
3653
+ }
3654
+ });
3655
+ }
3656
+
3401
3657
  /**
3402
3658
  * Handles changes to the trigger content slot and updates related properties.
3403
3659
  *
@@ -3445,6 +3701,7 @@ class AuroDropdown extends r {
3445
3701
  }
3446
3702
 
3447
3703
  if (this.triggerContentSlot) {
3704
+ this.setupTriggerFocusEventBinding();
3448
3705
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
3449
3706
  if (slot.textContent.trim()) {
3450
3707
  return true;
@@ -3550,6 +3807,7 @@ class AuroDropdown extends r {
3550
3807
  <${this.dropdownBibTag}
3551
3808
  id="bib"
3552
3809
  role="tooltip"
3810
+ ?data-show="${this.isPopoverVisible}"
3553
3811
  ?isfullscreen="${this.isBibFullscreen}"
3554
3812
  ?common="${this.common}"
3555
3813
  ?rounded="${this.common || this.rounded}"
@@ -107,7 +107,7 @@ The use of any Auro custom element has a dependency on the [Auro Design Tokens](
107
107
  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.
108
108
 
109
109
  ```html
110
- <script type="module" src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-formkit@2.2.1-beta.1/auro-dropdown/+esm"></script>
110
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-formkit@2.2.1-beta.3/auro-dropdown/+esm"></script>
111
111
  ```
112
112
  <!-- AURO-GENERATED-CONTENT:END -->
113
113