15 lines
10 KiB
JSON
15 lines
10 KiB
JSON
{
|
|
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
"name": "liquid-glass",
|
|
"type": "registry:ui",
|
|
"title": "Liquid Glass",
|
|
"description": "A component that allows you to display a liquid glass effect, inspired by iOS26.",
|
|
"files": [
|
|
{
|
|
"path": "registry/components/liquid-glass/index.tsx",
|
|
"content": "import * as React from 'react';\nimport { cn } from '@/lib/utils';\n\nconst DEFAULT_COMPONENT = 'div';\n\ntype LiquidGlassProps<T extends React.ElementType = typeof DEFAULT_COMPONENT> =\n {\n as?: T;\n radius?: number;\n blur?: number;\n childClassName?: string;\n } & React.ComponentProps<T>;\n\nfunction LiquidGlass<T extends React.ElementType = typeof DEFAULT_COMPONENT>({\n as,\n children,\n className,\n radius = 25,\n blur = 0,\n childClassName,\n ref,\n ...props\n}: LiquidGlassProps<T>) {\n const Component = as || DEFAULT_COMPONENT;\n\n const containerRef = React.useRef<HTMLDivElement>(null);\n React.useImperativeHandle(ref, () => containerRef.current as HTMLDivElement);\n\n const rx = radius;\n const [size, setSize] = React.useState<{ width: string; height: string }>({\n width: '0',\n height: '0',\n });\n\n const viewBox = React.useMemo(\n () => `0 0 ${size.width} ${size.height}`,\n [size.width, size.height],\n );\n\n const calculateSize = React.useCallback(() => {\n if (containerRef.current) {\n const rect = containerRef.current.getBoundingClientRect();\n setSize({\n width: rect.width.toString(),\n height: rect.height.toString(),\n });\n }\n }, []);\n\n React.useEffect(() => {\n calculateSize();\n }, [calculateSize, children, className, childClassName, radius]);\n\n return (\n <Component\n className={cn('relative overflow-hidden', className)}\n style={{ borderRadius: `${rx}px` }}\n ref={containerRef}\n {...props}\n >\n <svg className=\"hidden\">\n <filter\n id=\"glass-distortion\"\n x=\"0%\"\n y=\"0%\"\n width={size.width}\n height={size.height}\n filterUnits=\"objectBoundingBox\"\n >\n <feTurbulence\n type=\"fractalNoise\"\n baseFrequency=\"0.001 0.005\"\n numOctaves=\"1\"\n seed=\"17\"\n result=\"turbulence\"\n />\n\n <feComponentTransfer in=\"turbulence\" result=\"mapped\">\n <feFuncR type=\"gamma\" amplitude=\"1\" exponent=\"10\" offset=\"0.5\" />\n <feFuncG type=\"gamma\" amplitude=\"0\" exponent=\"1\" offset=\"0\" />\n <feFuncB type=\"gamma\" amplitude=\"0\" exponent=\"1\" offset=\"0.5\" />\n </feComponentTransfer>\n\n <feGaussianBlur in=\"turbulence\" stdDeviation=\"3\" result=\"softMap\" />\n\n <feSpecularLighting\n in=\"softMap\"\n surfaceScale=\"5\"\n specularConstant=\"1\"\n specularExponent=\"100\"\n lightingColor=\"white\"\n result=\"specLight\"\n >\n <fePointLight x=\"-200\" y=\"-200\" z=\"300\" />\n </feSpecularLighting>\n\n <feComposite\n in=\"specLight\"\n operator=\"arithmetic\"\n k1=\"0\"\n k2=\"1\"\n k3=\"1\"\n k4=\"0\"\n result=\"litImage\"\n />\n\n <feDisplacementMap\n in=\"SourceGraphic\"\n in2=\"softMap\"\n scale=\"200\"\n xChannelSelector=\"R\"\n yChannelSelector=\"G\"\n />\n </filter>\n </svg>\n\n <span\n className=\"flex items-center justify-center w-full h-full\"\n style={{\n backdropFilter: `blur(${blur}px) url(#displacementFilter4)`,\n boxShadow: 'inset 0 0 1px 0 rgba(255, 255, 255, 0.5)',\n borderRadius: `${rx}px`,\n }}\n >\n <span\n className=\"relative flex overflow-hidden transition-all duration-400 ease-in-out\"\n style={{\n borderRadius: `${rx}px`,\n }}\n >\n <span\n className=\"absolute z-0 inset-0 overflow-hidden isolate [filter:url(#glass-distortion)]\"\n style={{\n borderRadius: `${rx}px`,\n }}\n />\n <span\n className=\"z-[1] absolute inset-0\"\n style={{\n borderRadius: `${rx}px`,\n }}\n />\n <span className=\"relative z-[3] w-full h-full\">\n <span\n className={cn(\n 'flex items-center justify-center gap-2 w-full p-2',\n childClassName,\n )}\n >\n {children}\n </span>\n <svg\n width={size.width}\n height={size.height}\n viewBox={viewBox}\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"hidden\"\n >\n <filter\n id=\"displacementFilter4\"\n x=\"0\"\n y=\"0\"\n width={size.width}\n height={size.height}\n filterUnits=\"userSpaceOnUse\"\n >\n <feImage\n href={`data:image/svg+xml,%3Csvg width='${size.width}' height='${size.height}' viewBox='${viewBox}' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='${size.width}' height='${size.height}' rx='${rx}' fill='%230001' /%3E%3Crect width='${size.width}' height='${size.height}' rx='${rx}' fill='%23FFF' style='filter:blur(5px)' /%3E%3C/svg%3E`}\n x=\"0%\"\n y=\"0%\"\n width={size.width}\n height={size.height}\n result=\"thing9\"\n />\n <feImage\n href={`data:image/svg+xml,%3Csvg width='${size.width}' height='${size.height}' viewBox='${viewBox}' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='${size.width}' height='${size.height}' rx='${rx}' fill='%23FFF1' style='filter:blur(15px)' /%3E%3C/svg%3E`}\n x=\"0%\"\n y=\"0%\"\n width={size.width}\n height={size.height}\n result=\"thing0\"\n />\n <feImage\n href={`data:image/svg+xml,%3Csvg width='${size.width}' height='${size.height}' viewBox='${viewBox}' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='${size.width}' height='${size.height}' rx='${rx}' fill='%23000' /%3E%3C/svg%3E`}\n x=\"0%\"\n y=\"0%\"\n width={size.width}\n height={size.height}\n result=\"thing1\"\n />\n <feImage\n href={`data:image/svg+xml,%3Csvg width='${size.width}' height='${size.height}' viewBox='${viewBox}' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3ClinearGradient id='gradient1' x1='0%25' y1='0%25' x2='100%25' y2='0%25'%3E%3Cstop offset='0%25' stop-color='%23000'/%3E%3Cstop offset='100%25' stop-color='%2300F'/%3E%3C/linearGradient%3E%3ClinearGradient id='gradient2' x1='0%25' y1='0%25' x2='0%25' y2='100%25'%3E%3Cstop offset='0%25' stop-color='%23000'/%3E%3Cstop offset='100%25' stop-color='%230F0'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect x='0' y='0' width='${size.width}' height='${size.height}' rx='${rx}' fill='%237F7F7F' /%3E%3Crect width='${size.width}' height='${size.height}' rx='${rx}' fill='%23000' /%3E%3Crect width='${size.width}' height='${size.height}' rx='${rx}' fill='url(%23gradient1)' style='mix-blend-mode: screen' /%3E%3Crect width='${size.width}' height='${size.height}' rx='${rx}' fill='url(%23gradient2)' style='mix-blend-mode: screen' /%3E%3Crect width='${size.width}' height='${size.height}' rx='${rx}' fill='%237F7F7FBB' style='filter:blur(5px)' /%3E%3C/svg%3E`}\n x=\"0%\"\n y=\"0%\"\n width={size.width}\n height={size.height}\n result=\"thing2\"\n />\n <feDisplacementMap\n in2=\"thing2\"\n in=\"SourceGraphic\"\n scale=\"-148\"\n xChannelSelector=\"B\"\n yChannelSelector=\"G\"\n />\n <feColorMatrix\n type=\"matrix\"\n values=\"1 0 0 0 0\n 0 0 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0\"\n result=\"disp1\"\n />\n <feDisplacementMap\n in2=\"thing2\"\n in=\"SourceGraphic\"\n scale=\"-150\"\n xChannelSelector=\"B\"\n yChannelSelector=\"G\"\n />\n <feColorMatrix\n type=\"matrix\"\n values=\"0 0 0 0 0\n 0 1 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0\"\n result=\"disp2\"\n />\n <feDisplacementMap\n in2=\"thing2\"\n in=\"SourceGraphic\"\n scale=\"-152\"\n xChannelSelector=\"B\"\n yChannelSelector=\"G\"\n />\n <feColorMatrix\n type=\"matrix\"\n values=\"0 0 0 0 0\n 0 0 0 0 0\n 0 0 1 0 0\n 0 0 0 1 0\"\n result=\"disp3\"\n />\n <feBlend in2=\"disp2\" mode=\"screen\" />\n <feBlend in2=\"disp1\" mode=\"screen\" />\n <feGaussianBlur stdDeviation=\"0.7\" />\n <feBlend in2=\"thing0\" mode=\"screen\" />\n <feBlend in2=\"thing9\" mode=\"multiply\" />\n <feComposite in2=\"thing1\" operator=\"in\" />\n </filter>\n </svg>\n </span>\n </span>\n </span>\n </Component>\n );\n}\n\nLiquidGlass.displayName = 'LiquidGlass';\n\nexport { LiquidGlass, type LiquidGlassProps };\n",
|
|
"type": "registry:ui",
|
|
"target": "components/animate-ui/components/liquid-glass.tsx"
|
|
}
|
|
]
|
|
} |