@aurodesignsystem/auro-formkit 2.2.1-beta.2 → 2.2.1-beta.3

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 +16 -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
@@ -2051,17 +2051,70 @@ const computePosition = (reference, floating, options) => {
2051
2051
  /* eslint-disable line-comment-position, no-inline-comments */
2052
2052
 
2053
2053
 
2054
+
2055
+ const MAX_CONFIGURATION_COUNT = 10;
2056
+
2054
2057
  class AuroFloatingUI {
2055
- constructor() {
2058
+
2059
+ /**
2060
+ * @private
2061
+ */
2062
+ static isMousePressed = false;
2063
+
2064
+ /**
2065
+ * @private
2066
+ */
2067
+ static isMousePressHandlerInitialized = false;
2068
+
2069
+ /**
2070
+ * @private
2071
+ */
2072
+ static setupMousePressChecker() {
2073
+ if (!AuroFloatingUI.isMousePressHandlerInitialized && window && window.addEventListener) {
2074
+ AuroFloatingUI.isMousePressHandlerInitialized = true;
2075
+
2076
+ const mouseEventGlobalHandler = (event) => {
2077
+ AuroFloatingUI.isMousePressed = event.type === 'mousedown';
2078
+ };
2079
+
2080
+ window.addEventListener('mousedown', mouseEventGlobalHandler);
2081
+ window.addEventListener('mouseup', mouseEventGlobalHandler);
2082
+ }
2083
+ }
2084
+
2085
+ constructor(element, behavior) {
2086
+ this.element = element;
2087
+ this.behavior = behavior;
2088
+
2056
2089
  // Store event listener references for cleanup
2057
2090
  this.focusHandler = null;
2058
2091
  this.clickHandler = null;
2059
2092
  this.keyDownHandler = null;
2060
-
2093
+
2094
+ /**
2095
+ * @private
2096
+ */
2097
+ this.configureTrial = 0;
2098
+
2061
2099
  /**
2062
2100
  * @private
2063
2101
  */
2064
2102
  this.eventPrefix = undefined;
2103
+
2104
+ /**
2105
+ * @private
2106
+ */
2107
+ this.id = undefined;
2108
+
2109
+ /**
2110
+ * @private
2111
+ */
2112
+ this.showing = false;
2113
+
2114
+ /**
2115
+ * @private
2116
+ */
2117
+ this.strategy = undefined;
2065
2118
  }
2066
2119
 
2067
2120
  /**
@@ -2089,29 +2142,48 @@ class AuroFloatingUI {
2089
2142
  * @private
2090
2143
  * Determines the positioning strategy based on the current viewport size and mobile breakpoint.
2091
2144
  *
2092
- * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
2145
+ * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
2093
2146
  * defined in the bib element. If it is, the strategy is set to 'fullscreen'; otherwise, it defaults to 'floating'.
2094
2147
  *
2095
- * @returns {String} The positioning strategy, either 'fullscreen' or 'floating'.
2148
+ * @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
2096
2149
  */
2097
2150
  getPositioningStrategy() {
2098
- let strategy = 'floating';
2099
- if (this.element.bib.mobileFullscreenBreakpoint) {
2100
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${this.element.bib.mobileFullscreenBreakpoint})`).matches;
2101
- if (smallerThanBreakpoint) {
2102
- strategy = 'fullscreen';
2103
- }
2151
+ const breakpoint = this.element.bib.mobileFullscreenBreakpoint || this.element.floaterConfig?.fullscreenBreakpoint;
2152
+ switch (this.behavior) {
2153
+ case "tooltip":
2154
+ return "floating";
2155
+ case "dialog":
2156
+ case "drawer":
2157
+ if (breakpoint) {
2158
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
2159
+
2160
+ this.element.expanded = smallerThanBreakpoint;
2161
+ }
2162
+ if (this.element.nested) {
2163
+ return "cover";
2164
+ }
2165
+ return 'fullscreen';
2166
+ case "dropdown":
2167
+ case undefined:
2168
+ case null:
2169
+ if (breakpoint) {
2170
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
2171
+ if (smallerThanBreakpoint) {
2172
+ return 'fullscreen';
2173
+ }
2174
+ }
2175
+ return "floating";
2176
+ default:
2177
+ return this.behavior;
2104
2178
  }
2105
-
2106
- return strategy;
2107
2179
  }
2108
2180
 
2109
2181
  /**
2110
2182
  * @private
2111
2183
  * Positions the bib element based on the current configuration and positioning strategy.
2112
2184
  *
2113
- * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
2114
- * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
2185
+ * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
2186
+ * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
2115
2187
  * and applies the calculated position to the bib's style.
2116
2188
  */
2117
2189
  position() {
@@ -2122,21 +2194,33 @@ class AuroFloatingUI {
2122
2194
  this.mirrorSize();
2123
2195
  // Define the middlware for the floater configuration
2124
2196
  const middleware = [
2125
- offset(this.element.floaterConfig.offset || 0),
2126
- ...(this.element.floaterConfig.flip ? [flip()] : []), // Add flip middleware if flip is enabled
2127
- ...(this.element.floaterConfig.autoPlacement ? [autoPlacement()] : []), // Add autoPlacement middleware if autoPlacement is enabled
2197
+ offset(this.element.floaterConfig?.offset || 0),
2198
+ ...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
2199
+ ...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
2128
2200
  ];
2129
2201
 
2130
2202
  // Compute the position of the bib
2131
2203
  computePosition(this.element.trigger, this.element.bib, {
2132
- placement: this.element.floaterConfig.placement || 'bottom',
2204
+ placement: this.element.floaterConfig?.placement,
2133
2205
  middleware: middleware || []
2134
- }).then(({x, y}) => { // eslint-disable-line id-length
2206
+ }).then(({ x, y }) => { // eslint-disable-line id-length
2135
2207
  Object.assign(this.element.bib.style, {
2136
2208
  left: `${x}px`,
2137
2209
  top: `${y}px`,
2138
2210
  });
2139
2211
  });
2212
+ } else if (strategy === 'cover') {
2213
+ // Compute the position of the bib
2214
+ computePosition(this.element.parentNode, this.element.bib, {
2215
+ placement: 'bottom-start'
2216
+ }).then(({ x, y }) => { // eslint-disable-line id-length
2217
+ Object.assign(this.element.bib.style, {
2218
+ left: `${x}px`,
2219
+ top: `${y - this.element.parentNode.offsetHeight}px`,
2220
+ width: `${this.element.parentNode.offsetWidth}px`,
2221
+ height: `${this.element.parentNode.offsetHeight}px`
2222
+ });
2223
+ });
2140
2224
  }
2141
2225
  }
2142
2226
 
@@ -2165,34 +2249,48 @@ class AuroFloatingUI {
2165
2249
  *
2166
2250
  * @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
2167
2251
  */
2168
- configureBibStrategy(strategy) {
2169
- const prevStrategy = this.element.isBibFullscreen ? 'fullscreen' : 'floating';
2170
- if (strategy === 'fullscreen') {
2252
+ configureBibStrategy(value) {
2253
+ if (value === 'fullscreen') {
2171
2254
  this.element.isBibFullscreen = true;
2172
2255
  // reset the prev position
2256
+ this.element.bib.setAttribute('isfullscreen', "");
2257
+ this.element.bib.style.position = 'fixed';
2173
2258
  this.element.bib.style.top = "0px";
2174
2259
  this.element.bib.style.left = "0px";
2260
+ this.element.bib.style.width = '';
2261
+ this.element.bib.style.height = '';
2175
2262
 
2176
2263
  // reset the size that was mirroring `size` css-part
2177
2264
  const bibContent = this.element.bib.shadowRoot.querySelector(".container");
2178
- bibContent.style.width = '';
2179
- bibContent.style.height = '';
2180
- bibContent.style.maxWidth = '';
2181
- bibContent.style.maxHeight = `${window.visualViewport.height}px`;
2265
+ if (bibContent) {
2266
+ bibContent.style.width = '';
2267
+ bibContent.style.height = '';
2268
+ bibContent.style.maxWidth = '';
2269
+ bibContent.style.maxHeight = `${window.visualViewport.height}px`;
2270
+ this.configureTrial = 0;
2271
+ } else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
2272
+ this.configureTrial += 1;
2273
+
2274
+ setTimeout(() => {
2275
+ this.configureBibStrategy(value);
2276
+ }, 0);
2277
+ }
2182
2278
 
2183
2279
  if (this.element.isPopoverVisible) {
2184
2280
  this.lockScroll(true);
2185
2281
  }
2186
2282
  } else {
2283
+ this.element.bib.style.position = '';
2284
+ this.element.bib.removeAttribute('isfullscreen');
2187
2285
  this.element.isBibFullscreen = false;
2188
-
2189
- this.lockScroll(false);
2190
2286
  }
2191
2287
 
2192
- if (prevStrategy !== strategy) {
2288
+ const isChanged = this.strategy && this.strategy !== value;
2289
+ this.strategy = value;
2290
+ if (isChanged) {
2193
2291
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-strategy-change` : 'strategy-change', {
2194
2292
  detail: {
2195
- strategy,
2293
+ value,
2196
2294
  },
2197
2295
  composed: true
2198
2296
  });
@@ -2203,18 +2301,6 @@ class AuroFloatingUI {
2203
2301
 
2204
2302
  updateState() {
2205
2303
  const isVisible = this.element.isPopoverVisible;
2206
-
2207
- // Refactor this to apply attribute to correct focusable element
2208
- // Reference Issue: https://github.com/AlaskaAirlines/auro-library/issues/105
2209
- //
2210
- // this.element.trigger.setAttribute('aria-expanded', isVisible);
2211
-
2212
- if (isVisible) {
2213
- this.element.bib.setAttribute('data-show', true);
2214
- } else {
2215
- this.element.bib.removeAttribute('data-show');
2216
- }
2217
-
2218
2304
  if (!isVisible) {
2219
2305
  this.cleanupHideHandlers();
2220
2306
  try {
@@ -2225,16 +2311,32 @@ class AuroFloatingUI {
2225
2311
  }
2226
2312
  }
2227
2313
 
2314
+ /**
2315
+ * @private
2316
+ * getting called on 'blur' in trigger or `focusin` in document
2317
+ *
2318
+ * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
2319
+ * This method checks if the currently active element is still within the trigger or bib.
2320
+ * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
2321
+ */
2228
2322
  handleFocusLoss() {
2229
- if (this.element.noHideOnThisFocusLoss ||
2230
- this.element.hasAttribute('noHideOnThisFocusLoss')) {
2323
+ // if mouse is being pressed, skip and let click event to handle the action
2324
+ if (AuroFloatingUI.isMousePressed) {
2325
+ return;
2326
+ }
2327
+
2328
+ if (this.element.noHideOnThisFocusLoss ||
2329
+ this.element.hasAttribute('noHideOnThisFocusLoss')) {
2231
2330
  return;
2232
2331
  }
2233
2332
 
2234
- const {activeElement} = document;
2235
- if (activeElement === document.querySelector('body') ||
2236
- this.element.contains(activeElement) ||
2237
- this.element.bibContent?.contains(activeElement)) {
2333
+ const { activeElement } = document;
2334
+ // if focus is still inside of trigger or bib, do not close
2335
+ if (this.element.contains(activeElement) || this.element.bib?.contains(activeElement)) {
2336
+ return;
2337
+ }
2338
+ // if fullscreen bib is still open and the focus is missing, do not close
2339
+ if (this.element.bib.hasAttribute('isfullscreen') && activeElement === document.body) {
2238
2340
  return;
2239
2341
  }
2240
2342
 
@@ -2242,31 +2344,66 @@ class AuroFloatingUI {
2242
2344
  }
2243
2345
 
2244
2346
  setupHideHandlers() {
2347
+ this.preventFocusLoseOnBibClick = (event) => {
2348
+ event.preventDefault();
2349
+ event.stopPropagation();
2350
+ };
2351
+ this.element.bib.addEventListener('mousedown', this.preventFocusLoseOnBibClick);
2352
+
2245
2353
  // Define handlers & store references
2246
2354
  this.focusHandler = () => this.handleFocusLoss();
2247
2355
 
2248
2356
  this.clickHandler = (evt) => {
2249
- if (!evt.composedPath().includes(this.element.trigger) &&
2250
- !evt.composedPath().includes(this.element.bibContent)) {
2251
- this.hideBib();
2357
+ if ((!evt.composedPath().includes(this.element.trigger) &&
2358
+ !evt.composedPath().includes(this.element.bib)) ||
2359
+ (this.element.bib.backdrop && evt.composedPath().includes(this.element.bib.backdrop))) {
2360
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2361
+
2362
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI.element.isPopoverVisible) {
2363
+ // if something else is open, close that
2364
+ existedVisibleFloatingUI.hideBib();
2365
+ document.expandedAuroFormkitDropdown = null;
2366
+ document.expandedAuroFloater = this;
2367
+ } else {
2368
+ this.hideBib();
2369
+ }
2252
2370
  }
2253
2371
  };
2254
2372
 
2255
2373
  // ESC key handler
2256
2374
  this.keyDownHandler = (evt) => {
2257
2375
  if (evt.key === 'Escape' && this.element.isPopoverVisible) {
2376
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2377
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this && existedVisibleFloatingUI.element.isPopoverVisible) {
2378
+ // if something else is open, let it handle itself
2379
+ return;
2380
+ }
2258
2381
  this.hideBib();
2259
2382
  }
2260
2383
  };
2261
2384
 
2262
- // Add event listeners using the stored references
2263
- document.addEventListener('focusin', this.focusHandler);
2264
- window.addEventListener('click', this.clickHandler);
2385
+ if (this.behavior !== 'drawer' && this.behavior !== 'dialog') {
2386
+ // Add event listeners using the stored references
2387
+ document.addEventListener('focusin', this.focusHandler);
2388
+ }
2389
+
2265
2390
  document.addEventListener('keydown', this.keyDownHandler);
2391
+
2392
+ // send this task to the end of queue to prevent conflicting
2393
+ // it conflicts if showBib gets call from a button that's not this.element.trigger
2394
+ setTimeout(() => {
2395
+ window.addEventListener('click', this.clickHandler);
2396
+ }, 0);
2266
2397
  }
2267
2398
 
2268
2399
  cleanupHideHandlers() {
2269
2400
  // Remove event listeners if they exist
2401
+
2402
+ if (this.preventFocusLoseOnBibClick) {
2403
+ this.element.bib.removeEventListener('mousedown', this.preventFocusLoseOnBibClick);
2404
+ delete this.preventFocusLoseOnBibClick;
2405
+ }
2406
+
2270
2407
  if (this.focusHandler) {
2271
2408
  document.removeEventListener('focusin', this.focusHandler);
2272
2409
  this.focusHandler = null;
@@ -2291,40 +2428,54 @@ class AuroFloatingUI {
2291
2428
 
2292
2429
  updateCurrentExpandedDropdown() {
2293
2430
  // Close any other dropdown that is already open
2294
- if (document.expandedAuroFormkitDropdown) {
2295
- document.expandedAuroFormkitDropdown.hide;
2431
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2432
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
2433
+ existedVisibleFloatingUI.isPopoverVisible &&
2434
+ document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
2435
+ document.expandedAuroFloater.hideBib();
2296
2436
  }
2297
2437
 
2298
- document.expandedAuroFormkitDropdown = this;
2438
+ document.expandedAuroFloater = this;
2299
2439
  }
2300
2440
 
2301
2441
  showBib() {
2302
- if (!this.element.disabled && !this.element.isPopoverVisible) {
2442
+ if (!this.element.disabled && !this.showing) {
2303
2443
  this.updateCurrentExpandedDropdown();
2304
- this.element.isPopoverVisible = true;
2305
2444
  this.element.triggerChevron?.setAttribute('data-expanded', true);
2306
-
2307
- this.dispatchEventDropdownToggle();
2308
- this.position();
2309
-
2310
- // Clean up any existing handlers before setting up new ones
2311
- this.cleanupHideHandlers();
2312
- this.setupHideHandlers();
2445
+
2446
+ // prevent double showing: isPopovervisible gets first and showBib gets called later
2447
+ if (!this.showing) {
2448
+ if (!this.element.modal) {
2449
+ this.setupHideHandlers();
2450
+ }
2451
+ this.showing = true;
2452
+ this.element.isPopoverVisible = true;
2453
+ this.position();
2454
+ this.dispatchEventDropdownToggle();
2455
+ }
2313
2456
 
2314
2457
  // Setup auto update to handle resize and scroll
2315
- this.element.cleanup = autoUpdate(this.element.trigger, this.element.bib, () => {
2458
+ this.element.cleanup = autoUpdate(this.element.trigger || this.element.parentNode, this.element.bib, () => {
2316
2459
  this.position();
2317
2460
  });
2318
2461
  }
2319
2462
  }
2320
2463
 
2321
2464
  hideBib() {
2322
- if (this.element.isPopoverVisible && !this.element.disabled && !this.element.noToggle) {
2323
- this.element.isPopoverVisible = false;
2465
+ if (!this.element.disabled && !this.element.noToggle) {
2324
2466
  this.lockScroll(false);
2325
2467
  this.element.triggerChevron?.removeAttribute('data-expanded');
2326
- this.dispatchEventDropdownToggle();
2468
+
2469
+ if (this.element.isPopoverVisible) {
2470
+ this.element.isPopoverVisible = false;
2471
+ }
2472
+ if (this.showing) {
2473
+ this.cleanupHideHandlers();
2474
+ this.showing = false;
2475
+ this.dispatchEventDropdownToggle();
2476
+ }
2327
2477
  }
2478
+ document.expandedAuroFloater = null;
2328
2479
  }
2329
2480
 
2330
2481
  /**
@@ -2334,7 +2485,7 @@ class AuroFloatingUI {
2334
2485
  dispatchEventDropdownToggle() {
2335
2486
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-toggled` : 'toggled', {
2336
2487
  detail: {
2337
- expanded: this.element.isPopoverVisible,
2488
+ expanded: this.showing,
2338
2489
  },
2339
2490
  composed: true
2340
2491
  });
@@ -2382,15 +2533,18 @@ class AuroFloatingUI {
2382
2533
  break;
2383
2534
  case 'focus':
2384
2535
  if (this.element.focusShow) {
2536
+
2385
2537
  /*
2386
- This needs to better handle clicking that gives focus -
2387
- currently it shows and then immediately hides the bib
2538
+ This needs to better handle clicking that gives focus -
2539
+ currently it shows and then immediately hides the bib
2388
2540
  */
2389
2541
  this.showBib();
2390
2542
  }
2391
2543
  break;
2392
2544
  case 'blur':
2393
- this.handleFocusLoss();
2545
+ // send this task 100ms later queue to
2546
+ // wait a frame in case focus moves within the floating element/bib
2547
+ setTimeout(() => this.handleFocusLoss(), 0);
2394
2548
  break;
2395
2549
  case 'click':
2396
2550
  if (document.activeElement === document.body) {
@@ -2398,7 +2552,7 @@ class AuroFloatingUI {
2398
2552
  }
2399
2553
  this.handleClick();
2400
2554
  break;
2401
- // Do nothing
2555
+ // Do nothing
2402
2556
  }
2403
2557
  }
2404
2558
  }
@@ -2442,39 +2596,79 @@ class AuroFloatingUI {
2442
2596
  });
2443
2597
  }
2444
2598
 
2599
+ /**
2600
+ *
2601
+ * @param {*} eventPrefix
2602
+ */
2603
+ regenerateBibId() {
2604
+ this.id = this.element.getAttribute('id');
2605
+ if (!this.id) {
2606
+ this.id = window.crypto.randomUUID();
2607
+ this.element.setAttribute('id', this.id);
2608
+ }
2609
+
2610
+ this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
2611
+ }
2612
+
2445
2613
  configure(elem, eventPrefix) {
2614
+ AuroFloatingUI.setupMousePressChecker();
2615
+
2446
2616
  this.eventPrefix = eventPrefix;
2447
- this.element = elem;
2448
- this.element.trigger = this.element.shadowRoot.querySelector('#trigger');
2449
- this.element.bib = this.element.shadowRoot.querySelector('#bib');
2617
+ if (this.element !== elem) {
2618
+ this.element = elem;
2619
+ }
2620
+
2621
+ if (this.behavior !== this.element.behavior) {
2622
+ this.behavior = this.element.behavior;
2623
+ }
2624
+
2625
+ if (this.element.trigger) {
2626
+ this.disconnect();
2627
+ }
2628
+ this.element.trigger = this.element.triggerElement || this.element.shadowRoot.querySelector('#trigger') || this.element.trigger;
2629
+ this.element.bib = this.element.shadowRoot.querySelector('#bib') || this.element.bib;
2450
2630
  this.element.bibSizer = this.element.shadowRoot.querySelector('#bibSizer');
2451
2631
  this.element.triggerChevron = this.element.shadowRoot.querySelector('#showStateIcon');
2452
2632
 
2633
+
2634
+ if (this.element.floaterConfig) {
2635
+ this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
2636
+ }
2637
+
2453
2638
  document.body.append(this.element.bib);
2454
2639
 
2640
+ this.regenerateBibId();
2455
2641
  this.handleTriggerTabIndex();
2456
2642
 
2457
2643
  this.handleEvent = this.handleEvent.bind(this);
2458
- this.element.trigger.addEventListener('keydown', this.handleEvent);
2459
- this.element.trigger.addEventListener('click', this.handleEvent);
2460
- this.element.trigger.addEventListener('mouseenter', this.handleEvent);
2461
- this.element.trigger.addEventListener('mouseleave', this.handleEvent);
2462
- this.element.trigger.addEventListener('focus', this.handleEvent);
2463
- this.element.trigger.addEventListener('blur', this.handleEvent);
2644
+ if (this.element.trigger) {
2645
+ this.element.trigger.addEventListener('keydown', this.handleEvent);
2646
+ this.element.trigger.addEventListener('click', this.handleEvent);
2647
+ this.element.trigger.addEventListener('mouseenter', this.handleEvent);
2648
+ this.element.trigger.addEventListener('mouseleave', this.handleEvent);
2649
+ this.element.trigger.addEventListener('focus', this.handleEvent);
2650
+ this.element.trigger.addEventListener('blur', this.handleEvent);
2651
+ }
2464
2652
  }
2465
2653
 
2466
2654
  disconnect() {
2467
2655
  this.cleanupHideHandlers();
2468
- this.element.cleanup?.();
2469
-
2470
- // Remove event & keyboard listeners
2471
- if (this.element?.trigger) {
2472
- this.element.trigger.removeEventListener('keydown', this.handleEvent);
2473
- this.element.trigger.removeEventListener('click', this.handleEvent);
2474
- this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2475
- this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2476
- this.element.trigger.removeEventListener('focus', this.handleEvent);
2477
- this.element.trigger.removeEventListener('blur', this.handleEvent);
2656
+ if (this.element) {
2657
+ this.element.cleanup?.();
2658
+
2659
+ if (this.element.bib) {
2660
+ this.element.shadowRoot.append(this.element.bib);
2661
+ }
2662
+
2663
+ // Remove event & keyboard listeners
2664
+ if (this.element?.trigger) {
2665
+ this.element.trigger.removeEventListener('keydown', this.handleEvent);
2666
+ this.element.trigger.removeEventListener('click', this.handleEvent);
2667
+ this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2668
+ this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2669
+ this.element.trigger.removeEventListener('focus', this.handleEvent);
2670
+ this.element.trigger.removeEventListener('blur', this.handleEvent);
2671
+ }
2478
2672
  }
2479
2673
  }
2480
2674
  }
@@ -3437,6 +3631,11 @@ class AuroDropdown extends r {
3437
3631
  * @private
3438
3632
  */
3439
3633
  this.helpTextTag = versioning.generateTag('auro-formkit-dropdown-helptext', helpTextVersion, AuroHelpText);
3634
+
3635
+ /**
3636
+ * @private
3637
+ */
3638
+ this.bindFocusEventToTrigger = this.bindFocusEventToTrigger.bind(this);
3440
3639
  }
3441
3640
 
3442
3641
  /**
@@ -3705,6 +3904,7 @@ class AuroDropdown extends r {
3705
3904
  disconnectedCallback() {
3706
3905
  super.disconnectedCallback();
3707
3906
  this.floater.disconnect();
3907
+ this.clearTriggerFocusEventBinding();
3708
3908
  }
3709
3909
 
3710
3910
  updated(changedProperties) {
@@ -3819,6 +4019,62 @@ class AuroDropdown extends r {
3819
4019
  return result;
3820
4020
  }
3821
4021
 
4022
+ /**
4023
+ * @private
4024
+ * Creates and dispatches a duplicate focus event on the trigger element.
4025
+ * @param {Event} event - The original focus event.
4026
+ */
4027
+ bindFocusEventToTrigger(event) {
4028
+ const dupEvent = new FocusEvent(event.type, {
4029
+ bubbles: false,
4030
+ cancelable: false,
4031
+ composed: true,
4032
+ });
4033
+ this.trigger.dispatchEvent(dupEvent);
4034
+ }
4035
+
4036
+ /**
4037
+ * @private
4038
+ * Sets up event listeners to deliver focus and blur events from nested Auro components within the trigger slot to trigger.
4039
+ * This ensures that focus/blur events originating from within these components are propagated to the trigger element itself.
4040
+ */
4041
+ setupTriggerFocusEventBinding() {
4042
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
4043
+ return;
4044
+ }
4045
+
4046
+ this.triggerContentSlot.forEach((node) => {
4047
+ if (node.querySelectorAll) {
4048
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
4049
+ auroElements.forEach((auroEl) => {
4050
+ auroEl.addEventListener('focus', this.bindFocusEventToTrigger);
4051
+ auroEl.addEventListener('blur', this.bindFocusEventToTrigger);
4052
+ });
4053
+ }
4054
+ });
4055
+ }
4056
+
4057
+ /**
4058
+ * Clears focus and blur event listeners from nested Auro components within the trigger slot.
4059
+ * @private
4060
+ * @returns {void}
4061
+ */
4062
+ clearTriggerFocusEventBinding() {
4063
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
4064
+ return;
4065
+ }
4066
+
4067
+ this.triggerContentSlot.forEach((node) => {
4068
+ if (node.querySelectorAll) {
4069
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
4070
+ auroElements.forEach((auroEl) => {
4071
+ auroEl.removeEventListener('focus', this.bindFocusEventToTrigger);
4072
+ auroEl.removeEventListener('blur', this.bindFocusEventToTrigger);
4073
+ });
4074
+ }
4075
+ });
4076
+ }
4077
+
3822
4078
  /**
3823
4079
  * Handles changes to the trigger content slot and updates related properties.
3824
4080
  *
@@ -3866,6 +4122,7 @@ class AuroDropdown extends r {
3866
4122
  }
3867
4123
 
3868
4124
  if (this.triggerContentSlot) {
4125
+ this.setupTriggerFocusEventBinding();
3869
4126
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
3870
4127
  if (slot.textContent.trim()) {
3871
4128
  return true;
@@ -3971,6 +4228,7 @@ class AuroDropdown extends r {
3971
4228
  <${this.dropdownBibTag}
3972
4229
  id="bib"
3973
4230
  role="tooltip"
4231
+ ?data-show="${this.isPopoverVisible}"
3974
4232
  ?isfullscreen="${this.isBibFullscreen}"
3975
4233
  ?common="${this.common}"
3976
4234
  ?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-select/+esm"></script>
114
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-formkit@2.2.1-beta.2/auro-select/+esm"></script>
115
115
  ```
116
116
  <!-- AURO-GENERATED-CONTENT:END -->
117
117