@blotch/angular-lynx 22.2.2 → 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.
@@ -1,11 +1,13 @@
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";
3
- import { Animation, AnimationEvent, AnimationOptions, Element, KeyEvent, LayoutChangeEvent, MouseEvent, TouchEvent, TransitionEvent, UIAppearanceEvent, WheelEvent } from "@lynx-js/types/main-thread";
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
+ 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";
6
- import { PlatformType, ResourcePrefetchData, ResourcePrefetchResult, TextInfo, TextMetrics, TouchEvent as TouchEvent$1 } from "@lynx-js/types";
6
+ import { BaseAnimationEvent, BaseKeyEvent, BaseMouseEvent, BaseTouchEvent, BaseTransitionEvent, BaseWheelEvent, LayoutChangeDetailEvent, UIAppearanceDetailEvent } from "@lynx-js/types/events";
7
+ import { MouseEvent, PlatformType, ResourcePrefetchData, ResourcePrefetchResult, TextInfo, TextMetrics, TouchEvent } from "@lynx-js/types";
7
8
  import { LocationChangeListener, LocationStrategy, PlatformLocation } from "@angular/common";
8
9
  import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy, RouterFeatures, Routes } from "@angular/router";
10
+ import { Subject } from "rxjs";
9
11
  /**
10
12
  * Programmatic accessibility control for screen readers on Lynx.
11
13
  *
@@ -32,7 +34,9 @@ export declare class LynxAccessibility {
32
34
  * operation results that aren't reflected by focus movement alone
33
35
  * (e.g. toast messages, background task completion, live counters).
34
36
  *
35
- * Wraps `lynx.accessibilityAnnounce()`.
37
+ * Wraps `lynx.accessibilityAnnounce()`. Only the background thread's `lynx`
38
+ * has it, and event handlers run on the main thread, so the call goes
39
+ * through the background thread (see background-call.ts).
36
40
  */
37
41
  announce(content: string): Promise<void>;
38
42
  /**
@@ -43,11 +47,69 @@ export declare class LynxAccessibility {
43
47
  * Only ID selectors are reliably supported (e.g. `'#myElement'`).
44
48
  *
45
49
  * Wraps `lynx.createSelectorQuery().select(selector).invoke({ method: 'requestAccessibilityFocus' }).exec()`.
50
+ * The main thread's `lynx` has no createSelectorQuery, but it's where event
51
+ * handlers run and where the native elements live, so there the element is
52
+ * found and called directly.
46
53
  */
47
54
  requestFocus(selector: string): Promise<void>;
48
55
  static ɵfac: i0.ɵɵFactoryDeclaration<LynxAccessibility, never>;
49
56
  static ɵprov: i0.ɵɵInjectableDeclaration<any>;
50
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
+ }
51
113
  /**
52
114
  * Phantom brand symbol — makes each ElementRef variant nominally distinct at
53
115
  * the type level even though Lynx PAPI handles have no runtime structure.
@@ -247,19 +309,17 @@ type LynxAnimationOptions = AnimationOptions & {
247
309
  timingFunction?: string;
248
310
  };
249
311
  /**
250
- * Shared interface for all animation implementations (real and no-op).
251
- * Used by `BaseLynxElement.animate()` return type so both `LynxAnimation`
252
- * (main thread) and `NoopLynxAnimation` (background thread) are valid.
253
- * Required because LynxAnimation uses ES private fields (#element, #count)
254
- * which brand the class — TypeScript's structural typing won't accept
255
- * NoopLynxAnimation as assignable to LynxAnimation. This shared Pick type
256
- * extracts only the public API both implementations satisfy.
312
+ * The public API of an animation, which `BaseLynxElement.animate()` returns.
313
+ * LynxAnimation uses ES private fields (#element, #count), which brand the
314
+ * class, so a structural type lets other implementations, such as a test
315
+ * double, satisfy it.
257
316
  */
258
317
  type BaseLynxAnimation = Pick<Animation, 'id' | 'cancel' | 'pause' | 'play'>;
259
318
  /**
260
319
  * Represents a running animation on a Lynx element.
261
320
  * Created by calling `element.animate()` on a LynxElement.
262
- * Mirrors the Animation class from React Lynx's worklet-runtime.
321
+ * Mirrors the Animation class from React Lynx's worklet-runtime, except for
322
+ * the key a named animation is controlled by (see the constructor).
263
323
  */
264
324
  export declare class LynxAnimation implements Pick<Animation, 'id' | 'cancel' | 'pause' | 'play'> {
265
325
  #private;
@@ -269,21 +329,49 @@ export declare class LynxAnimation implements Pick<Animation, 'id' | 'cancel' |
269
329
  pause(): void;
270
330
  cancel(): void;
271
331
  }
332
+ /**
333
+ * Profiling counters collected by the renderer during a session.
334
+ * Only populated in development builds, where `__PROFILE__` is true — in
335
+ * production, instrumentation is dead-code-eliminated and all values stay 0.
336
+ */
337
+ type DevToolsStats = {
338
+ cdCycles: number;
339
+ elementCreated: number;
340
+ elementRemoved: number;
341
+ flushCount: number;
342
+ lastCdDurationMs: number;
343
+ };
344
+ /**
345
+ * Options for `LynxPerformance.profileStart()` and `profileMark()`. The same
346
+ * shape as Lynx's own `TraceOption`; `performance.ts` passes it to Lynx as
347
+ * one, so the compiler keeps the two in step.
348
+ */
349
+ type LynxTraceOptions = {
350
+ flowId?: number;
351
+ flowIds?: number[];
352
+ args?: Record<string, string>;
353
+ };
272
354
  /**
273
355
  * Wraps Lynx's native performance tracing APIs (`lynx.performance`).
274
356
  *
275
357
  * All methods are no-ops when `lynx.performance` is unavailable (e.g. in tests
276
358
  * or non-Lynx environments) or when profiling is not actively recording.
277
359
  *
360
+ * Unlike the `LynxDevTools` counters, the calls aren't gated by `__PROFILE__`,
361
+ * so they stay in production builds. A trace is worth recording from the build
362
+ * you ship, without development mode's extra work in it. They cost little
363
+ * there: release builds of the Lynx engine compile tracing out, so each call
364
+ * returns at once.
365
+ *
278
366
  * @usageNotes
279
367
  * ```typescript
280
368
  * const perf = inject(LynxPerformance);
281
369
  *
282
- * perf.profileStart('MyComponent::render', { itemCount: 42 });
370
+ * perf.profileStart('MyComponent::render', { args: { itemCount: '42' } });
283
371
  * // ... do work ...
284
372
  * perf.profileEnd();
285
373
  *
286
- * perf.profileMark('dataLoaded', { source: 'cache' });
374
+ * perf.profileMark('dataLoaded', { args: { source: 'cache' } });
287
375
  * ```
288
376
  */
289
377
  export declare class LynxPerformance {
@@ -297,10 +385,7 @@ export declare class LynxPerformance {
297
385
  * Begin a named trace. Must be paired with `profileEnd()`.
298
386
  * Traces nest — multiple `profileStart` calls create a stack.
299
387
  */
300
- profileStart(name: string, options?: {
301
- flowId?: number;
302
- args?: Record<string, unknown>;
303
- }): void;
388
+ profileStart(name: string, options?: LynxTraceOptions): void;
304
389
  /**
305
390
  * End the current trace (top of the trace stack).
306
391
  */
@@ -308,9 +393,7 @@ export declare class LynxPerformance {
308
393
  /**
309
394
  * Emit a discrete mark event in the trace timeline.
310
395
  */
311
- profileMark(name: string, options?: {
312
- args?: Record<string, unknown>;
313
- }): void;
396
+ profileMark(name: string, options?: LynxTraceOptions): void;
314
397
  /**
315
398
  * Generate a unique flow ID for correlating multi-threaded traces.
316
399
  */
@@ -318,24 +401,13 @@ export declare class LynxPerformance {
318
401
  static ɵfac: i0.ɵɵFactoryDeclaration<LynxPerformance, never>;
319
402
  static ɵprov: i0.ɵɵInjectableDeclaration<any>;
320
403
  }
321
- /**
322
- * Profiling counters collected by the renderer during a session.
323
- * Only populated when the app is built with `__PROFILE__` enabled —
324
- * in production, instrumentation is dead-code-eliminated and all values stay 0.
325
- */
326
- type DevToolsStats = {
327
- cdCycles: number;
328
- elementCreated: number;
329
- elementRemoved: number;
330
- flushCount: number;
331
- lastCdDurationMs: number;
332
- };
333
404
  /**
334
405
  * High-level DevTools service exposing performance stats as Angular signals.
335
406
  *
336
- * Stats are only meaningful when the app is built with `__PROFILE__` enabled.
337
- * In production builds, counters are never incremented (the instrumentation
338
- * code is dead-code-eliminated), so all values remain zero.
407
+ * Stats are only meaningful in development builds, where the build plugin sets
408
+ * `__PROFILE__` to true. In production builds, counters are never incremented
409
+ * (the instrumentation code is dead-code-eliminated), so all values remain
410
+ * zero.
339
411
  *
340
412
  * @usageNotes
341
413
  * ```typescript
@@ -382,10 +454,24 @@ export declare class LynxDevTools {
382
454
  declare const devStats: DevToolsStats & {
383
455
  reset(): void;
384
456
  };
457
+ /**
458
+ * Starts timing a change-detection cycle. The renderer factory calls it from
459
+ * `begin()`, and `endCdTiming()` from `end()`.
460
+ */
461
+ declare const startCdTiming: () => void;
462
+ /**
463
+ * Stops timing the innermost change-detection cycle in progress, and records
464
+ * its duration in `devStats.lastCdDurationMs`.
465
+ */
466
+ declare const endCdTiming: () => void;
385
467
  /**
386
468
  * Extend this interface to type the raw data passed from native before processing.
387
469
  *
388
470
  * @example
471
+ * // This export makes the file a module, so the block below adds to
472
+ * // @blotch/angular-lynx's types instead of replacing them.
473
+ * export {};
474
+ *
389
475
  * declare module '@blotch/angular-lynx' {
390
476
  * interface InitDataRaw { userId: string; }
391
477
  * }
@@ -395,6 +481,10 @@ interface InitDataRaw extends Record<string, unknown> {}
395
481
  * Extend this interface to type the processed init data used throughout the app.
396
482
  *
397
483
  * @example
484
+ * // This export makes the file a module, so the block below adds to
485
+ * // @blotch/angular-lynx's types instead of replacing them.
486
+ * export {};
487
+ *
398
488
  * declare module '@blotch/angular-lynx' {
399
489
  * interface InitData { userId: string; }
400
490
  * }
@@ -404,6 +494,10 @@ interface InitData extends Record<string, unknown> {}
404
494
  * Extend this interface to type the global data passed from the native host.
405
495
  *
406
496
  * @example
497
+ * // This export makes the file a module, so the block below adds to
498
+ * // @blotch/angular-lynx's types instead of replacing them.
499
+ * export {};
500
+ *
407
501
  * declare module '@blotch/angular-lynx' {
408
502
  * interface GlobalData { theme: 'light' | 'dark'; }
409
503
  * }
@@ -423,8 +517,9 @@ type DataProcessorDefinition = {
423
517
  * Register data processor functions that the native Lynx runtime calls before
424
518
  * delivering init data to the app. Maps to the global `processData` callback.
425
519
  *
426
- * Call this before bootstrapApplication so that native data is transformed
427
- * before LynxInitData receives the first onDataChanged event.
520
+ * Call this before bootstrapApplication. The engine runs the default processor
521
+ * on the InitData before passing it to renderPage, so its result is what
522
+ * LynxInitData starts with.
428
523
  *
429
524
  * @example
430
525
  * registerDataProcessors({
@@ -487,7 +582,11 @@ type ExposureEventDetail = {
487
582
  'exposure-scene': string;
488
583
  exposureID: string;
489
584
  exposureScene: string;
490
- 'unique-id': number;
585
+ /**
586
+ * Identifies the native element. Lynx documents it as a string, which iOS
587
+ * and Android send; the web sends the element's numeric unique ID.
588
+ */
589
+ 'unique-id': string | number;
491
590
  };
492
591
  /**
493
592
  * The Lynx engine batches element visibility changes at ~20fps and dispatches
@@ -499,6 +598,7 @@ type ObserverFrameRateOptions = {
499
598
  forExposureCheck?: number;
500
599
  };
501
600
  export declare class LynxGlobalExposure {
601
+ #private;
502
602
  readonly exposures: import("@angular/core").WritableSignal<GlobalExposureEvent>;
503
603
  readonly disexposures: import("@angular/core").WritableSignal<GlobalExposureEvent>;
504
604
  readonly active: import("@angular/core").WritableSignal<boolean>;
@@ -512,7 +612,13 @@ export declare class LynxGlobalExposure {
512
612
  sendEvent: boolean;
513
613
  }): void;
514
614
  resumeExposure(): void;
515
- setObserverFrameRate(options?: ObserverFrameRateOptions): void;
615
+ /**
616
+ * Sets how often Lynx checks for exposure. Only the background thread's
617
+ * `lynx` has setObserverFrameRate, so a call from an event handler, which
618
+ * runs on the main thread, goes through the background thread (see
619
+ * background-call.ts). Resolves once it's applied.
620
+ */
621
+ setObserverFrameRate(options?: ObserverFrameRateOptions): Promise<void>;
516
622
  static ɵfac: i0.ɵɵFactoryDeclaration<LynxGlobalExposure, never>;
517
623
  static ɵprov: i0.ɵɵInjectableDeclaration<any>;
518
624
  }
@@ -535,6 +641,9 @@ type LynxFontEntry = {
535
641
  };
536
642
  /**
537
643
  * Wraps `lynx.addFont()` with a Promise-based API and reactive signal state.
644
+ * Only the background thread's `lynx` has addFont, so a call from an event
645
+ * handler, which runs on the main thread, goes through the background thread
646
+ * (see background-call.ts).
538
647
  *
539
648
  * Use CSS `@font-face` in stylesheets for fonts known at build time (the
540
649
  * standard Angular approach). Use this service only for fonts that must be
@@ -569,6 +678,55 @@ export declare class LynxFont {
569
678
  * built with `experimental_isLazyBundle: true` in the rsbuild plugin.
570
679
  */
571
680
  export declare const loadLazyBundle: (source: string) => Promise<Type<unknown>>;
681
+ /**
682
+ * The parts of webpack's `module.hot` API that {@link ɵhmrAccept} uses.
683
+ */
684
+ type HotModule = {
685
+ accept(): void;
686
+ dispose(callback: (data: Record<string, unknown>) => void): void;
687
+ invalidate(): void;
688
+ /** What the module's previous version passed to its dispose handlers. */
689
+ data?: Record<string, unknown>;
690
+ };
691
+ /**
692
+ * Takes a hot update of a module that defines components. The build plugin
693
+ * adds a call to the end of each such module in a development build, which
694
+ * reassigns the module's component classes to what it returns.
695
+ *
696
+ * On the main thread, where the app runs, a new version of the module either
697
+ * updates the running app in place or passes the update on:
698
+ *
699
+ * - **Only a template or stylesheet changed** (the source `signature`, which
700
+ * leaves those out, is the same, and the compiled `code` isn't): each
701
+ * component's new definition replaces the old one with Angular's
702
+ * `ɵɵreplaceMetadata()`, which Angular's own dev server uses for the same
703
+ * edits. It re-renders every view of the component in place and keeps the
704
+ * component instances, so their state survives. The module's bindings are
705
+ * pointed back at the old classes, so every module keeps using the one
706
+ * class the app's instances and injectors know.
707
+ * - **Anything else changed**, such as the class, an import, or a module this
708
+ * one imports: the update can't be applied to the running instances, so
709
+ * `hot.invalidate()` passes it on to the modules that import this one, up
710
+ * to the app's entry, which bootstraps the app again (see
711
+ * `bootstrapApplication`).
712
+ *
713
+ * The background thread runs no Angular, only the module-level code that
714
+ * registers background functions. It accepts every version, which re-runs
715
+ * the module and registers them again.
716
+ *
717
+ * @param hot - The module's `import.meta.webpackHot`.
718
+ * @param components - The component classes this version of the module defines.
719
+ * @param signature - A hash of the module's source without its components'
720
+ * templates and styles.
721
+ * @param code - A hash of the module's compiled code.
722
+ * @returns The classes the module should use from now on.
723
+ */
724
+ export declare const ɵhmrAccept: (hot: HotModule, components: Type<unknown>[], signature: string, code: string) => Type<unknown>[];
725
+ /**
726
+ * The app's own locale: `sourceLocale` from angular.json, which the build
727
+ * injects as `__LYNX_SOURCE_LOCALE__`, or `'en-US'` without one.
728
+ */
729
+ declare const getSourceLocale: () => string;
572
730
  /**
573
731
  * Reads `lynx.__globalProps.appLocale` directly, without Angular DI.
574
732
  *
@@ -622,6 +780,12 @@ export declare class LynxLocale {
622
780
  * Angular's locale-aware features (pipes, i18n) with the locale from
623
781
  * `lynx.__globalProps.appLocale`.
624
782
  *
783
+ * The apps that `ng build --platform` makes send the phone's language, which
784
+ * the app may not support. When Angular has no locale data for it (see
785
+ * `registerLocaleData()`), `LOCALE_ID` is the app's source locale instead, as
786
+ * a native app shows its own language on a phone set to one it lacks.
787
+ * Otherwise Angular's date and number pipes would throw.
788
+ *
625
789
  * @usageNotes
626
790
  * ```typescript
627
791
  * bootstrapApplication(App, {
@@ -755,6 +919,12 @@ export declare abstract class BaseGesture<TEvent extends GestureEvent = GestureE
755
919
  _callbacks: Record<string, GestureCallback<any>>;
756
920
  /**
757
921
  * @internal
922
+ *
923
+ * Starts as `{ enabled: true }`, like React Lynx's gesture-runtime, so every
924
+ * gesture sends a config, even one with no options of its own (Fling, Pinch,
925
+ * Rotation). Gestures whose native handler reads options seed the rest of
926
+ * their defaults too: once a config is present, iOS reads each key it leaves
927
+ * out as `0` (see ./const).
758
928
  */
759
929
  _config: Record<string, unknown>;
760
930
  /**
@@ -769,6 +939,15 @@ export declare abstract class BaseGesture<TEvent extends GestureEvent = GestureE
769
939
  * @internal
770
940
  */
771
941
  _continueWith: BaseGesture[];
942
+ /**
943
+ * Fires when the gesture starts tracking a touch, before it's recognized:
944
+ * at touch-down for most gestures, and when the finger lifts for a fling.
945
+ *
946
+ * A continuous gesture doesn't need one for its `onStart` and `onEnd` to
947
+ * fire. LynxGestureDetector registers an empty `onBegin` when you don't, since
948
+ * Lynx's native handlers skip those callbacks without it. See
949
+ * gesture-detector.ts.
950
+ */
772
951
  onBegin(cb: GestureCallbackWithState<TEvent>): TSelf;
773
952
  /**
774
953
  * Fires when the gesture is RECOGNIZED (transitions to active). For a tap this
@@ -805,6 +984,12 @@ export declare abstract class BaseGesture<TEvent extends GestureEvent = GestureE
805
984
  * Useful for chaining: e.g. a long-press followed by a drag.
806
985
  */
807
986
  continueWith(...gestures: BaseGesture[]): TSelf;
987
+ /**
988
+ * ⚠️ Not read by Lynx's native gesture handlers yet (as of Lynx 4.1, no
989
+ * handler looks up `enabled`), so a disabled gesture still fires on a
990
+ * device. Unbind the gesture from `[lynxGesture]` to turn it off. Kept for
991
+ * API parity with Lynx's gesture-runtime.
992
+ */
808
993
  enabled(value: boolean): TSelf;
809
994
  }
810
995
  /**
@@ -825,16 +1010,31 @@ export declare const Gesture: {
825
1010
  Exclusive(...gestures: AnyGesture$1[]): ComposedGesture;
826
1011
  Race(...gestures: AnyGesture$1[]): ComposedGesture;
827
1012
  };
1013
+ /**
1014
+ * Lynx's fling follows the momentum of a drag after the finger lifts: `onBegin`
1015
+ * fires on release, `onUpdate` on every frame (with `deltaX`/`deltaY` in the
1016
+ * params), and `onEnd` when it stops. Lynx starts that fling in its BEGAN
1017
+ * state and never activates it, so `onStart` doesn't fire
1018
+ * (LynxFlingGestureHandler.m / FlingGestureHandler.java). Lynx also flings only
1019
+ * the element that won the touch, and a fling ignores the touch until the
1020
+ * finger lifts, so it needs a pan on the same element (`Gesture.Simultaneous`).
1021
+ */
828
1022
  export declare class FlingGesture extends ContinuousGesture<FlingGestureEvent, FlingGesture> {
829
1023
  readonly type = GestureType.FLING;
830
1024
  /**
831
1025
  * FlingDirection is a bitmask — combine values with | for multi-direction:
832
1026
  * e.g. FlingDirection.LEFT | FlingDirection.RIGHT recognizes horizontal flings.
1027
+ *
1028
+ * ⚠️ Not read by Lynx's native fling handlers yet: as of Lynx 4.1, iOS's
1029
+ * `handleConfigMap` is a TODO and Android's is empty, so every fling fires,
1030
+ * in any direction. Kept for API parity with Lynx's gesture-runtime.
833
1031
  */
834
1032
  direction(dir: FlingDirection): this;
835
1033
  /**
836
1034
  * The gesture only recognizes when exactly `count` fingers are involved.
837
1035
  * Defaults to 1 if not set.
1036
+ *
1037
+ * ⚠️ Not read by Lynx's native fling handlers yet (see `direction`).
838
1038
  */
839
1039
  numberOfPointers(count: number): this;
840
1040
  }
@@ -856,6 +1056,7 @@ type GestureInput = AnyGesture | AnyGesture[] | ComposedGesture;
856
1056
  export declare class LynxGestureDetector implements OnChanges, OnDestroy {
857
1057
  #private;
858
1058
  lynxGesture: GestureInput;
1059
+ constructor();
859
1060
  /**
860
1061
  * Full teardown + re-register on every input change. This is safe because
861
1062
  * gesture IDs are stable (assigned once in BaseGesture constructor), so
@@ -906,6 +1107,11 @@ export declare class PanGesture extends ContinuousGesture<PanGestureEvent, PanGe
906
1107
  * threshold. A number means "any direction" (symmetrical); a tuple [min, max]
907
1108
  * means the offset must be within that range. Example: activeOffsetX(20)
908
1109
  * activates after 20px of horizontal movement.
1110
+ *
1111
+ * ⚠️ Not read by Lynx's native pan handlers yet: as of Lynx 4.1 they read
1112
+ * only `minDistance` (LynxPanGestureHandler.m / PanGestureHandler.java
1113
+ * `handleConfigMap`). The same goes for activeOffsetY, failOffsetX/Y and
1114
+ * min/maxPointers. Kept for API parity with Lynx's gesture-runtime.
909
1115
  */
910
1116
  activeOffsetX(offset: number | [number, number]): this;
911
1117
  activeOffsetY(offset: number | [number, number]): this;
@@ -914,6 +1120,9 @@ export declare class PanGesture extends ContinuousGesture<PanGestureEvent, PanGe
914
1120
  * direction, the gesture fails (ceding to a competing gesture). Example:
915
1121
  * failOffsetY(10) on a horizontal pan: if the user moves >10px vertically
916
1122
  * before activating, the gesture fails and a vertical scroll can take over.
1123
+ *
1124
+ * ⚠️ Not read by Lynx's native pan handlers yet (see `activeOffsetX`). Call
1125
+ * the state manager's `fail()` from `onUpdate` instead.
917
1126
  */
918
1127
  failOffsetX(offset: number | [number, number]): this;
919
1128
  failOffsetY(offset: number | [number, number]): this;
@@ -958,6 +1167,16 @@ export declare class TapGesture extends BaseGesture<TapGestureEvent, TapGesture>
958
1167
  */
959
1168
  maxDistance(px: number): this;
960
1169
  }
1170
+ /**
1171
+ * A length Lynx's exposure detection parses, such as `'20px'` or `'-10rpx'`.
1172
+ * Lynx reads the margins as strings, so a bare number has no effect.
1173
+ */
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';
961
1180
  /**
962
1181
  * @Directive() is required so that ng-packagr's Angular partial compiler
963
1182
  * recognizes this base class as an Angular artifact. The selector is left
@@ -1002,9 +1221,17 @@ declare class LynxElementBase implements OnChanges {
1002
1221
  * Text read aloud by screen readers.
1003
1222
  */
1004
1223
  'accessibility-label'?: string;
1005
- 'accessibility-trait'?: 'none' | 'button' | 'image' | 'text';
1006
1224
  /**
1007
- * Comma-separated list of child element names that are accessibility nodes.
1225
+ * The kind of element a screen reader announces. Plural, as Lynx reads it:
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'
1230
+ */
1231
+ 'accessibility-traits'?: AccessibilityTrait | `${AccessibilityTrait},${string}`;
1232
+ /**
1233
+ * Comma-separated `id`s of the child elements a screen reader visits, in
1234
+ * order. iOS and Android look each one up as an `id` selector.
1008
1235
  */
1009
1236
  'accessibility-elements'?: string;
1010
1237
  'accessibility-elements-hidden'?: boolean;
@@ -1044,6 +1271,32 @@ declare class LynxElementBase implements OnChanges {
1044
1271
  * Allow simultaneous touch recognition (iOS).
1045
1272
  */
1046
1273
  'ios-enable-simultaneous-touch'?: boolean;
1274
+ /**
1275
+ * Lets Lynx draw the element into its parent's native view instead of
1276
+ * creating its own (Android). `false` gives it its own view, which sticky
1277
+ * positioning, text selection and reliable clipping need. @default true
1278
+ */
1279
+ flatten?: boolean;
1280
+ /**
1281
+ * Direction in which the element takes pan gestures from native views
1282
+ * outside Lynx: 0 = horizontal, 1 = vertical.
1283
+ */
1284
+ 'pan-intercept-direction'?: 0 | 1;
1285
+ /**
1286
+ * Which views `pan-intercept-direction` takes pans from: 0 = self,
1287
+ * 1 = ancestors, 2 = descendants, 3 = self and ancestors, 4 = self and
1288
+ * descendants, 5 = all.
1289
+ */
1290
+ 'pan-intercept-scope'?: 0 | 1 | 2 | 3 | 4 | 5;
1291
+ /**
1292
+ * Swipe angle ranges, `[start, end]` in degrees, that the element keeps
1293
+ * from platform gestures.
1294
+ */
1295
+ 'consume-slide-event'?: [number, number][];
1296
+ /**
1297
+ * Whether `:active` also applies to the ancestors on the touch's event path.
1298
+ */
1299
+ 'enable-touch-pseudo-propagation'?: boolean;
1047
1300
  /**
1048
1301
  * Unique ID used for impression/exposure analytics.
1049
1302
  */
@@ -1053,41 +1306,52 @@ declare class LynxElementBase implements OnChanges {
1053
1306
  */
1054
1307
  'exposure-scene'?: string;
1055
1308
  /**
1056
- * Percentage of the element that must be visible (0–100) to trigger exposure.
1309
+ * How much of the element must be visible to count as exposed, as a
1310
+ * percentage string such as `'50%'`. @default '0%'
1057
1311
  */
1058
- 'exposure-area'?: number;
1312
+ 'exposure-area'?: `${number}%`;
1059
1313
  /**
1060
- * Extends/shrinks the viewport detection zone (top edge, in px).
1314
+ * Extends/shrinks the viewport detection zone (top edge).
1061
1315
  */
1062
- 'exposure-screen-margin-top'?: number | string;
1316
+ 'exposure-screen-margin-top'?: ExposureMargin;
1063
1317
  /**
1064
- * Extends/shrinks the viewport detection zone (bottom edge, in px).
1318
+ * Extends/shrinks the viewport detection zone (bottom edge).
1065
1319
  */
1066
- 'exposure-screen-margin-bottom'?: number | string;
1320
+ 'exposure-screen-margin-bottom'?: ExposureMargin;
1067
1321
  /**
1068
- * Extends/shrinks the viewport detection zone (left edge, in px).
1322
+ * Extends/shrinks the viewport detection zone (left edge).
1069
1323
  */
1070
- 'exposure-screen-margin-left'?: number | string;
1324
+ 'exposure-screen-margin-left'?: ExposureMargin;
1071
1325
  /**
1072
- * Extends/shrinks the viewport detection zone (right edge, in px).
1326
+ * Extends/shrinks the viewport detection zone (right edge).
1073
1327
  */
1074
- 'exposure-screen-margin-right'?: number | string;
1328
+ 'exposure-screen-margin-right'?: ExposureMargin;
1075
1329
  /**
1076
- * Adjusts the element's own bounding rect for exposure detection (top, in px).
1330
+ * Adjusts the element's own bounding rect for exposure detection (top).
1331
+ * iOS and Android apply it only with `enable-exposure-ui-margin`.
1077
1332
  */
1078
- 'exposure-ui-margin-top'?: number | string;
1333
+ 'exposure-ui-margin-top'?: ExposureMargin;
1079
1334
  /**
1080
- * Adjusts the element's own bounding rect for exposure detection (bottom, in px).
1335
+ * Adjusts the element's own bounding rect for exposure detection (bottom).
1336
+ * iOS and Android apply it only with `enable-exposure-ui-margin`.
1081
1337
  */
1082
- 'exposure-ui-margin-bottom'?: number | string;
1338
+ 'exposure-ui-margin-bottom'?: ExposureMargin;
1083
1339
  /**
1084
- * Adjusts the element's own bounding rect for exposure detection (left, in px).
1340
+ * Adjusts the element's own bounding rect for exposure detection (left).
1341
+ * iOS and Android apply it only with `enable-exposure-ui-margin`.
1085
1342
  */
1086
- 'exposure-ui-margin-left'?: number | string;
1343
+ 'exposure-ui-margin-left'?: ExposureMargin;
1087
1344
  /**
1088
- * Adjusts the element's own bounding rect for exposure detection (right, in px).
1345
+ * Adjusts the element's own bounding rect for exposure detection (right).
1346
+ * iOS and Android apply it only with `enable-exposure-ui-margin`.
1089
1347
  */
1090
- 'exposure-ui-margin-right'?: number | string;
1348
+ 'exposure-ui-margin-right'?: ExposureMargin;
1349
+ /**
1350
+ * Turns on `exposure-ui-margin-*` on iOS and Android (always on for Harmony
1351
+ * and the web). It also changes how they apply `exposure-screen-margin-*`.
1352
+ * @default false
1353
+ */
1354
+ 'enable-exposure-ui-margin'?: boolean;
1091
1355
  static ɵfac: i0.ɵɵFactoryDeclaration<LynxElementBase, never>;
1092
1356
  static ɵdir: i0.ɵɵDirectiveDeclaration<LynxElementBase, never, never, {
1093
1357
  "id": {
@@ -1106,8 +1370,16 @@ declare class LynxElementBase implements OnChanges {
1106
1370
  "alias": "accessibility-label";
1107
1371
  "required": false;
1108
1372
  };
1109
- "accessibility-trait": {
1110
- "alias": "accessibility-trait";
1373
+ "accessibility-value": {
1374
+ "alias": "accessibility-value";
1375
+ "required": false;
1376
+ };
1377
+ "accessibility-actions": {
1378
+ "alias": "accessibility-actions";
1379
+ "required": false;
1380
+ };
1381
+ "accessibility-traits": {
1382
+ "alias": "accessibility-traits";
1111
1383
  "required": false;
1112
1384
  };
1113
1385
  "accessibility-elements": {
@@ -1154,6 +1426,26 @@ declare class LynxElementBase implements OnChanges {
1154
1426
  "alias": "ios-enable-simultaneous-touch";
1155
1427
  "required": false;
1156
1428
  };
1429
+ "flatten": {
1430
+ "alias": "flatten";
1431
+ "required": false;
1432
+ };
1433
+ "pan-intercept-direction": {
1434
+ "alias": "pan-intercept-direction";
1435
+ "required": false;
1436
+ };
1437
+ "pan-intercept-scope": {
1438
+ "alias": "pan-intercept-scope";
1439
+ "required": false;
1440
+ };
1441
+ "consume-slide-event": {
1442
+ "alias": "consume-slide-event";
1443
+ "required": false;
1444
+ };
1445
+ "enable-touch-pseudo-propagation": {
1446
+ "alias": "enable-touch-pseudo-propagation";
1447
+ "required": false;
1448
+ };
1157
1449
  "exposure-id": {
1158
1450
  "alias": "exposure-id";
1159
1451
  "required": false;
@@ -1198,12 +1490,36 @@ declare class LynxElementBase implements OnChanges {
1198
1490
  "alias": "exposure-ui-margin-right";
1199
1491
  "required": false;
1200
1492
  };
1493
+ "enable-exposure-ui-margin": {
1494
+ "alias": "enable-exposure-ui-margin";
1495
+ "required": false;
1496
+ };
1201
1497
  }, {}, never, never, true, never>;
1498
+ static "ngAcceptInputType_accessibility-element": boolean | "" | "true" | "false" | undefined;
1499
+ static "ngAcceptInputType_accessibility-elements-hidden": boolean | "" | "true" | "false" | undefined;
1500
+ static "ngAcceptInputType_accessibility-exclusive-focus": boolean | "" | "true" | "false" | undefined;
1501
+ static "ngAcceptInputType_user-interaction-enabled": boolean | "" | "true" | "false" | undefined;
1502
+ static "ngAcceptInputType_native-interaction-enabled": boolean | "" | "true" | "false" | undefined;
1503
+ static "ngAcceptInputType_event-through": boolean | "" | "true" | "false" | undefined;
1504
+ static "ngAcceptInputType_block-native-event": boolean | "" | "true" | "false" | undefined;
1505
+ static "ngAcceptInputType_ignore-focus": boolean | "" | "true" | "false" | undefined;
1506
+ static "ngAcceptInputType_ios-enable-simultaneous-touch": boolean | "" | "true" | "false" | undefined;
1507
+ static ngAcceptInputType_flatten: boolean | "" | "true" | "false" | undefined;
1508
+ static "ngAcceptInputType_pan-intercept-direction": 0 | 1 | "0" | "1" | undefined;
1509
+ static "ngAcceptInputType_pan-intercept-scope": 0 | 1 | 2 | 3 | 4 | 5 | "0" | "1" | "2" | "3" | "4" | "5" | undefined;
1510
+ static "ngAcceptInputType_enable-touch-pseudo-propagation": boolean | "" | "true" | "false" | undefined;
1511
+ static "ngAcceptInputType_enable-exposure-ui-margin": boolean | "" | "true" | "false" | undefined;
1202
1512
  }
1203
1513
  /**
1204
1514
  * Backdrop blur: blurs the content rendered behind the element, like CSS
1205
1515
  * `backdrop-filter: blur()`. On iOS, `blur-effect="glass"` renders the
1206
1516
  * Liquid Glass material.
1517
+ *
1518
+ * Android only has the plain blur, a Gaussian blur of `blur-radius`. There
1519
+ * the runtime approximates `blur-effect`, `glass-style` and
1520
+ * `glass-tint-color` with a translucent background and rim over the blur,
1521
+ * which a background, background image or shadow the app sets replaces.
1522
+ * Nothing refracts, and `glass-interactive` and `spacing` do nothing.
1207
1523
  */
1208
1524
  export declare class LynxBlurView extends LynxElementBase {
1209
1525
  /**
@@ -1219,7 +1535,10 @@ export declare class LynxBlurView extends LynxElementBase {
1219
1535
  */
1220
1536
  'enable-auto-blur'?: boolean;
1221
1537
  /**
1222
- * Raw id of the view to capture and blur; it must have `flatten="false"` (Android).
1538
+ * Raw id of the view to capture and blur; it must have `flatten="false"`
1539
+ * (Android). The runtime points it at the page, so a blur-view inside
1540
+ * another blur-view still blurs what's behind it; an empty string restores
1541
+ * Android's own choice, the nearest ancestor that clips or contains it.
1223
1542
  */
1224
1543
  'android-capture-target'?: string;
1225
1544
  /**
@@ -1228,7 +1547,8 @@ export declare class LynxBlurView extends LynxElementBase {
1228
1547
  'experimental-update-blur-radius'?: boolean;
1229
1548
  /**
1230
1549
  * Blur material (iOS). `glass` renders Liquid Glass; `glass-container`
1231
- * merges nested glass `<blur-view>`s into one combined effect. @default 'light'
1550
+ * merges nested glass `<blur-view>`s into one combined effect. Android
1551
+ * gets a tint that approximates it. @default 'light'
1232
1552
  */
1233
1553
  'blur-effect'?: 'light' | 'extra-light' | 'dark' | 'glass' | 'glass-container';
1234
1554
  /**
@@ -1240,11 +1560,11 @@ export declare class LynxBlurView extends LynxElementBase {
1240
1560
  */
1241
1561
  'glass-interactive'?: boolean;
1242
1562
  /**
1243
- * Tint color applied to the glass (iOS). @default 'transparent'
1563
+ * Tint color applied to the glass (iOS; approximated on Android). @default 'transparent'
1244
1564
  */
1245
1565
  'glass-tint-color'?: string;
1246
1566
  /**
1247
- * Glass variant (iOS). @default 'regular'
1567
+ * Glass variant (iOS; approximated on Android). @default 'regular'
1248
1568
  */
1249
1569
  'glass-style'?: 'regular' | 'clear';
1250
1570
  /**
@@ -1758,6 +2078,10 @@ export declare class LynxTextarea extends LynxElementBase {
1758
2078
  }
1759
2079
  /**
1760
2080
  * High-performance virtualized list, equivalent to RecyclerView / UITableView.
2081
+ *
2082
+ * Gaps between items aren't attributes: `list-main-axis-gap` and
2083
+ * `list-cross-axis-gap` are CSS properties, which Lynx's list reads from its
2084
+ * computed style, so set them in `style` (`[style.list-main-axis-gap]`).
1761
2085
  */
1762
2086
  export declare class LynxList extends LynxElementBase {
1763
2087
  /**
@@ -1823,14 +2147,6 @@ export declare class LynxList extends LynxElementBase {
1823
2147
  * Insert/remove animation style.
1824
2148
  */
1825
2149
  'update-animation'?: 'default' | 'none';
1826
- /**
1827
- * Gap between items on the main axis (CSS length).
1828
- */
1829
- 'list-main-axis-gap'?: string;
1830
- /**
1831
- * Gap between columns/rows on the cross axis (CSS length).
1832
- */
1833
- 'list-cross-axis-gap'?: string;
1834
2150
  /**
1835
2151
  * Required by Lynx's native list UI whenever the app uses the standard
1836
2152
  * dual-thread engine strategy (always true for AngularLynx) — without it
@@ -1929,14 +2245,6 @@ export declare class LynxList extends LynxElementBase {
1929
2245
  "alias": "update-animation";
1930
2246
  "required": false;
1931
2247
  };
1932
- "list-main-axis-gap": {
1933
- "alias": "list-main-axis-gap";
1934
- "required": false;
1935
- };
1936
- "list-cross-axis-gap": {
1937
- "alias": "list-cross-axis-gap";
1938
- "required": false;
1939
- };
1940
2248
  "enable-async-list": {
1941
2249
  "alias": "enable-async-list";
1942
2250
  "required": false;
@@ -1988,13 +2296,6 @@ export declare class LynxListItem extends LynxElementBase {
1988
2296
  * Estimated item size in px for layout pre-calculation.
1989
2297
  */
1990
2298
  'estimated-main-axis-size-px'?: number;
1991
- /**
1992
- * Deferred rendering. Pass `true` to defer, or an object to control
1993
- * whether the item unmounts when recycled.
1994
- */
1995
- defer?: boolean | {
1996
- unmountRecycled?: boolean;
1997
- };
1998
2299
  static ɵfac: i0.ɵɵFactoryDeclaration<LynxListItem, never>;
1999
2300
  static ɵdir: i0.ɵɵDirectiveDeclaration<LynxListItem, "list-item", never, {
2000
2301
  "item-key": {
@@ -2025,10 +2326,6 @@ export declare class LynxListItem extends LynxElementBase {
2025
2326
  "alias": "estimated-main-axis-size-px";
2026
2327
  "required": false;
2027
2328
  };
2028
- "defer": {
2029
- "alias": "defer";
2030
- "required": false;
2031
- };
2032
2329
  }, {}, never, never, true, never>;
2033
2330
  }
2034
2331
  /**
@@ -2063,8 +2360,9 @@ export declare class LynxOverlay extends LynxElementBase {
2063
2360
  */
2064
2361
  visible?: boolean;
2065
2362
  /**
2066
- * Z-order layer (higher = above other overlays).
2067
- * 1 = default, 2 = status bar level, 3 = keyboard level, 4 = top.
2363
+ * The layer the overlay sits in when several are open: 1 is the top layer
2364
+ * and 4 the lowest. Within a layer the last one shown is on top. Lynx reads
2365
+ * it only while the overlay is hidden. @default 1
2068
2366
  */
2069
2367
  level?: 1 | 2 | 3 | 4;
2070
2368
  /**
@@ -2386,7 +2684,10 @@ export declare class LynxSvg extends LynxElementBase {
2386
2684
  */
2387
2685
  export declare class LynxText extends LynxElementBase {
2388
2686
  /**
2389
- * Maximum number of lines before truncation with ellipsis.
2687
+ * Maximum number of lines the text is laid out in. The text box ends after
2688
+ * that many lines, but the ellipsis needs `text-overflow: ellipsis`
2689
+ * (Tailwind's `text-ellipsis`). Without it, iOS cuts the text off at the
2690
+ * last line, and Android draws the remaining lines past the box.
2390
2691
  */
2391
2692
  'text-maxline'?: number;
2392
2693
  /**
@@ -2558,45 +2859,13 @@ export declare class LynxVideo extends LynxElementBase {
2558
2859
  }, {}, never, never, true, never>;
2559
2860
  }
2560
2861
  /**
2561
- * General-purpose container element, equivalent to HTML `<div>`.
2862
+ * General-purpose container element, equivalent to HTML `<div>`. Its
2863
+ * attributes (`flatten`, the pan-intercept ones, …) work on every element, so
2864
+ * they live on {@link LynxElementBase}.
2562
2865
  */
2563
2866
  export declare class LynxView extends LynxElementBase {
2564
- /**
2565
- * Flatten the view into its parent's layer (Android only).
2566
- * Improves performance for non-interactive views.
2567
- */
2568
- flatten?: boolean;
2569
- /**
2570
- * Direction of pan-gesture interception.
2571
- * 0 = horizontal, 1 = vertical, 2 = none.
2572
- */
2573
- 'pan-intercept-direction'?: 0 | 1 | 2;
2574
- 'pan-intercept-scope'?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
2575
- 'consume-slide-event'?: [number, number][];
2576
- 'enable-touch-pseudo-propagation'?: boolean;
2577
2867
  static ɵfac: i0.ɵɵFactoryDeclaration<LynxView, never>;
2578
- static ɵdir: i0.ɵɵDirectiveDeclaration<LynxView, "view", never, {
2579
- "flatten": {
2580
- "alias": "flatten";
2581
- "required": false;
2582
- };
2583
- "pan-intercept-direction": {
2584
- "alias": "pan-intercept-direction";
2585
- "required": false;
2586
- };
2587
- "pan-intercept-scope": {
2588
- "alias": "pan-intercept-scope";
2589
- "required": false;
2590
- };
2591
- "consume-slide-event": {
2592
- "alias": "consume-slide-event";
2593
- "required": false;
2594
- };
2595
- "enable-touch-pseudo-propagation": {
2596
- "alias": "enable-touch-pseudo-propagation";
2597
- "required": false;
2598
- };
2599
- }, {}, never, never, true, never>;
2868
+ static ɵdir: i0.ɵɵDirectiveDeclaration<LynxView, "view", never, {}, {}, never, never, true, never>;
2600
2869
  }
2601
2870
  /**
2602
2871
  * Horizontally swipeable paging container.
@@ -2790,14 +3059,61 @@ export declare class LynxWebView extends LynxElementBase {
2790
3059
  };
2791
3060
  }, {}, never, never, true, never>;
2792
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
+ }
2793
3110
  /**
2794
3111
  * All Lynx native element directives as a single importable array.
2795
3112
  * Add to the `imports` of any component whose template uses Lynx elements.
2796
3113
  */
2797
- 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 import("@blotch/angular-lynx").LynxInputValueAccessor, typeof import("@blotch/angular-lynx").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];
2798
3115
  export declare class LynxLogger {
2799
3116
  #private;
2800
- constructor();
2801
3117
  log(...args: unknown[]): void;
2802
3118
  warn(...args: unknown[]): void;
2803
3119
  error(...args: unknown[]): void;
@@ -2810,9 +3126,15 @@ export declare class LynxLogger {
2810
3126
  * Extensible map of custom native modules declared by the host app.
2811
3127
  *
2812
3128
  * App developers augment this interface to get type-safe access
2813
- * via {@link LynxNativeModule.getNativeModule}:
3129
+ * via {@link LynxNativeModule.getNativeModule}. Describe each module's
3130
+ * methods as the host implements them; `getNativeModule()` turns their
3131
+ * return values into promises (see {@link NativeModuleProxy}):
2814
3132
  *
2815
3133
  * ```typescript
3134
+ * // This export makes the file a module, so the block below adds to
3135
+ * // @blotch/angular-lynx's types instead of replacing them.
3136
+ * export {};
3137
+ *
2816
3138
  * declare module '@blotch/angular-lynx' {
2817
3139
  * interface NativeModuleMap {
2818
3140
  * NativeLocalStorageModule: {
@@ -2824,7 +3146,17 @@ export declare class LynxLogger {
2824
3146
  * }
2825
3147
  * ```
2826
3148
  */
2827
- type NativeModuleMap = {};
3149
+ interface NativeModuleMap {}
3150
+ /**
3151
+ * A native module as {@link LynxNativeModule.getNativeModule} returns it on
3152
+ * the main thread, where Angular runs.
3153
+ *
3154
+ * Native modules exist only on the background thread, so each method call is
3155
+ * relayed there: the method returns a promise of its result (copied as JSON),
3156
+ * and function arguments are called back on the main thread. Only methods
3157
+ * cross; other properties of the module aren't reachable.
3158
+ */
3159
+ type NativeModuleProxy<T> = { [K in keyof T as T[K] extends ((...args: any[]) => unknown) ? K : never]: T[K] extends ((...args: infer A) => infer R) ? (...args: A) => Promise<Awaited<R>> : never; };
2828
3160
  /**
2829
3161
  * Wraps the Lynx native module bridge and JS module registry as an Angular injectable.
2830
3162
  *
@@ -2836,6 +3168,12 @@ type NativeModuleMap = {};
2836
3168
  * values within a single LynxView. This is the same API used internally by
2837
3169
  * `LynxInitData` and `LynxGlobalData` (via `GlobalEventEmitter`).
2838
3170
  *
3171
+ * Lynx provides both only on the background thread, while Angular runs on the
3172
+ * main thread. So on the main thread every method goes through the background
3173
+ * call relay (background-call.ts): calls run on the background thread, their
3174
+ * results and callbacks come back as JSON, and a module is a proxy whose
3175
+ * methods return promises.
3176
+ *
2839
3177
  * @usageNotes
2840
3178
  * ```typescript
2841
3179
  * const modules = inject(LynxNativeModule);
@@ -2863,13 +3201,14 @@ export declare class LynxNativeModule {
2863
3201
  * The native callback API is wrapped in a Promise for ergonomic
2864
3202
  * use with `async`/`await`.
2865
3203
  *
2866
- * Returns `undefined` when `NativeModules` is unavailable (web preview, tests).
3204
+ * Resolves `undefined` when there is no bridge (web preview, tests).
2867
3205
  */
2868
3206
  call<T = unknown>(name: string, params?: Record<string, unknown>): Promise<T | undefined>;
2869
3207
  /**
2870
- * Subscribes to a native event via `NativeModules.bridge.on()`.
3208
+ * Subscribes to a native event via `NativeModules.bridge.on()`. From the
3209
+ * main thread, the callback gets the event's arguments copied as JSON.
2871
3210
  *
2872
- * No-op when `NativeModules` is unavailable.
3211
+ * No-op when there is no bridge.
2873
3212
  */
2874
3213
  on(name: string, callback: (...args: unknown[]) => void): void;
2875
3214
  /**
@@ -2878,6 +3217,8 @@ export declare class LynxNativeModule {
2878
3217
  * Augment the {@link NativeModuleMap} interface for type-safe access:
2879
3218
  *
2880
3219
  * ```typescript
3220
+ * export {};
3221
+ *
2881
3222
  * declare module '@blotch/angular-lynx' {
2882
3223
  * interface NativeModuleMap {
2883
3224
  * NativeLocalStorageModule: { ... };
@@ -2887,25 +3228,35 @@ export declare class LynxNativeModule {
2887
3228
  * const storage = modules.getNativeModule('NativeLocalStorageModule');
2888
3229
  * ```
2889
3230
  *
2890
- * Returns `undefined` when `NativeModules` is unavailable or the module
2891
- * is not registered.
3231
+ * On the main thread, which can't reach native modules, it returns a proxy:
3232
+ * each method call runs on the background thread and returns a promise of
3233
+ * its result, and a call to a module or method the host doesn't have
3234
+ * rejects. The return type says so: a module in {@link NativeModuleMap}
3235
+ * comes back as a {@link NativeModuleProxy} of it, and any other name as
3236
+ * `unknown`.
3237
+ *
3238
+ * Returns `undefined` outside Lynx, or on the background thread when the
3239
+ * module is not registered.
2892
3240
  */
2893
- getNativeModule<K extends string>(name: K): K extends keyof NativeModuleMap ? NativeModuleMap[K] : unknown;
3241
+ getNativeModule<K extends string>(name: K): K extends keyof NativeModuleMap ? NativeModuleProxy<NativeModuleMap[K]> | undefined : unknown;
2894
3242
  /**
2895
3243
  * Retrieves a JS module registered within this LynxView.
2896
3244
  *
2897
3245
  * This wraps `lynx.getJSModule()` — the same API used internally
2898
- * for `GlobalEventEmitter`.
3246
+ * for `GlobalEventEmitter`. On the main thread it returns a proxy, as
3247
+ * getNativeModule() does.
2899
3248
  *
2900
- * Returns `undefined` when `lynx` is unavailable or the module
2901
- * is not registered.
3249
+ * Returns `undefined` when `lynx` is unavailable or, on the background
3250
+ * thread, when the module is not registered.
2902
3251
  */
2903
3252
  getJSModule<T = unknown>(name: string): T | undefined;
2904
3253
  /**
2905
3254
  * Registers a JS module for sharing within this LynxView.
2906
3255
  *
2907
3256
  * Other code (including native callbacks) can retrieve it via
2908
- * `getJSModule()` or `lynx.getJSModule()`.
3257
+ * `getJSModule()` or `lynx.getJSModule()`. From the main thread, the
3258
+ * background thread registers a copy whose methods call this module's, with
3259
+ * their arguments copied as JSON and their return values dropped.
2909
3260
  *
2910
3261
  * No-op when `lynx` is unavailable.
2911
3262
  */
@@ -2913,40 +3264,18 @@ export declare class LynxNativeModule {
2913
3264
  static ɵfac: i0.ɵɵFactoryDeclaration<LynxNativeModule, never>;
2914
3265
  static ɵprov: i0.ɵɵInjectableDeclaration<any>;
2915
3266
  }
2916
- /**
2917
- * A no-op animation returned when `animate()` is called on the background
2918
- * thread where `__ElementAnimate` is unavailable. Provides the same API
2919
- * surface as `LynxAnimation` so callers can call `.cancel()`, `.pause()`,
2920
- * `.play()` without crashing — the calls simply do nothing.
2921
- *
2922
- * Fixes: "Uncaught Error: animate() is only available on the main thread"
2923
- * in the Go web preview (and any background-thread context).
2924
- *
2925
- * Why needed: In the Lynx dual-thread model, Angular runs on the background
2926
- * thread where __ElementAnimate doesn't exist. Previously, calling
2927
- * element.animate() from a component (e.g. the animations example's "Tap to
2928
- * pulse" button) would throw, crashing the Go web preview on the docs site.
2929
- *
2930
- * Approach: Return a silent no-op instead of throwing. This matches how
2931
- * @lynx-js/web-core itself handles __ElementAnimate on the server — it's
2932
- * defined as `() => {}` (a no-op). We mirror that graceful degradation here.
2933
- * Alternatives considered:
2934
- * - Cross-thread bridge via lynx.getCoreContext().dispatchEvent() — correct
2935
- * long-term but complex; LynxBackgroundElement doesn't hold a native ref.
2936
- * - Removing animate() from the example — wrong because it's the primary
2937
- * demonstration of the JS animate API.
2938
- */
2939
- declare class NoopLynxAnimation implements Pick<Animation, 'id' | 'cancel' | 'pause' | 'play'> {
2940
- #private;
2941
- readonly id: string;
2942
- constructor();
2943
- play(): void;
2944
- pause(): void;
2945
- cancel(): void;
2946
- }
2947
3267
  type LynxEventType = 'bindEvent' | 'catchEvent' | 'capture-bindEvent' | 'capture-catchEvent' | 'global-bindEvent';
2948
3268
  declare const EVENT_PREFIXES: [string, LynxEventType][];
2949
- type BaseLynxElement = Pick<Element, 'setAttribute'> & {
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>;
3278
+ type BaseLynxElement = Pick<Element$1, 'setAttribute'> & {
2950
3279
  tagName: string;
2951
3280
  setProperty(name: string, value: any): void;
2952
3281
  getAttribute(name: string): string | null;
@@ -2957,7 +3286,18 @@ type BaseLynxElement = Pick<Element, 'setAttribute'> & {
2957
3286
  insertBefore(newChild: BaseLynxElement, refChild: BaseLynxElement | null): void;
2958
3287
  appendChild(newChild: BaseLynxElement): void;
2959
3288
  addClass(name: string): void;
3289
+ /**
3290
+ * Adds a class that stays when the whole class list is replaced, for
3291
+ * ViewEncapsulation.Emulated's scope classes (see EmulatedLynxRenderer).
3292
+ */
3293
+ addScopeClass(name: string): void;
2960
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;
2961
3301
  remove(): void;
2962
3302
  parentNode(): BaseLynxElement | null;
2963
3303
  nextSibling(): BaseLynxElement | null;
@@ -2967,58 +3307,10 @@ type BaseLynxElement = Pick<Element, 'setAttribute'> & {
2967
3307
  animate(keyframes: Record<string, string | number>[], options?: number | LynxAnimationOptions): BaseLynxAnimation;
2968
3308
  /**
2969
3309
  * Invokes a native UI method on this element (e.g. setValue, scrollTo).
2970
- *
2971
- * Marked optional because it only exists on the main thread: LynxElement
2972
- * implements it via __InvokeUIMethod, while LynxBackgroundElement (used in
2973
- * tests and the background-thread context) does not — UIMethod calls have no
2974
- * meaning outside the native render thread. Callers should use invoke?.() so
2975
- * they become no-ops in test/background environments rather than crashing.
3310
+ * LynxElement implements it via __InvokeUIMethod.
2976
3311
  */
2977
- invoke?(methodName: string, params?: Record<string, unknown>): void;
3312
+ invoke(methodName: string, params?: Record<string, unknown>): void;
2978
3313
  };
2979
- /**
2980
- * Virtual element for the background thread where no native PAPI functions exist.
2981
- * Maintains an in-memory linked-list tree (parent/child/sibling pointers) that
2982
- * mirrors what LynxDocument builds on the main thread. Used by:
2983
- * - Angular's change detection (reads parentNode/nextSibling for view insertion)
2984
- * - querySelector/querySelectorAll (for testing and background-thread lookups)
2985
- * - LynxBackgroundDocument (creates these instead of native elements)
2986
- *
2987
- * Props, styles, classes, and events are stored in Maps/Sets but never sent to
2988
- * native — they exist so component code can read back what it set without
2989
- * crashing, and so the testing library can inspect element state.
2990
- */
2991
- declare class LynxBackgroundElement implements BaseLynxElement {
2992
- #private;
2993
- isRootPageElement: boolean;
2994
- tagName: string;
2995
- setProperty(name: string, value: any): void;
2996
- setAttribute(name: string, value: any): void;
2997
- getAttribute(name: string): string | null;
2998
- removeAttribute(name: string): void;
2999
- setStyle(key: string, value: unknown): void;
3000
- removeStyle(key: string): void;
3001
- setInlineStyles(inlineStyle: string): void;
3002
- insertBefore(newChild: LynxBackgroundElement, refChild: LynxBackgroundElement | null): void;
3003
- appendChild(newChild: LynxBackgroundElement): void;
3004
- addClass(name: string): void;
3005
- removeClass(name: string): void;
3006
- remove(): void;
3007
- parentNode(): BaseLynxElement | null;
3008
- nextSibling(): BaseLynxElement | null;
3009
- querySelector(selector: string): BaseLynxElement | null;
3010
- querySelectorAll(selector: string): BaseLynxElement[];
3011
- /**
3012
- * Previously threw: `throw new Error('animate() is only available on the
3013
- * main thread')`. This crashed the Go web preview on the docs site because
3014
- * the animations example's (bindtap) handler calls el.nativeElement.animate()
3015
- * which lands here on the background thread. Returning a no-op is safe —
3016
- * the animation won't visually play, but the caller's code (including
3017
- * .cancel() / .pause() / .play() chains) continues without error.
3018
- */
3019
- animate(_keyframes: Record<string, string | number>[], _options?: number | LynxAnimationOptions): NoopLynxAnimation;
3020
- addEventListener(name: string, cb: (event: any) => any): () => void;
3021
- }
3022
3314
  declare class LynxElement implements BaseLynxElement {
3023
3315
  #private;
3024
3316
  get element(): ElementRef;
@@ -3056,6 +3348,18 @@ declare class LynxElement implements BaseLynxElement {
3056
3348
  */
3057
3349
  setInitialText(text: string): void;
3058
3350
  setAttribute(name: string, value: any): void;
3351
+ /**
3352
+ * On Android, gives a blur-view the CSS variables that approximate its iOS
3353
+ * material (see android-blur-material). LynxDocument calls it when it
3354
+ * creates one, and setAttribute whenever an attribute it depends on changes.
3355
+ */
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;
3059
3363
  getAttribute(name: string): string;
3060
3364
  removeAttribute(name: string): void;
3061
3365
  setStyle(key: string, value: unknown): void;
@@ -3064,6 +3368,7 @@ declare class LynxElement implements BaseLynxElement {
3064
3368
  insertBefore(newChild: LynxElement, refChild: LynxElement | null): void;
3065
3369
  appendChild(newChild: LynxElement): void;
3066
3370
  addClass(name: string): void;
3371
+ addScopeClass(name: string): void;
3067
3372
  /**
3068
3373
  * Lynx has no __RemoveClass PAPI — we must get current classes, filter,
3069
3374
  * and set back. This is O(n) per class removal but class lists on Lynx
@@ -3135,11 +3440,26 @@ declare class LynxElement implements BaseLynxElement {
3135
3440
  * Angular's renderer.listen() calls this with event names like 'bindtap',
3136
3441
  * 'catchtouchstart', 'bindscroll', etc. We strip the Lynx event prefix
3137
3442
  * (bind/catch/capture-bind/capture-catch) to extract the native event name
3138
- * and determine the event type for __AddEvent.
3139
- * Events that don't match any prefix (e.g. DOM-style 'click') are silently
3140
- * ignored — Lynx has no equivalent event system for arbitrary names.
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).
3141
3452
  */
3142
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;
3143
3463
  }
3144
3464
  /**
3145
3465
  * Commits all queued genuine element removals — a free-function wrapper over
@@ -3169,9 +3489,9 @@ declare const processPendingTextNormalization: () => void;
3169
3489
  * flush.) This mirrors the `<list>` path's own guard for the exact same case —
3170
3490
  * see `LynxListElement.#scheduleUpdate`.
3171
3491
  *
3172
- * Called from `LynxDocument`'s element creators — which only ever run on the
3173
- * main thread (the background thread uses LynxBackgroundDocument, which does not
3174
- * touch the native tree), so no thread guard is needed here. It schedules ONE
3492
+ * Called from `LynxDocument`'s element creators, which only run on the main
3493
+ * thread (Angular doesn't run on the background thread), so no thread guard is
3494
+ * needed here. It schedules ONE
3175
3495
  * coalesced microtask (matching the list guard's `queueMicrotask`, not
3176
3496
  * `setTimeout` — flushing from a macrotask crashes the native engine), and is a
3177
3497
  * no-op while:
@@ -3263,9 +3583,10 @@ declare class LynxListElement extends LynxElement {
3263
3583
  */
3264
3584
  type PortalConfig = {
3265
3585
  /**
3266
- * Overlay z-level (1–4). Higher levels render above lower ones.
3586
+ * The overlay's layer, from 1 (the top) to 4 (the lowest), as on
3587
+ * `<overlay>`. Lynx's default is 1.
3267
3588
  */
3268
- level?: number;
3589
+ level?: 1 | 2 | 3 | 4;
3269
3590
  /**
3270
3591
  * Custom injector for the component's dependency injection context.
3271
3592
  */
@@ -3363,10 +3684,6 @@ type MainThreadFnHandle<TArgs extends unknown[] = unknown[], TReturn = unknown>
3363
3684
  readonly __return?: TReturn;
3364
3685
  };
3365
3686
  export declare const mainThreadFn: <TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn) => MainThreadFnHandle<TArgs, TReturn>;
3366
- /**
3367
- * Reset counter on HMR — called from runtime.ts before modules re-evaluate.
3368
- */
3369
- declare const __resetWorkletCounter: () => void;
3370
3687
  /**
3371
3688
  * Type definition for background function handles used by {@link backgroundFn}.
3372
3689
  */
@@ -3377,32 +3694,78 @@ type BackgroundFnHandle<TArgs extends unknown[] = unknown[], TReturn = unknown>
3377
3694
  readonly __args?: TArgs;
3378
3695
  readonly __return?: TReturn;
3379
3696
  };
3380
- export declare const backgroundFn: <TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn) => BackgroundFnHandle<TArgs, TReturn>;
3381
3697
  /**
3382
- * Reset counter on HMR.
3698
+ * Registers `fn` on the background thread and returns a handle that
3699
+ * `runOnBackground()` calls it with from the main thread.
3700
+ *
3701
+ * @param fn - The function to run on the background thread.
3702
+ * @param id - Set by the build for a module-level call, so the handle has the
3703
+ * same ID on both threads. Don't pass it yourself.
3704
+ * @returns The handle.
3383
3705
  */
3384
- declare const __resetBgWorkletCounter: () => void;
3706
+ export declare const backgroundFn: <TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn, id?: string) => BackgroundFnHandle<TArgs, TReturn>;
3385
3707
  export declare class MainThreadRef<T> {
3386
3708
  #private;
3387
- readonly _wvid: number;
3388
- constructor(initValue: T);
3709
+ readonly _wvid: number | string;
3710
+ /**
3711
+ * @param initValue - The ref's starting value.
3712
+ * @param id - Set by the build for a ref created at module level, so the
3713
+ * ref has the same ID on both threads. Don't pass it yourself.
3714
+ */
3715
+ constructor(initValue: T, id?: string);
3389
3716
  get current(): T;
3390
3717
  set current(value: T);
3391
3718
  /**
3392
3719
  * Serialization hook for cross-thread transfer. JSON.stringify calls this
3393
3720
  * when the ref is passed as a param to dispatchEvent (MTS/background RPC).
3394
- * The receiving thread's transformParams() resolves { _wvid } back to the
3395
- * registered MainThreadRef instance.
3721
+ * The receiving thread resolves { _wvid } back to its own registered
3722
+ * MainThreadRef instance.
3396
3723
  */
3397
3724
  toJSON(): {
3398
- _wvid: number;
3725
+ _wvid: number | string;
3399
3726
  };
3400
3727
  }
3401
- export declare const createMainThreadRef: <T>(initValue: T) => MainThreadRef<T>;
3402
3728
  /**
3403
- * Reset counter on HMR.
3729
+ * Creates a {@link MainThreadRef}.
3730
+ *
3731
+ * @param initValue - The ref's starting value.
3732
+ * @param id - Set by the build for a ref created at module level. Don't pass
3733
+ * it yourself.
3734
+ * @returns The new ref.
3404
3735
  */
3405
- declare const __resetRefCounter: () => void;
3736
+ export declare const createMainThreadRef: <T>(initValue: T, id?: string) => MainThreadRef<T>;
3737
+ declare namespace MainThread {
3738
+ /**
3739
+ * An element's layout box, from `getBoundingClientRect()`, in pixels.
3740
+ */
3741
+ type BoundingClientRect = {
3742
+ left: number;
3743
+ top: number;
3744
+ right: number;
3745
+ bottom: number;
3746
+ width: number;
3747
+ height: number;
3748
+ };
3749
+ /**
3750
+ * Lynx's main-thread element, plus the `getBoundingClientRect()` that
3751
+ * AngularLynx's MainThreadElement adds. The events below are Lynx's, built on
3752
+ * this element type, so `event.currentTarget.getBoundingClientRect()` type
3753
+ * checks without a cast.
3754
+ */
3755
+ type Element = Element$1 & {
3756
+ getBoundingClientRect(options?: {
3757
+ relativeTo?: string;
3758
+ }): Promise<BoundingClientRect>;
3759
+ };
3760
+ type TouchEvent = BaseTouchEvent<Element>;
3761
+ type MouseEvent = BaseMouseEvent<Element>;
3762
+ type WheelEvent = BaseWheelEvent<Element>;
3763
+ type KeyEvent = BaseKeyEvent<Element>;
3764
+ type AnimationEvent = BaseAnimationEvent<Element>;
3765
+ type TransitionEvent = BaseTransitionEvent<Element>;
3766
+ type LayoutChangeEvent = LayoutChangeDetailEvent<Element>;
3767
+ type UIAppearanceEvent = UIAppearanceDetailEvent<Element>;
3768
+ }
3406
3769
  /**
3407
3770
  * Wraps a native ElementRef (elementRefptr) with the @lynx-js/types
3408
3771
  * MainThread.Element API surface. Created by runWorklet's param transformation
@@ -3428,21 +3791,24 @@ export declare class MainThreadElement {
3428
3791
  invoke(methodName: string, params?: Record<string, unknown>): Promise<unknown>;
3429
3792
  animate(keyframes: Record<string, number | string>[], options?: number | LynxAnimationOptions): LynxAnimation;
3430
3793
  /**
3794
+ * Measures the element's layout box, by default from the top-left corner of
3795
+ * the LynxView. `relativeTo` takes 'screen', or another element's `id`.
3796
+ *
3431
3797
  * Not part of the official @lynx-js/types Element interface, but useful for
3432
- * touch-tracking calculations. Uses __GetComputedStyleByKey when available.
3433
- */
3434
- getBoundingClientRect(): {
3435
- left: number;
3436
- top: number;
3437
- right: number;
3438
- bottom: number;
3439
- width: number;
3440
- height: number;
3441
- };
3798
+ * touch tracking. Unlike the DOM's, it's asynchronous: native Lynx gives a
3799
+ * main-thread script the layout position only through the
3800
+ * `boundingClientRect` UI method. The computed `left` and `top` styles are
3801
+ * CSS offsets, often 0, not where the element is.
3802
+ */
3803
+ getBoundingClientRect(options?: {
3804
+ relativeTo?: string;
3805
+ }): Promise<MainThread.BoundingClientRect>;
3442
3806
  }
3443
3807
  /**
3444
- * Plain functions are also accepted because the worklet build plugin transforms
3445
- * them into MainThreadFnHandle objects at compile time.
3808
+ * Plain functions are also accepted: the worklet build plugin turns one with
3809
+ * the 'main thread' directive into a MainThreadFnHandle at compile time, so
3810
+ * TypeScript only sees the function, and the directive registers any other
3811
+ * function itself.
3446
3812
  */
3447
3813
  type MaybeHandle = MainThreadFnHandle | ((...args: any[]) => any) | undefined | null;
3448
3814
  /**
@@ -3450,14 +3816,16 @@ type MaybeHandle = MainThreadFnHandle | ((...args: any[]) => any) | undefined |
3450
3816
  * Lynx's main-thread (Lepus) event dispatch.
3451
3817
  *
3452
3818
  * Why a dedicated directive and not the renderer's listen() path:
3453
- * - Normal `(bindtap)` events are delivered to the background JS thread and
3454
- * incur a thread hop on every dispatch — fine for one-shot taps, but too
3455
- * slow for gesture-driven UI (scroll-tracking, drag, pinch) where the
3456
- * handler needs to mutate styles at native frame rate.
3457
- * - The `mainThreadBind*` / `mainThreadCatch*` family registers the handler
3458
- * as a *worklet* with `_workletType: 'main-thread'`, so Lynx invokes it
3459
- * directly on the Lepus thread where __AddInlineStyle / __SetAttribute are
3460
- * synchronous. There is no thread hop and no background JS involvement.
3819
+ * - Normal `(bindtap)` handlers run on the main thread too (listen() registers
3820
+ * them as worklets), but each one goes through Angular's listener wrapper,
3821
+ * which marks the view for change detection on every dispatch: too much for
3822
+ * gesture-driven UI (scroll-tracking, drag, pinch) that mutates styles at
3823
+ * native frame rate. Their event's targets are also plain data.
3824
+ * - The `mainThreadBind*` / `mainThreadCatch*` family registers the function
3825
+ * itself as a *worklet* with `_workletType: 'main-thread'`, so Lynx invokes
3826
+ * it directly, and runWorklet hands it MainThreadElement targets, whose
3827
+ * __AddInlineStyle / __SetAttribute calls are synchronous. Angular does no
3828
+ * work per event.
3461
3829
  * - These inputs cannot be expressed as @Output() because Angular would route
3462
3830
  * them through its own event subscription system and the underlying
3463
3831
  * worklet handle would never be passed to __AddEvent.
@@ -3476,6 +3844,12 @@ export declare class LynxMainThreadEvent implements OnChanges, OnDestroy {
3476
3844
  mainThreadCatchtouchmove?: MaybeHandle;
3477
3845
  mainThreadBindtouchend?: MaybeHandle;
3478
3846
  mainThreadCatchtouchend?: MaybeHandle;
3847
+ mainThreadBindmousedown?: MaybeHandle;
3848
+ mainThreadCatchmousedown?: MaybeHandle;
3849
+ mainThreadBindmousemove?: MaybeHandle;
3850
+ mainThreadCatchmousemove?: MaybeHandle;
3851
+ mainThreadBindmouseup?: MaybeHandle;
3852
+ mainThreadCatchmouseup?: MaybeHandle;
3479
3853
  mainThreadBindlongpress?: MaybeHandle;
3480
3854
  mainThreadCatchlongpress?: MaybeHandle;
3481
3855
  mainThreadBindscroll?: MaybeHandle;
@@ -3487,7 +3861,7 @@ export declare class LynxMainThreadEvent implements OnChanges, OnDestroy {
3487
3861
  ngOnChanges(changes: SimpleChanges): void;
3488
3862
  ngOnDestroy(): void;
3489
3863
  static ɵfac: i0.ɵɵFactoryDeclaration<LynxMainThreadEvent, never>;
3490
- static ɵdir: i0.ɵɵDirectiveDeclaration<LynxMainThreadEvent, "[mainThreadBindtap],[mainThreadCatchtap],[mainThreadBindtouchstart],[mainThreadCatchtouchstart],[mainThreadBindtouchmove],[mainThreadCatchtouchmove],[mainThreadBindtouchend],[mainThreadCatchtouchend],[mainThreadBindlongpress],[mainThreadCatchlongpress],[mainThreadBindscroll],[mainThreadCatchscroll],[mainThreadBindanimationstart],[mainThreadBindanimationend],[mainThreadBindtransitionend],[mainThreadBindlayoutchange]", never, {
3864
+ static ɵdir: i0.ɵɵDirectiveDeclaration<LynxMainThreadEvent, "[mainThreadBindtap],[mainThreadCatchtap],[mainThreadBindtouchstart],[mainThreadCatchtouchstart],[mainThreadBindtouchmove],[mainThreadCatchtouchmove],[mainThreadBindtouchend],[mainThreadCatchtouchend],[mainThreadBindmousedown],[mainThreadCatchmousedown],[mainThreadBindmousemove],[mainThreadCatchmousemove],[mainThreadBindmouseup],[mainThreadCatchmouseup],[mainThreadBindlongpress],[mainThreadCatchlongpress],[mainThreadBindscroll],[mainThreadCatchscroll],[mainThreadBindanimationstart],[mainThreadBindanimationend],[mainThreadBindtransitionend],[mainThreadBindlayoutchange]", never, {
3491
3865
  "mainThreadBindtap": {
3492
3866
  "alias": "mainThreadBindtap";
3493
3867
  "required": false;
@@ -3520,6 +3894,30 @@ export declare class LynxMainThreadEvent implements OnChanges, OnDestroy {
3520
3894
  "alias": "mainThreadCatchtouchend";
3521
3895
  "required": false;
3522
3896
  };
3897
+ "mainThreadBindmousedown": {
3898
+ "alias": "mainThreadBindmousedown";
3899
+ "required": false;
3900
+ };
3901
+ "mainThreadCatchmousedown": {
3902
+ "alias": "mainThreadCatchmousedown";
3903
+ "required": false;
3904
+ };
3905
+ "mainThreadBindmousemove": {
3906
+ "alias": "mainThreadBindmousemove";
3907
+ "required": false;
3908
+ };
3909
+ "mainThreadCatchmousemove": {
3910
+ "alias": "mainThreadCatchmousemove";
3911
+ "required": false;
3912
+ };
3913
+ "mainThreadBindmouseup": {
3914
+ "alias": "mainThreadBindmouseup";
3915
+ "required": false;
3916
+ };
3917
+ "mainThreadCatchmouseup": {
3918
+ "alias": "mainThreadCatchmouseup";
3919
+ "required": false;
3920
+ };
3523
3921
  "mainThreadBindlongpress": {
3524
3922
  "alias": "mainThreadBindlongpress";
3525
3923
  "required": false;
@@ -3555,43 +3953,23 @@ export declare class LynxMainThreadEvent implements OnChanges, OnDestroy {
3555
3953
  }, {}, never, never, true, never>;
3556
3954
  }
3557
3955
  /**
3558
- * Injectable service for calling main-thread (Lepus) functions. From the
3559
- * background thread it uses Lynx's cross-thread RPC via JSContext events:
3560
- *
3561
- * background calls runOnMainThread(handle, ...args)
3562
- * → dispatches 'Lynx.Worklet.runWorkletCtx' with { worklet, params, resolveId }
3563
- * → main thread's listener (in runtime.ts) invokes the registered worklet fn
3564
- * → dispatches 'Lynx.Worklet.FunctionCallRet' with { resolveId, returnValue }
3565
- * → background thread's listener resolves the Promise
3956
+ * Injectable service for calling main-thread (Lepus) functions from Angular
3957
+ * code, and getting their return values.
3566
3958
  *
3567
- * This enables background-thread Angular code (services, effects) to trigger
3568
- * main-thread imperative operations (animate, measure, invoke UI methods)
3569
- * with proper async/await ergonomics.
3959
+ * Angular runs on the main thread only (see bootstrapApplication), so the
3960
+ * call never crosses threads: it invokes the registered worklet in place,
3961
+ * with the arguments as they are, and resolves with its result. Non-
3962
+ * serializable values (element handles, MainThreadRefs) pass through intact.
3570
3963
  *
3571
- * It is also safe to call from code already running on the main thread. The
3572
- * renderer registers Angular `(bind*)`/`(catch*)` event handlers as main-thread
3573
- * worklets, so a handler like `(bindtap)="flash()"` executes on the Lepus thread
3574
- * — and any runOnMainThread() call it makes originates there too. Rather than
3575
- * fail (there is no other thread to be "called from"), we detect that case and
3576
- * invoke the target worklet in-place, so the same call site works regardless of
3577
- * which thread reaches it.
3964
+ * It used to send the call across threads when it ran on the background
3965
+ * thread, for the copy of the app that booted there too. That copy is gone
3966
+ * (issue #81), and with it the background-to-main call channel.
3578
3967
  */
3579
3968
  export declare class LynxMainThread {
3580
3969
  runOnMainThread<TArgs extends unknown[], TReturn>(handle: MainThreadFnHandle<TArgs, TReturn>, ...args: TArgs): Promise<TReturn>;
3581
3970
  static ɵfac: i0.ɵɵFactoryDeclaration<LynxMainThread, never>;
3582
3971
  static ɵprov: i0.ɵɵInjectableDeclaration<any>;
3583
3972
  }
3584
- declare namespace MainThread {
3585
- type Element = Element;
3586
- type TouchEvent = TouchEvent;
3587
- type MouseEvent = MouseEvent;
3588
- type WheelEvent = WheelEvent;
3589
- type KeyEvent = KeyEvent;
3590
- type AnimationEvent = AnimationEvent;
3591
- type TransitionEvent = TransitionEvent;
3592
- type LayoutChangeEvent = LayoutChangeEvent;
3593
- type UIAppearanceEvent = UIAppearanceEvent;
3594
- }
3595
3973
  /**
3596
3974
  * Resource priority hint for the native prefetch engine.
3597
3975
  */
@@ -3645,8 +4023,9 @@ type PrefetchResultDetail = {
3645
4023
  * with a Promise-based API for preloading images and videos into the native
3646
4024
  * cache before they're needed for display.
3647
4025
  *
3648
- * Only available on the background thread — these APIs are not exposed on
3649
- * the main thread.
4026
+ * Lynx has these APIs only on the background thread, while Angular runs on
4027
+ * the main thread, so the calls go through the background call relay
4028
+ * (background-call.ts).
3650
4029
  *
3651
4030
  * @usageNotes
3652
4031
  * ```typescript
@@ -3768,7 +4147,8 @@ type SessionStorageSubscription = {
3768
4147
  * subscribe/unsubscribe at all — and `getSessionStorageItem` is
3769
4148
  * *synchronous*, taking just the key and returning the value directly.
3770
4149
  * Calling it with a callback (the background-thread shape) throws a native
3771
- * "GetSessionStorageItem param size should be 1" fatal error.
4150
+ * "GetSessionStorageItem param size should be 1" fatal error. Subscriptions
4151
+ * made there go through the background thread (see background-call.ts).
3772
4152
  *
3773
4153
  * @usageNotes
3774
4154
  * ```typescript
@@ -3858,6 +4238,11 @@ export declare class LynxSessionStorage {
3858
4238
  * `SystemInfo` is populated once when the Lynx view initializes and
3859
4239
  * is read-only for the lifetime of the app — the values never change.
3860
4240
  *
4241
+ * On iOS and Android (Lynx 4.1), the main thread has no global `SystemInfo`,
4242
+ * only `lynx.SystemInfo`, so that's read first. The background thread and the
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.
4245
+ *
3861
4246
  * @usageNotes
3862
4247
  * ```typescript
3863
4248
  * const systemInfo = inject(LynxSystemInfo);
@@ -3887,7 +4272,13 @@ export declare class LynxSystemInfo {
3887
4272
  */
3888
4273
  get engineVersion(): string;
3889
4274
  /**
3890
- * 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.
3891
4282
  */
3892
4283
  get osVersion(): string;
3893
4284
  /**
@@ -4119,13 +4510,25 @@ export declare class LynxTransitionGroup<T> {
4119
4510
  /**
4120
4511
  * Central DI configuration for the Lynx renderer. Must be included in every
4121
4512
  * Lynx Angular app's providers (typically via app.config.ts). Sets up:
4122
- * 1. Thread-aware document (LynxDocument vs LynxBackgroundDocument)
4513
+ * 1. The document (LynxDocument, or LynxHydrateDocument for SSR)
4123
4514
  * 2. DOCUMENT stub (Angular requires this token but Lynx has no DOM Document)
4124
4515
  * 3. APP_BASE_HREF (prevents BrowserPlatformLocation from crashing)
4125
4516
  * 4. Renderer factory (creates LynxRenderer / EmulatedLynxRenderer)
4126
4517
  * 5. Error handler (routes to _ReportError + __lynxLastError)
4127
4518
  */
4128
4519
  export declare const provideRenderer: () => EnvironmentProviders;
4520
+ /**
4521
+ * Keeps the app on the screen it was showing when a hot update re-bootstraps
4522
+ * it. Called with the old app's injector before it's destroyed, it saves the
4523
+ * old strategy's history, and the next strategy created starts from it. The
4524
+ * router's initial navigation then goes to the current URL instead of `/`,
4525
+ * and Back still has the screens before it.
4526
+ *
4527
+ * Does nothing for an app without the router, or with another strategy.
4528
+ *
4529
+ * @param injector - The injector of the app that's about to be destroyed.
4530
+ */
4531
+ declare const carryOverLocation: (injector: Injector | undefined) => void;
4129
4532
  /**
4130
4533
  * In-memory LocationStrategy for Lynx — equivalent to React Router's MemoryRouter.
4131
4534
  *
@@ -4141,6 +4544,13 @@ export declare const provideRenderer: () => EnvironmentProviders;
4141
4544
  */
4142
4545
  export declare class LynxLocationStrategy extends LocationStrategy {
4143
4546
  #private;
4547
+ constructor();
4548
+ /**
4549
+ * Whether there's an entry before the current one, so `back()` goes
4550
+ * somewhere. The Android back button follows it (see lynx-back-button.ts):
4551
+ * while it's false, back leaves the app, as on any root screen.
4552
+ */
4553
+ readonly canGoBack: import("@angular/core").Signal<boolean>;
4144
4554
  path(): string;
4145
4555
  prepareExternalUrl(internal: string): string;
4146
4556
  getBaseHref(): string;
@@ -4193,25 +4603,32 @@ export declare class LynxPlatformLocation extends PlatformLocation {
4193
4603
  /**
4194
4604
  * Route reuse strategy that keeps component views alive across navigations.
4195
4605
  *
4196
- * ## Why this is required on Lynx
4606
+ * Opt-in: `provideRouter()` doesn't install it, so leaving a route destroys
4607
+ * its components, as Angular does on the web. Provide it yourself to keep
4608
+ * every visited route's component, and its state, alive:
4609
+ *
4610
+ * ```typescript
4611
+ * providers: [
4612
+ * provideRouter(routes),
4613
+ * { provide: RouteReuseStrategy, useClass: LynxRouteReuseStrategy },
4614
+ * ]
4615
+ * ```
4197
4616
  *
4198
- * Lynx's native element APIs (`__CreateView`, `__CreateText`, etc.) allocate
4199
- * elements in a fixed-size native pool. `__RemoveElement` detaches an element
4200
- * from the tree but does NOT free its pool slot — there is no `__ReleaseElement`
4201
- * API in Lynx's public surface. Angular's default `RouteReuseStrategy` destroys
4202
- * components on every navigation, creating fresh native elements each time. Those
4203
- * freed elements accumulate in the pool until it overflows (~256 slots on device),
4204
- * causing a hard native crash on the 9th navigation in a back-and-forth pattern.
4617
+ * Nothing is ever evicted, and `ngOnDestroy()` doesn't run when you leave a
4618
+ * route.
4205
4619
  *
4206
- * ## What this strategy does
4620
+ * ## Why it exists
4207
4621
  *
4208
- * Instead of destroying a component when navigating away, Angular calls
4209
- * `ViewContainerRef.detach()`. The component's DOM elements are removed from the
4210
- * native tree (the slots are occupied but unused). When navigating back,
4211
- * `ViewContainerRef.insert()` re-adds those same native elements to the tree —
4212
- * reusing their existing pool slots with no new allocations. The pool stays bounded
4213
- * by (initial elements) + (max elements for any single route), regardless of how
4214
- * many times the user navigates.
4622
+ * `provideRouter()` used to install it. A crash investigation in May 2026
4623
+ * blamed a ~256-slot native element pool that `__RemoveElement` never freed,
4624
+ * and detaching views was meant to reuse their elements. Neither holds on
4625
+ * Lynx 4.1 (measured October 2026 on the iOS Simulator and an Android
4626
+ * emulator, issue #68): 400 navigations between two 300-element routes
4627
+ * created 121,527 native elements without a crash, with this strategy and
4628
+ * with Angular's default alike. A re-attached view's native elements were
4629
+ * destroyed when it was detached, so `LynxElement` rebuilds them from cache
4630
+ * (`#recreateSubtree`), and a revisit creates as many elements as a fresh
4631
+ * route.
4215
4632
  */
4216
4633
  export declare class LynxRouteReuseStrategy implements RouteReuseStrategy {
4217
4634
  #private;
@@ -4252,10 +4669,193 @@ export declare const provideRouter: (routes: Routes, ...features: RouterFeatures
4252
4669
  * convention). No-op off-device where `_ReportError` is absent.
4253
4670
  */
4254
4671
  declare const reportToNative: (err: Error) => void;
4672
+ type GlobalExposureBatch = {
4673
+ type: 'exposure' | 'disexposure';
4674
+ events: GlobalExposureEvent;
4675
+ };
4676
+ /**
4677
+ * Every batch of global exposure events, on whichever thread this module runs.
4678
+ * LynxGlobalExposure subscribes.
4679
+ */
4680
+ declare const globalExposureBatches: Subject<GlobalExposureBatch>;
4681
+ /**
4682
+ * The background thread's half of the main thread's `fetch` (see fetch.ts).
4683
+ * Lynx has `fetch` on the background thread only, and Angular runs on the
4684
+ * main thread, so the main thread's `fetch` sends each request here, where
4685
+ * background-call.ts's relay runs it, and this sends the response back.
4686
+ *
4687
+ * Everything crosses as JSON. A body is text when it can be, and base64
4688
+ * otherwise, since JSON can't carry bytes.
4689
+ */
4690
+ /** A request or response body as it crosses threads. */
4691
+ type RelayedBody = {
4692
+ text: string;
4693
+ } | {
4694
+ base64: string;
4695
+ } | null;
4696
+ /** A request as the main thread sends it. */
4697
+ type RelayedRequest = {
4698
+ url: string;
4699
+ method: string;
4700
+ /** Unique names, since the main thread's Headers joins repeated ones. */
4701
+ headers: [string, string][];
4702
+ body: RelayedBody;
4703
+ /** The rest of `RequestInit`, for hosts that use it (Lynx for Web's worker). */
4704
+ options: {
4705
+ cache?: string;
4706
+ credentials?: string;
4707
+ integrity?: string;
4708
+ keepalive?: boolean;
4709
+ mode?: string;
4710
+ priority?: string;
4711
+ redirect?: string;
4712
+ referrer?: string;
4713
+ referrerPolicy?: string;
4714
+ };
4715
+ };
4716
+ /** A response as the background thread sends it back. */
4717
+ type RelayedResponse = {
4718
+ status: number;
4719
+ statusText: string;
4720
+ url: string;
4721
+ redirected: boolean;
4722
+ headers: [string, string][];
4723
+ body: RelayedBody;
4724
+ };
4725
+ /**
4726
+ * Runs a request for the main thread and resolves with the response, body
4727
+ * included. It rejects with a TypeError when the request fails, as `fetch`
4728
+ * does.
4729
+ *
4730
+ * @param id - The main thread's ID for the request, to abort it by.
4731
+ * @param request - The request.
4732
+ * @returns The response.
4733
+ */
4734
+ declare const fetchForMainThread: (id: number, request: RelayedRequest) => Promise<RelayedResponse>;
4735
+ /**
4736
+ * Aborts a request the main thread sent, when its signal aborts. The main
4737
+ * thread has already rejected its own promise; this stops the work here.
4738
+ *
4739
+ * @param id - The main thread's ID for the request.
4740
+ */
4741
+ declare const abortFetchForMainThread: (id: number) => void;
4742
+ /**
4743
+ * `__MAIN_THREAD__` is a build-time define. Unit tests don't define it, and run
4744
+ * as the background thread unless they stub it.
4745
+ *
4746
+ * @returns Whether this code runs on the main thread.
4747
+ */
4748
+ declare const isMainThread: () => boolean;
4749
+ /**
4750
+ * Prepares a relayed call's arguments: on the main thread, each function in
4751
+ * them, or in a plain object or array in them, becomes a marker that the
4752
+ * background thread calls back. Elsewhere the call runs in place, so the
4753
+ * arguments are left alone.
4754
+ *
4755
+ * @param value - The arguments, or one of them.
4756
+ * @returns The value to send.
4757
+ */
4758
+ declare const relayFunctions: (value: unknown) => unknown;
4759
+ /**
4760
+ * Prepares a JS module for registering from the main thread: its methods,
4761
+ * including ones on its prototype such as a class's, become markers bound to
4762
+ * it, and its other fields are copied.
4763
+ *
4764
+ * @param module - The module to register.
4765
+ * @returns The value to send.
4766
+ */
4767
+ declare const relayModuleObject: (module: object) => unknown;
4768
+ /** Which registry a relayed module comes from. */
4769
+ type ModuleKind = 'native' | 'js';
4770
+ declare const handlers: {
4771
+ accessibilityAnnounce: (content: string) => Promise<void>;
4772
+ addFont: (fontFamily: string, src: string) => Promise<void>;
4773
+ setObserverFrameRate: (options?: ObserverFrameRateOptions) => void;
4774
+ stopExposure: (options?: {
4775
+ sendEvent: boolean;
4776
+ }) => void;
4777
+ resumeExposure: () => void;
4778
+ /**
4779
+ * Subscribes on the background thread and sends each change to the main
4780
+ * thread, where subscribeSessionStorageFromMainThread() delivers it.
4781
+ */
4782
+ subscribeSessionStorage: (key: string, relayId: number) => void;
4783
+ unsubscribeSessionStorage: (relayId: number) => void;
4784
+ requestResourcePrefetch: (data: unknown) => Promise<unknown>;
4785
+ cancelResourcePrefetch: (data: unknown) => Promise<unknown>;
4786
+ /**
4787
+ * Calls the host's bridge method and resolves with the first value it
4788
+ * passes back. Without a bridge, such as in the web preview, it resolves
4789
+ * `undefined`, as LynxNativeModule.call() always has.
4790
+ */
4791
+ nativeBridgeCall: (name: string, params: unknown) => Promise<unknown>;
4792
+ nativeBridgeOn: (name: string, callback: unknown) => void;
4793
+ /**
4794
+ * Calls a method of a native module or a JS module. The main thread's
4795
+ * module proxies (relayedModule() below) send their calls here.
4796
+ */
4797
+ callModule: (kind: ModuleKind, name: string, method: string, args: unknown[]) => unknown;
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;
4805
+ /** The main thread's `fetch` (network/fetch.ts) sends its requests here. */
4806
+ fetch: (id: number, request: RelayedRequest) => Promise<RelayedResponse>;
4807
+ abortFetch: (id: number) => void;
4808
+ };
4809
+ type Handlers = typeof handlers;
4810
+ type HandlerName = keyof Handlers;
4811
+ /**
4812
+ * Runs a background-only Lynx API, directly on the background thread or relayed
4813
+ * from the main thread.
4814
+ */
4815
+ declare const callOnBackground: <N extends HandlerName>(name: N, ...args: Parameters<Handlers[N]>) => Promise<Awaited<ReturnType<Handlers[N]>>>;
4816
+ /**
4817
+ * Main thread: a stand-in for a native module or JS module, which only the
4818
+ * background thread can reach. Each method call runs there and returns a
4819
+ * promise of its result, and function arguments are called back here. Reading
4820
+ * `then` gives `undefined`, so the proxy isn't mistaken for a promise.
4821
+ *
4822
+ * @param kind - `'native'` for `NativeModules`, `'js'` for `lynx.getJSModule`.
4823
+ * @param name - The module's name.
4824
+ * @returns The proxy.
4825
+ */
4826
+ declare const relayedModule: (kind: ModuleKind, name: string) => object;
4827
+ /**
4828
+ * Main thread only. Subscribes to a session storage key through the background
4829
+ * thread, the only thread that can, and returns the ID to unsubscribe with.
4830
+ */
4831
+ declare const subscribeSessionStorageFromMainThread: (key: string, listener: (value: unknown) => void) => number;
4832
+ declare const unsubscribeSessionStorageFromMainThread: (relayId: number) => void;
4833
+ /**
4834
+ * Starts the background thread. The build calls it from the background
4835
+ * thread's entry, a module it generates in place of the app's `main.ts`
4836
+ * (background-entry.ts in the build plugin): Angular runs on the main thread
4837
+ * only, so the background thread loads just this runtime and the modules that
4838
+ * define a background function or a `MainThreadRef`.
4839
+ *
4840
+ * Loading the runtime installs the background half of each bridge (the imports
4841
+ * above). This installs `lynx.loadLazyBundle`, for an `import()` in a
4842
+ * background function. Importing it is also what keeps the runtime in the
4843
+ * background bundle: the package is marked `"sideEffects": false`, so a bare
4844
+ * `import '@blotch/angular-lynx'` would be dropped.
4845
+ */
4846
+ export declare const ɵstartBackgroundThread: () => void;
4255
4847
  /**
4256
4848
  * Bootstrap Angular application on the Lynx runtime. Waits for the main thread to
4257
4849
  * signal it's ready before initializing the framework, then registers global
4258
4850
  * callbacks for page updates and worklet invocations.
4851
+ *
4852
+ * Angular runs on the main thread only. The background thread starts from an
4853
+ * entry the build generates instead of `main.ts` (see
4854
+ * {@link ɵstartBackgroundThread}), so it doesn't reach this function, unless a
4855
+ * module it loads also bootstraps, such as a `main.ts` that defines a
4856
+ * `backgroundFn()` itself. Then it gets no app: the returned promise never
4857
+ * settles on that thread. Booting a second copy there ran every constructor,
4858
+ * `ngOnInit` and `effect()` twice, and its views went nowhere (issue #81).
4259
4859
  */
4260
4860
  export declare const bootstrapApplication: (rootComponent: Type<unknown>, options?: ApplicationConfig) => Promise<ApplicationRef>;
4261
4861
  declare global {
@@ -4303,25 +4903,15 @@ declare global {
4303
4903
  var __LYNX_SOURCE_LOCALE__: string;
4304
4904
  interface Window {
4305
4905
  registerWorklet: (type: string, id: string, fn: Function) => void;
4306
- __workletRefMap: Record<number, {
4906
+ __workletRefMap: Record<number | string, {
4307
4907
  current: unknown;
4308
4908
  }>;
4309
- __lynxMtsPendingResolvers: Record<number, {
4310
- resolve: (v: unknown) => void;
4311
- reject: (e: unknown) => void;
4312
- }>;
4313
- __lynxMtsNextResolveId: () => number;
4314
4909
  __lynxRunMainThreadWorklet: (wkltId: string, args: unknown[]) => unknown;
4315
4910
  }
4316
4911
  var registerWorklet: (type: string, id: string, fn: Function) => void;
4317
- var __workletRefMap: Record<number, {
4912
+ var __workletRefMap: Record<number | string, {
4318
4913
  current: unknown;
4319
4914
  }>;
4320
- var __lynxMtsPendingResolvers: Record<number, {
4321
- resolve: (v: unknown) => void;
4322
- reject: (e: unknown) => void;
4323
- }>;
4324
- var __lynxMtsNextResolveId: () => number;
4325
4915
  var __lynxRunMainThreadWorklet: (wkltId: string, args: unknown[]) => unknown;
4326
4916
  function runOnBackground(handle: {
4327
4917
  _wkltId: string;
@@ -4329,21 +4919,31 @@ declare global {
4329
4919
  }
4330
4920
  declare global {
4331
4921
  interface HTMLElementEventMap {
4332
- bindtap: TouchEvent$1;
4333
- catchtap: TouchEvent$1;
4334
- 'capture-bindtap': TouchEvent$1;
4335
- 'capture-catchtap': TouchEvent$1;
4336
- 'global-bindtap': TouchEvent$1;
4337
- bindtouchstart: TouchEvent$1;
4338
- bindtouchend: TouchEvent$1;
4339
- bindtouchmove: TouchEvent$1;
4340
- bindtouchcancel: TouchEvent$1;
4341
- bindlongpress: TouchEvent$1;
4342
- catchtouchstart: TouchEvent$1;
4343
- catchtouchend: TouchEvent$1;
4344
- catchtouchmove: TouchEvent$1;
4345
- catchtouchcancel: TouchEvent$1;
4346
- catchlongpress: TouchEvent$1;
4922
+ bindtap: TouchEvent;
4923
+ catchtap: TouchEvent;
4924
+ 'capture-bindtap': TouchEvent;
4925
+ 'capture-catchtap': TouchEvent;
4926
+ 'global-bindtap': TouchEvent;
4927
+ bindtouchstart: TouchEvent;
4928
+ bindtouchend: TouchEvent;
4929
+ bindtouchmove: TouchEvent;
4930
+ bindtouchcancel: TouchEvent;
4931
+ bindlongpress: TouchEvent;
4932
+ catchtouchstart: TouchEvent;
4933
+ catchtouchend: TouchEvent;
4934
+ catchtouchmove: TouchEvent;
4935
+ catchtouchcancel: TouchEvent;
4936
+ catchlongpress: TouchEvent;
4937
+ bindmousedown: MouseEvent;
4938
+ bindmouseup: MouseEvent;
4939
+ bindmousemove: MouseEvent;
4940
+ bindmouseenter: MouseEvent;
4941
+ bindmouseleave: MouseEvent;
4942
+ catchmousedown: MouseEvent;
4943
+ catchmouseup: MouseEvent;
4944
+ catchmousemove: MouseEvent;
4945
+ catchmouseenter: MouseEvent;
4946
+ catchmouseleave: MouseEvent;
4347
4947
  }
4348
4948
  }
4349
- export type { BackgroundFnHandle, BaseLynxAnimation, DataProcessorDefinition, DevToolsStats, ExposureEventDetail, FlingGestureEvent, GestureCallback, GestureCallbackWithState, GestureEvent, GlobalData, GlobalExposureEvent, InitData, InitDataRaw, LongPressGestureEvent, LynxAnimationOptions, LynxFontEntry, LynxFontFaceConfig, LynxFontStatus, MainThread, MainThreadFnHandle, NativeModuleMap, ObserverFrameRateOptions, PanGestureEvent, PinchGestureEvent, PortalConfig, PrefetchCacheTarget, PrefetchPriority, PrefetchRequest, PrefetchResultDetail, RotationGestureEvent, SessionStorageSubscription, TapGestureEvent };
4949
+ export type { BackgroundFnHandle, BaseLynxAnimation, DataProcessorDefinition, DevToolsStats, ExposureEventDetail, FlingGestureEvent, GestureCallback, GestureCallbackWithState, GestureEvent, GlobalData, GlobalExposureEvent, InitData, InitDataRaw, LongPressGestureEvent, LynxAnimationOptions, LynxFontEntry, LynxFontFaceConfig, LynxFontStatus, LynxTraceOptions, MainThread, MainThreadFnHandle, NativeModuleMap, NativeModuleProxy, ObserverFrameRateOptions, PanGestureEvent, PinchGestureEvent, PortalConfig, PrefetchCacheTarget, PrefetchPriority, PrefetchRequest, PrefetchResultDetail, ResourcePrefetchData, ResourcePrefetchResult, RotationGestureEvent, SessionStorageSubscription, TapGestureEvent };