You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/arts/floating/middleware/offset.ts

64 lines
2.1 KiB

// 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<string>(['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 } }
}
}
}

Powered by TurnKey Linux.