diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 04c299600e..4e25f57299 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -57,7 +57,6 @@ const CLASS_NAME_SHOW = 'show' const CLASS_NAME_DROPUP = 'dropup' const CLASS_NAME_DROPEND = 'dropend' const CLASS_NAME_DROPSTART = 'dropstart' -const CLASS_NAME_MENUEND = 'dropdown-menu-end' const CLASS_NAME_NAVBAR = 'navbar' const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]' @@ -268,22 +267,23 @@ class Dropdown extends BaseComponent { _getPlacement() { const parentDropdown = this._element.parentNode - let placement = PLACEMENT_BOTTOM - // Handle dropup - if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) { - placement = this._menu.classList.contains(CLASS_NAME_MENUEND) ? - PLACEMENT_TOPEND : - PLACEMENT_TOP - } else if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) { - placement = PLACEMENT_RIGHT - } else if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) { - placement = PLACEMENT_LEFT - } else if (this._menu.classList.contains(CLASS_NAME_MENUEND)) { - placement = PLACEMENT_BOTTOMEND + if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) { + return PLACEMENT_RIGHT } - return placement + if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) { + return PLACEMENT_LEFT + } + + // We need to trim the value because custom properties can also include spaces + const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end' + + if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) { + return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP + } + + return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM } _detectNavbar() { diff --git a/scss/_dropdown.scss b/scss/_dropdown.scss index 9db6937aee..c86aac625b 100644 --- a/scss/_dropdown.scss +++ b/scss/_dropdown.scss @@ -32,19 +32,29 @@ border: $dropdown-border-width solid $dropdown-border-color; @include border-radius($dropdown-border-radius); @include box-shadow($dropdown-box-shadow); + + // Reset positioning when positioned with Popper + &[style] { + right: auto; + } } // scss-docs-start responsive-breakpoints +// We deliberately hardcode the `bs-` prefix because we check +// this custom property in JS to determine Popper's positioning + @each $breakpoint in map-keys($grid-breakpoints) { @include media-breakpoint-up($breakpoint) { $infix: breakpoint-infix($breakpoint, $grid-breakpoints); .dropdown-menu#{$infix}-start { + --bs-position: start; right: auto #{"/* rtl:ignore */"}; left: 0 #{"/* rtl:ignore */"}; } .dropdown-menu#{$infix}-end { + --bs-position: end; right: 0 #{"/* rtl:ignore */"}; left: auto #{"/* rtl:ignore */"}; } @@ -101,19 +111,6 @@ } } -// When Popper is enabled, reset the basic dropdown position -// stylelint-disable-next-line no-duplicate-selectors -.dropdown-menu { - &[data-popper-placement^="top"], - &[data-popper-placement^="right"], - &[data-popper-placement^="bottom"], - &[data-popper-placement^="left"] { - right: auto; - bottom: auto; - left: auto; - } -} - // Dividers (basically an `