"use client"; import { useEffect, useLayoutEffect, useRef, type CSSProperties, type ReactNode, type RefObject, } from "react"; import { attachLiquidGlass, createLiquidGlass, type LiquidGlass as LiquidGlassHandle, type LiquidGlassOptions, } from "./glass.js"; import { attachLiquidGlassHighlight, type LiquidGlassHighlight, type LiquidGlassHighlightOptions } from "./highlight.js"; import { attachLiquidGlassTabs, type LiquidGlassTabs, type LiquidGlassTabsOptions } from "./tabs.js"; const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect; /** * Applies options to a glass whenever one of their values changes, after the first * build. Returns the latest options, for that first build. */ function useGlassOptions(glass: RefObject, options: LiquidGlassOptions) { // Options arrive as fresh objects each render; compare values instead. A `shape` // function counts by its outline at the glass's size, which the glass reads itself. const latest = useRef(options); latest.current = options; const key = JSON.stringify(options, (name, value: unknown) => (name === "shape" && typeof value === "function" ? "function" : value)); const applied = useRef(key); useIsomorphicLayoutEffect(() => { if (applied.current === key) return; applied.current = key; glass.current?.update(latest.current); }, [glass, key]); return latest; } export type LiquidGlassProps = LiquidGlassOptions & { className?: string | undefined; style?: CSSProperties | undefined; /** Extra layers over the glass, such as a tint of your own. */ children?: ReactNode | undefined; /** Receives the glass, for materialize(), pourFrom() and the rest. */ glassRef?: { current: LiquidGlassHandle | null } | undefined; }; /** * Liquid Glass behind a surface's content. Render it first inside a positioned, * rounded element and paint nothing over it: no background, border, shadow or * backdrop-filter on the surface, and no opacity or filter on it or its ancestors * while the glass shows. * * ```tsx * * ``` */ export function LiquidGlass({ className, style, children, glassRef, ...options }: LiquidGlassProps) { const element = useRef(null); const glass = useRef(null); const latest = useGlassOptions(glass, options); useIsomorphicLayoutEffect(() => { const node = element.current; if (!node) return; const instance = attachLiquidGlass(node, latest.current); glass.current = instance; if (glassRef) glassRef.current = instance; return () => { instance.destroy(); glass.current = null; if (glassRef) glassRef.current = null; }; }, [glassRef]); return (