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/size.ts

79 lines
2.9 KiB

// size — computes the width/height available to the floating element within the
// clipping boundary and hands it to `apply` (the consumer writes CSS vars).
// PURE. Our engine never re-reads DOM mid-loop: `apply` doesn't resize the
// floating element synchronously in the soma layer, so the floating-ui
// `reset: { rects: true }` round-trip is unnecessary (a real resize re-triggers
// via the autoUpdate ResizeObserver). Reimplemented from floating-ui's `size`.
import { getAlignment, getSide, getSideAxis } from '../geometry'
import { detectOverflow, type DetectOverflowOptions } from '../overflow'
import type { Middleware, MiddlewareState } from '../types'
export type SizeApplyArgs = MiddlewareState & {
availableWidth: number
availableHeight: number
}
export type SizeOptions = DetectOverflowOptions & {
apply?: (args: SizeApplyArgs) => void
}
const { min, max } = Math
export function size(options: SizeOptions = {}): Middleware {
const { apply = () => {}, ...detectOptions } = options
return {
name: 'size',
options,
fn(state) {
const { placement, rects, rtl, middlewareData } = state
const overflow = detectOverflow(state, detectOptions)
const side = getSide(placement)
const alignment = getAlignment(placement)
const isYAxis = getSideAxis(placement) === 'y'
const { width, height } = rects.floating
let heightSide: 'top' | 'bottom'
let widthSide: 'left' | 'right'
if (side === 'top' || side === 'bottom') {
heightSide = side
widthSide = alignment === (rtl ? 'start' : 'end') ? 'left' : 'right'
} else {
widthSide = side as 'left' | 'right'
heightSide = alignment === 'end' ? 'top' : 'bottom'
}
const maximumClippingHeight = height - overflow.top - overflow.bottom
const maximumClippingWidth = width - overflow.left - overflow.right
const overflowAvailableHeight = min(height - overflow[heightSide], maximumClippingHeight)
const overflowAvailableWidth = min(width - overflow[widthSide], maximumClippingWidth)
const shiftData = middlewareData.shift as
| { enabled?: { x?: boolean; y?: boolean } }
| undefined
const noShift = !shiftData
let availableHeight = overflowAvailableHeight
let availableWidth = overflowAvailableWidth
if (shiftData?.enabled?.x) availableWidth = maximumClippingWidth
if (shiftData?.enabled?.y) availableHeight = maximumClippingHeight
if (noShift && !alignment) {
const xMin = max(overflow.left, 0)
const xMax = max(overflow.right, 0)
const yMin = max(overflow.top, 0)
const yMax = max(overflow.bottom, 0)
if (isYAxis) {
availableWidth =
width - 2 * (xMin !== 0 || xMax !== 0 ? xMin + xMax : max(overflow.left, overflow.right))
} else {
availableHeight =
height - 2 * (yMin !== 0 || yMax !== 0 ? yMin + yMax : max(overflow.top, overflow.bottom))
}
}
apply({ ...state, availableWidth, availableHeight })
return {}
}
}
}

Powered by TurnKey Linux.