Переиспользование middleware

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

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

Структура middleware

Каждый middleware имеет стандартный интерфейс:

function middlewareFunction({ x, y, placement, rects, middlewareData }) {
  // Логика изменения координат или данных
  return {
    x: newX,
    y: newY,
    data: { custom: value }
  };
}

Ключевые параметры:

  • x, y – текущие координаты элемента.
  • placement – направление позиции относительно reference элемента.
  • rects – объект с размерами reference и floating элементов.
  • middlewareData – объект, содержащий данные, переданные другими middleware.

Возвращаемое значение может содержать новые координаты и дополнительные данные, которые будут переданы следующим middleware.

Принципы переиспользования

  1. Изоляция логики Middleware должны быть независимыми и не полагаться на конкретные значения внешних переменных. Это позволяет применять одну и ту же функцию в разных компонентах без изменений.
const shiftMiddleware = ({ x, y, rects }) => {
  const overflowX = rects.reference.right - rects.floating.right;
  return { x: x + overflowX, y };
};
  1. Возврат стандартного формата Чтобы middleware можно было комбинировать, каждая функция должна возвращать объект с полями x, y и data. Это обеспечивает совместимость с другими middleware и корректное накопление изменений.

  2. Использование параметров конфигурации Создание фабрики middleware позволяет настраивать поведение через параметры, сохраняя возможность переиспользования.

function createOffsetMiddleware(offset) {
  return ({ x, y, placement }) => {
    if (placement.startsWith('top')) return { x, y: y - offset };
    if (placement.startsWith('bottom')) return { x, y: y + offset };
    return { x: x + offset, y };
  };
}

const offset10 = createOffsetMiddleware(10);
  1. Комбинирование middleware Floating UI позволяет применять несколько middleware последовательно. Переиспользуемые middleware можно комбинировать с другими для создания сложного поведения позиционирования.
import { computePosition, offset, flip, shift } from '@floating-ui/dom';

computePosition(referenceElement, floatingElement, {
  middleware: [offset10, flip(), shift({ padding: 5 })],
});
  1. Передача данных между middleware Поле middlewareData позволяет middleware взаимодействовать друг с другом без жёсткой связи. Например, один middleware может вычислять смещение и передавать его следующему для дополнительной корректировки.
const logMiddleware = ({ x, y, middlewareData }) => {
  console.log('Current coords:', x, y);
  return { x, y, data: { logged: true } };
};

Практические примеры

  • Переиспользуемое смещение – часто требуется одинаковый отступ от границ reference элемента. Создание middleware с параметром offset позволяет использовать его в любых компонентах.

  • Умное изменение направления – middleware flip проверяет доступное пространство и изменяет направление позиции. Его можно комбинировать с кастомными middleware для более сложной логики.

  • Анимация и задержка – middleware может добавлять вычисляемые значения для анимации, например, передавать координаты предыдущего кадра для плавного смещения.

Рекомендации по организации

  • Выносить middleware в отдельные модули для повторного использования.
  • Стараться избегать побочных эффектов, чтобы middleware оставался чистым.
  • Использовать параметры конфигурации вместо жесткого кодирования значений.
  • Документировать назначение и входные/выходные данные каждого middleware.

Пример структуры проекта с переиспользуемыми middleware

/middleware
  offset.js
  flip.js
  shift.js
/components
  Tooltip.js
  Dropdown.js

Каждый компонент импортирует только необходимые middleware, комбинирует их и передает в computePosition. Это снижает дублирование кода и делает систему позиционирования модульной и масштабируемой.

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