Типизация основных сущностей

Popper.js — это мощная библиотека для управления позиционированием всплывающих элементов относительно других элементов на странице. Ключевым аспектом её использования является понимание основных сущностей и их типов, что обеспечивает корректное взаимодействие и предотвращает ошибки во время разработки.


Popper Instance

Popper Instance — это объект, создаваемый функцией createPopper, который управляет положением всплывающего элемента относительно целевого элемента (reference element). Типичная структура объекта выглядит следующим образом:

const popperInstance = createPopper(reference, popper, options);
  • reference — HTMLElement, относительно которого позиционируется всплывающее окно.
  • popper — HTMLElement, который будет позиционироваться.
  • options — объект конфигурации с настройками поведения и модификаторами.

Тип объекта popperInstance включает методы:

  • update() — пересчитывает и обновляет положение Popper.
  • destroy() — уничтожает Popper и очищает слушатели событий.
  • setOptions(options) — позволяет динамически изменять конфигурацию.
interface PopperInstance {
    update: () => Promise<void>;
    destroy: () => void;
    setOptions: (options: Partial<Options>) => Promise<void>;
}

Reference и Popper Elements

Reference element и Popper element всегда являются DOM-элементами:

type ElementLike = HTMLElement | SVGElement | null;
  • reference — элемент, на основе которого вычисляется позиция.
  • popper — элемент, который отображается относительно reference.

Важно учитывать, что Popper.js корректно работает только с реальными элементами DOM. Передача null допустима только при динамическом рендеринге и требует проверки на существование элемента перед созданием Popper.


Options

Объект options определяет конфигурацию Popper и имеет следующие ключевые поля:

interface Options {
    placement?: Placement;
    modifiers?: Array<Modifier<any, any>>;
    strategy?: 'absolute' | 'fixed';
}
  • placement — определяет, где относительно reference будет находиться popper. Допустимые значения:
'auto' | 'top' | 'bottom' | 'left' | 'right' |
'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' |
'right-start' | 'right-end' | 'left-start' | 'left-end'
  • modifiers — массив объектов, влияющих на поведение Popper. Каждый модификатор имеет поля name, enabled, phase, fn, options.
interface Modifier<Name = string, Options = any> {
    name: Name;
    enabled?: boolean;
    phase?: 'beforeRead' | 'read' | 'afterRead' |
             'beforeMain' | 'main' | 'afterMain' |
             'beforeWrite' | 'write' | 'afterWrite';
    fn?: ModifierFn<any>;
    options?: Options;
}
  • strategy — определяет тип позиционирования элемента: absolute или fixed.

Placement и Variation

Placement — это комбинация основной позиции (top, bottom, left, right) и вариации (start, end).

  • Основная позиция указывает направление относительно reference.
  • Вариация (start или end) задаёт смещение по оси поперёк основной позиции.
type Placement =
    | 'auto'
    | 'top'
    | 'bottom'
    | 'right'
    | 'left'
    | 'top-start'
    | 'top-end'
    | 'bottom-start'
    | 'bottom-end'
    | 'right-start'
    | 'right-end'
    | 'left-start'
    | 'left-end';

Modifiers

Модификаторы — это ключевой инструмент настройки Popper.js. Каждый модификатор имеет:

  • name — уникальное имя.
  • enabled — флаг включения.
  • phase — фаза жизненного цикла Popper, когда вызывается модификатор.
  • fn — функция, реализующая логику модификатора.
  • effect — необязательная функция для побочных эффектов (например, добавление обработчиков событий).
  • options — объект настроек конкретного модификатора.

Пример модификатора offset:

const offsetModifier: Modifier<'offset', { offset: [number, number] }> = {
    name: 'offset',
    options: { offset: [0, 8] },
    enabled: true,
    phase: 'main',
    fn: ({ state, options }) => {
        state.styles.popper.top += options.offset[1];
        state.styles.popper.left += options.offset[0];
    }
};

State

Состояние Popper хранится в объекте state и содержит актуальные данные о позиции и размерах:

interface State {
    elements: { reference: ElementLike; popper: ElementLike };
    styles: { [key: string]: Partial<CSSStyleDeclaration> };
    attributes: { [key: string]: Record<string, string> };
    placement: Placement;
    modifiersData: { [key: string]: any };
}
  • elements — текущие DOM-элементы.
  • styles — вычисленные CSS-стили для popper.
  • attributes — атрибуты, автоматически управляемые Popper (например, data-popper-placement).
  • modifiersData — данные, которые модификаторы могут использовать и обновлять.

Strategy

Strategy определяет тип позиционирования Popper:

  • absolute — относительно ближайшего позиционированного предка.
  • fixed — относительно окна браузера.

Выбор стратегии влияет на вычисления размеров и смещений, особенно при использовании скролла и динамических контейнеров.


ReferenceRect и PopperRect

Для точного позиционирования Popper.js использует геометрические объекты:

interface Rect {
    x: number;
    y: number;
    width: number;
    height: number;
}

type ReferenceRect = Rect;
type PopperRect = Rect;
  • x, y — координаты относительно viewport.
  • width, height — размеры элемента.

Эти объекты формируются автоматически и используются в расчетах модификаторов.


Выводы по типизации

Popper.js строго разделяет:

  • Элементы DOM (reference, popper)
  • Конфигурационные объекты (options, modifiers)
  • Состояние и вычисленные данные (state, styles, attributes)

Это позволяет обеспечивать предсказуемое и безопасное позиционирование, минимизируя ошибки при работе с динамическими интерфейсами и адаптивными компонентами.


Хотите, могу продолжить и сделать раздел с подробной типизацией модификаторов с примером TypeScript? Это сильно углубит понимание структуры Popper.js.