@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
@@ -3484,17 +3484,70 @@ const computePosition = (reference, floating, options) => {
3484
3484
  /* eslint-disable line-comment-position, no-inline-comments */
3485
3485
 
3486
3486
 
3487
+
3488
+ const MAX_CONFIGURATION_COUNT = 10;
3489
+
3487
3490
  class AuroFloatingUI {
3488
- constructor() {
3491
+
3492
+ /**
3493
+ * @private
3494
+ */
3495
+ static isMousePressed = false;
3496
+
3497
+ /**
3498
+ * @private
3499
+ */
3500
+ static isMousePressHandlerInitialized = false;
3501
+
3502
+ /**
3503
+ * @private
3504
+ */
3505
+ static setupMousePressChecker() {
3506
+ if (!AuroFloatingUI.isMousePressHandlerInitialized && window && window.addEventListener) {
3507
+ AuroFloatingUI.isMousePressHandlerInitialized = true;
3508
+
3509
+ const mouseEventGlobalHandler = (event) => {
3510
+ AuroFloatingUI.isMousePressed = event.type === 'mousedown';
3511
+ };
3512
+
3513
+ window.addEventListener('mousedown', mouseEventGlobalHandler);
3514
+ window.addEventListener('mouseup', mouseEventGlobalHandler);
3515
+ }
3516
+ }
3517
+
3518
+ constructor(element, behavior) {
3519
+ this.element = element;
3520
+ this.behavior = behavior;
3521
+
3489
3522
  // Store event listener references for cleanup
3490
3523
  this.focusHandler = null;
3491
3524
  this.clickHandler = null;
3492
3525
  this.keyDownHandler = null;
3493
-
3526
+
3527
+ /**
3528
+ * @private
3529
+ */
3530
+ this.configureTrial = 0;
3531
+
3494
3532
  /**
3495
3533
  * @private
3496
3534
  */
3497
3535
  this.eventPrefix = undefined;
3536
+
3537
+ /**
3538
+ * @private
3539
+ */
3540
+ this.id = undefined;
3541
+
3542
+ /**
3543
+ * @private
3544
+ */
3545
+ this.showing = false;
3546
+
3547
+ /**
3548
+ * @private
3549
+ */
3550
+ this.strategy = undefined;
3498
3551
  }
3499
3552
 
3500
3553
  /**
@@ -3522,29 +3575,48 @@ class AuroFloatingUI {
3522
3575
  * @private
3523
3576
  * Determines the positioning strategy based on the current viewport size and mobile breakpoint.
3524
3577
  *
3525
- * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
3578
+ * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
3526
3579
  * defined in the bib element. If it is, the strategy is set to 'fullscreen'; otherwise, it defaults to 'floating'.
3527
3580
  *
3528
- * @returns {String} The positioning strategy, either 'fullscreen' or 'floating'.
3581
+ * @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
3529
3582
  */
3530
3583
  getPositioningStrategy() {
3531
- let strategy = 'floating';
3532
- if (this.element.bib.mobileFullscreenBreakpoint) {
3533
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${this.element.bib.mobileFullscreenBreakpoint})`).matches;
3534
- if (smallerThanBreakpoint) {
3535
- strategy = 'fullscreen';
3536
- }
3584
+ const breakpoint = this.element.bib.mobileFullscreenBreakpoint || this.element.floaterConfig?.fullscreenBreakpoint;
3585
+ switch (this.behavior) {
3586
+ case "tooltip":
3587
+ return "floating";
3588
+ case "dialog":
3589
+ case "drawer":
3590
+ if (breakpoint) {
3591
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
3592
+
3593
+ this.element.expanded = smallerThanBreakpoint;
3594
+ }
3595
+ if (this.element.nested) {
3596
+ return "cover";
3597
+ }
3598
+ return 'fullscreen';
3599
+ case "dropdown":
3600
+ case undefined:
3601
+ case null:
3602
+ if (breakpoint) {
3603
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
3604
+ if (smallerThanBreakpoint) {
3605
+ return 'fullscreen';
3606
+ }
3607
+ }
3608
+ return "floating";
3609
+ default:
3610
+ return this.behavior;
3537
3611
  }
3538
-
3539
- return strategy;
3540
3612
  }
3541
3613
 
3542
3614
  /**
3543
3615
  * @private
3544
3616
  * Positions the bib element based on the current configuration and positioning strategy.
3545
3617
  *
3546
- * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
3547
- * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
3618
+ * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
3619
+ * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
3548
3620
  * and applies the calculated position to the bib's style.
3549
3621
  */
3550
3622
  position() {
@@ -3555,21 +3627,33 @@ class AuroFloatingUI {
3555
3627
  this.mirrorSize();
3556
3628
  // Define the middlware for the floater configuration
3557
3629
  const middleware = [
3558
- offset(this.element.floaterConfig.offset || 0),
3559
- ...(this.element.floaterConfig.flip ? [flip()] : []), // Add flip middleware if flip is enabled
3560
- ...(this.element.floaterConfig.autoPlacement ? [autoPlacement()] : []), // Add autoPlacement middleware if autoPlacement is enabled
3630
+ offset(this.element.floaterConfig?.offset || 0),
3631
+ ...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
3632
+ ...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
3561
3633
  ];
3562
3634
 
3563
3635
  // Compute the position of the bib
3564
3636
  computePosition(this.element.trigger, this.element.bib, {
3565
- placement: this.element.floaterConfig.placement || 'bottom',
3637
+ placement: this.element.floaterConfig?.placement,
3566
3638
  middleware: middleware || []
3567
- }).then(({x, y}) => { // eslint-disable-line id-length
3639
+ }).then(({ x, y }) => { // eslint-disable-line id-length
3568
3640
  Object.assign(this.element.bib.style, {
3569
3641
  left: `${x}px`,
3570
3642
  top: `${y}px`,
3571
3643
  });
3572
3644
  });
3645
+ } else if (strategy === 'cover') {
3646
+ // Compute the position of the bib
3647
+ computePosition(this.element.parentNode, this.element.bib, {
3648
+ placement: 'bottom-start'
3649
+ }).then(({ x, y }) => { // eslint-disable-line id-length
3650
+ Object.assign(this.element.bib.style, {
3651
+ left: `${x}px`,
3652
+ top: `${y - this.element.parentNode.offsetHeight}px`,
3653
+ width: `${this.element.parentNode.offsetWidth}px`,
3654
+ height: `${this.element.parentNode.offsetHeight}px`
3655
+ });
3656
+ });
3573
3657
  }
3574
3658
  }
3575
3659
 
@@ -3598,34 +3682,48 @@ class AuroFloatingUI {
3598
3682
  *
3599
3683
  * @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
3600
3684
  */
3601
- configureBibStrategy(strategy) {
3602
- const prevStrategy = this.element.isBibFullscreen ? 'fullscreen' : 'floating';
3603
- if (strategy === 'fullscreen') {
3685
+ configureBibStrategy(value) {
3686
+ if (value === 'fullscreen') {
3604
3687
  this.element.isBibFullscreen = true;
3605
3688
  // reset the prev position
3689
+ this.element.bib.setAttribute('isfullscreen', "");
3690
+ this.element.bib.style.position = 'fixed';
3606
3691
  this.element.bib.style.top = "0px";
3607
3692
  this.element.bib.style.left = "0px";
3693
+ this.element.bib.style.width = '';
3694
+ this.element.bib.style.height = '';
3608
3695
 
3609
3696
  // reset the size that was mirroring `size` css-part
3610
3697
  const bibContent = this.element.bib.shadowRoot.querySelector(".container");
3611
- bibContent.style.width = '';
3612
- bibContent.style.height = '';
3613
- bibContent.style.maxWidth = '';
3614
- bibContent.style.maxHeight = `${window.visualViewport.height}px`;
3698
+ if (bibContent) {
3699
+ bibContent.style.width = '';
3700
+ bibContent.style.height = '';
3701
+ bibContent.style.maxWidth = '';
3702
+ bibContent.style.maxHeight = `${window.visualViewport.height}px`;
3703
+ this.configureTrial = 0;
3704
+ } else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
3705
+ this.configureTrial += 1;
3706
+
3707
+ setTimeout(() => {
3708
+ this.configureBibStrategy(value);
3709
+ }, 0);
3710
+ }
3615
3711
 
3616
3712
  if (this.element.isPopoverVisible) {
3617
3713
  this.lockScroll(true);
3618
3714
  }
3619
3715
  } else {
3716
+ this.element.bib.style.position = '';
3717
+ this.element.bib.removeAttribute('isfullscreen');
3620
3718
  this.element.isBibFullscreen = false;
3621
-
3622
- this.lockScroll(false);
3623
3719
  }
3624
3720
 
3625
- if (prevStrategy !== strategy) {
3721
+ const isChanged = this.strategy && this.strategy !== value;
3722
+ this.strategy = value;
3723
+ if (isChanged) {
3626
3724
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-strategy-change` : 'strategy-change', {
3627
3725
  detail: {
3628
- strategy,
3726
+ value,
3629
3727
  },
3630
3728
  composed: true
3631
3729
  });
@@ -3636,18 +3734,6 @@ class AuroFloatingUI {
3636
3734
 
3637
3735
  updateState() {
3638
3736
  const isVisible = this.element.isPopoverVisible;
3639
-
3640
- // Refactor this to apply attribute to correct focusable element
3641
- // Reference Issue: https://github.com/AlaskaAirlines/auro-library/issues/105
3642
- //
3643
- // this.element.trigger.setAttribute('aria-expanded', isVisible);
3644
-
3645
- if (isVisible) {
3646
- this.element.bib.setAttribute('data-show', true);
3647
- } else {
3648
- this.element.bib.removeAttribute('data-show');
3649
- }
3650
-
3651
3737
  if (!isVisible) {
3652
3738
  this.cleanupHideHandlers();
3653
3739
  try {
@@ -3658,16 +3744,32 @@ class AuroFloatingUI {
3658
3744
  }
3659
3745
  }
3660
3746
 
3747
+ /**
3748
+ * @private
3749
+ * getting called on 'blur' in trigger or `focusin` in document
3750
+ *
3751
+ * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
3752
+ * This method checks if the currently active element is still within the trigger or bib.
3753
+ * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
3754
+ */
3661
3755
  handleFocusLoss() {
3662
- if (this.element.noHideOnThisFocusLoss ||
3663
- this.element.hasAttribute('noHideOnThisFocusLoss')) {
3756
+ // if mouse is being pressed, skip and let click event to handle the action
3757
+ if (AuroFloatingUI.isMousePressed) {
3758
+ return;
3759
+ }
3760
+
3761
+ if (this.element.noHideOnThisFocusLoss ||
3762
+ this.element.hasAttribute('noHideOnThisFocusLoss')) {
3664
3763
  return;
3665
3764
  }
3666
3765
 
3667
- const {activeElement} = document;
3668
- if (activeElement === document.querySelector('body') ||
3669
- this.element.contains(activeElement) ||
3670
- this.element.bibContent?.contains(activeElement)) {
3766
+ const { activeElement } = document;
3767
+ // if focus is still inside of trigger or bib, do not close
3768
+ if (this.element.contains(activeElement) || this.element.bib?.contains(activeElement)) {
3769
+ return;
3770
+ }
3771
+ // if fullscreen bib is still open and the focus is missing, do not close
3772
+ if (this.element.bib.hasAttribute('isfullscreen') && activeElement === document.body) {
3671
3773
  return;
3672
3774
  }
3673
3775
 
@@ -3675,31 +3777,66 @@ class AuroFloatingUI {
3675
3777
  }
3676
3778
 
3677
3779
  setupHideHandlers() {
3780
+ this.preventFocusLoseOnBibClick = (event) => {
3781
+ event.preventDefault();
3782
+ event.stopPropagation();
3783
+ };
3784
+ this.element.bib.addEventListener('mousedown', this.preventFocusLoseOnBibClick);
3785
+
3678
3786
  // Define handlers & store references
3679
3787
  this.focusHandler = () => this.handleFocusLoss();
3680
3788
 
3681
3789
  this.clickHandler = (evt) => {
3682
- if (!evt.composedPath().includes(this.element.trigger) &&
3683
- !evt.composedPath().includes(this.element.bibContent)) {
3684
- this.hideBib();
3790
+ if ((!evt.composedPath().includes(this.element.trigger) &&
3791
+ !evt.composedPath().includes(this.element.bib)) ||
3792
+ (this.element.bib.backdrop && evt.composedPath().includes(this.element.bib.backdrop))) {
3793
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
3794
+
3795
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI.element.isPopoverVisible) {
3796
+ // if something else is open, close that
3797
+ existedVisibleFloatingUI.hideBib();
3798
+ document.expandedAuroFormkitDropdown = null;
3799
+ document.expandedAuroFloater = this;
3800
+ } else {
3801
+ this.hideBib();
3802
+ }
3685
3803
  }
3686
3804
  };
3687
3805
 
3688
3806
  // ESC key handler
3689
3807
  this.keyDownHandler = (evt) => {
3690
3808
  if (evt.key === 'Escape' && this.element.isPopoverVisible) {
3809
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
3810
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this && existedVisibleFloatingUI.element.isPopoverVisible) {
3811
+ // if something else is open, let it handle itself
3812
+ return;
3813
+ }
3691
3814
  this.hideBib();
3692
3815
  }
3693
3816
  };
3694
3817
 
3695
- // Add event listeners using the stored references
3696
- document.addEventListener('focusin', this.focusHandler);
3697
- window.addEventListener('click', this.clickHandler);
3818
+ if (this.behavior !== 'drawer' && this.behavior !== 'dialog') {
3819
+ // Add event listeners using the stored references
3820
+ document.addEventListener('focusin', this.focusHandler);
3821
+ }
3822
+
3698
3823
  document.addEventListener('keydown', this.keyDownHandler);
3824
+
3825
+ // send this task to the end of queue to prevent conflicting
3826
+ // it conflicts if showBib gets call from a button that's not this.element.trigger
3827
+ setTimeout(() => {
3828
+ window.addEventListener('click', this.clickHandler);
3829
+ }, 0);
3699
3830
  }
3700
3831
 
3701
3832
  cleanupHideHandlers() {
3702
3833
  // Remove event listeners if they exist
3834
+
3835
+ if (this.preventFocusLoseOnBibClick) {
3836
+ this.element.bib.removeEventListener('mousedown', this.preventFocusLoseOnBibClick);
3837
+ delete this.preventFocusLoseOnBibClick;
3838
+ }
3839
+
3703
3840
  if (this.focusHandler) {
3704
3841
  document.removeEventListener('focusin', this.focusHandler);
3705
3842
  this.focusHandler = null;
@@ -3724,40 +3861,54 @@ class AuroFloatingUI {
3724
3861
 
3725
3862
  updateCurrentExpandedDropdown() {
3726
3863
  // Close any other dropdown that is already open
3727
- if (document.expandedAuroFormkitDropdown) {
3728
- document.expandedAuroFormkitDropdown.hide;
3864
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
3865
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
3866
+ existedVisibleFloatingUI.isPopoverVisible &&
3867
+ document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
3868
+ document.expandedAuroFloater.hideBib();
3729
3869
  }
3730
3870
 
3731
- document.expandedAuroFormkitDropdown = this;
3871
+ document.expandedAuroFloater = this;
3732
3872
  }
3733
3873
 
3734
3874
  showBib() {
3735
- if (!this.element.disabled && !this.element.isPopoverVisible) {
3875
+ if (!this.element.disabled && !this.showing) {
3736
3876
  this.updateCurrentExpandedDropdown();
3737
- this.element.isPopoverVisible = true;
3738
3877
  this.element.triggerChevron?.setAttribute('data-expanded', true);
3739
-
3740
- this.dispatchEventDropdownToggle();
3741
- this.position();
3742
-
3743
- // Clean up any existing handlers before setting up new ones
3744
- this.cleanupHideHandlers();
3745
- this.setupHideHandlers();
3878
+
3879
+ // prevent double showing: isPopovervisible gets first and showBib gets called later
3880
+ if (!this.showing) {
3881
+ if (!this.element.modal) {
3882
+ this.setupHideHandlers();
3883
+ }
3884
+ this.showing = true;
3885
+ this.element.isPopoverVisible = true;
3886
+ this.position();
3887
+ this.dispatchEventDropdownToggle();
3888
+ }
3746
3889
 
3747
3890
  // Setup auto update to handle resize and scroll
3748
- this.element.cleanup = autoUpdate(this.element.trigger, this.element.bib, () => {
3891
+ this.element.cleanup = autoUpdate(this.element.trigger || this.element.parentNode, this.element.bib, () => {
3749
3892
  this.position();
3750
3893
  });
3751
3894
  }
3752
3895
  }
3753
3896
 
3754
3897
  hideBib() {
3755
- if (this.element.isPopoverVisible && !this.element.disabled && !this.element.noToggle) {
3756
- this.element.isPopoverVisible = false;
3898
+ if (!this.element.disabled && !this.element.noToggle) {
3757
3899
  this.lockScroll(false);
3758
3900
  this.element.triggerChevron?.removeAttribute('data-expanded');
3759
- this.dispatchEventDropdownToggle();
3901
+
3902
+ if (this.element.isPopoverVisible) {
3903
+ this.element.isPopoverVisible = false;
3904
+ }
3905
+ if (this.showing) {
3906
+ this.cleanupHideHandlers();
3907
+ this.showing = false;
3908
+ this.dispatchEventDropdownToggle();
3909
+ }
3760
3910
  }
3911
+ document.expandedAuroFloater = null;
3761
3912
  }
3762
3913
 
3763
3914
  /**
@@ -3767,7 +3918,7 @@ class AuroFloatingUI {
3767
3918
  dispatchEventDropdownToggle() {
3768
3919
  const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-toggled` : 'toggled', {
3769
3920
  detail: {
3770
- expanded: this.element.isPopoverVisible,
3921
+ expanded: this.showing,
3771
3922
  },
3772
3923
  composed: true
3773
3924
  });
@@ -3815,15 +3966,18 @@ class AuroFloatingUI {
3815
3966
  break;
3816
3967
  case 'focus':
3817
3968
  if (this.element.focusShow) {
3969
+
3818
3970
  /*
3819
- This needs to better handle clicking that gives focus -
3820
- currently it shows and then immediately hides the bib
3971
+ This needs to better handle clicking that gives focus -
3972
+ currently it shows and then immediately hides the bib
3821
3973
  */
3822
3974
  this.showBib();
3823
3975
  }
3824
3976
  break;
3825
3977
  case 'blur':
3826
- this.handleFocusLoss();
3978
+ // send this task 100ms later queue to
3979
+ // wait a frame in case focus moves within the floating element/bib
3980
+ setTimeout(() => this.handleFocusLoss(), 0);
3827
3981
  break;
3828
3982
  case 'click':
3829
3983
  if (document.activeElement === document.body) {
@@ -3831,7 +3985,7 @@ class AuroFloatingUI {
3831
3985
  }
3832
3986
  this.handleClick();
3833
3987
  break;
3834
- // Do nothing
3988
+ // Do nothing
3835
3989
  }
3836
3990
  }
3837
3991
  }
@@ -3875,39 +4029,79 @@ class AuroFloatingUI {
3875
4029
  });
3876
4030
  }
3877
4031
 
4032
+ /**
4033
+ *
4034
+ * @param {*} eventPrefix
4035
+ */
4036
+ regenerateBibId() {
4037
+ this.id = this.element.getAttribute('id');
4038
+ if (!this.id) {
4039
+ this.id = window.crypto.randomUUID();
4040
+ this.element.setAttribute('id', this.id);
4041
+ }
4042
+
4043
+ this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
4044
+ }
4045
+
3878
4046
  configure(elem, eventPrefix) {
4047
+ AuroFloatingUI.setupMousePressChecker();
4048
+
3879
4049
  this.eventPrefix = eventPrefix;
3880
- this.element = elem;
3881
- this.element.trigger = this.element.shadowRoot.querySelector('#trigger');
3882
- this.element.bib = this.element.shadowRoot.querySelector('#bib');
4050
+ if (this.element !== elem) {
4051
+ this.element = elem;
4052
+ }
4053
+
4054
+ if (this.behavior !== this.element.behavior) {
4055
+ this.behavior = this.element.behavior;
4056
+ }
4057
+
4058
+ if (this.element.trigger) {
4059
+ this.disconnect();
4060
+ }
4061
+ this.element.trigger = this.element.triggerElement || this.element.shadowRoot.querySelector('#trigger') || this.element.trigger;
4062
+ this.element.bib = this.element.shadowRoot.querySelector('#bib') || this.element.bib;
3883
4063
  this.element.bibSizer = this.element.shadowRoot.querySelector('#bibSizer');
3884
4064
  this.element.triggerChevron = this.element.shadowRoot.querySelector('#showStateIcon');
3885
4065
 
4066
+
4067
+ if (this.element.floaterConfig) {
4068
+ this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
4069
+ }
4070
+
3886
4071
  document.body.append(this.element.bib);
3887
4072
 
4073
+ this.regenerateBibId();
3888
4074
  this.handleTriggerTabIndex();
3889
4075
 
3890
4076
  this.handleEvent = this.handleEvent.bind(this);
3891
- this.element.trigger.addEventListener('keydown', this.handleEvent);
3892
- this.element.trigger.addEventListener('click', this.handleEvent);
3893
- this.element.trigger.addEventListener('mouseenter', this.handleEvent);
3894
- this.element.trigger.addEventListener('mouseleave', this.handleEvent);
3895
- this.element.trigger.addEventListener('focus', this.handleEvent);
3896
- this.element.trigger.addEventListener('blur', this.handleEvent);
4077
+ if (this.element.trigger) {
4078
+ this.element.trigger.addEventListener('keydown', this.handleEvent);
4079
+ this.element.trigger.addEventListener('click', this.handleEvent);
4080
+ this.element.trigger.addEventListener('mouseenter', this.handleEvent);
4081
+ this.element.trigger.addEventListener('mouseleave', this.handleEvent);
4082
+ this.element.trigger.addEventListener('focus', this.handleEvent);
4083
+ this.element.trigger.addEventListener('blur', this.handleEvent);
4084
+ }
3897
4085
  }
3898
4086
 
3899
4087
  disconnect() {
3900
4088
  this.cleanupHideHandlers();
3901
- this.element.cleanup?.();
3902
-
3903
- // Remove event & keyboard listeners
3904
- if (this.element?.trigger) {
3905
- this.element.trigger.removeEventListener('keydown', this.handleEvent);
3906
- this.element.trigger.removeEventListener('click', this.handleEvent);
3907
- this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
3908
- this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
3909
- this.element.trigger.removeEventListener('focus', this.handleEvent);
3910
- this.element.trigger.removeEventListener('blur', this.handleEvent);
4089
+ if (this.element) {
4090
+ this.element.cleanup?.();
4091
+
4092
+ if (this.element.bib) {
4093
+ this.element.shadowRoot.append(this.element.bib);
4094
+ }
4095
+
4096
+ // Remove event & keyboard listeners
4097
+ if (this.element?.trigger) {
4098
+ this.element.trigger.removeEventListener('keydown', this.handleEvent);
4099
+ this.element.trigger.removeEventListener('click', this.handleEvent);
4100
+ this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
4101
+ this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
4102
+ this.element.trigger.removeEventListener('focus', this.handleEvent);
4103
+ this.element.trigger.removeEventListener('blur', this.handleEvent);
4104
+ }
3911
4105
  }
3912
4106
  }
3913
4107
  }
@@ -4870,6 +5064,11 @@ class AuroDropdown extends LitElement {
4870
5064
  * @private
4871
5065
  */
4872
5066
  this.helpTextTag = versioning.generateTag('auro-formkit-dropdown-helptext', helpTextVersion, AuroHelpText);
5067
+
5068
+ /**
5069
+ * @private
5070
+ */
5071
+ this.bindFocusEventToTrigger = this.bindFocusEventToTrigger.bind(this);
4873
5072
  }
4874
5073
 
4875
5074
  /**
@@ -5138,6 +5337,7 @@ class AuroDropdown extends LitElement {
5138
5337
  disconnectedCallback() {
5139
5338
  super.disconnectedCallback();
5140
5339
  this.floater.disconnect();
5340
+ this.clearTriggerFocusEventBinding();
5141
5341
  }
5142
5342
 
5143
5343
  updated(changedProperties) {
@@ -5252,6 +5452,62 @@ class AuroDropdown extends LitElement {
5252
5452
  return result;
5253
5453
  }
5254
5454
 
5455
+ /**
5456
+ * @private
5457
+ * Creates and dispatches a duplicate focus event on the trigger element.
5458
+ * @param {Event} event - The original focus event.
5459
+ */
5460
+ bindFocusEventToTrigger(event) {
5461
+ const dupEvent = new FocusEvent(event.type, {
5462
+ bubbles: false,
5463
+ cancelable: false,
5464
+ composed: true,
5465
+ });
5466
+ this.trigger.dispatchEvent(dupEvent);
5467
+ }
5468
+
5469
+ /**
5470
+ * @private
5471
+ * Sets up event listeners to deliver focus and blur events from nested Auro components within the trigger slot to trigger.
5472
+ * This ensures that focus/blur events originating from within these components are propagated to the trigger element itself.
5473
+ */
5474
+ setupTriggerFocusEventBinding() {
5475
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
5476
+ return;
5477
+ }
5478
+
5479
+ this.triggerContentSlot.forEach((node) => {
5480
+ if (node.querySelectorAll) {
5481
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
5482
+ auroElements.forEach((auroEl) => {
5483
+ auroEl.addEventListener('focus', this.bindFocusEventToTrigger);
5484
+ auroEl.addEventListener('blur', this.bindFocusEventToTrigger);
5485
+ });
5486
+ }
5487
+ });
5488
+ }
5489
+
5490
+ /**
5491
+ * Clears focus and blur event listeners from nested Auro components within the trigger slot.
5492
+ * @private
5493
+ * @returns {void}
5494
+ */
5495
+ clearTriggerFocusEventBinding() {
5496
+ if (!this.triggerContentSlot || this.triggerContentSlot.length === 0) {
5497
+ return;
5498
+ }
5499
+
5500
+ this.triggerContentSlot.forEach((node) => {
5501
+ if (node.querySelectorAll) {
5502
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
5503
+ auroElements.forEach((auroEl) => {
5504
+ auroEl.removeEventListener('focus', this.bindFocusEventToTrigger);
5505
+ auroEl.removeEventListener('blur', this.bindFocusEventToTrigger);
5506
+ });
5507
+ }
5508
+ });
5509
+ }
5510
+
5255
5511
  /**
5256
5512
  * Handles changes to the trigger content slot and updates related properties.
5257
5513
  *
@@ -5299,6 +5555,7 @@ class AuroDropdown extends LitElement {
5299
5555
  }
5300
5556
 
5301
5557
  if (this.triggerContentSlot) {
5558
+ this.setupTriggerFocusEventBinding();
5302
5559
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
5303
5560
  if (slot.textContent.trim()) {
5304
5561
  return true;
@@ -5404,6 +5661,7 @@ class AuroDropdown extends LitElement {
5404
5661
  <${this.dropdownBibTag}
5405
5662
  id="bib"
5406
5663
  role="tooltip"
5664
+ ?data-show="${this.isPopoverVisible}"
5407
5665
  ?isfullscreen="${this.isBibFullscreen}"
5408
5666
  ?common="${this.common}"
5409
5667
  ?rounded="${this.common || this.rounded}"
@@ -6609,7 +6867,7 @@ class AuroCounterGroup extends LitElement {
6609
6867
  this.dropdown.hide();
6610
6868
  }
6611
6869
 
6612
- if (event.key === 'Tab' && event.target.offsetParent.id === 'bib') {
6870
+ if (event.key === 'Tab' && this.dropdown && event.target.offsetParent === this.dropdown.bib) {
6613
6871
  this.dropdown.noHideOnThisFocusLoss = true;
6614
6872
 
6615
6873
  const currentIndex = Array.from(counters).indexOf(document.activeElement);
@@ -104,7 +104,7 @@ The use of any Auro custom element has a dependency on the [Auro Design Tokens](
104
104
  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.
105
105
 
106
106
  ```html
107
- <script type="module" src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-formkit@2.2.1-beta.1/auro-datepicker/+esm"></script>
107
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-formkit@2.2.1-beta.3/auro-datepicker/+esm"></script>
108
108
  ```
109
109
  <!-- AURO-GENERATED-CONTENT:END -->
110
110