// Дропдауны кита вне мыши: GnDropdown позиционирует меню от левого края триггера
// (position:absolute; left:0), и у триггеров у правого края экрана меню вылезает
// наружу. Кит не даёт ручек позиционирования — после открытия выравниваем меню
// (и по горизонтали, и по вертикали) в пределах вьюпорта, не трогая стили кита.
//
// На мобильных (до 767px, ТЗ 0.77) этого не нужно: меню целиком раскладывается
// как шторка снизу из kit-overrides.css, и инлайн-координаты только мешали бы.
const MOBILE = '(max-width: 767px)'
export function installDropdownClamp(): void {
const clamp = () => {
const mobile = window.matchMedia(MOBILE).matches
for (const dropdown of Array.from(document.querySelectorAll<HTMLElement>('.dropdown.is-open'))) {
const menu = dropdown.querySelector<HTMLElement>('.dropdown-menu')
if (!menu) continue
// Следы прошлого открытия (или прошлой ширины окна) снимаем всегда:
// на мобильных они перебивали бы раскладку шторки
menu.style.left = ''
menu.style.right = ''
menu.style.top = ''
menu.style.bottom = ''
if (mobile) continue
const rect = dropdown.getBoundingClientRect()
const vw = document.documentElement.clientWidth
const vh = window.innerHeight
// Горизонталь: если меню не помещается справа от триггера — открыть влево.
// `left: auto` обязателен: у кита `.dropdown-menu{left:0}` — одного inline
// `right: 0` мало, оба края оказываются заданными, и при min-width:220px
// меню всё равно остаётся у левого края триггера (у правой колонки карточек
// это выезд за вьюпорт на всю свою ширину, 0.79)
if (rect.left + menu.offsetWidth > vw - 8) {
menu.style.left = 'auto'
menu.style.right = '0'
} else {
menu.style.left = '0'
}
// Вертикаль: если не помещается под триггером, но есть место сверху — открыть вверх
if (rect.bottom + 8 + menu.offsetHeight > vh && rect.top - menu.offsetHeight > 0) {
menu.style.top = 'auto'
menu.style.bottom = 'calc(100% + 8px)'
}
}
}
// Открытие дропдауна происходит по клику синхронно, DOM обновляется в
// микротаске Vue — macrotask setTimeout отрабатывает уже после рендера
document.addEventListener('click', () => setTimeout(clamp, 0), true)
// у открытого меню при смене ширины окна остаются координаты старого режима
window.addEventListener('resize', clamp)
}