"use client"; import * as React from "react"; import { cn } from "../../lib/utils"; import { ScrollFade } from "../primitives"; import { observeBrowserResize, subscribeBrowserWindowEvent, } from "../primitives/browser-transport"; import { sanitizeComposedHostProps, sanitizeInteractionHostProps, type SafeComposedHostElementProps, } from "../primitives/sanitize-composed-host-props"; 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"; const panelSurfaceClassName = "floating-popup-surface toolcraft-panel-surface isolate border text-[color:var(--popover-foreground)] supports-backdrop-filter:backdrop-blur-2xl supports-backdrop-filter:backdrop-saturate-150"; export const PanelSurface = React.forwardRef< HTMLDivElement, SafeComposedHostElementProps<"div"> >(function PanelSurface({ children, className, ...props }, ref) { return (
{children}
); }); export type PanelHoverSurfaceProps = SafeComposedHostElementProps<"div"> & Pick, "onPointerEnter" | "onPointerLeave">; export const PanelHoverSurface = React.forwardRef< HTMLDivElement, PanelHoverSurfaceProps >(function PanelHoverSurface({ children, className, ...props }, ref) { return (
{children}
); }); type PanelCollapsibleBodySurfaceProps = SafeComposedHostElementProps<"div"> & Pick, "onTransitionEnd">; export const PanelCollapsibleBodySurface = React.forwardRef< HTMLDivElement, PanelCollapsibleBodySurfaceProps >(function PanelCollapsibleBodySurface({ children, className, ...props }, ref) { return (
{children}
); }); export const PanelContentSurface = React.forwardRef< HTMLDivElement, SafeComposedHostElementProps<"div"> & { 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(); const unsubscribeResize = subscribeBrowserWindowEvent("resize", updateOverflow); const contentNode = viewportElement.firstElementChild; const unsubscribeResizeObserver = observeBrowserResize( contentNode ? [viewportElement, contentNode] : [viewportElement], updateOverflow, ); return () => { unsubscribeResize(); unsubscribeResizeObserver(); }; }, [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}
); }