@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
@@ -2074,17 +2074,70 @@ const computePosition = (reference, floating, options) => {
2074
2074
  /* eslint-disable line-comment-position, no-inline-comments */
2075
2075
 
2076
2076
 
2077
+
2078
+ const MAX_CONFIGURATION_COUNT = 10;
2079
+
2077
2080
  class AuroFloatingUI {
2078
- constructor() {
2081
+
2082
+ /**
2083
+ * @private
2084
+ */
2085
+ static isMousePressed = false;
2086
+
2087
+ /**
2088
+ * @private
2089
+ */
2090
+ static isMousePressHandlerInitialized = false;
2091
+
2092
+ /**
2093
+ * @private
2094
+ */
2095
+ static setupMousePressChecker() {
2096
+ if (!AuroFloatingUI.isMousePressHandlerInitialized && window && window.addEventListener) {
2097
+ AuroFloatingUI.isMousePressHandlerInitialized = true;
2098
+
2099
+ const mouseEventGlobalHandler = (event) => {
2100
+ AuroFloatingUI.isMousePressed = event.type === 'mousedown';
2101
+ };
2102
+
2103
+ window.addEventListener('mousedown', mouseEventGlobalHandler);
2104
+ window.addEventListener('mouseup', mouseEventGlobalHandler);
2105
+ }
2106
+ }
2107
+
2108
+ constructor(element, behavior) {
2109
+ this.element = element;
2110
+ this.behavior = behavior;
2111
+
2079
2112
  // Store event listener references for cleanup
2080
2113
  this.focusHandler = null;
2081
2114
  this.clickHandler = null;
2082
2115
  this.keyDownHandler = null;
2083
-
2116
+
2117
+ /**
2118
+ * @private
2119
+ */
2120
+ this.configureTrial = 0;
2121
+
2084
2122
  /**
2085
2123
  * @private
2086
2124
  */
2087
2125
  this.eventPrefix = undefined;
2126
+
2127
+ /**
2128
+ * @private
2129
+ */
2130
+ this.id = undefined;
2131
+
2132
+ /**
2133
+ * @private
2134
+ */
2135
+ this.showing = false;
2136
+
2137
+ /**
2138
+ * @private
2139
+ */
2140
+ this.strategy = undefined;
2088
2141
  }
2089
2142
 
2090
2143
  /**
@@ -2112,29 +2165,48 @@ class AuroFloatingUI {
2112
2165
  * @private
2113
2166
  * Determines the positioning strategy based on the current viewport size and mobile breakpoint.
2114
2167
  *
2115
- * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
2168
+ * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
2116
2169
  * defined in the bib element. If it is, the strategy is set to 'fullscreen'; otherwise, it defaults to 'floating'.
2117
2170
  *
2118
- * @returns {String} The positioning strategy, either 'fullscreen' or 'floating'.
2171
+ * @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
2119
2172
  */
2120
2173
  getPositioningStrategy() {
2121
- let strategy = 'floating';
2122
- if (this.element.bib.mobileFullscreenBreakpoint) {
2123
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${this.element.bib.mobileFullscreenBreakpoint})`).matches;
2124
- if (smallerThanBreakpoint) {
2125
- strategy = 'fullscreen';
2126
- }
2174
+ const breakpoint = this.element.bib.mobileFullscreenBreakpoint || this.element.floaterConfig?.fullscreenBreakpoint;
2175
+ switch (this.behavior) {
2176
+ case "tooltip":
2177
+ return "floating";
2178
+ case "dialog":
2179
+ case "drawer":
2180
+ if (breakpoint) {
2181
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
2182
+
2183
+ this.element.expanded = smallerThanBreakpoint;
2184
+ }
2185
+ if (this.element.nested) {
2186
+ return "cover";
2187
+ }
2188
+ return 'fullscreen';
2189
+ case "dropdown":
2190
+ case undefined:
2191
+ case null:
2192
+ if (breakpoint) {
2193
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
2194
+ if (smallerThanBreakpoint) {
2195
+ return 'fullscreen';
2196
+ }
2197
+ }
2198
+ return "floating";
2199
+ default:
2200
+ return this.behavior;
2127
2201
  }
2128
-
2129
- return strategy;
2130
2202
  }
2131
2203
 
2132
2204
  /**
2133
2205
  * @private
2134
2206
  * Positions the bib element based on the current configuration and positioning strategy.
2135
2207
  *
2136
- * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
2137
- * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
2208
+ * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
2209
+ * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
2138
2210
  * and applies the calculated position to the bib's style.
2139
2211
  */
2140
2212
  position() {
@@ -2145,21 +2217,33 @@ class AuroFloatingUI {
2145
2217
  this.mirrorSize();
2146
2218
  // Define the middlware for the floater configuration
2147
2219
  const middleware = [
2148
- offset(this.element.floaterConfig.offset || 0),
2149
- ...(this.element.floaterConfig.flip ? [flip()] : []), // Add flip middleware if flip is enabled
2150
- ...(this.element.floaterConfig.autoPlacement ? [autoPlacement()] : []), // Add autoPlacement middleware if autoPlacement is enabled
2220
+ offset(this.element.floaterConfig?.offset || 0),
2221
+ ...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
2222
+ ...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
2151
2223
  ];
2152
2224
 
2153
2225
  // Compute the position of the bib
2154
2226
  computePosition(this.element.trigger, this.element.bib, {
2155
- placement: this.element.floaterConfig.placement || 'bottom',
2227
+ placement: this.element.floaterConfig?.placement,
2156
2228
  middleware: middleware || []
2157
- }).then(({x, y}) => { // eslint-disable-line id-length
2229
+ }).then(({ x, y }) => { // eslint-disable-line id-length
2158
2230
  Object.assign(this.element.bib.style, {
2159
2231
  left: `${x}px`,
2160
2232
  top: `${y}px`,
2161
2233
  });
2162
2234
  });
2235
+ } else if (strategy === 'cover') {
2236
+ // Compute the position of the bib
2237
+ computePosition(this.element.parentNode, this.element.bib, {
2238
+ placement: 'bottom-start'
2239
+ }).then(({ x, y }) => { // eslint-disable-line id-length
2240
+ Object.assign(this.element.bib.style, {
2241
+ left: `${x}px`,
2242
+ top: `${y - this.element.parentNode.offsetHeight}px`,
2243
+ width: `${this.element.parentNode.offsetWidth}px`,
2244
+ height: `${this.element.parentNode.offsetHeight}px`
2245
+ });
2246
+ });
2163
2247
  }
2164
2248
  }
2165
2249
 
@@ -2188,34 +2272,48 @@ class AuroFloatingUI {
2188
2272
  *
2189
2273
  * @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
2190
2274
  */
2191
- configureBibStrategy(strategy) {
2192
- const prevStrategy = this.element.isBibFullscreen ? 'fullscreen' : 'floating';
2193
- if (strategy === 'fullscreen') {
2275
+ configureBibStrategy(value) {
2276
+ if (value === 'fullscreen') {
2194
2277
  this.element.isBibFullscreen = true;
2195
2278
  // reset the prev position
2279
+ this.element.bib.setAttribute('isfullscreen', "");
2280
+ this.element.bib.style.position = 'fixed';
2196
2281
  this.element.bib.style.top = "0px";
2197
2282
  this.element.bib.style.left = "0px";
2283
+ this.element.bib.style.width = '';
2284
+ this.element.bib.style.height = '';
2198
2285
 
2199
2286
  // reset the size that was mirroring `size` css-part
2200
2287
  const bibContent = this.element.bib.shadowRoot.querySelector(".container");
2201
- bibContent.style.width = '';
2202
- bibContent.style.height = '';
2203
- bibContent.style.maxWidth = '';
2204
- bibContent.style.maxHeight = `${window.visualViewport.height}px`;
2288
+ if (bibContent) {
2289
+ bibContent.style.width = '';
2290
+ bibContent.style.height = '';
2291
+ bibContent.style.maxWidth = '';
2292
+ bibContent.style.maxHeight = `${window.visualViewport.height}px`;
2293
+ this.configureTrial = 0;
2294
+ } else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
2295
+ this.configureTrial += 1;
2296
+
2297
+ setTimeout(() => {
2298
+ this.configureBibStrategy(value);
2299
+ }, 0);
2300
+ }
2205
2301
 
2206
2302
  if (this.element.isPopoverVisible) {
2207
2303
  this.lockScroll(true);
2208
2304
  }
2209
2305
  } else {
2306
+ this.element.bib.style.position = '';
2307
+ this.element.bib.removeAttribute('isfullscreen');
2210
2308
  this.element.isBibFullscreen = false;
2211
-
2212
- this.lockScroll(false);
2213
2309
  }
2214
2310
 
2215
- if (prevStrategy !== strategy) {
2311
+ const isChanged = this.strategy && this.strategy !== value;
2312
+ this.strategy = value;
2313
+ if (isChanged) {
2216
2314
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-strategy-change` : 'strategy-change', {
2217
2315
  detail: {
2218
- strategy,
2316
+ value,
2219
2317
  },
2220
2318
  composed: true
2221
2319
  });
@@ -2226,18 +2324,6 @@ class AuroFloatingUI {
2226
2324
 
2227
2325
  updateState() {
2228
2326
  const isVisible = this.element.isPopoverVisible;
2229
-
2230
- // Refactor this to apply attribute to correct focusable element
2231
- // Reference Issue: https://github.com/AlaskaAirlines/auro-library/issues/105
2232
- //
2233
- // this.element.trigger.setAttribute('aria-expanded', isVisible);
2234
-
2235
- if (isVisible) {
2236
- this.element.bib.setAttribute('data-show', true);
2237
- } else {
2238
- this.element.bib.removeAttribute('data-show');
2239
- }
2240
-
2241
2327
  if (!isVisible) {
2242
2328
  this.cleanupHideHandlers();
2243
2329
  try {
@@ -2248,16 +2334,32 @@ class AuroFloatingUI {
2248
2334
  }
2249
2335
  }
2250
2336
 
2337
+ /**
2338
+ * @private
2339
+ * getting called on 'blur' in trigger or `focusin` in document
2340
+ *
2341
+ * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
2342
+ * This method checks if the currently active element is still within the trigger or bib.
2343
+ * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
2344
+ */
2251
2345
  handleFocusLoss() {
2252
- if (this.element.noHideOnThisFocusLoss ||
2253
- this.element.hasAttribute('noHideOnThisFocusLoss')) {
2346
+ // if mouse is being pressed, skip and let click event to handle the action
2347
+ if (AuroFloatingUI.isMousePressed) {
2254
2348
  return;
2255
2349
  }
2256
2350
 
2257
- const {activeElement} = document;
2258
- if (activeElement === document.querySelector('body') ||
2259
- this.element.contains(activeElement) ||
2260
- this.element.bibContent?.contains(activeElement)) {
2351
+ if (this.element.noHideOnThisFocusLoss ||
2352
+ this.element.hasAttribute('noHideOnThisFocusLoss')) {
2353
+ return;
2354
+ }
2355
+
2356
+ const { activeElement } = document;
2357
+ // if focus is still inside of trigger or bib, do not close
2358
+ if (this.element.contains(activeElement) || this.element.bib?.contains(activeElement)) {
2359
+ return;
2360
+ }
2361
+ // if fullscreen bib is still open and the focus is missing, do not close
2362
+ if (this.element.bib.hasAttribute('isfullscreen') && activeElement === document.body) {
2261
2363
  return;
2262
2364
  }
2263
2365
 
@@ -2265,31 +2367,66 @@ class AuroFloatingUI {
2265
2367
  }
2266
2368
 
2267
2369
  setupHideHandlers() {
2370
+ this.preventFocusLoseOnBibClick = (event) => {
2371
+ event.preventDefault();
2372
+ event.stopPropagation();
2373
+ };
2374
+ this.element.bib.addEventListener('mousedown', this.preventFocusLoseOnBibClick);
2375
+
2268
2376
  // Define handlers & store references
2269
2377
  this.focusHandler = () => this.handleFocusLoss();
2270
2378
 
2271
2379
  this.clickHandler = (evt) => {
2272
- if (!evt.composedPath().includes(this.element.trigger) &&
2273
- !evt.composedPath().includes(this.element.bibContent)) {
2274
- this.hideBib();
2380
+ if ((!evt.composedPath().includes(this.element.trigger) &&
2381
+ !evt.composedPath().includes(this.element.bib)) ||
2382
+ (this.element.bib.backdrop && evt.composedPath().includes(this.element.bib.backdrop))) {
2383
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2384
+
2385
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI.element.isPopoverVisible) {
2386
+ // if something else is open, close that
2387
+ existedVisibleFloatingUI.hideBib();
2388
+ document.expandedAuroFormkitDropdown = null;
2389
+ document.expandedAuroFloater = this;
2390
+ } else {
2391
+ this.hideBib();
2392
+ }
2275
2393
  }
2276
2394
  };
2277
2395
 
2278
2396
  // ESC key handler
2279
2397
  this.keyDownHandler = (evt) => {
2280
2398
  if (evt.key === 'Escape' && this.element.isPopoverVisible) {
2399
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2400
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this && existedVisibleFloatingUI.element.isPopoverVisible) {
2401
+ // if something else is open, let it handle itself
2402
+ return;
2403
+ }
2281
2404
  this.hideBib();
2282
2405
  }
2283
2406
  };
2284
2407
 
2285
- // Add event listeners using the stored references
2286
- document.addEventListener('focusin', this.focusHandler);
2287
- window.addEventListener('click', this.clickHandler);
2408
+ if (this.behavior !== 'drawer' && this.behavior !== 'dialog') {
2409
+ // Add event listeners using the stored references
2410
+ document.addEventListener('focusin', this.focusHandler);
2411
+ }
2412
+
2288
2413
  document.addEventListener('keydown', this.keyDownHandler);
2414
+
2415
+ // send this task to the end of queue to prevent conflicting
2416
+ // it conflicts if showBib gets call from a button that's not this.element.trigger
2417
+ setTimeout(() => {
2418
+ window.addEventListener('click', this.clickHandler);
2419
+ }, 0);
2289
2420
  }
2290
2421
 
2291
2422
  cleanupHideHandlers() {
2292
2423
  // Remove event listeners if they exist
2424
+
2425
+ if (this.preventFocusLoseOnBibClick) {
2426
+ this.element.bib.removeEventListener('mousedown', this.preventFocusLoseOnBibClick);
2427
+ delete this.preventFocusLoseOnBibClick;
2428
+ }
2429
+
2293
2430
  if (this.focusHandler) {
2294
2431
  document.removeEventListener('focusin', this.focusHandler);
2295
2432
  this.focusHandler = null;
@@ -2314,40 +2451,54 @@ class AuroFloatingUI {
2314
2451
 
2315
2452
  updateCurrentExpandedDropdown() {
2316
2453
  // Close any other dropdown that is already open
2317
- if (document.expandedAuroFormkitDropdown) {
2318
- document.expandedAuroFormkitDropdown.hide;
2454
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2455
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
2456
+ existedVisibleFloatingUI.isPopoverVisible &&
2457
+ document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
2458
+ document.expandedAuroFloater.hideBib();
2319
2459
  }
2320
2460
 
2321
- document.expandedAuroFormkitDropdown = this;
2461
+ document.expandedAuroFloater = this;
2322
2462
  }
2323
2463
 
2324
2464
  showBib() {
2325
- if (!this.element.disabled && !this.element.isPopoverVisible) {
2465
+ if (!this.element.disabled && !this.showing) {
2326
2466
  this.updateCurrentExpandedDropdown();
2327
- this.element.isPopoverVisible = true;
2328
2467
  this.element.triggerChevron?.setAttribute('data-expanded', true);
2329
-
2330
- this.dispatchEventDropdownToggle();
2331
- this.position();
2332
-
2333
- // Clean up any existing handlers before setting up new ones
2334
- this.cleanupHideHandlers();
2335
- this.setupHideHandlers();
2468
+
2469
+ // prevent double showing: isPopovervisible gets first and showBib gets called later
2470
+ if (!this.showing) {
2471
+ if (!this.element.modal) {
2472
+ this.setupHideHandlers();
2473
+ }
2474
+ this.showing = true;
2475
+ this.element.isPopoverVisible = true;
2476
+ this.position();
2477
+ this.dispatchEventDropdownToggle();
2478
+ }
2336
2479
 
2337
2480
  // Setup auto update to handle resize and scroll
2338
- this.element.cleanup = autoUpdate(this.element.trigger, this.element.bib, () => {
2481
+ this.element.cleanup = autoUpdate(this.element.trigger || this.element.parentNode, this.element.bib, () => {
2339
2482
  this.position();
2340
2483
  });
2341
2484
  }
2342
2485
  }
2343
2486
 
2344
2487
  hideBib() {
2345
- if (this.element.isPopoverVisible && !this.element.disabled && !this.element.noToggle) {
2346
- this.element.isPopoverVisible = false;
2488
+ if (!this.element.disabled && !this.element.noToggle) {
2347
2489
  this.lockScroll(false);
2348
2490
  this.element.triggerChevron?.removeAttribute('data-expanded');
2349
- this.dispatchEventDropdownToggle();
2491
+
2492
+ if (this.element.isPopoverVisible) {
2493
+ this.element.isPopoverVisible = false;
2494
+ }
2495
+ if (this.showing) {
2496
+ this.cleanupHideHandlers();
2497
+ this.showing = false;
2498
+ this.dispatchEventDropdownToggle();
2499
+ }
2350
2500
  }
2501
+ document.expandedAuroFloater = null;
2351
2502
  }
2352
2503
 
2353
2504
  /**
@@ -2357,7 +2508,7 @@ class AuroFloatingUI {
2357
2508
  dispatchEventDropdownToggle() {
2358
2509
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-toggled` : 'toggled', {
2359
2510
  detail: {
2360
- expanded: this.element.isPopoverVisible,
2511
+ expanded: this.showing,
2361
2512
  },
2362
2513
  composed: true
2363
2514
  });
@@ -2405,15 +2556,18 @@ class AuroFloatingUI {
2405
2556
  break;
2406
2557
  case 'focus':
2407
2558
  if (this.element.focusShow) {
2559
+
2408
2560
  /*
2409
- This needs to better handle clicking that gives focus -
2410
- currently it shows and then immediately hides the bib
2561
+ This needs to better handle clicking that gives focus -
2562
+ currently it shows and then immediately hides the bib
2411
2563
  */
2412
2564
  this.showBib();
2413
2565
  }
2414
2566
  break;
2415
2567
  case 'blur':
2416
- this.handleFocusLoss();
2568
+ // send this task 100ms later queue to
2569
+ // wait a frame in case focus moves within the floating element/bib
2570
+ setTimeout(() => this.handleFocusLoss(), 0);
2417
2571
  break;
2418
2572
  case 'click':
2419
2573
  if (document.activeElement === document.body) {
@@ -2421,7 +2575,7 @@ class AuroFloatingUI {
2421
2575
  }
2422
2576
  this.handleClick();
2423
2577
  break;
2424
- // Do nothing
2578
+ // Do nothing
2425
2579
  }
2426
2580
  }
2427
2581
  }
@@ -2465,39 +2619,79 @@ class AuroFloatingUI {
2465
2619
  });
2466
2620
  }
2467
2621
 
2622
+ /**
2623
+ *
2624
+ * @param {*} eventPrefix
2625
+ */
2626
+ regenerateBibId() {
2627
+ this.id = this.element.getAttribute('id');
2628
+ if (!this.id) {
2629
+ this.id = window.crypto.randomUUID();
2630
+ this.element.setAttribute('id', this.id);
2631
+ }
2632
+
2633
+ this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
2634
+ }
2635
+
2468
2636
  configure(elem, eventPrefix) {
2637
+ AuroFloatingUI.setupMousePressChecker();
2638
+
2469
2639
  this.eventPrefix = eventPrefix;
2470
- this.element = elem;
2471
- this.element.trigger = this.element.shadowRoot.querySelector('#trigger');
2472
- this.element.bib = this.element.shadowRoot.querySelector('#bib');
2640
+ if (this.element !== elem) {
2641
+ this.element = elem;
2642
+ }
2643
+
2644
+ if (this.behavior !== this.element.behavior) {
2645
+ this.behavior = this.element.behavior;
2646
+ }
2647
+
2648
+ if (this.element.trigger) {
2649
+ this.disconnect();
2650
+ }
2651
+ this.element.trigger = this.element.triggerElement || this.element.shadowRoot.querySelector('#trigger') || this.element.trigger;
2652
+ this.element.bib = this.element.shadowRoot.querySelector('#bib') || this.element.bib;
2473
2653
  this.element.bibSizer = this.element.shadowRoot.querySelector('#bibSizer');
2474
2654
  this.element.triggerChevron = this.element.shadowRoot.querySelector('#showStateIcon');
2475
2655
 
2656
+
2657
+ if (this.element.floaterConfig) {
2658
+ this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
2659
+ }
2660
+
2476
2661
  document.body.append(this.element.bib);
2477
2662
 
2663
+ this.regenerateBibId();
2478
2664
  this.handleTriggerTabIndex();
2479
2665
 
2480
2666
  this.handleEvent = this.handleEvent.bind(this);
2481
- this.element.trigger.addEventListener('keydown', this.handleEvent);
2482
- this.element.trigger.addEventListener('click', this.handleEvent);
2483
- this.element.trigger.addEventListener('mouseenter', this.handleEvent);
2484
- this.element.trigger.addEventListener('mouseleave', this.handleEvent);
2485
- this.element.trigger.addEventListener('focus', this.handleEvent);
2486
- this.element.trigger.addEventListener('blur', this.handleEvent);
2667
+ if (this.element.trigger) {
2668
+ this.element.trigger.addEventListener('keydown', this.handleEvent);
2669
+ this.element.trigger.addEventListener('click', this.handleEvent);
2670
+ this.element.trigger.addEventListener('mouseenter', this.handleEvent);
2671
+ this.element.trigger.addEventListener('mouseleave', this.handleEvent);
2672
+ this.element.trigger.addEventListener('focus', this.handleEvent);
2673
+ this.element.trigger.addEventListener('blur', this.handleEvent);
2674
+ }
2487
2675
  }
2488
2676
 
2489
2677
  disconnect() {
2490
2678
  this.cleanupHideHandlers();
2491
- this.element.cleanup?.();
2492
-
2493
- // Remove event & keyboard listeners
2494
- if (this.element?.trigger) {
2495
- this.element.trigger.removeEventListener('keydown', this.handleEvent);
2496
- this.element.trigger.removeEventListener('click', this.handleEvent);
2497
- this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2498
- this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2499
- this.element.trigger.removeEventListener('focus', this.handleEvent);
2500
- this.element.trigger.removeEventListener('blur', this.handleEvent);
2679
+ if (this.element) {
2680
+ this.element.cleanup?.();
2681
+
2682
+ if (this.element.bib) {
2683
+ this.element.shadowRoot.append(this.element.bib);
2684
+ }
2685
+
2686
+ // Remove event & keyboard listeners
2687
+ if (this.element?.trigger) {
2688
+ this.element.trigger.removeEventListener('keydown', this.handleEvent);
2689
+ this.element.trigger.removeEventListener('click', this.handleEvent);
2690
+ this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2691
+ this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2692
+ this.element.trigger.removeEventListener('focus', this.handleEvent);
2693
+ this.element.trigger.removeEventListener('blur', this.handleEvent);
2694
+ }
2501
2695
  }
2502
2696
  }
2503
2697
  }
@@ -3460,6 +3654,11 @@ class AuroDropdown extends r$1 {
3460
3654
  * @private
3461
3655
  */
3462
3656
  this.helpTextTag = versioning.generateTag('auro-formkit-dropdown-helptext', helpTextVersion$1, AuroHelpText$1);
3657
+
3658
+ /**
3659
+ * @private
3660
+ */
3661
+ this.bindFocusEventToTrigger = this.bindFocusEventToTrigger.bind(this);
3463
3662
  }
3464
3663
 
3465
3664
  /**
@@ -3728,6 +3927,7 @@ class AuroDropdown extends r$1 {
3728
3927
  disconnectedCallback() {
3729
3928
  super.disconnectedCallback();
3730
3929
  this.floater.disconnect();
3930
+ this.clearTriggerFocusEventBinding();
3731
3931
  }
3732
3932
 
3733
3933
  updated(changedProperties) {
@@ -3842,6 +4042,62 @@ class AuroDropdown extends r$1 {
3842
4042
  return result;
3843
4043
  }
3844
4044
 
4045
+ /**
4046
+ * @private
4047
+ * Creates and dispatches a duplicate focus event on the trigger element.
4048
+ * @param {Event} event - The original focus event.
4049
+ */
4050
+ bindFocusEventToTrigger(event) {
4051
+ const dupEvent = new FocusEvent(event.type, {
4052
+ bubbles: false,
4053
+ cancelable: false,
4054
+ composed: true,
4055
+ });
4056
+ this.trigger.dispatchEvent(dupEvent);
4057
+ }
4058
+
4059
+ /**
4060
+ * @private
4061
+ * Sets up event listeners to deliver focus and blur events from nested Auro components within the trigger slot to trigger.
4062
+ * This ensures that focus/blur events originating from within these components are propagated to the trigger element itself.
4063
+ */
4064
+ setupTriggerFocusEventBinding() {
4065
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
4066
+ return;
4067
+ }
4068
+
4069
+ this.triggerContentSlot.forEach((node) => {
4070
+ if (node.querySelectorAll) {
4071
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
4072
+ auroElements.forEach((auroEl) => {
4073
+ auroEl.addEventListener('focus', this.bindFocusEventToTrigger);
4074
+ auroEl.addEventListener('blur', this.bindFocusEventToTrigger);
4075
+ });
4076
+ }
4077
+ });
4078
+ }
4079
+
4080
+ /**
4081
+ * Clears focus and blur event listeners from nested Auro components within the trigger slot.
4082
+ * @private
4083
+ * @returns {void}
4084
+ */
4085
+ clearTriggerFocusEventBinding() {
4086
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
4087
+ return;
4088
+ }
4089
+
4090
+ this.triggerContentSlot.forEach((node) => {
4091
+ if (node.querySelectorAll) {
4092
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
4093
+ auroElements.forEach((auroEl) => {
4094
+ auroEl.removeEventListener('focus', this.bindFocusEventToTrigger);
4095
+ auroEl.removeEventListener('blur', this.bindFocusEventToTrigger);
4096
+ });
4097
+ }
4098
+ });
4099
+ }
4100
+
3845
4101
  /**
3846
4102
  * Handles changes to the trigger content slot and updates related properties.
3847
4103
  *
@@ -3889,6 +4145,7 @@ class AuroDropdown extends r$1 {
3889
4145
  }
3890
4146
 
3891
4147
  if (this.triggerContentSlot) {
4148
+ this.setupTriggerFocusEventBinding();
3892
4149
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
3893
4150
  if (slot.textContent.trim()) {
3894
4151
  return true;
@@ -3994,6 +4251,7 @@ class AuroDropdown extends r$1 {
3994
4251
  <${this.dropdownBibTag}
3995
4252
  id="bib"
3996
4253
  role="tooltip"
4254
+ ?data-show="${this.isPopoverVisible}"
3997
4255
  ?isfullscreen="${this.isBibFullscreen}"
3998
4256
  ?common="${this.common}"
3999
4257
  ?rounded="${this.common || this.rounded}"
@@ -111,7 +111,7 @@ The use of any Auro custom element has a dependency on the [Auro Design Tokens](
111
111
  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.
112
112
 
113
113
  ```html
114
- <script type="module" src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-formkit@2.2.1-beta.1/auro-combobox/+esm"></script>
114
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-formkit@2.2.1-beta.3/auro-combobox/+esm"></script>
115
115
  ```
116
116
  <!-- AURO-GENERATED-CONTENT:END -->
117
117