@blotch/angular-lynx 22.2.3 → 22.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -22
- package/fesm2022/{blotch-angular-lynx-web-glass-8MFrhPz0.mjs → blotch-angular-lynx-web-glass-ciDHw7Bw.mjs} +15 -5
- package/fesm2022/blotch-angular-lynx-web-glass-ciDHw7Bw.mjs.map +1 -0
- package/fesm2022/blotch-angular-lynx.mjs +376 -93
- package/fesm2022/blotch-angular-lynx.mjs.map +1 -1
- package/package.json +1 -1
- package/schematics/add-tailwind/index.js +14 -74
- package/schematics/add-tailwind/schema.json +6 -1
- package/schematics/collection.json +1 -1
- package/schematics/ng-add/index.js +4 -58
- package/schematics/ng-add/schema.json +7 -2
- package/schematics/ng-add/versions.js +8 -2
- package/schematics/utility/tailwind.js +167 -0
- package/types/blotch-angular-lynx.d.ts +169 -9
- package/fesm2022/blotch-angular-lynx-web-glass-8MFrhPz0.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
|
-
import { ApplicationConfig, ApplicationRef, ComponentRef, EmbeddedViewRef, EnvironmentInjector, EnvironmentProviders, ErrorDetails, ErrorHandler, Injector, OnChanges, OnDestroy, SimpleChanges, TemplateRef, Type, ViewContainerRef, signal } from "@angular/core";
|
|
2
|
+
import { ApplicationConfig, ApplicationRef, ComponentRef, EmbeddedViewRef, EnvironmentInjector, EnvironmentProviders, ErrorDetails, ErrorHandler, InjectionToken, Injector, OnChanges, OnDestroy, OutputRef, Signal, SimpleChanges, TemplateRef, Type, ViewContainerRef, signal } from "@angular/core";
|
|
3
3
|
import { Animation, AnimationOptions, Element as Element$1 } from "@lynx-js/types/main-thread";
|
|
4
4
|
import { AnyObject } from "@lynx-js/types/common";
|
|
5
5
|
import { ControlValueAccessor } from "@angular/forms";
|
|
@@ -55,6 +55,61 @@ export declare class LynxAccessibility {
|
|
|
55
55
|
static ɵfac: i0.ɵɵFactoryDeclaration<LynxAccessibility, never>;
|
|
56
56
|
static ɵprov: i0.ɵɵInjectableDeclaration<any>;
|
|
57
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* The user's accessibility display settings, as signals: Reduce Motion,
|
|
60
|
+
* Reduce Transparency and Increase Contrast.
|
|
61
|
+
*
|
|
62
|
+
* Lynx has no API for them on any platform, so they come from the host app,
|
|
63
|
+
* in its global props, like the theme does: `reduceMotion`,
|
|
64
|
+
* `reduceTransparency` and `increaseContrast`, each `true` when on. The apps
|
|
65
|
+
* `ng build --platform` makes send them, and send them again when the user
|
|
66
|
+
* changes one:
|
|
67
|
+
*
|
|
68
|
+
* - **iOS:** `UIAccessibility.isReduceMotionEnabled`,
|
|
69
|
+
* `isReduceTransparencyEnabled` and `isDarkerSystemColorsEnabled`
|
|
70
|
+
* (Increase Contrast).
|
|
71
|
+
* - **Android:** Remove animations (an animator duration scale of 0) for
|
|
72
|
+
* Reduce Motion, and contrast above standard (Android 14) or high contrast
|
|
73
|
+
* text (Android 16) for Increase Contrast. Android has no Reduce
|
|
74
|
+
* Transparency setting.
|
|
75
|
+
*
|
|
76
|
+
* In the web preview they follow the browser's `prefers-reduced-motion`,
|
|
77
|
+
* `prefers-reduced-transparency` and `prefers-contrast: more` too. Lynx
|
|
78
|
+
* Explorer sends none of them, so they're off there, unless you add them to
|
|
79
|
+
* the bundle URL: `?reduceMotion=true`.
|
|
80
|
+
*
|
|
81
|
+
* iOS 27's Liquid Glass appearance setting (clear or tinted glass) has no
|
|
82
|
+
* public API, so it isn't here. UIKit's glass follows it, and Reduce
|
|
83
|
+
* Transparency and Increase Contrast, by itself.
|
|
84
|
+
*
|
|
85
|
+
* @usageNotes
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const settings = inject(LynxAccessibilitySettings);
|
|
88
|
+
*
|
|
89
|
+
* // Jump instead of sliding when the user asked for less motion.
|
|
90
|
+
* const duration = computed(() => (settings.reduceMotion() ? 0 : 250));
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare class LynxAccessibilitySettings {
|
|
94
|
+
#private;
|
|
95
|
+
/**
|
|
96
|
+
* The user asked for less motion. Replace movement, such as a slide or a
|
|
97
|
+
* bounce, with a fade or an instant change.
|
|
98
|
+
*/
|
|
99
|
+
readonly reduceMotion: Signal<boolean>;
|
|
100
|
+
/**
|
|
101
|
+
* The user asked for less transparency. Draw blurred and translucent
|
|
102
|
+
* surfaces opaque.
|
|
103
|
+
*/
|
|
104
|
+
readonly reduceTransparency: Signal<boolean>;
|
|
105
|
+
/**
|
|
106
|
+
* The user asked for more contrast: iOS's Increase Contrast. Strengthen
|
|
107
|
+
* borders and use full-strength text colors.
|
|
108
|
+
*/
|
|
109
|
+
readonly increaseContrast: Signal<boolean>;
|
|
110
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LynxAccessibilitySettings, never>;
|
|
111
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<any>;
|
|
112
|
+
}
|
|
58
113
|
/**
|
|
59
114
|
* Phantom brand symbol — makes each ElementRef variant nominally distinct at
|
|
60
115
|
* the type level even though Lynx PAPI handles have no runtime structure.
|
|
@@ -1117,6 +1172,11 @@ export declare class TapGesture extends BaseGesture<TapGestureEvent, TapGesture>
|
|
|
1117
1172
|
* Lynx reads the margins as strings, so a bare number has no effect.
|
|
1118
1173
|
*/
|
|
1119
1174
|
type ExposureMargin = `${number}px` | `${number}rpx`;
|
|
1175
|
+
/**
|
|
1176
|
+
* One trait of `accessibility-traits`, each of which iOS turns into a
|
|
1177
|
+
* UIAccessibilityTraits flag (`LynxConverter+UI.m`).
|
|
1178
|
+
*/
|
|
1179
|
+
type AccessibilityTrait = 'text' | 'image' | 'button' | 'link' | 'header' | 'search' | 'selected' | 'playable' | 'keyboard' | 'summary' | 'disabled' | 'updating' | 'adjustable' | 'tabbar' | 'none';
|
|
1120
1180
|
/**
|
|
1121
1181
|
* @Directive() is required so that ng-packagr's Angular partial compiler
|
|
1122
1182
|
* recognizes this base class as an Angular artifact. The selector is left
|
|
@@ -1163,9 +1223,12 @@ declare class LynxElementBase implements OnChanges {
|
|
|
1163
1223
|
'accessibility-label'?: string;
|
|
1164
1224
|
/**
|
|
1165
1225
|
* The kind of element a screen reader announces. Plural, as Lynx reads it:
|
|
1166
|
-
* iOS, Android and Harmony ignore `accessibility-trait`.
|
|
1226
|
+
* iOS, Android and Harmony ignore `accessibility-trait`. iOS also reads a
|
|
1227
|
+
* comma-separated list with no spaces, such as `button,selected`, which
|
|
1228
|
+
* is what LynxRouterLinkActive writes; Android and Harmony read a single
|
|
1229
|
+
* trait. @default 'none'
|
|
1167
1230
|
*/
|
|
1168
|
-
'accessibility-traits'?:
|
|
1231
|
+
'accessibility-traits'?: AccessibilityTrait | `${AccessibilityTrait},${string}`;
|
|
1169
1232
|
/**
|
|
1170
1233
|
* Comma-separated `id`s of the child elements a screen reader visits, in
|
|
1171
1234
|
* order. iOS and Android look each one up as an `id` selector.
|
|
@@ -2996,11 +3059,59 @@ export declare class LynxWebView extends LynxElementBase {
|
|
|
2996
3059
|
};
|
|
2997
3060
|
}, {}, never, never, true, never>;
|
|
2998
3061
|
}
|
|
3062
|
+
/**
|
|
3063
|
+
* Finds the `isActiveChange` output of Angular's `RouterLinkActive` on the
|
|
3064
|
+
* element being created, or null if it has none. Called in the injection
|
|
3065
|
+
* context of that element's LynxRouterLinkActive.
|
|
3066
|
+
*
|
|
3067
|
+
* `provideRouter()` provides it, rather than LynxRouterLinkActive importing
|
|
3068
|
+
* `RouterLinkActive` itself, because LynxRouterLinkActive is part of
|
|
3069
|
+
* LYNX_ELEMENTS, which every component imports: referring to the router from
|
|
3070
|
+
* there would put the whole router in the bundle of an app without routes.
|
|
3071
|
+
* Without `provideRouter()` there's no router to follow, and the token is
|
|
3072
|
+
* missing.
|
|
3073
|
+
*/
|
|
3074
|
+
declare const ROUTER_LINK_ACTIVE_CHANGE: InjectionToken<() => OutputRef<boolean> | null>;
|
|
3075
|
+
/**
|
|
3076
|
+
* Tells screen readers which router link is the current one: while Angular's
|
|
3077
|
+
* `RouterLinkActive` on the same element says its route is active, the
|
|
3078
|
+
* element has the `selected` accessibility trait, as the selected tab of a
|
|
3079
|
+
* native tab bar does. On the web, `routerLinkActive` only changes classes, or
|
|
3080
|
+
* `aria-current` with `ariaCurrentWhenActive`; Lynx elements have no ARIA,
|
|
3081
|
+
* and `accessibility-traits` is how they say this.
|
|
3082
|
+
*
|
|
3083
|
+
* It keeps the element's own traits: `accessibility-traits="button"` becomes
|
|
3084
|
+
* `button,selected` while the link is active. On Android, which reads one
|
|
3085
|
+
* trait and has no selected trait, the element keeps its own traits as they
|
|
3086
|
+
* are.
|
|
3087
|
+
*
|
|
3088
|
+
* It's part of LYNX_ELEMENTS, so a component that imports LYNX_ELEMENTS and
|
|
3089
|
+
* Angular's `RouterLinkActive` gets it on every `routerLinkActive` element.
|
|
3090
|
+
* To add it to a component's host instead, list it in `hostDirectives` next
|
|
3091
|
+
* to `RouterLinkActive`.
|
|
3092
|
+
*
|
|
3093
|
+
* @usageNotes
|
|
3094
|
+
* ```ts
|
|
3095
|
+
* @Component({
|
|
3096
|
+
* imports: [LYNX_ELEMENTS, RouterLink, RouterLinkActive],
|
|
3097
|
+
* template: `
|
|
3098
|
+
* <view routerLink="/settings" routerLinkActive="active">
|
|
3099
|
+
* <text>Settings</text>
|
|
3100
|
+
* </view>
|
|
3101
|
+
* `,
|
|
3102
|
+
* })
|
|
3103
|
+
* ```
|
|
3104
|
+
*/
|
|
3105
|
+
export declare class LynxRouterLinkActive {
|
|
3106
|
+
constructor();
|
|
3107
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LynxRouterLinkActive, never>;
|
|
3108
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<LynxRouterLinkActive, "[routerLinkActive]", never, {}, {}, never, never, true, never>;
|
|
3109
|
+
}
|
|
2999
3110
|
/**
|
|
3000
3111
|
* All Lynx native element directives as a single importable array.
|
|
3001
3112
|
* Add to the `imports` of any component whose template uses Lynx elements.
|
|
3002
3113
|
*/
|
|
3003
|
-
export declare const LYNX_ELEMENTS: readonly [typeof LynxView, typeof LynxText, typeof LynxInlineTruncation, typeof LynxImage, typeof LynxScrollView, typeof LynxList, typeof LynxListItem, typeof LynxBlock, typeof LynxIf, typeof LynxFor, typeof LynxFrame, typeof LynxInput, typeof LynxTextarea, typeof LynxInputValueAccessor, typeof LynxTextareaValueAccessor, typeof LynxOverlay, typeof LynxRefresh, typeof LynxRefreshHeader, typeof LynxScrollCoordinator, typeof LynxScrollCoordinatorHeader, typeof LynxScrollCoordinatorSlot, typeof LynxScrollCoordinatorSlotDrag, typeof LynxScrollCoordinatorToolbar, typeof LynxSvg, typeof LynxViewPager, typeof LynxViewPagerItem, typeof LynxBlurView, typeof LynxVideo, typeof LynxWebView, typeof LynxCoverView, typeof LynxTitleBarView];
|
|
3114
|
+
export declare const LYNX_ELEMENTS: readonly [typeof LynxView, typeof LynxText, typeof LynxInlineTruncation, typeof LynxImage, typeof LynxScrollView, typeof LynxList, typeof LynxListItem, typeof LynxBlock, typeof LynxIf, typeof LynxFor, typeof LynxFrame, typeof LynxInput, typeof LynxTextarea, typeof LynxInputValueAccessor, typeof LynxTextareaValueAccessor, typeof LynxOverlay, typeof LynxRefresh, typeof LynxRefreshHeader, typeof LynxScrollCoordinator, typeof LynxScrollCoordinatorHeader, typeof LynxScrollCoordinatorSlot, typeof LynxScrollCoordinatorSlotDrag, typeof LynxScrollCoordinatorToolbar, typeof LynxSvg, typeof LynxViewPager, typeof LynxViewPagerItem, typeof LynxBlurView, typeof LynxVideo, typeof LynxWebView, typeof LynxCoverView, typeof LynxTitleBarView, typeof LynxRouterLinkActive];
|
|
3004
3115
|
export declare class LynxLogger {
|
|
3005
3116
|
#private;
|
|
3006
3117
|
log(...args: unknown[]): void;
|
|
@@ -3155,6 +3266,15 @@ export declare class LynxNativeModule {
|
|
|
3155
3266
|
}
|
|
3156
3267
|
type LynxEventType = 'bindEvent' | 'catchEvent' | 'capture-bindEvent' | 'capture-catchEvent' | 'global-bindEvent';
|
|
3157
3268
|
declare const EVENT_PREFIXES: [string, LynxEventType][];
|
|
3269
|
+
/**
|
|
3270
|
+
* DOM event names whose Lynx event has another name. A listener for one of
|
|
3271
|
+
* them hears the Lynx event, bubbling, as if it were bound with `bind`: a
|
|
3272
|
+
* `(click)` listener runs on a tap. This is the mapping Lynx for Web makes
|
|
3273
|
+
* between the two (web-core's `W3cEventNameToLynx` turns a DOM `click` into
|
|
3274
|
+
* `tap`), and it's what lets Angular's own directives that listen for
|
|
3275
|
+
* `click`, such as `RouterLink`, work on Lynx elements.
|
|
3276
|
+
*/
|
|
3277
|
+
declare const DOM_EVENT_ALIASES: ReadonlyMap<string, string>;
|
|
3158
3278
|
type BaseLynxElement = Pick<Element$1, 'setAttribute'> & {
|
|
3159
3279
|
tagName: string;
|
|
3160
3280
|
setProperty(name: string, value: any): void;
|
|
@@ -3172,6 +3292,12 @@ type BaseLynxElement = Pick<Element$1, 'setAttribute'> & {
|
|
|
3172
3292
|
*/
|
|
3173
3293
|
addScopeClass(name: string): void;
|
|
3174
3294
|
removeClass(name: string): void;
|
|
3295
|
+
/**
|
|
3296
|
+
* Adds a trait to the element's own `accessibility-traits`, or takes it
|
|
3297
|
+
* away, keeping the traits the app sets. For state the runtime tracks, such
|
|
3298
|
+
* as `selected` on an active router link (see LynxRouterLinkActive).
|
|
3299
|
+
*/
|
|
3300
|
+
setAccessibilityTrait(trait: string, on: boolean): void;
|
|
3175
3301
|
remove(): void;
|
|
3176
3302
|
parentNode(): BaseLynxElement | null;
|
|
3177
3303
|
nextSibling(): BaseLynxElement | null;
|
|
@@ -3228,6 +3354,12 @@ declare class LynxElement implements BaseLynxElement {
|
|
|
3228
3354
|
* creates one, and setAttribute whenever an attribute it depends on changes.
|
|
3229
3355
|
*/
|
|
3230
3356
|
updateBlurMaterial(): void;
|
|
3357
|
+
/**
|
|
3358
|
+
* Adds `trait` to the app's own `accessibility-traits`, or takes it away.
|
|
3359
|
+
* The app can still set its traits at any time: setAttribute merges the two
|
|
3360
|
+
* (see withAddedTraits), so neither undoes the other.
|
|
3361
|
+
*/
|
|
3362
|
+
setAccessibilityTrait(trait: string, on: boolean): void;
|
|
3231
3363
|
getAttribute(name: string): string;
|
|
3232
3364
|
removeAttribute(name: string): void;
|
|
3233
3365
|
setStyle(key: string, value: unknown): void;
|
|
@@ -3308,11 +3440,26 @@ declare class LynxElement implements BaseLynxElement {
|
|
|
3308
3440
|
* Angular's renderer.listen() calls this with event names like 'bindtap',
|
|
3309
3441
|
* 'catchtouchstart', 'bindscroll', etc. We strip the Lynx event prefix
|
|
3310
3442
|
* (bind/catch/capture-bind/capture-catch) to extract the native event name
|
|
3311
|
-
* and determine the event type for __AddEvent.
|
|
3312
|
-
*
|
|
3313
|
-
*
|
|
3443
|
+
* and determine the event type for __AddEvent. A DOM name Lynx calls
|
|
3444
|
+
* something else (see DOM_EVENT_ALIASES) listens for the Lynx event, so
|
|
3445
|
+
* `(click)`, and Angular's RouterLink with it, runs on a tap.
|
|
3446
|
+
* Other names (e.g. `mouseover`) are ignored: Lynx has no event for them.
|
|
3447
|
+
*
|
|
3448
|
+
* An element can have any number of listeners for one event, as on the
|
|
3449
|
+
* web: a template's `(bindtap)` next to a directive's host listener for
|
|
3450
|
+
* `click`, say. Native Lynx keeps one handler per event name, so each name
|
|
3451
|
+
* gets one native handler that runs all of them (see #syncNativeHandler).
|
|
3314
3452
|
*/
|
|
3315
3453
|
addEventListener(name: string, cb: (event: any) => any): () => void;
|
|
3454
|
+
/**
|
|
3455
|
+
* Removes a listener added with addEventListener, as the DOM method does,
|
|
3456
|
+
* for code that pairs the two on the element itself rather than going
|
|
3457
|
+
* through the renderer's cleanup function. Angular's `@defer` interaction
|
|
3458
|
+
* and hover triggers do, for their `click`, `keydown` and `mouseenter`
|
|
3459
|
+
* listeners; without it, their cleanup would throw. A name Lynx has no
|
|
3460
|
+
* event for was never added, so removing it does nothing.
|
|
3461
|
+
*/
|
|
3462
|
+
removeEventListener(name: string, cb: (event: any) => any): void;
|
|
3316
3463
|
}
|
|
3317
3464
|
/**
|
|
3318
3465
|
* Commits all queued genuine element removals — a free-function wrapper over
|
|
@@ -4093,7 +4240,8 @@ export declare class LynxSessionStorage {
|
|
|
4093
4240
|
*
|
|
4094
4241
|
* On iOS and Android (Lynx 4.1), the main thread has no global `SystemInfo`,
|
|
4095
4242
|
* only `lynx.SystemInfo`, so that's read first. The background thread and the
|
|
4096
|
-
* web have the global.
|
|
4243
|
+
* web have the global. The main thread's copy has no `osVersion` either: see
|
|
4244
|
+
* {@link LynxSystemInfo.osVersion} for where that comes from instead.
|
|
4097
4245
|
*
|
|
4098
4246
|
* @usageNotes
|
|
4099
4247
|
* ```typescript
|
|
@@ -4124,7 +4272,13 @@ export declare class LynxSystemInfo {
|
|
|
4124
4272
|
*/
|
|
4125
4273
|
get engineVersion(): string;
|
|
4126
4274
|
/**
|
|
4127
|
-
* The current operating system version.
|
|
4275
|
+
* The current operating system version, such as `'26.1'` on iOS or `'15'`
|
|
4276
|
+
* on Android. Empty while it isn't known.
|
|
4277
|
+
*
|
|
4278
|
+
* The native main thread's SystemInfo lacks it, so there it comes from the
|
|
4279
|
+
* host app's `osVersion` global prop, or else from the background thread,
|
|
4280
|
+
* which answers shortly after the first frame. It reads a signal, so a
|
|
4281
|
+
* `computed()` that reads it updates when the answer arrives.
|
|
4128
4282
|
*/
|
|
4129
4283
|
get osVersion(): string;
|
|
4130
4284
|
/**
|
|
@@ -4642,6 +4796,12 @@ declare const handlers: {
|
|
|
4642
4796
|
*/
|
|
4643
4797
|
callModule: (kind: ModuleKind, name: string, method: string, args: unknown[]) => unknown;
|
|
4644
4798
|
registerJSModule: (name: string, module: unknown) => void;
|
|
4799
|
+
/**
|
|
4800
|
+
* The OS version, for LynxSystemInfo on the main thread: native Lynx builds
|
|
4801
|
+
* that thread's SystemInfo without one, and the background thread's global
|
|
4802
|
+
* has it.
|
|
4803
|
+
*/
|
|
4804
|
+
osVersion: () => string | undefined;
|
|
4645
4805
|
/** The main thread's `fetch` (network/fetch.ts) sends its requests here. */
|
|
4646
4806
|
fetch: (id: number, request: RelayedRequest) => Promise<RelayedResponse>;
|
|
4647
4807
|
abortFetch: (id: number) => void;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blotch-angular-lynx-web-glass-8MFrhPz0.mjs","names":[],"sources":["../../src/lib/web-glass/blur-view-layout.ts","../../src/lib/web-glass/backdrop-observer.ts","../../src/lib/web-glass/css-color.ts","../../src/lib/web-glass/drawn-scale.ts","../../src/lib/web-glass/backdrop-clone.ts","../../src/lib/web-glass/backdrop-snapshot.ts","../../src/lib/web-glass/glass-shaders.ts","../../src/lib/web-glass/glass-gl.ts","../../src/lib/web-glass/glass-renderer.ts","../../src/lib/web-glass/glass-press.ts","../../src/lib/web-glass/glass-shapes.ts","../../src/lib/web-glass/glass-group.ts","../../src/lib/web-glass/glass-host-style.ts","../../src/lib/web-glass/glass-manager.ts","../../src/lib/web-glass/web-glass.ts"],"sourcesContent":["/**\n * web-elements' container layout rules for `<x-view>` (`linear.css`), as\n * `:host` rules for `<x-blur-view>`.\n *\n * On iOS a blur view lays its children out like any view: `flex-col`,\n * `flex-row` and the default linear layout all apply. web-elements gives\n * `<x-blur-view>` `display: flex` but leaves it out of the rules that turn\n * Lynx's layout variables (the display toggle, the linear orientation,\n * `--flex-direction`) into CSS; those list only `<x-view>` and the other\n * containers. So on web a blur view ignored `flex-col` and set its children\n * out in a row: the element-blur-view example's label sat centered across the\n * top of its panel instead of vertically centered at the left.\n *\n * A `:host` rule loses to every style from outside the shadow root, so a class\n * such as `flex` (which sets `--lynx-display-toggle`) or an inline style still\n * wins, exactly as it does over web-elements' own `x-view` rules.\n */\nexport const BLUR_VIEW_LAYOUT_CSS =\n ':host{' +\n '--lynx-display-toggle:var(--lynx-display-linear);' +\n '--lynx-display-linear:var(--lynx-display-toggle,);' +\n '--lynx-display-flex:var(--lynx-display-toggle,);' +\n '--lynx-linear-orientation-toggle:var(--lynx-linear-orientation-vertical);' +\n '--lynx-linear-orientation-horizontal:var(--lynx-linear-orientation-toggle,);' +\n '--lynx-linear-orientation-vertical:var(--lynx-linear-orientation-toggle,);' +\n '--lynx-linear-orientation-horizontal-reverse:var(--lynx-linear-orientation-toggle,);' +\n '--lynx-linear-orientation-vertical-reverse:var(--lynx-linear-orientation-toggle,);' +\n '--linear-flex-direction:var(--lynx-linear-orientation-horizontal,row) ' +\n 'var(--lynx-linear-orientation-vertical,column) ' +\n 'var(--lynx-linear-orientation-horizontal-reverse,row-reverse) ' +\n 'var(--lynx-linear-orientation-vertical-reverse,column-reverse);' +\n '--linear-justify-content:var(--lynx-linear-orientation-horizontal,var(--justify-content-row)) ' +\n 'var(--lynx-linear-orientation-vertical,var(--justify-content-column)) ' +\n 'var(--lynx-linear-orientation-horizontal-reverse,var(--justify-content-row-reverse)) ' +\n 'var(--lynx-linear-orientation-vertical-reverse,var(--justify-content-column-reverse));' +\n 'flex-wrap:var(--lynx-display-linear,nowrap) var(--lynx-display-flex,var(--flex-wrap));' +\n 'flex-direction:var(--lynx-display-linear,var(--linear-flex-direction)) ' +\n 'var(--lynx-display-flex,var(--flex-direction));' +\n 'justify-content:var(--lynx-display-linear,var(--linear-justify-content))' +\n '}';\n\n/**\n * Gives a `<blur-view>` on Lynx for Web the layout of a `<view>` (see\n * {@link BLUR_VIEW_LAYOUT_CSS}), through a `<style>` in its own shadow root.\n * Like the glass styles, it stays inside the element: Lynx owns its `class`\n * and `style` attributes.\n */\nexport const applyBlurViewLayout = (element: HTMLElement): void => {\n const root = element.shadowRoot;\n if (!root) return;\n const style = element.ownerDocument.createElement('style');\n style.textContent = BLUR_VIEW_LAYOUT_CSS;\n root.appendChild(style);\n};\n","/**\n * Calls `onChange` whenever what's behind the glass may look different:\n * something in `backdrop` mutates, resizes, scrolls or loads, web fonts\n * finish loading, or the color scheme flips. Changes inside `glass` itself (a\n * blob dragged by its left/top) don't count, since they don't change what's\n * behind it. Returns a function that stops observing.\n */\nexport const observeBackdrop = (\n backdrop: HTMLElement,\n glass: Element,\n onChange: () => void,\n): (() => void) => {\n const win = backdrop.ownerDocument.defaultView!;\n const mutations = new win.MutationObserver((records) => {\n if (records.some((record) => !glass.contains(record.target))) onChange();\n });\n mutations.observe(backdrop, {\n subtree: true,\n childList: true,\n attributes: true,\n characterData: true,\n });\n const resizes = new win.ResizeObserver(onChange);\n resizes.observe(backdrop);\n // Scroll and image load events don't bubble, but they do reach a capturing\n // listener on an ancestor.\n backdrop.addEventListener('scroll', onChange, true);\n backdrop.addEventListener('load', onChange, true);\n const scheme = win.matchMedia('(prefers-color-scheme: dark)');\n scheme.addEventListener('change', onChange);\n // Text reflows once web fonts load, moving what's behind the glass.\n void backdrop.ownerDocument.fonts.ready.then(onChange);\n return () => {\n mutations.disconnect();\n resizes.disconnect();\n backdrop.removeEventListener('scroll', onChange, true);\n backdrop.removeEventListener('load', onChange, true);\n scheme.removeEventListener('change', onChange);\n };\n};\n","/** A color as red, green, blue and alpha channels, each from 0 to 1. */\nexport type Rgba = readonly [number, number, number, number];\n\nexport const TRANSPARENT: Rgba = [0, 0, 0, 0];\n\nconst RGB_FUNCTION = /^rgba?\\(([^)]*)\\)$/;\nconst HEX = /^#([0-9a-f]{6})$/i;\n\n/**\n * Parses the two forms a browser hands back for a color it has normalized:\n * six-digit hex (an opaque canvas `fillStyle`) and `rgb()`/`rgba()` (computed\n * styles, a translucent `fillStyle`). Anything else is transparent, so a value\n * the browser couldn't parse draws nothing rather than black.\n */\nexport const parseNormalizedColor = (value: string): Rgba => {\n const hex = HEX.exec(value);\n if (hex) {\n const n = parseInt(hex[1]!, 16);\n return [(n >> 16) / 255, ((n >> 8) & 255) / 255, (n & 255) / 255, 1];\n }\n const fn = RGB_FUNCTION.exec(value.trim());\n if (!fn) return TRANSPARENT;\n const parts = fn[1]!\n .split(/[\\s,/]+/)\n .filter(Boolean)\n .map(Number);\n if (parts.length < 3 || parts.some(Number.isNaN)) return TRANSPARENT;\n const [r, g, b, a = 1] = parts as [number, number, number, number?];\n return [r / 255, g / 255, b / 255, a];\n};\n\nconst cache = new Map<string, Rgba>();\nlet context: CanvasRenderingContext2D | null | undefined;\n\n/**\n * Resolves any CSS color an author can write (`red`, `#3b82f6`, `rgba(…)`)\n * into channels. A canvas `fillStyle` normalizes the value without touching the\n * DOM or forcing a style recalculation. An invalid value leaves `fillStyle` unchanged,\n * so a sentinel set first tells the two apart.\n */\nexport const resolveCssColor = (doc: Document, value: string | null): Rgba => {\n if (!value) return TRANSPARENT;\n const cached = cache.get(value);\n if (cached) return cached;\n context ??= doc.createElement('canvas').getContext('2d');\n if (!context) return TRANSPARENT;\n const sentinel = 'rgba(1, 2, 3, 0.5)';\n context.fillStyle = sentinel;\n context.fillStyle = value;\n const normalized = String(context.fillStyle);\n const color =\n normalized === sentinel ? TRANSPARENT : parseNormalizedColor(normalized);\n cache.set(value, color);\n return color;\n};\n\n/** Relative luminance, used to pick the light or dark glass material. */\nexport const luminance = ([r, g, b]: Rgba): number =>\n 0.2126 * r + 0.7152 * g + 0.0722 * b;\n","/**\n * Screen pixels per CSS pixel that `element` is drawn at: below 1 when a\n * transform on it or an ancestor scales it down, as the docs' previews do to\n * fit a phone-sized page in their pane. getBoundingClientRect() measures in\n * screen pixels, but layout and every CSS length are in CSS pixels, so the\n * glass code divides boxes by this to keep to CSS pixels.\n */\nexport const drawnScale = (element: HTMLElement): number => {\n const drawn = element.getBoundingClientRect().width;\n // A transform doesn't change offsetWidth.\n const laidOut = element.offsetWidth;\n // offsetWidth is rounded to a whole pixel, so a difference of less than one\n // is rounding, not scale.\n if (!laidOut || Math.abs(drawn - laidOut) < 1) return 1;\n return drawn / laidOut;\n};\n","import { parseNormalizedColor, type Rgba } from './css-color';\nimport { drawnScale } from './drawn-scale';\n\n/** A rectangle in viewport (client) coordinates. */\nexport type Region = {\n left: number;\n top: number;\n right: number;\n bottom: number;\n};\n\nexport type CloneOptions = {\n /** Leaves an element, and everything inside it, out of the copy. */\n exclude: (element: Element) => boolean;\n /**\n * The part of the page the glass can show. A clipping element wholly\n * outside it is copied empty, which keeps long lists cheap to capture.\n */\n region: Region;\n};\n\ntype Context = {\n doc: Document;\n win: Window;\n defaults: Map<string, string>;\n} & CloneOptions;\n\n// Properties that can't change a still image, or that would start animating\n// inside it. Custom properties are already resolved into the real ones.\nconst SKIPPED_PROPERTY =\n /^(--|transition|animation|will-change|cursor|pointer-events|user-select|-webkit-user-)/;\n// Widths whose computed value matches a plain div's only because that div has\n// no border or outline: `0px` comes from `border-style: none`. Lynx for Web\n// gives every element `border-style: solid`, so leaving the width out would\n// draw a 3px (`medium`) black border in the copy.\nconst ALWAYS_INLINED =\n /^(border-(top|right|bottom|left)-width|outline-width|column-rule-width)$/;\nconst SKIPPED_TAGS = new Set(['style', 'script', 'template', 'link', 'meta']);\n\n// Node types, spelled out: on Lynx for Web the main thread runs in an iframe's\n// realm while the elements belong to the page, so `instanceof` checks against\n// this realm's DOM classes would always fail.\nconst ELEMENT_NODE = 1;\nconst TEXT_NODE = 3;\n\nconst defaultsByDocument = new WeakMap<Document, Map<string, string>>();\n\n/**\n * A plain div's computed style: anything matching it needn't be inlined.\n */\nconst defaultStyle = (doc: Document, win: Window): Map<string, string> => {\n let defaults = defaultsByDocument.get(doc);\n if (!defaults) {\n const probe = doc.createElement('div');\n doc.documentElement.appendChild(probe);\n const style = win.getComputedStyle(probe);\n defaults = new Map(\n Array.from(style, (name) => [name, style.getPropertyValue(name)]),\n );\n probe.remove();\n defaultsByDocument.set(doc, defaults);\n }\n return defaults;\n};\n\n/**\n * Inlines a computed style, keeping each property that differs from a plain\n * div or from the parent. The parent check matters for inherited properties:\n * a black heading inside white text matches the default but would inherit\n * white in the copy if it were left out.\n */\nconst inlineStyle = (\n style: CSSStyleDeclaration,\n parent: CSSStyleDeclaration | null,\n defaults: Map<string, string>,\n): string => {\n let css = '';\n for (const name of Array.from(style)) {\n if (SKIPPED_PROPERTY.test(name)) continue;\n const value = style.getPropertyValue(name);\n if (\n ALWAYS_INLINED.test(name) ||\n value !== defaults.get(name) ||\n (parent && value !== parent.getPropertyValue(name))\n ) {\n css += `${name}:${value};`;\n }\n }\n return css;\n};\n\n/**\n * Children as they render: a shadow root's children instead of the light\n * ones, with each `<slot>` replaced by what's assigned to it. Every Lynx for\n * Web element is a custom element that draws its children through a slot.\n */\nconst renderedChildren = (element: Element): Node[] =>\n Array.from(element.shadowRoot?.childNodes ?? element.childNodes).flatMap(\n (child) =>\n (child as Element).localName === 'slot'\n ? (child as HTMLSlotElement).assignedNodes({ flatten: true })\n : [child],\n );\n\n/**\n * Moves a child of a scrolled element by the scroll offset, so the copy shows\n * what's scrolled into view rather than the top of the content.\n */\nconst scrollShift = (\n style: CSSStyleDeclaration,\n [x, y]: readonly [number, number],\n): string => {\n if (!x && !y) return '';\n if (style.position === 'fixed' || style.position === 'sticky') return '';\n if (style.position === 'static') {\n return `position:relative;left:${-x}px;top:${-y}px;`;\n }\n const left = (parseFloat(style.left) || 0) - x;\n const top = (parseFloat(style.top) || 0) - y;\n return `left:${left}px;top:${top}px;`;\n};\n\n/**\n * Inlines an image as a data URL: an SVG image can't load anything external.\n * A cross-origin image without CORS taints the canvas and is left blank.\n */\nconst mediaSource = (element: Element, doc: Document): string => {\n try {\n if (element.localName === 'canvas') {\n return (element as HTMLCanvasElement).toDataURL();\n }\n const image = element as HTMLImageElement;\n if (!image.complete || !image.naturalWidth) return '';\n const canvas = doc.createElement('canvas');\n canvas.width = image.naturalWidth;\n canvas.height = image.naturalHeight;\n canvas.getContext('2d')!.drawImage(image, 0, 0);\n return canvas.toDataURL();\n } catch {\n return '';\n }\n};\n\nconst outside = (rect: DOMRect, region: Region): boolean =>\n rect.right <= region.left ||\n rect.left >= region.right ||\n rect.bottom <= region.top ||\n rect.top >= region.bottom;\n\nconst cloneNode = (\n node: Node,\n context: Context,\n parent: CSSStyleDeclaration | null,\n scroll: readonly [number, number],\n): Node | null => {\n if (node.nodeType === TEXT_NODE) {\n return context.doc.createTextNode((node as Text).data);\n }\n if (node.nodeType !== ELEMENT_NODE) return null;\n const element = node as Element;\n if (SKIPPED_TAGS.has(element.localName) || context.exclude(element)) {\n return null;\n }\n const style = context.win.getComputedStyle(element);\n if (style.display === 'none') return null;\n\n const media = element.localName === 'img' || element.localName === 'canvas';\n const clone = context.doc.createElement(media ? 'img' : 'div');\n clone.setAttribute(\n 'style',\n inlineStyle(style, parent, context.defaults) + scrollShift(style, scroll),\n );\n if (media) {\n const source = mediaSource(element, context.doc);\n if (source) clone.setAttribute('src', source);\n return clone;\n }\n const clips = style.overflowX !== 'visible' || style.overflowY !== 'visible';\n if (clips && outside(element.getBoundingClientRect(), context.region)) {\n return clone;\n }\n const childScroll = [element.scrollLeft, element.scrollTop] as const;\n for (const child of renderedChildren(element)) {\n const copy = cloneNode(child, context, style, childScroll);\n if (copy) clone.appendChild(copy);\n }\n return clone;\n};\n\n/**\n * The color behind an element: its own background, or the first ancestor's\n * that isn't transparent, crossing shadow roots. White when nothing paints.\n */\nexport const effectiveBackground = (element: Element): Rgba => {\n const win = element.ownerDocument.defaultView!;\n let node: Element | null = element;\n while (node) {\n const color = parseNormalizedColor(\n win.getComputedStyle(node).backgroundColor,\n );\n if (color[3] > 0) return color;\n node =\n node.parentElement ??\n ((node.getRootNode() as Partial<ShadowRoot>).host as Element | null) ??\n null;\n }\n return [1, 1, 1, 1];\n};\n\n/**\n * Copies `root` into plain divs with inlined styles, ready to rasterize inside\n * an SVG `<foreignObject>`. The copy is pinned to the top-left of a frame the\n * size of `root`, painted with the color behind it, so transparent areas show\n * what the page shows there instead of nothing.\n *\n * The frame is rounded up to whole CSS pixels. The browser paints it in whole\n * pixels, so a fractional size would leave its last row or column part\n * transparent, and the glass shows a transparent image edge as a dark band.\n */\nexport const cloneBackdrop = (\n root: HTMLElement,\n options: CloneOptions,\n): HTMLElement => {\n const doc = root.ownerDocument;\n const win = doc.defaultView!;\n // The root's size in CSS pixels, which its copied contents lay out in,\n // rather than its scaled size when the page is drawn scaled.\n const bounds = root.getBoundingClientRect();\n const zoom = drawnScale(root);\n const width = bounds.width / zoom;\n const height = bounds.height / zoom;\n const [r, g, b, a] = effectiveBackground(root);\n const frame = doc.createElement('div');\n frame.setAttribute(\n 'style',\n `width:${Math.ceil(width)}px;height:${Math.ceil(height)}px;` +\n `overflow:hidden;` +\n `background:rgba(${r * 255},${g * 255},${b * 255},${a});`,\n );\n const context = { ...options, doc, win, defaults: defaultStyle(doc, win) };\n const clone = cloneNode(root, context, null, [0, 0]) as HTMLElement | null;\n if (clone) {\n // Whatever placed the root in the page (margins, offsets, transforms)\n // isn't part of the picture.\n clone.style.cssText +=\n `margin:0;position:relative;left:0;top:0;right:auto;bottom:auto;` +\n `transform:none;width:${width}px;height:${height}px;`;\n frame.appendChild(clone);\n }\n return frame;\n};\n","import {\n cloneBackdrop,\n effectiveBackground,\n type CloneOptions,\n} from './backdrop-clone';\nimport { luminance } from './css-color';\nimport { drawnScale } from './drawn-scale';\n\n/** An image of what sits behind a glass group. */\nexport type BackdropSnapshot = {\n image: HTMLCanvasElement;\n /** The captured region, relative to the backdrop root, in CSS pixels. */\n x: number;\n y: number;\n width: number;\n height: number;\n /** How bright the backdrop's background is, from 0 to 1. */\n luminance: number;\n};\n\nexport type SnapshotOptions = {\n /** Device pixels per CSS pixel to capture at. */\n scale: number;\n} & CloneOptions;\n\n// Keeps the image inside every GPU's texture limit (WebGL 1 guarantees far\n// less, but phones and desktops alike accept 4096).\nconst MAX_IMAGE_SIZE = 4096;\n\n/**\n * Captures part of `root` as an image. The browser can't hand page pixels to\n * WebGL, so the page is redrawn instead: the subtree is copied with inlined\n * styles (see backdrop-clone.ts), wrapped in an SVG `<foreignObject>` and\n * drawn to a canvas. The SVG's viewBox crops it to `region`, so only the area\n * the glass can show is rasterized.\n *\n * Resolves to null when the region doesn't overlap `root`.\n */\nexport const snapshotBackdrop = async (\n root: HTMLElement,\n options: SnapshotOptions,\n): Promise<BackdropSnapshot | null> => {\n const doc = root.ownerDocument;\n const win = doc.defaultView!;\n const bounds = root.getBoundingClientRect();\n const left = Math.max(options.region.left, bounds.left);\n const top = Math.max(options.region.top, bounds.top);\n const right = Math.min(options.region.right, bounds.right);\n const bottom = Math.min(options.region.bottom, bounds.bottom);\n if (right <= left || bottom <= top) return null;\n // The region and the root's box are in screen pixels, but the copy lays out\n // in CSS pixels: the two differ when the page is drawn scaled.\n const zoom = drawnScale(root);\n const x = (left - bounds.left) / zoom;\n const y = (top - bounds.top) / zoom;\n const width = (right - left) / zoom;\n const height = (bottom - top) / zoom;\n const scale = Math.min(\n options.scale,\n MAX_IMAGE_SIZE / Math.max(width, height),\n );\n\n const markup = new win.XMLSerializer().serializeToString(\n cloneBackdrop(root, options),\n );\n const pixelWidth = Math.max(1, Math.round(width * scale));\n const pixelHeight = Math.max(1, Math.round(height * scale));\n // The image's edges must be opaque: the glass clamps to them where its lens\n // looks past the image, so a transparent row there shows as a dark band.\n // Rounding the image's width and height separately leaves its shape a\n // little off the viewBox's, which the default `preserveAspectRatio` would\n // fit with an empty strip along one edge, so the viewBox is stretched\n // instead. The <foreignObject> matches the copy's frame, which is rounded up\n // to whole pixels (see cloneBackdrop).\n const svg =\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${pixelWidth}\" ` +\n `height=\"${pixelHeight}\" viewBox=\"${x} ${y} ${width} ${height}\" ` +\n `preserveAspectRatio=\"none\">` +\n `<foreignObject width=\"${Math.ceil(bounds.width / zoom)}\" ` +\n `height=\"${Math.ceil(bounds.height / zoom)}\">` +\n `${markup}</foreignObject></svg>`;\n const picture = new win.Image();\n picture.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;\n await picture.decode();\n\n const image = doc.createElement('canvas');\n image.width = pixelWidth;\n image.height = pixelHeight;\n image.getContext('2d')!.drawImage(picture, 0, 0, pixelWidth, pixelHeight);\n return {\n image,\n x,\n y,\n width,\n height,\n luminance: luminance(effectiveBackground(root)),\n };\n};\n","/**\n * The most glass shapes one group draws. GLSL ES 1.0 (WebGL 1) needs a\n * constant array size and loop bound; a container rarely holds more than a\n * handful of shapes, and any past this aren't drawn.\n */\nexport const MAX_GLASS_SHAPES = 16;\n\n/** Full-screen quad. `v_uv` runs 0→1 with y pointing up, as GL does. */\nexport const QUAD_VERTEX_SHADER = `\nattribute vec2 a_position;\nvarying vec2 v_uv;\nvoid main() {\n v_uv = a_position * 0.5 + 0.5;\n gl_Position = vec4(a_position, 0.0, 1.0);\n}`;\n\n/** Copies a texture, downsampling the backdrop before it is blurred. */\nexport const COPY_FRAGMENT_SHADER = `\nprecision mediump float;\nvarying vec2 v_uv;\nuniform sampler2D u_source;\nvoid main() {\n gl_FragColor = texture2D(u_source, v_uv);\n}`;\n\n/**\n * One direction of a separable Gaussian blur. Sampling between two pixels lets\n * the linear filter average both at once, so five fetches cover nine pixels.\n */\nexport const BLUR_FRAGMENT_SHADER = `\nprecision mediump float;\nvarying vec2 v_uv;\nuniform sampler2D u_source;\nuniform vec2 u_direction;\nvoid main() {\n vec2 near = u_direction * 1.3846153846;\n vec2 far = u_direction * 3.2307692308;\n gl_FragColor = texture2D(u_source, v_uv) * 0.2270270270\n + (texture2D(u_source, v_uv + near) + texture2D(u_source, v_uv - near)) * 0.3162162162\n + (texture2D(u_source, v_uv + far) + texture2D(u_source, v_uv - far)) * 0.0702702703;\n}`;\n\n/**\n * Draws every glass shape of a group in one pass, in CSS pixels with y down.\n *\n * GLSL ES 1.0 only lets a loop's own counter index the uniform arrays, so the\n * per-shape distance is written out in each loop rather than in a helper.\n *\n * - Each shape is a rounded box signed distance field (SDF). A smooth minimum\n * unions them, so shapes closer than the container's `spacing` flow into one\n * another like iOS 26's glass container.\n * - The lens samples the backdrop outward near the rim, where the glass is\n * steepest, and slightly inward elsewhere. The rim shows the content just\n * outside it bent around the edge, and the middle reads a little magnified.\n * The SDF gradient gives the direction; its length fades the effect where\n * merged shapes crease, which would otherwise show a seam.\n * - `regular` glass mixes in a blurred, brightened backdrop; `clear` glass\n * keeps it sharp. Tint, a specular rim lit from the top left, and a press\n * glow for interactive glass go on top.\n */\nexport const GLASS_FRAGMENT_SHADER = `\nprecision highp float;\n#define MAX_SHAPES ${MAX_GLASS_SHAPES}\nvarying vec2 v_uv;\nuniform sampler2D u_backdrop;\nuniform sampler2D u_frosted;\nuniform vec2 u_size;\nuniform vec2 u_offset;\nuniform vec2 u_backdropSize;\nuniform float u_scale;\nuniform float u_smoothing;\nuniform float u_dark;\nuniform float u_shadow;\nuniform int u_count;\nuniform vec4 u_bounds[MAX_SHAPES];\nuniform vec4 u_material[MAX_SHAPES];\nuniform vec4 u_tint[MAX_SHAPES];\nuniform vec3 u_pointer;\n\nfloat roundedBox(vec2 p, vec2 halfSize, float radius) {\n vec2 q = abs(p) - halfSize + radius;\n return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius;\n}\n\nfloat smoothUnion(float a, float b, float k) {\n if (k <= 0.0) return min(a, b);\n float h = max(k - abs(a - b), 0.0) / k;\n return min(a, b) - h * h * k * 0.25;\n}\n\nfloat scene(vec2 p) {\n float d = 1e5;\n for (int i = 0; i < MAX_SHAPES; i++) {\n if (i >= u_count) break;\n d = smoothUnion(d, roundedBox(p - u_bounds[i].xy, u_bounds[i].zw, u_material[i].x), u_smoothing);\n }\n return d;\n}\n\nvoid main() {\n vec2 p = vec2(v_uv.x, 1.0 - v_uv.y) * u_size;\n\n // Union the shapes, and blend each shape's material by how close it is, so\n // a merged bridge between two tints shades from one to the other.\n float d = 1e5;\n float weights = 0.0;\n float frost = 0.0;\n float lens = 0.0;\n vec4 tint = vec4(0.0);\n for (int i = 0; i < MAX_SHAPES; i++) {\n if (i >= u_count) break;\n float di = roundedBox(p - u_bounds[i].xy, u_bounds[i].zw, u_material[i].x);\n d = smoothUnion(d, di, u_smoothing);\n float w = exp(-max(di, 0.0) / max(u_smoothing * 0.3, 1.0)) + 1e-6;\n weights += w;\n frost += u_material[i].y * w;\n lens += min(u_bounds[i].z, u_bounds[i].w) * w;\n tint += u_tint[i] * w;\n }\n frost /= weights;\n lens = max(lens / weights, 1.0);\n tint /= weights;\n\n // One device pixel of anti-aliasing at the edge.\n float coverage = clamp(0.5 - d * u_scale, 0.0, 1.0);\n // A container can hug its shapes, so the shadow fades out before the canvas\n // edge rather than stopping at it in a hard line.\n vec2 inside = min(p, u_size - p);\n float shadow = u_shadow * 0.1 * exp(-max(d, 0.0) / 6.0)\n * smoothstep(0.0, 12.0, min(inside.x, inside.y));\n if (coverage <= 0.0) {\n gl_FragColor = vec4(0.0, 0.0, 0.0, d < 24.0 ? shadow : 0.0);\n return;\n }\n\n vec2 e = vec2(0.5, 0.0);\n vec2 gradient = vec2(\n scene(p + e.xy) - scene(p - e.xy),\n scene(p + e.yx) - scene(p - e.yx));\n float slope = length(gradient);\n vec2 normal = slope > 0.0 ? gradient / slope : vec2(0.0);\n gradient = normal * min(slope, 1.0);\n\n float depth = max(-d, 0.0);\n float rim = pow(1.0 - clamp(depth / lens, 0.0, 1.0), 3.0);\n vec2 offset = gradient * (lens * 0.45 * rim - max(lens - depth, 0.0) * 0.05);\n vec2 base = p + u_offset;\n vec2 uv = (base + offset) / u_backdropSize;\n\n // A touch of dispersion: red bends a little more than blue.\n vec3 sharp = vec3(\n texture2D(u_backdrop, (base + offset * 1.035) / u_backdropSize).r,\n texture2D(u_backdrop, uv).g,\n texture2D(u_backdrop, (base + offset * 0.965) / u_backdropSize).b);\n vec3 color = mix(sharp, texture2D(u_frosted, uv).rgb, frost);\n\n float brightness = dot(color, vec3(0.2126, 0.7152, 0.0722));\n color = mix(vec3(brightness), color, 1.0 + 0.3 * frost);\n color = mix(color, mix(vec3(1.0), vec3(0.12), u_dark), frost * mix(0.22, 0.34, u_dark));\n color *= 1.0 - 0.08 * u_dark * (1.0 - frost);\n color = mix(color, tint.rgb, tint.a);\n\n vec2 light = normalize(vec2(-0.6, -0.8));\n float facing = dot(normal, light);\n color += (1.0 - smoothstep(0.0, 1.5, depth)) * (0.22 + 0.58 * pow(abs(facing), 1.5)) * mix(0.75, 0.5, u_dark);\n color += (1.0 - smoothstep(0.0, lens * 0.5, depth)) * max(facing, 0.0) * 0.16;\n color += (1.0 - smoothstep(0.0, lens * 0.35, depth)) * max(-facing, 0.0) * 0.07;\n\n float reach = length(p - u_pointer.xy);\n color += u_pointer.z * 0.2 * exp(-reach * reach / (1.2 * lens * lens));\n\n gl_FragColor = vec4(clamp(color, 0.0, 1.0) * coverage, coverage + shadow * (1.0 - coverage));\n}`;\n","import { QUAD_VERTEX_SHADER } from './glass-shaders';\n\nexport type Program = {\n program: WebGLProgram;\n uniform: (name: string) => WebGLUniformLocation | null;\n};\n\nexport type Target = {\n texture: WebGLTexture;\n framebuffer: WebGLFramebuffer;\n};\n\nexport const compile = (\n gl: WebGLRenderingContext,\n fragmentSource: string,\n): Program | null => {\n const program = gl.createProgram();\n for (const [type, source] of [\n [gl.VERTEX_SHADER, QUAD_VERTEX_SHADER],\n [gl.FRAGMENT_SHADER, fragmentSource],\n ] as const) {\n const shader = gl.createShader(type)!;\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n gl.attachShader(program, shader);\n }\n // Every program shares the one quad buffer bound to attribute 0.\n gl.bindAttribLocation(program, 0, 'a_position');\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) return null;\n const locations = new Map<string, WebGLUniformLocation | null>();\n const uniform = (name: string) => {\n if (!locations.has(name)) {\n locations.set(name, gl.getUniformLocation(program, name));\n }\n return locations.get(name)!;\n };\n return { program, uniform };\n};\n\nexport const createTexture = (gl: WebGLRenderingContext): WebGLTexture => {\n const texture = gl.createTexture();\n gl.bindTexture(gl.TEXTURE_2D, texture);\n // WebGL 1 can't mipmap or repeat non-power-of-two textures; clamping also\n // stretches the backdrop's edge when the lens samples past it.\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n return texture;\n};\n\nexport const createTarget = (\n gl: WebGLRenderingContext,\n width: number,\n height: number,\n): Target => {\n const texture = createTexture(gl);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA,\n width,\n height,\n 0,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n null,\n );\n const framebuffer = gl.createFramebuffer();\n gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);\n gl.framebufferTexture2D(\n gl.FRAMEBUFFER,\n gl.COLOR_ATTACHMENT0,\n gl.TEXTURE_2D,\n texture,\n 0,\n );\n return { texture, framebuffer };\n};\n","import type { Rgba } from './css-color';\nimport {\n compile,\n createTarget,\n createTexture,\n type Program,\n type Target,\n} from './glass-gl';\nimport {\n BLUR_FRAGMENT_SHADER,\n COPY_FRAGMENT_SHADER,\n GLASS_FRAGMENT_SHADER,\n MAX_GLASS_SHAPES,\n} from './glass-shaders';\n\n/** One glass shape, in CSS pixels relative to the group's canvas. */\nexport type GlassShapeFrame = {\n centerX: number;\n centerY: number;\n halfWidth: number;\n halfHeight: number;\n radius: number;\n /** 1 for `regular` (frosted) glass, 0 for `clear`. */\n frost: number;\n tint: Rgba;\n};\n\n/** Everything one frame of a glass group draws. */\nexport type GlassFrame = {\n /** Device pixels per CSS pixel. */\n scale: number;\n /** Canvas size, in CSS pixels. */\n width: number;\n height: number;\n /** Where the canvas's top-left corner sits in the backdrop, in CSS pixels. */\n offsetX: number;\n offsetY: number;\n /** Smooth-union radius, in CSS pixels: twice the container's `spacing`. */\n smoothing: number;\n /** 1 for the dark material, 0 for light. */\n dark: number;\n /** 1 to draw a soft shadow around the shapes (containers only). */\n shadow: number;\n shapes: readonly GlassShapeFrame[];\n /** Press glow: x and y in CSS pixels, then strength from 0 to 1. */\n pointer: readonly [number, number, number];\n};\n\n// Frosted glass blurs a copy of the backdrop at a quarter of its resolution:\n// three blur passes there cost little and soften it as much as iOS's material.\nconst FROST_DOWNSAMPLE = 4;\nconst FROST_PASSES = 3;\n\n/**\n * Draws Liquid Glass with WebGL 1 for Lynx for Web, where `<blur-view>` only\n * knows `backdrop-filter: blur()`. The backdrop is an image of what sits\n * behind the glass; the group code takes it (see backdrop-snapshot.ts) and the\n * renderer refracts it through the glass shapes.\n */\nexport class GlassRenderer {\n readonly #gl: WebGLRenderingContext;\n readonly #copy: Program;\n readonly #blur: Program;\n readonly #glass: Program;\n readonly #quad: WebGLBuffer;\n #backdrop: WebGLTexture | null = null;\n #frosted: [Target, Target] | null = null;\n #frostedSize = '';\n #backdropWidth = 1;\n #backdropHeight = 1;\n\n /**\n * Use `GlassRenderer.create`, which builds the programs this needs.\n */\n constructor(\n gl: WebGLRenderingContext,\n copy: Program,\n blur: Program,\n glass: Program,\n ) {\n this.#gl = gl;\n this.#copy = copy;\n this.#blur = blur;\n this.#glass = glass;\n this.#quad = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, this.#quad);\n gl.bufferData(\n gl.ARRAY_BUFFER,\n new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),\n gl.STATIC_DRAW,\n );\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n }\n\n /**\n * Null when the browser has no WebGL or can't build the shaders.\n */\n static create(canvas: HTMLCanvasElement): GlassRenderer | null {\n const gl = canvas.getContext('webgl', {\n alpha: true,\n premultipliedAlpha: true,\n antialias: false,\n depth: false,\n stencil: false,\n });\n if (!gl) return null;\n const copy = compile(gl, COPY_FRAGMENT_SHADER);\n const blur = compile(gl, BLUR_FRAGMENT_SHADER);\n const glass = compile(gl, GLASS_FRAGMENT_SHADER);\n if (!copy || !blur || !glass) return null;\n return new GlassRenderer(gl, copy, blur, glass);\n }\n\n /**\n * True once the GPU dropped the context; the group then starts over.\n */\n get lost(): boolean {\n return this.#gl.isContextLost();\n }\n\n /**\n * Uploads a new backdrop image and blurs a copy of it for frosted glass.\n * `width` and `height` are its size in CSS pixels.\n */\n setBackdrop(image: HTMLCanvasElement, width: number, height: number): void {\n const gl = this.#gl;\n this.#backdropWidth = width;\n this.#backdropHeight = height;\n this.#backdrop ??= createTexture(gl);\n gl.bindTexture(gl.TEXTURE_2D, this.#backdrop);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);\n\n const w = Math.max(1, Math.round(image.width / FROST_DOWNSAMPLE));\n const h = Math.max(1, Math.round(image.height / FROST_DOWNSAMPLE));\n if (this.#frostedSize !== `${w}x${h}`) {\n this.#deleteFrosted();\n this.#frosted = [createTarget(gl, w, h), createTarget(gl, w, h)];\n this.#frostedSize = `${w}x${h}`;\n }\n const [a, b] = this.#frosted!;\n gl.viewport(0, 0, w, h);\n this.#pass(this.#copy, this.#backdrop, a);\n for (let i = 0; i < FROST_PASSES; i++) {\n this.#pass(this.#blur, a.texture, b, [1 / w, 0]);\n this.#pass(this.#blur, b.texture, a, [0, 1 / h]);\n }\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n }\n\n draw(frame: GlassFrame): void {\n const gl = this.#gl;\n const { uniform } = this.#glass;\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n if (!this.#backdrop) return;\n\n gl.useProgram(this.#glass.program);\n gl.activeTexture(gl.TEXTURE1);\n gl.bindTexture(gl.TEXTURE_2D, this.#frosted![0].texture);\n gl.uniform1i(uniform('u_frosted'), 1);\n gl.activeTexture(gl.TEXTURE0);\n gl.bindTexture(gl.TEXTURE_2D, this.#backdrop);\n gl.uniform1i(uniform('u_backdrop'), 0);\n\n gl.uniform2f(uniform('u_size'), frame.width, frame.height);\n gl.uniform2f(uniform('u_offset'), frame.offsetX, frame.offsetY);\n gl.uniform2f(\n uniform('u_backdropSize'),\n this.#backdropWidth,\n this.#backdropHeight,\n );\n gl.uniform1f(uniform('u_scale'), frame.scale);\n gl.uniform1f(uniform('u_smoothing'), frame.smoothing);\n gl.uniform1f(uniform('u_dark'), frame.dark);\n gl.uniform1f(uniform('u_shadow'), frame.shadow);\n gl.uniform3f(uniform('u_pointer'), ...frame.pointer);\n\n const shapes = frame.shapes.slice(0, MAX_GLASS_SHAPES);\n const bounds = new Float32Array(MAX_GLASS_SHAPES * 4);\n const material = new Float32Array(MAX_GLASS_SHAPES * 4);\n const tint = new Float32Array(MAX_GLASS_SHAPES * 4);\n shapes.forEach((shape, i) => {\n bounds.set(\n [shape.centerX, shape.centerY, shape.halfWidth, shape.halfHeight],\n i * 4,\n );\n material.set([shape.radius, shape.frost, 0, 0], i * 4);\n tint.set(shape.tint, i * 4);\n });\n gl.uniform1i(uniform('u_count'), shapes.length);\n gl.uniform4fv(uniform('u_bounds'), bounds);\n gl.uniform4fv(uniform('u_material'), material);\n gl.uniform4fv(uniform('u_tint'), tint);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n }\n\n dispose(): void {\n const gl = this.#gl;\n this.#deleteFrosted();\n gl.deleteTexture(this.#backdrop);\n gl.deleteBuffer(this.#quad);\n for (const { program } of [this.#copy, this.#blur, this.#glass]) {\n gl.deleteProgram(program);\n }\n // Browsers cap live WebGL contexts (16 in Chrome); give this one back now\n // instead of waiting for garbage collection.\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n }\n\n #pass(\n program: Program,\n source: WebGLTexture,\n target: Target,\n direction?: readonly [number, number],\n ): void {\n const gl = this.#gl;\n gl.useProgram(program.program);\n gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer);\n gl.activeTexture(gl.TEXTURE0);\n gl.bindTexture(gl.TEXTURE_2D, source);\n gl.uniform1i(program.uniform('u_source'), 0);\n if (direction) gl.uniform2f(program.uniform('u_direction'), ...direction);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n }\n\n #deleteFrosted(): void {\n for (const target of this.#frosted ?? []) {\n this.#gl.deleteTexture(target.texture);\n this.#gl.deleteFramebuffer(target.framebuffer);\n }\n this.#frosted = null;\n }\n}\n","/** How far an interactive glass shape is pressed, and where. */\nexport type PressState = {\n /** 1 while a pointer is down on the shape, else 0. */\n target: number;\n /** Eased from 0 (at rest) to 1 (fully pressed). */\n value: number;\n /** The pointer, in viewport (client) coordinates. */\n x: number;\n y: number;\n};\n\nconst presses = new WeakMap<Element, PressState>();\n\n// Time constants of the ease, in milliseconds: iOS's glass swells quickly\n// under a finger and settles back more slowly.\nconst PRESS_IN_MS = 70;\nconst PRESS_OUT_MS = 180;\n\n/**\n * Follows pointer presses on a `<blur-view>`, for `glass-interactive`. The\n * listeners are passive and never stop propagation, so the element's own\n * Lynx touch and tap handlers still run. The attribute is checked when a press\n * starts, since it can be bound and change at any time.\n */\nexport const trackPress = (element: HTMLElement): void => {\n const state: PressState = { target: 0, value: 0, x: 0, y: 0 };\n presses.set(element, state);\n const follow = (event: PointerEvent) => {\n state.x = event.clientX;\n state.y = event.clientY;\n };\n const release = () => {\n state.target = 0;\n };\n const options = { passive: true };\n element.addEventListener(\n 'pointerdown',\n (event) => {\n if (!element.hasAttribute('glass-interactive')) return;\n state.target = 1;\n follow(event);\n },\n options,\n );\n element.addEventListener(\n 'pointermove',\n (event) => {\n if (state.target) follow(event);\n },\n options,\n );\n for (const type of ['pointerup', 'pointercancel', 'pointerleave']) {\n element.addEventListener(type, release, options);\n }\n};\n\nexport const pressOf = (element: Element): PressState | undefined =>\n presses.get(element);\n\n/**\n * Eases a press toward its target over `elapsed` milliseconds. Returns the\n * new value, snapping to the target once it's indistinguishable.\n */\nexport const stepPress = (state: PressState, elapsed: number): number => {\n const time = state.target ? PRESS_IN_MS : PRESS_OUT_MS;\n const next =\n state.target + (state.value - state.target) * Math.exp(-elapsed / time);\n state.value = Math.abs(next - state.target) < 0.001 ? state.target : next;\n return state.value;\n};\n","import { resolveCssColor } from './css-color';\nimport { pressOf, stepPress } from './glass-press';\nimport type { GlassShapeFrame } from './glass-renderer';\n\n/**\n * What a `<blur-view>` is to the glass code:\n * - `container`: a `glass-container`, which draws its glass children as one\n * group so nearby shapes merge.\n * - `standalone`: a `glass` element outside any container, its own group.\n * - `member`: a `glass` element its parent container draws.\n */\nexport type GlassRole = 'container' | 'standalone' | 'member';\n\nexport const glassRole = (element: Element): GlassRole | null => {\n const effect = element.getAttribute('blur-effect');\n if (effect === 'glass-container') return 'container';\n if (effect !== 'glass') return null;\n const parent = element.parentElement?.getAttribute('blur-effect');\n return parent === 'glass-container' ? 'member' : 'standalone';\n};\n\n/**\n * The shapes a container groups. iOS only merges the glass views placed\n * directly in the container, so only direct children count here too.\n */\nexport const containerShapes = (container: Element): HTMLElement[] =>\n Array.from(container.children).filter(\n (child): child is HTMLElement =>\n child.getAttribute('blur-effect') === 'glass',\n );\n\n/**\n * A corner radius as the shader needs it: one value in pixels, no larger than\n * half the shorter side. Computed styles give pixels or a percentage, and\n * `rounded-full` (9999px) clamps to a circle or a pill.\n */\nexport const cornerRadius = (\n value: string,\n width: number,\n height: number,\n): number => {\n const shorter = Math.min(width, height);\n const radius = value.endsWith('%')\n ? (parseFloat(value) / 100) * shorter\n : parseFloat(value) || 0;\n return Math.min(radius, shorter / 2);\n};\n\n// How much an interactive shape swells while pressed, as on iOS.\nconst PRESS_GROWTH = 0.06;\n\n/**\n * Reads one shape for a frame, relative to the group canvas at `origin`.\n * Advances its press animation by `elapsed` milliseconds; only containers let\n * a pressed shape `grow`, since a standalone shape's canvas is its own box\n * and Lynx clips anything drawn outside it.\n *\n * The shape's box and `origin` are in screen pixels, drawn at `zoom` screen\n * pixels per CSS pixel (see drawn-scale.ts); the frame is in CSS pixels, like\n * its corner radius.\n */\nexport const readShape = (\n element: HTMLElement,\n origin: DOMRect,\n zoom: number,\n elapsed: number,\n grow: boolean,\n): GlassShapeFrame & { press: number } => {\n const box = element.getBoundingClientRect();\n const left = (box.left - origin.left) / zoom;\n const top = (box.top - origin.top) / zoom;\n const width = box.width / zoom;\n const height = box.height / zoom;\n const style = element.ownerDocument.defaultView!.getComputedStyle(element);\n const press = pressOf(element);\n const pressed = press ? stepPress(press, elapsed) : 0;\n const swell = grow ? 1 + PRESS_GROWTH * pressed : 1;\n return {\n centerX: left + width / 2,\n centerY: top + height / 2,\n halfWidth: (width / 2) * swell,\n halfHeight: (height / 2) * swell,\n radius: cornerRadius(style.borderTopLeftRadius, width, height) * swell,\n frost: element.getAttribute('glass-style') === 'clear' ? 0 : 1,\n tint: resolveCssColor(\n element.ownerDocument,\n element.getAttribute('glass-tint-color'),\n ),\n press: pressed,\n };\n};\n","import { observeBackdrop } from './backdrop-observer';\nimport { snapshotBackdrop, type BackdropSnapshot } from './backdrop-snapshot';\nimport { drawnScale } from './drawn-scale';\nimport { GlassRenderer, type GlassFrame } from './glass-renderer';\nimport { pressOf } from './glass-press';\nimport { containerShapes, readShape } from './glass-shapes';\n\n// The lens samples up to about half a shape's radius past its edge, so the\n// captured region reaches this far beyond the group.\nconst CAPTURE_MARGIN = 48;\n// Captures run on the main thread, so they're spaced out: at least this many\n// milliseconds apart, and four times as long as the last one took.\nconst MIN_CAPTURE_INTERVAL = 100;\n// Sharper than 2x costs memory and capture time for no visible gain.\nconst MAX_SCALE = 2;\n// Backdrops darker than this get the dark material, like iOS in dark mode.\nconst DARK_LUMINANCE = 0.4;\n\n/**\n * Draws one group of Liquid Glass on Lynx for Web: a `glass-container` and the\n * glass shapes directly inside it, or a lone `glass` element.\n *\n * A canvas in the root's shadow root, stacked under its children, draws every\n * shape refracting an image of the backdrop: the root's parent, captured up to\n * the root. The image is captured again when anything in the backdrop (other\n * than the glass itself) changes, resizes or scrolls.\n */\nexport class GlassGroup {\n readonly root: HTMLElement;\n readonly container: boolean;\n readonly #win: Window;\n readonly #canvas: HTMLCanvasElement;\n readonly #renderer: GlassRenderer | null;\n readonly #backdrop: HTMLElement | null;\n #stopObserving: (() => void) | null = null;\n #snapshot: BackdropSnapshot | null = null;\n #stale = true;\n #capturing = false;\n #failed = false;\n #disposed = false;\n #nextCapture = 0;\n #drawn = '';\n\n constructor(root: HTMLElement, container: boolean) {\n this.root = root;\n this.container = container;\n const doc = root.ownerDocument;\n this.#win = doc.defaultView!;\n this.#canvas = doc.createElement('canvas');\n this.#canvas.setAttribute('aria-hidden', 'true');\n // Fades in over the frosted fallback once the first frame is drawn.\n this.#canvas.style.cssText =\n 'position:absolute;left:0;top:0;width:100%;height:100%;' +\n 'pointer-events:none;z-index:-1;opacity:0;transition:opacity 0.2s';\n const shadow = root.shadowRoot;\n shadow?.insertBefore(this.#canvas, shadow.querySelector('slot'));\n this.#renderer = shadow ? GlassRenderer.create(this.#canvas) : null;\n this.#backdrop = root.parentElement;\n if (this.#renderer && this.#backdrop) {\n this.#stopObserving = observeBackdrop(this.#backdrop, root, () => {\n this.#stale = true;\n });\n }\n }\n\n /**\n * The glass elements this group draws.\n */\n get shapes(): HTMLElement[] {\n return this.container ? containerShapes(this.root) : [this.root];\n }\n\n /**\n * True once WebGL has drawn the glass, so the CSS fallback can go.\n */\n get active(): boolean {\n return this.#drawn !== '' && !this.#failed;\n }\n\n /**\n * True when the GPU dropped the context; the group must be rebuilt.\n */\n get lost(): boolean {\n return this.#renderer?.lost ?? false;\n }\n\n /**\n * Draws a frame if anything changed; `elapsed` is in milliseconds.\n */\n frame(elapsed: number): void {\n const renderer = this.#renderer;\n const backdrop = this.#backdrop;\n if (!renderer || !backdrop || this.#failed) return;\n // Boxes are measured in screen pixels, and the frame is drawn in CSS\n // pixels, which differ when the page is drawn scaled (see drawn-scale.ts).\n const origin = this.#canvas.getBoundingClientRect();\n const area = backdrop.getBoundingClientRect();\n const zoom = drawnScale(backdrop);\n if (this.#needsCapture(origin, area, zoom)) {\n this.#capture(backdrop, origin, zoom);\n }\n const snapshot = this.#snapshot;\n if (!snapshot) return;\n\n // Device pixels per CSS pixel, so the canvas stays sharp at any zoom.\n const scale = Math.min(this.#win.devicePixelRatio || 1, MAX_SCALE) * zoom;\n const elements = this.shapes;\n const shapes = elements.map((element) =>\n readShape(element, origin, zoom, elapsed, this.container),\n );\n // The press glow follows whichever shape is pressed the most.\n let pointer: [number, number, number] = [0, 0, 0];\n elements.forEach((element, i) => {\n const value = shapes[i]!.press;\n if (value > pointer[2]) {\n const { x, y } = pressOf(element)!;\n pointer = [(x - origin.left) / zoom, (y - origin.top) / zoom, value];\n }\n });\n const spacing = parseFloat(this.root.getAttribute('spacing') ?? '') || 0;\n const frame: GlassFrame = {\n scale,\n width: origin.width / zoom,\n height: origin.height / zoom,\n offsetX: (origin.left - area.left) / zoom - snapshot.x,\n offsetY: (origin.top - area.top) / zoom - snapshot.y,\n // Twice the spacing: the smooth union only bridges a gap up to half its\n // radius, and iOS merges shapes closer than `spacing`.\n smoothing: this.container ? spacing * 2 : 0,\n dark: this.#dark(snapshot),\n // Outside its shapes a container's canvas is empty space for a shadow;\n // a lone shape's canvas is its own box, where it would darken the corners.\n shadow: this.container ? 1 : 0,\n shapes,\n pointer,\n };\n const key = JSON.stringify(frame);\n if (key === this.#drawn) return;\n const width = Math.max(1, Math.round(frame.width * scale));\n const height = Math.max(1, Math.round(frame.height * scale));\n // Assigning a canvas size reallocates it even when the size is unchanged.\n if (this.#canvas.width !== width) this.#canvas.width = width;\n if (this.#canvas.height !== height) this.#canvas.height = height;\n renderer.draw(frame);\n this.#drawn = key;\n this.#canvas.style.opacity = '1';\n }\n\n dispose(): void {\n this.#disposed = true;\n this.#stopObserving?.();\n this.#renderer?.dispose();\n this.#canvas.remove();\n }\n\n #dark(snapshot: BackdropSnapshot): number {\n const forced = this.root.getAttribute('ios-user-interface-style');\n if (forced) return forced === 'dark' ? 1 : 0;\n return snapshot.luminance < DARK_LUMINANCE ? 1 : 0;\n }\n\n #needsCapture(origin: DOMRect, area: DOMRect, zoom: number): boolean {\n if (this.#capturing) return false;\n const snapshot = this.#snapshot;\n if (snapshot) {\n // Moving the whole group (not just its shapes) past the captured region\n // would refract the image's clamped edge, so capture around it again.\n const left = (Math.max(origin.left, area.left) - area.left) / zoom;\n const top = (Math.max(origin.top, area.top) - area.top) / zoom;\n const right = (Math.min(origin.right, area.right) - area.left) / zoom;\n const bottom = (Math.min(origin.bottom, area.bottom) - area.top) / zoom;\n if (\n left < snapshot.x - 1 ||\n top < snapshot.y - 1 ||\n right > snapshot.x + snapshot.width + 1 ||\n bottom > snapshot.y + snapshot.height + 1\n ) {\n this.#stale = true;\n }\n }\n return this.#stale && this.#win.performance.now() >= this.#nextCapture;\n }\n\n #capture(backdrop: HTMLElement, origin: DOMRect, zoom: number): void {\n const win = this.#win;\n this.#capturing = true;\n this.#stale = false;\n const started = win.performance.now();\n // The glass and everything after it paints on top of the glass, not\n // behind it.\n const above = new Set<Element>();\n for (\n let node: Element | null = this.root;\n node;\n node = node.nextElementSibling\n ) {\n above.add(node);\n }\n // The region is in screen pixels, and the margin in CSS pixels.\n const margin = CAPTURE_MARGIN * zoom;\n snapshotBackdrop(backdrop, {\n exclude: (element) => above.has(element),\n region: {\n left: origin.left - margin,\n top: origin.top - margin,\n right: origin.right + margin,\n bottom: origin.bottom + margin,\n },\n scale: Math.min(win.devicePixelRatio || 1, MAX_SCALE) * zoom,\n })\n .then((snapshot) => {\n if (this.#disposed || !snapshot) return;\n this.#renderer!.setBackdrop(\n snapshot.image,\n snapshot.width,\n snapshot.height,\n );\n this.#snapshot = snapshot;\n this.#drawn = '';\n })\n .catch(() => {\n // The image wouldn't decode, or it tainted the canvas (Safari can\n // treat any <foreignObject> as cross-origin): keep the CSS fallback.\n this.#failed = true;\n })\n .finally(() => {\n this.#capturing = false;\n const now = win.performance.now();\n this.#nextCapture =\n now + Math.max(MIN_CAPTURE_INTERVAL, (now - started) * 4);\n });\n }\n}\n","/** How a `<blur-view>` on web is styled while the glass code looks after it. */\nexport type HostStyleState = {\n /** It's a glass shape that WebGL isn't drawing (yet): show frosted CSS. */\n fallback: boolean;\n /** WebGL draws this shape, so web-elements' own backdrop blur must go. */\n rendered: boolean;\n /** It holds a group's canvas, which must stack under its children. */\n hostsCanvas: boolean;\n};\n\nconst styles = new WeakMap<Element, HTMLStyleElement>();\n\nconst DEFAULT_FALLBACK_BLUR = 12;\n\n/**\n * The frosted look a glass shape has before WebGL takes over, or without it:\n * a backdrop blur with a bright inner rim, roughly the pre-iOS-26 material.\n * Author styles on the element itself still win, since a `:host` rule loses to\n * them, so a background set in the template is kept.\n */\nexport const fallbackGlassCss = (element: Element): string => {\n const clear = element.getAttribute('glass-style') === 'clear';\n const radius =\n parseFloat(element.getAttribute('blur-radius') ?? '') ||\n (clear ? DEFAULT_FALLBACK_BLUR / 3 : DEFAULT_FALLBACK_BLUR);\n const filter = `blur(${radius}px) saturate(${clear ? 140 : 180}%)`;\n const background =\n element.getAttribute('glass-tint-color') ||\n `rgba(255, 255, 255, ${clear ? 0.04 : 0.18})`;\n return (\n `:host{backdrop-filter:${filter};-webkit-backdrop-filter:${filter};` +\n `background-color:${background};box-shadow:inset 0 1px 0 ` +\n `rgba(255, 255, 255, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.25)}`\n );\n};\n\n/**\n * The UIKit blur material a non-glass `<blur-view>` gets on iOS, which\n * `blur-effect` picks (`light` by default). Besides blurring, each material\n * shifts what's behind it, while web-elements' `<x-blur-view>` only blurs. So\n * these approximate them, fitted to the iOS simulator's pixels in the\n * element-blur-view example: `light` brightens the backdrop by about a third,\n * `extra-light` washes it with white, and `dark` with black. Like on iOS, a\n * blur view with no blur radius shows no material. The `light` rule repeats\n * the blur because it replaces web-elements' own `backdrop-filter`.\n */\nexport const materialCss = (element: Element): string => {\n const effect = element.getAttribute('blur-effect') ?? 'light';\n const radius = parseFloat(element.getAttribute('blur-radius') ?? '');\n if (!radius || effect === 'glass' || effect === 'glass-container') {\n return '';\n }\n if (effect === 'extra-light') {\n return ':host{background-color:rgba(255, 255, 255, 0.75)}';\n }\n if (effect === 'dark') {\n return ':host{background-color:rgba(0, 0, 0, 0.6)}';\n }\n const filter = `blur(${radius}px) brightness(1.35)`;\n return `:host{backdrop-filter:${filter};-webkit-backdrop-filter:${filter}}`;\n};\n\nexport const hostStyleCss = (element: Element, state: HostStyleState): string =>\n [\n materialCss(element),\n state.hostsCanvas ? ':host{isolation:isolate}' : '',\n state.rendered\n ? ':host{backdrop-filter:none!important;-webkit-backdrop-filter:none!important}'\n : '',\n state.fallback ? fallbackGlassCss(element) : '',\n ].join('');\n\n/**\n * Applies `state` through a `<style>` in the element's shadow root, written\n * only when it changes. The rules stay inside the element: Lynx owns its\n * `class` and `style` attributes, and an attribute of our own would show up in\n * the backdrop's mutation observer as a change to capture.\n */\nexport const applyHostStyle = (\n element: HTMLElement,\n state: HostStyleState,\n): void => {\n const root = element.shadowRoot;\n if (!root) return;\n const css = hostStyleCss(element, state);\n let style = styles.get(element);\n if (!style) {\n if (!css) return;\n style = element.ownerDocument.createElement('style');\n styles.set(element, style);\n }\n // Appended (again) last, so it follows web-elements' own dynamic style.\n if (style.parentNode !== root) root.appendChild(style);\n if (style.textContent !== css) style.textContent = css;\n};\n","import { GlassGroup } from './glass-group';\nimport { applyHostStyle } from './glass-host-style';\nimport { trackPress } from './glass-press';\nimport { glassRole } from './glass-shapes';\n\n// The attributes that change what a `<blur-view>` looks like as glass.\nconst GLASS_ATTRIBUTES = [\n 'blur-effect',\n 'blur-radius',\n 'glass-style',\n 'glass-tint-color',\n 'glass-interactive',\n 'spacing',\n 'ios-user-interface-style',\n];\n\n// How often removed `<blur-view>`s are checked for being put back.\nconst DETACHED_POLL_MS = 1000;\n// Caps a frame's elapsed time, so a tab returning from the background doesn't\n// jump its press animations.\nconst MAX_ELAPSED_MS = 100;\n\n// The page's window, as `Document.defaultView` types it: with constructors\n// such as IntersectionObserver, which `Window` alone doesn't declare.\ntype PageWindow = Window & typeof globalThis;\n\nconst managers = new WeakMap<PageWindow, GlassManager>();\n\n/**\n * Looks after every `<blur-view>` of one page on Lynx for Web. It tracks which\n * are on screen, builds a `GlassGroup` for each visible container or lone\n * glass element, and runs their frames while any is visible. Each element's\n * shadow-root style follows: frosted CSS until WebGL draws it, then none.\n */\nexport class GlassManager {\n readonly #win: PageWindow;\n readonly #visible = new Set<HTMLElement>();\n readonly #groups = new Map<HTMLElement, GlassGroup>();\n readonly #detached = new Set<WeakRef<HTMLElement>>();\n readonly #intersection: IntersectionObserver;\n readonly #attributes: MutationObserver;\n #frame = 0;\n #poll = 0;\n #last = 0;\n\n /**\n * Use `GlassManager.for`, which keeps one manager per page.\n */\n constructor(win: PageWindow) {\n this.#win = win;\n this.#intersection = new win.IntersectionObserver((entries) =>\n this.#onIntersection(entries),\n );\n this.#attributes = new win.MutationObserver(() => this.#wake());\n }\n\n static for(win: PageWindow): GlassManager {\n let manager = managers.get(win);\n if (!manager) {\n manager = new GlassManager(win);\n managers.set(win, manager);\n }\n return manager;\n }\n\n register(element: HTMLElement): void {\n this.#intersection.observe(element);\n this.#attributes.observe(element, {\n attributes: true,\n attributeFilter: GLASS_ATTRIBUTES,\n });\n trackPress(element);\n }\n\n #onIntersection(entries: IntersectionObserverEntry[]): void {\n for (const { target, isIntersecting } of entries) {\n const element = target as HTMLElement;\n if (isIntersecting) {\n this.#visible.add(element);\n continue;\n }\n this.#visible.delete(element);\n // Observing a removed element would keep it alive after Lynx drops it.\n // Hold it weakly instead, in case it's put back (a detached view).\n if (!element.isConnected) {\n this.#intersection.unobserve(element);\n this.#detached.add(new WeakRef(element));\n if (!this.#poll) {\n this.#poll = this.#win.setInterval(\n () => this.#checkDetached(),\n DETACHED_POLL_MS,\n );\n }\n }\n }\n this.#wake();\n }\n\n #checkDetached(): void {\n for (const ref of this.#detached) {\n const element = ref.deref();\n // Still removed, and not yet garbage collected: keep checking.\n if (element && !element.isConnected) continue;\n if (element) this.#intersection.observe(element);\n this.#detached.delete(ref);\n }\n if (!this.#detached.size) {\n this.#win.clearInterval(this.#poll);\n this.#poll = 0;\n }\n }\n\n #wake(): void {\n if (this.#frame) return;\n this.#frame = this.#win.requestAnimationFrame((now) => this.#tick(now));\n }\n\n #tick(now: number): void {\n this.#frame = 0;\n const elapsed = this.#last ? Math.min(now - this.#last, MAX_ELAPSED_MS) : 0;\n this.#last = now;\n\n const roots = new Map<HTMLElement, boolean>();\n for (const element of this.#visible) {\n const role = glassRole(element);\n if (role === 'container' || role === 'standalone') {\n roots.set(element, role === 'container');\n }\n }\n for (const [root, group] of this.#groups) {\n if (roots.get(root) !== group.container || group.lost) {\n group.dispose();\n this.#groups.delete(root);\n }\n }\n for (const [root, container] of roots) {\n if (!this.#groups.has(root)) {\n this.#groups.set(root, new GlassGroup(root, container));\n }\n }\n\n const styled = new Set(this.#visible);\n const rendered = new Set<HTMLElement>();\n for (const group of this.#groups.values()) {\n group.frame(elapsed);\n for (const shape of group.shapes) {\n styled.add(shape);\n if (group.active) rendered.add(shape);\n }\n }\n for (const element of styled) {\n applyHostStyle(element, {\n hostsCanvas: this.#groups.get(element)?.active ?? false,\n rendered: rendered.has(element),\n fallback:\n element.getAttribute('blur-effect') === 'glass' &&\n !rendered.has(element),\n });\n }\n\n // Keep drawing while glass is on screen: shapes can move every frame\n // (dragged, animated) without any event this code would hear about.\n if (this.#groups.size) this.#wake();\n else this.#last = 0;\n }\n}\n","import type { ElementRef } from '../types/lynx';\nimport { applyBlurViewLayout } from './blur-view-layout';\nimport { GlassManager } from './glass-manager';\n\n/**\n * Gives a `<blur-view>` on Lynx for Web what web-elements' `<x-blur-view>`\n * lacks: a view's layout (see blur-view-layout.ts), and Liquid Glass.\n *\n * On iOS 26, `blur-effect=\"glass\"` and `\"glass-container\"` render UIKit's\n * glass. Lynx for Web turns `<blur-view>` into an `<x-blur-view>` custom\n * element that only implements `blur-radius`, so glass elements would show at\n * most a frosted blur, and merging and refraction not at all. This draws them\n * with WebGL instead (see glass-group.ts), from the same attributes.\n *\n * Called for every `<blur-view>` the main thread creates. On web that thread\n * runs in an iframe while its elements live in the page, so everything here\n * goes through the element's own window, never this realm's globals.\n */\nexport const attachWebGlass = (element: ElementRef): void => {\n const node = element as Partial<HTMLElement>;\n const win = node.ownerDocument?.defaultView;\n if (!win) return;\n // Every blur view needs it, glass or not, and before its first paint, which\n // this microtask after creation still is.\n applyBlurViewLayout(node as HTMLElement);\n // Only a real element in a browser can host the glass.\n if (!win.IntersectionObserver) return;\n try {\n GlassManager.for(win).register(node as HTMLElement);\n } catch {\n // Glass is decoration: never let it break rendering.\n }\n};\n"],"mappings":"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"}
|