react-liquid-glass-svg 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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +276 -0
- package/dist/components/FullFilter.d.ts +10 -0
- package/dist/components/FullFilter.d.ts.map +1 -0
- package/dist/components/LiquidGlass.d.ts +5 -0
- package/dist/components/LiquidGlass.d.ts.map +1 -0
- package/dist/components/SimpleFilter.d.ts +9 -0
- package/dist/components/SimpleFilter.d.ts.map +1 -0
- package/dist/components/types.d.ts +31 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/hooks/useBrowserDetection.d.ts +15 -0
- package/dist/hooks/useBrowserDetection.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +367 -0
- package/dist/index.umd.js +9 -0
- package/docs/banner.svg +108 -0
- package/docs/example-navbar.png +0 -0
- package/docs/example-player.png +0 -0
- package/docs/example-search.png +0 -0
- package/docs/example-stats.png +0 -0
- package/docs/logo.svg +39 -0
- package/docs/preview.png +0 -0
- package/package.json +84 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.0.0]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Initial release.
|
|
10
|
+
- `<LiquidGlass>` polymorphic component with SVG filter-based refraction.
|
|
11
|
+
- Props: `backdropBlur`, `tintColor`, `displacementScale`, `turbulenceBaseFrequency`, `turbulenceSeed`, `glassBorder`, `as`, `className`, `style`.
|
|
12
|
+
- Safari/iOS automatic fallback via simplified filter chain.
|
|
13
|
+
- Hydration-safe `useBrowserDetection` hook.
|
|
14
|
+
- `'use client'` directive baked into ESM and UMD builds (Next.js App Router compatibility).
|
|
15
|
+
- Full TypeScript types bundled.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yurii Khvyshchuk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="docs/banner.svg" alt="react-liquid-glass-svg" width="100%" />
|
|
4
|
+
|
|
5
|
+
# `react-liquid-glass-svg`
|
|
6
|
+
|
|
7
|
+
### Apple liquid glass for React — pure SVG, zero shaders.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/react-liquid-glass-svg)
|
|
10
|
+
[](https://bundlephobia.com/package/react-liquid-glass-svg)
|
|
11
|
+
[](https://www.npmjs.com/package/react-liquid-glass-svg)
|
|
12
|
+
[](./LICENSE)
|
|
13
|
+
|
|
14
|
+
[**✨ Live demo**](https://yurkagon.github.io/react-liquid-glass-svg/) · [**Examples**](#-examples) · [**Playground**](https://yurkagon.github.io/react-liquid-glass-svg/#sandbox) · [**API**](#-api)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div align="center">
|
|
19
|
+
<img src="docs/preview.png" alt="Liquid glass live preview" width="75%" />
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🚀 Why this and not the others?
|
|
25
|
+
|
|
26
|
+
Most glass-effect packages rely on WebGL or canvas — heavy, SSR-hostile, and awkward inside normal DOM layouts. This one uses plain SVG filters (`feTurbulence` + `feDisplacementMap`) — no shaders, no heavy runtimes:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
<feTurbulence> ← organic noise
|
|
30
|
+
↓
|
|
31
|
+
<feDisplacementMap> ← warps pixels by the noise
|
|
32
|
+
↓
|
|
33
|
+
backdrop-filter: blur() ← softens the result
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
That's the entire trick. **No shaders. No canvas. No WebGL.** ~5 KB gzip.
|
|
37
|
+
|
|
38
|
+
## ✨ Features
|
|
39
|
+
|
|
40
|
+
| | |
|
|
41
|
+
| -------------------------- | --------------------------------------------------------------------------------------- |
|
|
42
|
+
| 🪟 **Apple liquid glass** | Real displacement-mapped refraction on Chromium/Firefox; noise+blur fallback on Safari. |
|
|
43
|
+
| ⚡ **5 KB gzipped** | One file, zero runtime deps. Tree-shakable, `sideEffects: false`. |
|
|
44
|
+
| 🧩 **Polymorphic API** | `<LiquidGlass as="button" />`, `as="nav"`, `as="article"` — semantics stay yours. |
|
|
45
|
+
| 🎨 **Tailwind-friendly** | Pass `className`. No clashes, no wrappers, no `!important` wars. |
|
|
46
|
+
| 🔠 **TypeScript-first** | Strict types, autocompleted props. Zero `@types/*` packages to install. |
|
|
47
|
+
| 🌐 **Cross-browser** | Full filter on Chromium/Firefox, graceful Safari/iOS fallback — automatic. |
|
|
48
|
+
| 🔮 **Next.js / SSR ready** | `'use client'` baked in, hydration-safe by design. Zero config. |
|
|
49
|
+
| 🍎 **iOS glass border** | Opt-in inset highlights + specular sheen via `glassBorder` prop. |
|
|
50
|
+
|
|
51
|
+
## 📦 Install
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install react-liquid-glass-svg
|
|
55
|
+
# or
|
|
56
|
+
pnpm add react-liquid-glass-svg
|
|
57
|
+
# or
|
|
58
|
+
yarn add react-liquid-glass-svg
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Peer deps: `react@>=18`, `react-dom@>=18`.
|
|
62
|
+
|
|
63
|
+
## 🎬 Quick start
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { LiquidGlass } from 'react-liquid-glass-svg';
|
|
67
|
+
|
|
68
|
+
export default function Card() {
|
|
69
|
+
return (
|
|
70
|
+
<LiquidGlass
|
|
71
|
+
glassBorder
|
|
72
|
+
backdropBlur={5}
|
|
73
|
+
tintColor="rgba(255,255,255,0.2)"
|
|
74
|
+
className="rounded-2xl p-6"
|
|
75
|
+
>
|
|
76
|
+
<h2>Hello, glass</h2>
|
|
77
|
+
<p>This card refracts whatever sits behind it.</p>
|
|
78
|
+
</LiquidGlass>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Drop a colorful background behind it — gradient, image, video — and you'll see real refraction along the edges. 🌈
|
|
84
|
+
|
|
85
|
+
## 🧪 Examples
|
|
86
|
+
|
|
87
|
+
> All four examples below are live in the [**demo**](https://yurkagon.github.io/react-liquid-glass-svg/#examples) — drag the playground sliders, swap the prismatic backgrounds, copy the result.
|
|
88
|
+
|
|
89
|
+
### 🎵 Music Player
|
|
90
|
+
|
|
91
|
+
<img src="docs/example-player.png" alt="Music player on ocean background" width="75%" />
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
<LiquidGlass
|
|
95
|
+
glassBorder
|
|
96
|
+
backdropBlur={5}
|
|
97
|
+
tintColor="rgba(255,255,255,0.15)"
|
|
98
|
+
className="w-[360px] rounded-2xl p-5"
|
|
99
|
+
>
|
|
100
|
+
<div className="flex items-center gap-4">
|
|
101
|
+
<AlbumArt />
|
|
102
|
+
<TrackMeta />
|
|
103
|
+
<PlayControls />
|
|
104
|
+
</div>
|
|
105
|
+
<ProgressBar value={42} />
|
|
106
|
+
</LiquidGlass>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 🧭 Header (polymorphic)
|
|
110
|
+
|
|
111
|
+
<img src="docs/example-navbar.png" alt="Glass navbar on animated grid background" width="75%" />
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
<LiquidGlass
|
|
115
|
+
as="header" // <header> instead of <div>
|
|
116
|
+
backdropBlur={1.2}
|
|
117
|
+
tintColor="rgba(0,0,0,0.2)"
|
|
118
|
+
displacementScale={60}
|
|
119
|
+
turbulenceSeed={1}
|
|
120
|
+
className="flex h-16 items-center justify-between rounded-2xl px-6"
|
|
121
|
+
>
|
|
122
|
+
<a href="/" className="flex items-center gap-2">
|
|
123
|
+
<Logo />
|
|
124
|
+
<span>yurkagon</span>
|
|
125
|
+
</a>
|
|
126
|
+
<div className="flex items-center gap-4">
|
|
127
|
+
<a href="/work">Work</a>
|
|
128
|
+
<a href="/notes">Notes</a>
|
|
129
|
+
<a href="/about">About</a>
|
|
130
|
+
<button aria-label="Open menu">
|
|
131
|
+
<Menu />
|
|
132
|
+
</button>
|
|
133
|
+
</div>
|
|
134
|
+
</LiquidGlass>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 📊 Stats card
|
|
138
|
+
|
|
139
|
+
<img src="docs/example-stats.png" alt="KPI stats card with trend chip and sparkline" width="75%" />
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
<LiquidGlass
|
|
143
|
+
glassBorder
|
|
144
|
+
backdropBlur={5}
|
|
145
|
+
tintColor="rgba(255,255,255,0.2)"
|
|
146
|
+
className="rounded-2xl p-6"
|
|
147
|
+
>
|
|
148
|
+
<Header label="Active users" trend={8.2} />
|
|
149
|
+
<BigNumber value="12.4k" />
|
|
150
|
+
<Sparkline data={[...]} />
|
|
151
|
+
<Footer days={7} />
|
|
152
|
+
</LiquidGlass>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 🔍 Search (command palette)
|
|
156
|
+
|
|
157
|
+
<img src="docs/example-search.png" alt="Command-palette style search bar" width="75%" />
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
<LiquidGlass
|
|
161
|
+
glassBorder
|
|
162
|
+
backdropBlur={6}
|
|
163
|
+
tintColor="rgba(255,255,255,0.12)"
|
|
164
|
+
className="w-[420px] rounded-full px-5 py-3"
|
|
165
|
+
>
|
|
166
|
+
<div className="flex items-center gap-3">
|
|
167
|
+
<SearchIcon />
|
|
168
|
+
<input placeholder="Search files…" />
|
|
169
|
+
<kbd>⌘K</kbd>
|
|
170
|
+
</div>
|
|
171
|
+
</LiquidGlass>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## 🛝 Try it live
|
|
175
|
+
|
|
176
|
+
Tweak every prop in real time, copy the result:
|
|
177
|
+
**→ [yurkagon.github.io/react-liquid-glass-svg/#sandbox](https://yurkagon.github.io/react-liquid-glass-svg/#sandbox)**
|
|
178
|
+
|
|
179
|
+
## 🧬 How it works
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
┌──────────────────────────────────────────────────┐
|
|
183
|
+
│ outer <Tag> position:relative; overflow:hidden │
|
|
184
|
+
│ ┌──────────────────────────────────────────────┐ │
|
|
185
|
+
│ │ z:0 backdrop-filter: blur() + filter: url() │ │ ← noise + displacement
|
|
186
|
+
│ ├──────────────────────────────────────────────┤ │
|
|
187
|
+
│ │ z:1 tint background │ │ ← tintColor
|
|
188
|
+
│ ├──────────────────────────────────────────────┤ │
|
|
189
|
+
│ │ z:2 sheen overlay (when glassBorder) │ │ ← gradient + inset shadow
|
|
190
|
+
│ ├──────────────────────────────────────────────┤ │
|
|
191
|
+
│ │ z:3 content (your children) │ │
|
|
192
|
+
│ └──────────────────────────────────────────────┘ │
|
|
193
|
+
└──────────────────────────────────────────────────┘
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The SVG filter chain lives in a hidden `<svg>` next to the component and is referenced by a unique id generated via `useId()` — safe for SSR and for many instances on one page.
|
|
197
|
+
|
|
198
|
+
## 📖 API
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
import { LiquidGlass } from 'react-liquid-glass-svg';
|
|
202
|
+
import type { LiquidGlassProps } from 'react-liquid-glass-svg';
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Props
|
|
206
|
+
|
|
207
|
+
| Prop | Type | Default | Description |
|
|
208
|
+
| ------------------------- | --------------------------- | --------------------------- | ------------------------------------------------------------------- |
|
|
209
|
+
| `children` | `ReactNode` | — | Content rendered inside the glass surface |
|
|
210
|
+
| `as` | `ElementType` | `'div'` | Root element. Use for semantics (`button`, `nav`, …) |
|
|
211
|
+
| `className` | `string` | `''` | Applied to the root element |
|
|
212
|
+
| `style` | `CSSProperties` | — | Merged onto the root element |
|
|
213
|
+
| `backdropBlur` | `number` | `2` | CSS `backdrop-filter` blur strength, in px |
|
|
214
|
+
| `tintColor` | `string` | `'rgba(255,255,255,.2)'` | Overlay color above the blurred backdrop |
|
|
215
|
+
| `displacementScale` | `number` | `150` | `feDisplacementMap` scale. Ignored in the Safari fallback path |
|
|
216
|
+
| `turbulenceBaseFrequency` | `number ∣ [number, number]` | `0.008` or `[0.008, 0.008]` | `feTurbulence` base frequency. Tuple for different x/y |
|
|
217
|
+
| `turbulenceSeed` | `number` | `1.5` | `feTurbulence` seed (different patterns) |
|
|
218
|
+
| `glassBorder` | `boolean` | `false` | iOS-style polished edge: inset highlights + diagonal specular sheen |
|
|
219
|
+
|
|
220
|
+
All other props (`onClick`, `role`, `aria-*`, `data-*`, etc.) are forwarded to the root element. 🎯
|
|
221
|
+
|
|
222
|
+
## 🔮 Next.js & SSR
|
|
223
|
+
|
|
224
|
+
The package is built specifically with React Server Components in mind.
|
|
225
|
+
|
|
226
|
+
The `'use client'` directive is **baked into the published ESM and UMD bundles** — you don't need to add it.
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
// app/page.tsx — Next.js App Router (Server Component)
|
|
230
|
+
import { LiquidGlass } from 'react-liquid-glass-svg';
|
|
231
|
+
|
|
232
|
+
export default function Page() {
|
|
233
|
+
// ✅ Works in a Server Component — package is marked as client
|
|
234
|
+
return (
|
|
235
|
+
<LiquidGlass glassBorder>
|
|
236
|
+
<h1>Hello from the server</h1>
|
|
237
|
+
</LiquidGlass>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## 🌐 Browser support
|
|
243
|
+
|
|
244
|
+
| Browser | Effect |
|
|
245
|
+
| --------------------------------- | ------------------------------------------------------ |
|
|
246
|
+
| Chrome 90+ / Edge 90+ / Opera 76+ | ✅ Full liquid refraction |
|
|
247
|
+
| Firefox 103+ | ✅ Full liquid refraction |
|
|
248
|
+
| Safari 16+ / iOS Safari 16+ | ✨ Simplified fallback (noise + blur, no displacement) |
|
|
249
|
+
| Older browsers | 🪟 Plain blurred glass — content still readable |
|
|
250
|
+
|
|
251
|
+
The fallback path is automatic. The package detects Safari/iOS at runtime and swaps to a filter chain that only uses primitives WebKit supports.
|
|
252
|
+
|
|
253
|
+
## ⚡ Performance
|
|
254
|
+
|
|
255
|
+
- **~5 KB gzipped** (ESM build, no peer deps counted)
|
|
256
|
+
- **Zero runtime deps**, only React/ReactDOM peer
|
|
257
|
+
- **Tree-shakable** (`sideEffects: false`)
|
|
258
|
+
- One `<svg>` per instance, no global pollution
|
|
259
|
+
|
|
260
|
+
## 🛠 Contributing
|
|
261
|
+
|
|
262
|
+
This is a pnpm monorepo. See [**CONTRIBUTING.md**](./CONTRIBUTING.md) for dev setup, project structure, and commands.
|
|
263
|
+
|
|
264
|
+
## 📜 License
|
|
265
|
+
|
|
266
|
+
[MIT](./LICENSE) — free for personal and commercial use. ❤️
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
<div align="center">
|
|
271
|
+
|
|
272
|
+
Built by **[Yurii Khvyshchuk](https://yuragon.dev)** · [yuragon.dev](https://yuragon.dev) · [@yurkagon](https://github.com/yurkagon)
|
|
273
|
+
|
|
274
|
+
If you like it, drop a ⭐ on [GitHub](https://github.com/yurkagon/react-liquid-glass-svg).
|
|
275
|
+
|
|
276
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
export interface FullFilterProps {
|
|
3
|
+
id: string;
|
|
4
|
+
turbulenceBaseFrequency: string;
|
|
5
|
+
turbulenceSeed: number;
|
|
6
|
+
displacementScale: number;
|
|
7
|
+
}
|
|
8
|
+
declare const FullFilter: FC<FullFilterProps>;
|
|
9
|
+
export default FullFilter;
|
|
10
|
+
//# sourceMappingURL=FullFilter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FullFilter.d.ts","sourceRoot":"","sources":["../../src/components/FullFilter.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAE3B,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,uBAAuB,EAAE,MAAM,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,QAAA,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CA2DnC,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LiquidGlass.d.ts","sourceRoot":"","sources":["../../src/components/LiquidGlass.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAS,MAAM,OAAO,CAAC;AAClC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAmBhD,QAAA,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAkGrC,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
export interface SimpleFilterProps {
|
|
3
|
+
id: string;
|
|
4
|
+
turbulenceBaseFrequency: string;
|
|
5
|
+
turbulenceSeed: number;
|
|
6
|
+
}
|
|
7
|
+
declare const SimpleFilter: FC<SimpleFilterProps>;
|
|
8
|
+
export default SimpleFilter;
|
|
9
|
+
//# sourceMappingURL=SimpleFilter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SimpleFilter.d.ts","sourceRoot":"","sources":["../../src/components/SimpleFilter.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAE3B,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,uBAAuB,EAAE,MAAM,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,QAAA,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAgCvC,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ReactNode, CSSProperties, ElementType, HTMLAttributes } from 'react';
|
|
2
|
+
export interface LiquidGlassProps extends Omit<HTMLAttributes<HTMLElement>, 'as'> {
|
|
3
|
+
/** Content to display inside the glass container */
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
/** Additional TailwindCSS classes */
|
|
6
|
+
className?: string;
|
|
7
|
+
/** Blur level for the backdrop filter (in px) */
|
|
8
|
+
backdropBlur?: number;
|
|
9
|
+
/** Tint overlay color */
|
|
10
|
+
tintColor?: string;
|
|
11
|
+
/** Displacement map scale (liquid effect intensity) */
|
|
12
|
+
displacementScale?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Turbulence base frequency (controls noise size).
|
|
15
|
+
* - Single number — applied to both x and y axes.
|
|
16
|
+
* - `[x, y]` tuple — different frequencies per axis.
|
|
17
|
+
*/
|
|
18
|
+
turbulenceBaseFrequency?: number | [number, number];
|
|
19
|
+
/** Turbulence seed (for different noise patterns) */
|
|
20
|
+
turbulenceSeed?: number;
|
|
21
|
+
/** HTML component to render (div, button, section, etc.) */
|
|
22
|
+
as?: ElementType;
|
|
23
|
+
/** Additional inline styles */
|
|
24
|
+
style?: CSSProperties;
|
|
25
|
+
/**
|
|
26
|
+
* Enable iOS-style polished glass edge: inset highlights + diagonal
|
|
27
|
+
* specular sheen. Default: false (uses the original soft drop-shadow).
|
|
28
|
+
*/
|
|
29
|
+
glassBorder?: boolean;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAE9E,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAC5C,cAAc,CAAC,WAAW,CAAC,EAC3B,IAAI,CACL;IACC,oDAAoD;IACpD,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpD,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,4DAA4D;IAC5D,EAAE,CAAC,EAAE,WAAW,CAAC;IAEjB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,aAAa,CAAC;IAEtB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom hook for detecting browser capabilities.
|
|
3
|
+
* Returns whether the browser fully supports advanced SVG filter primitives
|
|
4
|
+
* (non-Safari, non-iOS). When `false`, consumers should render a simplified
|
|
5
|
+
* filter fallback.
|
|
6
|
+
*
|
|
7
|
+
* Hydration-safe: both server and the first client render return `true`
|
|
8
|
+
* (assume full support), matching the server HTML. The actual detection
|
|
9
|
+
* runs in `useEffect` (client-only, after hydration) and triggers a
|
|
10
|
+
* re-render if a fallback is needed.
|
|
11
|
+
*/
|
|
12
|
+
export declare const useBrowserDetection: () => {
|
|
13
|
+
hasFullFilterSupport: boolean;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=useBrowserDetection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBrowserDetection.d.ts","sourceRoot":"","sources":["../../src/hooks/useBrowserDetection.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB;;CAY/B,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC3E,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect as e, useId as t, useState as n } from "react";
|
|
3
|
+
//#region \0rolldown/runtime.js
|
|
4
|
+
var r = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), i = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(e, { get: (e, t) => (typeof require < "u" ? require : e)[t] }) : e)(function(e) {
|
|
5
|
+
if (typeof require < "u") return require.apply(this, arguments);
|
|
6
|
+
throw Error("Calling `require` for \"" + e + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
|
|
7
|
+
}), a = /iPad|iPhone|iPod/, o = /^((?!chrome|android).)*safari/i, s = () => {
|
|
8
|
+
if (typeof window > "u") return !0;
|
|
9
|
+
let e = window.navigator.userAgent;
|
|
10
|
+
return !(a.test(e) || o.test(e));
|
|
11
|
+
}, c = () => {
|
|
12
|
+
let [t, r] = n(!0);
|
|
13
|
+
return e(() => {
|
|
14
|
+
r(s());
|
|
15
|
+
}, []), { hasFullFilterSupport: t };
|
|
16
|
+
}, l = /* @__PURE__ */ r(((e) => {
|
|
17
|
+
var t = Symbol.for("react.transitional.element"), n = Symbol.for("react.fragment");
|
|
18
|
+
function r(e, n, r) {
|
|
19
|
+
var i = null;
|
|
20
|
+
if (r !== void 0 && (i = "" + r), n.key !== void 0 && (i = "" + n.key), "key" in n) for (var a in r = {}, n) a !== "key" && (r[a] = n[a]);
|
|
21
|
+
else r = n;
|
|
22
|
+
return n = r.ref, {
|
|
23
|
+
$$typeof: t,
|
|
24
|
+
type: e,
|
|
25
|
+
key: i,
|
|
26
|
+
ref: n === void 0 ? null : n,
|
|
27
|
+
props: r
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
e.Fragment = n, e.jsx = r, e.jsxs = r;
|
|
31
|
+
})), u = /* @__PURE__ */ r(((e) => {
|
|
32
|
+
process.env.NODE_ENV !== "production" && (function() {
|
|
33
|
+
function t(e) {
|
|
34
|
+
if (e == null) return null;
|
|
35
|
+
if (typeof e == "function") return e.$$typeof === k ? null : e.displayName || e.name || null;
|
|
36
|
+
if (typeof e == "string") return e;
|
|
37
|
+
switch (e) {
|
|
38
|
+
case v: return "Fragment";
|
|
39
|
+
case b: return "Profiler";
|
|
40
|
+
case y: return "StrictMode";
|
|
41
|
+
case w: return "Suspense";
|
|
42
|
+
case T: return "SuspenseList";
|
|
43
|
+
case O: return "Activity";
|
|
44
|
+
}
|
|
45
|
+
if (typeof e == "object") switch (typeof e.tag == "number" && console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."), e.$$typeof) {
|
|
46
|
+
case _: return "Portal";
|
|
47
|
+
case S: return e.displayName || "Context";
|
|
48
|
+
case x: return (e._context.displayName || "Context") + ".Consumer";
|
|
49
|
+
case C:
|
|
50
|
+
var n = e.render;
|
|
51
|
+
return e = e.displayName, e || (e = n.displayName || n.name || "", e = e === "" ? "ForwardRef" : "ForwardRef(" + e + ")"), e;
|
|
52
|
+
case E: return n = e.displayName || null, n === null ? t(e.type) || "Memo" : n;
|
|
53
|
+
case D:
|
|
54
|
+
n = e._payload, e = e._init;
|
|
55
|
+
try {
|
|
56
|
+
return t(e(n));
|
|
57
|
+
} catch {}
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function n(e) {
|
|
62
|
+
return "" + e;
|
|
63
|
+
}
|
|
64
|
+
function r(e) {
|
|
65
|
+
try {
|
|
66
|
+
n(e);
|
|
67
|
+
var t = !1;
|
|
68
|
+
} catch {
|
|
69
|
+
t = !0;
|
|
70
|
+
}
|
|
71
|
+
if (t) {
|
|
72
|
+
t = console;
|
|
73
|
+
var r = t.error, i = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
|
|
74
|
+
return r.call(t, "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", i), n(e);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function a(e) {
|
|
78
|
+
if (e === v) return "<>";
|
|
79
|
+
if (typeof e == "object" && e && e.$$typeof === D) return "<...>";
|
|
80
|
+
try {
|
|
81
|
+
var n = t(e);
|
|
82
|
+
return n ? "<" + n + ">" : "<...>";
|
|
83
|
+
} catch {
|
|
84
|
+
return "<...>";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function o() {
|
|
88
|
+
var e = A.A;
|
|
89
|
+
return e === null ? null : e.getOwner();
|
|
90
|
+
}
|
|
91
|
+
function s() {
|
|
92
|
+
return Error("react-stack-top-frame");
|
|
93
|
+
}
|
|
94
|
+
function c(e) {
|
|
95
|
+
if (j.call(e, "key")) {
|
|
96
|
+
var t = Object.getOwnPropertyDescriptor(e, "key").get;
|
|
97
|
+
if (t && t.isReactWarning) return !1;
|
|
98
|
+
}
|
|
99
|
+
return e.key !== void 0;
|
|
100
|
+
}
|
|
101
|
+
function l(e, t) {
|
|
102
|
+
function n() {
|
|
103
|
+
P || (P = !0, console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)", t));
|
|
104
|
+
}
|
|
105
|
+
n.isReactWarning = !0, Object.defineProperty(e, "key", {
|
|
106
|
+
get: n,
|
|
107
|
+
configurable: !0
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function u() {
|
|
111
|
+
var e = t(this.type);
|
|
112
|
+
return F[e] || (F[e] = !0, console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")), e = this.props.ref, e === void 0 ? null : e;
|
|
113
|
+
}
|
|
114
|
+
function d(e, t, n, r, i, a) {
|
|
115
|
+
var o = n.ref;
|
|
116
|
+
return e = {
|
|
117
|
+
$$typeof: g,
|
|
118
|
+
type: e,
|
|
119
|
+
key: t,
|
|
120
|
+
props: n,
|
|
121
|
+
_owner: r
|
|
122
|
+
}, (o === void 0 ? null : o) === null ? Object.defineProperty(e, "ref", {
|
|
123
|
+
enumerable: !1,
|
|
124
|
+
value: null
|
|
125
|
+
}) : Object.defineProperty(e, "ref", {
|
|
126
|
+
enumerable: !1,
|
|
127
|
+
get: u
|
|
128
|
+
}), e._store = {}, Object.defineProperty(e._store, "validated", {
|
|
129
|
+
configurable: !1,
|
|
130
|
+
enumerable: !1,
|
|
131
|
+
writable: !0,
|
|
132
|
+
value: 0
|
|
133
|
+
}), Object.defineProperty(e, "_debugInfo", {
|
|
134
|
+
configurable: !1,
|
|
135
|
+
enumerable: !1,
|
|
136
|
+
writable: !0,
|
|
137
|
+
value: null
|
|
138
|
+
}), Object.defineProperty(e, "_debugStack", {
|
|
139
|
+
configurable: !1,
|
|
140
|
+
enumerable: !1,
|
|
141
|
+
writable: !0,
|
|
142
|
+
value: i
|
|
143
|
+
}), Object.defineProperty(e, "_debugTask", {
|
|
144
|
+
configurable: !1,
|
|
145
|
+
enumerable: !1,
|
|
146
|
+
writable: !0,
|
|
147
|
+
value: a
|
|
148
|
+
}), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
|
|
149
|
+
}
|
|
150
|
+
function f(e, n, i, a, s, u) {
|
|
151
|
+
var f = n.children;
|
|
152
|
+
if (f !== void 0) if (a) if (M(f)) {
|
|
153
|
+
for (a = 0; a < f.length; a++) p(f[a]);
|
|
154
|
+
Object.freeze && Object.freeze(f);
|
|
155
|
+
} else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");
|
|
156
|
+
else p(f);
|
|
157
|
+
if (j.call(n, "key")) {
|
|
158
|
+
f = t(e);
|
|
159
|
+
var m = Object.keys(n).filter(function(e) {
|
|
160
|
+
return e !== "key";
|
|
161
|
+
});
|
|
162
|
+
a = 0 < m.length ? "{key: someKey, " + m.join(": ..., ") + ": ...}" : "{key: someKey}", R[f + a] || (m = 0 < m.length ? "{" + m.join(": ..., ") + ": ...}" : "{}", console.error("A props object containing a \"key\" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />", a, f, m, f), R[f + a] = !0);
|
|
163
|
+
}
|
|
164
|
+
if (f = null, i !== void 0 && (r(i), f = "" + i), c(n) && (r(n.key), f = "" + n.key), "key" in n) for (var h in i = {}, n) h !== "key" && (i[h] = n[h]);
|
|
165
|
+
else i = n;
|
|
166
|
+
return f && l(i, typeof e == "function" ? e.displayName || e.name || "Unknown" : e), d(e, f, i, o(), s, u);
|
|
167
|
+
}
|
|
168
|
+
function p(e) {
|
|
169
|
+
m(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e && e.$$typeof === D && (e._payload.status === "fulfilled" ? m(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
|
|
170
|
+
}
|
|
171
|
+
function m(e) {
|
|
172
|
+
return typeof e == "object" && !!e && e.$$typeof === g;
|
|
173
|
+
}
|
|
174
|
+
var h = i("react"), g = Symbol.for("react.transitional.element"), _ = Symbol.for("react.portal"), v = Symbol.for("react.fragment"), y = Symbol.for("react.strict_mode"), b = Symbol.for("react.profiler"), x = Symbol.for("react.consumer"), S = Symbol.for("react.context"), C = Symbol.for("react.forward_ref"), w = Symbol.for("react.suspense"), T = Symbol.for("react.suspense_list"), E = Symbol.for("react.memo"), D = Symbol.for("react.lazy"), O = Symbol.for("react.activity"), k = Symbol.for("react.client.reference"), A = h.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, j = Object.prototype.hasOwnProperty, M = Array.isArray, N = console.createTask ? console.createTask : function() {
|
|
175
|
+
return null;
|
|
176
|
+
};
|
|
177
|
+
h = { react_stack_bottom_frame: function(e) {
|
|
178
|
+
return e();
|
|
179
|
+
} };
|
|
180
|
+
var P, F = {}, I = h.react_stack_bottom_frame.bind(h, s)(), L = N(a(s)), R = {};
|
|
181
|
+
e.Fragment = v, e.jsx = function(e, t, n) {
|
|
182
|
+
var r = 1e4 > A.recentlyCreatedOwnerStacks++;
|
|
183
|
+
return f(e, t, n, !1, r ? Error("react-stack-top-frame") : I, r ? N(a(e)) : L);
|
|
184
|
+
}, e.jsxs = function(e, t, n) {
|
|
185
|
+
var r = 1e4 > A.recentlyCreatedOwnerStacks++;
|
|
186
|
+
return f(e, t, n, !0, r ? Error("react-stack-top-frame") : I, r ? N(a(e)) : L);
|
|
187
|
+
};
|
|
188
|
+
})();
|
|
189
|
+
})), d = (/* @__PURE__ */ r(((e, t) => {
|
|
190
|
+
process.env.NODE_ENV === "production" ? t.exports = l() : t.exports = u();
|
|
191
|
+
})))(), f = ({ id: e, turbulenceBaseFrequency: t, turbulenceSeed: n, displacementScale: r }) => /* @__PURE__ */ (0, d.jsxs)("filter", {
|
|
192
|
+
id: e,
|
|
193
|
+
x: "0%",
|
|
194
|
+
y: "0%",
|
|
195
|
+
width: "100%",
|
|
196
|
+
height: "100%",
|
|
197
|
+
filterUnits: "objectBoundingBox",
|
|
198
|
+
children: [
|
|
199
|
+
/* @__PURE__ */ (0, d.jsx)("feTurbulence", {
|
|
200
|
+
type: "fractalNoise",
|
|
201
|
+
baseFrequency: t,
|
|
202
|
+
numOctaves: 1,
|
|
203
|
+
seed: n,
|
|
204
|
+
result: "turbulence"
|
|
205
|
+
}),
|
|
206
|
+
/* @__PURE__ */ (0, d.jsxs)("feComponentTransfer", {
|
|
207
|
+
in: "turbulence",
|
|
208
|
+
result: "mapped",
|
|
209
|
+
children: [
|
|
210
|
+
/* @__PURE__ */ (0, d.jsx)("feFuncR", {
|
|
211
|
+
type: "gamma",
|
|
212
|
+
amplitude: 1,
|
|
213
|
+
exponent: 10,
|
|
214
|
+
offset: .5
|
|
215
|
+
}),
|
|
216
|
+
/* @__PURE__ */ (0, d.jsx)("feFuncG", {
|
|
217
|
+
type: "gamma",
|
|
218
|
+
amplitude: 0,
|
|
219
|
+
exponent: 1,
|
|
220
|
+
offset: 0
|
|
221
|
+
}),
|
|
222
|
+
/* @__PURE__ */ (0, d.jsx)("feFuncB", {
|
|
223
|
+
type: "gamma",
|
|
224
|
+
amplitude: 0,
|
|
225
|
+
exponent: 1,
|
|
226
|
+
offset: .5
|
|
227
|
+
})
|
|
228
|
+
]
|
|
229
|
+
}),
|
|
230
|
+
/* @__PURE__ */ (0, d.jsx)("feGaussianBlur", {
|
|
231
|
+
in: "turbulence",
|
|
232
|
+
stdDeviation: 3,
|
|
233
|
+
result: "softMap"
|
|
234
|
+
}),
|
|
235
|
+
/* @__PURE__ */ (0, d.jsx)("feSpecularLighting", {
|
|
236
|
+
in: "softMap",
|
|
237
|
+
surfaceScale: 5,
|
|
238
|
+
specularConstant: 1,
|
|
239
|
+
specularExponent: 100,
|
|
240
|
+
lightingColor: "white",
|
|
241
|
+
result: "specLight",
|
|
242
|
+
children: /* @__PURE__ */ (0, d.jsx)("fePointLight", {
|
|
243
|
+
x: -200,
|
|
244
|
+
y: -200,
|
|
245
|
+
z: 300
|
|
246
|
+
})
|
|
247
|
+
}),
|
|
248
|
+
/* @__PURE__ */ (0, d.jsx)("feComposite", {
|
|
249
|
+
in: "specLight",
|
|
250
|
+
operator: "arithmetic",
|
|
251
|
+
k1: 0,
|
|
252
|
+
k2: 1,
|
|
253
|
+
k3: 1,
|
|
254
|
+
k4: 0,
|
|
255
|
+
result: "litImage"
|
|
256
|
+
}),
|
|
257
|
+
/* @__PURE__ */ (0, d.jsx)("feDisplacementMap", {
|
|
258
|
+
in: "SourceGraphic",
|
|
259
|
+
in2: "softMap",
|
|
260
|
+
scale: r,
|
|
261
|
+
xChannelSelector: "R",
|
|
262
|
+
yChannelSelector: "G"
|
|
263
|
+
})
|
|
264
|
+
]
|
|
265
|
+
}), p = ({ id: e, turbulenceBaseFrequency: t, turbulenceSeed: n }) => /* @__PURE__ */ (0, d.jsxs)("filter", {
|
|
266
|
+
id: e,
|
|
267
|
+
x: "-20%",
|
|
268
|
+
y: "-20%",
|
|
269
|
+
width: "140%",
|
|
270
|
+
height: "140%",
|
|
271
|
+
filterUnits: "objectBoundingBox",
|
|
272
|
+
children: [
|
|
273
|
+
/* @__PURE__ */ (0, d.jsx)("feTurbulence", {
|
|
274
|
+
type: "fractalNoise",
|
|
275
|
+
baseFrequency: t,
|
|
276
|
+
numOctaves: 2,
|
|
277
|
+
seed: n,
|
|
278
|
+
result: "turbulence"
|
|
279
|
+
}),
|
|
280
|
+
/* @__PURE__ */ (0, d.jsx)("feGaussianBlur", {
|
|
281
|
+
in: "turbulence",
|
|
282
|
+
stdDeviation: "2",
|
|
283
|
+
result: "blur"
|
|
284
|
+
}),
|
|
285
|
+
/* @__PURE__ */ (0, d.jsx)("feColorMatrix", {
|
|
286
|
+
in: "blur",
|
|
287
|
+
type: "matrix",
|
|
288
|
+
values: "1 0 0 0 0\n 0 1 0 0 0\n 0 0 1 0 0\n 0 0 0 0.15 0",
|
|
289
|
+
result: "transparency"
|
|
290
|
+
}),
|
|
291
|
+
/* @__PURE__ */ (0, d.jsx)("feBlend", {
|
|
292
|
+
in: "SourceGraphic",
|
|
293
|
+
in2: "transparency",
|
|
294
|
+
mode: "normal"
|
|
295
|
+
})
|
|
296
|
+
]
|
|
297
|
+
}), m = "0 6px 6px rgba(0, 0, 0, 0.2), 0 0 20px rgba(0, 0, 0, 0.1)", h = "0 8px 32px rgba(0,0,0,0.28)", g = "inset 0 1px 0 0 rgba(255,255,255,0.55), inset 0 -1px 1px 0 rgba(255,255,255,0.12), inset 0 0 0 1px rgba(255,255,255,0.08)", _ = (e) => Array.isArray(e) ? `${e[0]} ${e[1]}` : `${e}`, v = ({ children: e, className: n = "", backdropBlur: r = 2, tintColor: i = "rgba(255, 255, 255, .2)", displacementScale: a = 150, turbulenceBaseFrequency: o = .008, turbulenceSeed: s = 1.5, as: l = "div", style: u, glassBorder: v = !1, ...y }) => {
|
|
298
|
+
let b = t(), { hasFullFilterSupport: x } = c(), S = _(o);
|
|
299
|
+
return /* @__PURE__ */ (0, d.jsxs)(d.Fragment, { children: [/* @__PURE__ */ (0, d.jsx)("svg", {
|
|
300
|
+
style: { display: "none" },
|
|
301
|
+
children: x ? /* @__PURE__ */ (0, d.jsx)(f, {
|
|
302
|
+
id: b,
|
|
303
|
+
turbulenceBaseFrequency: S,
|
|
304
|
+
turbulenceSeed: s,
|
|
305
|
+
displacementScale: a
|
|
306
|
+
}) : /* @__PURE__ */ (0, d.jsx)(p, {
|
|
307
|
+
id: b,
|
|
308
|
+
turbulenceBaseFrequency: S,
|
|
309
|
+
turbulenceSeed: s
|
|
310
|
+
})
|
|
311
|
+
}), /* @__PURE__ */ (0, d.jsxs)(l, {
|
|
312
|
+
className: n,
|
|
313
|
+
style: {
|
|
314
|
+
position: "relative",
|
|
315
|
+
overflow: "hidden",
|
|
316
|
+
boxShadow: v ? h : m,
|
|
317
|
+
...u
|
|
318
|
+
},
|
|
319
|
+
...y,
|
|
320
|
+
children: [
|
|
321
|
+
/* @__PURE__ */ (0, d.jsx)("div", { style: {
|
|
322
|
+
position: "absolute",
|
|
323
|
+
inset: 0,
|
|
324
|
+
zIndex: 0,
|
|
325
|
+
overflow: "hidden",
|
|
326
|
+
borderRadius: "inherit",
|
|
327
|
+
backdropFilter: `blur(${r}px)`,
|
|
328
|
+
WebkitBackdropFilter: `blur(${r}px)`,
|
|
329
|
+
filter: `url(#${b})`,
|
|
330
|
+
isolation: "isolate",
|
|
331
|
+
...!x && {
|
|
332
|
+
transform: "translateZ(0)",
|
|
333
|
+
willChange: "transform"
|
|
334
|
+
}
|
|
335
|
+
} }),
|
|
336
|
+
/* @__PURE__ */ (0, d.jsx)("div", { style: {
|
|
337
|
+
position: "absolute",
|
|
338
|
+
inset: 0,
|
|
339
|
+
zIndex: 1,
|
|
340
|
+
borderRadius: "inherit",
|
|
341
|
+
background: i
|
|
342
|
+
} }),
|
|
343
|
+
v && /* @__PURE__ */ (0, d.jsx)("span", {
|
|
344
|
+
"aria-hidden": "true",
|
|
345
|
+
style: {
|
|
346
|
+
position: "absolute",
|
|
347
|
+
inset: 0,
|
|
348
|
+
zIndex: 2,
|
|
349
|
+
borderRadius: "inherit",
|
|
350
|
+
pointerEvents: "none",
|
|
351
|
+
background: "linear-gradient(135deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0) 38%, rgba(255,255,255,0) 62%, rgba(255,255,255,0.06) 100%)",
|
|
352
|
+
boxShadow: g
|
|
353
|
+
}
|
|
354
|
+
}),
|
|
355
|
+
/* @__PURE__ */ (0, d.jsx)("div", {
|
|
356
|
+
style: {
|
|
357
|
+
position: "relative",
|
|
358
|
+
zIndex: 3,
|
|
359
|
+
borderRadius: "inherit"
|
|
360
|
+
},
|
|
361
|
+
children: e
|
|
362
|
+
})
|
|
363
|
+
]
|
|
364
|
+
})] });
|
|
365
|
+
};
|
|
366
|
+
//#endregion
|
|
367
|
+
export { v as LiquidGlass, v as default };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use client";(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react")):typeof define==`function`&&define.amd?define([`exports`,`react`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.LiquidGlass={},e.React))})(this,function(e,t){Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var n=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),r=/iPad|iPhone|iPod/,i=/^((?!chrome|android).)*safari/i,a=()=>{if(typeof window>`u`)return!0;let e=window.navigator.userAgent;return!(r.test(e)||i.test(e))},o=()=>{let[e,n]=(0,t.useState)(!0);return(0,t.useEffect)(()=>{n(a())},[]),{hasFullFilterSupport:e}},s=n((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),c=n((e=>{process.env.NODE_ENV!==`production`&&(function(){function t(e){if(e==null)return null;if(typeof e==`function`)return e.$$typeof===O?null:e.displayName||e.name||null;if(typeof e==`string`)return e;switch(e){case _:return`Fragment`;case y:return`Profiler`;case v:return`StrictMode`;case C:return`Suspense`;case w:return`SuspenseList`;case D:return`Activity`}if(typeof e==`object`)switch(typeof e.tag==`number`&&console.error(`Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue.`),e.$$typeof){case g:return`Portal`;case x:return e.displayName||`Context`;case b:return(e._context.displayName||`Context`)+`.Consumer`;case S:var n=e.render;return e=e.displayName,e||(e=n.displayName||n.name||``,e=e===``?`ForwardRef`:`ForwardRef(`+e+`)`),e;case T:return n=e.displayName||null,n===null?t(e.type)||`Memo`:n;case E:n=e._payload,e=e._init;try{return t(e(n))}catch{}}return null}function n(e){return``+e}function r(e){try{n(e);var t=!1}catch{t=!0}if(t){t=console;var r=t.error,i=typeof Symbol==`function`&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||`Object`;return r.call(t,`The provided key is an unsupported type %s. This value must be coerced to a string before using it here.`,i),n(e)}}function i(e){if(e===_)return`<>`;if(typeof e==`object`&&e&&e.$$typeof===E)return`<...>`;try{var n=t(e);return n?`<`+n+`>`:`<...>`}catch{return`<...>`}}function a(){var e=k.A;return e===null?null:e.getOwner()}function o(){return Error(`react-stack-top-frame`)}function s(e){if(A.call(e,`key`)){var t=Object.getOwnPropertyDescriptor(e,`key`).get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function c(e,t){function n(){N||(N=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}n.isReactWarning=!0,Object.defineProperty(e,"key",{get:n,configurable:!0})}function l(){var e=t(this.type);return P[e]||(P[e]=!0,console.error(`Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.`)),e=this.props.ref,e===void 0?null:e}function u(e,t,n,r,i,a){var o=n.ref;return e={$$typeof:h,type:e,key:t,props:n,_owner:r},(o===void 0?null:o)===null?Object.defineProperty(e,"ref",{enumerable:!1,value:null}):Object.defineProperty(e,"ref",{enumerable:!1,get:l}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:i}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:a}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function d(e,n,i,o,l,d){var p=n.children;if(p!==void 0)if(o)if(j(p)){for(o=0;o<p.length;o++)f(p[o]);Object.freeze&&Object.freeze(p)}else console.error(`React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.`);else f(p);if(A.call(n,`key`)){p=t(e);var m=Object.keys(n).filter(function(e){return e!==`key`});o=0<m.length?`{key: someKey, `+m.join(`: ..., `)+`: ...}`:`{key: someKey}`,L[p+o]||(m=0<m.length?`{`+m.join(`: ..., `)+`: ...}`:`{}`,console.error(`A props object containing a "key" prop is being spread into JSX:
|
|
2
|
+
let props = %s;
|
|
3
|
+
<%s {...props} />
|
|
4
|
+
React keys must be passed directly to JSX without using spread:
|
|
5
|
+
let props = %s;
|
|
6
|
+
<%s key={someKey} {...props} />`,o,p,m,p),L[p+o]=!0)}if(p=null,i!==void 0&&(r(i),p=``+i),s(n)&&(r(n.key),p=``+n.key),`key`in n)for(var h in i={},n)h!==`key`&&(i[h]=n[h]);else i=n;return p&&c(i,typeof e==`function`?e.displayName||e.name||`Unknown`:e),u(e,p,i,a(),l,d)}function f(e){p(e)?e._store&&(e._store.validated=1):typeof e==`object`&&e&&e.$$typeof===E&&(e._payload.status===`fulfilled`?p(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function p(e){return typeof e==`object`&&!!e&&e.$$typeof===h}var m=require("react"),h=Symbol.for(`react.transitional.element`),g=Symbol.for(`react.portal`),_=Symbol.for(`react.fragment`),v=Symbol.for(`react.strict_mode`),y=Symbol.for(`react.profiler`),b=Symbol.for(`react.consumer`),x=Symbol.for(`react.context`),S=Symbol.for(`react.forward_ref`),C=Symbol.for(`react.suspense`),w=Symbol.for(`react.suspense_list`),T=Symbol.for(`react.memo`),E=Symbol.for(`react.lazy`),D=Symbol.for(`react.activity`),O=Symbol.for(`react.client.reference`),k=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,A=Object.prototype.hasOwnProperty,j=Array.isArray,M=console.createTask?console.createTask:function(){return null};m={react_stack_bottom_frame:function(e){return e()}};var N,P={},F=m.react_stack_bottom_frame.bind(m,o)(),I=M(i(o)),L={};e.Fragment=_,e.jsx=function(e,t,n){var r=1e4>k.recentlyCreatedOwnerStacks++;return d(e,t,n,!1,r?Error(`react-stack-top-frame`):F,r?M(i(e)):I)},e.jsxs=function(e,t,n){var r=1e4>k.recentlyCreatedOwnerStacks++;return d(e,t,n,!0,r?Error(`react-stack-top-frame`):F,r?M(i(e)):I)}})()})),l=n(((e,t)=>{process.env.NODE_ENV===`production`?t.exports=s():t.exports=c()}))(),u=({id:e,turbulenceBaseFrequency:t,turbulenceSeed:n,displacementScale:r})=>(0,l.jsxs)(`filter`,{id:e,x:`0%`,y:`0%`,width:`100%`,height:`100%`,filterUnits:`objectBoundingBox`,children:[(0,l.jsx)(`feTurbulence`,{type:`fractalNoise`,baseFrequency:t,numOctaves:1,seed:n,result:`turbulence`}),(0,l.jsxs)(`feComponentTransfer`,{in:`turbulence`,result:`mapped`,children:[(0,l.jsx)(`feFuncR`,{type:`gamma`,amplitude:1,exponent:10,offset:.5}),(0,l.jsx)(`feFuncG`,{type:`gamma`,amplitude:0,exponent:1,offset:0}),(0,l.jsx)(`feFuncB`,{type:`gamma`,amplitude:0,exponent:1,offset:.5})]}),(0,l.jsx)(`feGaussianBlur`,{in:`turbulence`,stdDeviation:3,result:`softMap`}),(0,l.jsx)(`feSpecularLighting`,{in:`softMap`,surfaceScale:5,specularConstant:1,specularExponent:100,lightingColor:`white`,result:`specLight`,children:(0,l.jsx)(`fePointLight`,{x:-200,y:-200,z:300})}),(0,l.jsx)(`feComposite`,{in:`specLight`,operator:`arithmetic`,k1:0,k2:1,k3:1,k4:0,result:`litImage`}),(0,l.jsx)(`feDisplacementMap`,{in:`SourceGraphic`,in2:`softMap`,scale:r,xChannelSelector:`R`,yChannelSelector:`G`})]}),d=({id:e,turbulenceBaseFrequency:t,turbulenceSeed:n})=>(0,l.jsxs)(`filter`,{id:e,x:`-20%`,y:`-20%`,width:`140%`,height:`140%`,filterUnits:`objectBoundingBox`,children:[(0,l.jsx)(`feTurbulence`,{type:`fractalNoise`,baseFrequency:t,numOctaves:2,seed:n,result:`turbulence`}),(0,l.jsx)(`feGaussianBlur`,{in:`turbulence`,stdDeviation:`2`,result:`blur`}),(0,l.jsx)(`feColorMatrix`,{in:`blur`,type:`matrix`,values:`1 0 0 0 0
|
|
7
|
+
0 1 0 0 0
|
|
8
|
+
0 0 1 0 0
|
|
9
|
+
0 0 0 0.15 0`,result:`transparency`}),(0,l.jsx)(`feBlend`,{in:`SourceGraphic`,in2:`transparency`,mode:`normal`})]}),f=`0 6px 6px rgba(0, 0, 0, 0.2), 0 0 20px rgba(0, 0, 0, 0.1)`,p=`0 8px 32px rgba(0,0,0,0.28)`,m=`inset 0 1px 0 0 rgba(255,255,255,0.55), inset 0 -1px 1px 0 rgba(255,255,255,0.12), inset 0 0 0 1px rgba(255,255,255,0.08)`,h=e=>Array.isArray(e)?`${e[0]} ${e[1]}`:`${e}`,g=({children:e,className:n=``,backdropBlur:r=2,tintColor:i=`rgba(255, 255, 255, .2)`,displacementScale:a=150,turbulenceBaseFrequency:s=.008,turbulenceSeed:c=1.5,as:g=`div`,style:_,glassBorder:v=!1,...y})=>{let b=(0,t.useId)(),{hasFullFilterSupport:x}=o(),S=h(s);return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`svg`,{style:{display:`none`},children:x?(0,l.jsx)(u,{id:b,turbulenceBaseFrequency:S,turbulenceSeed:c,displacementScale:a}):(0,l.jsx)(d,{id:b,turbulenceBaseFrequency:S,turbulenceSeed:c})}),(0,l.jsxs)(g,{className:n,style:{position:`relative`,overflow:`hidden`,boxShadow:v?p:f,..._},...y,children:[(0,l.jsx)(`div`,{style:{position:`absolute`,inset:0,zIndex:0,overflow:`hidden`,borderRadius:`inherit`,backdropFilter:`blur(${r}px)`,WebkitBackdropFilter:`blur(${r}px)`,filter:`url(#${b})`,isolation:`isolate`,...!x&&{transform:`translateZ(0)`,willChange:`transform`}}}),(0,l.jsx)(`div`,{style:{position:`absolute`,inset:0,zIndex:1,borderRadius:`inherit`,background:i}}),v&&(0,l.jsx)(`span`,{"aria-hidden":`true`,style:{position:`absolute`,inset:0,zIndex:2,borderRadius:`inherit`,pointerEvents:`none`,background:`linear-gradient(135deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0) 38%, rgba(255,255,255,0) 62%, rgba(255,255,255,0.06) 100%)`,boxShadow:m}}),(0,l.jsx)(`div`,{style:{position:`relative`,zIndex:3,borderRadius:`inherit`},children:e})]})]})};e.LiquidGlass=g,e.default=g});
|
package/docs/banner.svg
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<svg
|
|
2
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
3
|
+
viewBox="0 0 1200 630"
|
|
4
|
+
fill="none"
|
|
5
|
+
>
|
|
6
|
+
<defs>
|
|
7
|
+
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
8
|
+
<stop offset="0%" stop-color="#0a0b10" />
|
|
9
|
+
<stop offset="100%" stop-color="#12141d" />
|
|
10
|
+
</linearGradient>
|
|
11
|
+
<radialGradient id="b1" cx="20%" cy="30%" r="40%">
|
|
12
|
+
<stop offset="0%" stop-color="#4f7bff" stop-opacity="0.9" />
|
|
13
|
+
<stop offset="100%" stop-color="#4f7bff" stop-opacity="0" />
|
|
14
|
+
</radialGradient>
|
|
15
|
+
<radialGradient id="b2" cx="80%" cy="20%" r="40%">
|
|
16
|
+
<stop offset="0%" stop-color="#b14bff" stop-opacity="0.9" />
|
|
17
|
+
<stop offset="100%" stop-color="#b14bff" stop-opacity="0" />
|
|
18
|
+
</radialGradient>
|
|
19
|
+
<radialGradient id="b3" cx="70%" cy="85%" r="40%">
|
|
20
|
+
<stop offset="0%" stop-color="#1fd6c0" stop-opacity="0.9" />
|
|
21
|
+
<stop offset="100%" stop-color="#1fd6c0" stop-opacity="0" />
|
|
22
|
+
</radialGradient>
|
|
23
|
+
<radialGradient id="b4" cx="15%" cy="80%" r="40%">
|
|
24
|
+
<stop offset="0%" stop-color="#ff5fae" stop-opacity="0.9" />
|
|
25
|
+
<stop offset="100%" stop-color="#ff5fae" stop-opacity="0" />
|
|
26
|
+
</radialGradient>
|
|
27
|
+
<linearGradient id="mark-grad" x1="20%" y1="10%" x2="85%" y2="100%">
|
|
28
|
+
<stop offset="0%" stop-color="#a8e4f0" />
|
|
29
|
+
<stop offset="45%" stop-color="#5fa8ff" />
|
|
30
|
+
<stop offset="100%" stop-color="#b14bff" />
|
|
31
|
+
</linearGradient>
|
|
32
|
+
<radialGradient id="mark-glow" cx="32%" cy="25%" r="55%">
|
|
33
|
+
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.75" />
|
|
34
|
+
<stop offset="55%" stop-color="#ffffff" stop-opacity="0" />
|
|
35
|
+
</radialGradient>
|
|
36
|
+
<linearGradient id="title-grad" x1="0%" y1="0%" x2="100%" y2="0%">
|
|
37
|
+
<stop offset="0%" stop-color="#a8e4f0" />
|
|
38
|
+
<stop offset="50%" stop-color="#5fa8ff" />
|
|
39
|
+
<stop offset="100%" stop-color="#c084fc" />
|
|
40
|
+
</linearGradient>
|
|
41
|
+
</defs>
|
|
42
|
+
|
|
43
|
+
<rect width="1200" height="630" fill="url(#bg)" />
|
|
44
|
+
<rect width="1200" height="630" fill="url(#b1)" />
|
|
45
|
+
<rect width="1200" height="630" fill="url(#b2)" />
|
|
46
|
+
<rect width="1200" height="630" fill="url(#b3)" />
|
|
47
|
+
<rect width="1200" height="630" fill="url(#b4)" />
|
|
48
|
+
<rect width="1200" height="630" fill="#0a0b10" opacity="0.45" />
|
|
49
|
+
|
|
50
|
+
<g transform="translate(80 220)">
|
|
51
|
+
<rect width="80" height="80" rx="22" fill="url(#mark-grad)" />
|
|
52
|
+
<rect width="80" height="80" rx="22" fill="url(#mark-glow)" />
|
|
53
|
+
</g>
|
|
54
|
+
|
|
55
|
+
<text
|
|
56
|
+
x="190"
|
|
57
|
+
y="288"
|
|
58
|
+
font-family="'Space Grotesk', system-ui, sans-serif"
|
|
59
|
+
font-size="40"
|
|
60
|
+
font-weight="600"
|
|
61
|
+
fill="#eef0f6"
|
|
62
|
+
>
|
|
63
|
+
yuragon<tspan fill="#6b7186">/</tspan>liquid-glass-svg
|
|
64
|
+
</text>
|
|
65
|
+
|
|
66
|
+
<text
|
|
67
|
+
x="80"
|
|
68
|
+
y="400"
|
|
69
|
+
font-family="'Space Grotesk', system-ui, sans-serif"
|
|
70
|
+
font-size="78"
|
|
71
|
+
font-weight="700"
|
|
72
|
+
letter-spacing="-2"
|
|
73
|
+
fill="url(#title-grad)"
|
|
74
|
+
>
|
|
75
|
+
Apple liquid glass
|
|
76
|
+
</text>
|
|
77
|
+
<text
|
|
78
|
+
x="80"
|
|
79
|
+
y="478"
|
|
80
|
+
font-family="'Space Grotesk', system-ui, sans-serif"
|
|
81
|
+
font-size="78"
|
|
82
|
+
font-weight="700"
|
|
83
|
+
letter-spacing="-2"
|
|
84
|
+
fill="#eef0f6"
|
|
85
|
+
>
|
|
86
|
+
for React
|
|
87
|
+
</text>
|
|
88
|
+
|
|
89
|
+
<text
|
|
90
|
+
x="80"
|
|
91
|
+
y="540"
|
|
92
|
+
font-family="'JetBrains Mono', ui-monospace, monospace"
|
|
93
|
+
font-size="22"
|
|
94
|
+
fill="#aab0c2"
|
|
95
|
+
>
|
|
96
|
+
pure SVG filters · backdrop-blur · no WebGL · no shaders
|
|
97
|
+
</text>
|
|
98
|
+
|
|
99
|
+
<text
|
|
100
|
+
x="80"
|
|
101
|
+
y="585"
|
|
102
|
+
font-family="'JetBrains Mono', ui-monospace, monospace"
|
|
103
|
+
font-size="18"
|
|
104
|
+
fill="#6b7186"
|
|
105
|
+
>
|
|
106
|
+
npm install react-liquid-glass-svg
|
|
107
|
+
</text>
|
|
108
|
+
</svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/logo.svg
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<svg
|
|
2
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
3
|
+
viewBox="0 0 64 64"
|
|
4
|
+
fill="none"
|
|
5
|
+
>
|
|
6
|
+
<defs>
|
|
7
|
+
<linearGradient id="lg-grad" x1="20%" y1="10%" x2="85%" y2="100%">
|
|
8
|
+
<stop offset="0%" stop-color="oklch(0.86 0.12 200)" />
|
|
9
|
+
<stop offset="45%" stop-color="oklch(0.74 0.15 245)" />
|
|
10
|
+
<stop offset="100%" stop-color="oklch(0.66 0.2 300)" />
|
|
11
|
+
</linearGradient>
|
|
12
|
+
<radialGradient id="lg-glow" cx="32%" cy="25%" r="55%">
|
|
13
|
+
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.75" />
|
|
14
|
+
<stop offset="55%" stop-color="#ffffff" stop-opacity="0" />
|
|
15
|
+
</radialGradient>
|
|
16
|
+
<linearGradient id="lg-rim" x1="50%" y1="0%" x2="50%" y2="100%">
|
|
17
|
+
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.7" />
|
|
18
|
+
<stop offset="100%" stop-color="#ffffff" stop-opacity="0.05" />
|
|
19
|
+
</linearGradient>
|
|
20
|
+
</defs>
|
|
21
|
+
|
|
22
|
+
<!-- Base squircle with gradient fill -->
|
|
23
|
+
<rect x="6" y="6" width="52" height="52" rx="18" fill="url(#lg-grad)" />
|
|
24
|
+
|
|
25
|
+
<!-- Specular radial glow in top-left -->
|
|
26
|
+
<rect x="6" y="6" width="52" height="52" rx="18" fill="url(#lg-glow)" />
|
|
27
|
+
|
|
28
|
+
<!-- Inner rim highlight -->
|
|
29
|
+
<rect
|
|
30
|
+
x="6.5"
|
|
31
|
+
y="6.5"
|
|
32
|
+
width="51"
|
|
33
|
+
height="51"
|
|
34
|
+
rx="17.5"
|
|
35
|
+
fill="none"
|
|
36
|
+
stroke="url(#lg-rim)"
|
|
37
|
+
stroke-width="1"
|
|
38
|
+
/>
|
|
39
|
+
</svg>
|
package/docs/preview.png
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-liquid-glass-svg",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Apple liquid glass for React — pure SVG filters and backdrop-blur. No WebGL, no canvas, no shaders.",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.esm.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"homepage": "https://github.com/yurkagon/react-liquid-glass-svg#readme",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/yurkagon/react-liquid-glass-svg.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/yurkagon/react-liquid-glass-svg/issues"
|
|
16
|
+
},
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.esm.js",
|
|
21
|
+
"require": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./package.json": "./package.json"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"docs",
|
|
28
|
+
"README.md",
|
|
29
|
+
"CHANGELOG.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"keywords": [
|
|
34
|
+
"react",
|
|
35
|
+
"liquid-glass",
|
|
36
|
+
"frosted-glass",
|
|
37
|
+
"glassmorphism",
|
|
38
|
+
"glass-effect",
|
|
39
|
+
"svg-filter",
|
|
40
|
+
"displacement-map",
|
|
41
|
+
"backdrop-filter",
|
|
42
|
+
"refraction",
|
|
43
|
+
"ios",
|
|
44
|
+
"apple",
|
|
45
|
+
"polymorphic",
|
|
46
|
+
"typescript",
|
|
47
|
+
"nextjs",
|
|
48
|
+
"tailwind"
|
|
49
|
+
],
|
|
50
|
+
"author": {
|
|
51
|
+
"name": "Yurii Khvyshchuk"
|
|
52
|
+
},
|
|
53
|
+
"license": "MIT",
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"react": ">=18.0.0",
|
|
56
|
+
"react-dom": ">=18.0.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
60
|
+
"@testing-library/react": "^16.3.2",
|
|
61
|
+
"@types/react": "^19.2.17",
|
|
62
|
+
"@types/react-dom": "^19.2.3",
|
|
63
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
64
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
65
|
+
"jsdom": "^29.1.1",
|
|
66
|
+
"react": "^19.2.7",
|
|
67
|
+
"react-dom": "^19.2.7",
|
|
68
|
+
"typescript": "^6.0.3",
|
|
69
|
+
"vite": "^8.0.16",
|
|
70
|
+
"vite-plugin-dts": "^5.0.2",
|
|
71
|
+
"vitest": "^4.1.8"
|
|
72
|
+
},
|
|
73
|
+
"publishConfig": {
|
|
74
|
+
"registry": "https://registry.npmjs.org/",
|
|
75
|
+
"access": "public"
|
|
76
|
+
},
|
|
77
|
+
"scripts": {
|
|
78
|
+
"sync-meta": "node scripts/copy-meta.mjs",
|
|
79
|
+
"build": "pnpm sync-meta && tsc && vite build",
|
|
80
|
+
"test": "vitest",
|
|
81
|
+
"test:run": "vitest run",
|
|
82
|
+
"test:coverage": "vitest run --coverage"
|
|
83
|
+
}
|
|
84
|
+
}
|