{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "clip-bounds",
  "title": "clipBounds",
  "description": "The box a portalled floating panel must stay inside: the viewport intersected with every scrollable (overflow auto/scroll) ancestor of its anchor.",
  "files": [
    {
      "path": "src/registry/lib/clip-bounds.ts",
      "content": "/** A box in viewport coordinates (the same space as `getBoundingClientRect()`). */\nexport interface ClipBounds {\n  top: number\n  right: number\n  bottom: number\n  left: number\n}\n\n/**\n * The box a floating panel anchored to `anchor` has to stay inside: the window,\n * intersected with every ancestor whose computed `overflow-x` or `overflow-y` is\n * `auto` or `scroll`.\n *\n * Only scroll containers count. They are a real viewport for the anchor — a\n * sidebar, a scrollable dialog body, a virtualised list — and a panel spilling\n * out of one floats over unrelated content while its anchor is half scrolled\n * away. `overflow: hidden | clip` ancestors are deliberately NOT boundaries: a\n * panel portalled to <body> has already escaped them, and clamping it into a\n * small decorative card would crush it instead. The walk stops below <body> /\n * <html>, whose overflow belongs to the page scroll the window already covers.\n *\n * Read it inside the positioning pass (a ResizeObserver / rAF callback), never\n * during render: it forces style and layout.\n */\nexport function clipBounds(anchor: HTMLElement): ClipBounds {\n  const bounds: ClipBounds = {\n    top: 0,\n    left: 0,\n    right: window.innerWidth,\n    bottom: window.innerHeight,\n  }\n\n  let node: HTMLElement | null = anchor.parentElement\n  while (node && node !== document.body && node !== document.documentElement) {\n    const style = getComputedStyle(node)\n    if (/auto|scroll/.test(`${style.overflowX} ${style.overflowY}`)) {\n      const rect = node.getBoundingClientRect()\n      bounds.top = Math.max(bounds.top, rect.top)\n      bounds.left = Math.max(bounds.left, rect.left)\n      bounds.right = Math.min(bounds.right, rect.right)\n      bounds.bottom = Math.min(bounds.bottom, rect.bottom)\n    }\n    node = node.parentElement\n  }\n\n  return bounds\n}\n",
      "type": "registry:lib"
    }
  ],
  "type": "registry:lib"
}