UNPKG

simple-liquid-glass

Version:

A React component for creating liquid glass morphism effects with customizable distortion and blur

1 lines 49.4 kB
{"version":3,"file":"index.cjs","sources":["../src/index.tsx"],"sourcesContent":["import React, { useMemo, useEffect, useRef, useState, useId } from 'react';\r\n\r\ntype DisplacementChannel = 'R' | 'G' | 'B' | 'A';\r\n\r\ntype LiquidQuality = 'low' | 'standard' | 'high' | 'extreme';\r\n\r\nconst QUALITY_DIVISORS: Record<LiquidQuality, number> = {\r\n low: 5,\r\n standard: 3,\r\n high: 2.5,\r\n extreme: 2\r\n};\r\n\r\nconst QUALITY_QUANTIZATION_STEPS: Record<LiquidQuality, number> = {\r\n low: 32,\r\n standard: 24,\r\n high: 16,\r\n extreme: 8\r\n};\r\n\r\nconst DISPLACEMENT_CACHE: Map<string, string> = new Map();\r\n\r\nexport interface LiquidGlassProps extends React.HTMLAttributes<HTMLDivElement> {\r\n children?: React.ReactNode;\r\n mode?: string;\r\n scale?: number;\r\n radius?: number;\r\n border?: number;\r\n lightness?: number;\r\n displace?: number;\r\n alpha?: number;\r\n blur?: number;\r\n dispersion?: number;\r\n saturation?: number; // percent, 100 = normal\r\n aberrationIntensity?: number; // multiplier for chromatic separation\r\n frost?: number;\r\n borderColor?: string;\r\n glassColor?: string; // must be semi-transparent\r\n background?: string; // background color or gradient (CSS background value)\r\n autoTextColor?: boolean; // auto-detect background and set text color\r\n textOnDark?: string; // text color when background is dark\r\n textOnLight?: string; // text color when background is light\r\n forceTextColor?: boolean; // enforce text color on descendants\r\n quality?: LiquidQuality; // rendering quality preset\r\n autodetectquality?: boolean; // auto-detect device performance and pick quality\r\n className?: string;\r\n style?: React.CSSProperties;\r\n // iOS fallback controls\r\n iosMinBlur?: number; // minimum blur on iOS even when blur=0\r\n iosBlurMode?: 'auto' | 'off'; // allow opting out of the forced iOS blur\r\n mobileFallback?: 'css-only' | 'svg'; // control mobile rendering strategy\r\n effectMode?: 'auto' | 'svg' | 'blur' | 'off'; // choose filter strategy independently\r\n}\r\n\r\nfunction isSemiTransparentColor(input: string | undefined | null): boolean {\r\n if (!input) return false;\r\n const color = input.trim();\r\n // rgba(r,g,b,a)\r\n const rgba = /^rgba\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*(\\d*\\.?\\d+)\\s*\\)$/i.exec(color);\r\n if (rgba) {\r\n const a = parseFloat(rgba[1]);\r\n return a > 0 && a < 1;\r\n }\r\n // hsla(h,s,l,a)\r\n const hsla = /^hsla\\(.*?,\\s*(\\d*\\.?\\d+)\\s*\\)$/i.exec(color);\r\n if (hsla) {\r\n const a = parseFloat(hsla[1]);\r\n return a > 0 && a < 1;\r\n }\r\n // hsl(h s l / a) or hsl(h,s%,l%,a) with slash\r\n const hslSlash = /^hsl\\(.*?\\/\\s*(\\d*\\.?\\d+)\\s*\\)$/i.exec(color);\r\n if (hslSlash) {\r\n const a = parseFloat(hslSlash[1]);\r\n return a > 0 && a < 1;\r\n }\r\n // Hex with alpha: #RGBA or #RRGGBBAA\r\n const hex4 = /^#([0-9a-f]{4})$/i.exec(color);\r\n if (hex4) {\r\n const aHex = hex4[1].slice(3, 4);\r\n const a = parseInt(aHex + aHex, 16) / 255; // expand to 8-bit\r\n return a > 0 && a < 1;\r\n }\r\n const hex8 = /^#([0-9a-f]{8})$/i.exec(color);\r\n if (hex8) {\r\n const aHex = hex8[1].slice(6, 8);\r\n const a = parseInt(aHex, 16) / 255;\r\n return a > 0 && a < 1;\r\n }\r\n // No detectable alpha\r\n return false;\r\n}\r\n\r\nfunction addTransparencyToColor(color: string, alpha: number = 0.3): string {\r\n const trimmed = color.trim();\r\n \r\n // Handle hex colors\r\n const hex3 = /^#([0-9a-f]{3})$/i.exec(trimmed);\r\n if (hex3) {\r\n const r = parseInt(hex3[1][0] + hex3[1][0], 16);\r\n const g = parseInt(hex3[1][1] + hex3[1][1], 16);\r\n const b = parseInt(hex3[1][2] + hex3[1][2], 16);\r\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\r\n }\r\n \r\n const hex6 = /^#([0-9a-f]{6})$/i.exec(trimmed);\r\n if (hex6) {\r\n const r = parseInt(hex6[1].slice(0, 2), 16);\r\n const g = parseInt(hex6[1].slice(2, 4), 16);\r\n const b = parseInt(hex6[1].slice(4, 6), 16);\r\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\r\n }\r\n \r\n // Handle rgb colors\r\n const rgb = /^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i.exec(trimmed);\r\n if (rgb) {\r\n const r = parseInt(rgb[1], 10);\r\n const g = parseInt(rgb[2], 10);\r\n const b = parseInt(rgb[3], 10);\r\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\r\n }\r\n \r\n // Handle hsl colors\r\n const hsl = /^hsl\\(\\s*([^,]+)\\s*,\\s*([^,]+)\\s*,\\s*([^)]+)\\s*\\)$/i.exec(trimmed);\r\n if (hsl) {\r\n const h = hsl[1].trim();\r\n const s = hsl[2].trim();\r\n const l = hsl[3].trim();\r\n return `hsla(${h}, ${s}, ${l}, ${alpha})`;\r\n }\r\n \r\n // If we can't parse it, return as is\r\n return trimmed;\r\n}\r\n\r\nfunction addTransparencyToGradient(gradient: string, alpha: number = 0.3): string {\r\n // Handle linear-gradient, radial-gradient, conic-gradient, etc.\r\n const gradientMatch = /^(linear-gradient|radial-gradient|conic-gradient|repeating-linear-gradient|repeating-radial-gradient|repeating-conic-gradient)\\s*\\(/i.exec(gradient);\r\n if (!gradientMatch) return gradient;\r\n \r\n const gradientType = gradientMatch[1];\r\n const content = gradient.substring(gradientType.length + 1, gradient.length - 1);\r\n \r\n // Split by commas, but be careful with nested parentheses\r\n const parts: string[] = [];\r\n let current = '';\r\n let parenCount = 0;\r\n \r\n for (let i = 0; i < content.length; i++) {\r\n const char = content[i];\r\n if (char === '(') parenCount++;\r\n else if (char === ')') parenCount--;\r\n else if (char === ',' && parenCount === 0) {\r\n parts.push(current.trim());\r\n current = '';\r\n continue;\r\n }\r\n current += char;\r\n }\r\n parts.push(current.trim());\r\n \r\n // Process each color stop\r\n const processedParts = parts.map(part => {\r\n // Check if this part contains a color\r\n const colorMatch = /(#[0-9a-f]{3,6}|rgb\\([^)]+\\)|hsl\\([^)]+\\)|rgba\\([^)]+\\)|hsla\\([^)]+\\))/i.exec(part);\r\n if (colorMatch) {\r\n const color = colorMatch[1];\r\n const transparentColor = addTransparencyToColor(color, alpha);\r\n return part.replace(color, transparentColor);\r\n }\r\n return part;\r\n });\r\n \r\n return `${gradientType}(${processedParts.join(', ')})`;\r\n}\r\n\r\nfunction processBackground(background: string | undefined, alpha: number = 0.3): string | undefined {\r\n if (!background) return undefined;\r\n \r\n // Check if it's already semi-transparent\r\n if (isSemiTransparentColor(background)) return background;\r\n \r\n // Check if it's a gradient\r\n if (background.includes('gradient')) {\r\n return addTransparencyToGradient(background, alpha);\r\n }\r\n \r\n // Check if it's a URL (image)\r\n if (background.includes('url(')) return background;\r\n \r\n // Treat as solid color\r\n return addTransparencyToColor(background, alpha);\r\n}\r\n\r\nconst DEFAULT_WIDTH = 400;\r\nconst DEFAULT_HEIGHT = 200;\r\n\r\nconst preset = {\r\n scale: 160,\r\n radius: 50,\r\n border: 0.05,\r\n lightness: 53,\r\n displace: 5,\r\n alpha: 0.9,\r\n blur: 0,\r\n dispersion: 50,\r\n saturation: 140,\r\n aberrationIntensity: 0,\r\n frost: 0.1,\r\n borderColor: \"rgba(120, 120, 120, 0.7)\"\r\n};\r\n\r\nexport function LiquidGlass({ \r\n children,\r\n mode = \"preset\",\r\n scale = 160,\r\n radius = 50,\r\n border = 0.05,\r\n lightness = 53,\r\n displace = 5,\r\n alpha = 0.9,\r\n blur = 0,\r\n dispersion = 50,\r\n saturation = 140,\r\n aberrationIntensity = 0,\r\n frost = 0.1,\r\n borderColor = \"rgba(120, 120, 120, 0.7)\",\r\n glassColor = \"rgba(255, 255, 255, 0.4)\",\r\n background,\r\n autoTextColor = false,\r\n textOnDark = '#ffffff',\r\n textOnLight = '#111111',\r\n forceTextColor = false,\r\n className = \"\",\r\n style = {},\r\n quality: incomingQuality,\r\n autodetectquality = false,\r\n iosMinBlur = 7,\r\n iosBlurMode = 'auto',\r\n mobileFallback,\r\n effectMode = 'auto',\r\n ...props\r\n}: LiquidGlassProps) {\r\n // Configuration based on mode\r\n let config: {\r\n mode: string;\r\n scale: number;\r\n radius: number;\r\n border: number;\r\n lightness: number;\r\n displace: number;\r\n alpha: number;\r\n blur: number;\r\n dispersion: number;\r\n saturation: number;\r\n aberrationIntensity: number;\r\n frost: number;\r\n borderColor: string;\r\n blend: 'difference';\r\n x: DisplacementChannel;\r\n y: DisplacementChannel;\r\n };\r\n if (mode === \"preset\") {\r\n config = {\r\n // baseline to preset, but allow incoming props to override as per library behavior\r\n ...preset,\r\n scale,\r\n radius,\r\n border,\r\n lightness,\r\n displace,\r\n alpha,\r\n blur,\r\n dispersion,\r\n saturation,\r\n aberrationIntensity,\r\n frost,\r\n borderColor,\r\n mode: \"preset\",\r\n blend: \"difference\",\r\n x: \"R\",\r\n y: \"B\",\r\n };\r\n } else {\r\n config = {\r\n mode,\r\n scale,\r\n radius,\r\n border,\r\n lightness,\r\n displace,\r\n alpha,\r\n blur,\r\n dispersion,\r\n saturation,\r\n aberrationIntensity,\r\n frost,\r\n borderColor,\r\n blend: \"difference\",\r\n x: \"R\",\r\n y: \"B\"\r\n };\r\n }\r\n\r\n const containerRef = useRef<HTMLDivElement | null>(null);\r\n const [dimensions, setDimensions] = useState({\r\n width: DEFAULT_WIDTH,\r\n height: DEFAULT_HEIGHT\r\n });\r\n const [effectiveTextColor, setEffectiveTextColor] = useState<string>(textOnLight);\r\n const textClassNameRef = useRef<string | null>(null);\r\n if (!textClassNameRef.current) {\r\n textClassNameRef.current = `lg-text-${Math.random().toString(36).slice(2, 9)}`;\r\n }\r\n\r\n // Quality resolution management\r\n const hasExplicitQuality = typeof incomingQuality !== 'undefined' && incomingQuality !== null;\r\n const defaultQuality: LiquidQuality = 'low';\r\n const initialQuality: LiquidQuality = hasExplicitQuality ? (incomingQuality as LiquidQuality) : defaultQuality;\r\n const [resolvedQuality, setResolvedQuality] = useState<LiquidQuality>(initialQuality);\r\n\r\n useEffect(() => {\r\n if (hasExplicitQuality) {\r\n setResolvedQuality(incomingQuality as LiquidQuality);\r\n return;\r\n }\r\n if (!autodetectquality) {\r\n setResolvedQuality(defaultQuality);\r\n return;\r\n }\r\n if (typeof window === 'undefined' || typeof navigator === 'undefined') {\r\n // SSR safety\r\n setResolvedQuality(defaultQuality);\r\n return;\r\n }\r\n\r\n // Prefer low quality when user requests reduced motion\r\n const prefersReducedMotion = typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\r\n if (prefersReducedMotion) {\r\n setResolvedQuality('low');\r\n return;\r\n }\r\n\r\n const CACHE_KEY = 'simpleLiquidGlass_quality_v1';\r\n const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24h\r\n\r\n try {\r\n const cached = sessionStorage.getItem(CACHE_KEY);\r\n if (cached) {\r\n const data = JSON.parse(cached) as { q: LiquidQuality; t: number } | null;\r\n if (data && data.q && typeof data.t === 'number' && Date.now() - data.t < CACHE_TTL_MS) {\r\n setResolvedQuality(data.q);\r\n return;\r\n }\r\n }\r\n } catch {}\r\n\r\n // Heuristics + micro-benchmark\r\n const cores = (navigator as any).hardwareConcurrency || 4;\r\n const deviceMemory = (navigator as any).deviceMemory || 4;\r\n const ua = navigator.userAgent || '';\r\n const isMobile = /Mobi|Android|iPhone|iPad|iPod/i.test(ua);\r\n\r\n // micro-benchmark ~50ms\r\n let operations = 0;\r\n const start = performance.now();\r\n while (performance.now() - start < 50) {\r\n // simple math to stress FP unit\r\n // avoid optimizations by mixing operations\r\n for (let i = 0; i < 200; i++) {\r\n const x = Math.sin(i + operations) * Math.cos(i * 1.3 + operations) + Math.sqrt(i + 1);\r\n if (x > 1e9) {\r\n // never happens; prevents dead-code elimination\r\n operations -= 1;\r\n }\r\n operations += 1;\r\n }\r\n }\r\n const elapsed = Math.max(1, performance.now() - start);\r\n const opsPerMs = operations / elapsed;\r\n\r\n let q: LiquidQuality = defaultQuality;\r\n if (cores <= 2 || deviceMemory <= 1 || opsPerMs < 8000) {\r\n q = 'low';\r\n } else if (cores <= 4 || deviceMemory <= 2 || opsPerMs < 16000 || isMobile) {\r\n q = 'standard';\r\n } else if (cores >= 8 && deviceMemory >= 6 && opsPerMs >= 32000 && !isMobile) {\r\n q = 'extreme';\r\n } else {\r\n q = 'high';\r\n }\r\n\r\n setResolvedQuality(q);\r\n try {\r\n sessionStorage.setItem(CACHE_KEY, JSON.stringify({ q, t: Date.now() }));\r\n } catch {}\r\n }, [incomingQuality, autodetectquality]);\r\n\r\n function parseCssColorToRgba(color: string): { r: number; g: number; b: number; a: number } | null {\r\n const c = color.trim();\r\n let m: RegExpExecArray | null;\r\n if ((m = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)(?:\\s*,\\s*(\\d*\\.?\\d+))?\\s*\\)$/i.exec(c))) {\r\n const r = parseInt(m[1], 10);\r\n const g = parseInt(m[2], 10);\r\n const b = parseInt(m[3], 10);\r\n const a = m[4] !== undefined ? parseFloat(m[4]) : 1;\r\n return { r, g, b, a };\r\n }\r\n if ((m = /^#([0-9a-f]{3})$/i.exec(c))) {\r\n const hex = m[1];\r\n const r = parseInt(hex[0] + hex[0], 16);\r\n const g = parseInt(hex[1] + hex[1], 16);\r\n const b = parseInt(hex[2] + hex[2], 16);\r\n return { r, g, b, a: 1 };\r\n }\r\n if ((m = /^#([0-9a-f]{4})$/i.exec(c))) {\r\n const hex = m[1];\r\n const r = parseInt(hex[0] + hex[0], 16);\r\n const g = parseInt(hex[1] + hex[1], 16);\r\n const b = parseInt(hex[2] + hex[2], 16);\r\n const a = parseInt(hex[3] + hex[3], 16) / 255;\r\n return { r, g, b, a };\r\n }\r\n if ((m = /^#([0-9a-f]{6})$/i.exec(c))) {\r\n const hex = m[1];\r\n const r = parseInt(hex.slice(0, 2), 16);\r\n const g = parseInt(hex.slice(2, 4), 16);\r\n const b = parseInt(hex.slice(4, 6), 16);\r\n return { r, g, b, a: 1 };\r\n }\r\n if ((m = /^#([0-9a-f]{8})$/i.exec(c))) {\r\n const hex = m[1];\r\n const r = parseInt(hex.slice(0, 2), 16);\r\n const g = parseInt(hex.slice(2, 4), 16);\r\n const b = parseInt(hex.slice(4, 6), 16);\r\n const a = parseInt(hex.slice(6, 8), 16) / 255;\r\n return { r, g, b, a };\r\n }\r\n // hsla/hsl are not needed for detection since computed style returns rgb/rgba\r\n return null;\r\n }\r\n\r\n function findNearestOpaqueBackground(element: HTMLElement | null): { r: number; g: number; b: number; a: number } | null {\r\n let el: HTMLElement | null = element;\r\n while (el) {\r\n const style = getComputedStyle(el);\r\n const bg = style.backgroundColor;\r\n const parsed = bg ? parseCssColorToRgba(bg) : null;\r\n if (parsed && parsed.a > 0) {\r\n return parsed;\r\n }\r\n el = el.parentElement;\r\n }\r\n const bodyBg = getComputedStyle(document.body).backgroundColor;\r\n return bodyBg ? parseCssColorToRgba(bodyBg) : null;\r\n }\r\n\r\n function isRgbColorDark(rgb: { r: number; g: number; b: number }): boolean {\r\n const srgb = [rgb.r, rgb.g, rgb.b].map(v => v / 255);\r\n const linear = srgb.map(c => (c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)));\r\n const luminance = 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2];\r\n return luminance < 0.5; // threshold\r\n }\r\n\r\n // Update dimensions when the container size changes\r\n useEffect(() => {\r\n if (!containerRef.current) return;\r\n\r\n const updateDimensions = () => {\r\n if (!containerRef.current) return;\r\n\r\n const { width, height } = containerRef.current.getBoundingClientRect();\r\n if (width === 0 || height === 0) return;\r\n \r\n setDimensions({ width, height });\r\n };\r\n\r\n // Initial measurement\r\n updateDimensions();\r\n\r\n // Create ResizeObserver to watch for size changes\r\n const resizeObserver = new ResizeObserver(updateDimensions);\r\n resizeObserver.observe(containerRef.current);\r\n\r\n return () => resizeObserver.disconnect();\r\n }, []);\r\n\r\n // Auto-detect background and set text color for children; updates on resize/scroll/mutations\r\n useEffect(() => {\r\n if (!autoTextColor) return;\r\n\r\n const update = () => {\r\n const target = containerRef.current?.parentElement ?? null;\r\n if (!target) return;\r\n const bg = findNearestOpaqueBackground(target);\r\n if (!bg) {\r\n setEffectiveTextColor(textOnLight);\r\n return;\r\n }\r\n const dark = isRgbColorDark({ r: bg.r, g: bg.g, b: bg.b });\r\n setEffectiveTextColor(dark ? textOnDark : textOnLight);\r\n };\r\n\r\n update();\r\n\r\n const onWindowChange = () => update();\r\n window.addEventListener('resize', onWindowChange);\r\n window.addEventListener('scroll', onWindowChange, true);\r\n\r\n const observers: MutationObserver[] = [];\r\n const observedNodes: HTMLElement[] = [];\r\n let el: HTMLElement | null = containerRef.current?.parentElement ?? null;\r\n while (el) {\r\n observedNodes.push(el);\r\n el = el.parentElement;\r\n }\r\n observedNodes.push(document.body);\r\n\r\n for (const node of observedNodes) {\r\n if (!node) continue;\r\n const obs = new MutationObserver(update);\r\n obs.observe(node, { attributes: true, attributeFilter: ['class', 'style'] });\r\n observers.push(obs);\r\n }\r\n\r\n return () => {\r\n window.removeEventListener('resize', onWindowChange);\r\n window.removeEventListener('scroll', onWindowChange, true);\r\n observers.forEach(o => o.disconnect());\r\n };\r\n }, [autoTextColor, textOnDark, textOnLight]);\r\n\r\n // Effective radius in px clamped to box (prevents mismatch when radius > half size)\r\n const effectiveRadiusPx = Math.min(config.radius, dimensions.width / 2, dimensions.height / 2);\r\n\r\n // Generate displacement map SVG as data URI\r\n const displacementDataUri = useMemo(() => {\r\n const { width, height } = dimensions;\r\n const divisor = QUALITY_DIVISORS[resolvedQuality] || 3;\r\n const quantStep = QUALITY_QUANTIZATION_STEPS[resolvedQuality] || 16;\r\n const rawW = width / divisor;\r\n const rawH = height / divisor;\r\n const newwidth = Math.max(8, Math.round(rawW / quantStep) * quantStep);\r\n const newheight = Math.max(8, Math.round(rawH / quantStep) * quantStep);\r\n const borderWidth = Math.min(newwidth, newheight) * (config.border * 0.5);\r\n \r\n // Ensure radius doesn't exceed container constraints for consistent CSS/SVG behavior\r\n const effectiveRadius = Math.min(config.radius, width / 2, height / 2) / (QUALITY_DIVISORS[resolvedQuality] || 3); // scale to viewBox resolution\r\n\r\n // Shared cache key across instances to reuse identical displacement maps\r\n const cacheKey = `q:${resolvedQuality}|w:${newwidth}|h:${newheight}|r:${config.radius}|b:${config.border}|l:${config.lightness}|a:${config.alpha}|d:${config.displace}`;\r\n const cached = DISPLACEMENT_CACHE.get(cacheKey);\r\n if (cached) return cached;\r\n \r\n const svgContent = `\r\n <svg viewBox=\"0 0 ${newwidth} ${newheight}\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <defs>\r\n <linearGradient id=\"red\" x1=\"100%\" y1=\"0%\" x2=\"0%\" y2=\"0%\">\r\n <stop offset=\"0%\" stop-color=\"#0000\"/>\r\n <stop offset=\"100%\" stop-color=\"red\"/>\r\n </linearGradient>\r\n <linearGradient id=\"blue\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\r\n <stop offset=\"0%\" stop-color=\"#0000\"/>\r\n <stop offset=\"100%\" stop-color=\"blue\"/>\r\n </linearGradient>\r\n </defs>\r\n <rect x=\"0\" y=\"0\" width=\"${newwidth}\" height=\"${newheight}\" fill=\"black\"/>\r\n <rect x=\"0\" y=\"0\" width=\"${newwidth}\" height=\"${newheight}\" rx=\"${effectiveRadius}\" fill=\"url(#red)\" />\r\n <rect x=\"0\" y=\"0\" width=\"${newwidth}\" height=\"${newheight}\" rx=\"${effectiveRadius}\" fill=\"url(#blue)\" style=\"mix-blend-mode: ${config.blend}\" />\r\n <rect x=\"${borderWidth}\" y=\"${borderWidth}\" width=\"${newwidth - borderWidth * 2}\" height=\"${newheight - borderWidth * 2}\" rx=\"${effectiveRadius}\" fill=\"hsl(0 0% ${config.lightness}% / ${config.alpha})\" style=\"filter:blur(${config.displace}px)\" />\r\n </svg>\r\n `;\r\n \r\n const encoded = encodeURIComponent(svgContent);\r\n const uri = `data:image/svg+xml,${encoded}`;\r\n DISPLACEMENT_CACHE.set(cacheKey, uri);\r\n return uri;\r\n }, [dimensions, config, resolvedQuality]);\r\n\r\n // Generate a unique ID for the SVG filter\r\n const uniqueFilterId = useId();\r\n const filterId = `liquid-glass-filter-${uniqueFilterId}`;\r\n\r\n const resolvedGlassBackground = background\r\n ? 'transparent' // Use transparent when background is provided\r\n : glassColor && isSemiTransparentColor(glassColor)\r\n ? glassColor\r\n : `hsl(0 0% 100% / ${config.frost})`;\r\n\r\n if (glassColor && !isSemiTransparentColor(glassColor)) {\r\n // eslint-disable-next-line no-console\r\n console.warn(\r\n '[LiquidGlass] `glassColor` must be semi-transparent (alpha between 0 and 1). Falling back to frost-based color.'\r\n );\r\n }\r\n\r\n // detect iOS (WebKit on iPhone/iPad or Mac with touch)\r\n const isIOS = (() => {\r\n if (typeof navigator === 'undefined' || typeof window === 'undefined') return false;\r\n const ua = navigator.userAgent || '';\r\n const vendor = navigator.vendor || '';\r\n const isAndroid = /Android/i.test(ua);\r\n const isAppleUA = /(iPad|iPhone|iPod)/i.test(ua);\r\n const isIPadOS13Plus = /Macintosh/i.test(ua) && (navigator as any).maxTouchPoints > 1;\r\n const vendorIsApple = /Apple/i.test(vendor);\r\n const hasWK = typeof (window as any).webkit !== 'undefined';\r\n const hasMobileToken = /Mobile/i.test(ua);\r\n // Strict: real iOS or iPadOS WebKit on Apple device, exclude Android and most desktop emulation\r\n return !isAndroid && (isAppleUA || isIPadOS13Plus) && vendorIsApple && hasWK && hasMobileToken;\r\n })();\r\n\r\n // detect generic mobile (Android/iOS phones/tablets)\r\n const isMobile = (() => {\r\n if (typeof navigator === 'undefined') return false;\r\n const ua = navigator.userAgent || '';\r\n return /Mobi|Android|iPhone|iPad|iPod/i.test(ua);\r\n })();\r\n\r\n // Build backdrop-filter string with effectMode and mobile/iOS fallbacks\r\n const cssBlur = isIOS && iosBlurMode === 'auto' ? Math.max(blur, iosMinBlur) : blur;\r\n const useSvgFilter = (() => {\r\n // effectMode has highest precedence\r\n if (effectMode === 'off') return false;\r\n if (effectMode === 'blur') return false;\r\n if (effectMode === 'svg') return !(isIOS && iosBlurMode === 'auto');\r\n // effectMode === 'auto'\r\n if (mobileFallback === 'css-only') return false;\r\n if (mobileFallback === 'svg') return !(isIOS && iosBlurMode === 'auto');\r\n return !(isIOS && iosBlurMode === 'auto') && !isMobile;\r\n })();\r\n const cssOnlyBlurPx = (() => {\r\n if (effectMode === 'off') return 0;\r\n const base = (resolvedQuality === 'low' || isMobile || effectMode === 'blur') ? Math.min(cssBlur, 2) : cssBlur;\r\n return Math.max(0, base);\r\n })();\r\n const backdropFilterValue = useSvgFilter\r\n ? `saturate(${config.saturation}%) url(#${filterId})`\r\n : (cssOnlyBlurPx > 0\r\n ? `blur(${cssOnlyBlurPx}px) saturate(${config.saturation}%)`\r\n : `saturate(${config.saturation}%)`);\r\n\r\n // Cap SVG blur in low quality to reduce GPU cost\r\n const feBlurStdDev = resolvedQuality === 'low' ? Math.min(config.blur, 2) : config.blur;\r\n\r\n const glassMorphismStyle: React.CSSProperties = {\r\n width: \"100%\",\r\n height: \"100%\",\r\n borderRadius: effectiveRadiusPx,\r\n position: \"absolute\",\r\n zIndex: 1,\r\n background: resolvedGlassBackground,\r\n backdropFilter: backdropFilterValue,\r\n WebkitBackdropFilter: backdropFilterValue,\r\n overflow: 'hidden',\r\n willChange: 'backdrop-filter, filter'\r\n };\r\n\r\n // Gradient border styles\r\n const gradientBorderStyle: React.CSSProperties = {\r\n position: \"absolute\",\r\n inset: 0,\r\n borderRadius: effectiveRadiusPx,\r\n zIndex: 2,\r\n pointerEvents: \"none\",\r\n background: `linear-gradient(315deg, ${config.borderColor} 0%, rgba(120, 120, 120, 0) 30%, rgba(120, 120, 120, 0) 70%, ${config.borderColor} 100%) border-box`,\r\n mask: \"linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)\",\r\n maskComposite: \"exclude\",\r\n WebkitMask: \"linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0)\",\r\n WebkitMaskComposite: \"xor\",\r\n border: `1px solid transparent`\r\n };\r\n\r\n const containerStyle: React.CSSProperties = {\r\n width: \"100%\",\r\n height: \"100%\",\r\n position: \"relative\",\r\n borderRadius: effectiveRadiusPx,\r\n background: processBackground(background),\r\n ...style\r\n };\r\n\r\n return (\r\n <div \r\n ref={containerRef}\r\n className={className}\r\n style={containerStyle}\r\n {...props}\r\n >\r\n <div style={glassMorphismStyle}>\r\n {useSvgFilter && effectMode !== 'off' && (\r\n <svg \r\n className=\"liquid-glass-filter\"\r\n style={{\r\n width: \"100%\",\r\n height: \"100%\",\r\n pointerEvents: \"none\",\r\n position: \"absolute\",\r\n inset: 0\r\n }}\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <defs>\r\n <filter \r\n id={filterId}\r\n colorInterpolationFilters=\"sRGB\"\r\n >\r\n <feImage \r\n href={displacementDataUri}\r\n x=\"0\"\r\n y=\"0\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n result=\"map\"\r\n />\r\n {resolvedQuality === 'low' ? (\r\n <>\r\n <feDisplacementMap \r\n in=\"SourceGraphic\"\r\n in2=\"map\"\r\n scale={config.scale}\r\n xChannelSelector={config.x}\r\n yChannelSelector={config.y}\r\n result=\"output\"\r\n />\r\n <feGaussianBlur \r\n in=\"output\"\r\n stdDeviation={feBlurStdDev}\r\n />\r\n </>\r\n ) : (\r\n <>\r\n <feDisplacementMap \r\n in=\"SourceGraphic\"\r\n in2=\"map\"\r\n scale={config.scale + config.dispersion * config.aberrationIntensity}\r\n xChannelSelector={config.x}\r\n yChannelSelector={config.y}\r\n result=\"dispRed\"\r\n />\r\n <feColorMatrix \r\n in=\"dispRed\"\r\n type=\"matrix\"\r\n values=\"1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0\"\r\n result=\"red\"\r\n />\r\n \r\n <feDisplacementMap \r\n in=\"SourceGraphic\"\r\n in2=\"map\"\r\n scale={config.scale}\r\n xChannelSelector={config.x}\r\n yChannelSelector={config.y}\r\n result=\"dispGreen\"\r\n />\r\n <feColorMatrix \r\n in=\"dispGreen\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0\"\r\n result=\"green\"\r\n />\r\n \r\n <feDisplacementMap \r\n in=\"SourceGraphic\"\r\n in2=\"map\"\r\n scale={config.scale - config.dispersion * config.aberrationIntensity}\r\n xChannelSelector={config.x}\r\n yChannelSelector={config.y}\r\n result=\"dispBlue\"\r\n />\r\n <feColorMatrix \r\n in=\"dispBlue\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0\"\r\n result=\"blue\"\r\n />\r\n \r\n <feBlend \r\n in=\"red\"\r\n in2=\"green\"\r\n mode=\"screen\"\r\n result=\"rg\"\r\n />\r\n <feBlend \r\n in=\"rg\"\r\n in2=\"blue\"\r\n mode=\"screen\"\r\n result=\"output\"\r\n />\r\n <feGaussianBlur \r\n in=\"output\"\r\n stdDeviation={feBlurStdDev}\r\n />\r\n </>\r\n )}\r\n </filter>\r\n </defs>\r\n </svg>\r\n )}\r\n </div>\r\n \r\n <div \r\n className=\"liquid-glass-border\"\r\n style={gradientBorderStyle}\r\n />\r\n \r\n {/* Children content */}\r\n {children && (\r\n <div \r\n style={{\r\n position: \"relative\",\r\n zIndex: 3,\r\n width: \"100%\",\r\n height: \"100%\",\r\n color: autoTextColor ? effectiveTextColor : undefined,\r\n transition: 'color 300ms ease'\r\n }}\r\n className={forceTextColor ? textClassNameRef.current ?? undefined : undefined}\r\n >\r\n {forceTextColor && autoTextColor && (\r\n <style>\r\n {`\r\n .${textClassNameRef.current}, .${textClassNameRef.current} * { transition: color 300ms ease; }\r\n .${textClassNameRef.current} { color: ${effectiveTextColor} !important; }\r\n .${textClassNameRef.current} * { color: ${effectiveTextColor} !important; }\r\n `}\r\n </style>\r\n )}\r\n {children}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\nLiquidGlass.displayName = \"LiquidGlass\";\r\n\r\nexport default LiquidGlass;\r\n\r\n// Removed non-working experimental components per user request"],"names":["QUALITY_DIVISORS","low","standard","high","extreme","QUALITY_QUANTIZATION_STEPS","DISPLACEMENT_CACHE","Map","isSemiTransparentColor","input","color","trim","rgba","exec","a","parseFloat","hsla","hslSlash","hex4","aHex","slice","parseInt","hex8","addTransparencyToColor","alpha","arguments","length","undefined","trimmed","hex3","r","g","b","concat","hex6","rgb","hsl","h","s","l","processBackground","background","includes","gradient","gradientMatch","gradientType","content","substring","parts","current","parenCount","i","char","push","processedParts","map","part","colorMatch","transparentColor","replace","join","addTransparencyToGradient","preset","scale","radius","border","lightness","displace","blur","dispersion","saturation","aberrationIntensity","frost","borderColor","LiquidGlass","_ref","_textClassNameRef$cur","config","children","_ref$mode","mode","_ref$scale","_ref$radius","_ref$border","_ref$lightness","_ref$displace","_ref$alpha","_ref$blur","_ref$dispersion","_ref$saturation","_ref$aberrationIntens","_ref$frost","_ref$borderColor","_ref$glassColor","glassColor","_ref$autoTextColor","autoTextColor","_ref$textOnDark","textOnDark","_ref$textOnLight","textOnLight","_ref$forceTextColor","forceTextColor","_ref$className","className","_ref$style","style","incomingQuality","quality","_ref$autodetectqualit","autodetectquality","_ref$iosMinBlur","iosMinBlur","_ref$iosBlurMode","iosBlurMode","mobileFallback","_ref$effectMode","effectMode","props","_objectWithoutProperties","_excluded","_objectSpread","blend","x","y","containerRef","useRef","_useState2","_slicedToArray","useState","width","height","dimensions","setDimensions","_useState4","effectiveTextColor","setEffectiveTextColor","textClassNameRef","Math","random","toString","hasExplicitQuality","defaultQuality","initialQuality","_useState6","resolvedQuality","setResolvedQuality","parseCssColorToRgba","m","c","hex","useEffect","window","navigator","matchMedia","matches","CACHE_KEY","cached","sessionStorage","getItem","data","JSON","parse","q","t","Date","now","_unused","cores","hardwareConcurrency","deviceMemory","ua","userAgent","isMobile","test","operations","start","performance","sin","cos","sqrt","opsPerMs","max","setItem","stringify","_unused2","updateDimensions","_containerRef$current","getBoundingClientRect","resizeObserver","ResizeObserver","observe","disconnect","_containerRef$current4","_containerRef$current5","update","_containerRef$current2","_containerRef$current3","target","parentElement","bg","element","el","getComputedStyle","backgroundColor","parsed","bodyBg","document","body","findNearestOpaqueBackground","linear","dark","v","pow","onWindowChange","addEventListener","observers","observedNodes","_i","_observedNodes","node","obs","MutationObserver","attributes","attributeFilter","removeEventListener","forEach","o","effectiveRadiusPx","min","displacementDataUri","useMemo","divisor","quantStep","rawW","rawH","newwidth","round","newheight","borderWidth","effectiveRadius","cacheKey","get","svgContent","encoded","encodeURIComponent","uri","set","uniqueFilterId","useId","filterId","resolvedGlassBackground","console","warn","isIOS","vendor","isAndroid","isAppleUA","isIPadOS13Plus","maxTouchPoints","vendorIsApple","hasWK","webkit","hasMobileToken","cssBlur","useSvgFilter","cssOnlyBlurPx","base","backdropFilterValue","feBlurStdDev","glassMorphismStyle","borderRadius","position","zIndex","backdropFilter","WebkitBackdropFilter","overflow","willChange","gradientBorderStyle","inset","pointerEvents","mask","maskComposite","WebkitMask","WebkitMaskComposite","containerStyle","React","createElement","_extends","ref","xmlns","id","colorInterpolationFilters","href","result","Fragment","in","in2","xChannelSelector","yChannelSelector","stdDeviation","type","values","transition","displayName"],"mappings":"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"}