Arrow элемент

В библиотеке React Aria элемент Arrow используется для создания визуальной стрелки, которая обычно сопровождает компоненты всплывающих элементов: Tooltip, Popover, Menu и др. Он обеспечивает корректное позиционирование стрелки относительно целевого элемента, учитывая направление и смещения, которые задаются системой позиционирования из React Stately и React Aria.

Элемент Arrow не является самостоятельным компонентом UI. Он всегда зависит от контекста overlay — элемента, который появляется над основным контентом. Его задача — визуально связывать overlay с элементом-триггером.


Импорт и базовое использование

import { useOverlayPosition, useOverlayTriggerState } from '@react-stately/overlays';
import { Overlay, OverlayArrow } from '@react-aria/overlays';

Использование стрелки строится вокруг хука useOverlayPosition, который возвращает координаты для позиционирования overlay и стрелки.

const state = useOverlayTriggerState({});
const ref = useRef(null);
const overlayRef = useRef(null);

const { overlayProps, arrowProps } = useOverlayPosition({
  targetRef: ref,
  overlayRef: overlayRef,
  placement: 'bottom',
  offset: 10,
  isOpen: state.isOpen
});

return (
  <>
    <button ref={ref} onCl ick={state.toggle}>Открыть подсказку</button>
    {state.isOpen && (
      <Overlay {...overlayProps} ref={overlayRef}>
        <div>Содержимое подсказки</div>
        <OverlayArrow {...arrowProps} />
      </Overlay>
    )}
  </>
);

В этом примере:

  • targetRef — ссылка на элемент, относительно которого будет позиционироваться overlay.
  • overlayRef — ссылка на сам overlay.
  • placement — направление, в котором overlay появляется относительно target (top, bottom, left, right, с вариантами -start и -end).
  • offset — смещение overlay от target.
  • arrowProps — объект с координатами и стилями для корректного отображения стрелки.

Свойства и настройки стрелки

OverlayArrow принимает следующие ключевые параметры через arrowProps:

  • style — объект с inline-стилями для позиционирования стрелки (top, left, transform).
  • ref — ссылка на DOM-элемент стрелки.
  • placement — направление, в котором стрелка «смотрит» на target.
  • size — размер стрелки (обычно в пикселях, задается через CSS переменные или классы).

Пример кастомизации стрелки:

<OverlayArrow
  {...arrowProps}
  style={{
    ...arrowProps.style,
    width: '12px',
    height: '12px',
    backgroundColor: 'black',
    clipPath: 'polygon(50% 0%, 0% 100%, 100% 100%)'
  }}
/>
  • clipPath позволяет создать треугольную форму для стрелки.
  • Цвет и размер задаются через CSS свойства.
  • Все позиционные стили (top, left, transform) передаются из arrowProps, чтобы гарантировать правильное положение относительно overlay и target.

Совместная работа с overlay и trigger

Стрелка не имеет смысла без overlay, поэтому важно синхронизировать Arrow с состоянием overlay. Обычно это делается через React Stately:

const state = useOverlayTriggerState({ defaultOpen: false });
const triggerRef = useRef(null);
const overlayRef = useRef(null);

const { overlayProps, arrowProps } = useOverlayPosition({
  targetRef: triggerRef,
  overlayRef: overlayRef,
  placement: 'top-start',
  isOpen: state.isOpen
});

return (
  <>
    <button ref={triggerRef} onCl ick={state.toggle}>Кнопка</button>
    {state.isOpen && (
      <Overlay ref={overlayRef} {...overlayProps}>
        <div>Содержимое overlay</div>
        <OverlayArrow {...arrowProps} />
      </Overlay>
    )}
  </>
);
  • placement: 'top-start' указывает, что overlay появится над кнопкой с выравниванием по левому краю.
  • Стрелка автоматически выравнивается по этому же направлению.

Динамическая подгонка позиции стрелки

React Aria учитывает размеры overlay и target, чтобы стрелка не выходила за границы. Хук useOverlayPosition возвращает координаты arrowProps.left и arrowProps.top, которые динамически меняются при изменении размеров окна или overlay:

window.addEventListener('resize', () => {
  // React Aria автоматически пересчитывает позиции
});

Это избавляет от необходимости вручную отслеживать положение стрелки при изменении размеров экрана или элемента.


Настройка размеров и стилей через CSS

Для сложных дизайнов удобно использовать CSS-классы:

.arrow {
  width: 16px;
  height: 16px;
  background-color: #333;
  clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}

И применить класс к компоненту:

<OverlayArrow {...arrowProps} className="arrow" />

Стили могут меняться в зависимости от направления стрелки, используя модификаторы для placement (arrow-top, arrow-bottom и т.д.).


Поддержка анимаций

Стрелка легко интегрируется с анимациями overlay, например, плавное появление при открытии:

<OverlayArrow
  {...arrowProps}
  style={{
    ...arrowProps.style,
    transition: 'transform 0.2s ease, opacity 0.2s ease',
    opacity: state.isOpen ? 1 : 0
  }}
/>
  • transition позволяет анимировать перемещение и появление стрелки.
  • Использование opacity обеспечивает плавное исчезновение при закрытии overlay.

Важные рекомендации

  • Не использовать Arrow без overlay. Он рассчитан на позиционирование относительно overlay.
  • Передавать все arrowProps в компонент. Любые ручные изменения координат могут нарушить синхронизацию.
  • Использовать clip-path или SVG для кастомной формы. Стандартная стрелка — треугольник, но дизайн может требовать другие формы.
  • Поддержка разных направлений. React Aria автоматически поворачивает стрелку, если меняется placement.

Элемент Arrow в React Aria обеспечивает гибкое, корректное и адаптивное позиционирование визуальной связи между overlay и trigger. Он полностью интегрирован с системой overlay и React Stately, что позволяет создавать сложные интерфейсы с подсказками, меню и popover без ручного расчета координат.