@aberhamm/liquid-glass-react 0.2.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.
@@ -0,0 +1,464 @@
1
+ /**
2
+ * Public type contracts for `@aberhamm/liquid-glass-react`.
3
+ *
4
+ * These types are the load-bearing surface that every later plan (refraction,
5
+ * motion, fallback, prebuilt components) builds against. They are defined ONCE
6
+ * here so the API cannot drift between plans. No runtime code lives in this
7
+ * file — it is types only.
8
+ */
9
+ import type { CSSProperties, MouseEventHandler, ReactNode, RefObject } from 'react';
10
+ /**
11
+ * The displacement/refraction algorithm used to generate the SVG
12
+ * `feDisplacementMap` and tune the glass distortion.
13
+ *
14
+ * - `standard` — balanced edge-weighted displacement (the default look).
15
+ * - `polar` — radial/polar displacement, stronger toward the perimeter.
16
+ * - `prominent` — exaggerated displacement for a heavier "thick glass" feel.
17
+ * - `shader` — shader-style displacement profile for sharper highlights.
18
+ * - `turbulence` — adds fractal turbulence for an organic, watery distortion.
19
+ *
20
+ * @defaultValue `'standard'`
21
+ */
22
+ export type DisplacementMode = 'standard' | 'polar' | 'prominent' | 'shader' | 'turbulence';
23
+ /**
24
+ * The two Liquid Glass material variants Apple distinguishes — selected with one
25
+ * intentional prop instead of hand-tuning opacity.
26
+ *
27
+ * - `regular` — the dependable, fully adaptive control surface. Exactly the
28
+ * current behavior, including content-adaptive auto-tint when
29
+ * {@link LiquidGlassProps.adaptiveTint} is enabled.
30
+ * - `clear` — a permanently MORE transparent material for media-rich contexts
31
+ * (e.g. floating over a photo). It is **non-adaptive by definition**:
32
+ * {@link LiquidGlassProps.adaptiveTint} is force-disabled, and an optional
33
+ * dimming scrim sits behind the content so labels stay legible over busy media.
34
+ *
35
+ * Apple's guidance is that the two **should never be mixed** in the same context.
36
+ *
37
+ * @defaultValue `'regular'`
38
+ */
39
+ export type GlassVariant = 'regular' | 'clear';
40
+ /**
41
+ * Explicit lens size (CSS pixels) for the cross-browser copy-refraction path
42
+ * (plan 030). When omitted the lens is sized to the glass's measured dimensions.
43
+ */
44
+ export interface GlassSize {
45
+ /** Lens width in CSS pixels. */
46
+ width: number;
47
+ /** Lens height in CSS pixels. */
48
+ height: number;
49
+ }
50
+ /**
51
+ * Lens focal point for the cross-browser copy-refraction path (plan 030),
52
+ * expressed as fractions of the lens box in `[0, 1]` (`{ x: 0.5, y: 0.5 }` is
53
+ * the center). It drives the refracted copy's `transform-origin`, so the warp
54
+ * reads as if the light bends around that point.
55
+ */
56
+ export interface GlassCenter {
57
+ /** Horizontal focal point as a fraction of the lens width (`0`–`1`). */
58
+ x: number;
59
+ /** Vertical focal point as a fraction of the lens height (`0`–`1`). */
60
+ y: number;
61
+ }
62
+ /**
63
+ * A 2D pointer position in CSS pixels, used for mouse-driven motion/elasticity.
64
+ *
65
+ * Coordinates are interpreted relative to whatever container the consumer wires
66
+ * up via {@link LiquidGlassProps.mouseContainer} (viewport by default).
67
+ */
68
+ export type MousePos = {
69
+ /** Horizontal position in CSS pixels. */
70
+ x: number;
71
+ /** Vertical position in CSS pixels. */
72
+ y: number;
73
+ };
74
+ /**
75
+ * Result of runtime capability detection. Every field is a plain boolean so the
76
+ * object is trivially serializable and cheap to compare across renders.
77
+ *
78
+ * Produced by `detectGlassCapabilities()` and surfaced to components via the
79
+ * `useGlassCapabilities()` hook. During SSR (and before mount) all fields are
80
+ * conservatively `false`.
81
+ */
82
+ export type GlassCapabilities = {
83
+ /**
84
+ * Whether the browser supports `backdrop-filter` (or the `-webkit-` prefixed
85
+ * variant). Required for any frosted-glass blur at all.
86
+ */
87
+ supportsBackdropFilter: boolean;
88
+ /**
89
+ * Positive Blink-family detection (Chrome, Edge, Brave, Opera). Explicitly
90
+ * NOT Firefox and NOT Safari/WebKit.
91
+ */
92
+ isChromium: boolean;
93
+ /**
94
+ * Whether an SVG `feDisplacementMap` filter composites correctly over
95
+ * `backdrop-filter`. This is a Chromium-only rendering-pipeline quirk with no
96
+ * standardized `CSS.supports` probe, so it is derived from {@link isChromium}.
97
+ */
98
+ supportsSvgBackdropDisplacement: boolean;
99
+ /** Whether the user agent is Firefox (Gecko). */
100
+ isFirefox: boolean;
101
+ /**
102
+ * Whether the user has requested reduced motion via
103
+ * `(prefers-reduced-motion: reduce)`.
104
+ */
105
+ prefersReducedMotion: boolean;
106
+ /**
107
+ * Whether the user has requested reduced transparency via
108
+ * `(prefers-reduced-transparency: reduce)`. When `true`, `<LiquidGlass>`
109
+ * suppresses live SVG refraction and renders a frostier, more-opaque surface.
110
+ * Orthogonal to {@link canRefract} — it applies on every tier and changes no
111
+ * box geometry. The authoritative live source is `useReducedTransparency()`;
112
+ * this field is a point-in-time snapshot.
113
+ */
114
+ prefersReducedTransparency: boolean;
115
+ /**
116
+ * Whether the user has requested increased contrast via
117
+ * `(prefers-contrast: more)`. When `true`, `<LiquidGlass>` adds a solid,
118
+ * visible inset border, raises content legibility (a more-opaque surface
119
+ * fill), and tones down decorative saturation/aberration that harms contrast.
120
+ * Orthogonal to {@link canRefract} AND to {@link prefersReducedTransparency} —
121
+ * it applies on every tier, composes with reduced-transparency, and changes no
122
+ * box geometry. The authoritative live source is `usePrefersContrast()`; this
123
+ * field is a point-in-time snapshot.
124
+ */
125
+ prefersContrastMore: boolean;
126
+ /**
127
+ * The single gate later plans consult: `true` only when the full refraction
128
+ * effect can actually render
129
+ * (`supportsBackdropFilter && supportsSvgBackdropDisplacement`). When `false`,
130
+ * components must fall back to a degraded (non-refractive) presentation.
131
+ */
132
+ canRefract: boolean;
133
+ };
134
+ /**
135
+ * PLATFORM-NEUTRAL props for the `<LiquidGlass>` PRIMITIVE.
136
+ *
137
+ * The shared base that BOTH the web (`liquid-glass.tsx`) and React Native
138
+ * (`liquid-glass.native.tsx`, plan 025) surfaces extend. It holds every prop
139
+ * that does NOT depend on DOM types, so the native surface can build on it
140
+ * without leaking `CSSProperties` / DOM event handlers. The web
141
+ * {@link LiquidGlassProps} extends this with the DOM-only `style` / `onClick` /
142
+ * pointer props; the native barrel defines its own `style?: ViewStyle` /
143
+ * `onPress?` over this same core.
144
+ *
145
+ * Every prop except {@link children} is optional — the primitive ships sensible
146
+ * defaults. Defaults documented here are the contract; the implementation plan
147
+ * (004+) must honor them.
148
+ */
149
+ export interface LiquidGlassCoreProps {
150
+ /** Content rendered inside the glass surface. */
151
+ children: ReactNode;
152
+ /**
153
+ * Opt into the live SVG refraction/displacement pass (WEB-ONLY progressive
154
+ * enhancement). When `false` (the default) the glass renders the frosted
155
+ * fallback look — `blur()`/`saturate()` backdrop plus the pure-CSS bevel —
156
+ * with no `feDisplacementMap`.
157
+ *
158
+ * - **Web:** when `true` AND the browser can refract (Chromium), the SVG
159
+ * displacement filter is attached; otherwise it degrades to the frosted look.
160
+ * - **React Native:** a documented NO-OP. RN has no SVG-over-backdrop
161
+ * compositing, so the prop is accepted for a single cross-platform contract
162
+ * but the surface always renders the frosted fallback.
163
+ *
164
+ * @defaultValue `false`
165
+ */
166
+ displacement?: boolean;
167
+ /**
168
+ * Strength of the displacement/refraction distortion. Higher values bend the
169
+ * backdrop more aggressively.
170
+ *
171
+ * @defaultValue `70`
172
+ */
173
+ displacementScale?: number;
174
+ /**
175
+ * Backdrop blur radius in pixels applied behind the glass.
176
+ *
177
+ * @defaultValue `0.0625`
178
+ */
179
+ blurAmount?: number;
180
+ /**
181
+ * Backdrop saturation multiplier (`1` = unchanged). Boosts color vibrancy of
182
+ * the content seen through the glass.
183
+ *
184
+ * @defaultValue `140`
185
+ */
186
+ saturation?: number;
187
+ /**
188
+ * Intensity of the chromatic aberration (RGB channel separation) at the
189
+ * refracted edges. `0` disables it.
190
+ *
191
+ * @defaultValue `2`
192
+ */
193
+ aberrationIntensity?: number;
194
+ /**
195
+ * How elastically the glass reacts to pointer movement. `0` is rigid; higher
196
+ * values produce a softer, more rubbery follow.
197
+ *
198
+ * @defaultValue `0.15`
199
+ */
200
+ elasticity?: number;
201
+ /**
202
+ * Corner radius of the glass surface. A number is treated as pixels; a string
203
+ * is passed through as a CSS length (e.g. `'1rem'`, `'50%'`).
204
+ *
205
+ * @defaultValue `999`
206
+ */
207
+ cornerRadius?: number | string;
208
+ /**
209
+ * Inner padding of the glass surface. A number is treated as pixels; a string
210
+ * is passed through as a CSS shorthand (e.g. `'8px 16px'`).
211
+ *
212
+ * @defaultValue `'24px'`
213
+ */
214
+ padding?: number | string;
215
+ /**
216
+ * Hint that the glass sits over a light background, so it tunes its tint and
217
+ * contrast for legibility.
218
+ *
219
+ * This is the MANUAL override. When set explicitly it ALWAYS wins over
220
+ * {@link adaptiveTint} (see that prop's precedence note) — the two never fight.
221
+ *
222
+ * @defaultValue `false`
223
+ */
224
+ overLight?: boolean;
225
+ /**
226
+ * Opt into CONTENT-ADAPTIVE auto-tint (plan 018). When `true`, the glass
227
+ * samples the luminance of the backdrop behind it (via the plan-017 sampler)
228
+ * and automatically shifts toward a light or dark treatment — the SAME tint /
229
+ * displacement / blur plumbing {@link overLight} already drives — so foreground
230
+ * content stays legible without hand-tuning `overLight`. A bright backdrop
231
+ * yields the light treatment (`overLight`-equivalent), a dark backdrop the
232
+ * default treatment.
233
+ *
234
+ * ## Precedence (documented rule)
235
+ *
236
+ * An EXPLICIT {@link overLight} always wins. `adaptiveTint` only drives the
237
+ * light/dark treatment when `overLight` is left unset/undefined:
238
+ *
239
+ * ```ts
240
+ * effectiveOverLight = overLight ?? (adaptiveTint && scheme ? scheme === 'light' : false)
241
+ * ```
242
+ *
243
+ * ## SSR / hydration
244
+ *
245
+ * The server and the first client paint render the default (unsampled,
246
+ * conservative) treatment, so hydration never mismatches. The sampled treatment
247
+ * is applied in an effect after mount.
248
+ *
249
+ * ## Graceful degradation
250
+ *
251
+ * When the backdrop cannot be sampled (cross-origin-tainted canvas, no canvas,
252
+ * SSR) the reading is `sampled: false` and auto-tint falls back to
253
+ * `overLight ?? false` with no error, no flicker loop, and no `console.error`.
254
+ *
255
+ * ## Accessibility interaction
256
+ *
257
+ * Under `(prefers-contrast: more)` (plan 014) the high-contrast treatment wins:
258
+ * auto-tint never undercuts the increased-contrast surface/legibility treatment.
259
+ *
260
+ * ## Limitation
261
+ *
262
+ * Auto-tint is BEST-EFFORT legibility. Critical text over unknown or
263
+ * cross-origin backdrops (which cannot be sampled) should be verified manually —
264
+ * the auto path silently falls back rather than guessing.
265
+ *
266
+ * @defaultValue `false`
267
+ */
268
+ adaptiveTint?: boolean;
269
+ /**
270
+ * Opt into SCROLL-AWARE SHADOW (plan 021). When `true`, the glass's decoupled
271
+ * outer drop-shadow (the `[data-lg-shadow]` sibling rendered behind the clipped
272
+ * surface) modulates its depth/darkness from the backdrop behind the element
273
+ * (via the plan-017 sampler): it DEEPENS and DARKENS over a dark/dense backdrop
274
+ * (reinforcing the "floating above content" read as text scrolls beneath) and
275
+ * EASES/LIGHTENS over a light/solid one. Apple's Liquid Glass does exactly this
276
+ * as content scrolls under a pinned glass bar.
277
+ *
278
+ * ## What it touches
279
+ *
280
+ * ONLY the existing drop-shadow sibling's blur/offset/opacity vary. The shadow
281
+ * stays a SIBLING of the `overflow:hidden` glass surface (never a box-shadow on
282
+ * the clipped node — the plan-005 layering invariant); no new layer is added.
283
+ *
284
+ * ## SSR / hydration
285
+ *
286
+ * The server and the first client paint render the conservative static shadow,
287
+ * so hydration never mismatches. The modulated shadow is applied in an effect
288
+ * after mount; sampling is throttled by the hook.
289
+ *
290
+ * ## Graceful degradation
291
+ *
292
+ * When the backdrop cannot be sampled (cross-origin-tainted canvas, no canvas,
293
+ * SSR) the reading is `sampled: false` and the shadow falls back to the current
294
+ * static shadow with no error and no flicker loop.
295
+ *
296
+ * ## Reduced motion
297
+ *
298
+ * Under `(prefers-reduced-motion: reduce)` the shadow does not animate between
299
+ * depths — it snaps/stays static (no transition).
300
+ *
301
+ * This is ADDITIVE and non-breaking: omitting it (default `false`) keeps today's
302
+ * rendering byte-for-byte and leaves the committed pixel baseline unchanged.
303
+ *
304
+ * @defaultValue `false`
305
+ */
306
+ scrollAwareShadow?: boolean;
307
+ /**
308
+ * The Liquid Glass material variant. See {@link GlassVariant}.
309
+ *
310
+ * - `'regular'` (default) — EXACTLY the current behavior, including
311
+ * content-adaptive auto-tint when {@link adaptiveTint} is enabled. The
312
+ * dependable, fully adaptive control surface.
313
+ * - `'clear'` — a permanently MORE transparent surface (lower fill opacity /
314
+ * reduced tint) for media-rich contexts, with an optional dimming scrim
315
+ * behind the content so labels stay legible over busy media. Geometry is
316
+ * unchanged from `'regular'`.
317
+ *
318
+ * ## Interaction rules
319
+ *
320
+ * - **Clear is non-adaptive by definition.** In `'clear'`, {@link adaptiveTint}
321
+ * is a **no-op** — the glass never samples the backdrop and never flips its
322
+ * tint/ink. (Use `'regular'` + `adaptiveTint` for the adaptive material.)
323
+ * - **`overLight` still nudges legibility, not adaptivity.** In `'clear'`, an
324
+ * explicit {@link overLight} may still tune the dimming/legibility treatment,
325
+ * but it does NOT re-enable the adaptive sampling path.
326
+ * - **Accessibility wins.** Under `(prefers-contrast: more)` (plan 014) the
327
+ * high-contrast treatment STILL applies in both variants — a11y beats the
328
+ * Clear aesthetic, so Clear surfaces become legible/high-contrast when the
329
+ * user asks for it.
330
+ *
331
+ * Per Apple's guidance, the two variants **should never be mixed** in the same
332
+ * context. This is ADDITIVE and non-breaking: omitting it keeps today's
333
+ * behavior exactly.
334
+ *
335
+ * @defaultValue `'regular'`
336
+ */
337
+ variant?: GlassVariant;
338
+ /**
339
+ * Which displacement algorithm to use. See {@link DisplacementMode}.
340
+ *
341
+ * @defaultValue `'standard'`
342
+ */
343
+ mode?: DisplacementMode;
344
+ /**
345
+ * CROSS-BROWSER copy-refraction content (plan 030). Distinct from
346
+ * {@link displacement} (the Chromium-only `backdrop-filter: url(#…)` bend of
347
+ * the LIVE page behind the glass): this path applies the SAME SVG displacement
348
+ * filter as an ELEMENT `filter: url(#…)` to a COPY of content, which DOES run in
349
+ * Chromium, Firefox, AND WebKit. The refracted copy is a decorative sibling
350
+ * BEHIND the crisp {@link children} (never an ancestor of them), so interactive
351
+ * content stays selectable and clickable.
352
+ *
353
+ * - **`refract` set** — the copy layer renders THIS node (a lens floated over
354
+ * content the glass doesn't own), filtered; {@link behind} fills the bleed and
355
+ * crisp {@link children} render on top. The node re-renders with the parent
356
+ * (React keeps it in sync) and the lens region re-measures on resize.
357
+ * - **`refract` unset but {@link size}/{@link center} set** — IN-PLACE mode: the
358
+ * glass refracts a copy of its OWN {@link children} through the element filter,
359
+ * with the crisp children on top.
360
+ *
361
+ * Omitting `refract`, {@link size}, AND {@link center} disables this path
362
+ * entirely — the render is byte-for-byte the {@link displacement} behavior.
363
+ *
364
+ * ## Contract: the refracted copy must be PRESENTATIONAL
365
+ *
366
+ * The copy layer renders a SECOND instance of the copied node (`refract`, or —
367
+ * in IN-PLACE mode — a copy of {@link children}). It is `aria-hidden` + `inert`
368
+ * + `pointer-events: none`, so it is hidden from the a11y tree and cannot be
369
+ * interacted with. But React still MOUNTS it, so the copied subtree should be
370
+ * PURELY PRESENTATIONAL:
371
+ *
372
+ * - **No `id`s / label targets / in-page anchor targets** — they would be
373
+ * duplicated in the DOM (`getElementById` / `label[for]` / `#hash` could bind
374
+ * the hidden copy).
375
+ * - **No effects / focus-on-mount / data fetching / callback refs** — they run
376
+ * for BOTH instances.
377
+ * - **No focusable controls** on engines that don't honor `inert` (older
378
+ * Safari/Firefox), where they could otherwise become tabbable inside an
379
+ * `aria-hidden` subtree.
380
+ *
381
+ * For anything non-trivial, prefer `refract={<decorative node>}` (a background
382
+ * you fully control) over IN-PLACE copying of rich interactive `children`.
383
+ * Passing `refract={null}` opts in but renders an EMPTY lens (only the
384
+ * {@link behind} bleed) — it does NOT fall back to copying `children`.
385
+ *
386
+ * **React Native:** a documented NO-OP (no SVG filters; always frosted).
387
+ *
388
+ * @defaultValue `undefined`
389
+ */
390
+ refract?: ReactNode;
391
+ /**
392
+ * Explicit lens {@link GlassSize} for the copy-refraction path (plan 030). When
393
+ * omitted the lens is sized to the glass's measured dimensions. Presence of this
394
+ * prop (with or without {@link refract}) opts INTO the cross-browser copy
395
+ * refraction in IN-PLACE mode (refract a copy of the own {@link children}).
396
+ *
397
+ * **React Native:** a documented NO-OP.
398
+ *
399
+ * @defaultValue `undefined` (use measured dimensions)
400
+ */
401
+ size?: GlassSize;
402
+ /**
403
+ * Lens focal point ({@link GlassCenter}, fractions in `[0, 1]`) for the
404
+ * copy-refraction path (plan 030). Drives the refracted copy's
405
+ * `transform-origin`. Presence opts into the cross-browser copy refraction in
406
+ * IN-PLACE mode, same as {@link size}.
407
+ *
408
+ * **React Native:** a documented NO-OP.
409
+ *
410
+ * @defaultValue `{ x: 0.5, y: 0.5 }` (center)
411
+ */
412
+ center?: GlassCenter;
413
+ /**
414
+ * Bleed fill (any CSS `background` value) painted behind the refracted copy on
415
+ * the copy-refraction path (plan 030), so the displacement has something to pull
416
+ * from where the copied content doesn't cover the lens box. Most useful with
417
+ * {@link refract} (a lens over foreign content); usually unnecessary for
418
+ * IN-PLACE mode. No effect unless the copy-refraction path is active.
419
+ *
420
+ * **React Native:** a documented NO-OP.
421
+ *
422
+ * @defaultValue `undefined`
423
+ */
424
+ behind?: string;
425
+ /** Additional class name(s) applied to the outermost glass element. */
426
+ className?: string;
427
+ }
428
+ /**
429
+ * Props for the WEB `<LiquidGlass>` PRIMITIVE.
430
+ *
431
+ * The platform-neutral {@link LiquidGlassCoreProps} plus the DOM-only props the
432
+ * web surface needs: inline `style`, the `onClick` handler, and the externally
433
+ * controlled pointer inputs. This is the same surface the library has always
434
+ * exposed — splitting the core out is type-only and changes nothing for web
435
+ * consumers.
436
+ */
437
+ export type LiquidGlassProps = LiquidGlassCoreProps & {
438
+ /** Inline styles merged onto the outermost glass element. */
439
+ style?: CSSProperties;
440
+ /** Click handler forwarded to the glass surface. */
441
+ onClick?: MouseEventHandler<HTMLDivElement>;
442
+ /**
443
+ * Externally controlled global pointer position. When provided, the primitive
444
+ * uses this instead of subscribing to its own pointer events — useful for
445
+ * coordinating many glass surfaces from one shared tracker.
446
+ *
447
+ * Leave undefined for the uncontrolled default (the primitive tracks the
448
+ * pointer itself).
449
+ */
450
+ globalMousePos?: MousePos;
451
+ /**
452
+ * Externally controlled pointer offset relative to the glass element's
453
+ * center, in CSS pixels. Paired with {@link globalMousePos} for fully
454
+ * controlled motion.
455
+ */
456
+ mouseOffset?: MousePos;
457
+ /**
458
+ * Element (or ref to one) whose bounds define the coordinate space for
459
+ * pointer tracking. Defaults to the viewport when omitted or `null`.
460
+ *
461
+ * @defaultValue `null` (viewport)
462
+ */
463
+ mouseContainer?: RefObject<HTMLElement | null> | HTMLElement | null;
464
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Public type contracts for `@aberhamm/liquid-glass-react`.
3
+ *
4
+ * These types are the load-bearing surface that every later plan (refraction,
5
+ * motion, fallback, prebuilt components) builds against. They are defined ONCE
6
+ * here so the API cannot drift between plans. No runtime code lives in this
7
+ * file — it is types only.
8
+ */
9
+ export {};
package/package.json ADDED
@@ -0,0 +1,122 @@
1
+ {
2
+ "name": "@aberhamm/liquid-glass-react",
3
+ "version": "0.2.0",
4
+ "description": "An independent React reimplementation of a liquid-glass UI component library.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Matthew Aberham",
8
+ "keywords": [
9
+ "react",
10
+ "liquid-glass",
11
+ "glassmorphism",
12
+ "backdrop-filter",
13
+ "svg-filter",
14
+ "displacement-map",
15
+ "glass",
16
+ "ui",
17
+ "components",
18
+ "refraction"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/aberhamm/liquid-glass-react.git"
23
+ },
24
+ "homepage": "https://github.com/aberhamm/liquid-glass-react#readme",
25
+ "bugs": {
26
+ "url": "https://github.com/aberhamm/liquid-glass-react/issues"
27
+ },
28
+ "packageManager": "pnpm@10.33.3",
29
+ "sideEffects": ["**/*.css"],
30
+ "files": ["dist"],
31
+ "main": "./dist/index.cjs",
32
+ "module": "./dist/index.mjs",
33
+ "types": "./dist/index.d.ts",
34
+ "react-native": "./dist/native/index.native.js",
35
+ "exports": {
36
+ ".": {
37
+ "react-native": {
38
+ "types": "./dist/native/index.native.d.ts",
39
+ "default": "./dist/native/index.native.js"
40
+ },
41
+ "import": {
42
+ "types": "./dist/index.d.ts",
43
+ "default": "./dist/index.mjs"
44
+ },
45
+ "require": {
46
+ "types": "./dist/index.d.cts",
47
+ "default": "./dist/index.cjs"
48
+ }
49
+ },
50
+ "./styles.css": "./dist/liquid-glass-react.css"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "pnpm": {
56
+ "onlyBuiltDependencies": ["@biomejs/biome", "esbuild"]
57
+ },
58
+ "scripts": {
59
+ "build": "vite build && pnpm build:native",
60
+ "build:native": "tsc -p tsconfig.native.build.json",
61
+ "typecheck": "tsc --noEmit",
62
+ "typecheck:native": "tsc -p tsconfig.native.json --noEmit",
63
+ "lint": "biome check .",
64
+ "format": "biome format --write .",
65
+ "test": "vitest run",
66
+ "test:native": "vitest run --config vitest.native.config.ts",
67
+ "test:watch": "vitest",
68
+ "storybook": "storybook dev -p 6006 --no-open",
69
+ "build-storybook": "storybook build",
70
+ "e2e": "pnpm build-storybook && playwright test",
71
+ "e2e:ui": "pnpm build-storybook && playwright test --ui",
72
+ "attw": "attw --pack . --exclude-entrypoints ./styles.css",
73
+ "pack:check": "npm pack --dry-run",
74
+ "verify:expo": "node scripts/verify-native-resolution.mjs && vitest run --config vitest.native.config.ts",
75
+ "prepublishOnly": "pnpm lint && pnpm typecheck && pnpm test && pnpm build"
76
+ },
77
+ "peerDependencies": {
78
+ "react": ">=18",
79
+ "react-dom": ">=18",
80
+ "react-native": ">=0.74",
81
+ "expo-blur": ">=13",
82
+ "expo-linear-gradient": ">=13"
83
+ },
84
+ "peerDependenciesMeta": {
85
+ "react-native": {
86
+ "optional": true
87
+ },
88
+ "expo-blur": {
89
+ "optional": true
90
+ },
91
+ "expo-linear-gradient": {
92
+ "optional": true
93
+ }
94
+ },
95
+ "devDependencies": {
96
+ "@arethetypeswrong/cli": "^0.18.3",
97
+ "@biomejs/biome": "^1.9.4",
98
+ "@playwright/test": "^1.61.0",
99
+ "@storybook/addon-essentials": "^8.6.14",
100
+ "@storybook/react": "^8.6.18",
101
+ "@storybook/react-vite": "^8.6.18",
102
+ "@testing-library/dom": "^10.4.0",
103
+ "@testing-library/jest-dom": "^6.6.3",
104
+ "@testing-library/react": "^16.1.0",
105
+ "@testing-library/react-native": "^14.0.1",
106
+ "@types/react": "^18.3.18",
107
+ "@types/react-dom": "^18.3.5",
108
+ "expo-blur": "^56.0.3",
109
+ "expo-linear-gradient": "^56.0.4",
110
+ "http-server": "^14.1.1",
111
+ "jsdom": "^25.0.1",
112
+ "react": "^18.3.1",
113
+ "react-dom": "^18.3.1",
114
+ "react-native": "^0.83.10",
115
+ "react-test-renderer": "^18.3.1",
116
+ "storybook": "^8.6.18",
117
+ "typescript": "^5.7.3",
118
+ "vite": "^6.0.7",
119
+ "vite-plugin-dts": "^4.4.0",
120
+ "vitest": "^2.1.8"
121
+ }
122
+ }