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/uix/soma/layers/floating/engine/overflow.ts

64 lines
2.6 KiB

// detectOverflow — PURE. Compares the proposed element rect against the clipping
// region that the read phase already walked (`state.clipping`, viewport coords).
// No DOM read: the offsetParent→viewport conversion is folded into
// `state.viewportDelta` + `state.offsetScale` upfront. Reimplemented from
// floating-ui's `detectOverflow` (spec), our idioms.
import { getPaddingObject } from './geometry'
import { rectToClientRect } from './rects'
import type { MiddlewareState, Padding, SideObject } from './types'
export type DetectOverflowOptions = {
padding?: Padding
/** Which element's rect to test — `'floating'` at `state.x/y`, or the
* reference rect. @default 'floating' */
elementContext?: 'floating' | 'reference'
/** Test against the OTHER element's clipping region (swaps the boundary
* source). @default false */
altBoundary?: boolean
}
/**
* Per-side overflow of the tested element past its clipping boundary, in CSS px:
* positive = overflowing by that many pixels, negative = pixels of slack before
* it would overflow, 0 = flush.
*/
export function detectOverflow(
state: MiddlewareState,
options: DetectOverflowOptions = {}
): SideObject {
const { padding = 0, elementContext = 'floating', altBoundary = false } = options
const { x, y, rects, clipping, viewportDelta, offsetScale } = state
const paddingObject = getPaddingObject(padding)
const altContext = elementContext === 'floating' ? 'reference' : 'floating'
const context = altBoundary ? altContext : elementContext
// `clipping.reference` is only read when needed; fall back to the floating
// clip (identical when the boundary is explicit — the soma layer's only case).
const clip = clipping[context] ?? clipping.floating
const clippingClientRect = rectToClientRect(clip)
// The tested element's rect in offsetParent-relative coords…
const elementRect =
elementContext === 'floating'
? { x, y, width: rects.floating.width, height: rects.floating.height }
: rects.reference
// …converted to viewport coords purely via the precomputed delta.
const elementClientRect = rectToClientRect({
x: elementRect.x + viewportDelta.x,
y: elementRect.y + viewportDelta.y,
width: elementRect.width,
height: elementRect.height
})
return {
top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
bottom:
(elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
right:
(elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
}
}

Powered by TurnKey Linux.