В целом, всплывающие окна - зло, так как перекрывают собой интерфейс. И в общем случае, лучше открывать для них отдельную страницу в сторонке. Но когда надо выбрать значение в селекте из пары пунктов - открывать отдельную страницу было было оверкиллом.
Тут-то и выходит на сцену $mol_pop, на базе которого у нас работают все пикеры - он открывает небольшое окошко (Bubble) рядом с якорным компонентом (Anchor). В случае пикера, якорем выступает кнопка его открытия (Trigger).
10 лет у нас была простая и надёжная реализация - бабл располагался рядом с якорем и через CSS позиционировался как надо. Работало просто, быстро, надёжно. Но есть с такой реализацией одна беда - его надо было аккуратно позиционировать, иначе он мог быть обрезан из-за overflow или z-index, так как рендерился там же, где и располагался в доме - рядом с якорем.
Типичное решение этой проблемы - порталы, то есть вынос бабла в корень (body), чтобы он рендерился на отдельном слое поверх всего интерфейса. Но у этого подхода есть две беды:
- Так как он больше не располагается рядом с якорем, мы не можем простым css его позционировать рядом с ним. Эту проблему призван решить css-anchoring, но у него ещё слабая поддержка.
- Так как он выносится из компонента-владельца, то его содержимое невозможно стилизовать используя составные селекторы, включающие имя владельца. А на этом у нас построена вся стилизация.
- По той же причине, компонент-владелец перестаёт получать события от бабла, что требует хитрых костылей с их перекидыванием.
К счастью, сейчас уже добралась до всех браузеров поддержка Popover API, предназначенного как раз для реализации всплывашек. Просто ставим на бабл атрибут
popover="manual" и... ничего не меняется.Оказыается, надо императивно вызвать затем метод
showPopover(), чтобы браузер создал отдельный топовый слой и перенёс рендеринг бабла туда. hidePopover() же, наоборот, переносит рендеринг обратно (нейминг, конечно, божественный, да), но нам он и не нужен, так как баблы у нас рендерятся лишь когда начинают показываться, а когда перестают - удаляются нафиг, чтобы не тратить ресурсы впустую.Так как бабл в доме остаёются внутри владельца, рядом с якорем, то CSS и события работают как надо. А вот позиционирование, из-за рендеринга в отдельном топовом слое, тут уже приходится реализовывать вручную.
Благо, у нас уже есть компонент $mol_follower, который отслеживает позицию якоря в реальном времени и позиционирует себя так, чтобы оказаться рядом с нужной стороны.
Так что я скрестил ужа с ежом и.. вроде получилось. Давайте потестим. Из компромиссов:
- В устаревших браузерах бабл может обрезаться.
- При скроллинге, бабл на несколько кадров отстаёт от якоря. В будущем переведём $mol_follower на css-anchoring и это пройдёт.
