"use client"; import * as React from "react"; import { ScrollFade } from "../primitives"; import { cn } from "../../lib/utils"; const panelDividerClassName = "border-t border-[color:color-mix(in_oklab,var(--border)_8%,transparent)]"; const panelContentScrollFadeHeight = 44; const panelContentViewportClassName = "flex min-h-0 flex-col overflow-x-hidden overflow-y-auto overscroll-contain"; export const PanelSurface = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(function PanelSurface({ children, className, ...props }, ref) { return (
{children}
); }); export const PanelContentSurface = React.forwardRef< HTMLDivElement, React.HTMLAttributes & { scrollFadeMode?: "always" | "overflow"; stickyFooterActive?: boolean; stickyFooterProgress?: number | null; stickyFooter?: React.ReactNode; } >(function PanelContentSurface( { children, className, scrollFadeMode = "always", stickyFooter, stickyFooterActive = false, stickyFooterProgress = null, ...props }, ref, ) { const [viewportElement, setViewportElement] = React.useState(null); const [hasOverflow, setHasOverflow] = React.useState( scrollFadeMode === "always", ); const attachViewport = React.useCallback( (node: HTMLDivElement | null) => { setViewportElement(node); if (typeof ref === "function") { ref(node); return; } if (ref) { ref.current = node; } }, [ref], ); const hasStickyFooter = React.Children.count(stickyFooter) > 0; React.useLayoutEffect(() => { if (scrollFadeMode !== "overflow") { setHasOverflow(true); return; } if (!viewportElement) { setHasOverflow(false); return; } const updateOverflow = () => { setHasOverflow( viewportElement.scrollHeight > viewportElement.clientHeight + 1, ); }; updateOverflow(); window.addEventListener("resize", updateOverflow); const resizeObserver = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(updateOverflow); resizeObserver?.observe(viewportElement); const contentNode = viewportElement.firstElementChild; if (contentNode) { resizeObserver?.observe(contentNode); } return () => { window.removeEventListener("resize", updateOverflow); resizeObserver?.disconnect(); }; }, [scrollFadeMode, viewportElement]); if (scrollFadeMode === "overflow" && !hasOverflow) { const viewport = (
{children}
); return hasStickyFooter ? ( {viewport} ) : ( viewport ); } const viewport = ( {children} ); return hasStickyFooter ? ( {viewport} ) : ( viewport ); }); function PanelContentWithStickyFooter({ children, stickyFooter, stickyFooterActive, stickyFooterProgress, }: { children: React.ReactNode; stickyFooter: React.ReactNode; stickyFooterActive: boolean; stickyFooterProgress: number | null; }): React.JSX.Element { const stickyFooterStyle = typeof stickyFooterProgress === "number" ? ({ "--sticky-footer-progress": String(stickyFooterProgress), } as React.CSSProperties) : undefined; return (
{children}
{stickyFooter}
); }