@marcosdemik/liquidglass 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,188 @@
1
+ # @marcosdemik/liquidglass
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@marcosdemik/liquidglass.svg)](https://www.npmjs.com/package/@marcosdemik/liquidglass)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@marcosdemik/liquidglass.svg)](https://www.npmjs.com/package/@marcosdemik/liquidglass)
5
+ [![license](https://img.shields.io/npm/l/@marcosdemik/liquidglass.svg)](https://github.com/MarcosDemik/liquidglass/blob/main/LICENSE)
6
+
7
+ A React component that creates a **Liquid Glass** UI effect - glassmorphism with real-time refraction, chromatic aberration, and smooth GSAP animations.
8
+
9
+ Built with SVG filters and WebGL displacement maps.
10
+
11
+ [GitHub](https://github.com/MarcosDemik/liquidglass)
12
+
13
+ ---
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ # npm
19
+ npm install @marcosdemik/liquidglass
20
+
21
+ # yarn
22
+ yarn add @marcosdemik/liquidglass
23
+
24
+ # pnpm
25
+ pnpm add @marcosdemik/liquidglass
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ```tsx
31
+ import { LiquidGlassButton } from "@marcosdemik/liquidglass";
32
+
33
+ function App() {
34
+ return (
35
+ <LiquidGlassButton width={320} height={60} radius={60} chroma={3}>
36
+ Click me
37
+ </LiquidGlassButton>
38
+ );
39
+ }
40
+ ```
41
+
42
+ ## Works With
43
+
44
+ - Next.js (App Router & Pages Router)
45
+ - Vite + React
46
+ - Remix
47
+ - Gatsby
48
+ - Any React 18+ project
49
+
50
+ The component includes a `"use client"` directive, so it works out of the box with Server Components.
51
+
52
+ ## Props
53
+
54
+ | Prop | Type | Default | Description |
55
+ |------|------|---------|-------------|
56
+ | `width` | `number` | `300` | Button width in pixels |
57
+ | `height` | `number` | `56` | Button height in pixels |
58
+ | `radius` | `number` | `60` | Border radius in pixels |
59
+ | `edgeSize` | `number` | `40` | Size of the glass edge refraction zone |
60
+ | `intensity` | `number` | `1.0` | Refraction intensity multiplier |
61
+ | `smoothness` | `number` | `1.0` | Blur applied to the displacement map (softens edges) |
62
+ | `distortion` | `number` | `15.0` | Normal map distortion scale |
63
+ | `chroma` | `number` | `3` | Chromatic aberration strength (RGB channel offset) |
64
+ | `glassColor` | `string` | `"rgba(255,255,255,0.05)"` | Background tint color of the glass |
65
+ | `className` | `string` | | Additional CSS classes |
66
+ | `style` | `CSSProperties` | | Inline styles merged onto the button |
67
+ | `ref` | `Ref<HTMLButtonElement>` | | Forwarded ref to the underlying button |
68
+
69
+ All standard `<button>` HTML attributes (`onClick`, `disabled`, `aria-label`, etc.) are also supported.
70
+
71
+ ## Examples
72
+
73
+ ### Pill Button
74
+
75
+ ```tsx
76
+ <LiquidGlassButton width={320} height={60} radius={60}>
77
+ Get Started
78
+ </LiquidGlassButton>
79
+ ```
80
+
81
+ ### Square Icon Button
82
+
83
+ ```tsx
84
+ <LiquidGlassButton width={60} height={60} radius={16} className="text-xl">
85
+ +
86
+ </LiquidGlassButton>
87
+ ```
88
+
89
+ ### Circle Button
90
+
91
+ ```tsx
92
+ <LiquidGlassButton width={80} height={80} radius={9999}>
93
+ Play
94
+ </LiquidGlassButton>
95
+ ```
96
+
97
+ ### Wide Navigation Bar
98
+
99
+ ```tsx
100
+ <LiquidGlassButton width={400} height={48} radius={24}>
101
+ Navigation
102
+ </LiquidGlassButton>
103
+ ```
104
+
105
+ ### High Distortion
106
+
107
+ ```tsx
108
+ <LiquidGlassButton
109
+ width={320}
110
+ height={60}
111
+ radius={60}
112
+ distortion={30}
113
+ chroma={8}
114
+ intensity={2}
115
+ >
116
+ Distorted
117
+ </LiquidGlassButton>
118
+ ```
119
+
120
+ ### Subtle Glass
121
+
122
+ ```tsx
123
+ <LiquidGlassButton
124
+ width={320}
125
+ height={60}
126
+ radius={60}
127
+ distortion={5}
128
+ chroma={1}
129
+ smoothness={3}
130
+ >
131
+ Subtle
132
+ </LiquidGlassButton>
133
+ ```
134
+
135
+ ### With onClick Handler
136
+
137
+ ```tsx
138
+ <LiquidGlassButton
139
+ width={200}
140
+ height={50}
141
+ radius={30}
142
+ onClick={() => console.log("clicked!")}
143
+ >
144
+ Click me
145
+ </LiquidGlassButton>
146
+ ```
147
+
148
+ ### Custom Glass Color
149
+
150
+ ```tsx
151
+ <LiquidGlassButton
152
+ width={320}
153
+ height={60}
154
+ radius={60}
155
+ glassColor="rgba(0, 150, 255, 0.1)"
156
+ >
157
+ Blue Glass
158
+ </LiquidGlassButton>
159
+ ```
160
+
161
+ ## How It Works
162
+
163
+ The effect is built from three layers:
164
+
165
+ 1. **WebGL Displacement Map** - A GLSL fragment shader computes a displacement map from a signed distance field (SDF) of a rounded rectangle. The shader runs on an offscreen canvas and outputs a PNG data URL. The WebGL context is cached as a singleton for performance.
166
+
167
+ 2. **SVG Filter Chain** - The displacement map feeds into an SVG `<filter>` that applies per-channel (R/G/B) `feDisplacementMap` at slightly different scales, producing chromatic aberration. Channels are recombined with `feBlend mode="screen"`.
168
+
169
+ 3. **GSAP Animations** - Pointer events drive GSAP tweens that animate displacement scale, blur, chromatic separation, and button scale. Filter attributes are mutated directly each frame for maximum performance.
170
+
171
+ ## Accessibility
172
+
173
+ - Respects `prefers-reduced-motion` - all animations are automatically disabled
174
+ - Semantic `<button>` element - fully keyboard navigable
175
+ - Supports all ARIA attributes via standard button props
176
+
177
+ ## Requirements
178
+
179
+ - React 18+ (uses `useId` hook)
180
+ - Browser with WebGL support
181
+
182
+ ## Acknowledgments
183
+
184
+ The core glass refraction concept is inspired by [rahuldotdev](https://github.com/rahuldotdev)'s liquid glass button implementation.
185
+
186
+ ## License
187
+
188
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,311 @@
1
+ "use client";
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __defProps = Object.defineProperties;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
13
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
14
+ var __spreadValues = (a, b) => {
15
+ for (var prop in b || (b = {}))
16
+ if (__hasOwnProp.call(b, prop))
17
+ __defNormalProp(a, prop, b[prop]);
18
+ if (__getOwnPropSymbols)
19
+ for (var prop of __getOwnPropSymbols(b)) {
20
+ if (__propIsEnum.call(b, prop))
21
+ __defNormalProp(a, prop, b[prop]);
22
+ }
23
+ return a;
24
+ };
25
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
26
+ var __objRest = (source, exclude) => {
27
+ var target = {};
28
+ for (var prop in source)
29
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
30
+ target[prop] = source[prop];
31
+ if (source != null && __getOwnPropSymbols)
32
+ for (var prop of __getOwnPropSymbols(source)) {
33
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
34
+ target[prop] = source[prop];
35
+ }
36
+ return target;
37
+ };
38
+ var __export = (target, all) => {
39
+ for (var name in all)
40
+ __defProp(target, name, { get: all[name], enumerable: true });
41
+ };
42
+ var __copyProps = (to, from, except, desc) => {
43
+ if (from && typeof from === "object" || typeof from === "function") {
44
+ for (let key of __getOwnPropNames(from))
45
+ if (!__hasOwnProp.call(to, key) && key !== except)
46
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
47
+ }
48
+ return to;
49
+ };
50
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
51
+ // If the importer is in node compatibility mode or this is not an ESM
52
+ // file that has been converted to a CommonJS file using a Babel-
53
+ // compatible transform (i.e. "__esModule" has not been set), then set
54
+ // "default" to the CommonJS "module.exports" for node compatibility.
55
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
56
+ mod
57
+ ));
58
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
59
+
60
+ // src/index.ts
61
+ var index_exports = {};
62
+ __export(index_exports, {
63
+ LiquidGlassButton: () => LiquidGlassButton,
64
+ cn: () => cn,
65
+ generateGlassMaps: () => generateGlassMaps
66
+ });
67
+ module.exports = __toCommonJS(index_exports);
68
+
69
+ // src/liquid-glass-button.tsx
70
+ var import_react = require("react");
71
+ var import_gsap = __toESM(require("gsap"), 1);
72
+
73
+ // src/utils.ts
74
+ function cn(...classes) {
75
+ return classes.filter(Boolean).join(" ");
76
+ }
77
+
78
+ // src/generate-displacement-map.ts
79
+ var VERT = `attribute vec4 position; void main(){ gl_Position = position; }`;
80
+ var FRAG = `
81
+ precision mediump float;
82
+ uniform vec2 uRes;
83
+ uniform float uRadius;
84
+ uniform float uEdgeSize;
85
+ uniform float uIntensity;
86
+ uniform float uDistortion;
87
+
88
+ float sdRoundedBox(vec2 p, vec2 b, float r){
89
+ r = min(r, min(b.x, b.y));
90
+ vec2 q = abs(p) - b + r;
91
+ return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
92
+ }
93
+
94
+ float getHeight(vec2 p) {
95
+ vec2 halfSize = uRes * 0.5 - 2.0;
96
+
97
+ // Aumenta o tamanho base do box ligeiramente proporcinal ao edge
98
+ halfSize += uEdgeSize * 0.2;
99
+
100
+ float d = sdRoundedBox(p, halfSize, uRadius);
101
+
102
+ float borderSoftness = uEdgeSize * uIntensity;
103
+ d = max(d, -borderSoftness);
104
+ return smoothstep(0.0, -borderSoftness, d);
105
+ }
106
+
107
+ void main(){
108
+ vec2 p = gl_FragCoord.xy - uRes * 0.5;
109
+ p.y = -p.y;
110
+
111
+ // --- Displacement Map ---
112
+ const vec2 e = vec2(1.0, 0.0);
113
+ float hx = getHeight(p + e.xy) - getHeight(p - e.xy);
114
+ float hy = getHeight(p + e.yx) - getHeight(p - e.yx);
115
+
116
+ vec2 normal = vec2(-hx, -hy) * uDistortion;
117
+ vec2 color = clamp(normal * 0.5 + 0.5, 0.0, 1.0);
118
+
119
+ gl_FragColor = vec4(color.x, color.y, 0.5, 1.0);
120
+ }
121
+ `;
122
+ function compile(gl, type, src) {
123
+ const s = gl.createShader(type);
124
+ gl.shaderSource(s, src);
125
+ gl.compileShader(s);
126
+ return s;
127
+ }
128
+ var _cachedProgram = null;
129
+ function getGL() {
130
+ if (_cachedProgram) return _cachedProgram;
131
+ const canvas = document.createElement("canvas");
132
+ const gl = canvas.getContext("webgl", { preserveDrawingBuffer: true, premultipliedAlpha: false });
133
+ const vs = compile(gl, gl.VERTEX_SHADER, VERT);
134
+ const fs = compile(gl, gl.FRAGMENT_SHADER, FRAG);
135
+ const program = gl.createProgram();
136
+ gl.attachShader(program, vs);
137
+ gl.attachShader(program, fs);
138
+ gl.linkProgram(program);
139
+ gl.useProgram(program);
140
+ const buf = gl.createBuffer();
141
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
142
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
143
+ const pos = gl.getAttribLocation(program, "position");
144
+ gl.enableVertexAttribArray(pos);
145
+ gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
146
+ _cachedProgram = { gl, program, canvas };
147
+ return _cachedProgram;
148
+ }
149
+ function render(width, height, radius, edgeSize, intensity, distortion) {
150
+ const { gl, program, canvas } = getGL();
151
+ canvas.width = width;
152
+ canvas.height = height;
153
+ gl.viewport(0, 0, width, height);
154
+ gl.clearColor(0.5, 0.5, 0.5, 1);
155
+ gl.clear(gl.COLOR_BUFFER_BIT);
156
+ gl.useProgram(program);
157
+ gl.uniform2f(gl.getUniformLocation(program, "uRes"), width, height);
158
+ gl.uniform1f(gl.getUniformLocation(program, "uRadius"), radius);
159
+ gl.uniform1f(gl.getUniformLocation(program, "uEdgeSize"), edgeSize);
160
+ gl.uniform1f(gl.getUniformLocation(program, "uIntensity"), intensity);
161
+ gl.uniform1f(gl.getUniformLocation(program, "uDistortion"), distortion);
162
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
163
+ return canvas.toDataURL("image/png");
164
+ }
165
+ function generateGlassMaps(opts) {
166
+ const { width, height, radius = 60, edgeSize = 40, intensity = 1, distortion = 15 } = opts;
167
+ const r = Math.min(radius, width / 2, height / 2);
168
+ return {
169
+ displacement: render(width, height, r, edgeSize, intensity, distortion)
170
+ };
171
+ }
172
+
173
+ // src/liquid-glass-button.tsx
174
+ var import_jsx_runtime = require("react/jsx-runtime");
175
+ var CONFIG = {
176
+ initial: { scale: 1, displacement: 35, blur: 2, chroma: 3 },
177
+ hover: { scale: 1.05, displacement: 65, blur: 4, chroma: 10 },
178
+ click: { scaleDown: 0.95, scaleUp: 1.05 },
179
+ duration: { hover: 0.4, clickDown: 0.1, clickUp: 0.3 },
180
+ ease: {
181
+ hover: "power3.out",
182
+ hoverOut: "power2.out",
183
+ clickDown: "power2.in",
184
+ clickUp: "back.out(2)"
185
+ }
186
+ };
187
+ var PADDING = 60;
188
+ var LiquidGlassButton = (0, import_react.forwardRef)(
189
+ function LiquidGlassButton2(_a, ref) {
190
+ var _b = _a, { children, className, width = 300, height = 56, radius = 60, edgeSize, intensity, smoothness = 1, distortion, chroma = 3, glassColor = "rgba(255,255,255,0.05)", style } = _b, props = __objRest(_b, ["children", "className", "width", "height", "radius", "edgeSize", "intensity", "smoothness", "distortion", "chroma", "glassColor", "style"]);
191
+ const internalRef = (0, import_react.useRef)(null);
192
+ const buttonRef = ref != null ? ref : internalRef;
193
+ const blurRef = (0, import_react.useRef)(null);
194
+ const displacerR = (0, import_react.useRef)(null);
195
+ const displacerG = (0, import_react.useRef)(null);
196
+ const displacerB = (0, import_react.useRef)(null);
197
+ const filterId = "lg" + (0, import_react.useId)().replace(/:/g, "");
198
+ const [maps, setMaps] = (0, import_react.useState)(null);
199
+ (0, import_react.useEffect)(() => {
200
+ const result = generateGlassMaps({ width, height, radius, edgeSize, intensity, distortion });
201
+ setMaps(result);
202
+ }, [width, height, radius, edgeSize, intensity, distortion]);
203
+ (0, import_react.useEffect)(() => {
204
+ const button = buttonRef.current;
205
+ if (!button || !blurRef.current) return;
206
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
207
+ const fx = {
208
+ displacement: CONFIG.initial.displacement,
209
+ blur: CONFIG.initial.blur,
210
+ chroma
211
+ };
212
+ const sync = () => {
213
+ var _a2, _b2, _c, _d;
214
+ (_a2 = displacerR.current) == null ? void 0 : _a2.setAttribute("scale", (fx.displacement + fx.chroma).toString());
215
+ (_b2 = displacerG.current) == null ? void 0 : _b2.setAttribute("scale", fx.displacement.toString());
216
+ (_c = displacerB.current) == null ? void 0 : _c.setAttribute("scale", (fx.displacement - fx.chroma).toString());
217
+ (_d = blurRef.current) == null ? void 0 : _d.setAttribute("stdDeviation", fx.blur.toString());
218
+ };
219
+ sync();
220
+ const onEnter = () => {
221
+ import_gsap.default.killTweensOf([fx, button]);
222
+ import_gsap.default.to(fx, {
223
+ displacement: CONFIG.hover.displacement,
224
+ blur: CONFIG.hover.blur,
225
+ chroma: chroma * 2.5,
226
+ duration: CONFIG.duration.hover,
227
+ ease: CONFIG.ease.hover,
228
+ onUpdate: sync
229
+ });
230
+ import_gsap.default.to(button, { scale: CONFIG.hover.scale, duration: CONFIG.duration.hover, ease: CONFIG.ease.hover });
231
+ };
232
+ const onLeave = () => {
233
+ import_gsap.default.killTweensOf([fx, button]);
234
+ import_gsap.default.to(fx, {
235
+ displacement: CONFIG.initial.displacement,
236
+ blur: CONFIG.initial.blur,
237
+ chroma,
238
+ duration: CONFIG.duration.hover,
239
+ ease: CONFIG.ease.hoverOut,
240
+ onUpdate: sync
241
+ });
242
+ import_gsap.default.to(button, { scale: CONFIG.initial.scale, duration: CONFIG.duration.hover, ease: CONFIG.ease.hoverOut });
243
+ };
244
+ const onClick = () => {
245
+ import_gsap.default.killTweensOf(button);
246
+ const cur = import_gsap.default.getProperty(button, "scale");
247
+ import_gsap.default.timeline().to(button, { scale: cur * CONFIG.click.scaleDown, duration: CONFIG.duration.clickDown, ease: CONFIG.ease.clickDown }).to(button, { scale: CONFIG.click.scaleUp, duration: CONFIG.duration.clickUp, ease: CONFIG.ease.clickUp });
248
+ };
249
+ button.addEventListener("pointerenter", onEnter);
250
+ button.addEventListener("pointerleave", onLeave);
251
+ button.addEventListener("click", onClick);
252
+ return () => {
253
+ button.removeEventListener("pointerenter", onEnter);
254
+ button.removeEventListener("pointerleave", onLeave);
255
+ button.removeEventListener("click", onClick);
256
+ import_gsap.default.killTweensOf([button, fx]);
257
+ };
258
+ }, [buttonRef, maps, chroma]);
259
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
260
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
261
+ "button",
262
+ __spreadProps(__spreadValues({
263
+ ref: buttonRef,
264
+ className: cn("relative overflow-hidden shadow-2xl shadow-black/20 cursor-pointer", className),
265
+ style: __spreadValues({ width, height, borderRadius: radius, border: "none", background: glassColor }, style)
266
+ }, props), {
267
+ children: [
268
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
269
+ "div",
270
+ {
271
+ className: "absolute z-0",
272
+ style: {
273
+ top: -PADDING,
274
+ left: -PADDING,
275
+ right: -PADDING,
276
+ bottom: -PADDING,
277
+ backdropFilter: `url(#${filterId})`,
278
+ WebkitBackdropFilter: `url(#${filterId})`
279
+ }
280
+ }
281
+ ),
282
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 z-10 flex items-center justify-center font-bold text-white shadow-[inset_0_1px_1px_rgba(255,255,255,0.4)]", style: { background: "linear-gradient(180deg, rgba(255,255,255,0.15) 0%, rgba(255,255,255,0.0) 100%)", borderRadius: "inherit" }, children })
283
+ ]
284
+ })
285
+ ),
286
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { style: { position: "absolute", width: 0, height: 0, pointerEvents: "none" }, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("filter", { id: filterId, x: "0", y: "0", width: "100%", height: "100%", colorInterpolationFilters: "sRGB", children: [
287
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feGaussianBlur", { ref: blurRef, in: "SourceGraphic", stdDeviation: CONFIG.initial.blur, result: "blurred_bg", edgeMode: "duplicate" }),
288
+ maps && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
289
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feImage", { href: maps.displacement, result: "disp_map", x: PADDING, y: PADDING, width, height, preserveAspectRatio: "none" }),
290
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feGaussianBlur", { in: "disp_map", stdDeviation: smoothness, result: "disp_blurred", edgeMode: "duplicate" }),
291
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feDisplacementMap", { ref: displacerR, in: "blurred_bg", in2: "disp_blurred", scale: CONFIG.initial.displacement + chroma, xChannelSelector: "R", yChannelSelector: "G", result: "displaced_r" }),
292
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feColorMatrix", { in: "displaced_r", type: "matrix", values: "1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0", result: "red_channel" }),
293
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feDisplacementMap", { ref: displacerG, in: "blurred_bg", in2: "disp_blurred", scale: CONFIG.initial.displacement, xChannelSelector: "R", yChannelSelector: "G", result: "displaced_g" }),
294
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feColorMatrix", { in: "displaced_g", type: "matrix", values: "0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0", result: "green_channel" }),
295
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feDisplacementMap", { ref: displacerB, in: "blurred_bg", in2: "disp_blurred", scale: CONFIG.initial.displacement - chroma, xChannelSelector: "R", yChannelSelector: "G", result: "displaced_b" }),
296
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feColorMatrix", { in: "displaced_b", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0", result: "blue_channel" }),
297
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feBlend", { in: "red_channel", in2: "green_channel", mode: "screen", result: "rg_channels" }),
298
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feBlend", { in: "rg_channels", in2: "blue_channel", mode: "screen", result: "rgb_channels" }),
299
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("feColorMatrix", { in: "rgb_channels", type: "saturate", values: "1.2", result: "final" })
300
+ ] })
301
+ ] }) }) })
302
+ ] });
303
+ }
304
+ );
305
+ // Annotate the CommonJS export names for ESM import in node:
306
+ 0 && (module.exports = {
307
+ LiquidGlassButton,
308
+ cn,
309
+ generateGlassMaps
310
+ });
311
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/liquid-glass-button.tsx","../src/utils.ts","../src/generate-displacement-map.ts"],"sourcesContent":["export { LiquidGlassButton } from \"./liquid-glass-button\";\nexport type { LiquidGlassButtonProps } from \"./liquid-glass-button\";\nexport { generateGlassMaps } from \"./generate-displacement-map\";\nexport type { MapOptions } from \"./generate-displacement-map\";\nexport { cn } from \"./utils\";\n","import React, { useRef, useEffect, useState, useId, forwardRef } from \"react\";\nimport gsap from \"gsap\";\nimport { cn } from \"./utils\";\nimport { generateGlassMaps } from \"./generate-displacement-map\";\n\nconst CONFIG = {\n initial: { scale: 1, displacement: 35, blur: 2, chroma: 3 },\n hover: { scale: 1.05, displacement: 65, blur: 4, chroma: 10 },\n click: { scaleDown: 0.95, scaleUp: 1.05 },\n duration: { hover: 0.4, clickDown: 0.1, clickUp: 0.3 },\n ease: {\n hover: \"power3.out\",\n hoverOut: \"power2.out\",\n clickDown: \"power2.in\",\n clickUp: \"back.out(2)\",\n },\n} as const;\n\nconst PADDING = 60;\n\nexport interface LiquidGlassButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n width?: number;\n height?: number;\n radius?: number;\n edgeSize?: number;\n intensity?: number;\n smoothness?: number;\n distortion?: number;\n chroma?: number;\n glassColor?: string;\n}\n\nexport const LiquidGlassButton = forwardRef<HTMLButtonElement, LiquidGlassButtonProps>(\n function LiquidGlassButton({ children, className, width = 300, height = 56, radius = 60, edgeSize, intensity, smoothness = 1, distortion, chroma = 3, glassColor = \"rgba(255,255,255,0.05)\", style, ...props }, ref) {\n const internalRef = useRef<HTMLButtonElement>(null);\n const buttonRef = (ref as React.RefObject<HTMLButtonElement>) ?? internalRef;\n\n const blurRef = useRef<SVGFEGaussianBlurElement>(null);\n const displacerR = useRef<SVGFEDisplacementMapElement>(null);\n const displacerG = useRef<SVGFEDisplacementMapElement>(null);\n const displacerB = useRef<SVGFEDisplacementMapElement>(null);\n\n const filterId = \"lg\" + useId().replace(/:/g, \"\");\n\n const [maps, setMaps] = useState<{ displacement: string } | null>(null);\n\n useEffect(() => {\n const result = generateGlassMaps({ width, height, radius, edgeSize, intensity, distortion });\n setMaps(result);\n }, [width, height, radius, edgeSize, intensity, distortion]);\n\n useEffect(() => {\n const button = buttonRef.current;\n if (!button || !blurRef.current) return;\n\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n\n const fx = {\n displacement: CONFIG.initial.displacement,\n blur: CONFIG.initial.blur,\n chroma: chroma\n };\n\n const sync = () => {\n displacerR.current?.setAttribute(\"scale\", (fx.displacement + fx.chroma).toString());\n displacerG.current?.setAttribute(\"scale\", fx.displacement.toString());\n displacerB.current?.setAttribute(\"scale\", (fx.displacement - fx.chroma).toString());\n blurRef.current?.setAttribute(\"stdDeviation\", fx.blur.toString());\n };\n\n sync();\n\n const onEnter = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: CONFIG.hover.displacement,\n blur: CONFIG.hover.blur,\n chroma: chroma * 2.5,\n duration: CONFIG.duration.hover,\n ease: CONFIG.ease.hover,\n onUpdate: sync\n });\n gsap.to(button, { scale: CONFIG.hover.scale, duration: CONFIG.duration.hover, ease: CONFIG.ease.hover });\n };\n\n const onLeave = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: CONFIG.initial.displacement,\n blur: CONFIG.initial.blur,\n chroma: chroma,\n duration: CONFIG.duration.hover,\n ease: CONFIG.ease.hoverOut,\n onUpdate: sync\n });\n gsap.to(button, { scale: CONFIG.initial.scale, duration: CONFIG.duration.hover, ease: CONFIG.ease.hoverOut });\n };\n\n const onClick = () => {\n gsap.killTweensOf(button);\n const cur = gsap.getProperty(button, \"scale\") as number;\n gsap.timeline()\n .to(button, { scale: cur * CONFIG.click.scaleDown, duration: CONFIG.duration.clickDown, ease: CONFIG.ease.clickDown })\n .to(button, { scale: CONFIG.click.scaleUp, duration: CONFIG.duration.clickUp, ease: CONFIG.ease.clickUp });\n };\n\n button.addEventListener(\"pointerenter\", onEnter);\n button.addEventListener(\"pointerleave\", onLeave);\n button.addEventListener(\"click\", onClick);\n\n return () => {\n button.removeEventListener(\"pointerenter\", onEnter);\n button.removeEventListener(\"pointerleave\", onLeave);\n button.removeEventListener(\"click\", onClick);\n gsap.killTweensOf([button, fx]);\n };\n }, [buttonRef, maps, chroma]);\n\n return (\n <>\n <button\n ref={buttonRef}\n className={cn(\"relative overflow-hidden shadow-2xl shadow-black/20 cursor-pointer\", className)}\n style={{ width, height, borderRadius: radius, border: \"none\", background: glassColor, ...style }}\n {...props}\n >\n <div\n className=\"absolute z-0\"\n style={{\n top: -PADDING, left: -PADDING, right: -PADDING, bottom: -PADDING,\n backdropFilter: `url(#${filterId})`,\n WebkitBackdropFilter: `url(#${filterId})`\n }}\n />\n <div className=\"absolute inset-0 z-10 flex items-center justify-center font-bold text-white shadow-[inset_0_1px_1px_rgba(255,255,255,0.4)]\" style={{ background: \"linear-gradient(180deg, rgba(255,255,255,0.15) 0%, rgba(255,255,255,0.0) 100%)\", borderRadius: \"inherit\" }}>\n {children}\n </div>\n </button>\n\n <svg style={{ position: \"absolute\", width: 0, height: 0, pointerEvents: \"none\" }} aria-hidden=\"true\">\n <defs>\n <filter id={filterId} x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" colorInterpolationFilters=\"sRGB\">\n <feGaussianBlur ref={blurRef} in=\"SourceGraphic\" stdDeviation={CONFIG.initial.blur} result=\"blurred_bg\" edgeMode=\"duplicate\" />\n\n {maps && (\n <>\n <feImage href={maps.displacement} result=\"disp_map\" x={PADDING} y={PADDING} width={width} height={height} preserveAspectRatio=\"none\" />\n\n <feGaussianBlur in=\"disp_map\" stdDeviation={smoothness} result=\"disp_blurred\" edgeMode=\"duplicate\" />\n\n <feDisplacementMap ref={displacerR} in=\"blurred_bg\" in2=\"disp_blurred\" scale={CONFIG.initial.displacement + chroma} xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"displaced_r\" />\n <feColorMatrix in=\"displaced_r\" type=\"matrix\" values=\"1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0\" result=\"red_channel\" />\n\n <feDisplacementMap ref={displacerG} in=\"blurred_bg\" in2=\"disp_blurred\" scale={CONFIG.initial.displacement} xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"displaced_g\" />\n <feColorMatrix in=\"displaced_g\" type=\"matrix\" values=\"0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0\" result=\"green_channel\" />\n\n <feDisplacementMap ref={displacerB} in=\"blurred_bg\" in2=\"disp_blurred\" scale={CONFIG.initial.displacement - chroma} xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"displaced_b\" />\n <feColorMatrix in=\"displaced_b\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0\" result=\"blue_channel\" />\n\n <feBlend in=\"red_channel\" in2=\"green_channel\" mode=\"screen\" result=\"rg_channels\" />\n <feBlend in=\"rg_channels\" in2=\"blue_channel\" mode=\"screen\" result=\"rgb_channels\" />\n\n <feColorMatrix in=\"rgb_channels\" type=\"saturate\" values=\"1.2\" result=\"final\" />\n </>\n )}\n </filter>\n </defs>\n </svg>\n </>\n );\n }\n);\n","export function cn(...classes: (string | undefined | null | false)[]) {\n return classes.filter(Boolean).join(\" \");\n}\n","export interface MapOptions {\n width: number;\n height: number;\n radius?: number;\n edgeSize?: number;\n intensity?: number;\n distortion?: number;\n}\n\nconst VERT = `attribute vec4 position; void main(){ gl_Position = position; }`;\n\nconst FRAG = `\nprecision mediump float;\nuniform vec2 uRes;\nuniform float uRadius;\nuniform float uEdgeSize;\nuniform float uIntensity;\nuniform float uDistortion;\n\nfloat sdRoundedBox(vec2 p, vec2 b, float r){\n r = min(r, min(b.x, b.y));\n vec2 q = abs(p) - b + r;\n return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;\n}\n\nfloat getHeight(vec2 p) {\n vec2 halfSize = uRes * 0.5 - 2.0;\n\n // Aumenta o tamanho base do box ligeiramente proporcinal ao edge\n halfSize += uEdgeSize * 0.2;\n\n float d = sdRoundedBox(p, halfSize, uRadius);\n\n float borderSoftness = uEdgeSize * uIntensity;\n d = max(d, -borderSoftness);\n return smoothstep(0.0, -borderSoftness, d);\n}\n\nvoid main(){\n vec2 p = gl_FragCoord.xy - uRes * 0.5;\n p.y = -p.y;\n\n // --- Displacement Map ---\n const vec2 e = vec2(1.0, 0.0);\n float hx = getHeight(p + e.xy) - getHeight(p - e.xy);\n float hy = getHeight(p + e.yx) - getHeight(p - e.yx);\n\n vec2 normal = vec2(-hx, -hy) * uDistortion;\n vec2 color = clamp(normal * 0.5 + 0.5, 0.0, 1.0);\n\n gl_FragColor = vec4(color.x, color.y, 0.5, 1.0);\n}\n`;\n\nfunction compile(gl: WebGLRenderingContext, type: number, src: string) {\n const s = gl.createShader(type)!;\n gl.shaderSource(s, src);\n gl.compileShader(s);\n return s;\n}\n\nlet _cachedProgram: { gl: WebGLRenderingContext; program: WebGLProgram; canvas: HTMLCanvasElement } | null = null;\n\nfunction getGL() {\n if (_cachedProgram) return _cachedProgram;\n\n const canvas = document.createElement(\"canvas\");\n const gl = canvas.getContext(\"webgl\", { preserveDrawingBuffer: true, premultipliedAlpha: false })!;\n\n const vs = compile(gl, gl.VERTEX_SHADER, VERT);\n const fs = compile(gl, gl.FRAGMENT_SHADER, FRAG);\n const program = gl.createProgram()!;\n gl.attachShader(program, vs);\n gl.attachShader(program, fs);\n gl.linkProgram(program);\n gl.useProgram(program);\n\n const buf = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);\n const pos = gl.getAttribLocation(program, \"position\");\n gl.enableVertexAttribArray(pos);\n gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);\n\n _cachedProgram = { gl, program, canvas };\n return _cachedProgram;\n}\n\nfunction render(width: number, height: number, radius: number, edgeSize: number, intensity: number, distortion: number): string {\n const { gl, program, canvas } = getGL();\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, width, height);\n gl.clearColor(0.5, 0.5, 0.5, 1.0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.useProgram(program);\n\n gl.uniform2f(gl.getUniformLocation(program, \"uRes\"), width, height);\n gl.uniform1f(gl.getUniformLocation(program, \"uRadius\"), radius);\n gl.uniform1f(gl.getUniformLocation(program, \"uEdgeSize\"), edgeSize);\n gl.uniform1f(gl.getUniformLocation(program, \"uIntensity\"), intensity);\n gl.uniform1f(gl.getUniformLocation(program, \"uDistortion\"), distortion);\n\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n return canvas.toDataURL(\"image/png\");\n}\n\nexport function generateGlassMaps(opts: MapOptions): { displacement: string } {\n const { width, height, radius = 60, edgeSize = 40, intensity = 1.0, distortion = 15.0 } = opts;\n const r = Math.min(radius, width / 2, height / 2);\n\n return {\n displacement: render(width, height, r, edgeSize, intensity, distortion),\n };\n}\n"],"mappings":"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","names":["LiquidGlassButton","_a","_b","gsap"]}
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+
3
+ interface LiquidGlassButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
+ width?: number;
5
+ height?: number;
6
+ radius?: number;
7
+ edgeSize?: number;
8
+ intensity?: number;
9
+ smoothness?: number;
10
+ distortion?: number;
11
+ chroma?: number;
12
+ glassColor?: string;
13
+ }
14
+ declare const LiquidGlassButton: React.ForwardRefExoticComponent<LiquidGlassButtonProps & React.RefAttributes<HTMLButtonElement>>;
15
+
16
+ interface MapOptions {
17
+ width: number;
18
+ height: number;
19
+ radius?: number;
20
+ edgeSize?: number;
21
+ intensity?: number;
22
+ distortion?: number;
23
+ }
24
+ declare function generateGlassMaps(opts: MapOptions): {
25
+ displacement: string;
26
+ };
27
+
28
+ declare function cn(...classes: (string | undefined | null | false)[]): string;
29
+
30
+ export { LiquidGlassButton, type LiquidGlassButtonProps, type MapOptions, cn, generateGlassMaps };
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+
3
+ interface LiquidGlassButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
+ width?: number;
5
+ height?: number;
6
+ radius?: number;
7
+ edgeSize?: number;
8
+ intensity?: number;
9
+ smoothness?: number;
10
+ distortion?: number;
11
+ chroma?: number;
12
+ glassColor?: string;
13
+ }
14
+ declare const LiquidGlassButton: React.ForwardRefExoticComponent<LiquidGlassButtonProps & React.RefAttributes<HTMLButtonElement>>;
15
+
16
+ interface MapOptions {
17
+ width: number;
18
+ height: number;
19
+ radius?: number;
20
+ edgeSize?: number;
21
+ intensity?: number;
22
+ distortion?: number;
23
+ }
24
+ declare function generateGlassMaps(opts: MapOptions): {
25
+ displacement: string;
26
+ };
27
+
28
+ declare function cn(...classes: (string | undefined | null | false)[]): string;
29
+
30
+ export { LiquidGlassButton, type LiquidGlassButtonProps, type MapOptions, cn, generateGlassMaps };
package/dist/index.js ADDED
@@ -0,0 +1,275 @@
1
+ "use client";
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __spreadValues = (a, b) => {
10
+ for (var prop in b || (b = {}))
11
+ if (__hasOwnProp.call(b, prop))
12
+ __defNormalProp(a, prop, b[prop]);
13
+ if (__getOwnPropSymbols)
14
+ for (var prop of __getOwnPropSymbols(b)) {
15
+ if (__propIsEnum.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ }
18
+ return a;
19
+ };
20
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
+ var __objRest = (source, exclude) => {
22
+ var target = {};
23
+ for (var prop in source)
24
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
25
+ target[prop] = source[prop];
26
+ if (source != null && __getOwnPropSymbols)
27
+ for (var prop of __getOwnPropSymbols(source)) {
28
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
29
+ target[prop] = source[prop];
30
+ }
31
+ return target;
32
+ };
33
+
34
+ // src/liquid-glass-button.tsx
35
+ import { useRef, useEffect, useState, useId, forwardRef } from "react";
36
+ import gsap from "gsap";
37
+
38
+ // src/utils.ts
39
+ function cn(...classes) {
40
+ return classes.filter(Boolean).join(" ");
41
+ }
42
+
43
+ // src/generate-displacement-map.ts
44
+ var VERT = `attribute vec4 position; void main(){ gl_Position = position; }`;
45
+ var FRAG = `
46
+ precision mediump float;
47
+ uniform vec2 uRes;
48
+ uniform float uRadius;
49
+ uniform float uEdgeSize;
50
+ uniform float uIntensity;
51
+ uniform float uDistortion;
52
+
53
+ float sdRoundedBox(vec2 p, vec2 b, float r){
54
+ r = min(r, min(b.x, b.y));
55
+ vec2 q = abs(p) - b + r;
56
+ return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
57
+ }
58
+
59
+ float getHeight(vec2 p) {
60
+ vec2 halfSize = uRes * 0.5 - 2.0;
61
+
62
+ // Aumenta o tamanho base do box ligeiramente proporcinal ao edge
63
+ halfSize += uEdgeSize * 0.2;
64
+
65
+ float d = sdRoundedBox(p, halfSize, uRadius);
66
+
67
+ float borderSoftness = uEdgeSize * uIntensity;
68
+ d = max(d, -borderSoftness);
69
+ return smoothstep(0.0, -borderSoftness, d);
70
+ }
71
+
72
+ void main(){
73
+ vec2 p = gl_FragCoord.xy - uRes * 0.5;
74
+ p.y = -p.y;
75
+
76
+ // --- Displacement Map ---
77
+ const vec2 e = vec2(1.0, 0.0);
78
+ float hx = getHeight(p + e.xy) - getHeight(p - e.xy);
79
+ float hy = getHeight(p + e.yx) - getHeight(p - e.yx);
80
+
81
+ vec2 normal = vec2(-hx, -hy) * uDistortion;
82
+ vec2 color = clamp(normal * 0.5 + 0.5, 0.0, 1.0);
83
+
84
+ gl_FragColor = vec4(color.x, color.y, 0.5, 1.0);
85
+ }
86
+ `;
87
+ function compile(gl, type, src) {
88
+ const s = gl.createShader(type);
89
+ gl.shaderSource(s, src);
90
+ gl.compileShader(s);
91
+ return s;
92
+ }
93
+ var _cachedProgram = null;
94
+ function getGL() {
95
+ if (_cachedProgram) return _cachedProgram;
96
+ const canvas = document.createElement("canvas");
97
+ const gl = canvas.getContext("webgl", { preserveDrawingBuffer: true, premultipliedAlpha: false });
98
+ const vs = compile(gl, gl.VERTEX_SHADER, VERT);
99
+ const fs = compile(gl, gl.FRAGMENT_SHADER, FRAG);
100
+ const program = gl.createProgram();
101
+ gl.attachShader(program, vs);
102
+ gl.attachShader(program, fs);
103
+ gl.linkProgram(program);
104
+ gl.useProgram(program);
105
+ const buf = gl.createBuffer();
106
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
107
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
108
+ const pos = gl.getAttribLocation(program, "position");
109
+ gl.enableVertexAttribArray(pos);
110
+ gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
111
+ _cachedProgram = { gl, program, canvas };
112
+ return _cachedProgram;
113
+ }
114
+ function render(width, height, radius, edgeSize, intensity, distortion) {
115
+ const { gl, program, canvas } = getGL();
116
+ canvas.width = width;
117
+ canvas.height = height;
118
+ gl.viewport(0, 0, width, height);
119
+ gl.clearColor(0.5, 0.5, 0.5, 1);
120
+ gl.clear(gl.COLOR_BUFFER_BIT);
121
+ gl.useProgram(program);
122
+ gl.uniform2f(gl.getUniformLocation(program, "uRes"), width, height);
123
+ gl.uniform1f(gl.getUniformLocation(program, "uRadius"), radius);
124
+ gl.uniform1f(gl.getUniformLocation(program, "uEdgeSize"), edgeSize);
125
+ gl.uniform1f(gl.getUniformLocation(program, "uIntensity"), intensity);
126
+ gl.uniform1f(gl.getUniformLocation(program, "uDistortion"), distortion);
127
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
128
+ return canvas.toDataURL("image/png");
129
+ }
130
+ function generateGlassMaps(opts) {
131
+ const { width, height, radius = 60, edgeSize = 40, intensity = 1, distortion = 15 } = opts;
132
+ const r = Math.min(radius, width / 2, height / 2);
133
+ return {
134
+ displacement: render(width, height, r, edgeSize, intensity, distortion)
135
+ };
136
+ }
137
+
138
+ // src/liquid-glass-button.tsx
139
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
140
+ var CONFIG = {
141
+ initial: { scale: 1, displacement: 35, blur: 2, chroma: 3 },
142
+ hover: { scale: 1.05, displacement: 65, blur: 4, chroma: 10 },
143
+ click: { scaleDown: 0.95, scaleUp: 1.05 },
144
+ duration: { hover: 0.4, clickDown: 0.1, clickUp: 0.3 },
145
+ ease: {
146
+ hover: "power3.out",
147
+ hoverOut: "power2.out",
148
+ clickDown: "power2.in",
149
+ clickUp: "back.out(2)"
150
+ }
151
+ };
152
+ var PADDING = 60;
153
+ var LiquidGlassButton = forwardRef(
154
+ function LiquidGlassButton2(_a, ref) {
155
+ var _b = _a, { children, className, width = 300, height = 56, radius = 60, edgeSize, intensity, smoothness = 1, distortion, chroma = 3, glassColor = "rgba(255,255,255,0.05)", style } = _b, props = __objRest(_b, ["children", "className", "width", "height", "radius", "edgeSize", "intensity", "smoothness", "distortion", "chroma", "glassColor", "style"]);
156
+ const internalRef = useRef(null);
157
+ const buttonRef = ref != null ? ref : internalRef;
158
+ const blurRef = useRef(null);
159
+ const displacerR = useRef(null);
160
+ const displacerG = useRef(null);
161
+ const displacerB = useRef(null);
162
+ const filterId = "lg" + useId().replace(/:/g, "");
163
+ const [maps, setMaps] = useState(null);
164
+ useEffect(() => {
165
+ const result = generateGlassMaps({ width, height, radius, edgeSize, intensity, distortion });
166
+ setMaps(result);
167
+ }, [width, height, radius, edgeSize, intensity, distortion]);
168
+ useEffect(() => {
169
+ const button = buttonRef.current;
170
+ if (!button || !blurRef.current) return;
171
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
172
+ const fx = {
173
+ displacement: CONFIG.initial.displacement,
174
+ blur: CONFIG.initial.blur,
175
+ chroma
176
+ };
177
+ const sync = () => {
178
+ var _a2, _b2, _c, _d;
179
+ (_a2 = displacerR.current) == null ? void 0 : _a2.setAttribute("scale", (fx.displacement + fx.chroma).toString());
180
+ (_b2 = displacerG.current) == null ? void 0 : _b2.setAttribute("scale", fx.displacement.toString());
181
+ (_c = displacerB.current) == null ? void 0 : _c.setAttribute("scale", (fx.displacement - fx.chroma).toString());
182
+ (_d = blurRef.current) == null ? void 0 : _d.setAttribute("stdDeviation", fx.blur.toString());
183
+ };
184
+ sync();
185
+ const onEnter = () => {
186
+ gsap.killTweensOf([fx, button]);
187
+ gsap.to(fx, {
188
+ displacement: CONFIG.hover.displacement,
189
+ blur: CONFIG.hover.blur,
190
+ chroma: chroma * 2.5,
191
+ duration: CONFIG.duration.hover,
192
+ ease: CONFIG.ease.hover,
193
+ onUpdate: sync
194
+ });
195
+ gsap.to(button, { scale: CONFIG.hover.scale, duration: CONFIG.duration.hover, ease: CONFIG.ease.hover });
196
+ };
197
+ const onLeave = () => {
198
+ gsap.killTweensOf([fx, button]);
199
+ gsap.to(fx, {
200
+ displacement: CONFIG.initial.displacement,
201
+ blur: CONFIG.initial.blur,
202
+ chroma,
203
+ duration: CONFIG.duration.hover,
204
+ ease: CONFIG.ease.hoverOut,
205
+ onUpdate: sync
206
+ });
207
+ gsap.to(button, { scale: CONFIG.initial.scale, duration: CONFIG.duration.hover, ease: CONFIG.ease.hoverOut });
208
+ };
209
+ const onClick = () => {
210
+ gsap.killTweensOf(button);
211
+ const cur = gsap.getProperty(button, "scale");
212
+ gsap.timeline().to(button, { scale: cur * CONFIG.click.scaleDown, duration: CONFIG.duration.clickDown, ease: CONFIG.ease.clickDown }).to(button, { scale: CONFIG.click.scaleUp, duration: CONFIG.duration.clickUp, ease: CONFIG.ease.clickUp });
213
+ };
214
+ button.addEventListener("pointerenter", onEnter);
215
+ button.addEventListener("pointerleave", onLeave);
216
+ button.addEventListener("click", onClick);
217
+ return () => {
218
+ button.removeEventListener("pointerenter", onEnter);
219
+ button.removeEventListener("pointerleave", onLeave);
220
+ button.removeEventListener("click", onClick);
221
+ gsap.killTweensOf([button, fx]);
222
+ };
223
+ }, [buttonRef, maps, chroma]);
224
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
225
+ /* @__PURE__ */ jsxs(
226
+ "button",
227
+ __spreadProps(__spreadValues({
228
+ ref: buttonRef,
229
+ className: cn("relative overflow-hidden shadow-2xl shadow-black/20 cursor-pointer", className),
230
+ style: __spreadValues({ width, height, borderRadius: radius, border: "none", background: glassColor }, style)
231
+ }, props), {
232
+ children: [
233
+ /* @__PURE__ */ jsx(
234
+ "div",
235
+ {
236
+ className: "absolute z-0",
237
+ style: {
238
+ top: -PADDING,
239
+ left: -PADDING,
240
+ right: -PADDING,
241
+ bottom: -PADDING,
242
+ backdropFilter: `url(#${filterId})`,
243
+ WebkitBackdropFilter: `url(#${filterId})`
244
+ }
245
+ }
246
+ ),
247
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-10 flex items-center justify-center font-bold text-white shadow-[inset_0_1px_1px_rgba(255,255,255,0.4)]", style: { background: "linear-gradient(180deg, rgba(255,255,255,0.15) 0%, rgba(255,255,255,0.0) 100%)", borderRadius: "inherit" }, children })
248
+ ]
249
+ })
250
+ ),
251
+ /* @__PURE__ */ jsx("svg", { style: { position: "absolute", width: 0, height: 0, pointerEvents: "none" }, "aria-hidden": "true", children: /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("filter", { id: filterId, x: "0", y: "0", width: "100%", height: "100%", colorInterpolationFilters: "sRGB", children: [
252
+ /* @__PURE__ */ jsx("feGaussianBlur", { ref: blurRef, in: "SourceGraphic", stdDeviation: CONFIG.initial.blur, result: "blurred_bg", edgeMode: "duplicate" }),
253
+ maps && /* @__PURE__ */ jsxs(Fragment, { children: [
254
+ /* @__PURE__ */ jsx("feImage", { href: maps.displacement, result: "disp_map", x: PADDING, y: PADDING, width, height, preserveAspectRatio: "none" }),
255
+ /* @__PURE__ */ jsx("feGaussianBlur", { in: "disp_map", stdDeviation: smoothness, result: "disp_blurred", edgeMode: "duplicate" }),
256
+ /* @__PURE__ */ jsx("feDisplacementMap", { ref: displacerR, in: "blurred_bg", in2: "disp_blurred", scale: CONFIG.initial.displacement + chroma, xChannelSelector: "R", yChannelSelector: "G", result: "displaced_r" }),
257
+ /* @__PURE__ */ jsx("feColorMatrix", { in: "displaced_r", type: "matrix", values: "1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0", result: "red_channel" }),
258
+ /* @__PURE__ */ jsx("feDisplacementMap", { ref: displacerG, in: "blurred_bg", in2: "disp_blurred", scale: CONFIG.initial.displacement, xChannelSelector: "R", yChannelSelector: "G", result: "displaced_g" }),
259
+ /* @__PURE__ */ jsx("feColorMatrix", { in: "displaced_g", type: "matrix", values: "0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0", result: "green_channel" }),
260
+ /* @__PURE__ */ jsx("feDisplacementMap", { ref: displacerB, in: "blurred_bg", in2: "disp_blurred", scale: CONFIG.initial.displacement - chroma, xChannelSelector: "R", yChannelSelector: "G", result: "displaced_b" }),
261
+ /* @__PURE__ */ jsx("feColorMatrix", { in: "displaced_b", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0", result: "blue_channel" }),
262
+ /* @__PURE__ */ jsx("feBlend", { in: "red_channel", in2: "green_channel", mode: "screen", result: "rg_channels" }),
263
+ /* @__PURE__ */ jsx("feBlend", { in: "rg_channels", in2: "blue_channel", mode: "screen", result: "rgb_channels" }),
264
+ /* @__PURE__ */ jsx("feColorMatrix", { in: "rgb_channels", type: "saturate", values: "1.2", result: "final" })
265
+ ] })
266
+ ] }) }) })
267
+ ] });
268
+ }
269
+ );
270
+ export {
271
+ LiquidGlassButton,
272
+ cn,
273
+ generateGlassMaps
274
+ };
275
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/liquid-glass-button.tsx","../src/utils.ts","../src/generate-displacement-map.ts"],"sourcesContent":["import React, { useRef, useEffect, useState, useId, forwardRef } from \"react\";\nimport gsap from \"gsap\";\nimport { cn } from \"./utils\";\nimport { generateGlassMaps } from \"./generate-displacement-map\";\n\nconst CONFIG = {\n initial: { scale: 1, displacement: 35, blur: 2, chroma: 3 },\n hover: { scale: 1.05, displacement: 65, blur: 4, chroma: 10 },\n click: { scaleDown: 0.95, scaleUp: 1.05 },\n duration: { hover: 0.4, clickDown: 0.1, clickUp: 0.3 },\n ease: {\n hover: \"power3.out\",\n hoverOut: \"power2.out\",\n clickDown: \"power2.in\",\n clickUp: \"back.out(2)\",\n },\n} as const;\n\nconst PADDING = 60;\n\nexport interface LiquidGlassButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n width?: number;\n height?: number;\n radius?: number;\n edgeSize?: number;\n intensity?: number;\n smoothness?: number;\n distortion?: number;\n chroma?: number;\n glassColor?: string;\n}\n\nexport const LiquidGlassButton = forwardRef<HTMLButtonElement, LiquidGlassButtonProps>(\n function LiquidGlassButton({ children, className, width = 300, height = 56, radius = 60, edgeSize, intensity, smoothness = 1, distortion, chroma = 3, glassColor = \"rgba(255,255,255,0.05)\", style, ...props }, ref) {\n const internalRef = useRef<HTMLButtonElement>(null);\n const buttonRef = (ref as React.RefObject<HTMLButtonElement>) ?? internalRef;\n\n const blurRef = useRef<SVGFEGaussianBlurElement>(null);\n const displacerR = useRef<SVGFEDisplacementMapElement>(null);\n const displacerG = useRef<SVGFEDisplacementMapElement>(null);\n const displacerB = useRef<SVGFEDisplacementMapElement>(null);\n\n const filterId = \"lg\" + useId().replace(/:/g, \"\");\n\n const [maps, setMaps] = useState<{ displacement: string } | null>(null);\n\n useEffect(() => {\n const result = generateGlassMaps({ width, height, radius, edgeSize, intensity, distortion });\n setMaps(result);\n }, [width, height, radius, edgeSize, intensity, distortion]);\n\n useEffect(() => {\n const button = buttonRef.current;\n if (!button || !blurRef.current) return;\n\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n\n const fx = {\n displacement: CONFIG.initial.displacement,\n blur: CONFIG.initial.blur,\n chroma: chroma\n };\n\n const sync = () => {\n displacerR.current?.setAttribute(\"scale\", (fx.displacement + fx.chroma).toString());\n displacerG.current?.setAttribute(\"scale\", fx.displacement.toString());\n displacerB.current?.setAttribute(\"scale\", (fx.displacement - fx.chroma).toString());\n blurRef.current?.setAttribute(\"stdDeviation\", fx.blur.toString());\n };\n\n sync();\n\n const onEnter = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: CONFIG.hover.displacement,\n blur: CONFIG.hover.blur,\n chroma: chroma * 2.5,\n duration: CONFIG.duration.hover,\n ease: CONFIG.ease.hover,\n onUpdate: sync\n });\n gsap.to(button, { scale: CONFIG.hover.scale, duration: CONFIG.duration.hover, ease: CONFIG.ease.hover });\n };\n\n const onLeave = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: CONFIG.initial.displacement,\n blur: CONFIG.initial.blur,\n chroma: chroma,\n duration: CONFIG.duration.hover,\n ease: CONFIG.ease.hoverOut,\n onUpdate: sync\n });\n gsap.to(button, { scale: CONFIG.initial.scale, duration: CONFIG.duration.hover, ease: CONFIG.ease.hoverOut });\n };\n\n const onClick = () => {\n gsap.killTweensOf(button);\n const cur = gsap.getProperty(button, \"scale\") as number;\n gsap.timeline()\n .to(button, { scale: cur * CONFIG.click.scaleDown, duration: CONFIG.duration.clickDown, ease: CONFIG.ease.clickDown })\n .to(button, { scale: CONFIG.click.scaleUp, duration: CONFIG.duration.clickUp, ease: CONFIG.ease.clickUp });\n };\n\n button.addEventListener(\"pointerenter\", onEnter);\n button.addEventListener(\"pointerleave\", onLeave);\n button.addEventListener(\"click\", onClick);\n\n return () => {\n button.removeEventListener(\"pointerenter\", onEnter);\n button.removeEventListener(\"pointerleave\", onLeave);\n button.removeEventListener(\"click\", onClick);\n gsap.killTweensOf([button, fx]);\n };\n }, [buttonRef, maps, chroma]);\n\n return (\n <>\n <button\n ref={buttonRef}\n className={cn(\"relative overflow-hidden shadow-2xl shadow-black/20 cursor-pointer\", className)}\n style={{ width, height, borderRadius: radius, border: \"none\", background: glassColor, ...style }}\n {...props}\n >\n <div\n className=\"absolute z-0\"\n style={{\n top: -PADDING, left: -PADDING, right: -PADDING, bottom: -PADDING,\n backdropFilter: `url(#${filterId})`,\n WebkitBackdropFilter: `url(#${filterId})`\n }}\n />\n <div className=\"absolute inset-0 z-10 flex items-center justify-center font-bold text-white shadow-[inset_0_1px_1px_rgba(255,255,255,0.4)]\" style={{ background: \"linear-gradient(180deg, rgba(255,255,255,0.15) 0%, rgba(255,255,255,0.0) 100%)\", borderRadius: \"inherit\" }}>\n {children}\n </div>\n </button>\n\n <svg style={{ position: \"absolute\", width: 0, height: 0, pointerEvents: \"none\" }} aria-hidden=\"true\">\n <defs>\n <filter id={filterId} x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" colorInterpolationFilters=\"sRGB\">\n <feGaussianBlur ref={blurRef} in=\"SourceGraphic\" stdDeviation={CONFIG.initial.blur} result=\"blurred_bg\" edgeMode=\"duplicate\" />\n\n {maps && (\n <>\n <feImage href={maps.displacement} result=\"disp_map\" x={PADDING} y={PADDING} width={width} height={height} preserveAspectRatio=\"none\" />\n\n <feGaussianBlur in=\"disp_map\" stdDeviation={smoothness} result=\"disp_blurred\" edgeMode=\"duplicate\" />\n\n <feDisplacementMap ref={displacerR} in=\"blurred_bg\" in2=\"disp_blurred\" scale={CONFIG.initial.displacement + chroma} xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"displaced_r\" />\n <feColorMatrix in=\"displaced_r\" type=\"matrix\" values=\"1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0\" result=\"red_channel\" />\n\n <feDisplacementMap ref={displacerG} in=\"blurred_bg\" in2=\"disp_blurred\" scale={CONFIG.initial.displacement} xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"displaced_g\" />\n <feColorMatrix in=\"displaced_g\" type=\"matrix\" values=\"0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0\" result=\"green_channel\" />\n\n <feDisplacementMap ref={displacerB} in=\"blurred_bg\" in2=\"disp_blurred\" scale={CONFIG.initial.displacement - chroma} xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"displaced_b\" />\n <feColorMatrix in=\"displaced_b\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0\" result=\"blue_channel\" />\n\n <feBlend in=\"red_channel\" in2=\"green_channel\" mode=\"screen\" result=\"rg_channels\" />\n <feBlend in=\"rg_channels\" in2=\"blue_channel\" mode=\"screen\" result=\"rgb_channels\" />\n\n <feColorMatrix in=\"rgb_channels\" type=\"saturate\" values=\"1.2\" result=\"final\" />\n </>\n )}\n </filter>\n </defs>\n </svg>\n </>\n );\n }\n);\n","export function cn(...classes: (string | undefined | null | false)[]) {\n return classes.filter(Boolean).join(\" \");\n}\n","export interface MapOptions {\n width: number;\n height: number;\n radius?: number;\n edgeSize?: number;\n intensity?: number;\n distortion?: number;\n}\n\nconst VERT = `attribute vec4 position; void main(){ gl_Position = position; }`;\n\nconst FRAG = `\nprecision mediump float;\nuniform vec2 uRes;\nuniform float uRadius;\nuniform float uEdgeSize;\nuniform float uIntensity;\nuniform float uDistortion;\n\nfloat sdRoundedBox(vec2 p, vec2 b, float r){\n r = min(r, min(b.x, b.y));\n vec2 q = abs(p) - b + r;\n return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;\n}\n\nfloat getHeight(vec2 p) {\n vec2 halfSize = uRes * 0.5 - 2.0;\n\n // Aumenta o tamanho base do box ligeiramente proporcinal ao edge\n halfSize += uEdgeSize * 0.2;\n\n float d = sdRoundedBox(p, halfSize, uRadius);\n\n float borderSoftness = uEdgeSize * uIntensity;\n d = max(d, -borderSoftness);\n return smoothstep(0.0, -borderSoftness, d);\n}\n\nvoid main(){\n vec2 p = gl_FragCoord.xy - uRes * 0.5;\n p.y = -p.y;\n\n // --- Displacement Map ---\n const vec2 e = vec2(1.0, 0.0);\n float hx = getHeight(p + e.xy) - getHeight(p - e.xy);\n float hy = getHeight(p + e.yx) - getHeight(p - e.yx);\n\n vec2 normal = vec2(-hx, -hy) * uDistortion;\n vec2 color = clamp(normal * 0.5 + 0.5, 0.0, 1.0);\n\n gl_FragColor = vec4(color.x, color.y, 0.5, 1.0);\n}\n`;\n\nfunction compile(gl: WebGLRenderingContext, type: number, src: string) {\n const s = gl.createShader(type)!;\n gl.shaderSource(s, src);\n gl.compileShader(s);\n return s;\n}\n\nlet _cachedProgram: { gl: WebGLRenderingContext; program: WebGLProgram; canvas: HTMLCanvasElement } | null = null;\n\nfunction getGL() {\n if (_cachedProgram) return _cachedProgram;\n\n const canvas = document.createElement(\"canvas\");\n const gl = canvas.getContext(\"webgl\", { preserveDrawingBuffer: true, premultipliedAlpha: false })!;\n\n const vs = compile(gl, gl.VERTEX_SHADER, VERT);\n const fs = compile(gl, gl.FRAGMENT_SHADER, FRAG);\n const program = gl.createProgram()!;\n gl.attachShader(program, vs);\n gl.attachShader(program, fs);\n gl.linkProgram(program);\n gl.useProgram(program);\n\n const buf = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);\n const pos = gl.getAttribLocation(program, \"position\");\n gl.enableVertexAttribArray(pos);\n gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);\n\n _cachedProgram = { gl, program, canvas };\n return _cachedProgram;\n}\n\nfunction render(width: number, height: number, radius: number, edgeSize: number, intensity: number, distortion: number): string {\n const { gl, program, canvas } = getGL();\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, width, height);\n gl.clearColor(0.5, 0.5, 0.5, 1.0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.useProgram(program);\n\n gl.uniform2f(gl.getUniformLocation(program, \"uRes\"), width, height);\n gl.uniform1f(gl.getUniformLocation(program, \"uRadius\"), radius);\n gl.uniform1f(gl.getUniformLocation(program, \"uEdgeSize\"), edgeSize);\n gl.uniform1f(gl.getUniformLocation(program, \"uIntensity\"), intensity);\n gl.uniform1f(gl.getUniformLocation(program, \"uDistortion\"), distortion);\n\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n return canvas.toDataURL(\"image/png\");\n}\n\nexport function generateGlassMaps(opts: MapOptions): { displacement: string } {\n const { width, height, radius = 60, edgeSize = 40, intensity = 1.0, distortion = 15.0 } = opts;\n const r = Math.min(radius, width / 2, height / 2);\n\n return {\n displacement: render(width, height, r, edgeSize, intensity, distortion),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAgB,QAAQ,WAAW,UAAU,OAAO,kBAAkB;AACtE,OAAO,UAAU;;;ACDV,SAAS,MAAM,SAAgD;AACpE,SAAO,QAAQ,OAAO,OAAO,EAAE,KAAK,GAAG;AACzC;;;ACOA,IAAM,OAAO;AAEb,IAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2Cb,SAAS,QAAQ,IAA2B,MAAc,KAAa;AACrE,QAAM,IAAI,GAAG,aAAa,IAAI;AAC9B,KAAG,aAAa,GAAG,GAAG;AACtB,KAAG,cAAc,CAAC;AAClB,SAAO;AACT;AAEA,IAAI,iBAAyG;AAE7G,SAAS,QAAQ;AACf,MAAI,eAAgB,QAAO;AAE3B,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,QAAM,KAAK,OAAO,WAAW,SAAS,EAAE,uBAAuB,MAAM,oBAAoB,MAAM,CAAC;AAEhG,QAAM,KAAK,QAAQ,IAAI,GAAG,eAAe,IAAI;AAC7C,QAAM,KAAK,QAAQ,IAAI,GAAG,iBAAiB,IAAI;AAC/C,QAAM,UAAU,GAAG,cAAc;AACjC,KAAG,aAAa,SAAS,EAAE;AAC3B,KAAG,aAAa,SAAS,EAAE;AAC3B,KAAG,YAAY,OAAO;AACtB,KAAG,WAAW,OAAO;AAErB,QAAM,MAAM,GAAG,aAAa;AAC5B,KAAG,WAAW,GAAG,cAAc,GAAG;AAClC,KAAG,WAAW,GAAG,cAAc,IAAI,aAAa,CAAC,IAAI,IAAI,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,WAAW;AAC7F,QAAM,MAAM,GAAG,kBAAkB,SAAS,UAAU;AACpD,KAAG,wBAAwB,GAAG;AAC9B,KAAG,oBAAoB,KAAK,GAAG,GAAG,OAAO,OAAO,GAAG,CAAC;AAEpD,mBAAiB,EAAE,IAAI,SAAS,OAAO;AACvC,SAAO;AACT;AAEA,SAAS,OAAO,OAAe,QAAgB,QAAgB,UAAkB,WAAmB,YAA4B;AAC9H,QAAM,EAAE,IAAI,SAAS,OAAO,IAAI,MAAM;AACtC,SAAO,QAAQ;AACf,SAAO,SAAS;AAChB,KAAG,SAAS,GAAG,GAAG,OAAO,MAAM;AAC/B,KAAG,WAAW,KAAK,KAAK,KAAK,CAAG;AAChC,KAAG,MAAM,GAAG,gBAAgB;AAC5B,KAAG,WAAW,OAAO;AAErB,KAAG,UAAU,GAAG,mBAAmB,SAAS,MAAM,GAAG,OAAO,MAAM;AAClE,KAAG,UAAU,GAAG,mBAAmB,SAAS,SAAS,GAAG,MAAM;AAC9D,KAAG,UAAU,GAAG,mBAAmB,SAAS,WAAW,GAAG,QAAQ;AAClE,KAAG,UAAU,GAAG,mBAAmB,SAAS,YAAY,GAAG,SAAS;AACpE,KAAG,UAAU,GAAG,mBAAmB,SAAS,aAAa,GAAG,UAAU;AAEtE,KAAG,WAAW,GAAG,gBAAgB,GAAG,CAAC;AACrC,SAAO,OAAO,UAAU,WAAW;AACrC;AAEO,SAAS,kBAAkB,MAA4C;AAC5E,QAAM,EAAE,OAAO,QAAQ,SAAS,IAAI,WAAW,IAAI,YAAY,GAAK,aAAa,GAAK,IAAI;AAC1F,QAAM,IAAI,KAAK,IAAI,QAAQ,QAAQ,GAAG,SAAS,CAAC;AAEhD,SAAO;AAAA,IACL,cAAc,OAAO,OAAO,QAAQ,GAAG,UAAU,WAAW,UAAU;AAAA,EACxE;AACF;;;AFMQ,SAyBQ,UAnBN,KANF;AAnHR,IAAM,SAAS;AAAA,EACb,SAAS,EAAE,OAAO,GAAG,cAAc,IAAI,MAAM,GAAG,QAAQ,EAAE;AAAA,EAC1D,OAAO,EAAE,OAAO,MAAM,cAAc,IAAI,MAAM,GAAG,QAAQ,GAAG;AAAA,EAC5D,OAAO,EAAE,WAAW,MAAM,SAAS,KAAK;AAAA,EACxC,UAAU,EAAE,OAAO,KAAK,WAAW,KAAK,SAAS,IAAI;AAAA,EACrD,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX,SAAS;AAAA,EACX;AACF;AAEA,IAAM,UAAU;AAcT,IAAM,oBAAoB;AAAA,EAC/B,SAASA,mBAAkB,IAAqL,KAAK;AAA1L,iBAAE,YAAU,WAAW,QAAQ,KAAK,SAAS,IAAI,SAAS,IAAI,UAAU,WAAW,aAAa,GAAG,YAAY,SAAS,GAAG,aAAa,0BAA0B,MAjC/L,IAiC6B,IAA4K,kBAA5K,IAA4K,CAA1K,YAAU,aAAW,SAAa,UAAa,UAAa,YAAU,aAAW,cAAgB,cAAY,UAAY,cAAuC;AAC3L,UAAM,cAAc,OAA0B,IAAI;AAClD,UAAM,YAAa,oBAA8C;AAEjE,UAAM,UAAU,OAAiC,IAAI;AACrD,UAAM,aAAa,OAAoC,IAAI;AAC3D,UAAM,aAAa,OAAoC,IAAI;AAC3D,UAAM,aAAa,OAAoC,IAAI;AAE3D,UAAM,WAAW,OAAO,MAAM,EAAE,QAAQ,MAAM,EAAE;AAEhD,UAAM,CAAC,MAAM,OAAO,IAAI,SAA0C,IAAI;AAEtE,cAAU,MAAM;AACd,YAAM,SAAS,kBAAkB,EAAE,OAAO,QAAQ,QAAQ,UAAU,WAAW,WAAW,CAAC;AAC3F,cAAQ,MAAM;AAAA,IAChB,GAAG,CAAC,OAAO,QAAQ,QAAQ,UAAU,WAAW,UAAU,CAAC;AAE3D,cAAU,MAAM;AACd,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC,UAAU,CAAC,QAAQ,QAAS;AAEjC,UAAI,OAAO,WAAW,kCAAkC,EAAE,QAAS;AAEnE,YAAM,KAAK;AAAA,QACT,cAAc,OAAO,QAAQ;AAAA,QAC7B,MAAM,OAAO,QAAQ;AAAA,QACrB;AAAA,MACF;AAEA,YAAM,OAAO,MAAM;AA/DzB,YAAAC,KAAAC,KAAA;AAgEQ,SAAAD,MAAA,WAAW,YAAX,gBAAAA,IAAoB,aAAa,UAAU,GAAG,eAAe,GAAG,QAAQ,SAAS;AACjF,SAAAC,MAAA,WAAW,YAAX,gBAAAA,IAAoB,aAAa,SAAS,GAAG,aAAa,SAAS;AACnE,yBAAW,YAAX,mBAAoB,aAAa,UAAU,GAAG,eAAe,GAAG,QAAQ,SAAS;AACjF,sBAAQ,YAAR,mBAAiB,aAAa,gBAAgB,GAAG,KAAK,SAAS;AAAA,MACjE;AAEA,WAAK;AAEL,YAAM,UAAU,MAAM;AACpB,aAAK,aAAa,CAAC,IAAI,MAAM,CAAC;AAC9B,aAAK,GAAG,IAAI;AAAA,UACV,cAAc,OAAO,MAAM;AAAA,UAC3B,MAAM,OAAO,MAAM;AAAA,UACnB,QAAQ,SAAS;AAAA,UACjB,UAAU,OAAO,SAAS;AAAA,UAC1B,MAAM,OAAO,KAAK;AAAA,UAClB,UAAU;AAAA,QACZ,CAAC;AACD,aAAK,GAAG,QAAQ,EAAE,OAAO,OAAO,MAAM,OAAO,UAAU,OAAO,SAAS,OAAO,MAAM,OAAO,KAAK,MAAM,CAAC;AAAA,MACzG;AAEA,YAAM,UAAU,MAAM;AACpB,aAAK,aAAa,CAAC,IAAI,MAAM,CAAC;AAC9B,aAAK,GAAG,IAAI;AAAA,UACV,cAAc,OAAO,QAAQ;AAAA,UAC7B,MAAM,OAAO,QAAQ;AAAA,UACrB;AAAA,UACA,UAAU,OAAO,SAAS;AAAA,UAC1B,MAAM,OAAO,KAAK;AAAA,UAClB,UAAU;AAAA,QACZ,CAAC;AACD,aAAK,GAAG,QAAQ,EAAE,OAAO,OAAO,QAAQ,OAAO,UAAU,OAAO,SAAS,OAAO,MAAM,OAAO,KAAK,SAAS,CAAC;AAAA,MAC9G;AAEA,YAAM,UAAU,MAAM;AACpB,aAAK,aAAa,MAAM;AACxB,cAAM,MAAM,KAAK,YAAY,QAAQ,OAAO;AAC5C,aAAK,SAAS,EACX,GAAG,QAAQ,EAAE,OAAO,MAAM,OAAO,MAAM,WAAW,UAAU,OAAO,SAAS,WAAW,MAAM,OAAO,KAAK,UAAU,CAAC,EACpH,GAAG,QAAQ,EAAE,OAAO,OAAO,MAAM,SAAS,UAAU,OAAO,SAAS,SAAS,MAAM,OAAO,KAAK,QAAQ,CAAC;AAAA,MAC7G;AAEA,aAAO,iBAAiB,gBAAgB,OAAO;AAC/C,aAAO,iBAAiB,gBAAgB,OAAO;AAC/C,aAAO,iBAAiB,SAAS,OAAO;AAExC,aAAO,MAAM;AACX,eAAO,oBAAoB,gBAAgB,OAAO;AAClD,eAAO,oBAAoB,gBAAgB,OAAO;AAClD,eAAO,oBAAoB,SAAS,OAAO;AAC3C,aAAK,aAAa,CAAC,QAAQ,EAAE,CAAC;AAAA,MAChC;AAAA,IACF,GAAG,CAAC,WAAW,MAAM,MAAM,CAAC;AAE5B,WACE,iCACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,WAAW,GAAG,sEAAsE,SAAS;AAAA,UAC7F,OAAO,iBAAE,OAAO,QAAQ,cAAc,QAAQ,QAAQ,QAAQ,YAAY,cAAe;AAAA,WACrF,QAJL;AAAA,UAMC;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO;AAAA,kBACL,KAAK,CAAC;AAAA,kBAAS,MAAM,CAAC;AAAA,kBAAS,OAAO,CAAC;AAAA,kBAAS,QAAQ,CAAC;AAAA,kBACzD,gBAAgB,QAAQ,QAAQ;AAAA,kBAChC,sBAAsB,QAAQ,QAAQ;AAAA,gBACxC;AAAA;AAAA,YACF;AAAA,YACA,oBAAC,SAAI,WAAU,8HAA6H,OAAO,EAAE,YAAY,kFAAkF,cAAc,UAAU,GACxQ,UACH;AAAA;AAAA;AAAA,MACF;AAAA,MAEA,oBAAC,SAAI,OAAO,EAAE,UAAU,YAAY,OAAO,GAAG,QAAQ,GAAG,eAAe,OAAO,GAAG,eAAY,QAC5F,8BAAC,UACC,+BAAC,YAAO,IAAI,UAAU,GAAE,KAAI,GAAE,KAAI,OAAM,QAAO,QAAO,QAAO,2BAA0B,QACrF;AAAA,4BAAC,oBAAe,KAAK,SAAS,IAAG,iBAAgB,cAAc,OAAO,QAAQ,MAAM,QAAO,cAAa,UAAS,aAAY;AAAA,QAE5H,QACC,iCACE;AAAA,8BAAC,aAAQ,MAAM,KAAK,cAAc,QAAO,YAAW,GAAG,SAAS,GAAG,SAAS,OAAc,QAAgB,qBAAoB,QAAO;AAAA,UAErI,oBAAC,oBAAe,IAAG,YAAW,cAAc,YAAY,QAAO,gBAAe,UAAS,aAAY;AAAA,UAEnG,oBAAC,uBAAkB,KAAK,YAAY,IAAG,cAAa,KAAI,gBAAe,OAAO,OAAO,QAAQ,eAAe,QAAQ,kBAAiB,KAAI,kBAAiB,KAAI,QAAO,eAAc;AAAA,UACnL,oBAAC,mBAAc,IAAG,eAAc,MAAK,UAAS,QAAO,8CAA6C,QAAO,eAAc;AAAA,UAEvH,oBAAC,uBAAkB,KAAK,YAAY,IAAG,cAAa,KAAI,gBAAe,OAAO,OAAO,QAAQ,cAAc,kBAAiB,KAAI,kBAAiB,KAAI,QAAO,eAAc;AAAA,UAC1K,oBAAC,mBAAc,IAAG,eAAc,MAAK,UAAS,QAAO,8CAA6C,QAAO,iBAAgB;AAAA,UAEzH,oBAAC,uBAAkB,KAAK,YAAY,IAAG,cAAa,KAAI,gBAAe,OAAO,OAAO,QAAQ,eAAe,QAAQ,kBAAiB,KAAI,kBAAiB,KAAI,QAAO,eAAc;AAAA,UACnL,oBAAC,mBAAc,IAAG,eAAc,MAAK,UAAS,QAAO,8CAA6C,QAAO,gBAAe;AAAA,UAExH,oBAAC,aAAQ,IAAG,eAAc,KAAI,iBAAgB,MAAK,UAAS,QAAO,eAAc;AAAA,UACjF,oBAAC,aAAQ,IAAG,eAAc,KAAI,gBAAe,MAAK,UAAS,QAAO,gBAAe;AAAA,UAEjF,oBAAC,mBAAc,IAAG,gBAAe,MAAK,YAAW,QAAO,OAAM,QAAO,SAAQ;AAAA,WAC/E;AAAA,SAEJ,GACF,GACF;AAAA,OACF;AAAA,EAEJ;AACF;","names":["LiquidGlassButton","_a","_b"]}
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@marcosdemik/liquidglass",
3
+ "version": "1.0.0",
4
+ "description": "Liquid Glass UI effect for React - glassmorphism refraction with SVG filters, WebGL and GSAP animations",
5
+ "author": "Marcos Demik <marcosdemik>",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "import": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ },
17
+ "require": {
18
+ "types": "./dist/index.d.cts",
19
+ "default": "./dist/index.cjs"
20
+ }
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "README.md"
26
+ ],
27
+ "sideEffects": false,
28
+ "scripts": {
29
+ "build": "tsup",
30
+ "dev": "tsup --watch"
31
+ },
32
+ "dependencies": {
33
+ "gsap": "^3.12.0"
34
+ },
35
+ "peerDependencies": {
36
+ "react": ">=18.0.0",
37
+ "react-dom": ">=18.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/react": "^19",
41
+ "@types/react-dom": "^19",
42
+ "tsup": "^8",
43
+ "typescript": "^5"
44
+ },
45
+ "keywords": [
46
+ "liquid-glass",
47
+ "liquidglass",
48
+ "glassmorphism",
49
+ "glass",
50
+ "glass-effect",
51
+ "refraction",
52
+ "svg-filter",
53
+ "webgl",
54
+ "react",
55
+ "react-component",
56
+ "ui",
57
+ "button",
58
+ "apple",
59
+ "ios",
60
+ "macos",
61
+ "chromatic-aberration",
62
+ "gsap",
63
+ "animation"
64
+ ],
65
+ "repository": {
66
+ "type": "git",
67
+ "url": "https://github.com/MarcosDemik/liquidglass"
68
+ },
69
+ "homepage": "https://github.com/MarcosDemik/liquidglass#readme",
70
+ "bugs": {
71
+ "url": "https://github.com/MarcosDemik/liquidglass/issues"
72
+ }
73
+ }