"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"; import { attachLiquidGlassTabs, type LiquidGlassTabs, type LiquidGlassTabsOptions } from "./tabs"; const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect; /** Applies options to a glass whenever one of their values changes, after the first build. */ function useGlassOptions(glass: RefObject, options: LiquidGlassOptions) { // Options arrive as fresh objects each render; compare values instead. const key = JSON.stringify(options); const applied = useRef(key); useIsomorphicLayoutEffect(() => { if (applied.current === key) return; applied.current = key; glass.current?.update(JSON.parse(key) as LiquidGlassOptions); }, [glass, key]); return key; } 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() and dematerialize(). */ 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 key = useGlassOptions(glass, options); const initial = useRef(key); initial.current = key; useIsomorphicLayoutEffect(() => { const node = element.current; if (!node) return; const instance = attachLiquidGlass(node, JSON.parse(initial.current) as LiquidGlassOptions); glass.current = instance; if (glassRef) glassRef.current = instance; return () => { instance.destroy(); glass.current = null; if (glassRef) glassRef.current = null; }; }, [glassRef]); return (