@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
@@ -3531,17 +3531,70 @@ const computePosition = (reference, floating, options) => {
3531
3531
  /* eslint-disable line-comment-position, no-inline-comments */
3532
3532
 
3533
3533
 
3534
+
3535
+ const MAX_CONFIGURATION_COUNT = 10;
3536
+
3534
3537
  class AuroFloatingUI {
3535
- constructor() {
3538
+
3539
+ /**
3540
+ * @private
3541
+ */
3542
+ static isMousePressed = false;
3543
+
3544
+ /**
3545
+ * @private
3546
+ */
3547
+ static isMousePressHandlerInitialized = false;
3548
+
3549
+ /**
3550
+ * @private
3551
+ */
3552
+ static setupMousePressChecker() {
3553
+ if (!AuroFloatingUI.isMousePressHandlerInitialized && window && window.addEventListener) {
3554
+ AuroFloatingUI.isMousePressHandlerInitialized = true;
3555
+
3556
+ const mouseEventGlobalHandler = (event) => {
3557
+ AuroFloatingUI.isMousePressed = event.type === 'mousedown';
3558
+ };
3559
+
3560
+ window.addEventListener('mousedown', mouseEventGlobalHandler);
3561
+ window.addEventListener('mouseup', mouseEventGlobalHandler);
3562
+ }
3563
+ }
3564
+
3565
+ constructor(element, behavior) {
3566
+ this.element = element;
3567
+ this.behavior = behavior;
3568
+
3536
3569
  // Store event listener references for cleanup
3537
3570
  this.focusHandler = null;
3538
3571
  this.clickHandler = null;
3539
3572
  this.keyDownHandler = null;
3540
-
3573
+
3574
+ /**
3575
+ * @private
3576
+ */
3577
+ this.configureTrial = 0;
3578
+
3541
3579
  /**
3542
3580
  * @private
3543
3581
  */
3544
3582
  this.eventPrefix = undefined;
3583
+
3584
+ /**
3585
+ * @private
3586
+ */
3587
+ this.id = undefined;
3588
+
3589
+ /**
3590
+ * @private
3591
+ */
3592
+ this.showing = false;
3593
+
3594
+ /**
3595
+ * @private
3596
+ */
3597
+ this.strategy = undefined;
3545
3598
  }
3546
3599
 
3547
3600
  /**
@@ -3569,29 +3622,48 @@ class AuroFloatingUI {
3569
3622
  * @private
3570
3623
  * Determines the positioning strategy based on the current viewport size and mobile breakpoint.
3571
3624
  *
3572
- * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
3625
+ * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
3573
3626
  * defined in the bib element. If it is, the strategy is set to 'fullscreen'; otherwise, it defaults to 'floating'.
3574
3627
  *
3575
- * @returns {String} The positioning strategy, either 'fullscreen' or 'floating'.
3628
+ * @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
3576
3629
  */
3577
3630
  getPositioningStrategy() {
3578
- let strategy = 'floating';
3579
- if (this.element.bib.mobileFullscreenBreakpoint) {
3580
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${this.element.bib.mobileFullscreenBreakpoint})`).matches;
3581
- if (smallerThanBreakpoint) {
3582
- strategy = 'fullscreen';
3583
- }
3631
+ const breakpoint = this.element.bib.mobileFullscreenBreakpoint || this.element.floaterConfig?.fullscreenBreakpoint;
3632
+ switch (this.behavior) {
3633
+ case "tooltip":
3634
+ return "floating";
3635
+ case "dialog":
3636
+ case "drawer":
3637
+ if (breakpoint) {
3638
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
3639
+
3640
+ this.element.expanded = smallerThanBreakpoint;
3641
+ }
3642
+ if (this.element.nested) {
3643
+ return "cover";
3644
+ }
3645
+ return 'fullscreen';
3646
+ case "dropdown":
3647
+ case undefined:
3648
+ case null:
3649
+ if (breakpoint) {
3650
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
3651
+ if (smallerThanBreakpoint) {
3652
+ return 'fullscreen';
3653
+ }
3654
+ }
3655
+ return "floating";
3656
+ default:
3657
+ return this.behavior;
3584
3658
  }
3585
-
3586
- return strategy;
3587
3659
  }
3588
3660
 
3589
3661
  /**
3590
3662
  * @private
3591
3663
  * Positions the bib element based on the current configuration and positioning strategy.
3592
3664
  *
3593
- * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
3594
- * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
3665
+ * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
3666
+ * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
3595
3667
  * and applies the calculated position to the bib's style.
3596
3668
  */
3597
3669
  position() {
@@ -3602,21 +3674,33 @@ class AuroFloatingUI {
3602
3674
  this.mirrorSize();
3603
3675
  // Define the middlware for the floater configuration
3604
3676
  const middleware = [
3605
- offset(this.element.floaterConfig.offset || 0),
3606
- ...(this.element.floaterConfig.flip ? [flip()] : []), // Add flip middleware if flip is enabled
3607
- ...(this.element.floaterConfig.autoPlacement ? [autoPlacement()] : []), // Add autoPlacement middleware if autoPlacement is enabled
3677
+ offset(this.element.floaterConfig?.offset || 0),
3678
+ ...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
3679
+ ...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
3608
3680
  ];
3609
3681
 
3610
3682
  // Compute the position of the bib
3611
3683
  computePosition(this.element.trigger, this.element.bib, {
3612
- placement: this.element.floaterConfig.placement || 'bottom',
3684
+ placement: this.element.floaterConfig?.placement,
3613
3685
  middleware: middleware || []
3614
- }).then(({x, y}) => { // eslint-disable-line id-length
3686
+ }).then(({ x, y }) => { // eslint-disable-line id-length
3615
3687
  Object.assign(this.element.bib.style, {
3616
3688
  left: `${x}px`,
3617
3689
  top: `${y}px`,
3618
3690
  });
3619
3691
  });
3692
+ } else if (strategy === 'cover') {
3693
+ // Compute the position of the bib
3694
+ computePosition(this.element.parentNode, this.element.bib, {
3695
+ placement: 'bottom-start'
3696
+ }).then(({ x, y }) => { // eslint-disable-line id-length
3697
+ Object.assign(this.element.bib.style, {
3698
+ left: `${x}px`,
3699
+ top: `${y - this.element.parentNode.offsetHeight}px`,
3700
+ width: `${this.element.parentNode.offsetWidth}px`,
3701
+ height: `${this.element.parentNode.offsetHeight}px`
3702
+ });
3703
+ });
3620
3704
  }
3621
3705
  }
3622
3706
 
@@ -3645,34 +3729,48 @@ class AuroFloatingUI {
3645
3729
  *
3646
3730
  * @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
3647
3731
  */
3648
- configureBibStrategy(strategy) {
3649
- const prevStrategy = this.element.isBibFullscreen ? 'fullscreen' : 'floating';
3650
- if (strategy === 'fullscreen') {
3732
+ configureBibStrategy(value) {
3733
+ if (value === 'fullscreen') {
3651
3734
  this.element.isBibFullscreen = true;
3652
3735
  // reset the prev position
3736
+ this.element.bib.setAttribute('isfullscreen', "");
3737
+ this.element.bib.style.position = 'fixed';
3653
3738
  this.element.bib.style.top = "0px";
3654
3739
  this.element.bib.style.left = "0px";
3740
+ this.element.bib.style.width = '';
3741
+ this.element.bib.style.height = '';
3655
3742
 
3656
3743
  // reset the size that was mirroring `size` css-part
3657
3744
  const bibContent = this.element.bib.shadowRoot.querySelector(".container");
3658
- bibContent.style.width = '';
3659
- bibContent.style.height = '';
3660
- bibContent.style.maxWidth = '';
3661
- bibContent.style.maxHeight = `${window.visualViewport.height}px`;
3745
+ if (bibContent) {
3746
+ bibContent.style.width = '';
3747
+ bibContent.style.height = '';
3748
+ bibContent.style.maxWidth = '';
3749
+ bibContent.style.maxHeight = `${window.visualViewport.height}px`;
3750
+ this.configureTrial = 0;
3751
+ } else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
3752
+ this.configureTrial += 1;
3753
+
3754
+ setTimeout(() => {
3755
+ this.configureBibStrategy(value);
3756
+ }, 0);
3757
+ }
3662
3758
 
3663
3759
  if (this.element.isPopoverVisible) {
3664
3760
  this.lockScroll(true);
3665
3761
  }
3666
3762
  } else {
3763
+ this.element.bib.style.position = '';
3764
+ this.element.bib.removeAttribute('isfullscreen');
3667
3765
  this.element.isBibFullscreen = false;
3668
-
3669
- this.lockScroll(false);
3670
3766
  }
3671
3767
 
3672
- if (prevStrategy !== strategy) {
3768
+ const isChanged = this.strategy && this.strategy !== value;
3769
+ this.strategy = value;
3770
+ if (isChanged) {
3673
3771
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-strategy-change` : 'strategy-change', {
3674
3772
  detail: {
3675
- strategy,
3773
+ value,
3676
3774
  },
3677
3775
  composed: true
3678
3776
  });
@@ -3683,18 +3781,6 @@ class AuroFloatingUI {
3683
3781
 
3684
3782
  updateState() {
3685
3783
  const isVisible = this.element.isPopoverVisible;
3686
-
3687
- // Refactor this to apply attribute to correct focusable element
3688
- // Reference Issue: https://github.com/AlaskaAirlines/auro-library/issues/105
3689
- //
3690
- // this.element.trigger.setAttribute('aria-expanded', isVisible);
3691
-
3692
- if (isVisible) {
3693
- this.element.bib.setAttribute('data-show', true);
3694
- } else {
3695
- this.element.bib.removeAttribute('data-show');
3696
- }
3697
-
3698
3784
  if (!isVisible) {
3699
3785
  this.cleanupHideHandlers();
3700
3786
  try {
@@ -3705,16 +3791,32 @@ class AuroFloatingUI {
3705
3791
  }
3706
3792
  }
3707
3793
 
3794
+ /**
3795
+ * @private
3796
+ * getting called on 'blur' in trigger or `focusin` in document
3797
+ *
3798
+ * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
3799
+ * This method checks if the currently active element is still within the trigger or bib.
3800
+ * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
3801
+ */
3708
3802
  handleFocusLoss() {
3709
- if (this.element.noHideOnThisFocusLoss ||
3710
- this.element.hasAttribute('noHideOnThisFocusLoss')) {
3803
+ // if mouse is being pressed, skip and let click event to handle the action
3804
+ if (AuroFloatingUI.isMousePressed) {
3805
+ return;
3806
+ }
3807
+
3808
+ if (this.element.noHideOnThisFocusLoss ||
3809
+ this.element.hasAttribute('noHideOnThisFocusLoss')) {
3711
3810
  return;
3712
3811
  }
3713
3812
 
3714
- const {activeElement} = document;
3715
- if (activeElement === document.querySelector('body') ||
3716
- this.element.contains(activeElement) ||
3717
- this.element.bibContent?.contains(activeElement)) {
3813
+ const { activeElement } = document;
3814
+ // if focus is still inside of trigger or bib, do not close
3815
+ if (this.element.contains(activeElement) || this.element.bib?.contains(activeElement)) {
3816
+ return;
3817
+ }
3818
+ // if fullscreen bib is still open and the focus is missing, do not close
3819
+ if (this.element.bib.hasAttribute('isfullscreen') && activeElement === document.body) {
3718
3820
  return;
3719
3821
  }
3720
3822
 
@@ -3722,31 +3824,66 @@ class AuroFloatingUI {
3722
3824
  }
3723
3825
 
3724
3826
  setupHideHandlers() {
3827
+ this.preventFocusLoseOnBibClick = (event) => {
3828
+ event.preventDefault();
3829
+ event.stopPropagation();
3830
+ };
3831
+ this.element.bib.addEventListener('mousedown', this.preventFocusLoseOnBibClick);
3832
+
3725
3833
  // Define handlers & store references
3726
3834
  this.focusHandler = () => this.handleFocusLoss();
3727
3835
 
3728
3836
  this.clickHandler = (evt) => {
3729
- if (!evt.composedPath().includes(this.element.trigger) &&
3730
- !evt.composedPath().includes(this.element.bibContent)) {
3731
- this.hideBib();
3837
+ if ((!evt.composedPath().includes(this.element.trigger) &&
3838
+ !evt.composedPath().includes(this.element.bib)) ||
3839
+ (this.element.bib.backdrop && evt.composedPath().includes(this.element.bib.backdrop))) {
3840
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
3841
+
3842
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI.element.isPopoverVisible) {
3843
+ // if something else is open, close that
3844
+ existedVisibleFloatingUI.hideBib();
3845
+ document.expandedAuroFormkitDropdown = null;
3846
+ document.expandedAuroFloater = this;
3847
+ } else {
3848
+ this.hideBib();
3849
+ }
3732
3850
  }
3733
3851
  };
3734
3852
 
3735
3853
  // ESC key handler
3736
3854
  this.keyDownHandler = (evt) => {
3737
3855
  if (evt.key === 'Escape' && this.element.isPopoverVisible) {
3856
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
3857
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this && existedVisibleFloatingUI.element.isPopoverVisible) {
3858
+ // if something else is open, let it handle itself
3859
+ return;
3860
+ }
3738
3861
  this.hideBib();
3739
3862
  }
3740
3863
  };
3741
3864
 
3742
- // Add event listeners using the stored references
3743
- document.addEventListener('focusin', this.focusHandler);
3744
- window.addEventListener('click', this.clickHandler);
3865
+ if (this.behavior !== 'drawer' && this.behavior !== 'dialog') {
3866
+ // Add event listeners using the stored references
3867
+ document.addEventListener('focusin', this.focusHandler);
3868
+ }
3869
+
3745
3870
  document.addEventListener('keydown', this.keyDownHandler);
3871
+
3872
+ // send this task to the end of queue to prevent conflicting
3873
+ // it conflicts if showBib gets call from a button that's not this.element.trigger
3874
+ setTimeout(() => {
3875
+ window.addEventListener('click', this.clickHandler);
3876
+ }, 0);
3746
3877
  }
3747
3878
 
3748
3879
  cleanupHideHandlers() {
3749
3880
  // Remove event listeners if they exist
3881
+
3882
+ if (this.preventFocusLoseOnBibClick) {
3883
+ this.element.bib.removeEventListener('mousedown', this.preventFocusLoseOnBibClick);
3884
+ delete this.preventFocusLoseOnBibClick;
3885
+ }
3886
+
3750
3887
  if (this.focusHandler) {
3751
3888
  document.removeEventListener('focusin', this.focusHandler);
3752
3889
  this.focusHandler = null;
@@ -3771,40 +3908,54 @@ class AuroFloatingUI {
3771
3908
 
3772
3909
  updateCurrentExpandedDropdown() {
3773
3910
  // Close any other dropdown that is already open
3774
- if (document.expandedAuroFormkitDropdown) {
3775
- document.expandedAuroFormkitDropdown.hide;
3911
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
3912
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
3913
+ existedVisibleFloatingUI.isPopoverVisible &&
3914
+ document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
3915
+ document.expandedAuroFloater.hideBib();
3776
3916
  }
3777
3917
 
3778
- document.expandedAuroFormkitDropdown = this;
3918
+ document.expandedAuroFloater = this;
3779
3919
  }
3780
3920
 
3781
3921
  showBib() {
3782
- if (!this.element.disabled && !this.element.isPopoverVisible) {
3922
+ if (!this.element.disabled && !this.showing) {
3783
3923
  this.updateCurrentExpandedDropdown();
3784
- this.element.isPopoverVisible = true;
3785
3924
  this.element.triggerChevron?.setAttribute('data-expanded', true);
3786
-
3787
- this.dispatchEventDropdownToggle();
3788
- this.position();
3789
-
3790
- // Clean up any existing handlers before setting up new ones
3791
- this.cleanupHideHandlers();
3792
- this.setupHideHandlers();
3925
+
3926
+ // prevent double showing: isPopovervisible gets first and showBib gets called later
3927
+ if (!this.showing) {
3928
+ if (!this.element.modal) {
3929
+ this.setupHideHandlers();
3930
+ }
3931
+ this.showing = true;
3932
+ this.element.isPopoverVisible = true;
3933
+ this.position();
3934
+ this.dispatchEventDropdownToggle();
3935
+ }
3793
3936
 
3794
3937
  // Setup auto update to handle resize and scroll
3795
- this.element.cleanup = autoUpdate(this.element.trigger, this.element.bib, () => {
3938
+ this.element.cleanup = autoUpdate(this.element.trigger || this.element.parentNode, this.element.bib, () => {
3796
3939
  this.position();
3797
3940
  });
3798
3941
  }
3799
3942
  }
3800
3943
 
3801
3944
  hideBib() {
3802
- if (this.element.isPopoverVisible && !this.element.disabled && !this.element.noToggle) {
3803
- this.element.isPopoverVisible = false;
3945
+ if (!this.element.disabled && !this.element.noToggle) {
3804
3946
  this.lockScroll(false);
3805
3947
  this.element.triggerChevron?.removeAttribute('data-expanded');
3806
- this.dispatchEventDropdownToggle();
3948
+
3949
+ if (this.element.isPopoverVisible) {
3950
+ this.element.isPopoverVisible = false;
3951
+ }
3952
+ if (this.showing) {
3953
+ this.cleanupHideHandlers();
3954
+ this.showing = false;
3955
+ this.dispatchEventDropdownToggle();
3956
+ }
3807
3957
  }
3958
+ document.expandedAuroFloater = null;
3808
3959
  }
3809
3960
 
3810
3961
  /**
@@ -3814,7 +3965,7 @@ class AuroFloatingUI {
3814
3965
  dispatchEventDropdownToggle() {
3815
3966
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-toggled` : 'toggled', {
3816
3967
  detail: {
3817
- expanded: this.element.isPopoverVisible,
3968
+ expanded: this.showing,
3818
3969
  },
3819
3970
  composed: true
3820
3971
  });
@@ -3862,15 +4013,18 @@ class AuroFloatingUI {
3862
4013
  break;
3863
4014
  case 'focus':
3864
4015
  if (this.element.focusShow) {
4016
+
3865
4017
  /*
3866
- This needs to better handle clicking that gives focus -
3867
- currently it shows and then immediately hides the bib
4018
+ This needs to better handle clicking that gives focus -
4019
+ currently it shows and then immediately hides the bib
3868
4020
  */
3869
4021
  this.showBib();
3870
4022
  }
3871
4023
  break;
3872
4024
  case 'blur':
3873
- this.handleFocusLoss();
4025
+ // send this task 100ms later queue to
4026
+ // wait a frame in case focus moves within the floating element/bib
4027
+ setTimeout(() => this.handleFocusLoss(), 0);
3874
4028
  break;
3875
4029
  case 'click':
3876
4030
  if (document.activeElement === document.body) {
@@ -3878,7 +4032,7 @@ class AuroFloatingUI {
3878
4032
  }
3879
4033
  this.handleClick();
3880
4034
  break;
3881
- // Do nothing
4035
+ // Do nothing
3882
4036
  }
3883
4037
  }
3884
4038
  }
@@ -3922,39 +4076,79 @@ class AuroFloatingUI {
3922
4076
  });
3923
4077
  }
3924
4078
 
4079
+ /**
4080
+ *
4081
+ * @param {*} eventPrefix
4082
+ */
4083
+ regenerateBibId() {
4084
+ this.id = this.element.getAttribute('id');
4085
+ if (!this.id) {
4086
+ this.id = window.crypto.randomUUID();
4087
+ this.element.setAttribute('id', this.id);
4088
+ }
4089
+
4090
+ this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
4091
+ }
4092
+
3925
4093
  configure(elem, eventPrefix) {
4094
+ AuroFloatingUI.setupMousePressChecker();
4095
+
3926
4096
  this.eventPrefix = eventPrefix;
3927
- this.element = elem;
3928
- this.element.trigger = this.element.shadowRoot.querySelector('#trigger');
3929
- this.element.bib = this.element.shadowRoot.querySelector('#bib');
4097
+ if (this.element !== elem) {
4098
+ this.element = elem;
4099
+ }
4100
+
4101
+ if (this.behavior !== this.element.behavior) {
4102
+ this.behavior = this.element.behavior;
4103
+ }
4104
+
4105
+ if (this.element.trigger) {
4106
+ this.disconnect();
4107
+ }
4108
+ this.element.trigger = this.element.triggerElement || this.element.shadowRoot.querySelector('#trigger') || this.element.trigger;
4109
+ this.element.bib = this.element.shadowRoot.querySelector('#bib') || this.element.bib;
3930
4110
  this.element.bibSizer = this.element.shadowRoot.querySelector('#bibSizer');
3931
4111
  this.element.triggerChevron = this.element.shadowRoot.querySelector('#showStateIcon');
3932
4112
 
4113
+
4114
+ if (this.element.floaterConfig) {
4115
+ this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
4116
+ }
4117
+
3933
4118
  document.body.append(this.element.bib);
3934
4119
 
4120
+ this.regenerateBibId();
3935
4121
  this.handleTriggerTabIndex();
3936
4122
 
3937
4123
  this.handleEvent = this.handleEvent.bind(this);
3938
- this.element.trigger.addEventListener('keydown', this.handleEvent);
3939
- this.element.trigger.addEventListener('click', this.handleEvent);
3940
- this.element.trigger.addEventListener('mouseenter', this.handleEvent);
3941
- this.element.trigger.addEventListener('mouseleave', this.handleEvent);
3942
- this.element.trigger.addEventListener('focus', this.handleEvent);
3943
- this.element.trigger.addEventListener('blur', this.handleEvent);
4124
+ if (this.element.trigger) {
4125
+ this.element.trigger.addEventListener('keydown', this.handleEvent);
4126
+ this.element.trigger.addEventListener('click', this.handleEvent);
4127
+ this.element.trigger.addEventListener('mouseenter', this.handleEvent);
4128
+ this.element.trigger.addEventListener('mouseleave', this.handleEvent);
4129
+ this.element.trigger.addEventListener('focus', this.handleEvent);
4130
+ this.element.trigger.addEventListener('blur', this.handleEvent);
4131
+ }
3944
4132
  }
3945
4133
 
3946
4134
  disconnect() {
3947
4135
  this.cleanupHideHandlers();
3948
- this.element.cleanup?.();
3949
-
3950
- // Remove event & keyboard listeners
3951
- if (this.element?.trigger) {
3952
- this.element.trigger.removeEventListener('keydown', this.handleEvent);
3953
- this.element.trigger.removeEventListener('click', this.handleEvent);
3954
- this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
3955
- this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
3956
- this.element.trigger.removeEventListener('focus', this.handleEvent);
3957
- this.element.trigger.removeEventListener('blur', this.handleEvent);
4136
+ if (this.element) {
4137
+ this.element.cleanup?.();
4138
+
4139
+ if (this.element.bib) {
4140
+ this.element.shadowRoot.append(this.element.bib);
4141
+ }
4142
+
4143
+ // Remove event & keyboard listeners
4144
+ if (this.element?.trigger) {
4145
+ this.element.trigger.removeEventListener('keydown', this.handleEvent);
4146
+ this.element.trigger.removeEventListener('click', this.handleEvent);
4147
+ this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
4148
+ this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
4149
+ this.element.trigger.removeEventListener('focus', this.handleEvent);
4150
+ this.element.trigger.removeEventListener('blur', this.handleEvent);
4151
+ }
3958
4152
  }
3959
4153
  }
3960
4154
  }
@@ -4917,6 +5111,11 @@ class AuroDropdown extends r {
4917
5111
  * @private
4918
5112
  */
4919
5113
  this.helpTextTag = versioning.generateTag('auro-formkit-dropdown-helptext', helpTextVersion, AuroHelpText);
5114
+
5115
+ /**
5116
+ * @private
5117
+ */
5118
+ this.bindFocusEventToTrigger = this.bindFocusEventToTrigger.bind(this);
4920
5119
  }
4921
5120
 
4922
5121
  /**
@@ -5185,6 +5384,7 @@ class AuroDropdown extends r {
5185
5384
  disconnectedCallback() {
5186
5385
  super.disconnectedCallback();
5187
5386
  this.floater.disconnect();
5387
+ this.clearTriggerFocusEventBinding();
5188
5388
  }
5189
5389
 
5190
5390
  updated(changedProperties) {
@@ -5299,6 +5499,62 @@ class AuroDropdown extends r {
5299
5499
  return result;
5300
5500
  }
5301
5501
 
5502
+ /**
5503
+ * @private
5504
+ * Creates and dispatches a duplicate focus event on the trigger element.
5505
+ * @param {Event} event - The original focus event.
5506
+ */
5507
+ bindFocusEventToTrigger(event) {
5508
+ const dupEvent = new FocusEvent(event.type, {
5509
+ bubbles: false,
5510
+ cancelable: false,
5511
+ composed: true,
5512
+ });
5513
+ this.trigger.dispatchEvent(dupEvent);
5514
+ }
5515
+
5516
+ /**
5517
+ * @private
5518
+ * Sets up event listeners to deliver focus and blur events from nested Auro components within the trigger slot to trigger.
5519
+ * This ensures that focus/blur events originating from within these components are propagated to the trigger element itself.
5520
+ */
5521
+ setupTriggerFocusEventBinding() {
5522
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
5523
+ return;
5524
+ }
5525
+
5526
+ this.triggerContentSlot.forEach((node) => {
5527
+ if (node.querySelectorAll) {
5528
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
5529
+ auroElements.forEach((auroEl) => {
5530
+ auroEl.addEventListener('focus', this.bindFocusEventToTrigger);
5531
+ auroEl.addEventListener('blur', this.bindFocusEventToTrigger);
5532
+ });
5533
+ }
5534
+ });
5535
+ }
5536
+
5537
+ /**
5538
+ * Clears focus and blur event listeners from nested Auro components within the trigger slot.
5539
+ * @private
5540
+ * @returns {void}
5541
+ */
5542
+ clearTriggerFocusEventBinding() {
5543
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
5544
+ return;
5545
+ }
5546
+
5547
+ this.triggerContentSlot.forEach((node) => {
5548
+ if (node.querySelectorAll) {
5549
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
5550
+ auroElements.forEach((auroEl) => {
5551
+ auroEl.removeEventListener('focus', this.bindFocusEventToTrigger);
5552
+ auroEl.removeEventListener('blur', this.bindFocusEventToTrigger);
5553
+ });
5554
+ }
5555
+ });
5556
+ }
5557
+
5302
5558
  /**
5303
5559
  * Handles changes to the trigger content slot and updates related properties.
5304
5560
  *
@@ -5346,6 +5602,7 @@ class AuroDropdown extends r {
5346
5602
  }
5347
5603
 
5348
5604
  if (this.triggerContentSlot) {
5605
+ this.setupTriggerFocusEventBinding();
5349
5606
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
5350
5607
  if (slot.textContent.trim()) {
5351
5608
  return true;
@@ -5451,6 +5708,7 @@ class AuroDropdown extends r {
5451
5708
  <${this.dropdownBibTag}
5452
5709
  id="bib"
5453
5710
  role="tooltip"
5711
+ ?data-show="${this.isPopoverVisible}"
5454
5712
  ?isfullscreen="${this.isBibFullscreen}"
5455
5713
  ?common="${this.common}"
5456
5714
  ?rounded="${this.common || this.rounded}"
@@ -6656,7 +6914,7 @@ class AuroCounterGroup extends r {
6656
6914
  this.dropdown.hide();
6657
6915
  }
6658
6916
 
6659
- if (event.key === 'Tab' && event.target.offsetParent.id === 'bib') {
6917
+ if (event.key === 'Tab' && this.dropdown && event.target.offsetParent === this.dropdown.bib) {
6660
6918
  this.dropdown.noHideOnThisFocusLoss = true;
6661
6919
 
6662
6920
  const currentIndex = Array.from(counters).indexOf(document.activeElement);