{"version":3,"file":"VirtualScrollArea.mjs","names":[],"sources":["../../../src/base-ui/virtual/VirtualScrollArea.tsx"],"sourcesContent":["'use client';\n\nimport { createStaticStyles, cx } from 'antd-style';\nimport {\n  Children,\n  cloneElement,\n  type ReactElement,\n  type ReactNode,\n  type Ref,\n  useCallback,\n  useEffect,\n  useRef,\n} from 'react';\nimport { useMergeRefs } from 'react-merge-refs';\nimport { Virtualizer, type VirtualizerHandle } from 'virtua';\n\nimport {\n  ScrollAreaRoot,\n  type ScrollAreaRootProps,\n  ScrollAreaScrollbar,\n  ScrollAreaThumb,\n  ScrollAreaViewport,\n  type ScrollAreaViewportProps,\n} from '@/base-ui/ScrollArea/atoms';\n\n// `--lobe-virtual-scroll-inset` is the inline padding of the box the scroll area sits in: the\n// root bleeds out by it so the scrollbar hugs that box's edge, and the viewport pads the rows back.\nconst styles = createStaticStyles(({ css }) => ({\n  root: css`\n    display: flex;\n    flex: 1;\n    flex-direction: column;\n\n    min-height: 0;\n    margin-inline: calc(-1 * var(--lobe-virtual-scroll-inset, 0px));\n  `,\n  viewport: css`\n    flex: 1;\n    height: auto;\n    min-height: 0;\n    padding-inline: var(--lobe-virtual-scroll-inset, 0);\n  `,\n}));\n\n// Rows mounted on the very first render, before the viewport is measured, so Base UI's\n// list navigation sees the leading rows (not a pinned footer item) when it focuses on open.\nconst INITIAL_ROW_COUNT = 20;\n\nexport interface VirtualScrollAreaProps extends Omit<ScrollAreaRootProps, 'children'> {\n  children: ReactNode;\n  itemSize?: number;\n  keepMounted?: readonly number[];\n  /**\n   * Element that owns the scrolling box (e.g. a Base UI `Select.List`); it is rendered\n   * through the ScrollArea viewport so its own props and role win.\n   */\n  viewport?: ReactElement<{ children?: ReactNode; render?: ReactElement }>;\n  viewportProps?: ScrollAreaViewportProps;\n  virtualizerRef?: Ref<VirtualizerHandle>;\n}\n\nexport const VirtualScrollArea = ({\n  children,\n  className,\n  itemSize,\n  keepMounted,\n  viewport,\n  viewportProps,\n  virtualizerRef,\n  ...rest\n}: VirtualScrollAreaProps) => {\n  const viewportRef = useRef<HTMLDivElement | null>(null);\n  const mergedViewportRef = useMergeRefs([viewportRef, viewportProps?.ref]);\n\n  const list = (\n    <Virtualizer\n      itemSize={itemSize}\n      keepMounted={keepMounted}\n      ref={virtualizerRef}\n      scrollRef={viewportRef}\n      ssrCount={Math.min(INITIAL_ROW_COUNT, Children.count(children))}\n    >\n      {children}\n    </Virtualizer>\n  );\n  const viewportElement = (\n    <ScrollAreaViewport\n      tabIndex={-1}\n      {...viewportProps}\n      className={cx(styles.viewport, viewportProps?.className as string)}\n      ref={mergedViewportRef}\n    />\n  );\n\n  return (\n    <ScrollAreaRoot data-virtual=\"\" {...rest} className={cx(styles.root, className as string)}>\n      {cloneElement(viewport ?? viewportElement, {\n        children: list,\n        ...(viewport && { render: viewportElement }),\n      })}\n      <ScrollAreaScrollbar>\n        <ScrollAreaThumb />\n      </ScrollAreaScrollbar>\n    </ScrollAreaRoot>\n  );\n};\n\nVirtualScrollArea.displayName = 'VirtualScrollArea';\n\n// Base UI scrolls the highlighted item into view after focusing it; while the pointer drives\n// the scroll that would yank the list back, so callers consult `pointerScrollRef` first.\nexport function usePointerScrollGuard() {\n  const pointerScrollRef = useRef(false);\n  const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n  const markPointerScroll = useCallback(() => {\n    pointerScrollRef.current = true;\n    if (timeoutRef.current) clearTimeout(timeoutRef.current);\n    timeoutRef.current = setTimeout(() => {\n      pointerScrollRef.current = false;\n    }, 120);\n  }, []);\n\n  useEffect(() => {\n    return () => {\n      if (timeoutRef.current) clearTimeout(timeoutRef.current);\n    };\n  }, []);\n\n  return {\n    markPointerScroll,\n    pointerScrollRef,\n    scrollGuardProps: {\n      onPointerDown: markPointerScroll,\n      onTouchMove: markPointerScroll,\n      onWheel: markPointerScroll,\n    },\n  };\n}\n"],"mappings":";;;;;;;;AA2BA,MAAM,SAAS,oBAAoB,EAAE,WAAW;CAC9C,MAAM,GAAG;;;;;;;;CAQT,UAAU,GAAG;;;;;;AAMf,EAAE;AAIF,MAAM,oBAAoB;AAe1B,MAAa,qBAAqB,EAChC,UACA,WACA,UACA,aACA,UACA,eACA,gBACA,GAAG,WACyB;CAC5B,MAAM,cAAc,OAA8B,IAAI;CACtD,MAAM,oBAAoB,aAAa,CAAC,aAAa,eAAe,GAAG,CAAC;CAExE,MAAM,OACJ,oBAAC,aAAD;EACY;EACG;EACb,KAAK;EACL,WAAW;EACX,UAAU,KAAK,IAAI,mBAAmB,SAAS,MAAM,QAAQ,CAAC;EAE7D;CACU,CAAA;CAEf,MAAM,kBACJ,oBAAC,oBAAD;EACE,UAAU;EACV,GAAI;EACJ,WAAW,GAAG,OAAO,UAAU,eAAe,SAAmB;EACjE,KAAK;CACN,CAAA;CAGH,OACE,qBAAC,gBAAD;EAAgB,gBAAa;EAAG,GAAI;EAAM,WAAW,GAAG,OAAO,MAAM,SAAmB;EAAxF,UAAA,CACG,aAAa,YAAY,iBAAiB;GACzC,UAAU;GACV,GAAI,YAAY,EAAE,QAAQ,gBAAgB;EAC5C,CAAC,GACD,oBAAC,qBAAD,EAAA,UACE,oBAAC,iBAAD,CAAkB,CAAA,EACC,CAAA,CACP;;AAEpB;AAEA,kBAAkB,cAAc;AAIhC,SAAgB,wBAAwB;CACtC,MAAM,mBAAmB,OAAO,KAAK;CACrC,MAAM,aAAa,OAA6C,IAAI;CAEpE,MAAM,oBAAoB,kBAAkB;EAC1C,iBAAiB,UAAU;EAC3B,IAAI,WAAW,SAAS,aAAa,WAAW,OAAO;EACvD,WAAW,UAAU,iBAAiB;GACpC,iBAAiB,UAAU;EAC7B,GAAG,GAAG;CACR,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,aAAa;GACX,IAAI,WAAW,SAAS,aAAa,WAAW,OAAO;EACzD;CACF,GAAG,CAAC,CAAC;CAEL,OAAO;EACL;EACA;EACA,kBAAkB;GAChB,eAAe;GACf,aAAa;GACb,SAAS;EACX;CACF;AACF"}