@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
@@ -2004,17 +2004,70 @@ const computePosition = (reference, floating, options) => {
2004
2004
  /* eslint-disable line-comment-position, no-inline-comments */
2005
2005
 
2006
2006
 
2007
+
2008
+ const MAX_CONFIGURATION_COUNT = 10;
2009
+
2007
2010
  class AuroFloatingUI {
2008
- constructor() {
2011
+
2012
+ /**
2013
+ * @private
2014
+ */
2015
+ static isMousePressed = false;
2016
+
2017
+ /**
2018
+ * @private
2019
+ */
2020
+ static isMousePressHandlerInitialized = false;
2021
+
2022
+ /**
2023
+ * @private
2024
+ */
2025
+ static setupMousePressChecker() {
2026
+ if (!AuroFloatingUI.isMousePressHandlerInitialized && window && window.addEventListener) {
2027
+ AuroFloatingUI.isMousePressHandlerInitialized = true;
2028
+
2029
+ const mouseEventGlobalHandler = (event) => {
2030
+ AuroFloatingUI.isMousePressed = event.type === 'mousedown';
2031
+ };
2032
+
2033
+ window.addEventListener('mousedown', mouseEventGlobalHandler);
2034
+ window.addEventListener('mouseup', mouseEventGlobalHandler);
2035
+ }
2036
+ }
2037
+
2038
+ constructor(element, behavior) {
2039
+ this.element = element;
2040
+ this.behavior = behavior;
2041
+
2009
2042
  // Store event listener references for cleanup
2010
2043
  this.focusHandler = null;
2011
2044
  this.clickHandler = null;
2012
2045
  this.keyDownHandler = null;
2013
-
2046
+
2047
+ /**
2048
+ * @private
2049
+ */
2050
+ this.configureTrial = 0;
2051
+
2014
2052
  /**
2015
2053
  * @private
2016
2054
  */
2017
2055
  this.eventPrefix = undefined;
2056
+
2057
+ /**
2058
+ * @private
2059
+ */
2060
+ this.id = undefined;
2061
+
2062
+ /**
2063
+ * @private
2064
+ */
2065
+ this.showing = false;
2066
+
2067
+ /**
2068
+ * @private
2069
+ */
2070
+ this.strategy = undefined;
2018
2071
  }
2019
2072
 
2020
2073
  /**
@@ -2042,29 +2095,48 @@ class AuroFloatingUI {
2042
2095
  * @private
2043
2096
  * Determines the positioning strategy based on the current viewport size and mobile breakpoint.
2044
2097
  *
2045
- * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
2098
+ * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
2046
2099
  * defined in the bib element. If it is, the strategy is set to 'fullscreen'; otherwise, it defaults to 'floating'.
2047
2100
  *
2048
- * @returns {String} The positioning strategy, either 'fullscreen' or 'floating'.
2101
+ * @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
2049
2102
  */
2050
2103
  getPositioningStrategy() {
2051
- let strategy = 'floating';
2052
- if (this.element.bib.mobileFullscreenBreakpoint) {
2053
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${this.element.bib.mobileFullscreenBreakpoint})`).matches;
2054
- if (smallerThanBreakpoint) {
2055
- strategy = 'fullscreen';
2056
- }
2104
+ const breakpoint = this.element.bib.mobileFullscreenBreakpoint || this.element.floaterConfig?.fullscreenBreakpoint;
2105
+ switch (this.behavior) {
2106
+ case "tooltip":
2107
+ return "floating";
2108
+ case "dialog":
2109
+ case "drawer":
2110
+ if (breakpoint) {
2111
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
2112
+
2113
+ this.element.expanded = smallerThanBreakpoint;
2114
+ }
2115
+ if (this.element.nested) {
2116
+ return "cover";
2117
+ }
2118
+ return 'fullscreen';
2119
+ case "dropdown":
2120
+ case undefined:
2121
+ case null:
2122
+ if (breakpoint) {
2123
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
2124
+ if (smallerThanBreakpoint) {
2125
+ return 'fullscreen';
2126
+ }
2127
+ }
2128
+ return "floating";
2129
+ default:
2130
+ return this.behavior;
2057
2131
  }
2058
-
2059
- return strategy;
2060
2132
  }
2061
2133
 
2062
2134
  /**
2063
2135
  * @private
2064
2136
  * Positions the bib element based on the current configuration and positioning strategy.
2065
2137
  *
2066
- * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
2067
- * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
2138
+ * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
2139
+ * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
2068
2140
  * and applies the calculated position to the bib's style.
2069
2141
  */
2070
2142
  position() {
@@ -2075,21 +2147,33 @@ class AuroFloatingUI {
2075
2147
  this.mirrorSize();
2076
2148
  // Define the middlware for the floater configuration
2077
2149
  const middleware = [
2078
- offset(this.element.floaterConfig.offset || 0),
2079
- ...(this.element.floaterConfig.flip ? [flip()] : []), // Add flip middleware if flip is enabled
2080
- ...(this.element.floaterConfig.autoPlacement ? [autoPlacement()] : []), // Add autoPlacement middleware if autoPlacement is enabled
2150
+ offset(this.element.floaterConfig?.offset || 0),
2151
+ ...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
2152
+ ...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
2081
2153
  ];
2082
2154
 
2083
2155
  // Compute the position of the bib
2084
2156
  computePosition(this.element.trigger, this.element.bib, {
2085
- placement: this.element.floaterConfig.placement || 'bottom',
2157
+ placement: this.element.floaterConfig?.placement,
2086
2158
  middleware: middleware || []
2087
- }).then(({x, y}) => { // eslint-disable-line id-length
2159
+ }).then(({ x, y }) => { // eslint-disable-line id-length
2088
2160
  Object.assign(this.element.bib.style, {
2089
2161
  left: `${x}px`,
2090
2162
  top: `${y}px`,
2091
2163
  });
2092
2164
  });
2165
+ } else if (strategy === 'cover') {
2166
+ // Compute the position of the bib
2167
+ computePosition(this.element.parentNode, this.element.bib, {
2168
+ placement: 'bottom-start'
2169
+ }).then(({ x, y }) => { // eslint-disable-line id-length
2170
+ Object.assign(this.element.bib.style, {
2171
+ left: `${x}px`,
2172
+ top: `${y - this.element.parentNode.offsetHeight}px`,
2173
+ width: `${this.element.parentNode.offsetWidth}px`,
2174
+ height: `${this.element.parentNode.offsetHeight}px`
2175
+ });
2176
+ });
2093
2177
  }
2094
2178
  }
2095
2179
 
@@ -2118,34 +2202,48 @@ class AuroFloatingUI {
2118
2202
  *
2119
2203
  * @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
2120
2204
  */
2121
- configureBibStrategy(strategy) {
2122
- const prevStrategy = this.element.isBibFullscreen ? 'fullscreen' : 'floating';
2123
- if (strategy === 'fullscreen') {
2205
+ configureBibStrategy(value) {
2206
+ if (value === 'fullscreen') {
2124
2207
  this.element.isBibFullscreen = true;
2125
2208
  // reset the prev position
2209
+ this.element.bib.setAttribute('isfullscreen', "");
2210
+ this.element.bib.style.position = 'fixed';
2126
2211
  this.element.bib.style.top = "0px";
2127
2212
  this.element.bib.style.left = "0px";
2213
+ this.element.bib.style.width = '';
2214
+ this.element.bib.style.height = '';
2128
2215
 
2129
2216
  // reset the size that was mirroring `size` css-part
2130
2217
  const bibContent = this.element.bib.shadowRoot.querySelector(".container");
2131
- bibContent.style.width = '';
2132
- bibContent.style.height = '';
2133
- bibContent.style.maxWidth = '';
2134
- bibContent.style.maxHeight = `${window.visualViewport.height}px`;
2218
+ if (bibContent) {
2219
+ bibContent.style.width = '';
2220
+ bibContent.style.height = '';
2221
+ bibContent.style.maxWidth = '';
2222
+ bibContent.style.maxHeight = `${window.visualViewport.height}px`;
2223
+ this.configureTrial = 0;
2224
+ } else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
2225
+ this.configureTrial += 1;
2226
+
2227
+ setTimeout(() => {
2228
+ this.configureBibStrategy(value);
2229
+ }, 0);
2230
+ }
2135
2231
 
2136
2232
  if (this.element.isPopoverVisible) {
2137
2233
  this.lockScroll(true);
2138
2234
  }
2139
2235
  } else {
2236
+ this.element.bib.style.position = '';
2237
+ this.element.bib.removeAttribute('isfullscreen');
2140
2238
  this.element.isBibFullscreen = false;
2141
-
2142
- this.lockScroll(false);
2143
2239
  }
2144
2240
 
2145
- if (prevStrategy !== strategy) {
2241
+ const isChanged = this.strategy && this.strategy !== value;
2242
+ this.strategy = value;
2243
+ if (isChanged) {
2146
2244
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-strategy-change` : 'strategy-change', {
2147
2245
  detail: {
2148
- strategy,
2246
+ value,
2149
2247
  },
2150
2248
  composed: true
2151
2249
  });
@@ -2156,18 +2254,6 @@ class AuroFloatingUI {
2156
2254
 
2157
2255
  updateState() {
2158
2256
  const isVisible = this.element.isPopoverVisible;
2159
-
2160
- // Refactor this to apply attribute to correct focusable element
2161
- // Reference Issue: https://github.com/AlaskaAirlines/auro-library/issues/105
2162
- //
2163
- // this.element.trigger.setAttribute('aria-expanded', isVisible);
2164
-
2165
- if (isVisible) {
2166
- this.element.bib.setAttribute('data-show', true);
2167
- } else {
2168
- this.element.bib.removeAttribute('data-show');
2169
- }
2170
-
2171
2257
  if (!isVisible) {
2172
2258
  this.cleanupHideHandlers();
2173
2259
  try {
@@ -2178,16 +2264,32 @@ class AuroFloatingUI {
2178
2264
  }
2179
2265
  }
2180
2266
 
2267
+ /**
2268
+ * @private
2269
+ * getting called on 'blur' in trigger or `focusin` in document
2270
+ *
2271
+ * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
2272
+ * This method checks if the currently active element is still within the trigger or bib.
2273
+ * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
2274
+ */
2181
2275
  handleFocusLoss() {
2182
- if (this.element.noHideOnThisFocusLoss ||
2183
- this.element.hasAttribute('noHideOnThisFocusLoss')) {
2276
+ // if mouse is being pressed, skip and let click event to handle the action
2277
+ if (AuroFloatingUI.isMousePressed) {
2278
+ return;
2279
+ }
2280
+
2281
+ if (this.element.noHideOnThisFocusLoss ||
2282
+ this.element.hasAttribute('noHideOnThisFocusLoss')) {
2184
2283
  return;
2185
2284
  }
2186
2285
 
2187
- const {activeElement} = document;
2188
- if (activeElement === document.querySelector('body') ||
2189
- this.element.contains(activeElement) ||
2190
- this.element.bibContent?.contains(activeElement)) {
2286
+ const { activeElement } = document;
2287
+ // if focus is still inside of trigger or bib, do not close
2288
+ if (this.element.contains(activeElement) || this.element.bib?.contains(activeElement)) {
2289
+ return;
2290
+ }
2291
+ // if fullscreen bib is still open and the focus is missing, do not close
2292
+ if (this.element.bib.hasAttribute('isfullscreen') && activeElement === document.body) {
2191
2293
  return;
2192
2294
  }
2193
2295
 
@@ -2195,31 +2297,66 @@ class AuroFloatingUI {
2195
2297
  }
2196
2298
 
2197
2299
  setupHideHandlers() {
2300
+ this.preventFocusLoseOnBibClick = (event) => {
2301
+ event.preventDefault();
2302
+ event.stopPropagation();
2303
+ };
2304
+ this.element.bib.addEventListener('mousedown', this.preventFocusLoseOnBibClick);
2305
+
2198
2306
  // Define handlers & store references
2199
2307
  this.focusHandler = () => this.handleFocusLoss();
2200
2308
 
2201
2309
  this.clickHandler = (evt) => {
2202
- if (!evt.composedPath().includes(this.element.trigger) &&
2203
- !evt.composedPath().includes(this.element.bibContent)) {
2204
- this.hideBib();
2310
+ if ((!evt.composedPath().includes(this.element.trigger) &&
2311
+ !evt.composedPath().includes(this.element.bib)) ||
2312
+ (this.element.bib.backdrop && evt.composedPath().includes(this.element.bib.backdrop))) {
2313
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2314
+
2315
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI.element.isPopoverVisible) {
2316
+ // if something else is open, close that
2317
+ existedVisibleFloatingUI.hideBib();
2318
+ document.expandedAuroFormkitDropdown = null;
2319
+ document.expandedAuroFloater = this;
2320
+ } else {
2321
+ this.hideBib();
2322
+ }
2205
2323
  }
2206
2324
  };
2207
2325
 
2208
2326
  // ESC key handler
2209
2327
  this.keyDownHandler = (evt) => {
2210
2328
  if (evt.key === 'Escape' && this.element.isPopoverVisible) {
2329
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2330
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this && existedVisibleFloatingUI.element.isPopoverVisible) {
2331
+ // if something else is open, let it handle itself
2332
+ return;
2333
+ }
2211
2334
  this.hideBib();
2212
2335
  }
2213
2336
  };
2214
2337
 
2215
- // Add event listeners using the stored references
2216
- document.addEventListener('focusin', this.focusHandler);
2217
- window.addEventListener('click', this.clickHandler);
2338
+ if (this.behavior !== 'drawer' && this.behavior !== 'dialog') {
2339
+ // Add event listeners using the stored references
2340
+ document.addEventListener('focusin', this.focusHandler);
2341
+ }
2342
+
2218
2343
  document.addEventListener('keydown', this.keyDownHandler);
2344
+
2345
+ // send this task to the end of queue to prevent conflicting
2346
+ // it conflicts if showBib gets call from a button that's not this.element.trigger
2347
+ setTimeout(() => {
2348
+ window.addEventListener('click', this.clickHandler);
2349
+ }, 0);
2219
2350
  }
2220
2351
 
2221
2352
  cleanupHideHandlers() {
2222
2353
  // Remove event listeners if they exist
2354
+
2355
+ if (this.preventFocusLoseOnBibClick) {
2356
+ this.element.bib.removeEventListener('mousedown', this.preventFocusLoseOnBibClick);
2357
+ delete this.preventFocusLoseOnBibClick;
2358
+ }
2359
+
2223
2360
  if (this.focusHandler) {
2224
2361
  document.removeEventListener('focusin', this.focusHandler);
2225
2362
  this.focusHandler = null;
@@ -2244,40 +2381,54 @@ class AuroFloatingUI {
2244
2381
 
2245
2382
  updateCurrentExpandedDropdown() {
2246
2383
  // Close any other dropdown that is already open
2247
- if (document.expandedAuroFormkitDropdown) {
2248
- document.expandedAuroFormkitDropdown.hide;
2384
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2385
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
2386
+ existedVisibleFloatingUI.isPopoverVisible &&
2387
+ document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
2388
+ document.expandedAuroFloater.hideBib();
2249
2389
  }
2250
2390
 
2251
- document.expandedAuroFormkitDropdown = this;
2391
+ document.expandedAuroFloater = this;
2252
2392
  }
2253
2393
 
2254
2394
  showBib() {
2255
- if (!this.element.disabled && !this.element.isPopoverVisible) {
2395
+ if (!this.element.disabled && !this.showing) {
2256
2396
  this.updateCurrentExpandedDropdown();
2257
- this.element.isPopoverVisible = true;
2258
2397
  this.element.triggerChevron?.setAttribute('data-expanded', true);
2259
-
2260
- this.dispatchEventDropdownToggle();
2261
- this.position();
2262
-
2263
- // Clean up any existing handlers before setting up new ones
2264
- this.cleanupHideHandlers();
2265
- this.setupHideHandlers();
2398
+
2399
+ // prevent double showing: isPopovervisible gets first and showBib gets called later
2400
+ if (!this.showing) {
2401
+ if (!this.element.modal) {
2402
+ this.setupHideHandlers();
2403
+ }
2404
+ this.showing = true;
2405
+ this.element.isPopoverVisible = true;
2406
+ this.position();
2407
+ this.dispatchEventDropdownToggle();
2408
+ }
2266
2409
 
2267
2410
  // Setup auto update to handle resize and scroll
2268
- this.element.cleanup = autoUpdate(this.element.trigger, this.element.bib, () => {
2411
+ this.element.cleanup = autoUpdate(this.element.trigger || this.element.parentNode, this.element.bib, () => {
2269
2412
  this.position();
2270
2413
  });
2271
2414
  }
2272
2415
  }
2273
2416
 
2274
2417
  hideBib() {
2275
- if (this.element.isPopoverVisible && !this.element.disabled && !this.element.noToggle) {
2276
- this.element.isPopoverVisible = false;
2418
+ if (!this.element.disabled && !this.element.noToggle) {
2277
2419
  this.lockScroll(false);
2278
2420
  this.element.triggerChevron?.removeAttribute('data-expanded');
2279
- this.dispatchEventDropdownToggle();
2421
+
2422
+ if (this.element.isPopoverVisible) {
2423
+ this.element.isPopoverVisible = false;
2424
+ }
2425
+ if (this.showing) {
2426
+ this.cleanupHideHandlers();
2427
+ this.showing = false;
2428
+ this.dispatchEventDropdownToggle();
2429
+ }
2280
2430
  }
2431
+ document.expandedAuroFloater = null;
2281
2432
  }
2282
2433
 
2283
2434
  /**
@@ -2287,7 +2438,7 @@ class AuroFloatingUI {
2287
2438
  dispatchEventDropdownToggle() {
2288
2439
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-toggled` : 'toggled', {
2289
2440
  detail: {
2290
- expanded: this.element.isPopoverVisible,
2441
+ expanded: this.showing,
2291
2442
  },
2292
2443
  composed: true
2293
2444
  });
@@ -2335,15 +2486,18 @@ class AuroFloatingUI {
2335
2486
  break;
2336
2487
  case 'focus':
2337
2488
  if (this.element.focusShow) {
2489
+
2338
2490
  /*
2339
- This needs to better handle clicking that gives focus -
2340
- currently it shows and then immediately hides the bib
2491
+ This needs to better handle clicking that gives focus -
2492
+ currently it shows and then immediately hides the bib
2341
2493
  */
2342
2494
  this.showBib();
2343
2495
  }
2344
2496
  break;
2345
2497
  case 'blur':
2346
- this.handleFocusLoss();
2498
+ // send this task 100ms later queue to
2499
+ // wait a frame in case focus moves within the floating element/bib
2500
+ setTimeout(() => this.handleFocusLoss(), 0);
2347
2501
  break;
2348
2502
  case 'click':
2349
2503
  if (document.activeElement === document.body) {
@@ -2351,7 +2505,7 @@ class AuroFloatingUI {
2351
2505
  }
2352
2506
  this.handleClick();
2353
2507
  break;
2354
- // Do nothing
2508
+ // Do nothing
2355
2509
  }
2356
2510
  }
2357
2511
  }
@@ -2395,39 +2549,79 @@ class AuroFloatingUI {
2395
2549
  });
2396
2550
  }
2397
2551
 
2552
+ /**
2553
+ *
2554
+ * @param {*} eventPrefix
2555
+ */
2556
+ regenerateBibId() {
2557
+ this.id = this.element.getAttribute('id');
2558
+ if (!this.id) {
2559
+ this.id = window.crypto.randomUUID();
2560
+ this.element.setAttribute('id', this.id);
2561
+ }
2562
+
2563
+ this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
2564
+ }
2565
+
2398
2566
  configure(elem, eventPrefix) {
2567
+ AuroFloatingUI.setupMousePressChecker();
2568
+
2399
2569
  this.eventPrefix = eventPrefix;
2400
- this.element = elem;
2401
- this.element.trigger = this.element.shadowRoot.querySelector('#trigger');
2402
- this.element.bib = this.element.shadowRoot.querySelector('#bib');
2570
+ if (this.element !== elem) {
2571
+ this.element = elem;
2572
+ }
2573
+
2574
+ if (this.behavior !== this.element.behavior) {
2575
+ this.behavior = this.element.behavior;
2576
+ }
2577
+
2578
+ if (this.element.trigger) {
2579
+ this.disconnect();
2580
+ }
2581
+ this.element.trigger = this.element.triggerElement || this.element.shadowRoot.querySelector('#trigger') || this.element.trigger;
2582
+ this.element.bib = this.element.shadowRoot.querySelector('#bib') || this.element.bib;
2403
2583
  this.element.bibSizer = this.element.shadowRoot.querySelector('#bibSizer');
2404
2584
  this.element.triggerChevron = this.element.shadowRoot.querySelector('#showStateIcon');
2405
2585
 
2586
+
2587
+ if (this.element.floaterConfig) {
2588
+ this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
2589
+ }
2590
+
2406
2591
  document.body.append(this.element.bib);
2407
2592
 
2593
+ this.regenerateBibId();
2408
2594
  this.handleTriggerTabIndex();
2409
2595
 
2410
2596
  this.handleEvent = this.handleEvent.bind(this);
2411
- this.element.trigger.addEventListener('keydown', this.handleEvent);
2412
- this.element.trigger.addEventListener('click', this.handleEvent);
2413
- this.element.trigger.addEventListener('mouseenter', this.handleEvent);
2414
- this.element.trigger.addEventListener('mouseleave', this.handleEvent);
2415
- this.element.trigger.addEventListener('focus', this.handleEvent);
2416
- this.element.trigger.addEventListener('blur', this.handleEvent);
2597
+ if (this.element.trigger) {
2598
+ this.element.trigger.addEventListener('keydown', this.handleEvent);
2599
+ this.element.trigger.addEventListener('click', this.handleEvent);
2600
+ this.element.trigger.addEventListener('mouseenter', this.handleEvent);
2601
+ this.element.trigger.addEventListener('mouseleave', this.handleEvent);
2602
+ this.element.trigger.addEventListener('focus', this.handleEvent);
2603
+ this.element.trigger.addEventListener('blur', this.handleEvent);
2604
+ }
2417
2605
  }
2418
2606
 
2419
2607
  disconnect() {
2420
2608
  this.cleanupHideHandlers();
2421
- this.element.cleanup?.();
2422
-
2423
- // Remove event & keyboard listeners
2424
- if (this.element?.trigger) {
2425
- this.element.trigger.removeEventListener('keydown', this.handleEvent);
2426
- this.element.trigger.removeEventListener('click', this.handleEvent);
2427
- this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2428
- this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2429
- this.element.trigger.removeEventListener('focus', this.handleEvent);
2430
- this.element.trigger.removeEventListener('blur', this.handleEvent);
2609
+ if (this.element) {
2610
+ this.element.cleanup?.();
2611
+
2612
+ if (this.element.bib) {
2613
+ this.element.shadowRoot.append(this.element.bib);
2614
+ }
2615
+
2616
+ // Remove event & keyboard listeners
2617
+ if (this.element?.trigger) {
2618
+ this.element.trigger.removeEventListener('keydown', this.handleEvent);
2619
+ this.element.trigger.removeEventListener('click', this.handleEvent);
2620
+ this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2621
+ this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2622
+ this.element.trigger.removeEventListener('focus', this.handleEvent);
2623
+ this.element.trigger.removeEventListener('blur', this.handleEvent);
2624
+ }
2431
2625
  }
2432
2626
  }
2433
2627
  }
@@ -3390,6 +3584,11 @@ class AuroDropdown extends LitElement {
3390
3584
  * @private
3391
3585
  */
3392
3586
  this.helpTextTag = versioning.generateTag('auro-formkit-dropdown-helptext', helpTextVersion, AuroHelpText);
3587
+
3588
+ /**
3589
+ * @private
3590
+ */
3591
+ this.bindFocusEventToTrigger = this.bindFocusEventToTrigger.bind(this);
3393
3592
  }
3394
3593
 
3395
3594
  /**
@@ -3658,6 +3857,7 @@ class AuroDropdown extends LitElement {
3658
3857
  disconnectedCallback() {
3659
3858
  super.disconnectedCallback();
3660
3859
  this.floater.disconnect();
3860
+ this.clearTriggerFocusEventBinding();
3661
3861
  }
3662
3862
 
3663
3863
  updated(changedProperties) {
@@ -3772,6 +3972,62 @@ class AuroDropdown extends LitElement {
3772
3972
  return result;
3773
3973
  }
3774
3974
 
3975
+ /**
3976
+ * @private
3977
+ * Creates and dispatches a duplicate focus event on the trigger element.
3978
+ * @param {Event} event - The original focus event.
3979
+ */
3980
+ bindFocusEventToTrigger(event) {
3981
+ const dupEvent = new FocusEvent(event.type, {
3982
+ bubbles: false,
3983
+ cancelable: false,
3984
+ composed: true,
3985
+ });
3986
+ this.trigger.dispatchEvent(dupEvent);
3987
+ }
3988
+
3989
+ /**
3990
+ * @private
3991
+ * Sets up event listeners to deliver focus and blur events from nested Auro components within the trigger slot to trigger.
3992
+ * This ensures that focus/blur events originating from within these components are propagated to the trigger element itself.
3993
+ */
3994
+ setupTriggerFocusEventBinding() {
3995
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
3996
+ return;
3997
+ }
3998
+
3999
+ this.triggerContentSlot.forEach((node) => {
4000
+ if (node.querySelectorAll) {
4001
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
4002
+ auroElements.forEach((auroEl) => {
4003
+ auroEl.addEventListener('focus', this.bindFocusEventToTrigger);
4004
+ auroEl.addEventListener('blur', this.bindFocusEventToTrigger);
4005
+ });
4006
+ }
4007
+ });
4008
+ }
4009
+
4010
+ /**
4011
+ * Clears focus and blur event listeners from nested Auro components within the trigger slot.
4012
+ * @private
4013
+ * @returns {void}
4014
+ */
4015
+ clearTriggerFocusEventBinding() {
4016
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
4017
+ return;
4018
+ }
4019
+
4020
+ this.triggerContentSlot.forEach((node) => {
4021
+ if (node.querySelectorAll) {
4022
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
4023
+ auroElements.forEach((auroEl) => {
4024
+ auroEl.removeEventListener('focus', this.bindFocusEventToTrigger);
4025
+ auroEl.removeEventListener('blur', this.bindFocusEventToTrigger);
4026
+ });
4027
+ }
4028
+ });
4029
+ }
4030
+
3775
4031
  /**
3776
4032
  * Handles changes to the trigger content slot and updates related properties.
3777
4033
  *
@@ -3819,6 +4075,7 @@ class AuroDropdown extends LitElement {
3819
4075
  }
3820
4076
 
3821
4077
  if (this.triggerContentSlot) {
4078
+ this.setupTriggerFocusEventBinding();
3822
4079
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
3823
4080
  if (slot.textContent.trim()) {
3824
4081
  return true;
@@ -3924,6 +4181,7 @@ class AuroDropdown extends LitElement {
3924
4181
  <${this.dropdownBibTag}
3925
4182
  id="bib"
3926
4183
  role="tooltip"
4184
+ ?data-show="${this.isPopoverVisible}"
3927
4185
  ?isfullscreen="${this.isBibFullscreen}"
3928
4186
  ?common="${this.common}"
3929
4187
  ?rounded="${this.common || this.rounded}"