"use client"; import { createContext, useContext, useSyncExternalStore, type ComponentProps, type CSSProperties, } from "react"; import { GlassMaterial } from "./_glass/GlassMaterial.js"; export type GlassShade = "frost" | "clear" | "deep"; export interface GlassAppearance { /** Change from React state to respond to your app's own context. */ shade?: GlassShade; /** Blur in CSS pixels; defaults to the selected shade. */ blur?: number; /** Edge displacement strength, 0–0.2. Chromium backdrop enhancement. */ refraction?: number; /** RGB edge dispersion, 0–1. */ dispersion?: number; } export const glassShades = { frost: { blur: 8, refraction: 0.055, dispersion: 0.13 }, clear: { blur: 1.5, refraction: 0.14, dispersion: 0.25 }, deep: { blur: 16, refraction: 0.035, dispersion: 0.08 }, } as const satisfies Record< GlassShade, Required> >; export const GlassContext = createContext<{ shade: GlassShade; group: boolean; control?: boolean; appearance?: GlassAppearance; }>({ shade: "frost", group: false }); const opaqueQuery = "(prefers-reduced-transparency: reduce), (forced-colors: active)"; function subscribe(listener: () => void) { const media = matchMedia(opaqueQuery); media.addEventListener("change", listener); return () => media.removeEventListener("change", listener); } const snapshot = () => matchMedia(opaqueQuery).matches; const serverSnapshot = () => true; const clamp = (value: number, min: number, max: number, fallback: number) => Number.isFinite(value) ? Math.max(min, Math.min(max, value)) : fallback; /** Internal noninteractive layer; its parent owns native semantics and layout. */ export function GlassLayer({ shade, blur, refraction, dispersion, flat = false, }: GlassAppearance & { flat?: boolean }) { const inherited = useContext(GlassContext); const selected = shade ?? inherited.shade; const preset = glassShades[selected]; const opaque = useSyncExternalStore(subscribe, snapshot, serverSnapshot); const optics = { frost: clamp(blur ?? preset.blur, 0, 24, preset.blur), strength: flat ? 0 : clamp(refraction ?? preset.refraction, 0, 0.2, preset.refraction), dispersion: clamp(dispersion ?? preset.dispersion, 0, 1, preset.dispersion), specular: 0.5, sheen: 0.25, glow: 0.03, mapSize: 256, }; return ( ); } export interface GlassSurfaceProps extends ComponentProps<"div">, GlassAppearance {} /** A content-sized glass surface. Large surfaces use frost rather than a stretched lens. */ export function GlassSurface({ shade, blur, refraction, dispersion, className = "", children, style, ...props }: GlassSurfaceProps) { return (
{children}
); }