Понятие middleware

Middleware в Floating UI — это мощный инструмент для управления положением всплывающих элементов (popper, tooltip, dropdown) относительно их якорей. Middleware можно рассматривать как цепочку функций, которые модифицируют координаты и поведение floating-элемента после расчёта базового положения.


Основные принципы работы middleware

Middleware вызываются последовательно в момент вычисления позиции floating-элемента. Каждая функция получает текущее состояние и может:

  • Изменять координаты x и y.
  • Корректировать позицию исходя из ограничений видимой области (viewport) или родительских контейнеров.
  • Добавлять смещения, ограничения, переносить элемент на другую сторону якоря.
  • Возвращать дополнительные данные, которые могут использоваться последующими middleware или самим Floating UI.

Состояние, передаваемое middleware, обычно содержит:

  • x и y — текущие координаты floating-элемента.
  • strategy — стратегия позиционирования (absolute или fixed).
  • placement — текущая выбранная позиция (top, bottom, left, right и их варианты с -start/-end).
  • middlewareData — объект для хранения данных между middleware.

Каждая middleware-функция возвращает объект с потенциальными изменениями:

{
  x: number, // новая координата по оси X
  y: number, // новая координата по оси Y
  data: any  // дополнительные данные
}

Встроенные middleware

Floating UI предоставляет ряд готовых middleware для решения распространённых задач:

1. offset

Добавляет смещение между якорем и floating-элементом. Используется для создания отступов, чтобы элемент не прилипал к триггеру.

import { offset } from '@floating-ui/dom';

const middleware = [offset(10)]; // смещение 10px

Параметры offset могут быть числами или функциями, возвращающими массив [mainAxis, crossAxis].


2. flip

Автоматически меняет сторону появления floating-элемента, если исходная позиция выходит за границы видимой области.

import { flip } from '@floating-ui/dom';

const middleware = [flip({ fallbackPlacements: ['top', 'right'] })];
  • fallbackPlacements — список альтернативных позиций, к которым можно «приклеиться».
  • Использует расчет размера элемента и viewport для выбора оптимальной стороны.

3. shift

Сдвигает floating-элемент по оси, чтобы он оставался полностью видимым.

import { shift } from '@floating-ui/dom';

const middleware = [shift({ padding: 8 })];
  • padding задаёт минимальное расстояние до краев видимой области.
  • Не меняет основное направление (например, top остаётся top), а лишь корректирует координаты.

4. size

Позволяет динамически изменять размеры floating-элемента на основе доступного пространства.

import { size } from '@floating-ui/dom';

const middleware = [size({
  apply({ availableWidth, availableHeight, elements }) {
    Object.assign(elements.floating.style, {
      maxWidth: `${availableWidth}px`,
      maxHeight: `${availableHeight}px`
    });
  }
})];
  • availableWidth и availableHeight рассчитываются исходя из позиции и ограничений viewport.
  • Полезно для dropdown и tooltip, которые должны адаптироваться к окну.

Создание пользовательских middleware

Middleware можно создавать самостоятельно, если требуется особая логика позиционирования:

function myMiddleware(options) {
  return {
    name: 'myMiddleware',
    fn({ x, y, placement, elements }) {
      // Пример: сдвигаем floating элемент на 20px вправо
      return { x: x + 20, y };
    }
  };
}
  • name обязателен, используется для дебага и идентификации.
  • Функция fn получает текущее состояние и возвращает изменения.
  • Можно использовать data для передачи информации следующей middleware.

Порядок применения middleware

Порядок подключения middleware критически важен:

  1. Сначала устанавливаются смещения (offset).
  2. Затем проверка видимости и корректировка позиции (flip, shift).
  3. В конце — изменение размеров или кастомные манипуляции (size, кастомные middleware).

Нарушение порядка может привести к неправильному позиционированию, например, элемент может «выпасть» за границы экрана или не учесть смещение.


Практические рекомендации

  • Использовать несколько middleware одновременно для комплексной настройки: [offset(8), flip(), shift(), size()].
  • Минимизировать вычисления в кастомных middleware для производительности.
  • Хранить промежуточные данные в middlewareData для повторного использования.
  • Тестировать на разных разрешениях и с различными размерами floating-элемента.

Floating UI с middleware предоставляет гибкую и расширяемую архитектуру для позиционирования элементов. Понимание работы цепочек middleware позволяет создавать сложные, динамичные интерфейсы без необходимости вручную управлять координатами и проверками видимости.