{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "interactive-item-list",
  "title": "Interactive item list",
  "description": "A virtualized listbox interaction primitive for preview, selection, keyboard navigation, and visible-item reporting.",
  "registryDependencies": [
    "@retab/scroll-area",
    "@retab/utils",
    "@retab/effect-key",
    "@retab/use-keyed-layout-effect"
  ],
  "files": [
    {
      "path": "registry/new-york-v4/ui/interactive-item-list.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { useMeasuredRowVirtualization } from \"./measured-row-virtualization\";\n\nexport type InteractiveItemListItem = {\n  id: string;\n  disabled?: boolean;\n};\n\nexport type InteractiveItemListRenderState = {\n  isActive: boolean;\n  isDisabled: boolean;\n  isSelected: boolean;\n};\n\nconst DEFAULT_ESTIMATE_SIZE = 72;\nconst ROW_PADDING = 12;\n\nfunction requestFrame(callback: () => void) {\n  if (typeof window !== \"undefined\" && window.requestAnimationFrame) {\n    window.requestAnimationFrame(callback);\n    return;\n  }\n  setTimeout(callback, 0);\n}\n\nexport function InteractiveItemList<Item extends InteractiveItemListItem>({\n  activeItemId,\n  \"aria-label\": ariaLabel,\n  className,\n  emptyLabel = \"No items.\",\n  estimateSize = DEFAULT_ESTIMATE_SIZE,\n  items,\n  onActivateItem,\n  onClearPreview,\n  onClearSelection,\n  onPreviewItem,\n  onVisibleItemChange,\n  renderItem,\n  selectedItemId,\n}: {\n  activeItemId?: string | null;\n  \"aria-label\": string;\n  className?: string;\n  emptyLabel?: string;\n  estimateSize?: number;\n  items: readonly Item[];\n  onActivateItem?: (item: Item) => void;\n  onClearPreview?: () => void;\n  onClearSelection?: () => void;\n  onPreviewItem?: (item: Item) => void;\n  onVisibleItemChange?: (item: Item) => void;\n  renderItem: (\n    item: Item,\n    state: InteractiveItemListRenderState,\n  ) => React.ReactNode;\n  selectedItemId?: string | null;\n}) {\n  const viewportRef = React.useRef<HTMLDivElement | null>(null);\n  const optionRefs = React.useRef(new Map<string, HTMLButtonElement>());\n  const visibleItemIdRef = React.useRef<string | null>(null);\n  const getItemKey = React.useCallback(\n    (index: number) => items[index]?.id ?? index,\n    [items],\n  );\n  const { measureRow, scrollToIndex, totalSize, virtualRows } =\n    useMeasuredRowVirtualization({\n      count: items.length,\n      estimateSize,\n      getItemKey,\n      initialViewportHeight: 600,\n      overscan: 8,\n      paddingEnd: ROW_PADDING,\n      paddingStart: ROW_PADDING,\n      scrollRef: viewportRef,\n    });\n\n  const firstEnabledIndex = React.useCallback(\n    () => items.findIndex((item) => !item.disabled),\n    [items],\n  );\n\n  const lastEnabledIndex = React.useCallback(() => {\n    for (let index = items.length - 1; index >= 0; index -= 1) {\n      if (!items[index]?.disabled) return index;\n    }\n    return -1;\n  }, [items]);\n\n  const enabledIndexFrom = React.useCallback(\n    (startIndex: number, direction: 1 | -1) => {\n      for (\n        let index = startIndex;\n        index >= 0 && index < items.length;\n        index += direction\n      ) {\n        if (!items[index]?.disabled) return index;\n      }\n      return -1;\n    },\n    [items],\n  );\n\n  const focusItem = React.useCallback(\n    (index: number) => {\n      const item = items[index];\n      if (!item || item.disabled) return;\n      scrollToIndex(index, { align: \"center\", behavior: \"auto\" });\n      requestFrame(() => {\n        optionRefs.current.get(item.id)?.focus();\n      });\n    },\n    [items, scrollToIndex],\n  );\n\n  const reportVisibleItem = React.useCallback(() => {\n    if (!onVisibleItemChange) return;\n    const viewport = viewportRef.current;\n    if (!viewport) return;\n\n    const marker = viewport.scrollTop + ROW_PADDING;\n    const virtualItem =\n      virtualRows.find((row) => row.start + row.size >= marker) ??\n      virtualRows[0];\n    const fallbackIndex = Math.min(\n      items.length - 1,\n      Math.max(0, Math.floor(marker / estimateSize)),\n    );\n    const item = virtualItem ? items[virtualItem.index] : items[fallbackIndex];\n    if (!item || item.disabled || item.id === visibleItemIdRef.current) return;\n\n    visibleItemIdRef.current = item.id;\n    onVisibleItemChange(item);\n  }, [estimateSize, items, onVisibleItemChange, virtualRows]);\n\n  const handleViewportScroll = React.useCallback(() => {\n    requestFrame(reportVisibleItem);\n  }, [reportVisibleItem]);\n\n  return (\n    <ScrollArea\n      className={cn(\"min-h-0 flex-1\", className)}\n      scrollFade\n      viewportProps={{ onScroll: handleViewportScroll }}\n      viewportRef={viewportRef}\n    >\n      {items.length ? (\n        <div\n          role=\"listbox\"\n          aria-label={ariaLabel}\n          className=\"relative\"\n          style={{ height: totalSize }}\n        >\n          {virtualRows.map((virtualRow) => {\n            const item = items[virtualRow.index];\n            if (!item) return null;\n\n            const isActive = item.id === activeItemId;\n            const isDisabled = Boolean(item.disabled);\n            const isSelected = item.id === selectedItemId;\n\n            return (\n              <div\n                key={virtualRow.key}\n                ref={(element) => measureRow(virtualRow.index, element)}\n                data-index={virtualRow.index}\n                className=\"absolute top-0 right-3 left-3 pb-2 [contain:layout_paint]\"\n                style={{\n                  transform: `translateY(${virtualRow.start}px)`,\n                }}\n              >\n                <button\n                  ref={(element) => {\n                    if (element) {\n                      optionRefs.current.set(item.id, element);\n                    } else {\n                      optionRefs.current.delete(item.id);\n                    }\n                  }}\n                  type=\"button\"\n                  role=\"option\"\n                  aria-disabled={isDisabled || undefined}\n                  aria-selected={isSelected}\n                  data-active={isActive ? \"true\" : \"false\"}\n                  data-disabled={isDisabled ? \"true\" : \"false\"}\n                  data-selected={isSelected ? \"true\" : \"false\"}\n                  disabled={isDisabled}\n                  className=\"block w-full text-left outline-none disabled:cursor-not-allowed disabled:opacity-60\"\n                  onBlur={() => onClearPreview?.()}\n                  onClick={() => {\n                    if (!isDisabled) onActivateItem?.(item);\n                  }}\n                  onFocus={() => {\n                    if (!isDisabled) onPreviewItem?.(item);\n                  }}\n                  onKeyDown={(event) => {\n                    if (event.key === \"ArrowDown\") {\n                      event.preventDefault();\n                      focusItem(enabledIndexFrom(virtualRow.index + 1, 1));\n                      return;\n                    }\n                    if (event.key === \"ArrowUp\") {\n                      event.preventDefault();\n                      focusItem(enabledIndexFrom(virtualRow.index - 1, -1));\n                      return;\n                    }\n                    if (event.key === \"Home\") {\n                      event.preventDefault();\n                      focusItem(firstEnabledIndex());\n                      return;\n                    }\n                    if (event.key === \"End\") {\n                      event.preventDefault();\n                      focusItem(lastEnabledIndex());\n                      return;\n                    }\n                    if (event.key === \"Escape\") {\n                      event.preventDefault();\n                      onClearPreview?.();\n                      onClearSelection?.();\n                      return;\n                    }\n                    if (event.key === \"Enter\" || event.key === \" \") {\n                      event.preventDefault();\n                      if (!isDisabled) onActivateItem?.(item);\n                    }\n                  }}\n                  onMouseEnter={() => {\n                    if (!isDisabled) onPreviewItem?.(item);\n                  }}\n                  onMouseLeave={() => onClearPreview?.()}\n                >\n                  {renderItem(item, { isActive, isDisabled, isSelected })}\n                </button>\n              </div>\n            );\n          })}\n        </div>\n      ) : (\n        <div className=\"p-3\">\n          <div className=\"bg-muted/30 text-muted-foreground rounded-lg border p-3 text-sm\">\n            {emptyLabel}\n          </div>\n        </div>\n      )}\n    </ScrollArea>\n  );\n}\n",
      "type": "registry:ui",
      "target": "@ui/interactive-item-list.tsx"
    },
    {
      "path": "registry/new-york-v4/ui/measured-row-virtualization.ts",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { useKeyedLayoutEffect } from \"@/hooks/use-keyed-layout-effect\";\nimport { joinEffectKey } from \"@/lib/effect-key\";\n\nconst DEFAULT_INITIAL_VIEWPORT_HEIGHT = 600;\nconst DEFAULT_OVERSCAN = 6;\nconst MAX_VIRTUAL_ITEMS = 1_000;\n\nexport interface MeasuredRowVirtualItem {\n  index: number;\n  key: React.Key;\n  start: number;\n  size: number;\n  end: number;\n}\n\nexport interface MeasuredRowVirtualItemWindow {\n  end: number;\n  items: MeasuredRowVirtualItem[];\n  size: number;\n  start: number;\n}\n\nexport interface MeasuredRowOffsets {\n  starts: number[];\n  totalSize: number;\n}\n\nexport interface MeasuredRowScrollTarget {\n  align?: \"start\" | \"center\" | \"end\";\n  behavior?: ScrollBehavior;\n}\n\nexport function buildMeasuredRowOffsets({\n  rowSizes,\n  paddingStart = 0,\n  paddingEnd = 0,\n}: {\n  rowSizes: readonly number[];\n  paddingStart?: number;\n  paddingEnd?: number;\n}): MeasuredRowOffsets {\n  const starts: number[] = [];\n  let offset = safeSize(paddingStart);\n\n  for (const rowSize of rowSizes) {\n    starts.push(offset);\n    offset += safeSize(rowSize);\n  }\n\n  return {\n    starts,\n    totalSize: offset + safeSize(paddingEnd),\n  };\n}\n\nexport function getMeasuredRowVirtualItems({\n  getItemKey,\n  maxItems = MAX_VIRTUAL_ITEMS,\n  offsets,\n  overscan = DEFAULT_OVERSCAN,\n  rowSizes,\n  scrollTop,\n  viewportHeight,\n}: {\n  getItemKey?: (index: number) => React.Key;\n  maxItems?: number;\n  offsets: MeasuredRowOffsets;\n  overscan?: number;\n  rowSizes: readonly number[];\n  scrollTop: number;\n  viewportHeight: number;\n}): MeasuredRowVirtualItem[] {\n  const count = rowSizes.length;\n  if (count === 0) return [];\n\n  const safeScrollTop = safeOffset(scrollTop);\n  const safeViewportHeight = Math.max(1, safeSize(viewportHeight));\n  const visibleStartIndex = findFirstRowEndingAfter({\n    offset: safeScrollTop,\n    rowSizes,\n    starts: offsets.starts,\n  });\n  const visibleEndExclusive = findFirstRowStartingAtOrAfter({\n    offset: safeScrollTop + safeViewportHeight,\n    starts: offsets.starts,\n  });\n  const start = Math.max(0, visibleStartIndex - safeCount(overscan));\n  const end = Math.min(\n    count,\n    Math.max(visibleStartIndex + 1, visibleEndExclusive) + safeCount(overscan),\n  );\n  const [cappedStart, cappedEnd] = capMeasuredRowRange({\n    count,\n    end,\n    maxItems,\n    start,\n    visibleEnd: Math.min(\n      count,\n      Math.max(visibleStartIndex + 1, visibleEndExclusive),\n    ),\n    visibleStart: visibleStartIndex,\n  });\n\n  return Array.from({ length: cappedEnd - cappedStart }, (_, offset) => {\n    const index = cappedStart + offset;\n    const rowStart = offsets.starts[index] ?? 0;\n    const size = safeSize(rowSizes[index]);\n    return {\n      index,\n      key: getItemKey?.(index) ?? index,\n      start: rowStart,\n      size,\n      end: rowStart + size,\n    };\n  });\n}\n\nexport function measuredRowVirtualItemWindow(\n  items: readonly MeasuredRowVirtualItem[],\n): MeasuredRowVirtualItemWindow {\n  const start = items[0]?.start ?? 0;\n  const end = items.length ? items[items.length - 1]!.end : start;\n\n  return {\n    end,\n    items: items.map((item) => ({\n      ...item,\n      start: item.start - start,\n      end: item.end - start,\n    })),\n    size: Math.max(0, end - start),\n    start,\n  };\n}\n\nexport function measuredRowScrollTopForIndex({\n  align = \"center\",\n  index,\n  offsets,\n  rowSizes,\n  viewportHeight,\n}: {\n  align?: NonNullable<MeasuredRowScrollTarget[\"align\"]>;\n  index: number;\n  offsets: MeasuredRowOffsets;\n  rowSizes: readonly number[];\n  viewportHeight: number;\n}) {\n  if (!Number.isSafeInteger(index) || index < 0) return 0;\n\n  const rowStart = offsets.starts[index];\n  if (rowStart == null) return 0;\n\n  const rowSize = safeSize(rowSizes[index]);\n  const safeViewportHeight = safeSize(viewportHeight);\n\n  if (align === \"end\")\n    return Math.max(0, rowStart - safeViewportHeight + rowSize);\n  if (align === \"center\") {\n    return Math.max(0, rowStart - safeViewportHeight / 2 + rowSize / 2);\n  }\n  return Math.max(0, rowStart);\n}\n\nexport function useMeasuredRowVirtualization({\n  count,\n  estimateSize,\n  getItemKey,\n  initialViewportHeight = DEFAULT_INITIAL_VIEWPORT_HEIGHT,\n  overscan = DEFAULT_OVERSCAN,\n  paddingEnd = 0,\n  paddingStart = 0,\n  scrollRef,\n}: {\n  count: number;\n  estimateSize: number;\n  getItemKey?: (index: number) => React.Key;\n  initialViewportHeight?: number;\n  overscan?: number;\n  paddingEnd?: number;\n  paddingStart?: number;\n  scrollRef: React.RefObject<HTMLElement | null>;\n}) {\n  const safeCount = measuredRowCount(count);\n  const safeEstimateSize = Math.max(1, safeSize(estimateSize));\n  const [version, forceVersion] = React.useReducer(\n    (current: number) => current + 1,\n    0,\n  );\n  const [scrollElement, setScrollElement] = React.useState<HTMLElement | null>(\n    scrollRef.current,\n  );\n  const [viewport, setViewport] = React.useState({\n    clientHeight: 0,\n    scrollTop: 0,\n  });\n  const measuredSizesRef = React.useRef(new Map<number, number>());\n  const rowElementsRef = React.useRef(new Map<number, HTMLElement>());\n  const observedIndexesRef = React.useRef(new Map<HTMLElement, number>());\n  const rowObserverRef = React.useRef<ResizeObserver | null>(null);\n  const offsetsRef = React.useRef<MeasuredRowOffsets>({\n    starts: [],\n    totalSize: 0,\n  });\n  const rowSizesRef = React.useRef<number[]>([]);\n  const viewportRef = React.useRef(viewport);\n\n  viewportRef.current = viewport;\n\n  const updateMeasuredSize = React.useCallback(\n    (index: number, nextSize: number | null) => {\n      if (!Number.isSafeInteger(index) || index < 0 || index >= safeCount) {\n        return;\n      }\n      if (nextSize == null) return;\n\n      const safeNextSize = safeSize(nextSize);\n      if (safeNextSize <= 0) return;\n\n      const measuredSizes = measuredSizesRef.current;\n      const previousSize = measuredSizes.get(index) ?? safeEstimateSize;\n      if (previousSize === safeNextSize) return;\n\n      const previousOffsets = offsetsRef.current;\n      const previousStart = previousOffsets.starts[index] ?? 0;\n      const previousEnd = previousStart + previousSize;\n      const delta = safeNextSize - previousSize;\n      const currentScrollTop = viewportRef.current.scrollTop;\n\n      measuredSizes.set(index, safeNextSize);\n\n      const currentScrollElement = scrollRef.current;\n      if (\n        currentScrollElement &&\n        previousEnd <= currentScrollTop &&\n        delta !== 0\n      ) {\n        currentScrollElement.scrollTop = Math.max(\n          0,\n          currentScrollElement.scrollTop + delta,\n        );\n        setViewport((current) => ({\n          ...current,\n          scrollTop: safeOffset(currentScrollElement.scrollTop),\n        }));\n      }\n\n      forceVersion();\n    },\n    [safeCount, safeEstimateSize, scrollRef],\n  );\n\n  const measureRow = React.useCallback(\n    (index: number, element: HTMLElement | null) => {\n      if (!Number.isSafeInteger(index) || index < 0) return;\n\n      const rowElements = rowElementsRef.current;\n      const previousElement = rowElements.get(index);\n      if (previousElement && previousElement !== element) {\n        rowObserverRef.current?.unobserve(previousElement);\n        observedIndexesRef.current.delete(previousElement);\n        rowElements.delete(index);\n      }\n\n      if (!element) return;\n\n      rowElements.set(index, element);\n      observedIndexesRef.current.set(element, index);\n      rowObserverRef.current?.observe(element);\n      updateMeasuredSize(index, readElementHeight(element));\n    },\n    [updateMeasuredSize],\n  );\n\n  useKeyedLayoutEffect(\n    joinEffectKey([scrollRef, scrollRef.current, scrollElement]),\n    () => {\n      const nextScrollElement = scrollRef.current;\n      if (nextScrollElement !== scrollElement) {\n        setScrollElement(nextScrollElement);\n      }\n    },\n  );\n\n  useKeyedLayoutEffect(\n    joinEffectKey([scrollElement, updateMeasuredSize]),\n    () => {\n      if (typeof ResizeObserver === \"undefined\") return;\n\n      const observer = new ResizeObserver((entries) => {\n        for (const entry of entries) {\n          const index = observedIndexesRef.current.get(\n            entry.target as HTMLElement,\n          );\n          if (index == null) continue;\n          updateMeasuredSize(index, readResizeEntryHeight(entry));\n        }\n      });\n\n      rowObserverRef.current = observer;\n      for (const element of rowElementsRef.current.values()) {\n        observer.observe(element);\n      }\n\n      return () => {\n        observer.disconnect();\n        if (rowObserverRef.current === observer) rowObserverRef.current = null;\n      };\n    },\n  );\n\n  useKeyedLayoutEffect(\n    joinEffectKey([scrollElement, initialViewportHeight]),\n    () => {\n      if (!scrollElement) {\n        setViewport({ clientHeight: 0, scrollTop: 0 });\n        return;\n      }\n\n      let frame = 0;\n      const readViewport = () => {\n        frame = 0;\n        const next = {\n          clientHeight: safeSize(scrollElement.clientHeight),\n          scrollTop: safeOffset(scrollElement.scrollTop),\n        };\n        setViewport((current) =>\n          current.clientHeight === next.clientHeight &&\n          current.scrollTop === next.scrollTop\n            ? current\n            : next,\n        );\n      };\n      const scheduleRead = () => {\n        if (frame) return;\n        frame = requestFrame(readViewport);\n      };\n\n      readViewport();\n      scrollElement.addEventListener(\"scroll\", scheduleRead, { passive: true });\n      const observer =\n        typeof ResizeObserver !== \"undefined\"\n          ? new ResizeObserver(scheduleRead)\n          : null;\n      observer?.observe(scrollElement);\n\n      return () => {\n        if (frame) cancelFrame(frame);\n        scrollElement.removeEventListener(\"scroll\", scheduleRead);\n        observer?.disconnect();\n      };\n    },\n  );\n\n  const rowSizes = React.useMemo(\n    () => {\n      void version;\n      return Array.from(\n        { length: safeCount },\n        (_, index) => measuredSizesRef.current.get(index) ?? safeEstimateSize,\n      );\n    },\n    [safeCount, safeEstimateSize, version],\n  );\n  const offsets = React.useMemo(\n    () =>\n      buildMeasuredRowOffsets({\n        paddingEnd,\n        paddingStart,\n        rowSizes,\n      }),\n    [paddingEnd, paddingStart, rowSizes],\n  );\n  const viewportHeight =\n    viewport.clientHeight ||\n    safeSize(initialViewportHeight) ||\n    safeEstimateSize;\n  const virtualRows = React.useMemo(\n    () =>\n      getMeasuredRowVirtualItems({\n        getItemKey,\n        offsets,\n        overscan,\n        rowSizes,\n        scrollTop: viewport.scrollTop,\n        viewportHeight,\n      }),\n    [\n      getItemKey,\n      offsets,\n      overscan,\n      rowSizes,\n      viewport.scrollTop,\n      viewportHeight,\n    ],\n  );\n  const virtualRowWindow = React.useMemo(\n    () => measuredRowVirtualItemWindow(virtualRows),\n    [virtualRows],\n  );\n  const scrollToIndex = React.useCallback(\n    (index: number, options?: MeasuredRowScrollTarget) => {\n      const currentScrollElement = scrollRef.current;\n      if (!currentScrollElement) return;\n\n      const top = measuredRowScrollTopForIndex({\n        align: options?.align ?? \"center\",\n        index,\n        offsets: offsetsRef.current,\n        rowSizes: rowSizesRef.current,\n        viewportHeight: currentScrollElement.clientHeight || viewportHeight,\n      });\n      if (typeof currentScrollElement.scrollTo === \"function\") {\n        currentScrollElement.scrollTo({\n          behavior: options?.behavior ?? \"smooth\",\n          top,\n        });\n      } else {\n        currentScrollElement.scrollTop = top;\n      }\n      setViewport((current) => ({\n        ...current,\n        scrollTop: safeOffset(currentScrollElement.scrollTop),\n      }));\n    },\n    [scrollRef, viewportHeight],\n  );\n\n  offsetsRef.current = offsets;\n  rowSizesRef.current = rowSizes;\n\n  return {\n    measureRow,\n    scrollToIndex,\n    totalSize: offsets.totalSize,\n    viewportClientHeight: viewportHeight,\n    virtualRowWindow,\n    virtualRows,\n  };\n}\n\nfunction capMeasuredRowRange({\n  count,\n  end,\n  maxItems,\n  start,\n  visibleEnd,\n  visibleStart,\n}: {\n  count: number;\n  end: number;\n  maxItems: number;\n  start: number;\n  visibleEnd: number;\n  visibleStart: number;\n}) {\n  const safeMaxItems = Math.max(1, safeCount(maxItems));\n  if (end - start <= safeMaxItems) return [start, end] as const;\n\n  const visibleCount = Math.min(\n    safeMaxItems,\n    Math.max(1, visibleEnd - visibleStart),\n  );\n  const leadingBudget = Math.floor((safeMaxItems - visibleCount) / 2);\n  let cappedStart = Math.max(start, visibleStart - leadingBudget);\n  let cappedEnd = Math.min(end, cappedStart + safeMaxItems);\n\n  if (cappedEnd - cappedStart < safeMaxItems) {\n    cappedStart = Math.max(start, cappedEnd - safeMaxItems);\n  }\n  if (cappedEnd < visibleEnd) {\n    cappedEnd = Math.min(end, visibleEnd);\n    cappedStart = Math.max(start, cappedEnd - safeMaxItems);\n  }\n  cappedEnd = Math.min(count, cappedEnd);\n\n  return [cappedStart, cappedEnd] as const;\n}\n\nfunction findFirstRowEndingAfter({\n  offset,\n  rowSizes,\n  starts,\n}: {\n  offset: number;\n  rowSizes: readonly number[];\n  starts: readonly number[];\n}) {\n  let low = 0;\n  let high = rowSizes.length - 1;\n  let result = rowSizes.length - 1;\n\n  while (low <= high) {\n    const middle = Math.floor((low + high) / 2);\n    const end = (starts[middle] ?? 0) + safeSize(rowSizes[middle]);\n    if (end > offset) {\n      result = middle;\n      high = middle - 1;\n    } else {\n      low = middle + 1;\n    }\n  }\n\n  return result;\n}\n\nfunction findFirstRowStartingAtOrAfter({\n  offset,\n  starts,\n}: {\n  offset: number;\n  starts: readonly number[];\n}) {\n  let low = 0;\n  let high = starts.length - 1;\n  let result = starts.length;\n\n  while (low <= high) {\n    const middle = Math.floor((low + high) / 2);\n    if ((starts[middle] ?? 0) >= offset) {\n      result = middle;\n      high = middle - 1;\n    } else {\n      low = middle + 1;\n    }\n  }\n\n  return result;\n}\n\nfunction readElementHeight(element: HTMLElement) {\n  const rectHeight = element.getBoundingClientRect().height;\n  if (Number.isFinite(rectHeight) && rectHeight > 0) return rectHeight;\n  return element.offsetHeight;\n}\n\nfunction readResizeEntryHeight(entry: ResizeObserverEntry) {\n  const borderBoxSize = entry.borderBoxSize;\n  const boxSize = Array.isArray(borderBoxSize)\n    ? borderBoxSize[0]\n    : borderBoxSize;\n  if (boxSize && Number.isFinite(boxSize.blockSize) && boxSize.blockSize > 0) {\n    return boxSize.blockSize;\n  }\n  if (\n    Number.isFinite(entry.contentRect.height) &&\n    entry.contentRect.height > 0\n  ) {\n    return entry.contentRect.height;\n  }\n  return readElementHeight(entry.target as HTMLElement);\n}\n\nfunction requestFrame(callback: FrameRequestCallback) {\n  if (typeof window !== \"undefined\" && window.requestAnimationFrame) {\n    return window.requestAnimationFrame(callback);\n  }\n  return setTimeout(() => callback(performance.now()), 0) as unknown as number;\n}\n\nfunction cancelFrame(frame: number) {\n  if (typeof window !== \"undefined\" && window.cancelAnimationFrame) {\n    window.cancelAnimationFrame(frame);\n    return;\n  }\n  clearTimeout(frame);\n}\n\nfunction measuredRowCount(count: number) {\n  return Number.isFinite(count) && count > 0 ? Math.floor(count) : 0;\n}\n\nfunction safeCount(value: number) {\n  return Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;\n}\n\nfunction safeOffset(value: number) {\n  return Number.isFinite(value) && value > 0 ? value : 0;\n}\n\nfunction safeSize(value: number | undefined) {\n  return Number.isFinite(value) && value != null && value > 0 ? value : 0;\n}\n",
      "type": "registry:ui",
      "target": "@ui/measured-row-virtualization.ts"
    }
  ],
  "type": "registry:ui"
}