@aberhamm/liquid-glass-react 0.2.1 → 0.3.1

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/dist/index.d.cts CHANGED
@@ -1,1191 +1,144 @@
1
1
  import { ButtonHTMLAttributes } from 'react';
2
- import { CSSProperties } from 'react';
2
+ import { default as default_2 } from 'react';
3
3
  import { ForwardRefExoticComponent } from 'react';
4
+ import { Glass } from '@samasante/liquid-glass';
5
+ import { GlassOptics } from '@samasante/liquid-glass';
6
+ import { GlassProps } from '@samasante/liquid-glass';
7
+ import { GlassSurfaceLens } from '@samasante/liquid-glass';
4
8
  import { HTMLAttributes } from 'react';
5
- import { MouseEventHandler } from 'react';
9
+ import { JSX as JSX_2 } from 'react';
6
10
  import { ReactNode } from 'react';
7
11
  import { RefAttributes } from 'react';
8
- import { RefObject } from 'react';
9
12
 
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;
13
+ export { Glass }
14
+ export { Glass as LiquidGlass }
17
15
 
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
- */
16
+ /** A native button over an upstream glass material; decoration never receives input. */
230
17
  export declare const GlassButton: ForwardRefExoticComponent<GlassButtonProps & RefAttributes<HTMLButtonElement>>;
231
18
 
232
19
  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). */
20
+ variant?: 'primary' | 'secondary' | 'subtle';
21
+ size?: 'sm' | 'md' | 'lg' | 'icon';
22
+ glassProps?: Omit<GlassProps, 'children'>;
247
23
  contentClassName?: string;
248
- /** Escape hatch: pass-through overrides to the underlying `<LiquidGlass>`. */
249
- glassProps?: Partial<Omit<LiquidGlassProps, 'children'>>;
24
+ children?: ReactNode;
250
25
  }
251
26
 
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
27
  export declare const GlassCard: ForwardRefExoticComponent<GlassCardProps & RefAttributes<HTMLDivElement>>;
318
28
 
319
- export declare type GlassCardElevation = 'flat' | 'raised' | 'floating';
320
-
321
29
  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'>>;
30
+ elevation?: 'flat' | 'raised' | 'floating';
31
+ glassProps?: Omit<GlassProps, 'children'>;
334
32
  }
335
33
 
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;
34
+ export declare const GlassNotification: default_2.FC<GlassNotificationProps>;
35
+
36
+ export declare interface GlassNotificationProps {
37
+ title?: string;
38
+ time?: string;
39
+ body?: string;
40
+ /** Avatar initials, rendered in a gradient circle. */
41
+ avatar?: string;
42
+ /** Any CSS `background` value the glass refracts. */
43
+ wallpaper?: string;
44
+ /** Override the glass optics (merged over the built-in look). */
45
+ lens?: Partial<GlassOptics>;
347
46
  }
348
47
 
349
- /** Colour scheme selector for {@link getGlassEdgeShadow}. */
350
- export declare type GlassEdgeScheme = 'light' | 'dark';
48
+ export { GlassOptics }
49
+
50
+ export { GlassProps }
51
+ export { GlassProps as LiquidGlassProps }
351
52
 
352
- export declare const GlassSegmentedControl: ForwardRefExoticComponent<GlassSegmentedControlProps & RefAttributes<HTMLFieldSetElement>>;
53
+ /** Native radio semantics provide arrow-key navigation, focus and form values. */
54
+ export declare function GlassSegmentedControl({ label, options, value, defaultValue, onValueChange, name, disabled, className, }: GlassSegmentedControlProps): JSX_2.Element;
353
55
 
354
56
  export declare interface GlassSegmentedControlProps {
355
- /** The selectable segments. */
356
- options: GlassSegmentedOption[];
357
- /** Controlled selected value. When set, the component is controlled. */
57
+ label: string;
58
+ options: {
59
+ value: string;
60
+ label: ReactNode;
61
+ disabled?: boolean;
62
+ }[];
358
63
  value?: string;
359
- /** Initial selected value when uncontrolled. Defaults to the first option. */
360
64
  defaultValue?: string;
361
- /** Fires on every user selection with the newly-selected value. */
362
65
  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
66
  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
67
  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
68
  className?: string;
762
69
  }
763
70
 
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;
71
+ export declare const GlassSlider: default_2.FC<GlassSliderProps>;
934
72
 
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
- */
73
+ export declare interface GlassSliderProps {
74
+ value?: number;
75
+ defaultValue?: number;
76
+ onValueChange?: (value: number) => void;
77
+ min?: number;
78
+ max?: number;
79
+ step?: number;
1050
80
  disabled?: boolean;
81
+ /** Full control width. */
82
+ width?: number;
83
+ /** Thumb (lens) height; the control is this tall. */
84
+ thumbHeight?: number;
85
+ thumbWidth?: number;
86
+ /** Visible track height. */
87
+ height?: number;
88
+ rubberOvershoot?: number;
89
+ rubberDampening?: number;
90
+ /** Height of the refraction copy of the track (default 0.75 × thumbHeight). */
91
+ refractionTrackHeight?: number;
92
+ lens?: Partial<GlassOptics>;
93
+ tintBlur?: number;
94
+ /** Supersample factor for the lens filter (2 = crisp edges; Chromium-only). */
95
+ filterResolution?: number;
96
+ name?: string;
97
+ ariaLabel?: string;
98
+ forceExpanded?: boolean;
99
+ onLensMapChange?: (url: string | null) => void;
100
+ /** Resolved colour scheme — picks the light/dark lens preset. */
101
+ scheme?: 'light' | 'dark';
102
+ /** Track colour. Must be opaque. */
103
+ trackColor?: string;
104
+ /** Fill colour. */
105
+ activeColor?: string;
106
+ /** Background colour the lens refracts against. */
107
+ surface?: string;
1051
108
  }
1052
109
 
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;
110
+ export { GlassSurfaceLens }
1060
111
 
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;
112
+ export declare const GlassSwitch: default_2.FC<GlassSwitchProps>;
1068
113
 
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>;
114
+ export declare interface GlassSwitchProps {
115
+ checked?: boolean;
116
+ defaultChecked?: boolean;
117
+ onCheckedChange?: (checked: boolean) => void;
118
+ disabled?: boolean;
119
+ name?: string;
120
+ value?: string;
121
+ ariaLabel?: string;
122
+ width?: number;
123
+ height?: number;
124
+ lens?: Partial<GlassOptics>;
125
+ tintBlur?: number;
126
+ rubberOvershoot?: number;
127
+ rubberDampening?: number;
128
+ /** Supersample factor for the lens filter (2 = crisp edges; Chromium-only). */
129
+ filterResolution?: number;
130
+ forceExpanded?: boolean;
131
+ onLensMapChange?: (url: string | null) => void;
132
+ /** Resolved colour scheme — picks the light/dark lens preset. */
133
+ scheme?: 'light' | 'dark';
134
+ /** Track colour at rest. Must be opaque. */
135
+ trackColor?: string;
136
+ /** Track colour when on. */
137
+ activeColor?: string;
138
+ /** Background colour the lens refracts against. */
139
+ surface?: string;
1093
140
  }
1094
141
 
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";
142
+ export declare const VERSION = "0.3.1";
1190
143
 
1191
144
  export { }