@symbiote-native/angular 2.0.1 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/babel-register-composed.cjs +0 -8
- package/build/angular/callback-host.d.ts +25 -0
- package/build/angular/callback-host.js +211 -0
- package/build/angular/callback-host.js.map +1 -0
- package/build/angular/change-detection-flush.d.ts +14 -2
- package/build/angular/change-detection-flush.js +54 -6
- package/build/angular/change-detection-flush.js.map +1 -1
- package/build/angular/components/flat-list/index.js +39 -86
- package/build/angular/components/flat-list/index.js.map +1 -1
- package/build/angular/components/image-shared.js +49 -110
- package/build/angular/components/image-shared.js.map +1 -1
- package/build/angular/components/keyboard-avoiding-view/index.js +33 -72
- package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
- package/build/angular/components/modal/index.js +58 -103
- package/build/angular/components/modal/index.js.map +1 -1
- package/build/angular/components/pressable-props.d.ts +2 -0
- package/build/angular/components/section-list/index.js +20 -103
- package/build/angular/components/section-list/index.js.map +1 -1
- package/build/angular/components/touchable-props.d.ts +1 -0
- package/build/angular/components/virtualized-list/directives.js +32 -22
- package/build/angular/components/virtualized-list/directives.js.map +1 -1
- package/build/angular/components/virtualized-list/index.d.ts +7 -1
- package/build/angular/components/virtualized-list/index.js +350 -359
- package/build/angular/components/virtualized-list/index.js.map +1 -1
- package/build/angular/components/virtualized-section-list/directives.js +20 -12
- package/build/angular/components/virtualized-section-list/directives.js.map +1 -1
- package/build/angular/components/virtualized-section-list/index.js +36 -142
- package/build/angular/components/virtualized-section-list/index.js.map +1 -1
- package/build/angular/components.d.ts +1 -1
- package/build/angular/components.js +1 -1
- package/build/angular/components.js.map +1 -1
- package/build/angular/create-portal/index.js +9 -8
- package/build/angular/create-portal/index.js.map +1 -1
- package/build/angular/create-tunnel/index.js +13 -12
- package/build/angular/create-tunnel/index.js.map +1 -1
- package/build/angular/descriptor-to-angular/index.js +6 -6
- package/build/angular/descriptor-to-angular/index.js.map +1 -1
- package/build/angular/diagnostics.d.ts +13 -0
- package/build/angular/diagnostics.js +18 -0
- package/build/angular/diagnostics.js.map +1 -1
- package/build/angular/element-props.d.ts +1 -3
- package/build/angular/elements.d.ts +46 -32
- package/build/angular/elements.js +217 -434
- package/build/angular/elements.js.map +1 -1
- package/build/angular/index.d.ts +3 -1
- package/build/angular/index.js +44 -13
- package/build/angular/index.js.map +1 -1
- package/build/angular/modules/animated/animated-leaf-binder.js +0 -2
- package/build/angular/modules/animated/animated-leaf-binder.js.map +1 -1
- package/build/angular/modules/animated/create-animated-component.js +69 -74
- package/build/angular/modules/animated/create-animated-component.js.map +1 -1
- package/build/angular/modules/animated/index.d.ts +30 -19
- package/build/angular/modules/status-bar/index.js +2 -8
- package/build/angular/modules/status-bar/index.js.map +1 -1
- package/build/angular/primitives/index.d.ts +14 -28
- package/build/angular/primitives/index.js +44 -107
- package/build/angular/primitives/index.js.map +1 -1
- package/build/angular/primitives/shared.d.ts +1 -0
- package/build/angular/primitives/shared.js +47 -32
- package/build/angular/primitives/shared.js.map +1 -1
- package/build/angular/render/index.js +40 -3
- package/build/angular/render/index.js.map +1 -1
- package/build/angular/renderer/index.d.ts +80 -0
- package/build/angular/renderer/index.js +324 -114
- package/build/angular/renderer/index.js.map +1 -1
- package/build/angular/runtime-matching.d.ts +9 -0
- package/build/angular/runtime-matching.js +82 -0
- package/build/angular/runtime-matching.js.map +1 -0
- package/build/angular/services/color-scheme.service.js +4 -4
- package/build/angular/services/color-scheme.service.js.map +1 -1
- package/build/angular/services/window-dimensions.service.js +4 -4
- package/build/angular/services/window-dimensions.service.js.map +1 -1
- package/build/angular/style-host.d.ts +11 -0
- package/build/angular/style-host.js +86 -0
- package/build/angular/style-host.js.map +1 -0
- package/package.json +6 -6
- package/src/callback-host.ts +229 -0
- package/src/change-detection-flush.ts +62 -9
- package/src/components/flat-list/index.ts +2 -1
- package/src/components/keyboard-avoiding-view/index.ts +8 -0
- package/src/components/pressable-props.ts +8 -0
- package/src/components/touchable-props.ts +4 -0
- package/src/components/virtualized-list/index.ts +98 -45
- package/src/components.ts +0 -2
- package/src/diagnostics.ts +18 -0
- package/src/element-props.ts +1 -5
- package/src/elements.ts +159 -38
- package/src/index.ts +47 -14
- package/src/primitives/index.ts +14 -70
- package/src/primitives/shared.ts +21 -6
- package/src/render/index.ts +56 -2
- package/src/renderer/index.ts +378 -104
- package/src/runtime-matching.ts +80 -0
- package/src/style-host.ts +94 -0
- package/tsconfig.angular.base.json +11 -0
package/README.md
CHANGED
|
@@ -26,9 +26,9 @@ npm install @symbiote-native/angular react-native @angular/core
|
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
`react-native` and `@angular/core` (**>=20**, for stable zoneless change detection) stay your app's
|
|
29
|
-
own top-level dependencies.
|
|
30
|
-
|
|
31
|
-
[`examples/angular`](../../examples/angular) rather than a generator.
|
|
29
|
+
own top-level dependencies. `npx @symbiote-native/cli new` wires the AOT pipeline (`ngc --watch`
|
|
30
|
+
alongside Metro — see [Run it](#run-it)) and the Metro config for a new app; wiring them into an
|
|
31
|
+
existing one still follows [`examples/angular`](../../examples/angular) rather than a generator.
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
@@ -89,7 +89,8 @@ reference canaries, standalone components, zoneless change detection.
|
|
|
89
89
|
## Parity — and the one gap
|
|
90
90
|
|
|
91
91
|
Angular reaches the same 21+ primitives, runtime modules, `Animated` on both drivers, gestures,
|
|
92
|
-
accessibility, and the `VirtualizedList` family as React and Vue
|
|
92
|
+
accessibility, and the `VirtualizedList` family as React and Vue, verified on-device on iOS and
|
|
93
|
+
Android. That parity is **structural, not
|
|
93
94
|
hand-copied**: the component logic (state machines + render functions) is written **once** in
|
|
94
95
|
`@symbiote-native/components`, and Angular supplies only its lifecycle (`Renderer2` + zoneless change
|
|
95
96
|
detection + the descriptor→`createElement` bridge).
|
|
@@ -37,15 +37,7 @@ const PRIMITIVE_SELECTORS = new Set([
|
|
|
37
37
|
'horizontal-scroll-content',
|
|
38
38
|
'text-input',
|
|
39
39
|
'text-input-multiline',
|
|
40
|
-
// The COMPONENT path's pair. Only a lowering transform may emit the plain tags above — those
|
|
41
|
-
// carry the engine's TextInput machine, and this adapter's own component runs that state in
|
|
42
|
-
// its template. See `core/components/src/component-names/shared.ts`.
|
|
43
|
-
'text-input-managed',
|
|
44
|
-
'text-input-multiline-managed',
|
|
45
40
|
'switch',
|
|
46
|
-
// The component path's spelling — same native view, a tag the engine's Switch behavior does
|
|
47
|
-
// not carry. See `core/components/src/component-names/shared.ts`.
|
|
48
|
-
'switch-managed',
|
|
49
41
|
// The centering RCTView RN wraps the spinner in — the tag an app writes — plus the native
|
|
50
42
|
// spinner the ActivityIndicator behavior builds under it.
|
|
51
43
|
'activity-indicator',
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type OnChanges, type OnDestroy, type SimpleChanges } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/**
|
|
4
|
+
* THE SAME NAMES AS A LITERAL, and the duplication is forced rather than chosen.
|
|
5
|
+
*
|
|
6
|
+
* ngtsc STATICALLY EVALUATES a decorator's metadata, and a selector built with `.map().join()` is not
|
|
7
|
+
* something it can evaluate — it reports the class as `Component imports must be standalone
|
|
8
|
+
* components, directives, pipes, or must be NgModules`, which reads as a missing `standalone: true`
|
|
9
|
+
* and is not that. Thirty-seven of this adapter's compile-time guards went red on it at once.
|
|
10
|
+
*
|
|
11
|
+
* So the selector is written out, and `callback-host-selector.test.ts` holds the two in step.
|
|
12
|
+
*/
|
|
13
|
+
export declare const CALLBACK_ATTRIBUTE_SELECTOR: string;
|
|
14
|
+
/** Exported for the guard alone — the decorator below must spell its own list for ngtsc. */
|
|
15
|
+
export declare const CALLBACK_INPUT_NAMES: readonly string[];
|
|
16
|
+
export declare class SymbioteCallbackHost implements OnChanges, OnDestroy {
|
|
17
|
+
private readonly renderer;
|
|
18
|
+
private readonly host;
|
|
19
|
+
private readonly detector;
|
|
20
|
+
constructor();
|
|
21
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
22
|
+
ngOnDestroy(): void;
|
|
23
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SymbioteCallbackHost, never>;
|
|
24
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<SymbioteCallbackHost, "[onAccessibilityAction],[onAccessibilityEscape],[onAccessibilityTap],[onBlur],[onContentSizeChange],[onEndEditing],[onError],[onFocus],[onHoverIn],[onHoverOut],[onKeyPress],[onLayout],[onLoad],[onLoadEnd],[onLoadStart],[onLongPress],[onMagicTap],[onMomentumScrollBegin],[onMomentumScrollEnd],[onMoveShouldSetResponder],[onMoveShouldSetResponderCapture],[onPartialLoad],[onPress],[onPressIn],[onPressMove],[onPressOut],[onProgress],[onRefresh],[onResponderEnd],[onResponderGrant],[onResponderMove],[onResponderReject],[onResponderRelease],[onResponderStart],[onResponderTerminate],[onResponderTerminationRequest],[onScrollBeginDrag],[onScrollEndDrag],[onScrollToTop],[onSelectionChange],[onStartShouldSetResponder],[onStartShouldSetResponderCapture],[onSubmitEditing],[onValueChange]", never, { "onAccessibilityAction": { "alias": "onAccessibilityAction"; "required": false; }; "onAccessibilityEscape": { "alias": "onAccessibilityEscape"; "required": false; }; "onAccessibilityTap": { "alias": "onAccessibilityTap"; "required": false; }; "onBlur": { "alias": "onBlur"; "required": false; }; "onContentSizeChange": { "alias": "onContentSizeChange"; "required": false; }; "onEndEditing": { "alias": "onEndEditing"; "required": false; }; "onError": { "alias": "onError"; "required": false; }; "onFocus": { "alias": "onFocus"; "required": false; }; "onHoverIn": { "alias": "onHoverIn"; "required": false; }; "onHoverOut": { "alias": "onHoverOut"; "required": false; }; "onKeyPress": { "alias": "onKeyPress"; "required": false; }; "onLayout": { "alias": "onLayout"; "required": false; }; "onLoad": { "alias": "onLoad"; "required": false; }; "onLoadEnd": { "alias": "onLoadEnd"; "required": false; }; "onLoadStart": { "alias": "onLoadStart"; "required": false; }; "onLongPress": { "alias": "onLongPress"; "required": false; }; "onMagicTap": { "alias": "onMagicTap"; "required": false; }; "onMomentumScrollBegin": { "alias": "onMomentumScrollBegin"; "required": false; }; "onMomentumScrollEnd": { "alias": "onMomentumScrollEnd"; "required": false; }; "onMoveShouldSetResponder": { "alias": "onMoveShouldSetResponder"; "required": false; }; "onMoveShouldSetResponderCapture": { "alias": "onMoveShouldSetResponderCapture"; "required": false; }; "onPartialLoad": { "alias": "onPartialLoad"; "required": false; }; "onPress": { "alias": "onPress"; "required": false; }; "onPressIn": { "alias": "onPressIn"; "required": false; }; "onPressMove": { "alias": "onPressMove"; "required": false; }; "onPressOut": { "alias": "onPressOut"; "required": false; }; "onProgress": { "alias": "onProgress"; "required": false; }; "onRefresh": { "alias": "onRefresh"; "required": false; }; "onResponderEnd": { "alias": "onResponderEnd"; "required": false; }; "onResponderGrant": { "alias": "onResponderGrant"; "required": false; }; "onResponderMove": { "alias": "onResponderMove"; "required": false; }; "onResponderReject": { "alias": "onResponderReject"; "required": false; }; "onResponderRelease": { "alias": "onResponderRelease"; "required": false; }; "onResponderStart": { "alias": "onResponderStart"; "required": false; }; "onResponderTerminate": { "alias": "onResponderTerminate"; "required": false; }; "onResponderTerminationRequest": { "alias": "onResponderTerminationRequest"; "required": false; }; "onScrollBeginDrag": { "alias": "onScrollBeginDrag"; "required": false; }; "onScrollEndDrag": { "alias": "onScrollEndDrag"; "required": false; }; "onScrollToTop": { "alias": "onScrollToTop"; "required": false; }; "onSelectionChange": { "alias": "onSelectionChange"; "required": false; }; "onStartShouldSetResponder": { "alias": "onStartShouldSetResponder"; "required": false; }; "onStartShouldSetResponderCapture": { "alias": "onStartShouldSetResponderCapture"; "required": false; }; "onSubmitEditing": { "alias": "onSubmitEditing"; "required": false; }; "onValueChange": { "alias": "onValueChange"; "required": false; }; }, {}, never, never, true, never>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// The directive that owns a `ChangeDetectorRef` for the elements that actually need one.
|
|
2
|
+
//
|
|
3
|
+
// An `on*` PROP is forwarded to the engine node, and the ENGINE calls it — Angular is told nothing,
|
|
4
|
+
// so a plain field mutation inside the app's handler dirties no view. `createCallbackWrapper` fixes
|
|
5
|
+
// that with `markForCheck`, and until 2026-09-18 the ref it marked came from `SymbioteElement`
|
|
6
|
+
// injecting one on EVERY element, because any element MAY carry a callback.
|
|
7
|
+
//
|
|
8
|
+
// Almost none does. Priced on JavaScriptCore, an injection is ~1.0-2.4 us per element — 10-24 ms
|
|
9
|
+
// over the ten thousand of a thousand-row screen, all of it to build `ViewRef`s nothing reads
|
|
10
|
+
// (`core/engine/cpp/tests/js/angular-directive-cost.itest.ts`, the `ChangeDetectorRef` row).
|
|
11
|
+
//
|
|
12
|
+
// MATCHING IS THE CHEAPER QUESTION THAN INJECTING, and that had to be measured rather than assumed,
|
|
13
|
+
// because the selector below is dozens of alternatives and Angular tries a component's whole
|
|
14
|
+
// directive list against every element it creates. The ladder's `cb-probe` arm carries this exact
|
|
15
|
+
// string WITHOUT matching anything — the state of every element on the benchmark row — so the two
|
|
16
|
+
// halves are priced against each other in one process, rotated, with a resolution bar:
|
|
17
|
+
//
|
|
18
|
+
// carrying the selector 4.3 5.9 -2.0 5.7 -1.5 ms inside the bar in four of five
|
|
19
|
+
// the ChangeDetectorRef 9.7 23.5 13.6 31.3 23.8 ms
|
|
20
|
+
// the CALLBACK HOST -3.9 -9.3 -25.5 -25.6 -25.3 ms all five negative, three outside
|
|
21
|
+
//
|
|
22
|
+
// WHAT IS NOT VERIFIED, said plainly: the ladder's arm carries ONE element directive beside this one,
|
|
23
|
+
// where a real screen carries two dozen, and the `ng-elements` bench arm could not confirm the change
|
|
24
|
+
// at app scale — the machine it was measured on swung its untouched CONTROL from 229 to 566 ms, so
|
|
25
|
+
// nothing quoted off it would have carried a verdict either way. The controlled A/B is the evidence
|
|
26
|
+
// here; the bench-arm confirmation is owed.
|
|
27
|
+
//
|
|
28
|
+
// IT HOLDS NO INPUTS, which is what keeps the change off the public surface. The `on*` props stay
|
|
29
|
+
// declared on `SymbioteElement` and its subclasses, so every type and every forward is unchanged;
|
|
30
|
+
// this directive only needs to BE on the element, and a missing name in its selector costs a change
|
|
31
|
+
// detection mark rather than a prop. `callback-host-selector.test.ts` derives the list from the
|
|
32
|
+
// directives' own declared inputs so it cannot go stale quietly.
|
|
33
|
+
//
|
|
34
|
+
// A LEAF, like `change-detection-flush` and `renderer/value-change`: importing `elements.ts` from
|
|
35
|
+
// here would close a cycle, since that file is what puts this directive in `SYMBIOTE_ELEMENTS`.
|
|
36
|
+
import { ChangeDetectorRef, Directive, ElementRef, Renderer2, inject, } from '@angular/core';
|
|
37
|
+
import { registerViewMarker, unregisterViewMarker, } from './change-detection-flush';
|
|
38
|
+
import * as i0 from "@angular/core";
|
|
39
|
+
/**
|
|
40
|
+
* Every `on*` input any element directive declares, except the one that fires per FRAME.
|
|
41
|
+
*
|
|
42
|
+
* `onScroll` is absent deliberately and not by oversight: with sticky headers RN pins
|
|
43
|
+
* `scrollEventThrottle` to 1, and `markForCheck` walks to the root, so wrapping it cost the canary
|
|
44
|
+
* ~37fps. `isWrappableCallback` excludes it, and the guard test asserts this string does too.
|
|
45
|
+
*/
|
|
46
|
+
const CALLBACK_INPUTS = [
|
|
47
|
+
'onAccessibilityAction',
|
|
48
|
+
'onAccessibilityEscape',
|
|
49
|
+
'onAccessibilityTap',
|
|
50
|
+
'onBlur',
|
|
51
|
+
'onChangeText',
|
|
52
|
+
'onContentSizeChange',
|
|
53
|
+
'onEndEditing',
|
|
54
|
+
'onError',
|
|
55
|
+
'onFocus',
|
|
56
|
+
'onHoverIn',
|
|
57
|
+
'onHoverOut',
|
|
58
|
+
'onKeyPress',
|
|
59
|
+
'onLayout',
|
|
60
|
+
'onLoad',
|
|
61
|
+
'onLoadEnd',
|
|
62
|
+
'onLoadStart',
|
|
63
|
+
'onLongPress',
|
|
64
|
+
'onMagicTap',
|
|
65
|
+
'onMomentumScrollBegin',
|
|
66
|
+
'onMomentumScrollEnd',
|
|
67
|
+
'onMoveShouldSetResponder',
|
|
68
|
+
'onMoveShouldSetResponderCapture',
|
|
69
|
+
'onPartialLoad',
|
|
70
|
+
'onPress',
|
|
71
|
+
'onPressIn',
|
|
72
|
+
'onPressMove',
|
|
73
|
+
'onPressOut',
|
|
74
|
+
'onProgress',
|
|
75
|
+
'onRefresh',
|
|
76
|
+
'onResponderEnd',
|
|
77
|
+
'onResponderGrant',
|
|
78
|
+
'onResponderMove',
|
|
79
|
+
'onResponderReject',
|
|
80
|
+
'onResponderRelease',
|
|
81
|
+
'onResponderStart',
|
|
82
|
+
'onResponderTerminate',
|
|
83
|
+
'onResponderTerminationRequest',
|
|
84
|
+
'onScrollBeginDrag',
|
|
85
|
+
'onScrollEndDrag',
|
|
86
|
+
'onScrollToTop',
|
|
87
|
+
'onSelectionChange',
|
|
88
|
+
'onStartShouldSetResponder',
|
|
89
|
+
'onStartShouldSetResponderCapture',
|
|
90
|
+
'onSubmitEditing',
|
|
91
|
+
'onValueChange',
|
|
92
|
+
];
|
|
93
|
+
/**
|
|
94
|
+
* THE SAME NAMES AS A LITERAL, and the duplication is forced rather than chosen.
|
|
95
|
+
*
|
|
96
|
+
* ngtsc STATICALLY EVALUATES a decorator's metadata, and a selector built with `.map().join()` is not
|
|
97
|
+
* something it can evaluate — it reports the class as `Component imports must be standalone
|
|
98
|
+
* components, directives, pipes, or must be NgModules`, which reads as a missing `standalone: true`
|
|
99
|
+
* and is not that. Thirty-seven of this adapter's compile-time guards went red on it at once.
|
|
100
|
+
*
|
|
101
|
+
* So the selector is written out, and `callback-host-selector.test.ts` holds the two in step.
|
|
102
|
+
*/
|
|
103
|
+
export const CALLBACK_ATTRIBUTE_SELECTOR = '[onAccessibilityAction],[onAccessibilityEscape],[onAccessibilityTap],[onBlur],' +
|
|
104
|
+
'[onChangeText],[onContentSizeChange],[onEndEditing],[onError],[onFocus],[onHoverIn],[onHoverOut],' +
|
|
105
|
+
'[onKeyPress],[onLayout],[onLoad],[onLoadEnd],[onLoadStart],[onLongPress],[onMagicTap],' +
|
|
106
|
+
'[onMomentumScrollBegin],[onMomentumScrollEnd],[onMoveShouldSetResponder],' +
|
|
107
|
+
'[onMoveShouldSetResponderCapture],[onPartialLoad],[onPress],[onPressIn],[onPressMove],' +
|
|
108
|
+
'[onPressOut],[onProgress],[onRefresh],[onResponderEnd],[onResponderGrant],[onResponderMove],' +
|
|
109
|
+
'[onResponderReject],[onResponderRelease],[onResponderStart],[onResponderTerminate],' +
|
|
110
|
+
'[onResponderTerminationRequest],[onScrollBeginDrag],[onScrollEndDrag],[onScrollToTop],' +
|
|
111
|
+
'[onSelectionChange],[onStartShouldSetResponder],[onStartShouldSetResponderCapture],' +
|
|
112
|
+
'[onSubmitEditing],[onValueChange]';
|
|
113
|
+
/** Exported for the guard alone — the decorator below must spell its own list for ngtsc. */
|
|
114
|
+
export const CALLBACK_INPUT_NAMES = CALLBACK_INPUTS;
|
|
115
|
+
export class SymbioteCallbackHost {
|
|
116
|
+
constructor() {
|
|
117
|
+
this.renderer = inject(Renderer2);
|
|
118
|
+
this.host = inject(ElementRef);
|
|
119
|
+
this.detector = inject(ChangeDetectorRef);
|
|
120
|
+
const node = this.host.nativeElement;
|
|
121
|
+
if (typeof node === 'object' && node !== null)
|
|
122
|
+
registerViewMarker(node, this.detector);
|
|
123
|
+
}
|
|
124
|
+
ngOnChanges(changes) {
|
|
125
|
+
// The renderer wraps the value on its way through, so this forwards it raw — same shape as the
|
|
126
|
+
// tag directives' own forward, and the only place a withheld tag's callback can now come from.
|
|
127
|
+
for (const name of Object.keys(changes))
|
|
128
|
+
this.renderer.setProperty(this.host.nativeElement, name, changes[name]?.currentValue);
|
|
129
|
+
}
|
|
130
|
+
ngOnDestroy() {
|
|
131
|
+
const node = this.host.nativeElement;
|
|
132
|
+
if (typeof node === 'object' && node !== null)
|
|
133
|
+
unregisterViewMarker(node);
|
|
134
|
+
}
|
|
135
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SymbioteCallbackHost, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
136
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.8", type: SymbioteCallbackHost, isStandalone: true, selector: "[onAccessibilityAction],[onAccessibilityEscape],[onAccessibilityTap],[onBlur],[onContentSizeChange],[onEndEditing],[onError],[onFocus],[onHoverIn],[onHoverOut],[onKeyPress],[onLayout],[onLoad],[onLoadEnd],[onLoadStart],[onLongPress],[onMagicTap],[onMomentumScrollBegin],[onMomentumScrollEnd],[onMoveShouldSetResponder],[onMoveShouldSetResponderCapture],[onPartialLoad],[onPress],[onPressIn],[onPressMove],[onPressOut],[onProgress],[onRefresh],[onResponderEnd],[onResponderGrant],[onResponderMove],[onResponderReject],[onResponderRelease],[onResponderStart],[onResponderTerminate],[onResponderTerminationRequest],[onScrollBeginDrag],[onScrollEndDrag],[onScrollToTop],[onSelectionChange],[onStartShouldSetResponder],[onStartShouldSetResponderCapture],[onSubmitEditing],[onValueChange]", inputs: { onAccessibilityAction: "onAccessibilityAction", onAccessibilityEscape: "onAccessibilityEscape", onAccessibilityTap: "onAccessibilityTap", onBlur: "onBlur", onContentSizeChange: "onContentSizeChange", onEndEditing: "onEndEditing", onError: "onError", onFocus: "onFocus", onHoverIn: "onHoverIn", onHoverOut: "onHoverOut", onKeyPress: "onKeyPress", onLayout: "onLayout", onLoad: "onLoad", onLoadEnd: "onLoadEnd", onLoadStart: "onLoadStart", onLongPress: "onLongPress", onMagicTap: "onMagicTap", onMomentumScrollBegin: "onMomentumScrollBegin", onMomentumScrollEnd: "onMomentumScrollEnd", onMoveShouldSetResponder: "onMoveShouldSetResponder", onMoveShouldSetResponderCapture: "onMoveShouldSetResponderCapture", onPartialLoad: "onPartialLoad", onPress: "onPress", onPressIn: "onPressIn", onPressMove: "onPressMove", onPressOut: "onPressOut", onProgress: "onProgress", onRefresh: "onRefresh", onResponderEnd: "onResponderEnd", onResponderGrant: "onResponderGrant", onResponderMove: "onResponderMove", onResponderReject: "onResponderReject", onResponderRelease: "onResponderRelease", onResponderStart: "onResponderStart", onResponderTerminate: "onResponderTerminate", onResponderTerminationRequest: "onResponderTerminationRequest", onScrollBeginDrag: "onScrollBeginDrag", onScrollEndDrag: "onScrollEndDrag", onScrollToTop: "onScrollToTop", onSelectionChange: "onSelectionChange", onStartShouldSetResponder: "onStartShouldSetResponder", onStartShouldSetResponderCapture: "onStartShouldSetResponderCapture", onSubmitEditing: "onSubmitEditing", onValueChange: "onValueChange" }, usesOnChanges: true, ngImport: i0 }); }
|
|
137
|
+
}
|
|
138
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SymbioteCallbackHost, decorators: [{
|
|
139
|
+
type: Directive,
|
|
140
|
+
args: [{
|
|
141
|
+
selector: '[onAccessibilityAction],[onAccessibilityEscape],[onAccessibilityTap],[onBlur],' +
|
|
142
|
+
'[onContentSizeChange],[onEndEditing],[onError],[onFocus],[onHoverIn],[onHoverOut],' +
|
|
143
|
+
'[onKeyPress],[onLayout],[onLoad],[onLoadEnd],[onLoadStart],[onLongPress],[onMagicTap],' +
|
|
144
|
+
'[onMomentumScrollBegin],[onMomentumScrollEnd],[onMoveShouldSetResponder],' +
|
|
145
|
+
'[onMoveShouldSetResponderCapture],[onPartialLoad],[onPress],[onPressIn],[onPressMove],' +
|
|
146
|
+
'[onPressOut],[onProgress],[onRefresh],[onResponderEnd],[onResponderGrant],[onResponderMove],' +
|
|
147
|
+
'[onResponderReject],[onResponderRelease],[onResponderStart],[onResponderTerminate],' +
|
|
148
|
+
'[onResponderTerminationRequest],[onScrollBeginDrag],[onScrollEndDrag],[onScrollToTop],' +
|
|
149
|
+
'[onSelectionChange],[onStartShouldSetResponder],[onStartShouldSetResponderCapture],' +
|
|
150
|
+
'[onSubmitEditing],[onValueChange]',
|
|
151
|
+
// DECLARED, and this is not an optimisation — it is what makes withholding the tag directives
|
|
152
|
+
// possible at all. `ɵɵproperty` on an element no directive claimed ends in `setDomProperty`, which
|
|
153
|
+
// runs `validateAgainstEventProperties` and THROWS NG0306 on any name beginning with `on`
|
|
154
|
+
// (upstream `sanitization/sanitization.ts:267`). So an `on*` prop is not merely unwrapped without a
|
|
155
|
+
// claiming input — it is a hard runtime error, and the first attempt at this change hit it on the
|
|
156
|
+
// first test that binds one.
|
|
157
|
+
//
|
|
158
|
+
// The TYPES still come from `SymbioteElement` and its subclasses, which ngtsc goes on matching from
|
|
159
|
+
// the decorator's selector however empty the runtime array is. Angular requires an expression to
|
|
160
|
+
// satisfy EVERY directive that claims the input, so a permissive declaration here cannot loosen the
|
|
161
|
+
// exact one there.
|
|
162
|
+
inputs: [
|
|
163
|
+
'onAccessibilityAction',
|
|
164
|
+
'onAccessibilityEscape',
|
|
165
|
+
'onAccessibilityTap',
|
|
166
|
+
'onBlur',
|
|
167
|
+
'onContentSizeChange',
|
|
168
|
+
'onEndEditing',
|
|
169
|
+
'onError',
|
|
170
|
+
'onFocus',
|
|
171
|
+
'onHoverIn',
|
|
172
|
+
'onHoverOut',
|
|
173
|
+
'onKeyPress',
|
|
174
|
+
'onLayout',
|
|
175
|
+
'onLoad',
|
|
176
|
+
'onLoadEnd',
|
|
177
|
+
'onLoadStart',
|
|
178
|
+
'onLongPress',
|
|
179
|
+
'onMagicTap',
|
|
180
|
+
'onMomentumScrollBegin',
|
|
181
|
+
'onMomentumScrollEnd',
|
|
182
|
+
'onMoveShouldSetResponder',
|
|
183
|
+
'onMoveShouldSetResponderCapture',
|
|
184
|
+
'onPartialLoad',
|
|
185
|
+
'onPress',
|
|
186
|
+
'onPressIn',
|
|
187
|
+
'onPressMove',
|
|
188
|
+
'onPressOut',
|
|
189
|
+
'onProgress',
|
|
190
|
+
'onRefresh',
|
|
191
|
+
'onResponderEnd',
|
|
192
|
+
'onResponderGrant',
|
|
193
|
+
'onResponderMove',
|
|
194
|
+
'onResponderReject',
|
|
195
|
+
'onResponderRelease',
|
|
196
|
+
'onResponderStart',
|
|
197
|
+
'onResponderTerminate',
|
|
198
|
+
'onResponderTerminationRequest',
|
|
199
|
+
'onScrollBeginDrag',
|
|
200
|
+
'onScrollEndDrag',
|
|
201
|
+
'onScrollToTop',
|
|
202
|
+
'onSelectionChange',
|
|
203
|
+
'onStartShouldSetResponder',
|
|
204
|
+
'onStartShouldSetResponderCapture',
|
|
205
|
+
'onSubmitEditing',
|
|
206
|
+
'onValueChange',
|
|
207
|
+
],
|
|
208
|
+
standalone: true,
|
|
209
|
+
}]
|
|
210
|
+
}], ctorParameters: () => [] });
|
|
211
|
+
//# sourceMappingURL=callback-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-host.js","sourceRoot":"","sources":["../../src/callback-host.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
interface IViewMarker {
|
|
2
2
|
markForCheck(): void;
|
|
3
3
|
}
|
|
4
|
-
type ICallbackWrapper = (key: string, value: unknown) => unknown;
|
|
4
|
+
export type ICallbackWrapper = (key: string, value: unknown) => unknown;
|
|
5
|
+
/**
|
|
6
|
+
* Is this prop write one the wrapper would touch at all?
|
|
7
|
+
*
|
|
8
|
+
* Exported so a CALLER can ask before building a wrapper it may never need — an element directive is
|
|
9
|
+
* constructed per TAG, and a screen's tags overwhelmingly carry no `on*` function prop. Keeping the
|
|
10
|
+
* question here rather than copying the two tests at the call site is what stops the predicate and
|
|
11
|
+
* the wrapper drifting apart.
|
|
12
|
+
*/
|
|
13
|
+
export declare function isWrappableCallback(key: string, value: unknown): boolean;
|
|
5
14
|
/**
|
|
6
15
|
* Makes an app callback handed to the engine as a PROP re-enter Angular's update loop.
|
|
7
16
|
*
|
|
@@ -24,7 +33,10 @@ type ICallbackWrapper = (key: string, value: unknown) => unknown;
|
|
|
24
33
|
* ONE wrapper per original handler, for the caller's lifetime. A fresh closure per push would make
|
|
25
34
|
* the engine store a new listener every time and would defeat every downstream identity check.
|
|
26
35
|
*/
|
|
27
|
-
export declare function createCallbackWrapper(
|
|
36
|
+
export declare function createCallbackWrapper(node: unknown): ICallbackWrapper;
|
|
37
|
+
export declare function registerViewMarker(node: object, marker: IViewMarker): void;
|
|
38
|
+
export declare function unregisterViewMarker(node: object): void;
|
|
39
|
+
export declare function markViewFor(node: unknown): void;
|
|
28
40
|
export declare function registerViewFlush(node: object, flush: () => void): void;
|
|
29
41
|
export declare function unregisterViewFlush(node: object): void;
|
|
30
42
|
export declare function flushViewFor(node: unknown): void;
|
|
@@ -51,6 +51,19 @@ const ON_PREFIX = /^on[A-Z]/;
|
|
|
51
51
|
// typically an Animated.event touching no Angular state. Drag and momentum begin/end stay wrapped;
|
|
52
52
|
// once per gesture is not a hot path.
|
|
53
53
|
const PER_FRAME_CALLBACK = 'onScroll';
|
|
54
|
+
/**
|
|
55
|
+
* Is this prop write one the wrapper would touch at all?
|
|
56
|
+
*
|
|
57
|
+
* Exported so a CALLER can ask before building a wrapper it may never need — an element directive is
|
|
58
|
+
* constructed per TAG, and a screen's tags overwhelmingly carry no `on*` function prop. Keeping the
|
|
59
|
+
* question here rather than copying the two tests at the call site is what stops the predicate and
|
|
60
|
+
* the wrapper drifting apart.
|
|
61
|
+
*/
|
|
62
|
+
export function isWrappableCallback(key, value) {
|
|
63
|
+
return (ON_PREFIX.test(key) &&
|
|
64
|
+
typeof value === 'function' &&
|
|
65
|
+
key !== PER_FRAME_CALLBACK);
|
|
66
|
+
}
|
|
54
67
|
/**
|
|
55
68
|
* Makes an app callback handed to the engine as a PROP re-enter Angular's update loop.
|
|
56
69
|
*
|
|
@@ -73,13 +86,18 @@ const PER_FRAME_CALLBACK = 'onScroll';
|
|
|
73
86
|
* ONE wrapper per original handler, for the caller's lifetime. A fresh closure per push would make
|
|
74
87
|
* the engine store a new listener every time and would defeat every downstream identity check.
|
|
75
88
|
*/
|
|
76
|
-
export function createCallbackWrapper(
|
|
77
|
-
|
|
89
|
+
export function createCallbackWrapper(node) {
|
|
90
|
+
// Allocated on the FIRST wrap, not at construction. The map is per-CALLER, so an eager one is one
|
|
91
|
+
// `WeakMap` per directive instance — 7 000 on a 1 000-row create of the benchmark row, none of
|
|
92
|
+
// which is ever read, because that row carries no `on*` prop.
|
|
93
|
+
let wrappers;
|
|
78
94
|
return (key, value) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
95
|
+
// The second test is redundant at RUNTIME and load-bearing for the TYPE: `isWrappableCallback`
|
|
96
|
+
// answers a boolean, which narrows nothing, and the alternative is a cast. Keeping the `typeof`
|
|
97
|
+
// here is what lets `value` be a `Function` below without one.
|
|
98
|
+
if (!isWrappableCallback(key, value) || typeof value !== 'function')
|
|
82
99
|
return value;
|
|
100
|
+
wrappers ??= new WeakMap();
|
|
83
101
|
const cached = wrappers.get(value);
|
|
84
102
|
if (cached !== undefined)
|
|
85
103
|
return cached;
|
|
@@ -88,7 +106,7 @@ export function createCallbackWrapper(view, node) {
|
|
|
88
106
|
// `undefined` as the receiver preserves the previous unbound call.
|
|
89
107
|
const wrapper = (...args) => {
|
|
90
108
|
const result = Reflect.apply(value, undefined, args);
|
|
91
|
-
|
|
109
|
+
markViewFor(node);
|
|
92
110
|
flushViewFor(node);
|
|
93
111
|
return result;
|
|
94
112
|
};
|
|
@@ -96,6 +114,36 @@ export function createCallbackWrapper(view, node) {
|
|
|
96
114
|
return wrapper;
|
|
97
115
|
};
|
|
98
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* The MARKER half, keyed on the node rather than injected.
|
|
119
|
+
*
|
|
120
|
+
* `markForCheck` needs the view holding the binding, and until 2026-09-18 the only way to have one
|
|
121
|
+
* was for `SymbioteElement` to inject a `ChangeDetectorRef` — on EVERY element, so that its lazy
|
|
122
|
+
* `on*` wrapper could reach one on the few that carry a callback. An injection is ~1-2.4 us per
|
|
123
|
+
* element on JavaScriptCore (`core/engine/cpp/tests/js/angular-directive-cost.itest.ts`), so a
|
|
124
|
+
* thousand-row screen paid for ten thousand `ViewRef`s to serve none.
|
|
125
|
+
*
|
|
126
|
+
* `SymbioteCallbackHost` registers here instead, and it MATCHES on the callback attributes rather
|
|
127
|
+
* than being injected — so an element with no `on*` binding neither instantiates it nor pays for it.
|
|
128
|
+
* Measured as the whole trade, selector included: -3.9 / -9.3 / -25.5 ms over ten thousand elements.
|
|
129
|
+
*
|
|
130
|
+
* Separate from `viewFlushes` deliberately. They come from different directives, on overlapping but
|
|
131
|
+
* different sets of tags, and they are not the same instruction: this one SCHEDULES and reaches every
|
|
132
|
+
* ancestor, that one re-checks ONE view synchronously. Collapsing them into a single entry would make
|
|
133
|
+
* whichever directive registered last decide which of the two an element gets.
|
|
134
|
+
*/
|
|
135
|
+
const viewMarkers = new WeakMap();
|
|
136
|
+
export function registerViewMarker(node, marker) {
|
|
137
|
+
viewMarkers.set(node, marker);
|
|
138
|
+
}
|
|
139
|
+
export function unregisterViewMarker(node) {
|
|
140
|
+
viewMarkers.delete(node);
|
|
141
|
+
}
|
|
142
|
+
export function markViewFor(node) {
|
|
143
|
+
if (typeof node !== 'object' || node === null)
|
|
144
|
+
return;
|
|
145
|
+
viewMarkers.get(node)?.markForCheck();
|
|
146
|
+
}
|
|
99
147
|
export function registerViewFlush(node, flush) {
|
|
100
148
|
viewFlushes.set(node, flush);
|
|
101
149
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-detection-flush.js","sourceRoot":"","sources":["../../src/change-detection-flush.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,kGAAkG;AAClG,kCAAkC;AAClC,EAAE;AACF,sEAAsE;AACtE,kFAAkF;AAClF,6FAA6F;AAC7F,iGAAiG;AACjG,oGAAoG;AACpG,6DAA6D;AAC7D,EAAE;AACF,+FAA+F;AAC/F,iFAAiF;AACjF,sFAAsF;AACtF,EAAE;AACF,mGAAmG;AACnG,2FAA2F;AAC3F,qGAAqG;AACrG,0DAA0D;AAC1D,EAAE;AACF,gGAAgG;AAChG,4FAA4F;AAC5F,kGAAkG;AAClG,mGAAmG;AACnG,oGAAoG;AACpG,iGAAiG;AACjG,6FAA6F;AAC7F,oGAAoG;AACpG,oGAAoG;AACpG,kFAAkF;AAClF,yFAAyF;AACzF,gGAAgG;AAChG,iEAAiE;AACjE,EAAE;AACF,6FAA6F;AAC7F,oGAAoG;AACpG,4FAA4F;AAC5F,kGAAkG;AAClG,oBAAoB;AACpB,EAAE;AACF,6FAA6F;AAC7F,yEAAyE;AACzE,mCAAmC;AACnC,MAAM,WAAW,GAAG,IAAI,OAAO,EAAsB,CAAC;AAEtD,MAAM,SAAS,GAAG,UAAU,CAAC;AAE7B,2FAA2F;AAC3F,oGAAoG;AACpG,gGAAgG;AAChG,mGAAmG;AACnG,oGAAoG;AACpG,mGAAmG;AACnG,sCAAsC;AACtC,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAQtC
|
|
1
|
+
{"version":3,"file":"change-detection-flush.js","sourceRoot":"","sources":["../../src/change-detection-flush.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,kGAAkG;AAClG,kCAAkC;AAClC,EAAE;AACF,sEAAsE;AACtE,kFAAkF;AAClF,6FAA6F;AAC7F,iGAAiG;AACjG,oGAAoG;AACpG,6DAA6D;AAC7D,EAAE;AACF,+FAA+F;AAC/F,iFAAiF;AACjF,sFAAsF;AACtF,EAAE;AACF,mGAAmG;AACnG,2FAA2F;AAC3F,qGAAqG;AACrG,0DAA0D;AAC1D,EAAE;AACF,gGAAgG;AAChG,4FAA4F;AAC5F,kGAAkG;AAClG,mGAAmG;AACnG,oGAAoG;AACpG,iGAAiG;AACjG,6FAA6F;AAC7F,oGAAoG;AACpG,oGAAoG;AACpG,kFAAkF;AAClF,yFAAyF;AACzF,gGAAgG;AAChG,iEAAiE;AACjE,EAAE;AACF,6FAA6F;AAC7F,oGAAoG;AACpG,4FAA4F;AAC5F,kGAAkG;AAClG,oBAAoB;AACpB,EAAE;AACF,6FAA6F;AAC7F,yEAAyE;AACzE,mCAAmC;AACnC,MAAM,WAAW,GAAG,IAAI,OAAO,EAAsB,CAAC;AAEtD,MAAM,SAAS,GAAG,UAAU,CAAC;AAE7B,2FAA2F;AAC3F,oGAAoG;AACpG,gGAAgG;AAChG,mGAAmG;AACnG,oGAAoG;AACpG,mGAAmG;AACnG,sCAAsC;AACtC,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAQtC;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,KAAc;IAC7D,OAAO,CACL,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;QACnB,OAAO,KAAK,KAAK,UAAU;QAC3B,GAAG,KAAK,kBAAkB,CAC3B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,kGAAkG;IAClG,+FAA+F;IAC/F,8DAA8D;IAC9D,IAAI,QAAsE,CAAC;IAC3E,OAAO,CAAC,GAAW,EAAE,KAAc,EAAW,EAAE;QAC9C,+FAA+F;QAC/F,gGAAgG;QAChG,+DAA+D;QAC/D,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,KAAK,KAAK,UAAU;YACjE,OAAO,KAAK,CAAC;QACf,QAAQ,KAAK,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,gGAAgG;QAChG,iGAAiG;QACjG,mEAAmE;QACnE,MAAM,OAAO,GAAG,CAAC,GAAG,IAAe,EAAW,EAAE;YAC9C,MAAM,MAAM,GAAY,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;YAC9D,WAAW,CAAC,IAAI,CAAC,CAAC;YAClB,YAAY,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QACF,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC7B,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,GAAG,IAAI,OAAO,EAAuB,CAAC;AAEvD,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,MAAmB;IAClE,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO;IACtD,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,KAAiB;IAC/D,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAa;IACxC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO;IACtD,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -68,77 +68,42 @@ function asItem(value) {
|
|
|
68
68
|
}
|
|
69
69
|
export { VListEmptyDirective, VListFooterDirective, VListHeaderDirective, VListItemDirective, VListSeparatorDirective, } from '../virtualized-list';
|
|
70
70
|
export class FlatList {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
onScrollBeginDrag;
|
|
108
|
-
onScrollEndDrag;
|
|
109
|
-
onMomentumScrollBegin;
|
|
110
|
-
onMomentumScrollEnd;
|
|
111
|
-
scrollEventThrottle;
|
|
112
|
-
keyboardShouldPersistTaps;
|
|
113
|
-
keyboardDismissMode;
|
|
114
|
-
style;
|
|
115
|
-
contentContainerStyle;
|
|
116
|
-
// The app's cell + slot templates, captured for the multi-column re-stamp path. In the
|
|
117
|
-
// single-column path they are ALSO projected through <ng-content> to the inner list and these
|
|
118
|
-
// captures stay unused (the inner list's own @ContentChild resolves them across the projection).
|
|
119
|
-
itemDir;
|
|
120
|
-
headerDir;
|
|
121
|
-
footerDir;
|
|
122
|
-
emptyDir;
|
|
123
|
-
separatorDir;
|
|
124
|
-
// The composed inner list (whichever numColumns branch rendered). Its instance IS the
|
|
125
|
-
// IVirtualizedListHandle, so FlatList's handle delegates straight to it.
|
|
126
|
-
listRef;
|
|
127
|
-
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
128
|
-
// onto (see anchorHostStyle's doc comment) — NOT `listRef` above, which targets the real inner
|
|
129
|
-
// `<VirtualizedList>` one level down (itself its own separate anchor host).
|
|
130
|
-
elementRef = inject(ElementRef);
|
|
131
|
-
// --- derived view state (recomputed in ngOnChanges, stable identity across CD) ---
|
|
132
|
-
rows = [];
|
|
133
|
-
// Angular's [style]="…" binding compiles to the built-in ɵɵstyleMap instruction (NOT a
|
|
134
|
-
// regular @Input() property write), which only understands a flat object — an array (RN's
|
|
135
|
-
// own `style={[a, b]}` composition idiom) crashes deep inside Angular's styling engine. So
|
|
136
|
-
// every style value this component stamps onto a template `[style]=` binding is flattened
|
|
137
|
-
// via the engine's own flattenStyle first, here at the source rather than at each call site.
|
|
138
|
-
rowStyle = flattenStyle([{ flexDirection: 'row' }]);
|
|
139
|
-
rowViewabilityPairs;
|
|
140
|
-
columnCellStyle = { flex: 1 };
|
|
141
|
-
resolvedStyle = undefined;
|
|
71
|
+
constructor() {
|
|
72
|
+
// The list's edge/viewability/failure events as real Angular events: `(endReached)="…"`, not
|
|
73
|
+
// `[onEndReached]="…"` — re-emitted straight from the inner VirtualizedList's own @Output()s (see
|
|
74
|
+
// the template's `(endReached)="endReached.emit($event)"` style forwarding above).
|
|
75
|
+
this.endReached = new EventEmitter();
|
|
76
|
+
this.startReached = new EventEmitter();
|
|
77
|
+
this.refresh = new EventEmitter();
|
|
78
|
+
this.viewableItemsChanged = new EventEmitter();
|
|
79
|
+
this.scrollToIndexFailed = new EventEmitter();
|
|
80
|
+
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
81
|
+
// onto (see anchorHostStyle's doc comment) — NOT `listRef` above, which targets the real inner
|
|
82
|
+
// `<VirtualizedList>` one level down (itself its own separate anchor host).
|
|
83
|
+
this.elementRef = inject(ElementRef);
|
|
84
|
+
// --- derived view state (recomputed in ngOnChanges, stable identity across CD) ---
|
|
85
|
+
this.rows = [];
|
|
86
|
+
// Angular's [style]="…" binding compiles to the built-in ɵɵstyleMap instruction (NOT a
|
|
87
|
+
// regular @Input() property write), which only understands a flat object — an array (RN's
|
|
88
|
+
// own `style={[a, b]}` composition idiom) crashes deep inside Angular's styling engine. So
|
|
89
|
+
// every style value this component stamps onto a template `[style]=` binding is flattened
|
|
90
|
+
// via the engine's own flattenStyle first, here at the source rather than at each call site.
|
|
91
|
+
this.rowStyle = flattenStyle([{ flexDirection: 'row' }]);
|
|
92
|
+
this.columnCellStyle = { flex: 1 };
|
|
93
|
+
this.resolvedStyle = undefined;
|
|
94
|
+
// ---- single-column data adaptation (plain array -> getItem/getItemCount) ----
|
|
95
|
+
this.getFlatItem = (_data, index) => this.data[index];
|
|
96
|
+
this.getFlatCount = (_data) => this.data.length;
|
|
97
|
+
// ---- multi-column data adaptation (the virtualized stream is rows) ----
|
|
98
|
+
this.getRow = (_data, index) => this.rows[index];
|
|
99
|
+
this.getRowCount = (_data) => this.rows.length;
|
|
100
|
+
this.rowKey = (row, _index) => rowKeyExtractor(row, this.keyExtractor);
|
|
101
|
+
// Viewability over rows expands back to per-item tokens, so the caller sees item-level
|
|
102
|
+
// visibility, not row-level (shared expandRowViewability), matching Vue.
|
|
103
|
+
this.rowViewableItemsChanged = (info) => {
|
|
104
|
+
this.viewableItemsChanged.emit(expandRowViewability(info, this.keyExtractor));
|
|
105
|
+
};
|
|
106
|
+
}
|
|
142
107
|
get columns() {
|
|
143
108
|
return this.numColumns ?? SINGLE_COLUMN;
|
|
144
109
|
}
|
|
@@ -176,18 +141,6 @@ export class FlatList {
|
|
|
176
141
|
this.rowViewabilityPairs = this.buildRowViewabilityPairs();
|
|
177
142
|
}
|
|
178
143
|
}
|
|
179
|
-
// ---- single-column data adaptation (plain array -> getItem/getItemCount) ----
|
|
180
|
-
getFlatItem = (_data, index) => this.data[index];
|
|
181
|
-
getFlatCount = (_data) => this.data.length;
|
|
182
|
-
// ---- multi-column data adaptation (the virtualized stream is rows) ----
|
|
183
|
-
getRow = (_data, index) => this.rows[index];
|
|
184
|
-
getRowCount = (_data) => this.rows.length;
|
|
185
|
-
rowKey = (row, _index) => rowKeyExtractor(row);
|
|
186
|
-
// Viewability over rows expands back to per-item tokens, so the caller sees item-level
|
|
187
|
-
// visibility, not row-level (shared expandRowViewability), matching Vue.
|
|
188
|
-
rowViewableItemsChanged = (info) => {
|
|
189
|
-
this.viewableItemsChanged.emit(expandRowViewability(info, this.keyExtractor));
|
|
190
|
-
};
|
|
191
144
|
buildRowViewabilityPairs() {
|
|
192
145
|
return this.viewabilityConfigCallbackPairs?.map(pair => ({
|
|
193
146
|
viewabilityConfig: pair.viewabilityConfig,
|
|
@@ -270,8 +223,8 @@ export class FlatList {
|
|
|
270
223
|
recordInteraction() {
|
|
271
224
|
this.listRef?.recordInteraction();
|
|
272
225
|
}
|
|
273
|
-
static
|
|
274
|
-
static
|
|
226
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FlatList, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
227
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FlatList, isStandalone: true, selector: "FlatList", inputs: { data: "data", testID: "testID", numColumns: "numColumns", columnWrapperStyle: "columnWrapperStyle", keyExtractor: "keyExtractor", getItemLayout: "getItemLayout", horizontal: "horizontal", inverted: "inverted", extraData: "extraData", onEndReachedThreshold: "onEndReachedThreshold", onStartReachedThreshold: "onStartReachedThreshold", refreshing: "refreshing", progressViewOffset: "progressViewOffset", viewabilityConfig: "viewabilityConfig", viewabilityConfigCallbackPairs: "viewabilityConfigCallbackPairs", initialNumToRender: "initialNumToRender", initialScrollIndex: "initialScrollIndex", maxToRenderPerBatch: "maxToRenderPerBatch", updateCellsBatchingPeriod: "updateCellsBatchingPeriod", windowSize: "windowSize", stickyHeaderIndices: "stickyHeaderIndices", maintainVisibleContentPosition: "maintainVisibleContentPosition", onScroll: "onScroll", onScrollBeginDrag: "onScrollBeginDrag", onScrollEndDrag: "onScrollEndDrag", onMomentumScrollBegin: "onMomentumScrollBegin", onMomentumScrollEnd: "onMomentumScrollEnd", scrollEventThrottle: "scrollEventThrottle", keyboardShouldPersistTaps: "keyboardShouldPersistTaps", keyboardDismissMode: "keyboardDismissMode", style: "style", contentContainerStyle: "contentContainerStyle" }, outputs: { endReached: "endReached", startReached: "startReached", refresh: "refresh", viewableItemsChanged: "viewableItemsChanged", scrollToIndexFailed: "scrollToIndexFailed" }, queries: [{ propertyName: "itemDir", first: true, predicate: VListItemDirective, descendants: true }, { propertyName: "headerDir", first: true, predicate: VListHeaderDirective, descendants: true }, { propertyName: "footerDir", first: true, predicate: VListFooterDirective, descendants: true }, { propertyName: "emptyDir", first: true, predicate: VListEmptyDirective, descendants: true }, { propertyName: "separatorDir", first: true, predicate: VListSeparatorDirective, descendants: true }], viewQueries: [{ propertyName: "listRef", first: true, predicate: VirtualizedList, descendants: true }], usesOnChanges: true, hostDirectives: [{ directive: i1.SymbioteStyleInputDirective, inputs: ["style", "style"] }], ngImport: i0, template: `
|
|
275
228
|
@if (isMultiColumn) {
|
|
276
229
|
<VirtualizedList
|
|
277
230
|
[data]="rows"
|
|
@@ -440,7 +393,7 @@ export class FlatList {
|
|
|
440
393
|
}
|
|
441
394
|
</VirtualizedList>
|
|
442
395
|
}
|
|
443
|
-
`, isInline: true, dependencies: [{ kind: "component", type: VirtualizedList, selector: "VirtualizedList", inputs: ["data", "getItem", "getItemCount", "keyExtractor", "getItemLayout", "horizontal", "inverted", "extraData", "onEndReachedThreshold", "onStartReachedThreshold", "refreshing", "progressViewOffset", "refreshRequested", "viewabilityConfig", "viewabilityConfigCallbackPairs", "initialNumToRender", "initialScrollIndex", "maxToRenderPerBatch", "updateCellsBatchingPeriod", "windowSize", "stickyHeaderIndices", "maintainVisibleContentPosition", "onScroll", "onScrollBeginDrag", "onScrollEndDrag", "onMomentumScrollBegin", "onMomentumScrollEnd", "scrollEventThrottle", "keyboardShouldPersistTaps", "keyboardDismissMode", "style", "contentContainerStyle", "testID", "nativeID", "accessible", "accessibilityLabel", "accessibilityHint", "accessibilityRole", "accessibilityState", "accessibilityValue", "accessibilityActions", "accessibilityLabelledBy", "importantForAccessibility", "accessibilityLiveRegion", "screenReaderFocusable", "accessibilityViewIsModal", "accessibilityElementsHidden", "accessibilityIgnoresInvertColors", "accessibilityLanguage", "accessibilityRespondsToUserInteraction", "accessibilityShowsLargeContentViewer", "accessibilityLargeContentTitle", "role", "ariaLabel", "ariaLabelledBy", "ariaLive", "ariaHidden", "ariaBusy", "ariaChecked", "ariaDisabled", "ariaExpanded", "ariaSelected", "ariaModal", "ariaValueMax", "ariaValueMin", "ariaValueNow", "ariaValueText"], outputs: ["endReached", "startReached", "refresh", "viewableItemsChanged", "scrollToIndexFailed", "accessibilityAction", "accessibilityTap", "magicTap", "accessibilityEscape"] }, { kind: "directive", type: VListItemDirective, selector: "[vListItem]" }, { kind: "directive", type: VListHeaderDirective, selector: "[vListHeader]" }, { kind: "directive", type: VListFooterDirective, selector: "[vListFooter]" }, { kind: "directive", type: VListEmptyDirective, selector: "[vListEmpty]" }, { kind: "directive", type: VListSeparatorDirective, selector: "[vListSeparator]" }, { kind: "directive", type: VListOutletDirective, selector: "[vListOutlet]", inputs: ["vListOutlet", "vListOutletContext"] }, { kind: "component", type: ViewHost, selector: "view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
396
|
+
`, isInline: true, dependencies: [{ kind: "component", type: VirtualizedList, selector: "VirtualizedList", inputs: ["data", "getItem", "getItemCount", "keyExtractor", "getItemLayout", "horizontal", "inverted", "extraData", "onEndReachedThreshold", "onStartReachedThreshold", "refreshing", "progressViewOffset", "refreshRequested", "viewabilityConfig", "viewabilityConfigCallbackPairs", "initialNumToRender", "initialScrollIndex", "maxToRenderPerBatch", "updateCellsBatchingPeriod", "windowSize", "stickyHeaderIndices", "maintainVisibleContentPosition", "onScroll", "onScrollBeginDrag", "onScrollEndDrag", "onMomentumScrollBegin", "onMomentumScrollEnd", "scrollEventThrottle", "keyboardShouldPersistTaps", "keyboardDismissMode", "style", "contentContainerStyle", "testID", "nativeID", "accessible", "accessibilityLabel", "accessibilityHint", "accessibilityRole", "accessibilityState", "accessibilityValue", "accessibilityActions", "accessibilityLabelledBy", "importantForAccessibility", "accessibilityLiveRegion", "screenReaderFocusable", "accessibilityViewIsModal", "accessibilityElementsHidden", "accessibilityIgnoresInvertColors", "accessibilityLanguage", "accessibilityRespondsToUserInteraction", "accessibilityShowsLargeContentViewer", "accessibilityLargeContentTitle", "role", "ariaLabel", "ariaLabelledBy", "ariaLive", "ariaHidden", "ariaBusy", "ariaChecked", "ariaDisabled", "ariaExpanded", "ariaSelected", "ariaModal", "ariaValueMax", "ariaValueMin", "ariaValueNow", "ariaValueText"], outputs: ["endReached", "startReached", "refresh", "viewableItemsChanged", "scrollToIndexFailed", "accessibilityAction", "accessibilityTap", "magicTap", "accessibilityEscape"] }, { kind: "directive", type: VListItemDirective, selector: "[vListItem]" }, { kind: "directive", type: VListHeaderDirective, selector: "[vListHeader]" }, { kind: "directive", type: VListFooterDirective, selector: "[vListFooter]" }, { kind: "directive", type: VListEmptyDirective, selector: "[vListEmpty]" }, { kind: "directive", type: VListSeparatorDirective, selector: "[vListSeparator]" }, { kind: "directive", type: VListOutletDirective, selector: "[vListOutlet]", inputs: ["vListOutlet", "vListOutletContext"] }, { kind: "component", type: ViewHost, selector: "view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
444
397
|
}
|
|
445
398
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FlatList, decorators: [{
|
|
446
399
|
type: Component,
|