@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.
- package/LICENSE +38 -0
- package/README.md +627 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +1191 -0
- package/dist/index.d.ts +1191 -0
- package/dist/index.mjs +1314 -0
- package/dist/liquid-glass-react.css +1 -0
- package/dist/native/index.native.d.ts +19 -0
- package/dist/native/index.native.js +19 -0
- package/dist/native/liquid-glass.native.d.ts +65 -0
- package/dist/native/liquid-glass.native.js +200 -0
- package/dist/native/tokens.d.ts +245 -0
- package/dist/native/tokens.js +254 -0
- package/dist/native/types.d.ts +464 -0
- package/dist/native/types.js +9 -0
- package/package.json +122 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1191 @@
|
|
|
1
|
+
import { ButtonHTMLAttributes } from 'react';
|
|
2
|
+
import { CSSProperties } from 'react';
|
|
3
|
+
import { ForwardRefExoticComponent } from 'react';
|
|
4
|
+
import { HTMLAttributes } from 'react';
|
|
5
|
+
import { MouseEventHandler } from 'react';
|
|
6
|
+
import { ReactNode } from 'react';
|
|
7
|
+
import { RefAttributes } from 'react';
|
|
8
|
+
import { RefObject } from 'react';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Build a complete {@link BackdropSample} from an RGB backdrop estimate.
|
|
12
|
+
*
|
|
13
|
+
* @param color - The estimated backdrop color.
|
|
14
|
+
* @returns A `sampled: true` result with luminance + scheme filled in.
|
|
15
|
+
*/
|
|
16
|
+
export declare function averageColorToSample(color: Rgb): BackdropSample;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The single result contract shared by every sampling strategy and surfaced by
|
|
20
|
+
* `useBackdropLuminance`.
|
|
21
|
+
*/
|
|
22
|
+
export declare interface BackdropSample {
|
|
23
|
+
/**
|
|
24
|
+
* Estimated relative luminance of the backdrop, normalized to `[0, 1]`, or
|
|
25
|
+
* `null` when sampling did not run or could not produce a value (SSR, no
|
|
26
|
+
* window, a tainted canvas, no element under the point).
|
|
27
|
+
*/
|
|
28
|
+
luminance: number | null;
|
|
29
|
+
/**
|
|
30
|
+
* Coarse verdict derived from {@link BackdropSample.luminance} at
|
|
31
|
+
* {@link LIGHT_DARK_THRESHOLD}, or `null` when unsampled.
|
|
32
|
+
*/
|
|
33
|
+
scheme: BackdropScheme | null;
|
|
34
|
+
/** `true` only when a real luminance reading was produced this call. */
|
|
35
|
+
sampled: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A coarse light/dark classification of a backdrop. */
|
|
39
|
+
export declare type BackdropScheme = 'light' | 'dark';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Directional scale (stretch) toward the cursor.
|
|
43
|
+
*
|
|
44
|
+
* The cursor offset `(mouse - center)` is normalized to a unit direction
|
|
45
|
+
* `(nx, ny)`. The stretch magnitude is
|
|
46
|
+
* `min(centerDist / 300, 1) * elasticity * fadeIn`. The element grows along the
|
|
47
|
+
* dominant axis and narrows along the other:
|
|
48
|
+
*
|
|
49
|
+
* ```text
|
|
50
|
+
* scaleX = 1 + |nx| * stretch * 0.3 - |ny| * stretch * 0.15
|
|
51
|
+
* scaleY = 1 + |ny| * stretch * 0.3 - |nx| * stretch * 0.15
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* Both factors are clamped to `>= 0.8`. When `elasticity` is `0` (or the cursor
|
|
55
|
+
* is exactly on center) the result is the identity `{ scaleX: 1, scaleY: 1 }`.
|
|
56
|
+
*
|
|
57
|
+
* @param mouseX - Cursor X in the same coordinate space as `centerX`.
|
|
58
|
+
* @param mouseY - Cursor Y in the same coordinate space as `centerY`.
|
|
59
|
+
* @param centerX - Element center X.
|
|
60
|
+
* @param centerY - Element center Y.
|
|
61
|
+
* @param elasticity - Elastic strength; `0` disables motion entirely.
|
|
62
|
+
*/
|
|
63
|
+
export declare function calculateDirectionalScale(mouseX: number, mouseY: number, centerX: number, centerY: number, elasticity: number): DirectionalScale;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Elastic positional nudge toward the cursor.
|
|
67
|
+
*
|
|
68
|
+
* Translates by `(mouse - center) * elasticity * 0.1 * fadeIn`, where `fadeIn`
|
|
69
|
+
* is the same activation ramp used by {@link calculateDirectionalScale}. When
|
|
70
|
+
* `elasticity` is `0` (or the cursor is on center / out of range) the result is
|
|
71
|
+
* `{ x: 0, y: 0 }`.
|
|
72
|
+
*
|
|
73
|
+
* @param mouseX - Cursor X in the same coordinate space as `centerX`.
|
|
74
|
+
* @param mouseY - Cursor Y in the same coordinate space as `centerY`.
|
|
75
|
+
* @param centerX - Element center X.
|
|
76
|
+
* @param centerY - Element center Y.
|
|
77
|
+
* @param elasticity - Elastic strength; `0` disables motion entirely.
|
|
78
|
+
*/
|
|
79
|
+
export declare function calculateElasticTranslation(mouseX: number, mouseY: number, centerX: number, centerY: number, elasticity: number): ElasticTranslation;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Build a canvas-snapshot strategy from a caller-supplied painter.
|
|
83
|
+
*
|
|
84
|
+
* The library does NOT bundle an HTML-to-canvas renderer (zero new deps). A
|
|
85
|
+
* consumer that wants pixel-accurate sampling passes a `draw` callback that
|
|
86
|
+
* paints the backdrop region into the provided `CanvasRenderingContext2D`; this
|
|
87
|
+
* helper then averages the pixels and returns a {@link BackdropSample}. If the
|
|
88
|
+
* canvas is tainted by cross-origin content, `getImageData` throws
|
|
89
|
+
* `SecurityError` — which {@link safeSample} (or the hook) converts to
|
|
90
|
+
* {@link UNSAMPLED}. This helper does NOT swallow the error itself, so the
|
|
91
|
+
* single taint-handling boundary stays in {@link safeSample}.
|
|
92
|
+
*
|
|
93
|
+
* @param draw - Paints the backdrop into the 2D context for the given size.
|
|
94
|
+
* @returns A {@link SamplingStrategy} that averages the painted pixels.
|
|
95
|
+
*/
|
|
96
|
+
export declare function createCanvasSnapshotStrategy(draw: (ctx: CanvasRenderingContext2D, width: number, height: number) => void, size?: number): SamplingStrategy;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Detect the current browser's liquid-glass capabilities.
|
|
100
|
+
*
|
|
101
|
+
* Safe to call during SSR: returns conservative all-`false` defaults when
|
|
102
|
+
* browser globals are unavailable, and never throws.
|
|
103
|
+
*/
|
|
104
|
+
export declare function detectGlassCapabilities(): GlassCapabilities;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Pure elastic-motion math for `<LiquidGlass>` (plan 005).
|
|
108
|
+
*
|
|
109
|
+
* Two deterministic, side-effect-free functions translate a pointer position
|
|
110
|
+
* (relative to an element's center) into a CSS `transform`:
|
|
111
|
+
*
|
|
112
|
+
* - {@link calculateDirectionalScale} — a directional stretch (the glass bulges
|
|
113
|
+
* toward the cursor, narrows across the perpendicular axis).
|
|
114
|
+
* - {@link calculateElasticTranslation} — a subtle positional nudge toward the
|
|
115
|
+
* cursor.
|
|
116
|
+
*
|
|
117
|
+
* Both share the same activation model: a `fadeIn` ramp that grows as the cursor
|
|
118
|
+
* nears the element, a `stretch` magnitude that scales with distance from center
|
|
119
|
+
* and `elasticity`, and a hard `elasticity === 0 ⇒ no motion` guarantee. The
|
|
120
|
+
* component and the unit tests both consume these exact signatures.
|
|
121
|
+
*/
|
|
122
|
+
/** Result of {@link calculateDirectionalScale}. */
|
|
123
|
+
export declare interface DirectionalScale {
|
|
124
|
+
/** Horizontal scale factor (`1` = unscaled), clamped `>= 0.8`. */
|
|
125
|
+
scaleX: number;
|
|
126
|
+
/** Vertical scale factor (`1` = unscaled), clamped `>= 0.8`. */
|
|
127
|
+
scaleY: number;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The displacement/refraction algorithm used to generate the SVG
|
|
132
|
+
* `feDisplacementMap` and tune the glass distortion.
|
|
133
|
+
*
|
|
134
|
+
* - `standard` — balanced edge-weighted displacement (the default look).
|
|
135
|
+
* - `polar` — radial/polar displacement, stronger toward the perimeter.
|
|
136
|
+
* - `prominent` — exaggerated displacement for a heavier "thick glass" feel.
|
|
137
|
+
* - `shader` — shader-style displacement profile for sharper highlights.
|
|
138
|
+
* - `turbulence` — adds fractal turbulence for an organic, watery distortion.
|
|
139
|
+
*
|
|
140
|
+
* @defaultValue `'standard'`
|
|
141
|
+
*/
|
|
142
|
+
export declare type DisplacementMode = 'standard' | 'polar' | 'prominent' | 'shader' | 'turbulence';
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The default, canvas-free sampling strategy.
|
|
146
|
+
*
|
|
147
|
+
* Walks the elements stacked under `point` (front-to-back via
|
|
148
|
+
* `document.elementsFromPoint`), reads each one's computed `background-color`,
|
|
149
|
+
* and composites them over an assumed-white page base. If an element carries an
|
|
150
|
+
* opaque `background-image` (e.g. a photo or gradient), its real pixel color is
|
|
151
|
+
* unknown to CSSOM, so the walk stops at that layer and treats it as a neutral
|
|
152
|
+
* mid-gray occluder — better than ignoring it (which would let a bright page
|
|
153
|
+
* base bleed through a dark photo). This is a heuristic: it captures solid
|
|
154
|
+
* colors and translucency precisely and image presence coarsely, with zero
|
|
155
|
+
* canvas and zero taint risk.
|
|
156
|
+
*
|
|
157
|
+
* @param point - Viewport coordinates to sample under.
|
|
158
|
+
* @param ignore - An element to skip (the glass surface itself).
|
|
159
|
+
* @returns A sampled {@link BackdropSample}, or {@link UNSAMPLED} when there is
|
|
160
|
+
* no DOM / no element under the point.
|
|
161
|
+
*/
|
|
162
|
+
export declare function domBackgroundStrategy(point: {
|
|
163
|
+
x: number;
|
|
164
|
+
y: number;
|
|
165
|
+
}, ignore?: Element | null): BackdropSample;
|
|
166
|
+
|
|
167
|
+
/** Result of {@link calculateElasticTranslation}. */
|
|
168
|
+
export declare interface ElasticTranslation {
|
|
169
|
+
/** Horizontal nudge in CSS pixels. */
|
|
170
|
+
x: number;
|
|
171
|
+
/** Vertical nudge in CSS pixels. */
|
|
172
|
+
y: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Conservative, all-`false` capability snapshot. Exported so the hook and any
|
|
177
|
+
* consumer can render a stable degraded state during SSR / first paint without
|
|
178
|
+
* re-deriving the shape.
|
|
179
|
+
*/
|
|
180
|
+
export declare function getConservativeGlassCapabilities(): GlassCapabilities;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Generate (or return a cached) displacement map for the given mode and size.
|
|
184
|
+
*
|
|
185
|
+
* Width/height are quantized to a 16px grid before both keying and rendering, so
|
|
186
|
+
* a resize storm of near-identical sizes collapses to a single render while
|
|
187
|
+
* keeping aspect-correct corners. Results are memoized in a bounded LRU
|
|
188
|
+
* (cap {@link CACHE_CAP}).
|
|
189
|
+
*
|
|
190
|
+
* Degenerate input (`width <= 0` or `height <= 0`, or non-finite) returns a 1×1
|
|
191
|
+
* transparent PNG instead of throwing, making the function SSR- and
|
|
192
|
+
* no-dimension-safe.
|
|
193
|
+
*
|
|
194
|
+
* @param mode - Which generator to use. Excludes `'turbulence'` (procedural, 004).
|
|
195
|
+
* @param width - Target map width in px.
|
|
196
|
+
* @param height - Target map height in px.
|
|
197
|
+
* @returns A `data:image/png;base64,…` URL.
|
|
198
|
+
*/
|
|
199
|
+
export declare function getDisplacementMap(mode: MapMode, width: number, height: number): string;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Return the layered inset `box-shadow` string for the requested colour scheme.
|
|
203
|
+
*
|
|
204
|
+
* @param scheme - `'light'` or `'dark'`.
|
|
205
|
+
* @returns The comma-joined `box-shadow` value (see {@link GLASS_EDGE_LIGHT} /
|
|
206
|
+
* {@link GLASS_EDGE_DARK}).
|
|
207
|
+
*/
|
|
208
|
+
export declare function getGlassEdgeShadow(scheme: GlassEdgeScheme): string;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Dark-mode bevel: the highlight direction is flipped to a cooler, dimmer
|
|
212
|
+
* top-left sheen and the lower-right inset shade is deepened so the rim still
|
|
213
|
+
* reads against dark backdrops without blowing out.
|
|
214
|
+
*/
|
|
215
|
+
export declare const GLASS_EDGE_DARK: string;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Light-mode bevel: bright top-left inset highlight, softer bottom-right inset
|
|
219
|
+
* shade, plus a thin hairline ring for crispness. Tuned for glass over light or
|
|
220
|
+
* mid-tone backgrounds.
|
|
221
|
+
*/
|
|
222
|
+
export declare const GLASS_EDGE_LIGHT: string;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Controlled/uncontrolled convention (locked here for the whole library — plan
|
|
226
|
+
* 007 / 012): any future stateful surface MUST accept a `value`/`defaultValue`
|
|
227
|
+
* pair plus an `onValueChange` callback and fall back to internal state when
|
|
228
|
+
* uncontrolled. `GlassButton` itself is stateless, so it exposes none.
|
|
229
|
+
*/
|
|
230
|
+
export declare const GlassButton: ForwardRefExoticComponent<GlassButtonProps & RefAttributes<HTMLButtonElement>>;
|
|
231
|
+
|
|
232
|
+
export declare interface GlassButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
233
|
+
/** Visual emphasis. @defaultValue `'primary'` */
|
|
234
|
+
variant?: GlassButtonVariant;
|
|
235
|
+
/** Sizing; `icon` is square and centers a single icon child. @defaultValue `'md'` */
|
|
236
|
+
size?: GlassButtonSize;
|
|
237
|
+
/**
|
|
238
|
+
* Render the single child element instead of a `<button>`, merging this
|
|
239
|
+
* component's props/className/ref onto it. The child then owns its own
|
|
240
|
+
* semantics and a11y (e.g. an `<a href>` for a link-styled button).
|
|
241
|
+
* @defaultValue `false`
|
|
242
|
+
*/
|
|
243
|
+
asChild?: boolean;
|
|
244
|
+
/** Brief highlight sweep on press. @defaultValue `true` */
|
|
245
|
+
shine?: boolean;
|
|
246
|
+
/** Class applied to the isolated content layer (the span holding children). */
|
|
247
|
+
contentClassName?: string;
|
|
248
|
+
/** Escape hatch: pass-through overrides to the underlying `<LiquidGlass>`. */
|
|
249
|
+
glassProps?: Partial<Omit<LiquidGlassProps, 'children'>>;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export declare type GlassButtonSize = 'sm' | 'md' | 'lg' | 'icon';
|
|
253
|
+
|
|
254
|
+
export declare type GlassButtonVariant = 'primary' | 'secondary' | 'subtle';
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Result of runtime capability detection. Every field is a plain boolean so the
|
|
258
|
+
* object is trivially serializable and cheap to compare across renders.
|
|
259
|
+
*
|
|
260
|
+
* Produced by `detectGlassCapabilities()` and surfaced to components via the
|
|
261
|
+
* `useGlassCapabilities()` hook. During SSR (and before mount) all fields are
|
|
262
|
+
* conservatively `false`.
|
|
263
|
+
*/
|
|
264
|
+
export declare type GlassCapabilities = {
|
|
265
|
+
/**
|
|
266
|
+
* Whether the browser supports `backdrop-filter` (or the `-webkit-` prefixed
|
|
267
|
+
* variant). Required for any frosted-glass blur at all.
|
|
268
|
+
*/
|
|
269
|
+
supportsBackdropFilter: boolean;
|
|
270
|
+
/**
|
|
271
|
+
* Positive Blink-family detection (Chrome, Edge, Brave, Opera). Explicitly
|
|
272
|
+
* NOT Firefox and NOT Safari/WebKit.
|
|
273
|
+
*/
|
|
274
|
+
isChromium: boolean;
|
|
275
|
+
/**
|
|
276
|
+
* Whether an SVG `feDisplacementMap` filter composites correctly over
|
|
277
|
+
* `backdrop-filter`. This is a Chromium-only rendering-pipeline quirk with no
|
|
278
|
+
* standardized `CSS.supports` probe, so it is derived from {@link isChromium}.
|
|
279
|
+
*/
|
|
280
|
+
supportsSvgBackdropDisplacement: boolean;
|
|
281
|
+
/** Whether the user agent is Firefox (Gecko). */
|
|
282
|
+
isFirefox: boolean;
|
|
283
|
+
/**
|
|
284
|
+
* Whether the user has requested reduced motion via
|
|
285
|
+
* `(prefers-reduced-motion: reduce)`.
|
|
286
|
+
*/
|
|
287
|
+
prefersReducedMotion: boolean;
|
|
288
|
+
/**
|
|
289
|
+
* Whether the user has requested reduced transparency via
|
|
290
|
+
* `(prefers-reduced-transparency: reduce)`. When `true`, `<LiquidGlass>`
|
|
291
|
+
* suppresses live SVG refraction and renders a frostier, more-opaque surface.
|
|
292
|
+
* Orthogonal to {@link canRefract} — it applies on every tier and changes no
|
|
293
|
+
* box geometry. The authoritative live source is `useReducedTransparency()`;
|
|
294
|
+
* this field is a point-in-time snapshot.
|
|
295
|
+
*/
|
|
296
|
+
prefersReducedTransparency: boolean;
|
|
297
|
+
/**
|
|
298
|
+
* Whether the user has requested increased contrast via
|
|
299
|
+
* `(prefers-contrast: more)`. When `true`, `<LiquidGlass>` adds a solid,
|
|
300
|
+
* visible inset border, raises content legibility (a more-opaque surface
|
|
301
|
+
* fill), and tones down decorative saturation/aberration that harms contrast.
|
|
302
|
+
* Orthogonal to {@link canRefract} AND to {@link prefersReducedTransparency} —
|
|
303
|
+
* it applies on every tier, composes with reduced-transparency, and changes no
|
|
304
|
+
* box geometry. The authoritative live source is `usePrefersContrast()`; this
|
|
305
|
+
* field is a point-in-time snapshot.
|
|
306
|
+
*/
|
|
307
|
+
prefersContrastMore: boolean;
|
|
308
|
+
/**
|
|
309
|
+
* The single gate later plans consult: `true` only when the full refraction
|
|
310
|
+
* effect can actually render
|
|
311
|
+
* (`supportsBackdropFilter && supportsSvgBackdropDisplacement`). When `false`,
|
|
312
|
+
* components must fall back to a degraded (non-refractive) presentation.
|
|
313
|
+
*/
|
|
314
|
+
canRefract: boolean;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
export declare const GlassCard: ForwardRefExoticComponent<GlassCardProps & RefAttributes<HTMLDivElement>>;
|
|
318
|
+
|
|
319
|
+
export declare type GlassCardElevation = 'flat' | 'raised' | 'floating';
|
|
320
|
+
|
|
321
|
+
export declare interface GlassCardProps extends HTMLAttributes<HTMLDivElement> {
|
|
322
|
+
/** Ambient lift under the card. @defaultValue `'raised'` */
|
|
323
|
+
elevation?: GlassCardElevation;
|
|
324
|
+
/**
|
|
325
|
+
* Render the single child element instead of a `<div>`, merging this
|
|
326
|
+
* component's props/className/ref onto it. The child then owns its semantics.
|
|
327
|
+
* @defaultValue `false`
|
|
328
|
+
*/
|
|
329
|
+
asChild?: boolean;
|
|
330
|
+
/** Class applied to the isolated content layer (the wrapper holding children). */
|
|
331
|
+
contentClassName?: string;
|
|
332
|
+
/** Escape hatch: pass-through overrides to the underlying `<LiquidGlass>`. */
|
|
333
|
+
glassProps?: Partial<Omit<LiquidGlassProps, 'children'>>;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Lens focal point for the cross-browser copy-refraction path (plan 030),
|
|
338
|
+
* expressed as fractions of the lens box in `[0, 1]` (`{ x: 0.5, y: 0.5 }` is
|
|
339
|
+
* the center). It drives the refracted copy's `transform-origin`, so the warp
|
|
340
|
+
* reads as if the light bends around that point.
|
|
341
|
+
*/
|
|
342
|
+
export declare interface GlassCenter {
|
|
343
|
+
/** Horizontal focal point as a fraction of the lens width (`0`–`1`). */
|
|
344
|
+
x: number;
|
|
345
|
+
/** Vertical focal point as a fraction of the lens height (`0`–`1`). */
|
|
346
|
+
y: number;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** Colour scheme selector for {@link getGlassEdgeShadow}. */
|
|
350
|
+
export declare type GlassEdgeScheme = 'light' | 'dark';
|
|
351
|
+
|
|
352
|
+
export declare const GlassSegmentedControl: ForwardRefExoticComponent<GlassSegmentedControlProps & RefAttributes<HTMLFieldSetElement>>;
|
|
353
|
+
|
|
354
|
+
export declare interface GlassSegmentedControlProps {
|
|
355
|
+
/** The selectable segments. */
|
|
356
|
+
options: GlassSegmentedOption[];
|
|
357
|
+
/** Controlled selected value. When set, the component is controlled. */
|
|
358
|
+
value?: string;
|
|
359
|
+
/** Initial selected value when uncontrolled. Defaults to the first option. */
|
|
360
|
+
defaultValue?: string;
|
|
361
|
+
/** Fires on every user selection with the newly-selected value. */
|
|
362
|
+
onValueChange?: (value: string) => void;
|
|
363
|
+
/** Size variant. @defaultValue `'md'` */
|
|
364
|
+
size?: GlassSegmentedControlSize;
|
|
365
|
+
/**
|
|
366
|
+
* Accessible group label. Rendered into the `<legend>` (visually hidden unless
|
|
367
|
+
* `showLabel`) so screen-reader users hear the group's purpose.
|
|
368
|
+
*/
|
|
369
|
+
label?: ReactNode;
|
|
370
|
+
/** Accessible group label as a plain string (alternative to `label`). */
|
|
371
|
+
'aria-label'?: string;
|
|
372
|
+
/** Show the `label` visually above the control instead of hiding it. */
|
|
373
|
+
showLabel?: boolean;
|
|
374
|
+
/** Class applied to the root `<fieldset>`. */
|
|
375
|
+
className?: string;
|
|
376
|
+
/** Inline styles merged onto the root `<fieldset>`. */
|
|
377
|
+
style?: CSSProperties;
|
|
378
|
+
/** Stable `name` for the radio group. Defaults to a generated id. */
|
|
379
|
+
name?: string;
|
|
380
|
+
/** Escape hatch: pass-through overrides to the indicator's `<LiquidGlass>`. */
|
|
381
|
+
glassProps?: Partial<Omit<LiquidGlassProps, 'children'>>;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export declare type GlassSegmentedControlSize = 'sm' | 'md' | 'lg';
|
|
385
|
+
|
|
386
|
+
/** A single selectable segment. `label` and/or `icon` may be supplied. */
|
|
387
|
+
export declare interface GlassSegmentedOption {
|
|
388
|
+
/** Stable value emitted via `onValueChange` and used to mark selection. */
|
|
389
|
+
value: string;
|
|
390
|
+
/** Visible text/content (optional when an `icon` carries the meaning). */
|
|
391
|
+
label?: ReactNode;
|
|
392
|
+
/** Leading icon (optional). Icon-only options are supported. */
|
|
393
|
+
icon?: ReactNode;
|
|
394
|
+
/** Disable this single option. */
|
|
395
|
+
disabled?: boolean;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Explicit lens size (CSS pixels) for the cross-browser copy-refraction path
|
|
400
|
+
* (plan 030). When omitted the lens is sized to the glass's measured dimensions.
|
|
401
|
+
*/
|
|
402
|
+
export declare interface GlassSize {
|
|
403
|
+
/** Lens width in CSS pixels. */
|
|
404
|
+
width: number;
|
|
405
|
+
/** Lens height in CSS pixels. */
|
|
406
|
+
height: number;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* The two Liquid Glass material variants Apple distinguishes — selected with one
|
|
411
|
+
* intentional prop instead of hand-tuning opacity.
|
|
412
|
+
*
|
|
413
|
+
* - `regular` — the dependable, fully adaptive control surface. Exactly the
|
|
414
|
+
* current behavior, including content-adaptive auto-tint when
|
|
415
|
+
* {@link LiquidGlassProps.adaptiveTint} is enabled.
|
|
416
|
+
* - `clear` — a permanently MORE transparent material for media-rich contexts
|
|
417
|
+
* (e.g. floating over a photo). It is **non-adaptive by definition**:
|
|
418
|
+
* {@link LiquidGlassProps.adaptiveTint} is force-disabled, and an optional
|
|
419
|
+
* dimming scrim sits behind the content so labels stay legible over busy media.
|
|
420
|
+
*
|
|
421
|
+
* Apple's guidance is that the two **should never be mixed** in the same context.
|
|
422
|
+
*
|
|
423
|
+
* @defaultValue `'regular'`
|
|
424
|
+
*/
|
|
425
|
+
export declare type GlassVariant = 'regular' | 'clear';
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Luminance at or above this value is classified `'light'`; below it, `'dark'`.
|
|
429
|
+
*
|
|
430
|
+
* `0.5` is the midpoint of the normalized `[0, 1]` luminance range. It is a
|
|
431
|
+
* coarse, deliberately simple split: relative luminance is already perceptually
|
|
432
|
+
* weighted (see {@link relativeLuminance}), so a midpoint cut maps cleanly to
|
|
433
|
+
* "should dark text or light text sit on this?" for the adaptive-tint consumer
|
|
434
|
+
* (plan 018). Exposed as a constant so consumers and tests share one threshold.
|
|
435
|
+
*/
|
|
436
|
+
export declare const LIGHT_DARK_THRESHOLD = 0.5;
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* The liquid-glass refraction primitive. See the file header for the layer
|
|
440
|
+
* stack, application mechanism, and measurement strategy.
|
|
441
|
+
*
|
|
442
|
+
* ## Motion + rim lighting (plan 005)
|
|
443
|
+
*
|
|
444
|
+
* The elastic stretch/translate (from {@link useMousePosition} + the pure
|
|
445
|
+
* `motion.ts` math) and the rim/highlight layers are PURE CSS — they render in
|
|
446
|
+
* every browser regardless of `canRefract`. The `transform` is applied to the
|
|
447
|
+
* GLASS SURFACE and the rim/highlight layers (which are siblings of the content
|
|
448
|
+
* layer), so the elastic distortion never warps the crisp `children`. The pure-
|
|
449
|
+
* CSS bevel (`glass-edge.ts`) is an inset `box-shadow` on the surface, while the
|
|
450
|
+
* outer drop-shadow/glow is a SEPARATE sibling element rendered BEHIND the
|
|
451
|
+
* `overflow:hidden` surface so clipping can't eat it.
|
|
452
|
+
*
|
|
453
|
+
* ## Specular hotspot + glow-on-press (plan 016)
|
|
454
|
+
*
|
|
455
|
+
* The highlight layer is a POSITIONED `radial-gradient` specular hotspot whose
|
|
456
|
+
* center tracks the pointer over the glass (driven by `--lg-spec-x/y` from
|
|
457
|
+
* {@link useMousePosition}), with a neutral top-biased fallback at rest. A second
|
|
458
|
+
* `[data-lg-press-glow]` layer blooms a radial glow from the contact point on
|
|
459
|
+
* press and fades out. Both are pure CSS (gradient/opacity/transform), render in
|
|
460
|
+
* EVERY engine regardless of `canRefract` (polish, not refraction), and are
|
|
461
|
+
* GATED on {@link useReducedMotion}: when reduced-motion is set the hotspot is
|
|
462
|
+
* static (neutral, no tracking) and the press glow snaps without animating. They
|
|
463
|
+
* are decorative siblings (aria-hidden, pointer-events:none) and never touch
|
|
464
|
+
* layout/geometry. They compose with {@link GlassButton}'s diagonal `shine`
|
|
465
|
+
* sweep (a `::after` on the button element) — different nodes, different layers.
|
|
466
|
+
*/
|
|
467
|
+
export declare function LiquidGlass({ children, displacement, displacementScale, blurAmount, saturation, aberrationIntensity, elasticity, cornerRadius, padding, overLight, adaptiveTint, scrollAwareShadow, variant, mode, refract, size, center, behind, className, style, onClick, globalMousePos, mouseOffset, mouseContainer, }: LiquidGlassProps): ReactNode;
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* PLATFORM-NEUTRAL props for the `<LiquidGlass>` PRIMITIVE.
|
|
471
|
+
*
|
|
472
|
+
* The shared base that BOTH the web (`liquid-glass.tsx`) and React Native
|
|
473
|
+
* (`liquid-glass.native.tsx`, plan 025) surfaces extend. It holds every prop
|
|
474
|
+
* that does NOT depend on DOM types, so the native surface can build on it
|
|
475
|
+
* without leaking `CSSProperties` / DOM event handlers. The web
|
|
476
|
+
* {@link LiquidGlassProps} extends this with the DOM-only `style` / `onClick` /
|
|
477
|
+
* pointer props; the native barrel defines its own `style?: ViewStyle` /
|
|
478
|
+
* `onPress?` over this same core.
|
|
479
|
+
*
|
|
480
|
+
* Every prop except {@link children} is optional — the primitive ships sensible
|
|
481
|
+
* defaults. Defaults documented here are the contract; the implementation plan
|
|
482
|
+
* (004+) must honor them.
|
|
483
|
+
*/
|
|
484
|
+
declare interface LiquidGlassCoreProps {
|
|
485
|
+
/** Content rendered inside the glass surface. */
|
|
486
|
+
children: ReactNode;
|
|
487
|
+
/**
|
|
488
|
+
* Opt into the live SVG refraction/displacement pass (WEB-ONLY progressive
|
|
489
|
+
* enhancement). When `false` (the default) the glass renders the frosted
|
|
490
|
+
* fallback look — `blur()`/`saturate()` backdrop plus the pure-CSS bevel —
|
|
491
|
+
* with no `feDisplacementMap`.
|
|
492
|
+
*
|
|
493
|
+
* - **Web:** when `true` AND the browser can refract (Chromium), the SVG
|
|
494
|
+
* displacement filter is attached; otherwise it degrades to the frosted look.
|
|
495
|
+
* - **React Native:** a documented NO-OP. RN has no SVG-over-backdrop
|
|
496
|
+
* compositing, so the prop is accepted for a single cross-platform contract
|
|
497
|
+
* but the surface always renders the frosted fallback.
|
|
498
|
+
*
|
|
499
|
+
* @defaultValue `false`
|
|
500
|
+
*/
|
|
501
|
+
displacement?: boolean;
|
|
502
|
+
/**
|
|
503
|
+
* Strength of the displacement/refraction distortion. Higher values bend the
|
|
504
|
+
* backdrop more aggressively.
|
|
505
|
+
*
|
|
506
|
+
* @defaultValue `70`
|
|
507
|
+
*/
|
|
508
|
+
displacementScale?: number;
|
|
509
|
+
/**
|
|
510
|
+
* Backdrop blur radius in pixels applied behind the glass.
|
|
511
|
+
*
|
|
512
|
+
* @defaultValue `0.0625`
|
|
513
|
+
*/
|
|
514
|
+
blurAmount?: number;
|
|
515
|
+
/**
|
|
516
|
+
* Backdrop saturation multiplier (`1` = unchanged). Boosts color vibrancy of
|
|
517
|
+
* the content seen through the glass.
|
|
518
|
+
*
|
|
519
|
+
* @defaultValue `140`
|
|
520
|
+
*/
|
|
521
|
+
saturation?: number;
|
|
522
|
+
/**
|
|
523
|
+
* Intensity of the chromatic aberration (RGB channel separation) at the
|
|
524
|
+
* refracted edges. `0` disables it.
|
|
525
|
+
*
|
|
526
|
+
* @defaultValue `2`
|
|
527
|
+
*/
|
|
528
|
+
aberrationIntensity?: number;
|
|
529
|
+
/**
|
|
530
|
+
* How elastically the glass reacts to pointer movement. `0` is rigid; higher
|
|
531
|
+
* values produce a softer, more rubbery follow.
|
|
532
|
+
*
|
|
533
|
+
* @defaultValue `0.15`
|
|
534
|
+
*/
|
|
535
|
+
elasticity?: number;
|
|
536
|
+
/**
|
|
537
|
+
* Corner radius of the glass surface. A number is treated as pixels; a string
|
|
538
|
+
* is passed through as a CSS length (e.g. `'1rem'`, `'50%'`).
|
|
539
|
+
*
|
|
540
|
+
* @defaultValue `999`
|
|
541
|
+
*/
|
|
542
|
+
cornerRadius?: number | string;
|
|
543
|
+
/**
|
|
544
|
+
* Inner padding of the glass surface. A number is treated as pixels; a string
|
|
545
|
+
* is passed through as a CSS shorthand (e.g. `'8px 16px'`).
|
|
546
|
+
*
|
|
547
|
+
* @defaultValue `'24px'`
|
|
548
|
+
*/
|
|
549
|
+
padding?: number | string;
|
|
550
|
+
/**
|
|
551
|
+
* Hint that the glass sits over a light background, so it tunes its tint and
|
|
552
|
+
* contrast for legibility.
|
|
553
|
+
*
|
|
554
|
+
* This is the MANUAL override. When set explicitly it ALWAYS wins over
|
|
555
|
+
* {@link adaptiveTint} (see that prop's precedence note) — the two never fight.
|
|
556
|
+
*
|
|
557
|
+
* @defaultValue `false`
|
|
558
|
+
*/
|
|
559
|
+
overLight?: boolean;
|
|
560
|
+
/**
|
|
561
|
+
* Opt into CONTENT-ADAPTIVE auto-tint (plan 018). When `true`, the glass
|
|
562
|
+
* samples the luminance of the backdrop behind it (via the plan-017 sampler)
|
|
563
|
+
* and automatically shifts toward a light or dark treatment — the SAME tint /
|
|
564
|
+
* displacement / blur plumbing {@link overLight} already drives — so foreground
|
|
565
|
+
* content stays legible without hand-tuning `overLight`. A bright backdrop
|
|
566
|
+
* yields the light treatment (`overLight`-equivalent), a dark backdrop the
|
|
567
|
+
* default treatment.
|
|
568
|
+
*
|
|
569
|
+
* ## Precedence (documented rule)
|
|
570
|
+
*
|
|
571
|
+
* An EXPLICIT {@link overLight} always wins. `adaptiveTint` only drives the
|
|
572
|
+
* light/dark treatment when `overLight` is left unset/undefined:
|
|
573
|
+
*
|
|
574
|
+
* ```ts
|
|
575
|
+
* effectiveOverLight = overLight ?? (adaptiveTint && scheme ? scheme === 'light' : false)
|
|
576
|
+
* ```
|
|
577
|
+
*
|
|
578
|
+
* ## SSR / hydration
|
|
579
|
+
*
|
|
580
|
+
* The server and the first client paint render the default (unsampled,
|
|
581
|
+
* conservative) treatment, so hydration never mismatches. The sampled treatment
|
|
582
|
+
* is applied in an effect after mount.
|
|
583
|
+
*
|
|
584
|
+
* ## Graceful degradation
|
|
585
|
+
*
|
|
586
|
+
* When the backdrop cannot be sampled (cross-origin-tainted canvas, no canvas,
|
|
587
|
+
* SSR) the reading is `sampled: false` and auto-tint falls back to
|
|
588
|
+
* `overLight ?? false` with no error, no flicker loop, and no `console.error`.
|
|
589
|
+
*
|
|
590
|
+
* ## Accessibility interaction
|
|
591
|
+
*
|
|
592
|
+
* Under `(prefers-contrast: more)` (plan 014) the high-contrast treatment wins:
|
|
593
|
+
* auto-tint never undercuts the increased-contrast surface/legibility treatment.
|
|
594
|
+
*
|
|
595
|
+
* ## Limitation
|
|
596
|
+
*
|
|
597
|
+
* Auto-tint is BEST-EFFORT legibility. Critical text over unknown or
|
|
598
|
+
* cross-origin backdrops (which cannot be sampled) should be verified manually —
|
|
599
|
+
* the auto path silently falls back rather than guessing.
|
|
600
|
+
*
|
|
601
|
+
* @defaultValue `false`
|
|
602
|
+
*/
|
|
603
|
+
adaptiveTint?: boolean;
|
|
604
|
+
/**
|
|
605
|
+
* Opt into SCROLL-AWARE SHADOW (plan 021). When `true`, the glass's decoupled
|
|
606
|
+
* outer drop-shadow (the `[data-lg-shadow]` sibling rendered behind the clipped
|
|
607
|
+
* surface) modulates its depth/darkness from the backdrop behind the element
|
|
608
|
+
* (via the plan-017 sampler): it DEEPENS and DARKENS over a dark/dense backdrop
|
|
609
|
+
* (reinforcing the "floating above content" read as text scrolls beneath) and
|
|
610
|
+
* EASES/LIGHTENS over a light/solid one. Apple's Liquid Glass does exactly this
|
|
611
|
+
* as content scrolls under a pinned glass bar.
|
|
612
|
+
*
|
|
613
|
+
* ## What it touches
|
|
614
|
+
*
|
|
615
|
+
* ONLY the existing drop-shadow sibling's blur/offset/opacity vary. The shadow
|
|
616
|
+
* stays a SIBLING of the `overflow:hidden` glass surface (never a box-shadow on
|
|
617
|
+
* the clipped node — the plan-005 layering invariant); no new layer is added.
|
|
618
|
+
*
|
|
619
|
+
* ## SSR / hydration
|
|
620
|
+
*
|
|
621
|
+
* The server and the first client paint render the conservative static shadow,
|
|
622
|
+
* so hydration never mismatches. The modulated shadow is applied in an effect
|
|
623
|
+
* after mount; sampling is throttled by the hook.
|
|
624
|
+
*
|
|
625
|
+
* ## Graceful degradation
|
|
626
|
+
*
|
|
627
|
+
* When the backdrop cannot be sampled (cross-origin-tainted canvas, no canvas,
|
|
628
|
+
* SSR) the reading is `sampled: false` and the shadow falls back to the current
|
|
629
|
+
* static shadow with no error and no flicker loop.
|
|
630
|
+
*
|
|
631
|
+
* ## Reduced motion
|
|
632
|
+
*
|
|
633
|
+
* Under `(prefers-reduced-motion: reduce)` the shadow does not animate between
|
|
634
|
+
* depths — it snaps/stays static (no transition).
|
|
635
|
+
*
|
|
636
|
+
* This is ADDITIVE and non-breaking: omitting it (default `false`) keeps today's
|
|
637
|
+
* rendering byte-for-byte and leaves the committed pixel baseline unchanged.
|
|
638
|
+
*
|
|
639
|
+
* @defaultValue `false`
|
|
640
|
+
*/
|
|
641
|
+
scrollAwareShadow?: boolean;
|
|
642
|
+
/**
|
|
643
|
+
* The Liquid Glass material variant. See {@link GlassVariant}.
|
|
644
|
+
*
|
|
645
|
+
* - `'regular'` (default) — EXACTLY the current behavior, including
|
|
646
|
+
* content-adaptive auto-tint when {@link adaptiveTint} is enabled. The
|
|
647
|
+
* dependable, fully adaptive control surface.
|
|
648
|
+
* - `'clear'` — a permanently MORE transparent surface (lower fill opacity /
|
|
649
|
+
* reduced tint) for media-rich contexts, with an optional dimming scrim
|
|
650
|
+
* behind the content so labels stay legible over busy media. Geometry is
|
|
651
|
+
* unchanged from `'regular'`.
|
|
652
|
+
*
|
|
653
|
+
* ## Interaction rules
|
|
654
|
+
*
|
|
655
|
+
* - **Clear is non-adaptive by definition.** In `'clear'`, {@link adaptiveTint}
|
|
656
|
+
* is a **no-op** — the glass never samples the backdrop and never flips its
|
|
657
|
+
* tint/ink. (Use `'regular'` + `adaptiveTint` for the adaptive material.)
|
|
658
|
+
* - **`overLight` still nudges legibility, not adaptivity.** In `'clear'`, an
|
|
659
|
+
* explicit {@link overLight} may still tune the dimming/legibility treatment,
|
|
660
|
+
* but it does NOT re-enable the adaptive sampling path.
|
|
661
|
+
* - **Accessibility wins.** Under `(prefers-contrast: more)` (plan 014) the
|
|
662
|
+
* high-contrast treatment STILL applies in both variants — a11y beats the
|
|
663
|
+
* Clear aesthetic, so Clear surfaces become legible/high-contrast when the
|
|
664
|
+
* user asks for it.
|
|
665
|
+
*
|
|
666
|
+
* Per Apple's guidance, the two variants **should never be mixed** in the same
|
|
667
|
+
* context. This is ADDITIVE and non-breaking: omitting it keeps today's
|
|
668
|
+
* behavior exactly.
|
|
669
|
+
*
|
|
670
|
+
* @defaultValue `'regular'`
|
|
671
|
+
*/
|
|
672
|
+
variant?: GlassVariant;
|
|
673
|
+
/**
|
|
674
|
+
* Which displacement algorithm to use. See {@link DisplacementMode}.
|
|
675
|
+
*
|
|
676
|
+
* @defaultValue `'standard'`
|
|
677
|
+
*/
|
|
678
|
+
mode?: DisplacementMode;
|
|
679
|
+
/**
|
|
680
|
+
* CROSS-BROWSER copy-refraction content (plan 030). Distinct from
|
|
681
|
+
* {@link displacement} (the Chromium-only `backdrop-filter: url(#…)` bend of
|
|
682
|
+
* the LIVE page behind the glass): this path applies the SAME SVG displacement
|
|
683
|
+
* filter as an ELEMENT `filter: url(#…)` to a COPY of content, which DOES run in
|
|
684
|
+
* Chromium, Firefox, AND WebKit. The refracted copy is a decorative sibling
|
|
685
|
+
* BEHIND the crisp {@link children} (never an ancestor of them), so interactive
|
|
686
|
+
* content stays selectable and clickable.
|
|
687
|
+
*
|
|
688
|
+
* - **`refract` set** — the copy layer renders THIS node (a lens floated over
|
|
689
|
+
* content the glass doesn't own), filtered; {@link behind} fills the bleed and
|
|
690
|
+
* crisp {@link children} render on top. The node re-renders with the parent
|
|
691
|
+
* (React keeps it in sync) and the lens region re-measures on resize.
|
|
692
|
+
* - **`refract` unset but {@link size}/{@link center} set** — IN-PLACE mode: the
|
|
693
|
+
* glass refracts a copy of its OWN {@link children} through the element filter,
|
|
694
|
+
* with the crisp children on top.
|
|
695
|
+
*
|
|
696
|
+
* Omitting `refract`, {@link size}, AND {@link center} disables this path
|
|
697
|
+
* entirely — the render is byte-for-byte the {@link displacement} behavior.
|
|
698
|
+
*
|
|
699
|
+
* ## Contract: the refracted copy must be PRESENTATIONAL
|
|
700
|
+
*
|
|
701
|
+
* The copy layer renders a SECOND instance of the copied node (`refract`, or —
|
|
702
|
+
* in IN-PLACE mode — a copy of {@link children}). It is `aria-hidden` + `inert`
|
|
703
|
+
* + `pointer-events: none`, so it is hidden from the a11y tree and cannot be
|
|
704
|
+
* interacted with. But React still MOUNTS it, so the copied subtree should be
|
|
705
|
+
* PURELY PRESENTATIONAL:
|
|
706
|
+
*
|
|
707
|
+
* - **No `id`s / label targets / in-page anchor targets** — they would be
|
|
708
|
+
* duplicated in the DOM (`getElementById` / `label[for]` / `#hash` could bind
|
|
709
|
+
* the hidden copy).
|
|
710
|
+
* - **No effects / focus-on-mount / data fetching / callback refs** — they run
|
|
711
|
+
* for BOTH instances.
|
|
712
|
+
* - **No focusable controls** on engines that don't honor `inert` (older
|
|
713
|
+
* Safari/Firefox), where they could otherwise become tabbable inside an
|
|
714
|
+
* `aria-hidden` subtree.
|
|
715
|
+
*
|
|
716
|
+
* For anything non-trivial, prefer `refract={<decorative node>}` (a background
|
|
717
|
+
* you fully control) over IN-PLACE copying of rich interactive `children`.
|
|
718
|
+
* Passing `refract={null}` opts in but renders an EMPTY lens (only the
|
|
719
|
+
* {@link behind} bleed) — it does NOT fall back to copying `children`.
|
|
720
|
+
*
|
|
721
|
+
* **React Native:** a documented NO-OP (no SVG filters; always frosted).
|
|
722
|
+
*
|
|
723
|
+
* @defaultValue `undefined`
|
|
724
|
+
*/
|
|
725
|
+
refract?: ReactNode;
|
|
726
|
+
/**
|
|
727
|
+
* Explicit lens {@link GlassSize} for the copy-refraction path (plan 030). When
|
|
728
|
+
* omitted the lens is sized to the glass's measured dimensions. Presence of this
|
|
729
|
+
* prop (with or without {@link refract}) opts INTO the cross-browser copy
|
|
730
|
+
* refraction in IN-PLACE mode (refract a copy of the own {@link children}).
|
|
731
|
+
*
|
|
732
|
+
* **React Native:** a documented NO-OP.
|
|
733
|
+
*
|
|
734
|
+
* @defaultValue `undefined` (use measured dimensions)
|
|
735
|
+
*/
|
|
736
|
+
size?: GlassSize;
|
|
737
|
+
/**
|
|
738
|
+
* Lens focal point ({@link GlassCenter}, fractions in `[0, 1]`) for the
|
|
739
|
+
* copy-refraction path (plan 030). Drives the refracted copy's
|
|
740
|
+
* `transform-origin`. Presence opts into the cross-browser copy refraction in
|
|
741
|
+
* IN-PLACE mode, same as {@link size}.
|
|
742
|
+
*
|
|
743
|
+
* **React Native:** a documented NO-OP.
|
|
744
|
+
*
|
|
745
|
+
* @defaultValue `{ x: 0.5, y: 0.5 }` (center)
|
|
746
|
+
*/
|
|
747
|
+
center?: GlassCenter;
|
|
748
|
+
/**
|
|
749
|
+
* Bleed fill (any CSS `background` value) painted behind the refracted copy on
|
|
750
|
+
* the copy-refraction path (plan 030), so the displacement has something to pull
|
|
751
|
+
* from where the copied content doesn't cover the lens box. Most useful with
|
|
752
|
+
* {@link refract} (a lens over foreign content); usually unnecessary for
|
|
753
|
+
* IN-PLACE mode. No effect unless the copy-refraction path is active.
|
|
754
|
+
*
|
|
755
|
+
* **React Native:** a documented NO-OP.
|
|
756
|
+
*
|
|
757
|
+
* @defaultValue `undefined`
|
|
758
|
+
*/
|
|
759
|
+
behind?: string;
|
|
760
|
+
/** Additional class name(s) applied to the outermost glass element. */
|
|
761
|
+
className?: string;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* Props for the WEB `<LiquidGlass>` PRIMITIVE.
|
|
766
|
+
*
|
|
767
|
+
* The platform-neutral {@link LiquidGlassCoreProps} plus the DOM-only props the
|
|
768
|
+
* web surface needs: inline `style`, the `onClick` handler, and the externally
|
|
769
|
+
* controlled pointer inputs. This is the same surface the library has always
|
|
770
|
+
* exposed — splitting the core out is type-only and changes nothing for web
|
|
771
|
+
* consumers.
|
|
772
|
+
*/
|
|
773
|
+
export declare type LiquidGlassProps = LiquidGlassCoreProps & {
|
|
774
|
+
/** Inline styles merged onto the outermost glass element. */
|
|
775
|
+
style?: CSSProperties;
|
|
776
|
+
/** Click handler forwarded to the glass surface. */
|
|
777
|
+
onClick?: MouseEventHandler<HTMLDivElement>;
|
|
778
|
+
/**
|
|
779
|
+
* Externally controlled global pointer position. When provided, the primitive
|
|
780
|
+
* uses this instead of subscribing to its own pointer events — useful for
|
|
781
|
+
* coordinating many glass surfaces from one shared tracker.
|
|
782
|
+
*
|
|
783
|
+
* Leave undefined for the uncontrolled default (the primitive tracks the
|
|
784
|
+
* pointer itself).
|
|
785
|
+
*/
|
|
786
|
+
globalMousePos?: MousePos;
|
|
787
|
+
/**
|
|
788
|
+
* Externally controlled pointer offset relative to the glass element's
|
|
789
|
+
* center, in CSS pixels. Paired with {@link globalMousePos} for fully
|
|
790
|
+
* controlled motion.
|
|
791
|
+
*/
|
|
792
|
+
mouseOffset?: MousePos;
|
|
793
|
+
/**
|
|
794
|
+
* Element (or ref to one) whose bounds define the coordinate space for
|
|
795
|
+
* pointer tracking. Defaults to the viewport when omitted or `null`.
|
|
796
|
+
*
|
|
797
|
+
* @defaultValue `null` (viewport)
|
|
798
|
+
*/
|
|
799
|
+
mouseContainer?: RefObject<HTMLElement | null> | HTMLElement | null;
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Classify a normalized luminance as `'light'` or `'dark'`.
|
|
804
|
+
*
|
|
805
|
+
* @param luminance - Relative luminance in `[0, 1]`.
|
|
806
|
+
* @returns `'light'` when `luminance >= ` {@link LIGHT_DARK_THRESHOLD}, else
|
|
807
|
+
* `'dark'`.
|
|
808
|
+
*/
|
|
809
|
+
export declare function luminanceToScheme(luminance: number): BackdropScheme;
|
|
810
|
+
|
|
811
|
+
/** Modes that resolve to a `data:` URL map. `'turbulence'` is procedural (plan 004). */
|
|
812
|
+
declare type MapMode = Exclude<DisplacementMode, 'turbulence'>;
|
|
813
|
+
|
|
814
|
+
/** A container reference accepted by {@link useMousePosition}. */
|
|
815
|
+
export declare type MouseContainer = RefObject<HTMLElement | null> | HTMLElement | null | undefined;
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* A 2D pointer position in CSS pixels, used for mouse-driven motion/elasticity.
|
|
819
|
+
*
|
|
820
|
+
* Coordinates are interpreted relative to whatever container the consumer wires
|
|
821
|
+
* up via {@link LiquidGlassProps.mouseContainer} (viewport by default).
|
|
822
|
+
*/
|
|
823
|
+
export declare type MousePos = {
|
|
824
|
+
/** Horizontal position in CSS pixels. */
|
|
825
|
+
x: number;
|
|
826
|
+
/** Vertical position in CSS pixels. */
|
|
827
|
+
y: number;
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
/** Return shape of {@link useMousePosition}. */
|
|
831
|
+
export declare interface MousePositionState {
|
|
832
|
+
/** Absolute pointer position in CSS pixels (`{0,0}` when inactive). */
|
|
833
|
+
mousePos: MousePos;
|
|
834
|
+
/** Pointer offset from the tracked element center, in CSS pixels. */
|
|
835
|
+
offset: MousePos;
|
|
836
|
+
/**
|
|
837
|
+
* Whether motion is live: `false` under SSR, reduced-motion, or touch — in
|
|
838
|
+
* which case `mousePos`/`offset` are neutral and the component must not
|
|
839
|
+
* animate.
|
|
840
|
+
*/
|
|
841
|
+
isActive: boolean;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* Parse a CSS color string into RGB + alpha.
|
|
846
|
+
*
|
|
847
|
+
* Handles the forms `getComputedStyle` actually returns for
|
|
848
|
+
* `background-color`: `rgb(r, g, b)`, `rgba(r, g, b, a)`, and the special
|
|
849
|
+
* `transparent` / empty values (alpha 0). Modern engines may also emit
|
|
850
|
+
* `rgb(r g b / a)` (space-separated, slash alpha); both are accepted. Anything
|
|
851
|
+
* unrecognized (e.g. exotic `color()` functions) is treated as fully
|
|
852
|
+
* transparent so it is skipped rather than mis-composited.
|
|
853
|
+
*
|
|
854
|
+
* @param value - A computed CSS color string.
|
|
855
|
+
* @returns `{ r, g, b, a }` with channels in `[0, 255]` and `a` in `[0, 1]`.
|
|
856
|
+
*/
|
|
857
|
+
export declare function parseCssColor(value: string | null | undefined): Rgb & {
|
|
858
|
+
a: number;
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* Relative luminance of an sRGB color, per the WCAG 2.x definition.
|
|
863
|
+
*
|
|
864
|
+
* Linearizes each channel (see {@link srgbChannelToLinear}) then applies the
|
|
865
|
+
* Rec. 709 luma weights (`0.2126 R + 0.7152 G + 0.0722 B`). The result is in
|
|
866
|
+
* `[0, 1]`: `0` for black, `1` for white, with green contributing most and blue
|
|
867
|
+
* least — matching human brightness perception.
|
|
868
|
+
*
|
|
869
|
+
* @param r - Red channel, `[0, 255]`.
|
|
870
|
+
* @param g - Green channel, `[0, 255]`.
|
|
871
|
+
* @param b - Blue channel, `[0, 255]`.
|
|
872
|
+
* @returns Relative luminance in `[0, 1]`.
|
|
873
|
+
*
|
|
874
|
+
* @example
|
|
875
|
+
* relativeLuminance(0, 0, 0); // 0 (black)
|
|
876
|
+
* relativeLuminance(255, 255, 255); // 1 (white)
|
|
877
|
+
*/
|
|
878
|
+
export declare function relativeLuminance(r: number, g: number, b: number): number;
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Backdrop-luminance sampling (plan 017) — the React-free core.
|
|
882
|
+
*
|
|
883
|
+
* Apple's Liquid Glass is content-adaptive: the material reads the brightness of
|
|
884
|
+
* what sits behind it and adjusts its tint for legibility. There is no reliable,
|
|
885
|
+
* cheap, universal way to read "the pixels behind an arbitrary element" in a
|
|
886
|
+
* browser — `backdrop-filter` happens in the compositor, never exposed to JS. So
|
|
887
|
+
* this module ships a PLUGGABLE, degrading sampling strategy plus the pure
|
|
888
|
+
* luminance math, all framework-free. The React hook
|
|
889
|
+
* (`useBackdropLuminance`) wraps this with effects, throttling, and SSR guards.
|
|
890
|
+
*
|
|
891
|
+
* Two strategies, ONE contract ({@link BackdropSample}):
|
|
892
|
+
*
|
|
893
|
+
* 1. **DOM-background (default).** Walk the stacking order behind the element's
|
|
894
|
+
* center via `document.elementsFromPoint`, read each layer's computed
|
|
895
|
+
* `background-color` (and detect opaque `background-image`s), and composite
|
|
896
|
+
* them front-to-back into one estimated backdrop color. Cheap, synchronous,
|
|
897
|
+
* no canvas, and NEVER taints — it only reads CSSOM, not pixels. It cannot see
|
|
898
|
+
* *image content* luminance (only that an opaque image exists), which is an
|
|
899
|
+
* accepted trade-off for the zero-cost default.
|
|
900
|
+
* 2. **Canvas snapshot (opt-in).** A caller-supplied function that paints the
|
|
901
|
+
* backdrop into a canvas and returns its average color. This CAN read real
|
|
902
|
+
* image luminance but can TAINT: a cross-origin image drawn without CORS makes
|
|
903
|
+
* `getImageData` throw `SecurityError`. This module treats any throw from the
|
|
904
|
+
* sampler as "could not sample" and returns an unsampled result — it never
|
|
905
|
+
* rethrows and never logs. (The hook layer enforces the same contract.)
|
|
906
|
+
*
|
|
907
|
+
* This module is intentionally independent of `liquid-glass.tsx`: it is imported
|
|
908
|
+
* only by consumers opting into adaptive tint, so it tree-shakes out of the
|
|
909
|
+
* default `<LiquidGlass>` path and adds zero bytes there.
|
|
910
|
+
*/
|
|
911
|
+
/** A linear-RGB / sRGB color triple, each channel in `[0, 255]`. */
|
|
912
|
+
export declare interface Rgb {
|
|
913
|
+
r: number;
|
|
914
|
+
g: number;
|
|
915
|
+
b: number;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Signed distance from point `(x, y)` to a rounded rectangle of size `w × h`
|
|
920
|
+
* **centered at the origin**, with corner radius `r`.
|
|
921
|
+
*
|
|
922
|
+
* Convention: **negative inside**, **zero on the border**, **positive outside**
|
|
923
|
+
* (the standard SDF sign convention). The radius is clamped to half the smaller
|
|
924
|
+
* side so it can never exceed the rectangle.
|
|
925
|
+
*
|
|
926
|
+
* @param x - X coordinate relative to the rectangle center.
|
|
927
|
+
* @param y - Y coordinate relative to the rectangle center.
|
|
928
|
+
* @param w - Full width of the rectangle.
|
|
929
|
+
* @param h - Full height of the rectangle.
|
|
930
|
+
* @param r - Corner radius.
|
|
931
|
+
* @returns Signed distance in the same units as the inputs.
|
|
932
|
+
*/
|
|
933
|
+
export declare function roundedRectSDF(x: number, y: number, w: number, h: number, r: number): number;
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Run a sampling strategy with a total taint/error guard.
|
|
937
|
+
*
|
|
938
|
+
* If the strategy throws for ANY reason — most importantly a `SecurityError`
|
|
939
|
+
* from `getImageData` on a cross-origin-tainted canvas — this returns
|
|
940
|
+
* {@link UNSAMPLED} instead of propagating. It deliberately does NOT log: a
|
|
941
|
+
* tainted backdrop is an expected, recoverable condition, not an application
|
|
942
|
+
* error, and console noise on every animation frame would be hostile.
|
|
943
|
+
*
|
|
944
|
+
* @param strategy - The strategy to invoke.
|
|
945
|
+
* @param point - The viewport point to sample.
|
|
946
|
+
* @returns The strategy's result, or {@link UNSAMPLED} on any throw.
|
|
947
|
+
*/
|
|
948
|
+
export declare function safeSample(strategy: SamplingStrategy, point: {
|
|
949
|
+
x: number;
|
|
950
|
+
y: number;
|
|
951
|
+
}): BackdropSample;
|
|
952
|
+
|
|
953
|
+
/**
|
|
954
|
+
* Sample the estimated backdrop luminance under a viewport point.
|
|
955
|
+
*
|
|
956
|
+
* Thin orchestrator: resolves the strategy (default {@link domBackgroundStrategy})
|
|
957
|
+
* and runs it through {@link safeSample} so a tainted canvas or any failure
|
|
958
|
+
* yields {@link UNSAMPLED} rather than throwing.
|
|
959
|
+
*
|
|
960
|
+
* @param point - Viewport coordinates (typically the glass element's center).
|
|
961
|
+
* @param options - {@link SampleBackdropOptions}.
|
|
962
|
+
* @returns A {@link BackdropSample}.
|
|
963
|
+
*/
|
|
964
|
+
export declare function sampleBackdropLuminance(point: {
|
|
965
|
+
x: number;
|
|
966
|
+
y: number;
|
|
967
|
+
}, options?: SampleBackdropOptions): BackdropSample;
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Options for {@link sampleBackdropLuminance}.
|
|
971
|
+
*/
|
|
972
|
+
export declare interface SampleBackdropOptions {
|
|
973
|
+
/**
|
|
974
|
+
* Override the sampling strategy. Defaults to {@link domBackgroundStrategy}.
|
|
975
|
+
* Pass a canvas-based strategy here to opt into pixel-accurate sampling
|
|
976
|
+
* (taint-safe: any throw becomes {@link UNSAMPLED}).
|
|
977
|
+
*/
|
|
978
|
+
strategy?: SamplingStrategy;
|
|
979
|
+
/**
|
|
980
|
+
* The element to exclude from the DOM walk (the glass surface itself) so its
|
|
981
|
+
* own background is not mistaken for the backdrop. Only used by the default
|
|
982
|
+
* DOM strategy.
|
|
983
|
+
*/
|
|
984
|
+
ignore?: Element | null;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* A sampling strategy: given a viewport point, return a backdrop sample (or
|
|
989
|
+
* {@link UNSAMPLED}). Pluggable so consumers can swap the default DOM walk for a
|
|
990
|
+
* canvas-snapshot path.
|
|
991
|
+
*
|
|
992
|
+
* Implementations MUST NOT throw — a strategy that cannot read (e.g. a tainted
|
|
993
|
+
* canvas) returns {@link UNSAMPLED}. See {@link safeSample}, which enforces this
|
|
994
|
+
* even for a misbehaving strategy.
|
|
995
|
+
*/
|
|
996
|
+
export declare type SamplingStrategy = (point: {
|
|
997
|
+
x: number;
|
|
998
|
+
y: number;
|
|
999
|
+
}) => BackdropSample;
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Standard GLSL-style smoothstep. Returns `0` for `t <= a`, `1` for `t >= b`,
|
|
1003
|
+
* and a smooth Hermite interpolation (`3u² − 2u³`) in between. Clamps outside
|
|
1004
|
+
* the `[a, b]` range. If `a === b` it degenerates to a step at `a`.
|
|
1005
|
+
*
|
|
1006
|
+
* @param a - Lower edge.
|
|
1007
|
+
* @param b - Upper edge.
|
|
1008
|
+
* @param t - Value to interpolate.
|
|
1009
|
+
* @returns A value in `[0, 1]`.
|
|
1010
|
+
*/
|
|
1011
|
+
export declare function smoothStep(a: number, b: number, t: number): number;
|
|
1012
|
+
|
|
1013
|
+
/** The canonical "we could not sample" result. */
|
|
1014
|
+
export declare const UNSAMPLED: BackdropSample;
|
|
1015
|
+
|
|
1016
|
+
/**
|
|
1017
|
+
* Estimate the luminance of the backdrop behind `ref`'s element.
|
|
1018
|
+
*
|
|
1019
|
+
* @param ref - Ref to the glass element whose backdrop should be sampled. Its
|
|
1020
|
+
* center point drives the sample, and the element itself is excluded from the
|
|
1021
|
+
* DOM walk so its own background is not mistaken for the backdrop.
|
|
1022
|
+
* @param options - {@link UseBackdropLuminanceOptions}.
|
|
1023
|
+
* @returns A {@link BackdropSample}: {@link UNSAMPLED} during SSR / before mount /
|
|
1024
|
+
* when disabled / on taint, otherwise the live reading.
|
|
1025
|
+
*/
|
|
1026
|
+
export declare function useBackdropLuminance(ref: RefObject<HTMLElement | null>, options?: UseBackdropLuminanceOptions): BackdropSample;
|
|
1027
|
+
|
|
1028
|
+
/** Options for {@link useBackdropLuminance}. */
|
|
1029
|
+
export declare interface UseBackdropLuminanceOptions {
|
|
1030
|
+
/**
|
|
1031
|
+
* Custom sampling strategy (e.g. a canvas-snapshot strategy from
|
|
1032
|
+
* `createCanvasSnapshotStrategy`). Defaults to the canvas-free DOM-background
|
|
1033
|
+
* walk. Any throw from the strategy is caught and surfaced as an unsampled
|
|
1034
|
+
* result.
|
|
1035
|
+
*/
|
|
1036
|
+
strategy?: SamplingStrategy;
|
|
1037
|
+
/**
|
|
1038
|
+
* Re-sample when the window scrolls. Default `true`. Scroll changes what is
|
|
1039
|
+
* behind the element, so the reading goes stale without this.
|
|
1040
|
+
*/
|
|
1041
|
+
resampleOnScroll?: boolean;
|
|
1042
|
+
/**
|
|
1043
|
+
* Re-sample when the window resizes. Default `true`.
|
|
1044
|
+
*/
|
|
1045
|
+
resampleOnResize?: boolean;
|
|
1046
|
+
/**
|
|
1047
|
+
* Skip sampling entirely (returns {@link UNSAMPLED}). Lets a consumer disable
|
|
1048
|
+
* the work without unmounting the hook — e.g. when adaptive tint is off.
|
|
1049
|
+
*/
|
|
1050
|
+
disabled?: boolean;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* Detect liquid-glass capabilities on the client.
|
|
1055
|
+
*
|
|
1056
|
+
* @returns Conservative all-`false` {@link GlassCapabilities} until mounted,
|
|
1057
|
+
* then the detected capabilities for the current browser.
|
|
1058
|
+
*/
|
|
1059
|
+
export declare function useGlassCapabilities(): GlassCapabilities;
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Track the pointer relative to an element center.
|
|
1063
|
+
*
|
|
1064
|
+
* @returns A {@link MousePositionState}: neutral (and `isActive: false`) under
|
|
1065
|
+
* SSR, reduced-motion, touch, or controlled-with-no-data; live otherwise.
|
|
1066
|
+
*/
|
|
1067
|
+
export declare function useMousePosition(options?: UseMousePositionOptions): MousePositionState;
|
|
1068
|
+
|
|
1069
|
+
/** Inputs accepted by {@link useMousePosition}. */
|
|
1070
|
+
export declare interface UseMousePositionOptions {
|
|
1071
|
+
/**
|
|
1072
|
+
* Element (or ref) whose bounds define the tracking frame. When provided, the
|
|
1073
|
+
* pointer offset is measured against this container's center; otherwise the
|
|
1074
|
+
* tracked element's own center is used.
|
|
1075
|
+
*/
|
|
1076
|
+
container?: MouseContainer;
|
|
1077
|
+
/**
|
|
1078
|
+
* Externally controlled absolute pointer position. When set, the hook uses it
|
|
1079
|
+
* verbatim instead of subscribing to pointer events.
|
|
1080
|
+
*/
|
|
1081
|
+
globalMousePos?: MousePos;
|
|
1082
|
+
/**
|
|
1083
|
+
* Externally controlled offset from the element center. Paired with
|
|
1084
|
+
* {@link UseMousePositionOptions.globalMousePos} for fully controlled motion;
|
|
1085
|
+
* when present it is used directly as the offset.
|
|
1086
|
+
*/
|
|
1087
|
+
mouseOffset?: MousePos;
|
|
1088
|
+
/**
|
|
1089
|
+
* The element whose center the offset is measured from when no `container` is
|
|
1090
|
+
* supplied — typically the glass wrapper itself.
|
|
1091
|
+
*/
|
|
1092
|
+
elementRef?: RefObject<HTMLElement | null>;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* `usePrefersContrast()` — the SINGLE live source of increased-contrast state.
|
|
1097
|
+
*
|
|
1098
|
+
* This hook is authoritative for the whole library (plan 014), mirroring
|
|
1099
|
+
* `useReducedTransparency` (013) and `useReducedMotion` (005) exactly:
|
|
1100
|
+
*
|
|
1101
|
+
* - It subscribes to `matchMedia('(prefers-contrast: more)')` AND its `'change'`
|
|
1102
|
+
* event, so it reacts when the user toggles the OS "Increase contrast" setting
|
|
1103
|
+
* mid-session — not just on mount.
|
|
1104
|
+
* - It is SSR-safe: it returns `false` (no-increase default) before mount and
|
|
1105
|
+
* when `window` / `matchMedia` are unavailable, so server and first-client
|
|
1106
|
+
* render agree and never crash. Browsers that don't understand the query report
|
|
1107
|
+
* `matches: false`, so the conservative default holds there too.
|
|
1108
|
+
*
|
|
1109
|
+
* When this returns `true`, `<LiquidGlass>` adds a SOLID, visible inset border,
|
|
1110
|
+
* raises content legibility (a more-opaque scheme-aware surface fill), and tones
|
|
1111
|
+
* down decorative saturation/aberration that harms contrast. It is an axis
|
|
1112
|
+
* ORTHOGONAL to the 3 capability tiers AND to reduced-transparency (013) — both
|
|
1113
|
+
* a11y axes may be active at once and must stay legible and shift-free. No other
|
|
1114
|
+
* code path may call `matchMedia('(prefers-contrast: more)')` reactively. (The
|
|
1115
|
+
* point-in-time `prefersContrastMore` snapshot in `capabilities.ts` may stay for
|
|
1116
|
+
* one-shot detection, but it is not the live reactive source.)
|
|
1117
|
+
*/
|
|
1118
|
+
/**
|
|
1119
|
+
* Live increased-contrast state.
|
|
1120
|
+
*
|
|
1121
|
+
* @returns `false` during SSR / before mount, then the real
|
|
1122
|
+
* `(prefers-contrast: more)` value, updating on OS-level changes.
|
|
1123
|
+
*/
|
|
1124
|
+
export declare function usePrefersContrast(): boolean;
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* `useReducedMotion()` — the SINGLE live source of reduced-motion state.
|
|
1128
|
+
*
|
|
1129
|
+
* This hook is authoritative for the whole library (plan 005 eng-review):
|
|
1130
|
+
*
|
|
1131
|
+
* - It subscribes to `matchMedia('(prefers-reduced-motion: reduce)')` AND its
|
|
1132
|
+
* `'change'` event, so it reacts when the user toggles the OS "Reduce motion"
|
|
1133
|
+
* setting mid-session — not just on mount.
|
|
1134
|
+
* - It is SSR-safe: it returns `false` (no-motion default) before mount and when
|
|
1135
|
+
* `window` / `matchMedia` are unavailable, so server and first-client render
|
|
1136
|
+
* agree and never crash.
|
|
1137
|
+
*
|
|
1138
|
+
* Every motion-aware consumer — {@link useMousePosition} (005), the
|
|
1139
|
+
* unsupported-browser fallback path (006), and the segmented control (012) —
|
|
1140
|
+
* reads reduced-motion state through THIS hook. No other code path may call
|
|
1141
|
+
* `matchMedia('(prefers-reduced-motion: reduce)')` reactively. (The point-in-time
|
|
1142
|
+
* `prefersReducedMotion` snapshot in `capabilities.ts` may stay for one-shot
|
|
1143
|
+
* detection, but it is not the live reactive source.)
|
|
1144
|
+
*/
|
|
1145
|
+
/**
|
|
1146
|
+
* Live reduced-motion state.
|
|
1147
|
+
*
|
|
1148
|
+
* @returns `false` during SSR / before mount, then the real
|
|
1149
|
+
* `(prefers-reduced-motion: reduce)` value, updating on OS-level changes.
|
|
1150
|
+
*/
|
|
1151
|
+
export declare function useReducedMotion(): boolean;
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* `useReducedTransparency()` — the SINGLE live source of reduced-transparency state.
|
|
1155
|
+
*
|
|
1156
|
+
* This hook is authoritative for the whole library (plan 013), mirroring
|
|
1157
|
+
* `useReducedMotion` (005) exactly:
|
|
1158
|
+
*
|
|
1159
|
+
* - It subscribes to `matchMedia('(prefers-reduced-transparency: reduce)')` AND
|
|
1160
|
+
* its `'change'` event, so it reacts when the user toggles the OS "Reduce
|
|
1161
|
+
* transparency" setting mid-session — not just on mount.
|
|
1162
|
+
* - It is SSR-safe: it returns `false` (no-reduction default) before mount and
|
|
1163
|
+
* when `window` / `matchMedia` are unavailable, so server and first-client
|
|
1164
|
+
* render agree and never crash. Browsers that don't understand the query
|
|
1165
|
+
* report `matches: false`, so the conservative default holds there too.
|
|
1166
|
+
*
|
|
1167
|
+
* When this returns `true`, `<LiquidGlass>` forces the existing no-filter path
|
|
1168
|
+
* (omitting the SVG `url(#id)` refraction) and raises the surface fill opacity
|
|
1169
|
+
* for a frostier, more-opaque result. No other code path may call
|
|
1170
|
+
* `matchMedia('(prefers-reduced-transparency: reduce)')` reactively. (The
|
|
1171
|
+
* point-in-time `prefersReducedTransparency` snapshot in `capabilities.ts` may
|
|
1172
|
+
* stay for one-shot detection, but it is not the live reactive source.)
|
|
1173
|
+
*/
|
|
1174
|
+
/**
|
|
1175
|
+
* Live reduced-transparency state.
|
|
1176
|
+
*
|
|
1177
|
+
* @returns `false` during SSR / before mount, then the real
|
|
1178
|
+
* `(prefers-reduced-transparency: reduce)` value, updating on OS-level changes.
|
|
1179
|
+
*/
|
|
1180
|
+
export declare function useReducedTransparency(): boolean;
|
|
1181
|
+
|
|
1182
|
+
/**
|
|
1183
|
+
* Public entry point for @aberhamm/liquid-glass-react.
|
|
1184
|
+
*
|
|
1185
|
+
* Plan 002 establishes the load-bearing contracts: public types, runtime
|
|
1186
|
+
* capability detection, and the React hook. Rendering, the SVG filter, and the
|
|
1187
|
+
* `<LiquidGlass>` component itself land in later plans.
|
|
1188
|
+
*/
|
|
1189
|
+
export declare const VERSION = "0.0.0";
|
|
1190
|
+
|
|
1191
|
+
export { }
|