@symbiote-native/angular 3.1.3 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/angular/accessibility-events.d.ts +12 -0
- package/build/angular/accessibility-events.js +28 -0
- package/build/angular/accessibility-events.js.map +1 -0
- package/build/angular/accessibility-inputs.d.ts +40 -0
- package/build/angular/accessibility-inputs.js +130 -0
- package/build/angular/accessibility-inputs.js.map +1 -0
- package/build/angular/bootstrap.d.ts +3 -1
- package/build/angular/bootstrap.js +4 -1
- package/build/angular/bootstrap.js.map +1 -1
- package/build/angular/components/flat-list/flat-list-template.d.ts +1 -0
- package/build/angular/components/flat-list/flat-list-template.js +158 -0
- package/build/angular/components/flat-list/flat-list-template.js.map +1 -0
- package/build/angular/components/flat-list/index.d.ts +6 -61
- package/build/angular/components/flat-list/index.js +26 -463
- package/build/angular/components/flat-list/index.js.map +1 -1
- package/build/angular/components/keyboard-avoiding-view/index.d.ts +4 -40
- package/build/angular/components/keyboard-avoiding-view/index.js +7 -131
- package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
- package/build/angular/components/modal/index.d.ts +5 -41
- package/build/angular/components/modal/index.js +8 -133
- package/build/angular/components/modal/index.js.map +1 -1
- package/build/angular/components/section-list/index.d.ts +4 -51
- package/build/angular/components/section-list/index.js +18 -335
- package/build/angular/components/section-list/index.js.map +1 -1
- package/build/angular/components/virtualized-list/cell-registry.d.ts +35 -0
- package/build/angular/components/virtualized-list/cell-registry.js +133 -0
- package/build/angular/components/virtualized-list/cell-registry.js.map +1 -0
- package/build/angular/components/virtualized-list/index.d.ts +18 -253
- package/build/angular/components/virtualized-list/index.js +112 -1178
- package/build/angular/components/virtualized-list/index.js.map +1 -1
- package/build/angular/components/virtualized-list/list-a11y-forward.d.ts +1 -0
- package/build/angular/components/virtualized-list/list-a11y-forward.js +42 -0
- package/build/angular/components/virtualized-list/list-a11y-forward.js.map +1 -0
- package/build/angular/components/virtualized-list/list-bags.d.ts +32 -0
- package/build/angular/components/virtualized-list/list-bags.js +120 -0
- package/build/angular/components/virtualized-list/list-bags.js.map +1 -0
- package/build/angular/components/virtualized-list/list-effects.d.ts +31 -0
- package/build/angular/components/virtualized-list/list-effects.js +83 -0
- package/build/angular/components/virtualized-list/list-effects.js.map +1 -0
- package/build/angular/components/virtualized-list/list-events.d.ts +17 -0
- package/build/angular/components/virtualized-list/list-events.js +34 -0
- package/build/angular/components/virtualized-list/list-events.js.map +1 -0
- package/build/angular/components/virtualized-list/list-handle.d.ts +35 -0
- package/build/angular/components/virtualized-list/list-handle.js +61 -0
- package/build/angular/components/virtualized-list/list-handle.js.map +1 -0
- package/build/angular/components/virtualized-list/list-inputs.d.ts +78 -0
- package/build/angular/components/virtualized-list/list-inputs.js +150 -0
- package/build/angular/components/virtualized-list/list-inputs.js.map +1 -0
- package/build/angular/components/virtualized-list/list-props.d.ts +58 -0
- package/build/angular/components/virtualized-list/list-props.js +3 -0
- package/build/angular/components/virtualized-list/list-props.js.map +1 -0
- package/build/angular/components/virtualized-list/list-styles.d.ts +23 -0
- package/build/angular/components/virtualized-list/list-styles.js +26 -0
- package/build/angular/components/virtualized-list/list-styles.js.map +1 -0
- package/build/angular/components/virtualized-list/list-template.d.ts +1 -0
- package/build/angular/components/virtualized-list/list-template.js +176 -0
- package/build/angular/components/virtualized-list/list-template.js.map +1 -0
- package/build/angular/components/virtualized-section-list/index.d.ts +13 -70
- package/build/angular/components/virtualized-section-list/index.js +22 -455
- package/build/angular/components/virtualized-section-list/index.js.map +1 -1
- package/build/angular/components/virtualized-section-list/section-list-template.d.ts +1 -0
- package/build/angular/components/virtualized-section-list/section-list-template.js +107 -0
- package/build/angular/components/virtualized-section-list/section-list-template.js.map +1 -0
- package/build/angular/finalization-registry.d.ts +4 -0
- package/build/angular/finalization-registry.js +17 -0
- package/build/angular/finalization-registry.js.map +1 -0
- package/build/angular/index.d.ts +5 -1
- package/build/angular/index.js +5 -1
- package/build/angular/index.js.map +1 -1
- package/build/angular/native-view-base.d.ts +19 -0
- package/build/angular/native-view-base.js +48 -0
- package/build/angular/native-view-base.js.map +1 -0
- package/build/angular/render/index.d.ts +2 -1
- package/build/angular/render/index.js +46 -73
- package/build/angular/render/index.js.map +1 -1
- package/build/angular/services/connect-watched-signal.d.ts +2 -0
- package/build/angular/services/connect-watched-signal.js +9 -0
- package/build/angular/services/connect-watched-signal.js.map +1 -0
- package/build/angular/services/create-event-value-hook.d.ts +3 -0
- package/build/angular/services/create-event-value-hook.js +17 -0
- package/build/angular/services/create-event-value-hook.js.map +1 -0
- package/build/angular/services/create-resource-hook.d.ts +7 -0
- package/build/angular/services/create-resource-hook.js +20 -0
- package/build/angular/services/create-resource-hook.js.map +1 -0
- package/build/angular/services/index.d.ts +4 -0
- package/build/angular/services/index.js +4 -0
- package/build/angular/services/index.js.map +1 -1
- package/build/angular/services/permissions-service-base.d.ts +14 -0
- package/build/angular/services/permissions-service-base.js +38 -0
- package/build/angular/services/permissions-service-base.js.map +1 -0
- package/package.json +6 -6
- package/src/accessibility-events.ts +13 -0
- package/src/accessibility-inputs.ts +89 -0
- package/src/bootstrap.ts +6 -2
- package/src/components/flat-list/flat-list-template.ts +159 -0
- package/src/components/flat-list/index.ts +30 -307
- package/src/components/keyboard-avoiding-view/index.ts +4 -78
- package/src/components/modal/index.ts +7 -80
- package/src/components/section-list/index.ts +21 -172
- package/src/components/virtualized-list/cell-registry.ts +199 -0
- package/src/components/virtualized-list/index.ts +145 -1181
- package/src/components/virtualized-list/list-a11y-forward.ts +42 -0
- package/src/components/virtualized-list/list-bags.ts +142 -0
- package/src/components/virtualized-list/list-effects.ts +116 -0
- package/src/components/virtualized-list/list-events.ts +31 -0
- package/src/components/virtualized-list/list-handle.ts +92 -0
- package/src/components/virtualized-list/list-inputs.ts +149 -0
- package/src/components/virtualized-list/list-props.ts +81 -0
- package/src/components/virtualized-list/list-styles.ts +62 -0
- package/src/components/virtualized-list/list-template.ts +175 -0
- package/src/components/virtualized-section-list/index.ts +40 -351
- package/src/components/virtualized-section-list/section-list-template.ts +108 -0
- package/src/finalization-registry.ts +18 -0
- package/src/index.ts +12 -1
- package/src/native-view-base.ts +51 -0
- package/src/render/index.ts +76 -77
- package/src/services/connect-watched-signal.ts +15 -0
- package/src/services/create-event-value-hook.ts +24 -0
- package/src/services/create-resource-hook.ts +32 -0
- package/src/services/index.ts +4 -0
- package/src/services/permissions-service-base.ts +46 -0
|
@@ -1,339 +1,66 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// committedWindow throttle and assembles the windowed cells before the template bindings are read),
|
|
8
|
-
// and the after-commit work (batch fill, onEndReached/onStartReached, viewability, initialScroll, MVCP)
|
|
9
|
-
// in ngAfterViewChecked. OnPush + ChangeDetectorRef.markForCheck() drives re-render off the native
|
|
10
|
-
// scroll/layout/measure callbacks (they fire outside Angular's own event bindings, so they must
|
|
11
|
-
// mark the view dirty). This is the Angular twin of the React useReducer/useEffect and Vue
|
|
12
|
-
// ref/computed/watch over the same shared functions. It writes the `scroll-view`/
|
|
13
|
-
// `horizontal-scroll-view` TAG directly, exactly as the React/Vue lists drive their scroll tag.
|
|
14
|
-
//
|
|
15
|
-
// Per-item rendering is TEMPLATES, not a callback: React/Vue `renderItem: (info) => element` does
|
|
16
|
-
// not translate to Angular. The app supplies the cell via `<ng-template vListItem>` (and the
|
|
17
|
-
// header/footer/empty/separator slots via vListHeader/vListFooter/vListEmpty/vListSeparator); the
|
|
18
|
-
// list captures them with @ContentChild and stamps the WINDOWED slice through VListOutletDirective
|
|
19
|
-
// (a core-only NgTemplateOutlet twin — @angular/common is not a dependency). See ./directives.ts.
|
|
20
|
-
// Every React/Vue behavior is present (windowing, onEndReached, viewability, headers/footers/empty/
|
|
21
|
-
// separators, refresh, imperative scroll, horizontal, inverted, MVCP); only the cell AUTHORING
|
|
22
|
-
// shape differs, since a callback prop returning an element has no Angular equivalent.
|
|
23
|
-
//
|
|
24
|
-
// Lists have no Descriptor render fn — the cell content is the framework's own children.
|
|
25
|
-
// Cells/spacers are plain view host elements.
|
|
26
|
-
import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, Input, Output, TemplateRef, ViewChild, computed, inject, signal, } from '@angular/core';
|
|
27
|
-
import { DEFAULT_INITIAL_NUM_TO_RENDER, DEFAULT_MAX_TO_RENDER_PER_BATCH, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD, DEFAULT_WINDOW_SIZE, EMPTY_OFFSET, FIRST_INDEX, INVERTED_X_STYLE, INVERTED_Y_STYLE, buildListPlan, buildViewabilityPairs, computeWindow, createInitialListState, isSeparatorGapInRange, listEffectSignature, readLayoutLength, readLayoutOffset, readScrollOffset, reduceList, resolveAccessibilityProps, resolveItemKey, buildScrollViewHandle, } from '@symbiote-native/components';
|
|
28
|
-
import { dlog, flattenStyle, isSymbioteNode, } from '@symbiote-native/engine';
|
|
1
|
+
// Angular lifecycle half of VirtualizedList, the windowing engine is shared with React and Vue
|
|
2
|
+
// The bound surface is in ./list-inputs.ts, cells in ./cell-registry.ts, effects in
|
|
3
|
+
// ./list-effects.ts, styles in ./list-styles.ts and the authoring templates in ./directives.ts
|
|
4
|
+
import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, ViewChild, inject, } from '@angular/core';
|
|
5
|
+
import { EMPTY_OFFSET, FIRST_INDEX, LIST_ACTION_KIND, buildListPlan, buildScrollViewHandle, buildViewabilityPairs, computeWindow, createInitialListState, listEffectSignature, reduceList, resolveItemKey, } from '@symbiote-native/components';
|
|
6
|
+
import { dlog, isSymbioteNode, } from '@symbiote-native/engine';
|
|
29
7
|
import { countAngular } from '../../diagnostics';
|
|
30
8
|
import { anchorHostStyle, SymbioteHostPropsDirective, SymbioteStyleInputDirective, ViewHost, } from '../../primitives';
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
9
|
+
import { CellRegistry } from './cell-registry';
|
|
10
|
+
import { VListOutletDirective } from './directives';
|
|
11
|
+
import { ListEffectRunner } from './list-effects';
|
|
12
|
+
import { VirtualizedListBagsBase } from './list-bags';
|
|
13
|
+
import { resolveListStyles } from './list-styles';
|
|
14
|
+
import { VIRTUALIZED_LIST_TEMPLATE } from './list-template';
|
|
33
15
|
import * as i0 from "@angular/core";
|
|
34
16
|
import * as i1 from "../../primitives/shared";
|
|
35
17
|
export { VListEmptyDirective, VListFooterDirective, VListHeaderDirective, VListItemDirective, VListSeparatorDirective, } from './directives';
|
|
36
|
-
|
|
37
|
-
// TAG, never a prop — `<horizontal-scroll-view>` vs `<scroll-view>`, matching every other adapter,
|
|
38
|
-
// `.claude/rules/host-primitive-tier.md`). No shared-outlet primitive exists to de-duplicate this
|
|
39
|
-
// (this package's own NgTemplateOutlet twin is keyed on a per-cell context, not a static block, and
|
|
40
|
-
// ngc's partial evaluator needs the decorator's `template` to be one literal), so the body is
|
|
41
|
-
// duplicated across the two branches — the same shape Svelte's own `{#if horizontal}` takes.
|
|
42
|
-
export class VirtualizedList {
|
|
18
|
+
export class VirtualizedList extends VirtualizedListBagsBase {
|
|
43
19
|
constructor() {
|
|
44
|
-
|
|
45
|
-
// `[onEndReached]="…"`. See handleRefresh/accessibility*Tick below for how the still-callback-
|
|
46
|
-
// shaped scroll-view/refresh-control bag keys are fed from these.
|
|
47
|
-
this.endReached = new EventEmitter();
|
|
48
|
-
this.startReached = new EventEmitter();
|
|
49
|
-
this.refresh = new EventEmitter();
|
|
50
|
-
this.viewableItemsChanged = new EventEmitter();
|
|
51
|
-
this.scrollToIndexFailed = new EventEmitter();
|
|
52
|
-
this.accessibilityAction = new EventEmitter();
|
|
53
|
-
this.accessibilityTap = new EventEmitter();
|
|
54
|
-
this.magicTap = new EventEmitter();
|
|
55
|
-
this.accessibilityEscape = new EventEmitter();
|
|
56
|
-
// This wrapper binds the four gated accessibility events on the component it renders, which
|
|
57
|
-
// Angular forces to be unconditional and which would light that component's gates on every
|
|
58
|
-
// instance. It answers for them instead — see `gate-demand.ts`.
|
|
59
|
-
this.gateDemandAbove = injectGateDemandAbove();
|
|
60
|
-
// `buildScrollViewHandle` reads the node lazily through the getter above and no-ops before
|
|
61
|
-
// commit — the same function every other adapter feeds from its own host-instance accessor.
|
|
20
|
+
super(...arguments);
|
|
62
21
|
this.scrollHandle = buildScrollViewHandle(() => this.scrollNode);
|
|
63
|
-
//
|
|
22
|
+
// Template-bound view state, assembled by `recomputeView` in `ngDoCheck`
|
|
64
23
|
this.itemCount = EMPTY_OFFSET;
|
|
65
24
|
this.windowCells = [];
|
|
66
|
-
// The nearest sticky
|
|
67
|
-
// Angular twin of RN's _ensureClosestStickyHeader. Rendered ahead of windowCells, right after the
|
|
68
|
-
// leading spacer, with gapSpacerStyle filling the gap to the window's own first cell — see
|
|
69
|
-
// buildListPlan's doc comment for the exact child order this assumes.
|
|
25
|
+
// The nearest sticky cell mounted outside the window, `gapSpacerStyle` fills up to the window
|
|
70
26
|
this.forcedStickyCell = null;
|
|
71
27
|
this.leadingSpacerStyle = null;
|
|
72
28
|
this.gapSpacerStyle = null;
|
|
73
29
|
this.trailingSpacerStyle = null;
|
|
74
30
|
this.cellStyle = undefined;
|
|
75
|
-
//
|
|
76
|
-
// ɵɵstyleMap instruction — it only understands a flat object, never an array (RN's own
|
|
77
|
-
// `style={[a, b]}` composition idiom crashes deep inside Angular's styling engine), so this
|
|
78
|
-
// is always pre-flattened via the engine's own flattenStyle, never left as an array.
|
|
79
|
-
this.resolvedStyle = undefined;
|
|
80
|
-
this.resolvedContentContainerStyle = undefined;
|
|
81
|
-
this.resolvedMaintainVisibleContentPosition = undefined;
|
|
82
|
-
// The offset we are imperatively driving native to before the scroll handle attaches (rides down
|
|
83
|
-
// as contentOffset). A fresh object identity each push so the commit re-applies a repeated value.
|
|
84
|
-
this.commandedOffset = undefined;
|
|
85
|
-
// The one folded state cell (the Angular twin of React's stateRef): scroll offset, viewport,
|
|
86
|
-
// measured lengths, committed window, edge/viewability dedup, MVCP anchor — all in IListState,
|
|
87
|
-
// driven by the shared reduceList. `renderVersion` bumps whenever a transition changes render
|
|
88
|
-
// state, so ngDoCheck's recompute-dedup can detect it (listState is a plain object, not tracked).
|
|
31
|
+
// `renderVersion` bumps on every transition that changes render state, for the recompute dedup
|
|
89
32
|
this.listState = createInitialListState();
|
|
90
33
|
this.renderVersion = EMPTY_OFFSET;
|
|
91
|
-
this.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// Everything a cell's CONTENT can depend on that is not its own item identity. RN's contract for
|
|
106
|
-
// "re-render the cells, the data object itself did not change" is extraData; without it here an
|
|
107
|
-
// extraData flip would reuse every context and repaint nothing.
|
|
108
|
-
this.cellContextEpoch = undefined;
|
|
109
|
-
this.separatorOverrides = new Map();
|
|
110
|
-
// The adapter-owned debounce (minimumViewTime) and incremental-fill timers; the reducer only
|
|
111
|
-
// hands back a delay.
|
|
112
|
-
this.viewableTimer = null;
|
|
113
|
-
this.batchTimer = null;
|
|
114
|
-
// Dedupes the after-commit effects: they run only when the windowing signature changed.
|
|
34
|
+
this.cells = new CellRegistry({
|
|
35
|
+
itemAt: index => this.getItem(this.data, index),
|
|
36
|
+
itemCount: () => this.listState.metrics.count,
|
|
37
|
+
isHorizontal: () => this.isHorizontal,
|
|
38
|
+
markForCheck: () => this.cdr.markForCheck(),
|
|
39
|
+
measured: (index, length, offset) => this.dispatch({ kind: LIST_ACTION_KIND.measure, index, length, offset }),
|
|
40
|
+
});
|
|
41
|
+
this.effects = new ListEffectRunner({
|
|
42
|
+
scrollToPixel: (offset, animated) => this.scrollToPixel(offset, animated),
|
|
43
|
+
dispatch: action => this.dispatch(action),
|
|
44
|
+
endReached: this.endReached,
|
|
45
|
+
startReached: this.startReached,
|
|
46
|
+
scrollToIndexFailed: this.scrollToIndexFailed,
|
|
47
|
+
});
|
|
115
48
|
this.lastEffectSignature = '';
|
|
116
|
-
//
|
|
117
|
-
// windowCells (and each cell's `separators` handle — fresh closures every call) on EVERY CD pass,
|
|
118
|
-
// including ones triggered by something else entirely in the app. A fresh context object flows
|
|
119
|
-
// into VListOutletDirective, which (correctly) sees its `context` @Input() change and calls
|
|
120
|
-
// `viewRef.markForCheck()` — which reschedules ANOTHER change-detection tick via the zoneless
|
|
121
|
-
// scheduler (adapters/angular/src/render.ts). Recomputing unconditionally therefore free-runs
|
|
122
|
-
// forever the moment a list actually has cells to stamp (a real, previously-dormant bug only
|
|
123
|
-
// exposed once flat-list.test.ts's projection fix let cells render for the first time — see that
|
|
124
|
-
// test's comment). Guarding recompute behind "did anything relevant actually change" breaks the
|
|
125
|
-
// cycle: unrelated CD passes reuse the same windowCells/context identities, so
|
|
126
|
-
// VListOutletDirective's ngOnChanges sees no change and never reschedules.
|
|
49
|
+
// Without this dedup a rebuilt cell context reschedules another tick and the list free-runs
|
|
127
50
|
this.lastRecompute = undefined;
|
|
128
51
|
this.cdr = inject(ChangeDetectorRef);
|
|
129
|
-
// This component's
|
|
130
|
-
// onto (see anchorHostStyle's doc comment) — NOT `scrollHostRef` above, which targets the real
|
|
131
|
-
// inner `<scroll-view>`/`<horizontal-scroll-view>` tag one level down.
|
|
52
|
+
// This component's own host, the anchor that `class="..."` at the use site resolves onto
|
|
132
53
|
this.elementRef = inject(ElementRef);
|
|
133
|
-
// Bridges the non-reactive @Input fields into the reactive graph so `foldedAccessibility` below
|
|
134
|
-
// can memoize a bag derived from them (read its own comment for why signal inputs are not an
|
|
135
|
-
// option while this package's unit suite runs on JIT).
|
|
136
|
-
//
|
|
137
|
-
// ONLY safe for a bag whose every dependency is an @Input. This list's window machinery
|
|
138
|
-
// (listState, renderVersion, windowCells, the measured metrics) is driven from scroll/layout
|
|
139
|
-
// callbacks that never touch ngOnChanges, so nothing derived from it may ride this signal - it
|
|
140
|
-
// would memoize a window that stops re-computing mid-scroll. Make that state its own signal
|
|
141
|
-
// instead of widening this one.
|
|
142
|
-
this.inputsRevision = signal(0, /* @ts-ignore */
|
|
143
|
-
...(ngDevMode ? [{ debugName: "inputsRevision" }] : /* istanbul ignore next */ []));
|
|
144
|
-
// MEASURED (while ScrollView was still a wrapper): the template fed 20 separate inputs off this
|
|
145
|
-
// one bag, and Angular does not cache a getter across binding expressions - as a getter it
|
|
146
|
-
// rebuilt the object 20 times per refresh, and every consumer saw a fresh reference, so all 20
|
|
147
|
-
// reported "changed" and wrote through. A computed evaluates once and hands back the SAME object
|
|
148
|
-
// until an input actually changes. Every dependency below is an @Input, which is what makes
|
|
149
|
-
// inputsRevision a complete dependency set here — `scrollViewBag()` reuses this result rather
|
|
150
|
-
// than re-running the fold.
|
|
151
|
-
this.foldedAccessibility = computed(() => {
|
|
152
|
-
this.inputsRevision();
|
|
153
|
-
return resolveAccessibilityProps({
|
|
154
|
-
testID: this.testID,
|
|
155
|
-
nativeID: this.nativeID,
|
|
156
|
-
accessible: this.accessible,
|
|
157
|
-
accessibilityLabel: this.accessibilityLabel,
|
|
158
|
-
accessibilityHint: this.accessibilityHint,
|
|
159
|
-
accessibilityRole: this.accessibilityRole,
|
|
160
|
-
accessibilityState: this.accessibilityState,
|
|
161
|
-
accessibilityValue: this.accessibilityValue,
|
|
162
|
-
accessibilityActions: this.accessibilityActions,
|
|
163
|
-
accessibilityLabelledBy: this.accessibilityLabelledBy,
|
|
164
|
-
importantForAccessibility: this.importantForAccessibility,
|
|
165
|
-
accessibilityLiveRegion: this.accessibilityLiveRegion,
|
|
166
|
-
screenReaderFocusable: this.screenReaderFocusable,
|
|
167
|
-
accessibilityViewIsModal: this.accessibilityViewIsModal,
|
|
168
|
-
accessibilityElementsHidden: this.accessibilityElementsHidden,
|
|
169
|
-
accessibilityIgnoresInvertColors: this.accessibilityIgnoresInvertColors,
|
|
170
|
-
accessibilityLanguage: this.accessibilityLanguage,
|
|
171
|
-
accessibilityRespondsToUserInteraction: this.accessibilityRespondsToUserInteraction,
|
|
172
|
-
accessibilityShowsLargeContentViewer: this.accessibilityShowsLargeContentViewer,
|
|
173
|
-
accessibilityLargeContentTitle: this.accessibilityLargeContentTitle,
|
|
174
|
-
role: this.role,
|
|
175
|
-
'aria-label': this.ariaLabel,
|
|
176
|
-
'aria-labelledby': this.ariaLabelledBy,
|
|
177
|
-
'aria-live': this.ariaLive,
|
|
178
|
-
'aria-hidden': this.ariaHidden,
|
|
179
|
-
'aria-busy': this.ariaBusy,
|
|
180
|
-
'aria-checked': this.ariaChecked,
|
|
181
|
-
'aria-disabled': this.ariaDisabled,
|
|
182
|
-
'aria-expanded': this.ariaExpanded,
|
|
183
|
-
'aria-selected': this.ariaSelected,
|
|
184
|
-
'aria-modal': this.ariaModal,
|
|
185
|
-
'aria-valuemax': this.ariaValueMax,
|
|
186
|
-
'aria-valuemin': this.ariaValueMin,
|
|
187
|
-
'aria-valuenow': this.ariaValueNow,
|
|
188
|
-
'aria-valuetext': this.ariaValueText,
|
|
189
|
-
});
|
|
190
|
-
}, /* @ts-ignore */
|
|
191
|
-
...(ngDevMode ? [{ debugName: "foldedAccessibility" }] : /* istanbul ignore next */ []));
|
|
192
|
-
// onScroll stays a plain callback bag key (an Animated.event(...) target must be able to flow
|
|
193
|
-
// through it, which an @Output() can't carry), so this is a stable arrow field read straight into
|
|
194
|
-
// scrollViewBag()'s `onScroll`. onLayout is unconditional too — this list always needs its own
|
|
195
|
-
// layout for windowing, regardless of whether an app subscribes to anything.
|
|
196
|
-
this.onScrollTick = (event) => {
|
|
197
|
-
countAngular('scrollTicks');
|
|
198
|
-
const offset = readScrollOffset(event, this.isHorizontal);
|
|
199
|
-
if (offset === undefined)
|
|
200
|
-
return;
|
|
201
|
-
dlog(`Angular VirtualizedList onScroll offset=${offset}`);
|
|
202
|
-
// A real native scroll supersedes any pending commanded offset.
|
|
203
|
-
this.commandedOffset = undefined;
|
|
204
|
-
this.dispatch({ kind: 'scroll', offset });
|
|
205
|
-
// Compose, don't clobber: internal windowing ran first, now the user's onScroll.
|
|
206
|
-
this.onScroll?.(event);
|
|
207
|
-
};
|
|
208
|
-
this.onLayoutTick = (event) => {
|
|
209
|
-
const length = readLayoutLength(event, this.isHorizontal);
|
|
210
|
-
if (length === undefined)
|
|
211
|
-
return;
|
|
212
|
-
dlog(`Angular VirtualizedList onLayout viewport=${length}`);
|
|
213
|
-
this.dispatch({ kind: 'layout', length });
|
|
214
|
-
};
|
|
215
|
-
// RefreshControl's refresh and the scroll tag's accessibility events reach here as plain
|
|
216
|
-
// listener-prop values in scrollViewBag()/refreshControlBag() — these fields just adapt
|
|
217
|
-
// VirtualizedList's own @Output() into a plain re-emit callback.
|
|
218
|
-
this.handleRefresh = () => {
|
|
219
|
-
this.refresh.emit();
|
|
220
|
-
};
|
|
221
|
-
this.accessibilityActionTick = (event) => {
|
|
222
|
-
this.accessibilityAction.emit(event);
|
|
223
|
-
};
|
|
224
|
-
this.accessibilityTapTick = (event) => {
|
|
225
|
-
this.accessibilityTap.emit(event);
|
|
226
|
-
};
|
|
227
|
-
this.magicTapTick = (event) => {
|
|
228
|
-
this.magicTap.emit(event);
|
|
229
|
-
};
|
|
230
|
-
this.accessibilityEscapeTick = (event) => {
|
|
231
|
-
this.accessibilityEscape.emit(event);
|
|
232
|
-
};
|
|
233
54
|
this.keyFor = (index) => {
|
|
234
55
|
const item = this.getItem(this.data, index);
|
|
235
56
|
return resolveItemKey(item, index, this.keyExtractor);
|
|
236
57
|
};
|
|
237
58
|
}
|
|
238
|
-
wantsGate(name) {
|
|
239
|
-
return gateWanted(this.gateDemandAbove, name, this[name]);
|
|
240
|
-
}
|
|
241
|
-
get cellTemplate() {
|
|
242
|
-
return this.itemTemplate ?? this.itemDir?.templateRef;
|
|
243
|
-
}
|
|
244
|
-
get separatorTemplate() {
|
|
245
|
-
return this.itemSeparatorTemplate ?? this.separatorDir?.templateRef;
|
|
246
|
-
}
|
|
247
59
|
get scrollNode() {
|
|
248
60
|
const node = this.scrollHostRef?.nativeElement;
|
|
249
61
|
return isSymbioteNode(node) ? node : null;
|
|
250
62
|
}
|
|
251
|
-
|
|
252
|
-
return this.refreshRequested ?? this.refresh.observed;
|
|
253
|
-
}
|
|
254
|
-
// The flat bag fed to the scroll tag via `[symbioteHostProps]`. A plain method, not `computed()`:
|
|
255
|
-
// most of these fields (resolvedStyle, renderedStickyIndices, commandedOffset, …) are recomputed
|
|
256
|
-
// in ngDoCheck/dispatch as ordinary fields, not signals, so a computed() memoized only against
|
|
257
|
-
// `inputsRevision` would go stale the moment one of them changed outside an @Input() write. The
|
|
258
|
-
// directive itself diffs per key before writing to the engine (`primitives/shared.ts`), so a
|
|
259
|
-
// fresh object every CD pass costs nothing beyond the literal allocation.
|
|
260
|
-
scrollViewBag() {
|
|
261
|
-
return {
|
|
262
|
-
...this.foldedAccessibility(),
|
|
263
|
-
style: this.resolvedStyle,
|
|
264
|
-
contentContainerStyle: this.resolvedContentContainerStyle,
|
|
265
|
-
onScroll: this.onScrollTick,
|
|
266
|
-
onLayout: this.onLayoutTick,
|
|
267
|
-
onScrollBeginDrag: this.onScrollBeginDrag,
|
|
268
|
-
onScrollEndDrag: this.onScrollEndDrag,
|
|
269
|
-
onMomentumScrollBegin: this.onMomentumScrollBegin,
|
|
270
|
-
onMomentumScrollEnd: this.onMomentumScrollEnd,
|
|
271
|
-
scrollEventThrottle: this.scrollEventThrottle,
|
|
272
|
-
keyboardShouldPersistTaps: this.keyboardShouldPersistTaps,
|
|
273
|
-
keyboardDismissMode: this.keyboardDismissMode,
|
|
274
|
-
// RN's VirtualizedList spreads its props onto the ScrollView, this one included.
|
|
275
|
-
removeClippedSubviews: this.removeClippedSubviews,
|
|
276
|
-
nestedScrollEnabled: this.nestedScrollEnabled,
|
|
277
|
-
// VirtualizedList.js:1111 — Android moves the scrollbar back after the `scale: -1` flip.
|
|
278
|
-
isInvertedVirtualizedList: this.isInverted ? true : undefined,
|
|
279
|
-
contentOffset: this.commandedOffset,
|
|
280
|
-
// `stickyHeaderIndices` is deliberately NOT forwarded — it numbers the scroll view's PAINT
|
|
281
|
-
// children, and a windowed list paints a header, a spacer and a slice, so the positions move
|
|
282
|
-
// every time the window slides and the behavior re-wraps a different child each pass. The
|
|
283
|
-
// cells carry the `sticky-header` TAG instead, which pins by DOCUMENT order.
|
|
284
|
-
maintainVisibleContentPosition: this.resolvedMaintainVisibleContentPosition,
|
|
285
|
-
// The four boolean-gated Fabric events (`.claude/rules/fabric-boolean-event-gates.md`): the
|
|
286
|
-
// TAG has no `.observed` of its own, so `wantsGate` (own subscriber, or the demand from
|
|
287
|
-
// whatever wraps this list) is what decides whether the flag reaches Fabric at all.
|
|
288
|
-
onAccessibilityAction: this.wantsGate('accessibilityAction')
|
|
289
|
-
? this.accessibilityActionTick
|
|
290
|
-
: undefined,
|
|
291
|
-
onAccessibilityTap: this.wantsGate('accessibilityTap')
|
|
292
|
-
? this.accessibilityTapTick
|
|
293
|
-
: undefined,
|
|
294
|
-
onMagicTap: this.wantsGate('magicTap') ? this.magicTapTick : undefined,
|
|
295
|
-
onAccessibilityEscape: this.wantsGate('accessibilityEscape')
|
|
296
|
-
? this.accessibilityEscapeTick
|
|
297
|
-
: undefined,
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
// The `refresh-control` tag's own bag — an ordinary first child, re-parented per platform by the
|
|
301
|
-
// scroll-view behavior (`../refresh-control-props.ts`). `onRefresh` is a plain listener prop, not
|
|
302
|
-
// a gated one: RefreshControl's `refresh` is unaffected by `fabric-boolean-event-gates.md`.
|
|
303
|
-
refreshControlBag() {
|
|
304
|
-
return {
|
|
305
|
-
refreshing: this.refreshing ?? false,
|
|
306
|
-
progressViewOffset: this.progressViewOffset,
|
|
307
|
-
onRefresh: this.handleRefresh,
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
get isHorizontal() {
|
|
311
|
-
return this.horizontal === true;
|
|
312
|
-
}
|
|
313
|
-
get isInverted() {
|
|
314
|
-
return this.inverted === true;
|
|
315
|
-
}
|
|
316
|
-
get windowSizeValue() {
|
|
317
|
-
return this.windowSize ?? DEFAULT_WINDOW_SIZE;
|
|
318
|
-
}
|
|
319
|
-
get initialNumToRenderValue() {
|
|
320
|
-
return this.initialNumToRender ?? DEFAULT_INITIAL_NUM_TO_RENDER;
|
|
321
|
-
}
|
|
322
|
-
get maxToRenderPerBatchValue() {
|
|
323
|
-
return this.maxToRenderPerBatch ?? DEFAULT_MAX_TO_RENDER_PER_BATCH;
|
|
324
|
-
}
|
|
325
|
-
get updateCellsBatchingPeriodValue() {
|
|
326
|
-
return (this.updateCellsBatchingPeriod ?? DEFAULT_UPDATE_CELLS_BATCHING_PERIOD);
|
|
327
|
-
}
|
|
328
|
-
get onEndReachedThresholdValue() {
|
|
329
|
-
return this.onEndReachedThreshold;
|
|
330
|
-
}
|
|
331
|
-
get onStartReachedThresholdValue() {
|
|
332
|
-
return this.onStartReachedThreshold;
|
|
333
|
-
}
|
|
334
|
-
// The reducer inputs, folded off the @Input()s each call. The edge/viewability listeners map to
|
|
335
|
-
// `.observed` (Angular's "is anyone bound to this @Output()"), so the reducer emits only when the
|
|
336
|
-
// consumer listens — the same on-demand gating the prop-callback era had.
|
|
63
|
+
// Edge and viewability listeners map to `.observed`, so the reducer emits only if listened to
|
|
337
64
|
buildInputs() {
|
|
338
65
|
return {
|
|
339
66
|
data: this.data,
|
|
@@ -346,8 +73,8 @@ export class VirtualizedList {
|
|
|
346
73
|
initialNumToRender: this.initialNumToRenderValue,
|
|
347
74
|
maxToRenderPerBatch: this.maxToRenderPerBatchValue,
|
|
348
75
|
updateCellsBatchingPeriod: this.updateCellsBatchingPeriodValue,
|
|
349
|
-
onEndReachedThreshold: this.
|
|
350
|
-
onStartReachedThreshold: this.
|
|
76
|
+
onEndReachedThreshold: this.onEndReachedThreshold,
|
|
77
|
+
onStartReachedThreshold: this.onStartReachedThreshold,
|
|
351
78
|
onEndReachedActive: this.endReached.observed,
|
|
352
79
|
onStartReachedActive: this.startReached.observed,
|
|
353
80
|
viewabilityPairs: buildViewabilityPairs(this.viewableItemsChanged.observed
|
|
@@ -357,12 +84,11 @@ export class VirtualizedList {
|
|
|
357
84
|
initialScrollIndex: this.initialScrollIndex,
|
|
358
85
|
};
|
|
359
86
|
}
|
|
360
|
-
//
|
|
361
|
-
// dirty when render state changed (the native callbacks fire outside Angular's own bindings).
|
|
87
|
+
// Native callbacks fire outside Angular's bindings, so a changed state must mark the view dirty
|
|
362
88
|
dispatch(action) {
|
|
363
89
|
const inputs = this.buildInputs();
|
|
364
90
|
const result = reduceList(this.listState, action, inputs);
|
|
365
|
-
this.
|
|
91
|
+
this.effects.run(result.effects, inputs);
|
|
366
92
|
if (!result.changed)
|
|
367
93
|
return;
|
|
368
94
|
this.renderVersion += 1;
|
|
@@ -371,30 +97,14 @@ export class VirtualizedList {
|
|
|
371
97
|
countAngular('listMarks');
|
|
372
98
|
this.cdr.markForCheck();
|
|
373
99
|
}
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
// TEMPLATE reads none of those; it reads the window. Marking on the offset repainted the whole
|
|
377
|
-
// ancestor chain 60 times a second on a sticky screen for a window that had not moved.
|
|
378
|
-
//
|
|
379
|
-
// So the question here is "would a render leave the window exactly where it is", and it is asked
|
|
380
|
-
// of the state as it is NOW. It must NOT be answered by comparing the last-rendered window with
|
|
381
|
-
// the one before it: that window was derived from the PREVIOUS scroll offset, so once two
|
|
382
|
-
// consecutive derives agree the comparison reads "settled" for every offset that ever follows -
|
|
383
|
-
// no mark, no CD, no ngDoCheck, no refresh-metrics, so the window can never move again and the
|
|
384
|
-
// list goes permanently deaf mid-scroll (device: examples/angular Benchmark sticky path B froze
|
|
385
|
-
// at exactly the window the first viewport asked for, blank below it).
|
|
386
|
-
//
|
|
387
|
-
// computeWindow re-run over the CACHED offset table answers it directly. Two scans, no
|
|
388
|
-
// allocation - buildOffsets, the O(count) allocating half, still runs once per render only. It is
|
|
389
|
-
// the same function the render will use, so this cannot drift away from the window it predicts.
|
|
100
|
+
// Asks whether a render would leave the window where it is, of the state as it is now
|
|
101
|
+
// Comparing the last two rendered windows would read settled forever and the list goes deaf
|
|
390
102
|
isWindowSettled(action) {
|
|
391
|
-
// A measurement rewrites the
|
|
392
|
-
|
|
393
|
-
if (action.kind === 'measure')
|
|
103
|
+
// A measurement rewrites the offset table the prediction reads
|
|
104
|
+
if (action.kind === LIST_ACTION_KIND.measure)
|
|
394
105
|
return false;
|
|
395
106
|
const m = this.listState.metrics;
|
|
396
|
-
// Mid-fill
|
|
397
|
-
// only a render advances it. Skipping the mark here is what stalls the incremental fill.
|
|
107
|
+
// Mid-fill the window climbs one batch step per render, only a render advances it
|
|
398
108
|
if (m.first !== m.target.first || m.last !== m.target.last)
|
|
399
109
|
return false;
|
|
400
110
|
const next = computeWindow(m.count, m.offsets, m.lengths, this.listState.scrollOffset, this.listState.viewportLength, this.windowSizeValue, this.initialNumToRenderValue);
|
|
@@ -404,80 +114,7 @@ export class VirtualizedList {
|
|
|
404
114
|
`[${next.first}, ${next.last}] at offset ${this.listState.scrollOffset}`);
|
|
405
115
|
return isSettled;
|
|
406
116
|
}
|
|
407
|
-
|
|
408
|
-
for (const effect of effects) {
|
|
409
|
-
switch (effect.kind) {
|
|
410
|
-
case 'scroll-to':
|
|
411
|
-
this.scrollToPixel(effect.offset, effect.animated);
|
|
412
|
-
break;
|
|
413
|
-
case 'fire-end-reached':
|
|
414
|
-
this.endReached.emit({ distanceFromEnd: effect.distanceFromEnd });
|
|
415
|
-
break;
|
|
416
|
-
case 'fire-start-reached':
|
|
417
|
-
this.startReached.emit({
|
|
418
|
-
distanceFromStart: effect.distanceFromStart,
|
|
419
|
-
});
|
|
420
|
-
break;
|
|
421
|
-
case 'fire-scroll-to-index-failed':
|
|
422
|
-
this.scrollToIndexFailed.emit({
|
|
423
|
-
index: effect.index,
|
|
424
|
-
highestMeasuredFrameIndex: effect.highestMeasuredFrameIndex,
|
|
425
|
-
averageItemLength: effect.averageItemLength,
|
|
426
|
-
});
|
|
427
|
-
break;
|
|
428
|
-
case 'schedule-refill': {
|
|
429
|
-
if (this.batchTimer !== null)
|
|
430
|
-
clearTimeout(this.batchTimer);
|
|
431
|
-
this.batchTimer = setTimeout(() => {
|
|
432
|
-
this.batchTimer = null;
|
|
433
|
-
this.dispatch({ kind: 'batch-tick' });
|
|
434
|
-
}, effect.delay);
|
|
435
|
-
break;
|
|
436
|
-
}
|
|
437
|
-
case 'fire-viewable': {
|
|
438
|
-
const pairs = inputs.viewabilityPairs;
|
|
439
|
-
const info = effect.info;
|
|
440
|
-
const map = effect.map;
|
|
441
|
-
const fire = () => {
|
|
442
|
-
for (const pair of pairs) {
|
|
443
|
-
pair.onViewableItemsChanged({
|
|
444
|
-
...info,
|
|
445
|
-
viewabilityConfig: pair.viewabilityConfig,
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
this.dispatch({ kind: 'viewable-fired', map });
|
|
449
|
-
};
|
|
450
|
-
if (this.viewableTimer !== null) {
|
|
451
|
-
clearTimeout(this.viewableTimer);
|
|
452
|
-
this.viewableTimer = null;
|
|
453
|
-
}
|
|
454
|
-
if (effect.delay > EMPTY_OFFSET) {
|
|
455
|
-
this.viewableTimer = setTimeout(() => {
|
|
456
|
-
this.viewableTimer = null;
|
|
457
|
-
fire();
|
|
458
|
-
}, effect.delay);
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
fire();
|
|
462
|
-
}
|
|
463
|
-
break;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
// foldedAccessibility reads plain @Input fields, which are NOT reactive on their own - this bump
|
|
469
|
-
// is what tells that computed an input changed. It must stay in ngOnChanges: that is the single
|
|
470
|
-
// moment Angular has finished writing every changed input for this pass, and it runs before
|
|
471
|
-
// ngDoCheck below, so the recompute already sees the current values.
|
|
472
|
-
ngOnChanges() {
|
|
473
|
-
this.inputsRevision.update(revision => revision + 1);
|
|
474
|
-
}
|
|
475
|
-
// Once-per-CD recompute, BEFORE the template bindings are read (so the freshly computed
|
|
476
|
-
// template-bound fields render this pass — computing them in ngAfterContentChecked instead would
|
|
477
|
-
// trip ExpressionChangedAfterItHasBeenChecked). The dedup guard runs refresh-metrics (which owns
|
|
478
|
-
// the controlled committedWindow throttle) only when something relevant changed, so the window
|
|
479
|
-
// grows exactly one step per meaningful CD. The projected templates (ContentChild) are resolved
|
|
480
|
-
// from the second CD on; the first paint (count/viewport still 0) corrects on the layout-driven CD.
|
|
117
|
+
// Runs before the bindings are read, a later hook would trip the changed-after-checked guard
|
|
481
118
|
ngDoCheck() {
|
|
482
119
|
countAngular('listChecks');
|
|
483
120
|
const recomputeInputs = [
|
|
@@ -493,12 +130,9 @@ export class VirtualizedList {
|
|
|
493
130
|
this.stickyHeaderIndices,
|
|
494
131
|
this.maintainVisibleContentPosition,
|
|
495
132
|
this.style,
|
|
496
|
-
// `
|
|
497
|
-
// addClass/removeClass, never as an @Input - so without it here no entry moves on a class
|
|
498
|
-
// toggle and the gate skips the recompute forever. Reference-stable, so the dedup holds.
|
|
133
|
+
// Arrives through `addClass` and `removeClass`, never as an input
|
|
499
134
|
anchorHostStyle(this.elementRef),
|
|
500
135
|
this.contentContainerStyle,
|
|
501
|
-
// Folds scroll / layout / measure / batch-tick: dispatch bumps renderVersion on any change.
|
|
502
136
|
this.renderVersion,
|
|
503
137
|
this.headerDir !== undefined,
|
|
504
138
|
this.footerDir !== undefined,
|
|
@@ -512,9 +146,8 @@ export class VirtualizedList {
|
|
|
512
146
|
previous.every((value, index) => value === recomputeInputs[index])) {
|
|
513
147
|
return;
|
|
514
148
|
}
|
|
515
|
-
// The single derive-per-CD: recompute the window off the current state before the view reads it.
|
|
516
149
|
countAngular('listRecomputes');
|
|
517
|
-
reduceList(this.listState, { kind:
|
|
150
|
+
reduceList(this.listState, { kind: LIST_ACTION_KIND.refreshMetrics }, this.buildInputs());
|
|
518
151
|
this.recomputeView();
|
|
519
152
|
}
|
|
520
153
|
ngAfterViewChecked() {
|
|
@@ -523,72 +156,29 @@ export class VirtualizedList {
|
|
|
523
156
|
return;
|
|
524
157
|
this.lastEffectSignature = signature;
|
|
525
158
|
const inputs = this.buildInputs();
|
|
526
|
-
const result = reduceList(this.listState, { kind:
|
|
527
|
-
this.
|
|
159
|
+
const result = reduceList(this.listState, { kind: LIST_ACTION_KIND.commit }, inputs);
|
|
160
|
+
this.effects.run(result.effects, inputs);
|
|
528
161
|
}
|
|
529
162
|
ngOnDestroy() {
|
|
530
|
-
|
|
531
|
-
clearTimeout(this.viewableTimer);
|
|
532
|
-
if (this.batchTimer !== null)
|
|
533
|
-
clearTimeout(this.batchTimer);
|
|
163
|
+
this.effects.dispose();
|
|
534
164
|
}
|
|
535
165
|
recomputeView() {
|
|
536
166
|
const m = this.listState.metrics;
|
|
537
167
|
this.itemCount = m.count;
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
const stickySet = this.stickyHeaderIndices !== undefined
|
|
541
|
-
? new Set(this.stickyHeaderIndices)
|
|
542
|
-
: undefined;
|
|
543
|
-
this.resolvedContentContainerStyle = this.isHorizontal
|
|
544
|
-
? [this.contentContainerStyle, { width: m.total }]
|
|
545
|
-
: this.contentContainerStyle;
|
|
546
|
-
this.resolvedStyle = flattenStyle([
|
|
547
|
-
anchorHostStyle(this.elementRef),
|
|
548
|
-
// VirtualizedList.js: `[inversionStyle, style]` — the app's style can override the flip.
|
|
549
|
-
this.isInverted
|
|
550
|
-
? [this.isHorizontal ? INVERTED_X_STYLE : INVERTED_Y_STYLE, this.style]
|
|
551
|
-
: this.style,
|
|
552
|
-
]);
|
|
553
|
-
this.cellStyle = this.isInverted
|
|
554
|
-
? this.isHorizontal
|
|
555
|
-
? INVERTED_X_STYLE
|
|
556
|
-
: INVERTED_Y_STYLE
|
|
557
|
-
: undefined;
|
|
558
|
-
this.resolvedMaintainVisibleContentPosition =
|
|
559
|
-
this.maintainVisibleContentPosition === undefined
|
|
560
|
-
? undefined
|
|
561
|
-
: {
|
|
562
|
-
...this.maintainVisibleContentPosition,
|
|
563
|
-
minIndexForVisible: this.maintainVisibleContentPosition.minIndexForVisible +
|
|
564
|
-
(hasHeader ? 1 : 0),
|
|
565
|
-
};
|
|
566
|
-
// A change in anything a cell's content reads other than its own item invalidates every cached
|
|
567
|
-
// context: identity reuse is only sound while the reused object still describes the cell.
|
|
568
|
-
const epoch = [
|
|
168
|
+
this.applyStyles(m.total);
|
|
169
|
+
this.cells.beginPass([
|
|
569
170
|
this.data,
|
|
570
171
|
this.extraData,
|
|
571
172
|
this.getItem,
|
|
572
173
|
this.keyExtractor,
|
|
573
|
-
];
|
|
574
|
-
const previousEpoch = this.cellContextEpoch;
|
|
575
|
-
this.cellContextEpoch = epoch;
|
|
576
|
-
if (previousEpoch === undefined ||
|
|
577
|
-
previousEpoch.length !== epoch.length ||
|
|
578
|
-
!previousEpoch.every((value, index) => value === epoch[index])) {
|
|
579
|
-
this.cellContexts.clear();
|
|
580
|
-
}
|
|
174
|
+
]);
|
|
581
175
|
if (m.count === FIRST_INDEX) {
|
|
582
|
-
this.
|
|
583
|
-
this.nextCellContexts.clear();
|
|
584
|
-
this.windowCells = [];
|
|
585
|
-
this.forcedStickyCell = null;
|
|
586
|
-
this.leadingSpacerStyle = null;
|
|
587
|
-
this.gapSpacerStyle = null;
|
|
588
|
-
this.trailingSpacerStyle = null;
|
|
589
|
-
dlog(`Angular VirtualizedList empty (viewport=${this.listState.viewportLength})`);
|
|
176
|
+
this.showEmpty();
|
|
590
177
|
return;
|
|
591
178
|
}
|
|
179
|
+
const stickySet = this.stickyHeaderIndices !== undefined
|
|
180
|
+
? new Set(this.stickyHeaderIndices)
|
|
181
|
+
: undefined;
|
|
592
182
|
const plan = buildListPlan({
|
|
593
183
|
count: m.count,
|
|
594
184
|
first: m.first,
|
|
@@ -598,121 +188,67 @@ export class VirtualizedList {
|
|
|
598
188
|
total: m.total,
|
|
599
189
|
keyFor: this.keyFor,
|
|
600
190
|
stickyIndices: stickySet,
|
|
601
|
-
hasHeader,
|
|
191
|
+
hasHeader: this.headerDir !== undefined,
|
|
602
192
|
});
|
|
603
|
-
this.
|
|
604
|
-
|
|
605
|
-
? this.spacerStyle(plan.leadingExtent)
|
|
606
|
-
: null;
|
|
607
|
-
this.gapSpacerStyle =
|
|
608
|
-
plan.gapExtent > EMPTY_OFFSET ? this.spacerStyle(plan.gapExtent) : null;
|
|
609
|
-
this.trailingSpacerStyle =
|
|
610
|
-
plan.trailingExtent > EMPTY_OFFSET
|
|
611
|
-
? this.spacerStyle(plan.trailingExtent)
|
|
612
|
-
: null;
|
|
613
|
-
// `plan.stickyChildPositions` is deliberately NOT read — it was the input to the index form.
|
|
614
|
-
dlog(`STICKY[list] stickySet=${stickySet === undefined ? 'undefined' : JSON.stringify([...stickySet])} ` +
|
|
615
|
-
`childPositions=${JSON.stringify(plan.stickyChildPositions)} ` +
|
|
616
|
-
`forcedStickyCell=${plan.forcedStickyCell === undefined ? 'none' : plan.forcedStickyCell.index} ` +
|
|
617
|
-
`window=[${m.first},${m.last}] hasHeader=${this.headerDir !== undefined}`);
|
|
618
|
-
this.forcedStickyCell =
|
|
619
|
-
plan.forcedStickyCell !== undefined
|
|
620
|
-
? this.buildWindowCell(plan.forcedStickyCell.index, plan.forcedStickyCell.key, false,
|
|
621
|
-
// Sticky by construction — `forcedStickyCell` exists only for an index in `stickySet`.
|
|
622
|
-
true)
|
|
623
|
-
: null;
|
|
624
|
-
const cells = [];
|
|
625
|
-
for (const planned of plan.cells) {
|
|
626
|
-
// RN gates the separator on the last index of the DATA, not the WINDOW
|
|
627
|
-
// (VirtualizedList.js:793 `getItemCount(data) - 1`). The separator lives INSIDE the
|
|
628
|
-
// measuring wrapper, so gating on the window would shift a cell's height as it slides past.
|
|
629
|
-
const includeSeparator = hasSeparators && planned.index < m.count - 1;
|
|
630
|
-
cells.push(this.buildWindowCell(planned.index, planned.key, includeSeparator, stickySet?.has(planned.index) === true));
|
|
631
|
-
}
|
|
632
|
-
this.windowCells = cells;
|
|
633
|
-
// Swap, don't prune: a cell that left the window is simply absent from the pass that just ran,
|
|
634
|
-
// so the old map is the garbage and the new one is exactly the live set.
|
|
635
|
-
this.cellContexts = this.nextCellContexts;
|
|
636
|
-
this.nextCellContexts = new Map();
|
|
193
|
+
this.applySpacers(plan);
|
|
194
|
+
this.buildCells(plan, stickySet);
|
|
637
195
|
dlog(`Angular VirtualizedList window [${m.first}, ${m.last}] of ${m.count} ` +
|
|
638
|
-
`(offset=${this.listState.scrollOffset}, viewport=${this.listState.viewportLength}, rendered=${
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
196
|
+
`(offset=${this.listState.scrollOffset}, viewport=${this.listState.viewportLength}, rendered=${this.windowCells.length})`);
|
|
197
|
+
}
|
|
198
|
+
applyStyles(total) {
|
|
199
|
+
const styles = resolveListStyles({
|
|
200
|
+
isHorizontal: this.isHorizontal,
|
|
201
|
+
isInverted: this.isInverted,
|
|
202
|
+
total,
|
|
203
|
+
hasHeader: this.headerDir !== undefined,
|
|
204
|
+
style: this.style,
|
|
205
|
+
contentContainerStyle: this.contentContainerStyle,
|
|
206
|
+
anchorStyle: anchorHostStyle(this.elementRef),
|
|
207
|
+
maintainVisibleContentPosition: this.maintainVisibleContentPosition,
|
|
208
|
+
});
|
|
209
|
+
this.resolvedStyle = styles.style;
|
|
210
|
+
this.resolvedContentContainerStyle = styles.contentContainerStyle;
|
|
211
|
+
this.cellStyle = styles.cellStyle;
|
|
212
|
+
this.resolvedMaintainVisibleContentPosition =
|
|
213
|
+
styles.maintainVisibleContentPosition;
|
|
654
214
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}
|
|
664
|
-
const context = {
|
|
665
|
-
$implicit: item,
|
|
666
|
-
index,
|
|
667
|
-
separators: this.makeSeparators(index),
|
|
668
|
-
};
|
|
669
|
-
this.nextCellContexts.set(key, context);
|
|
670
|
-
return context;
|
|
215
|
+
showEmpty() {
|
|
216
|
+
this.cells.clear();
|
|
217
|
+
this.windowCells = [];
|
|
218
|
+
this.forcedStickyCell = null;
|
|
219
|
+
this.leadingSpacerStyle = null;
|
|
220
|
+
this.gapSpacerStyle = null;
|
|
221
|
+
this.trailingSpacerStyle = null;
|
|
222
|
+
dlog(`Angular VirtualizedList empty (viewport=${this.listState.viewportLength})`);
|
|
671
223
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
$implicit: highlighted,
|
|
677
|
-
highlighted,
|
|
678
|
-
leadingItem: item,
|
|
679
|
-
trailingItem: this.getItem(this.data, index + 1),
|
|
680
|
-
};
|
|
681
|
-
// Fold any custom updateProps keys through the context's index signature (RN lets a row drive
|
|
682
|
-
// arbitrary separator props); the typed fields above stay authoritative.
|
|
683
|
-
if (overrides !== undefined) {
|
|
684
|
-
for (const key of Object.keys(overrides)) {
|
|
685
|
-
if (key === 'highlighted' ||
|
|
686
|
-
key === 'leadingItem' ||
|
|
687
|
-
key === 'trailingItem')
|
|
688
|
-
continue;
|
|
689
|
-
context[key] = overrides[key];
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
return context;
|
|
224
|
+
applySpacers(plan) {
|
|
225
|
+
this.leadingSpacerStyle = this.spacerStyle(plan.leadingExtent);
|
|
226
|
+
this.gapSpacerStyle = this.spacerStyle(plan.gapExtent);
|
|
227
|
+
this.trailingSpacerStyle = this.spacerStyle(plan.trailingExtent);
|
|
693
228
|
}
|
|
694
229
|
spacerStyle(extent) {
|
|
230
|
+
if (extent <= EMPTY_OFFSET)
|
|
231
|
+
return null;
|
|
695
232
|
return this.isHorizontal ? { width: extent } : { height: extent };
|
|
696
233
|
}
|
|
697
|
-
|
|
698
|
-
const
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
this.
|
|
712
|
-
|
|
234
|
+
buildCells(plan, stickySet) {
|
|
235
|
+
const count = this.listState.metrics.count;
|
|
236
|
+
const forced = plan.forcedStickyCell;
|
|
237
|
+
dlog(`STICKY[list] stickySet=${stickySet === undefined ? 'undefined' : JSON.stringify([...stickySet])} ` +
|
|
238
|
+
`childPositions=${JSON.stringify(plan.stickyChildPositions)} ` +
|
|
239
|
+
`forcedStickyCell=${forced === undefined ? 'none' : forced.index}`);
|
|
240
|
+
// Sticky by construction: a forced cell exists only for an index in `stickySet`
|
|
241
|
+
this.forcedStickyCell =
|
|
242
|
+
forced !== undefined
|
|
243
|
+
? this.cells.windowCell(forced.index, forced.key, false, true)
|
|
244
|
+
: null;
|
|
245
|
+
const hasSeparators = this.separatorTemplate !== undefined;
|
|
246
|
+
// The separator gates on the last index of the data, not of the window, or a cell's height
|
|
247
|
+
// would shift as it slides past
|
|
248
|
+
this.windowCells = plan.cells.map(planned => this.cells.windowCell(planned.index, planned.key, hasSeparators && planned.index < count - 1, stickySet?.has(planned.index) === true));
|
|
249
|
+
this.cells.endPass();
|
|
713
250
|
}
|
|
714
|
-
//
|
|
715
|
-
// [onLayout] property binding (NG8002). $event arrives untyped, narrowed before reaching measure.
|
|
251
|
+
// Angular forbids an `[onLayout]` binding, so the event arrives untyped and is narrowed here
|
|
716
252
|
handleCellLayout(measure, event) {
|
|
717
253
|
if (this.isSymbioteEvent(event))
|
|
718
254
|
measure(event);
|
|
@@ -720,84 +256,6 @@ export class VirtualizedList {
|
|
|
720
256
|
isSymbioteEvent(value) {
|
|
721
257
|
return (typeof value === 'object' && value !== null && 'nativeEvent' in value);
|
|
722
258
|
}
|
|
723
|
-
mergeSeparator(gapIndex, patch) {
|
|
724
|
-
const count = this.listState.metrics.count;
|
|
725
|
-
if (!isSeparatorGapInRange(gapIndex, count))
|
|
726
|
-
return;
|
|
727
|
-
this.separatorOverrides.set(gapIndex, {
|
|
728
|
-
...this.separatorOverrides.get(gapIndex),
|
|
729
|
-
...patch,
|
|
730
|
-
});
|
|
731
|
-
this.cdr.markForCheck();
|
|
732
|
-
}
|
|
733
|
-
makeSeparators(index) {
|
|
734
|
-
return {
|
|
735
|
-
highlight: () => {
|
|
736
|
-
dlog(`Angular VirtualizedList separator highlight cell=${index}`);
|
|
737
|
-
this.mergeSeparator(index - 1, { highlighted: true });
|
|
738
|
-
this.mergeSeparator(index, { highlighted: true });
|
|
739
|
-
},
|
|
740
|
-
unhighlight: () => {
|
|
741
|
-
dlog(`Angular VirtualizedList separator unhighlight cell=${index}`);
|
|
742
|
-
this.mergeSeparator(index - 1, { highlighted: false });
|
|
743
|
-
this.mergeSeparator(index, { highlighted: false });
|
|
744
|
-
},
|
|
745
|
-
updateProps: (select, newProps) => {
|
|
746
|
-
this.mergeSeparator(select === 'leading' ? index - 1 : index, newProps);
|
|
747
|
-
},
|
|
748
|
-
};
|
|
749
|
-
}
|
|
750
|
-
// ---- imperative handle (the shared IVirtualizedListHandle surface) ----
|
|
751
|
-
// Each scroll resolves to an offset (or a scroll-to-index failure) inside the reducer, then rides
|
|
752
|
-
// the scroll-to effect through scrollToPixel.
|
|
753
|
-
scrollToOffset(params) {
|
|
754
|
-
this.dispatch({
|
|
755
|
-
kind: 'scroll-to-offset',
|
|
756
|
-
offset: params.offset,
|
|
757
|
-
animated: params.animated ?? true,
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
scrollToIndex(params) {
|
|
761
|
-
this.dispatch({
|
|
762
|
-
kind: 'scroll-to-index',
|
|
763
|
-
index: params.index,
|
|
764
|
-
animated: params.animated ?? true,
|
|
765
|
-
viewPosition: params.viewPosition ?? FIRST_INDEX,
|
|
766
|
-
viewOffset: params.viewOffset ?? EMPTY_OFFSET,
|
|
767
|
-
});
|
|
768
|
-
}
|
|
769
|
-
scrollToItem(params) {
|
|
770
|
-
this.dispatch({
|
|
771
|
-
kind: 'scroll-to-item',
|
|
772
|
-
item: params.item,
|
|
773
|
-
animated: params.animated ?? true,
|
|
774
|
-
viewPosition: params.viewPosition ?? FIRST_INDEX,
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
scrollToEnd(params) {
|
|
778
|
-
this.dispatch({
|
|
779
|
-
kind: 'scroll-to-end',
|
|
780
|
-
animated: params?.animated ?? true,
|
|
781
|
-
});
|
|
782
|
-
}
|
|
783
|
-
flashScrollIndicators() {
|
|
784
|
-
this.scrollHandle.flashScrollIndicators();
|
|
785
|
-
}
|
|
786
|
-
getNativeScrollRef() {
|
|
787
|
-
return this.scrollNode !== null ? this.scrollHandle : null;
|
|
788
|
-
}
|
|
789
|
-
getScrollableNode() {
|
|
790
|
-
return this.scrollNode !== null ? this.scrollHandle : null;
|
|
791
|
-
}
|
|
792
|
-
getScrollResponder() {
|
|
793
|
-
return this.scrollNode !== null ? this.scrollHandle : null;
|
|
794
|
-
}
|
|
795
|
-
getScrollNode() {
|
|
796
|
-
return this.scrollHandle.getScrollNode();
|
|
797
|
-
}
|
|
798
|
-
recordInteraction() {
|
|
799
|
-
this.dispatch({ kind: 'record-interaction' });
|
|
800
|
-
}
|
|
801
259
|
scrollToPixel(offset, animated) {
|
|
802
260
|
const clamped = Math.max(EMPTY_OFFSET, offset);
|
|
803
261
|
const target = this.isHorizontal
|
|
@@ -812,181 +270,8 @@ export class VirtualizedList {
|
|
|
812
270
|
this.commandedOffset = target;
|
|
813
271
|
this.cdr.markForCheck();
|
|
814
272
|
}
|
|
815
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: VirtualizedList, deps:
|
|
816
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: VirtualizedList, isStandalone: true, selector: "VirtualizedList",
|
|
817
|
-
@if (isHorizontal) {
|
|
818
|
-
<horizontal-scroll-view #scrollHost [symbioteHostProps]="scrollViewBag()">
|
|
819
|
-
@if (shouldRenderRefreshControl) {
|
|
820
|
-
<refresh-control
|
|
821
|
-
[symbioteHostProps]="refreshControlBag()"
|
|
822
|
-
></refresh-control>
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
@if (headerDir !== undefined) {
|
|
826
|
-
<view>
|
|
827
|
-
<ng-container [vListOutlet]="headerDir.templateRef"></ng-container>
|
|
828
|
-
</view>
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
@if (itemCount === 0) {
|
|
832
|
-
@if (emptyDir !== undefined) {
|
|
833
|
-
<view>
|
|
834
|
-
<ng-container [vListOutlet]="emptyDir.templateRef"></ng-container>
|
|
835
|
-
</view>
|
|
836
|
-
}
|
|
837
|
-
} @else {
|
|
838
|
-
@if (leadingSpacerStyle !== null) {
|
|
839
|
-
<view [style]="leadingSpacerStyle"></view>
|
|
840
|
-
}
|
|
841
|
-
@if (forcedStickyCell !== null) {
|
|
842
|
-
<sticky-header
|
|
843
|
-
(layout)="handleCellLayout(forcedStickyCell.measure, $event)"
|
|
844
|
-
[style]="cellStyle"
|
|
845
|
-
>
|
|
846
|
-
<ng-container
|
|
847
|
-
[vListOutlet]="cellTemplate"
|
|
848
|
-
[vListOutletContext]="forcedStickyCell.context"
|
|
849
|
-
></ng-container>
|
|
850
|
-
</sticky-header>
|
|
851
|
-
}
|
|
852
|
-
@if (gapSpacerStyle !== null) {
|
|
853
|
-
<view [style]="gapSpacerStyle"></view>
|
|
854
|
-
}
|
|
855
|
-
@for (cell of windowCells; track cell.key) {
|
|
856
|
-
@if (cell.isSticky) {
|
|
857
|
-
<sticky-header
|
|
858
|
-
(layout)="handleCellLayout(cell.measure, $event)"
|
|
859
|
-
[style]="cellStyle"
|
|
860
|
-
>
|
|
861
|
-
<ng-container
|
|
862
|
-
[vListOutlet]="cellTemplate"
|
|
863
|
-
[vListOutletContext]="cell.context"
|
|
864
|
-
></ng-container>
|
|
865
|
-
@if (cell.separatorContext !== undefined) {
|
|
866
|
-
<ng-container
|
|
867
|
-
[vListOutlet]="separatorTemplate"
|
|
868
|
-
[vListOutletContext]="cell.separatorContext"
|
|
869
|
-
></ng-container>
|
|
870
|
-
}
|
|
871
|
-
</sticky-header>
|
|
872
|
-
} @else {
|
|
873
|
-
<view
|
|
874
|
-
(layout)="handleCellLayout(cell.measure, $event)"
|
|
875
|
-
[style]="cellStyle"
|
|
876
|
-
>
|
|
877
|
-
<ng-container
|
|
878
|
-
[vListOutlet]="cellTemplate"
|
|
879
|
-
[vListOutletContext]="cell.context"
|
|
880
|
-
></ng-container>
|
|
881
|
-
@if (cell.separatorContext !== undefined) {
|
|
882
|
-
<ng-container
|
|
883
|
-
[vListOutlet]="separatorTemplate"
|
|
884
|
-
[vListOutletContext]="cell.separatorContext"
|
|
885
|
-
></ng-container>
|
|
886
|
-
}
|
|
887
|
-
</view>
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
@if (trailingSpacerStyle !== null) {
|
|
891
|
-
<view [style]="trailingSpacerStyle"></view>
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
@if (footerDir !== undefined) {
|
|
896
|
-
<view>
|
|
897
|
-
<ng-container [vListOutlet]="footerDir.templateRef"></ng-container>
|
|
898
|
-
</view>
|
|
899
|
-
}
|
|
900
|
-
</horizontal-scroll-view>
|
|
901
|
-
} @else {
|
|
902
|
-
<scroll-view #scrollHost [symbioteHostProps]="scrollViewBag()">
|
|
903
|
-
@if (shouldRenderRefreshControl) {
|
|
904
|
-
<refresh-control
|
|
905
|
-
[symbioteHostProps]="refreshControlBag()"
|
|
906
|
-
></refresh-control>
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
@if (headerDir !== undefined) {
|
|
910
|
-
<view>
|
|
911
|
-
<ng-container [vListOutlet]="headerDir.templateRef"></ng-container>
|
|
912
|
-
</view>
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
@if (itemCount === 0) {
|
|
916
|
-
@if (emptyDir !== undefined) {
|
|
917
|
-
<view>
|
|
918
|
-
<ng-container [vListOutlet]="emptyDir.templateRef"></ng-container>
|
|
919
|
-
</view>
|
|
920
|
-
}
|
|
921
|
-
} @else {
|
|
922
|
-
@if (leadingSpacerStyle !== null) {
|
|
923
|
-
<view [style]="leadingSpacerStyle"></view>
|
|
924
|
-
}
|
|
925
|
-
@if (forcedStickyCell !== null) {
|
|
926
|
-
<sticky-header
|
|
927
|
-
(layout)="handleCellLayout(forcedStickyCell.measure, $event)"
|
|
928
|
-
[style]="cellStyle"
|
|
929
|
-
>
|
|
930
|
-
<ng-container
|
|
931
|
-
[vListOutlet]="cellTemplate"
|
|
932
|
-
[vListOutletContext]="forcedStickyCell.context"
|
|
933
|
-
></ng-container>
|
|
934
|
-
</sticky-header>
|
|
935
|
-
}
|
|
936
|
-
@if (gapSpacerStyle !== null) {
|
|
937
|
-
<view [style]="gapSpacerStyle"></view>
|
|
938
|
-
}
|
|
939
|
-
<!-- Separator sits INSIDE the measuring view, matching RN's cell renderer
|
|
940
|
-
(VirtualizedListCellRenderer.js:218-221) — as a sibling it'd add an extra flex gap.
|
|
941
|
-
See list-geometry-feedback-loop.md. -->
|
|
942
|
-
@for (cell of windowCells; track cell.key) {
|
|
943
|
-
@if (cell.isSticky) {
|
|
944
|
-
<sticky-header
|
|
945
|
-
(layout)="handleCellLayout(cell.measure, $event)"
|
|
946
|
-
[style]="cellStyle"
|
|
947
|
-
>
|
|
948
|
-
<ng-container
|
|
949
|
-
[vListOutlet]="cellTemplate"
|
|
950
|
-
[vListOutletContext]="cell.context"
|
|
951
|
-
></ng-container>
|
|
952
|
-
@if (cell.separatorContext !== undefined) {
|
|
953
|
-
<ng-container
|
|
954
|
-
[vListOutlet]="separatorTemplate"
|
|
955
|
-
[vListOutletContext]="cell.separatorContext"
|
|
956
|
-
></ng-container>
|
|
957
|
-
}
|
|
958
|
-
</sticky-header>
|
|
959
|
-
} @else {
|
|
960
|
-
<view
|
|
961
|
-
(layout)="handleCellLayout(cell.measure, $event)"
|
|
962
|
-
[style]="cellStyle"
|
|
963
|
-
>
|
|
964
|
-
<ng-container
|
|
965
|
-
[vListOutlet]="cellTemplate"
|
|
966
|
-
[vListOutletContext]="cell.context"
|
|
967
|
-
></ng-container>
|
|
968
|
-
@if (cell.separatorContext !== undefined) {
|
|
969
|
-
<ng-container
|
|
970
|
-
[vListOutlet]="separatorTemplate"
|
|
971
|
-
[vListOutletContext]="cell.separatorContext"
|
|
972
|
-
></ng-container>
|
|
973
|
-
}
|
|
974
|
-
</view>
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
@if (trailingSpacerStyle !== null) {
|
|
978
|
-
<view [style]="trailingSpacerStyle"></view>
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
@if (footerDir !== undefined) {
|
|
983
|
-
<view>
|
|
984
|
-
<ng-container [vListOutlet]="footerDir.templateRef"></ng-container>
|
|
985
|
-
</view>
|
|
986
|
-
}
|
|
987
|
-
</scroll-view>
|
|
988
|
-
}
|
|
989
|
-
`, isInline: true, dependencies: [{ kind: "directive", type: SymbioteHostPropsDirective, selector: "[symbioteHostProps]", inputs: ["symbioteHostProps"], exportAs: ["symbioteHost"] }, { kind: "directive", type: VListOutletDirective, selector: "[vListOutlet]", inputs: ["vListOutlet", "vListOutletContext"] }, { kind: "component", type: ViewHost, selector: "view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
273
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: VirtualizedList, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
274
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: VirtualizedList, isStandalone: true, selector: "VirtualizedList", viewQueries: [{ propertyName: "scrollHostRef", first: true, predicate: ["scrollHost"], descendants: true, read: ElementRef }], usesInheritance: true, hostDirectives: [{ directive: i1.SymbioteStyleInputDirective, inputs: ["style", "style"] }], ngImport: i0, template: "\n @if (isHorizontal) {\n <horizontal-scroll-view #scrollHost [symbioteHostProps]=\"scrollViewBag()\">\n @if (shouldRenderRefreshControl) {\n <refresh-control\n [symbioteHostProps]=\"refreshControlBag()\"\n ></refresh-control>\n }\n\n @if (headerDir !== undefined) {\n <view>\n <ng-container [vListOutlet]=\"headerDir.templateRef\"></ng-container>\n </view>\n }\n\n @if (itemCount === 0) {\n @if (emptyDir !== undefined) {\n <view>\n <ng-container [vListOutlet]=\"emptyDir.templateRef\"></ng-container>\n </view>\n }\n } @else {\n @if (leadingSpacerStyle !== null) {\n <view [style]=\"leadingSpacerStyle\"></view>\n }\n @if (forcedStickyCell !== null) {\n <sticky-header\n (layout)=\"handleCellLayout(forcedStickyCell.measure, $event)\"\n [style]=\"cellStyle\"\n >\n <ng-container\n [vListOutlet]=\"cellTemplate\"\n [vListOutletContext]=\"forcedStickyCell.context\"\n ></ng-container>\n </sticky-header>\n }\n @if (gapSpacerStyle !== null) {\n <view [style]=\"gapSpacerStyle\"></view>\n }\n @for (cell of windowCells; track cell.key) {\n @if (cell.isSticky) {\n <sticky-header\n (layout)=\"handleCellLayout(cell.measure, $event)\"\n [style]=\"cellStyle\"\n >\n <ng-container\n [vListOutlet]=\"cellTemplate\"\n [vListOutletContext]=\"cell.context\"\n ></ng-container>\n @if (cell.separatorContext !== undefined) {\n <ng-container\n [vListOutlet]=\"separatorTemplate\"\n [vListOutletContext]=\"cell.separatorContext\"\n ></ng-container>\n }\n </sticky-header>\n } @else {\n <view\n (layout)=\"handleCellLayout(cell.measure, $event)\"\n [style]=\"cellStyle\"\n >\n <ng-container\n [vListOutlet]=\"cellTemplate\"\n [vListOutletContext]=\"cell.context\"\n ></ng-container>\n @if (cell.separatorContext !== undefined) {\n <ng-container\n [vListOutlet]=\"separatorTemplate\"\n [vListOutletContext]=\"cell.separatorContext\"\n ></ng-container>\n }\n </view>\n }\n }\n @if (trailingSpacerStyle !== null) {\n <view [style]=\"trailingSpacerStyle\"></view>\n }\n }\n\n @if (footerDir !== undefined) {\n <view>\n <ng-container [vListOutlet]=\"footerDir.templateRef\"></ng-container>\n </view>\n }\n </horizontal-scroll-view>\n } @else {\n <scroll-view #scrollHost [symbioteHostProps]=\"scrollViewBag()\">\n @if (shouldRenderRefreshControl) {\n <refresh-control\n [symbioteHostProps]=\"refreshControlBag()\"\n ></refresh-control>\n }\n\n @if (headerDir !== undefined) {\n <view>\n <ng-container [vListOutlet]=\"headerDir.templateRef\"></ng-container>\n </view>\n }\n\n @if (itemCount === 0) {\n @if (emptyDir !== undefined) {\n <view>\n <ng-container [vListOutlet]=\"emptyDir.templateRef\"></ng-container>\n </view>\n }\n } @else {\n @if (leadingSpacerStyle !== null) {\n <view [style]=\"leadingSpacerStyle\"></view>\n }\n @if (forcedStickyCell !== null) {\n <sticky-header\n (layout)=\"handleCellLayout(forcedStickyCell.measure, $event)\"\n [style]=\"cellStyle\"\n >\n <ng-container\n [vListOutlet]=\"cellTemplate\"\n [vListOutletContext]=\"forcedStickyCell.context\"\n ></ng-container>\n </sticky-header>\n }\n @if (gapSpacerStyle !== null) {\n <view [style]=\"gapSpacerStyle\"></view>\n }\n <!-- The separator sits INSIDE the measuring view, matching RN's cell renderer, as a\n sibling it would add an extra flex gap -->\n @for (cell of windowCells; track cell.key) {\n @if (cell.isSticky) {\n <sticky-header\n (layout)=\"handleCellLayout(cell.measure, $event)\"\n [style]=\"cellStyle\"\n >\n <ng-container\n [vListOutlet]=\"cellTemplate\"\n [vListOutletContext]=\"cell.context\"\n ></ng-container>\n @if (cell.separatorContext !== undefined) {\n <ng-container\n [vListOutlet]=\"separatorTemplate\"\n [vListOutletContext]=\"cell.separatorContext\"\n ></ng-container>\n }\n </sticky-header>\n } @else {\n <view\n (layout)=\"handleCellLayout(cell.measure, $event)\"\n [style]=\"cellStyle\"\n >\n <ng-container\n [vListOutlet]=\"cellTemplate\"\n [vListOutletContext]=\"cell.context\"\n ></ng-container>\n @if (cell.separatorContext !== undefined) {\n <ng-container\n [vListOutlet]=\"separatorTemplate\"\n [vListOutletContext]=\"cell.separatorContext\"\n ></ng-container>\n }\n </view>\n }\n }\n @if (trailingSpacerStyle !== null) {\n <view [style]=\"trailingSpacerStyle\"></view>\n }\n }\n\n @if (footerDir !== undefined) {\n <view>\n <ng-container [vListOutlet]=\"footerDir.templateRef\"></ng-container>\n </view>\n }\n </scroll-view>\n }\n ", isInline: true, dependencies: [{ kind: "directive", type: SymbioteHostPropsDirective, selector: "[symbioteHostProps]", inputs: ["symbioteHostProps"], exportAs: ["symbioteHost"] }, { kind: "directive", type: VListOutletDirective, selector: "[vListOutlet]", inputs: ["vListOutlet", "vListOutletContext"] }, { kind: "component", type: ViewHost, selector: "view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
990
275
|
}
|
|
991
276
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: VirtualizedList, decorators: [{
|
|
992
277
|
type: Component,
|
|
@@ -999,360 +284,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
999
284
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
1000
285
|
imports: [SymbioteHostPropsDirective, VListOutletDirective, ViewHost],
|
|
1001
286
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1002
|
-
template:
|
|
1003
|
-
@if (isHorizontal) {
|
|
1004
|
-
<horizontal-scroll-view #scrollHost [symbioteHostProps]="scrollViewBag()">
|
|
1005
|
-
@if (shouldRenderRefreshControl) {
|
|
1006
|
-
<refresh-control
|
|
1007
|
-
[symbioteHostProps]="refreshControlBag()"
|
|
1008
|
-
></refresh-control>
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
@if (headerDir !== undefined) {
|
|
1012
|
-
<view>
|
|
1013
|
-
<ng-container [vListOutlet]="headerDir.templateRef"></ng-container>
|
|
1014
|
-
</view>
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
@if (itemCount === 0) {
|
|
1018
|
-
@if (emptyDir !== undefined) {
|
|
1019
|
-
<view>
|
|
1020
|
-
<ng-container [vListOutlet]="emptyDir.templateRef"></ng-container>
|
|
1021
|
-
</view>
|
|
1022
|
-
}
|
|
1023
|
-
} @else {
|
|
1024
|
-
@if (leadingSpacerStyle !== null) {
|
|
1025
|
-
<view [style]="leadingSpacerStyle"></view>
|
|
1026
|
-
}
|
|
1027
|
-
@if (forcedStickyCell !== null) {
|
|
1028
|
-
<sticky-header
|
|
1029
|
-
(layout)="handleCellLayout(forcedStickyCell.measure, $event)"
|
|
1030
|
-
[style]="cellStyle"
|
|
1031
|
-
>
|
|
1032
|
-
<ng-container
|
|
1033
|
-
[vListOutlet]="cellTemplate"
|
|
1034
|
-
[vListOutletContext]="forcedStickyCell.context"
|
|
1035
|
-
></ng-container>
|
|
1036
|
-
</sticky-header>
|
|
1037
|
-
}
|
|
1038
|
-
@if (gapSpacerStyle !== null) {
|
|
1039
|
-
<view [style]="gapSpacerStyle"></view>
|
|
1040
|
-
}
|
|
1041
|
-
@for (cell of windowCells; track cell.key) {
|
|
1042
|
-
@if (cell.isSticky) {
|
|
1043
|
-
<sticky-header
|
|
1044
|
-
(layout)="handleCellLayout(cell.measure, $event)"
|
|
1045
|
-
[style]="cellStyle"
|
|
1046
|
-
>
|
|
1047
|
-
<ng-container
|
|
1048
|
-
[vListOutlet]="cellTemplate"
|
|
1049
|
-
[vListOutletContext]="cell.context"
|
|
1050
|
-
></ng-container>
|
|
1051
|
-
@if (cell.separatorContext !== undefined) {
|
|
1052
|
-
<ng-container
|
|
1053
|
-
[vListOutlet]="separatorTemplate"
|
|
1054
|
-
[vListOutletContext]="cell.separatorContext"
|
|
1055
|
-
></ng-container>
|
|
1056
|
-
}
|
|
1057
|
-
</sticky-header>
|
|
1058
|
-
} @else {
|
|
1059
|
-
<view
|
|
1060
|
-
(layout)="handleCellLayout(cell.measure, $event)"
|
|
1061
|
-
[style]="cellStyle"
|
|
1062
|
-
>
|
|
1063
|
-
<ng-container
|
|
1064
|
-
[vListOutlet]="cellTemplate"
|
|
1065
|
-
[vListOutletContext]="cell.context"
|
|
1066
|
-
></ng-container>
|
|
1067
|
-
@if (cell.separatorContext !== undefined) {
|
|
1068
|
-
<ng-container
|
|
1069
|
-
[vListOutlet]="separatorTemplate"
|
|
1070
|
-
[vListOutletContext]="cell.separatorContext"
|
|
1071
|
-
></ng-container>
|
|
1072
|
-
}
|
|
1073
|
-
</view>
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
@if (trailingSpacerStyle !== null) {
|
|
1077
|
-
<view [style]="trailingSpacerStyle"></view>
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
@if (footerDir !== undefined) {
|
|
1082
|
-
<view>
|
|
1083
|
-
<ng-container [vListOutlet]="footerDir.templateRef"></ng-container>
|
|
1084
|
-
</view>
|
|
1085
|
-
}
|
|
1086
|
-
</horizontal-scroll-view>
|
|
1087
|
-
} @else {
|
|
1088
|
-
<scroll-view #scrollHost [symbioteHostProps]="scrollViewBag()">
|
|
1089
|
-
@if (shouldRenderRefreshControl) {
|
|
1090
|
-
<refresh-control
|
|
1091
|
-
[symbioteHostProps]="refreshControlBag()"
|
|
1092
|
-
></refresh-control>
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
@if (headerDir !== undefined) {
|
|
1096
|
-
<view>
|
|
1097
|
-
<ng-container [vListOutlet]="headerDir.templateRef"></ng-container>
|
|
1098
|
-
</view>
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
@if (itemCount === 0) {
|
|
1102
|
-
@if (emptyDir !== undefined) {
|
|
1103
|
-
<view>
|
|
1104
|
-
<ng-container [vListOutlet]="emptyDir.templateRef"></ng-container>
|
|
1105
|
-
</view>
|
|
1106
|
-
}
|
|
1107
|
-
} @else {
|
|
1108
|
-
@if (leadingSpacerStyle !== null) {
|
|
1109
|
-
<view [style]="leadingSpacerStyle"></view>
|
|
1110
|
-
}
|
|
1111
|
-
@if (forcedStickyCell !== null) {
|
|
1112
|
-
<sticky-header
|
|
1113
|
-
(layout)="handleCellLayout(forcedStickyCell.measure, $event)"
|
|
1114
|
-
[style]="cellStyle"
|
|
1115
|
-
>
|
|
1116
|
-
<ng-container
|
|
1117
|
-
[vListOutlet]="cellTemplate"
|
|
1118
|
-
[vListOutletContext]="forcedStickyCell.context"
|
|
1119
|
-
></ng-container>
|
|
1120
|
-
</sticky-header>
|
|
1121
|
-
}
|
|
1122
|
-
@if (gapSpacerStyle !== null) {
|
|
1123
|
-
<view [style]="gapSpacerStyle"></view>
|
|
1124
|
-
}
|
|
1125
|
-
<!-- Separator sits INSIDE the measuring view, matching RN's cell renderer
|
|
1126
|
-
(VirtualizedListCellRenderer.js:218-221) — as a sibling it'd add an extra flex gap.
|
|
1127
|
-
See list-geometry-feedback-loop.md. -->
|
|
1128
|
-
@for (cell of windowCells; track cell.key) {
|
|
1129
|
-
@if (cell.isSticky) {
|
|
1130
|
-
<sticky-header
|
|
1131
|
-
(layout)="handleCellLayout(cell.measure, $event)"
|
|
1132
|
-
[style]="cellStyle"
|
|
1133
|
-
>
|
|
1134
|
-
<ng-container
|
|
1135
|
-
[vListOutlet]="cellTemplate"
|
|
1136
|
-
[vListOutletContext]="cell.context"
|
|
1137
|
-
></ng-container>
|
|
1138
|
-
@if (cell.separatorContext !== undefined) {
|
|
1139
|
-
<ng-container
|
|
1140
|
-
[vListOutlet]="separatorTemplate"
|
|
1141
|
-
[vListOutletContext]="cell.separatorContext"
|
|
1142
|
-
></ng-container>
|
|
1143
|
-
}
|
|
1144
|
-
</sticky-header>
|
|
1145
|
-
} @else {
|
|
1146
|
-
<view
|
|
1147
|
-
(layout)="handleCellLayout(cell.measure, $event)"
|
|
1148
|
-
[style]="cellStyle"
|
|
1149
|
-
>
|
|
1150
|
-
<ng-container
|
|
1151
|
-
[vListOutlet]="cellTemplate"
|
|
1152
|
-
[vListOutletContext]="cell.context"
|
|
1153
|
-
></ng-container>
|
|
1154
|
-
@if (cell.separatorContext !== undefined) {
|
|
1155
|
-
<ng-container
|
|
1156
|
-
[vListOutlet]="separatorTemplate"
|
|
1157
|
-
[vListOutletContext]="cell.separatorContext"
|
|
1158
|
-
></ng-container>
|
|
1159
|
-
}
|
|
1160
|
-
</view>
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
@if (trailingSpacerStyle !== null) {
|
|
1164
|
-
<view [style]="trailingSpacerStyle"></view>
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
@if (footerDir !== undefined) {
|
|
1169
|
-
<view>
|
|
1170
|
-
<ng-container [vListOutlet]="footerDir.templateRef"></ng-container>
|
|
1171
|
-
</view>
|
|
1172
|
-
}
|
|
1173
|
-
</scroll-view>
|
|
1174
|
-
}
|
|
1175
|
-
`,
|
|
287
|
+
template: VIRTUALIZED_LIST_TEMPLATE,
|
|
1176
288
|
}]
|
|
1177
|
-
}], propDecorators: {
|
|
1178
|
-
type: Output
|
|
1179
|
-
}], startReached: [{
|
|
1180
|
-
type: Output
|
|
1181
|
-
}], refresh: [{
|
|
1182
|
-
type: Output
|
|
1183
|
-
}], viewableItemsChanged: [{
|
|
1184
|
-
type: Output
|
|
1185
|
-
}], scrollToIndexFailed: [{
|
|
1186
|
-
type: Output
|
|
1187
|
-
}], accessibilityAction: [{
|
|
1188
|
-
type: Output
|
|
1189
|
-
}], accessibilityTap: [{
|
|
1190
|
-
type: Output
|
|
1191
|
-
}], magicTap: [{
|
|
1192
|
-
type: Output
|
|
1193
|
-
}], accessibilityEscape: [{
|
|
1194
|
-
type: Output
|
|
1195
|
-
}], data: [{
|
|
1196
|
-
type: Input,
|
|
1197
|
-
args: [{ required: true }]
|
|
1198
|
-
}], getItem: [{
|
|
1199
|
-
type: Input,
|
|
1200
|
-
args: [{ required: true }]
|
|
1201
|
-
}], getItemCount: [{
|
|
1202
|
-
type: Input,
|
|
1203
|
-
args: [{ required: true }]
|
|
1204
|
-
}], keyExtractor: [{
|
|
1205
|
-
type: Input
|
|
1206
|
-
}], getItemLayout: [{
|
|
1207
|
-
type: Input
|
|
1208
|
-
}], horizontal: [{
|
|
1209
|
-
type: Input
|
|
1210
|
-
}], inverted: [{
|
|
1211
|
-
type: Input
|
|
1212
|
-
}], extraData: [{
|
|
1213
|
-
type: Input
|
|
1214
|
-
}], onEndReachedThreshold: [{
|
|
1215
|
-
type: Input
|
|
1216
|
-
}], onStartReachedThreshold: [{
|
|
1217
|
-
type: Input
|
|
1218
|
-
}], refreshing: [{
|
|
1219
|
-
type: Input
|
|
1220
|
-
}], progressViewOffset: [{
|
|
1221
|
-
type: Input
|
|
1222
|
-
}], refreshRequested: [{
|
|
1223
|
-
type: Input
|
|
1224
|
-
}], viewabilityConfig: [{
|
|
1225
|
-
type: Input
|
|
1226
|
-
}], viewabilityConfigCallbackPairs: [{
|
|
1227
|
-
type: Input
|
|
1228
|
-
}], initialNumToRender: [{
|
|
1229
|
-
type: Input
|
|
1230
|
-
}], initialScrollIndex: [{
|
|
1231
|
-
type: Input
|
|
1232
|
-
}], maxToRenderPerBatch: [{
|
|
1233
|
-
type: Input
|
|
1234
|
-
}], updateCellsBatchingPeriod: [{
|
|
1235
|
-
type: Input
|
|
1236
|
-
}], windowSize: [{
|
|
1237
|
-
type: Input
|
|
1238
|
-
}], stickyHeaderIndices: [{
|
|
1239
|
-
type: Input
|
|
1240
|
-
}], maintainVisibleContentPosition: [{
|
|
1241
|
-
type: Input
|
|
1242
|
-
}], onScroll: [{
|
|
1243
|
-
type: Input
|
|
1244
|
-
}], onScrollBeginDrag: [{
|
|
1245
|
-
type: Input
|
|
1246
|
-
}], onScrollEndDrag: [{
|
|
1247
|
-
type: Input
|
|
1248
|
-
}], onMomentumScrollBegin: [{
|
|
1249
|
-
type: Input
|
|
1250
|
-
}], onMomentumScrollEnd: [{
|
|
1251
|
-
type: Input
|
|
1252
|
-
}], scrollEventThrottle: [{
|
|
1253
|
-
type: Input
|
|
1254
|
-
}], keyboardShouldPersistTaps: [{
|
|
1255
|
-
type: Input
|
|
1256
|
-
}], keyboardDismissMode: [{
|
|
1257
|
-
type: Input
|
|
1258
|
-
}], removeClippedSubviews: [{
|
|
1259
|
-
type: Input
|
|
1260
|
-
}], nestedScrollEnabled: [{
|
|
1261
|
-
type: Input
|
|
1262
|
-
}], style: [{
|
|
1263
|
-
type: Input
|
|
1264
|
-
}], contentContainerStyle: [{
|
|
1265
|
-
type: Input
|
|
1266
|
-
}], testID: [{
|
|
1267
|
-
type: Input
|
|
1268
|
-
}], nativeID: [{
|
|
1269
|
-
type: Input
|
|
1270
|
-
}], accessible: [{
|
|
1271
|
-
type: Input
|
|
1272
|
-
}], accessibilityLabel: [{
|
|
1273
|
-
type: Input
|
|
1274
|
-
}], accessibilityHint: [{
|
|
1275
|
-
type: Input
|
|
1276
|
-
}], accessibilityRole: [{
|
|
1277
|
-
type: Input
|
|
1278
|
-
}], accessibilityState: [{
|
|
1279
|
-
type: Input
|
|
1280
|
-
}], accessibilityValue: [{
|
|
1281
|
-
type: Input
|
|
1282
|
-
}], accessibilityActions: [{
|
|
1283
|
-
type: Input
|
|
1284
|
-
}], accessibilityLabelledBy: [{
|
|
1285
|
-
type: Input
|
|
1286
|
-
}], importantForAccessibility: [{
|
|
1287
|
-
type: Input
|
|
1288
|
-
}], accessibilityLiveRegion: [{
|
|
1289
|
-
type: Input
|
|
1290
|
-
}], screenReaderFocusable: [{
|
|
1291
|
-
type: Input
|
|
1292
|
-
}], accessibilityViewIsModal: [{
|
|
1293
|
-
type: Input
|
|
1294
|
-
}], accessibilityElementsHidden: [{
|
|
1295
|
-
type: Input
|
|
1296
|
-
}], accessibilityIgnoresInvertColors: [{
|
|
1297
|
-
type: Input
|
|
1298
|
-
}], accessibilityLanguage: [{
|
|
1299
|
-
type: Input
|
|
1300
|
-
}], accessibilityRespondsToUserInteraction: [{
|
|
1301
|
-
type: Input
|
|
1302
|
-
}], accessibilityShowsLargeContentViewer: [{
|
|
1303
|
-
type: Input
|
|
1304
|
-
}], accessibilityLargeContentTitle: [{
|
|
1305
|
-
type: Input
|
|
1306
|
-
}], role: [{
|
|
1307
|
-
type: Input
|
|
1308
|
-
}], ariaLabel: [{
|
|
1309
|
-
type: Input
|
|
1310
|
-
}], ariaLabelledBy: [{
|
|
1311
|
-
type: Input
|
|
1312
|
-
}], ariaLive: [{
|
|
1313
|
-
type: Input
|
|
1314
|
-
}], ariaHidden: [{
|
|
1315
|
-
type: Input
|
|
1316
|
-
}], ariaBusy: [{
|
|
1317
|
-
type: Input
|
|
1318
|
-
}], ariaChecked: [{
|
|
1319
|
-
type: Input
|
|
1320
|
-
}], ariaDisabled: [{
|
|
1321
|
-
type: Input
|
|
1322
|
-
}], ariaExpanded: [{
|
|
1323
|
-
type: Input
|
|
1324
|
-
}], ariaSelected: [{
|
|
1325
|
-
type: Input
|
|
1326
|
-
}], ariaModal: [{
|
|
1327
|
-
type: Input
|
|
1328
|
-
}], ariaValueMax: [{
|
|
1329
|
-
type: Input
|
|
1330
|
-
}], ariaValueMin: [{
|
|
1331
|
-
type: Input
|
|
1332
|
-
}], ariaValueNow: [{
|
|
1333
|
-
type: Input
|
|
1334
|
-
}], ariaValueText: [{
|
|
1335
|
-
type: Input
|
|
1336
|
-
}], itemDir: [{
|
|
1337
|
-
type: ContentChild,
|
|
1338
|
-
args: [VListItemDirective]
|
|
1339
|
-
}], headerDir: [{
|
|
1340
|
-
type: ContentChild,
|
|
1341
|
-
args: [VListHeaderDirective]
|
|
1342
|
-
}], footerDir: [{
|
|
1343
|
-
type: ContentChild,
|
|
1344
|
-
args: [VListFooterDirective]
|
|
1345
|
-
}], emptyDir: [{
|
|
1346
|
-
type: ContentChild,
|
|
1347
|
-
args: [VListEmptyDirective]
|
|
1348
|
-
}], separatorDir: [{
|
|
1349
|
-
type: ContentChild,
|
|
1350
|
-
args: [VListSeparatorDirective]
|
|
1351
|
-
}], itemTemplate: [{
|
|
1352
|
-
type: Input
|
|
1353
|
-
}], itemSeparatorTemplate: [{
|
|
1354
|
-
type: Input
|
|
1355
|
-
}], scrollHostRef: [{
|
|
289
|
+
}], propDecorators: { scrollHostRef: [{
|
|
1356
290
|
type: ViewChild,
|
|
1357
291
|
args: ['scrollHost', { read: ElementRef }]
|
|
1358
292
|
}] } });
|