// offset — shifts the floating element along the main / cross / alignment axes. // PURE. Reimplemented from floating-ui's `offset` (spec). import type { Placement } from '../placement' import { getAlignment, getSide, getSideAxis } from '../geometry' import type { Coords, Middleware, MiddlewareState } from '../types' export type OffsetOptions = | number | { mainAxis?: number; crossAxis?: number; alignmentAxis?: number | null } const ORIGIN_SIDES = new Set(['left', 'top']) function convertValueToCoords(state: MiddlewareState, options: OffsetOptions): Coords { const { placement, rtl } = state const side = getSide(placement) const alignment = getAlignment(placement) const isVertical = getSideAxis(placement) === 'y' const mainAxisMulti = ORIGIN_SIDES.has(side) ? -1 : 1 const crossAxisMulti = rtl && isVertical ? -1 : 1 let mainAxis: number let crossAxis: number let alignmentAxis: number | null if (typeof options === 'number') { mainAxis = options crossAxis = 0 alignmentAxis = null } else { mainAxis = options.mainAxis || 0 crossAxis = options.crossAxis || 0 alignmentAxis = options.alignmentAxis ?? null } if (alignment && typeof alignmentAxis === 'number') { crossAxis = alignment === 'end' ? alignmentAxis * -1 : alignmentAxis } return isVertical ? { x: crossAxis * crossAxisMulti, y: mainAxis * mainAxisMulti } : { x: mainAxis * mainAxisMulti, y: crossAxis * crossAxisMulti } } export function offset(options: OffsetOptions = 0): Middleware { return { name: 'offset', options, fn(state) { const { x, y, placement, middlewareData } = state const diff = convertValueToCoords(state, options) // If the placement is unchanged and the arrow applied an alignment // offset, leave the coords alone (offset already ran for this placement). const offsetData = middlewareData.offset as { placement?: Placement } | undefined const arrowData = middlewareData.arrow as { alignmentOffset?: number } | undefined if (placement === offsetData?.placement && arrowData?.alignmentOffset) { return {} } return { x: x + diff.x, y: y + diff.y, data: { ...diff, placement } } } } }