@symbiote-native/angular 3.1.2 → 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,22 +1,6 @@
|
|
|
1
|
-
// VirtualizedSectionList
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// so headers/items/footers are all windowed by the same machinery. The flattening, entry keying,
|
|
5
|
-
// separator-item unwrap, and scrollToLocation mapping are shared from @symbiote-native/components; this
|
|
6
|
-
// file wires Angular's lifecycle (typed @Input/@Output surface + the imperative handle + the
|
|
7
|
-
// per-cell-tag template dispatch). The Angular twin of the React/Vue adapters' VirtualizedSectionList.
|
|
8
|
-
//
|
|
9
|
-
// The KEY mechanic — per-cell-tag template dispatch. VirtualizedList renders every cell through ONE
|
|
10
|
-
// `vListItem` template, but a section list has DIFFERENT cell types (section header, item, section
|
|
11
|
-
// footer, between-section separators). So VSL supplies the inner list a SINGLE synthesized
|
|
12
|
-
// `vListItem` template that @switch-es on the flattened entry's tag and stamps the matching app
|
|
13
|
-
// template (captured via @ContentChild on the vSection* directives) through VListOutletDirective.
|
|
14
|
-
// list-level header/footer/empty/item-separator reuse VirtualizedList's own directives, forwarded
|
|
15
|
-
// the same way. Only the cell-AUTHORING shape is framework-specific; the rest of the surface
|
|
16
|
-
// stays shared with React/Vue.
|
|
17
|
-
//
|
|
18
|
-
// Accessibility / aria props are forwarded unchanged to the inner VirtualizedList, which owns the
|
|
19
|
-
// shared aria→accessibility* fold before the props reach the ScrollView host.
|
|
1
|
+
// VirtualizedSectionList flattens sections into one virtualized stream over VirtualizedList
|
|
2
|
+
// Flattening, entry keying and `scrollToLocation` are shared from `@symbiote-native/components`
|
|
3
|
+
// This file is the Angular lifecycle and the per-entry template dispatch
|
|
20
4
|
|
|
21
5
|
import {
|
|
22
6
|
ChangeDetectionStrategy,
|
|
@@ -24,9 +8,7 @@ import {
|
|
|
24
8
|
Component,
|
|
25
9
|
ContentChild,
|
|
26
10
|
ElementRef,
|
|
27
|
-
EventEmitter,
|
|
28
11
|
Input,
|
|
29
|
-
Output,
|
|
30
12
|
ViewChild,
|
|
31
13
|
inject,
|
|
32
14
|
type DoCheck,
|
|
@@ -38,7 +20,6 @@ import {
|
|
|
38
20
|
sectionEntryKey,
|
|
39
21
|
unwrapEntryItem,
|
|
40
22
|
type IAccessibilityProps,
|
|
41
|
-
type IAccessibilityStateValue,
|
|
42
23
|
type IAriaProps,
|
|
43
24
|
type ISection,
|
|
44
25
|
type ISectionEntry,
|
|
@@ -64,6 +45,8 @@ import {
|
|
|
64
45
|
type IVListSeparatorContext,
|
|
65
46
|
} from '../virtualized-list';
|
|
66
47
|
import { VListOutletDirective } from '../virtualized-list/directives';
|
|
48
|
+
import { ListEventsBase } from '../virtualized-list/list-events';
|
|
49
|
+
import { provideGateDemand } from '../../gate-demand';
|
|
67
50
|
import {
|
|
68
51
|
stableAnchorStyle,
|
|
69
52
|
SymbioteStyleInputDirective,
|
|
@@ -76,48 +59,32 @@ import {
|
|
|
76
59
|
type IVSectionContext,
|
|
77
60
|
type IVSectionItemContext,
|
|
78
61
|
} from './directives';
|
|
62
|
+
import { VIRTUALIZED_SECTION_LIST_TEMPLATE } from './section-list-template';
|
|
79
63
|
|
|
80
64
|
export type { ISection } from '@symbiote-native/components';
|
|
81
|
-
// Re-export the shared handle type so section-list imports it from '../virtualized-section-list'.
|
|
82
65
|
export type { IVirtualizedSectionListHandle } from '@symbiote-native/components';
|
|
83
|
-
// Re-export the section authoring directives + their contexts so flat consumers (and SectionList)
|
|
84
|
-
// import them from '../virtualized-section-list', mirroring how VirtualizedList re-exports its own.
|
|
85
66
|
export {
|
|
86
67
|
VSectionFooterDirective,
|
|
87
68
|
VSectionHeaderDirective,
|
|
88
69
|
VSectionItemDirective,
|
|
89
70
|
VSectionSeparatorDirective,
|
|
90
71
|
} from './directives';
|
|
91
|
-
import {
|
|
92
|
-
gateWanted,
|
|
93
|
-
injectGateDemandAbove,
|
|
94
|
-
provideGateDemand,
|
|
95
|
-
type IGatedAccessibilityEvent,
|
|
96
|
-
} from '../../gate-demand';
|
|
97
72
|
export type { IVSectionContext, IVSectionItemContext } from './directives';
|
|
98
73
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
// Everything agnostic is the SAME surface as the
|
|
103
|
-
// React/Vue adapters, including the a11y/aria prop family forwarded through VirtualizedList.
|
|
74
|
+
type IItemLayout = { length: number; offset: number; index: number };
|
|
75
|
+
|
|
76
|
+
// The React and Vue surface minus element-returning props, which are `<ng-template>` here
|
|
104
77
|
export interface IVirtualizedSectionListProps<ItemT>
|
|
105
78
|
extends IAccessibilityProps, IAriaProps {
|
|
106
79
|
sections: ReadonlyArray<ISection<ItemT>>;
|
|
107
80
|
keyExtractor?: (item: ItemT, index: number) => string;
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
// A `({ section, index })` form would be our invention, not parity - `VirtualizedSectionList.js`
|
|
111
|
-
// has no getItemLayout code at all, the prop rides through `passThroughProps`; that shape is the
|
|
112
|
-
// community react-native-section-list-get-item-layout, layered on top. Without it a fast scroll
|
|
113
|
-
// outruns measurement and leaves blank windows.
|
|
81
|
+
// Flat like RN's: the sections array plus a flat entry index, where every section adds two rows
|
|
82
|
+
// beyond its items (header, footer). Without it a fast scroll outruns measurement
|
|
114
83
|
getItemLayout?: (
|
|
115
84
|
data: ReadonlyArray<ISection<ItemT>> | null,
|
|
116
85
|
index: number,
|
|
117
|
-
) =>
|
|
118
|
-
//
|
|
119
|
-
// VirtualizedList's stickyHeaderIndices. Defaults to `Platform.OS === 'ios'`; Android does not
|
|
120
|
-
// stick by default. Pass true/false to override.
|
|
86
|
+
) => IItemLayout;
|
|
87
|
+
// Defaults to `Platform.OS === 'ios'`, pass true or false to override
|
|
121
88
|
stickySectionHeadersEnabled?: boolean;
|
|
122
89
|
extraData?: unknown;
|
|
123
90
|
onEndReached?: (info: { distanceFromEnd: number }) => void;
|
|
@@ -151,9 +118,7 @@ export interface IVirtualizedSectionListProps<ItemT>
|
|
|
151
118
|
contentContainerStyle?: IStyleProp<IViewStyle>;
|
|
152
119
|
}
|
|
153
120
|
|
|
154
|
-
//
|
|
155
|
-
// minus the list-lifecycle events, which it exposes as real @Output() EventEmitters instead (see
|
|
156
|
-
// the class below) — mirrors IAngularPressableInputs in pressable/index.ts.
|
|
121
|
+
// The plain inputs: the full surface minus the events exposed as real outputs
|
|
157
122
|
export type IVirtualizedSectionListInputs<ItemT> = Omit<
|
|
158
123
|
IVirtualizedSectionListProps<ItemT>,
|
|
159
124
|
| 'onEndReached'
|
|
@@ -182,155 +147,10 @@ export type IVirtualizedSectionListInputs<ItemT> = Omit<
|
|
|
182
147
|
VListOutletDirective,
|
|
183
148
|
],
|
|
184
149
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
185
|
-
template:
|
|
186
|
-
<VirtualizedList
|
|
187
|
-
[data]="flatEntries"
|
|
188
|
-
[getItem]="getEntry"
|
|
189
|
-
[getItemCount]="getEntryCount"
|
|
190
|
-
[keyExtractor]="entryKeyExtractor"
|
|
191
|
-
[getItemLayout]="entryItemLayout"
|
|
192
|
-
[stickyHeaderIndices]="stickyHeaderIndices"
|
|
193
|
-
[extraData]="extraData"
|
|
194
|
-
[inverted]="inverted"
|
|
195
|
-
[refreshing]="refreshing"
|
|
196
|
-
[progressViewOffset]="progressViewOffset"
|
|
197
|
-
[refreshRequested]="refreshRequested ?? refresh.observed"
|
|
198
|
-
(refresh)="resolvedOnRefresh?.()"
|
|
199
|
-
(endReached)="resolvedOnEndReached?.($event)"
|
|
200
|
-
[onEndReachedThreshold]="onEndReachedThreshold"
|
|
201
|
-
(startReached)="resolvedOnStartReached?.($event)"
|
|
202
|
-
[onStartReachedThreshold]="onStartReachedThreshold"
|
|
203
|
-
[initialNumToRender]="initialNumToRender"
|
|
204
|
-
[initialScrollIndex]="initialScrollIndex"
|
|
205
|
-
[maxToRenderPerBatch]="maxToRenderPerBatch"
|
|
206
|
-
[updateCellsBatchingPeriod]="updateCellsBatchingPeriod"
|
|
207
|
-
[windowSize]="windowSize"
|
|
208
|
-
[maintainVisibleContentPosition]="maintainVisibleContentPosition"
|
|
209
|
-
[onScroll]="onScroll"
|
|
210
|
-
[onScrollBeginDrag]="onScrollBeginDrag"
|
|
211
|
-
[onScrollEndDrag]="onScrollEndDrag"
|
|
212
|
-
[onMomentumScrollBegin]="onMomentumScrollBegin"
|
|
213
|
-
[onMomentumScrollEnd]="onMomentumScrollEnd"
|
|
214
|
-
[scrollEventThrottle]="scrollEventThrottle"
|
|
215
|
-
[keyboardShouldPersistTaps]="keyboardShouldPersistTaps"
|
|
216
|
-
[keyboardDismissMode]="keyboardDismissMode"
|
|
217
|
-
[removeClippedSubviews]="removeClippedSubviews"
|
|
218
|
-
[nestedScrollEnabled]="nestedScrollEnabled"
|
|
219
|
-
[style]="resolvedStyle"
|
|
220
|
-
[contentContainerStyle]="contentContainerStyle"
|
|
221
|
-
[testID]="testID"
|
|
222
|
-
[nativeID]="nativeID"
|
|
223
|
-
[accessible]="accessible"
|
|
224
|
-
[accessibilityLabel]="accessibilityLabel"
|
|
225
|
-
[accessibilityHint]="accessibilityHint"
|
|
226
|
-
[accessibilityRole]="accessibilityRole"
|
|
227
|
-
[accessibilityState]="accessibilityState"
|
|
228
|
-
[accessibilityValue]="accessibilityValue"
|
|
229
|
-
[accessibilityActions]="accessibilityActions"
|
|
230
|
-
[accessibilityLabelledBy]="accessibilityLabelledBy"
|
|
231
|
-
[importantForAccessibility]="importantForAccessibility"
|
|
232
|
-
[accessibilityLiveRegion]="accessibilityLiveRegion"
|
|
233
|
-
[screenReaderFocusable]="screenReaderFocusable"
|
|
234
|
-
[accessibilityViewIsModal]="accessibilityViewIsModal"
|
|
235
|
-
[accessibilityElementsHidden]="accessibilityElementsHidden"
|
|
236
|
-
[accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
|
|
237
|
-
[accessibilityLanguage]="accessibilityLanguage"
|
|
238
|
-
[accessibilityRespondsToUserInteraction]="
|
|
239
|
-
accessibilityRespondsToUserInteraction
|
|
240
|
-
"
|
|
241
|
-
[accessibilityShowsLargeContentViewer]="
|
|
242
|
-
accessibilityShowsLargeContentViewer
|
|
243
|
-
"
|
|
244
|
-
[accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
|
|
245
|
-
(accessibilityAction)="resolvedOnAccessibilityAction?.($event)"
|
|
246
|
-
(accessibilityTap)="resolvedOnAccessibilityTap?.($event)"
|
|
247
|
-
(magicTap)="resolvedOnMagicTap?.($event)"
|
|
248
|
-
(accessibilityEscape)="resolvedOnAccessibilityEscape?.($event)"
|
|
249
|
-
[role]="role"
|
|
250
|
-
[ariaLabel]="ariaLabel"
|
|
251
|
-
[ariaLabelledBy]="ariaLabelledBy"
|
|
252
|
-
[ariaLive]="ariaLive"
|
|
253
|
-
[ariaHidden]="ariaHidden"
|
|
254
|
-
[ariaBusy]="ariaBusy"
|
|
255
|
-
[ariaChecked]="ariaChecked"
|
|
256
|
-
[ariaDisabled]="ariaDisabled"
|
|
257
|
-
[ariaExpanded]="ariaExpanded"
|
|
258
|
-
[ariaSelected]="ariaSelected"
|
|
259
|
-
[ariaModal]="ariaModal"
|
|
260
|
-
[ariaValueMax]="ariaValueMax"
|
|
261
|
-
[ariaValueMin]="ariaValueMin"
|
|
262
|
-
[ariaValueNow]="ariaValueNow"
|
|
263
|
-
[ariaValueText]="ariaValueText"
|
|
264
|
-
>
|
|
265
|
-
<!-- The single synthesized cell template: dispatch per flattened entry tag. -->
|
|
266
|
-
<ng-template vListItem let-entry let-separators="separators">
|
|
267
|
-
@switch (entryKind(entry)) {
|
|
268
|
-
@case ('header') {
|
|
269
|
-
<ng-container
|
|
270
|
-
[vListOutlet]="sectionHeaderDir?.templateRef"
|
|
271
|
-
[vListOutletContext]="sectionContextOf(entry)"
|
|
272
|
-
></ng-container>
|
|
273
|
-
}
|
|
274
|
-
@case ('footer') {
|
|
275
|
-
<ng-container
|
|
276
|
-
[vListOutlet]="sectionFooterDir?.templateRef"
|
|
277
|
-
[vListOutletContext]="sectionContextOf(entry)"
|
|
278
|
-
></ng-container>
|
|
279
|
-
}
|
|
280
|
-
@case ('section-separator') {
|
|
281
|
-
<ng-container
|
|
282
|
-
[vListOutlet]="sectionSeparatorDir?.templateRef"
|
|
283
|
-
></ng-container>
|
|
284
|
-
}
|
|
285
|
-
@case ('item') {
|
|
286
|
-
<ng-container
|
|
287
|
-
[vListOutlet]="sectionItemDir?.templateRef"
|
|
288
|
-
[vListOutletContext]="itemContextOf(entry, separators)"
|
|
289
|
-
></ng-container>
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
</ng-template>
|
|
293
|
-
|
|
294
|
-
<!-- list-level slots: forward the app's VirtualizedList directives to the inner list. -->
|
|
295
|
-
@if (listHeaderDir !== undefined) {
|
|
296
|
-
<ng-template vListHeader>
|
|
297
|
-
<ng-container
|
|
298
|
-
[vListOutlet]="listHeaderDir.templateRef"
|
|
299
|
-
></ng-container>
|
|
300
|
-
</ng-template>
|
|
301
|
-
}
|
|
302
|
-
@if (listFooterDir !== undefined) {
|
|
303
|
-
<ng-template vListFooter>
|
|
304
|
-
<ng-container
|
|
305
|
-
[vListOutlet]="listFooterDir.templateRef"
|
|
306
|
-
></ng-container>
|
|
307
|
-
</ng-template>
|
|
308
|
-
}
|
|
309
|
-
@if (listEmptyDir !== undefined) {
|
|
310
|
-
<ng-template vListEmpty>
|
|
311
|
-
<ng-container [vListOutlet]="listEmptyDir.templateRef"></ng-container>
|
|
312
|
-
</ng-template>
|
|
313
|
-
}
|
|
314
|
-
<!-- item separator: forward, unwrapping each flattened entry back to its ItemT. -->
|
|
315
|
-
@if (itemSeparatorDir !== undefined) {
|
|
316
|
-
<ng-template
|
|
317
|
-
vListSeparator
|
|
318
|
-
let-highlighted
|
|
319
|
-
let-leadingItem="leadingItem"
|
|
320
|
-
let-trailingItem="trailingItem"
|
|
321
|
-
>
|
|
322
|
-
<ng-container
|
|
323
|
-
[vListOutlet]="itemSeparatorDir.templateRef"
|
|
324
|
-
[vListOutletContext]="
|
|
325
|
-
itemSeparatorContextOf(highlighted, leadingItem, trailingItem)
|
|
326
|
-
"
|
|
327
|
-
></ng-container>
|
|
328
|
-
</ng-template>
|
|
329
|
-
}
|
|
330
|
-
</VirtualizedList>
|
|
331
|
-
`,
|
|
150
|
+
template: VIRTUALIZED_SECTION_LIST_TEMPLATE,
|
|
332
151
|
})
|
|
333
152
|
export class VirtualizedSectionList<ItemT = unknown>
|
|
153
|
+
extends ListEventsBase
|
|
334
154
|
implements
|
|
335
155
|
IVirtualizedSectionListInputs<ItemT>,
|
|
336
156
|
IVirtualizedSectionListHandle,
|
|
@@ -341,24 +161,15 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
341
161
|
@Input() getItemLayout?: (
|
|
342
162
|
data: ReadonlyArray<ISection<ItemT>> | null,
|
|
343
163
|
index: number,
|
|
344
|
-
) =>
|
|
164
|
+
) => IItemLayout;
|
|
345
165
|
@Input() stickySectionHeadersEnabled?: boolean;
|
|
346
166
|
@Input() extraData?: unknown;
|
|
347
|
-
@Output() readonly endReached = new EventEmitter<{
|
|
348
|
-
distanceFromEnd: number;
|
|
349
|
-
}>();
|
|
350
167
|
@Input() onEndReachedThreshold?: number;
|
|
351
|
-
@Output() readonly startReached = new EventEmitter<{
|
|
352
|
-
distanceFromStart: number;
|
|
353
|
-
}>();
|
|
354
168
|
@Input() onStartReachedThreshold?: number;
|
|
355
|
-
@Output() readonly refresh = new EventEmitter<void>();
|
|
356
169
|
@Input() refreshing?: boolean | null;
|
|
357
170
|
@Input() progressViewOffset?: number;
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
// which would otherwise make its `.observed` permanently true. SectionList passes ITS OWN
|
|
361
|
-
// public `refresh.observed` here; direct usage falls back to this component's own `.observed`.
|
|
171
|
+
// The template always subscribes to the inner list's refresh to re-forward it, which keeps that
|
|
172
|
+
// `.observed` true. `SectionList` passes its own public `refresh.observed` here instead
|
|
362
173
|
@Input() refreshRequested?: boolean;
|
|
363
174
|
@Input() initialNumToRender?: number;
|
|
364
175
|
@Input() initialScrollIndex?: number;
|
|
@@ -385,17 +196,8 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
385
196
|
@Input() testID?: string;
|
|
386
197
|
@Input() nativeID?: string;
|
|
387
198
|
|
|
388
|
-
//
|
|
389
|
-
//
|
|
390
|
-
// `style={[a, b]}` composition idiom crashes deep inside Angular's styling engine), so this
|
|
391
|
-
// flattens `style` via the engine's own flattenStyle before it ever reaches that binding.
|
|
392
|
-
// anchorHostStyle merges in this component's OWN anchor's class-derived style (see its doc
|
|
393
|
-
// comment) — `elementRef` below is VirtualizedSectionList's OWN host, not `list`'s inner
|
|
394
|
-
// VirtualizedList. A plain `flattenStyle([...])` here would allocate a FRESH object on every
|
|
395
|
-
// getter read, which — bound onto the inner VirtualizedList's own `@Input() style` — defeats
|
|
396
|
-
// its `ngDoCheck` dedup gate and free-runs change detection forever (see stableAnchorStyle's
|
|
397
|
-
// doc comment and the `flat-list-array-style.test.ts` regression it fixes).
|
|
398
|
-
// `cachedResolvedStyle` is the getter's own persisted "previous" value across reads.
|
|
199
|
+
// A flat object bound to `[style]`, merged with this host's own class-derived style. A fresh
|
|
200
|
+
// object per read would defeat the inner list's dedup gate, `stableAnchorStyle` keeps it steady
|
|
399
201
|
private cachedResolvedStyle: Record<string, unknown> | undefined;
|
|
400
202
|
get resolvedStyle(): IViewStyle {
|
|
401
203
|
this.cachedResolvedStyle = stableAnchorStyle(
|
|
@@ -405,59 +207,8 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
405
207
|
);
|
|
406
208
|
return this.cachedResolvedStyle;
|
|
407
209
|
}
|
|
408
|
-
@Input() accessible?: boolean;
|
|
409
|
-
@Input() accessibilityLabel?: string;
|
|
410
|
-
@Input() accessibilityHint?: string;
|
|
411
|
-
@Input() accessibilityRole?: IAccessibilityProps['accessibilityRole'];
|
|
412
|
-
@Input() accessibilityState?: IAccessibilityStateValue;
|
|
413
|
-
@Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
|
|
414
|
-
@Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
|
|
415
|
-
@Input() accessibilityLabelledBy?: string | string[];
|
|
416
|
-
@Input()
|
|
417
|
-
importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
|
|
418
|
-
@Input()
|
|
419
|
-
accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
|
|
420
|
-
@Input() screenReaderFocusable?: boolean;
|
|
421
|
-
@Input() accessibilityViewIsModal?: boolean;
|
|
422
|
-
@Input() accessibilityElementsHidden?: boolean;
|
|
423
|
-
@Input() accessibilityIgnoresInvertColors?: boolean;
|
|
424
|
-
@Input() accessibilityLanguage?: string;
|
|
425
|
-
@Input() accessibilityRespondsToUserInteraction?: boolean;
|
|
426
|
-
@Input() accessibilityShowsLargeContentViewer?: boolean;
|
|
427
|
-
@Input() accessibilityLargeContentTitle?: string;
|
|
428
|
-
@Output() readonly accessibilityAction = new EventEmitter<ISymbioteEvent>();
|
|
429
|
-
@Output() readonly accessibilityTap = new EventEmitter<ISymbioteEvent>();
|
|
430
|
-
@Output() readonly magicTap = new EventEmitter<ISymbioteEvent>();
|
|
431
|
-
@Output() readonly accessibilityEscape = new EventEmitter<ISymbioteEvent>();
|
|
432
|
-
|
|
433
|
-
// This wrapper binds the four gated accessibility events on the component it renders, which
|
|
434
|
-
// Angular forces to be unconditional and which would light that component's gates on every
|
|
435
|
-
// instance. It answers for them instead — see `gate-demand.ts`.
|
|
436
|
-
private readonly gateDemandAbove = injectGateDemandAbove();
|
|
437
|
-
|
|
438
|
-
wantsGate(name: IGatedAccessibilityEvent): boolean {
|
|
439
|
-
return gateWanted(this.gateDemandAbove, name, this[name]);
|
|
440
|
-
}
|
|
441
210
|
|
|
442
|
-
|
|
443
|
-
@Input() ariaLabel?: string;
|
|
444
|
-
@Input() ariaLabelledBy?: string;
|
|
445
|
-
@Input() ariaLive?: IAriaProps['aria-live'];
|
|
446
|
-
@Input() ariaHidden?: boolean;
|
|
447
|
-
@Input() ariaBusy?: boolean;
|
|
448
|
-
@Input() ariaChecked?: boolean | 'mixed';
|
|
449
|
-
@Input() ariaDisabled?: boolean;
|
|
450
|
-
@Input() ariaExpanded?: boolean;
|
|
451
|
-
@Input() ariaSelected?: boolean;
|
|
452
|
-
@Input() ariaModal?: boolean;
|
|
453
|
-
@Input() ariaValueMax?: number;
|
|
454
|
-
@Input() ariaValueMin?: number;
|
|
455
|
-
@Input() ariaValueNow?: number;
|
|
456
|
-
@Input() ariaValueText?: string;
|
|
457
|
-
|
|
458
|
-
// The section cell templates the app authors (the Angular twin of renderItem /
|
|
459
|
-
// renderSectionHeader / renderSectionFooter / SectionSeparatorComponent), captured from projected
|
|
460
|
-
// <ng-template> content and stamped by the synthesized vListItem dispatch.
|
|
211
|
+
// The section cell templates the app authors, stamped by the synthesized entry dispatch
|
|
461
212
|
@ContentChild(VSectionItemDirective)
|
|
462
213
|
sectionItemDir?: VSectionItemDirective<ItemT>;
|
|
463
214
|
@ContentChild(VSectionHeaderDirective)
|
|
@@ -467,33 +218,27 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
467
218
|
@ContentChild(VSectionSeparatorDirective)
|
|
468
219
|
sectionSeparatorDir?: VSectionSeparatorDirective;
|
|
469
220
|
|
|
470
|
-
//
|
|
221
|
+
// List-level slots reuse the `VirtualizedList` directives and are forwarded to the inner list
|
|
471
222
|
@ContentChild(VListHeaderDirective) listHeaderDir?: VListHeaderDirective;
|
|
472
223
|
@ContentChild(VListFooterDirective) listFooterDir?: VListFooterDirective;
|
|
473
224
|
@ContentChild(VListEmptyDirective) listEmptyDir?: VListEmptyDirective;
|
|
474
225
|
@ContentChild(VListSeparatorDirective)
|
|
475
226
|
itemSeparatorDir?: VListSeparatorDirective<ItemT>;
|
|
476
227
|
|
|
477
|
-
// The
|
|
478
|
-
// handle delegates straight to it. Available from ngAfterViewInit; reads lazily, no-ops pre-commit.
|
|
228
|
+
// The inner list, whose instance is the scroll handle, reads lazily and no-ops before commit
|
|
479
229
|
@ViewChild(VirtualizedList) private list?: VirtualizedList<
|
|
480
230
|
ISectionEntry<ItemT>
|
|
481
231
|
>;
|
|
482
232
|
|
|
483
|
-
// This component's
|
|
484
|
-
// onto (see anchorHostStyle's doc comment) — NOT `list` above, which targets the real inner
|
|
485
|
-
// `<VirtualizedList>` one level down (itself its own separate anchor host).
|
|
233
|
+
// This component's own host, the anchor `class="..."` resolves onto, not the inner list's
|
|
486
234
|
private readonly elementRef = inject(ElementRef);
|
|
487
235
|
|
|
488
|
-
// --- template-bound state, recomputed in ngDoCheck when sections / separator presence change ---
|
|
489
236
|
flatEntries: ISectionEntry<ItemT>[] = [];
|
|
490
237
|
stickyHeaderIndices: number[] | undefined = undefined;
|
|
491
238
|
|
|
492
|
-
//
|
|
493
|
-
// (sectionIndex, itemIndex) coordinate through them without re-deriving the flat layout.
|
|
239
|
+
// Flat positions of every section header, so `scrollToLocation` skips re-deriving the layout
|
|
494
240
|
private headerIndices: number[] = [];
|
|
495
|
-
// Memo guards
|
|
496
|
-
// every scroll tick, which re-runs VSL's ngDoCheck too).
|
|
241
|
+
// Memo guards, the inner list marks for check on every scroll tick and re-runs `ngDoCheck`
|
|
497
242
|
private lastSectionsRef: ReadonlyArray<ISection<ItemT>> | null = null;
|
|
498
243
|
private lastHasSectionSeparator = false;
|
|
499
244
|
|
|
@@ -518,7 +263,7 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
518
263
|
this.flatEntries = entries;
|
|
519
264
|
this.headerIndices = headerIndices;
|
|
520
265
|
|
|
521
|
-
// RN sticks section headers by default only on iOS
|
|
266
|
+
// RN sticks section headers by default only on iOS
|
|
522
267
|
this.stickyHeaderIndices = resolveStickySectionHeaders(
|
|
523
268
|
this.stickySectionHeadersEnabled,
|
|
524
269
|
headerIndices,
|
|
@@ -531,57 +276,34 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
531
276
|
this.cdr.markForCheck();
|
|
532
277
|
}
|
|
533
278
|
|
|
534
|
-
//
|
|
535
|
-
// the bindings keep a constant identity; they read the live flatEntries.
|
|
279
|
+
// Stable arrow fields, so the bindings to the inner list keep a constant identity
|
|
536
280
|
getEntry = (_source: unknown, index: number): ISectionEntry<ItemT> =>
|
|
537
281
|
this.flatEntries[index];
|
|
538
282
|
getEntryCount = (): number => this.flatEntries.length;
|
|
539
283
|
entryKeyExtractor = (entry: ISectionEntry<ItemT>, index: number): string =>
|
|
540
284
|
sectionEntryKey(entry, index, this.keyExtractor);
|
|
541
285
|
|
|
542
|
-
//
|
|
543
|
-
//
|
|
544
|
-
//
|
|
545
|
-
|
|
546
|
-
// UPSTREAM-DIVERGENCE(react-native): the flat INDEX matches RN's (two rows per section, header
|
|
547
|
-
// and footer) only while the vSectionSeparator template is unset. With it, flattenSections emits
|
|
548
|
-
// an extra 'section-separator' row per boundary that RN renders inside the neighbouring cell, so
|
|
549
|
-
// indices shift by one per boundary from the second section on. Deliberate - that row is how this
|
|
550
|
-
// adapter paints the separator; a caller combining the two must account for it.
|
|
551
|
-
//
|
|
552
|
-
// Cached on the input's own identity, like resolvedStyle above: the inner VirtualizedList folds
|
|
553
|
-
// getItemLayout into its ngDoCheck dedup array, so a wrapper allocated per getter read would
|
|
554
|
-
// re-run its whole recompute every CD.
|
|
555
|
-
private cachedEntryItemLayout?: (
|
|
556
|
-
data: unknown,
|
|
557
|
-
index: number,
|
|
558
|
-
) => { length: number; offset: number; index: number };
|
|
286
|
+
// RN hands the callback `sections`, not the flattened entries. The flat index matches RN's only
|
|
287
|
+
// while no section separator template is set, which adds one row per boundary here
|
|
288
|
+
// Cached on the input's identity, the inner list folds it into its dedup array
|
|
289
|
+
private cachedEntryItemLayout?: (data: unknown, index: number) => IItemLayout;
|
|
559
290
|
private lastGetItemLayout?: IVirtualizedSectionListProps<ItemT>['getItemLayout'];
|
|
560
291
|
get entryItemLayout():
|
|
561
|
-
|
|
|
562
|
-
data: unknown,
|
|
563
|
-
index: number,
|
|
564
|
-
) => { length: number; offset: number; index: number })
|
|
565
|
-
| undefined {
|
|
292
|
+
((data: unknown, index: number) => IItemLayout) | undefined {
|
|
566
293
|
if (this.getItemLayout !== this.lastGetItemLayout) {
|
|
567
294
|
const getItemLayout = this.getItemLayout;
|
|
568
295
|
this.lastGetItemLayout = getItemLayout;
|
|
569
296
|
this.cachedEntryItemLayout =
|
|
570
297
|
getItemLayout === undefined
|
|
571
298
|
? undefined
|
|
572
|
-
: (
|
|
573
|
-
_entries: unknown,
|
|
574
|
-
index: number,
|
|
575
|
-
): { length: number; offset: number; index: number } =>
|
|
299
|
+
: (_entries: unknown, index: number): IItemLayout =>
|
|
576
300
|
getItemLayout(this.sections, index);
|
|
577
301
|
}
|
|
578
302
|
return this.cachedEntryItemLayout;
|
|
579
303
|
}
|
|
580
304
|
|
|
581
|
-
//
|
|
582
|
-
//
|
|
583
|
-
// contract the old @Input() callback passthrough had (e.g. onRefresh presence gates whether a
|
|
584
|
-
// RefreshControl is built downstream; see the Vue twin's `listens('onRefresh')` gate).
|
|
305
|
+
// Each output becomes the plain callback the inner list wants, or `undefined` when nobody
|
|
306
|
+
// listens, since a callback's presence gates whether a `RefreshControl` is built downstream
|
|
585
307
|
get resolvedOnEndReached():
|
|
586
308
|
((info: { distanceFromEnd: number }) => void) | undefined {
|
|
587
309
|
return this.endReached.observed
|
|
@@ -600,36 +322,7 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
600
322
|
return this.refresh.observed ? () => this.refresh.emit() : undefined;
|
|
601
323
|
}
|
|
602
324
|
|
|
603
|
-
|
|
604
|
-
((event: ISymbioteEvent) => void) | undefined {
|
|
605
|
-
return this.accessibilityAction.observed
|
|
606
|
-
? event => this.accessibilityAction.emit(event)
|
|
607
|
-
: undefined;
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
get resolvedOnAccessibilityTap():
|
|
611
|
-
((event: ISymbioteEvent) => void) | undefined {
|
|
612
|
-
return this.accessibilityTap.observed
|
|
613
|
-
? event => this.accessibilityTap.emit(event)
|
|
614
|
-
: undefined;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
get resolvedOnMagicTap(): ((event: ISymbioteEvent) => void) | undefined {
|
|
618
|
-
return this.magicTap.observed
|
|
619
|
-
? event => this.magicTap.emit(event)
|
|
620
|
-
: undefined;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
get resolvedOnAccessibilityEscape():
|
|
624
|
-
((event: ISymbioteEvent) => void) | undefined {
|
|
625
|
-
return this.accessibilityEscape.observed
|
|
626
|
-
? event => this.accessibilityEscape.emit(event)
|
|
627
|
-
: undefined;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// --- per-cell-tag dispatch (the inner vListItem context is typed `unknown` under strictTemplates,
|
|
631
|
-
// since VListItemDirective's generic is not bound here; narrow with a runtime guard, no casts). ---
|
|
632
|
-
|
|
325
|
+
// The inner cell context is typed `unknown` under strict templates, so entries are narrowed
|
|
633
326
|
private isEntry(value: unknown): value is ISectionEntry<ItemT> {
|
|
634
327
|
return typeof value === 'object' && value !== null && 'kind' in value;
|
|
635
328
|
}
|
|
@@ -658,10 +351,8 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
658
351
|
};
|
|
659
352
|
}
|
|
660
353
|
|
|
661
|
-
// The inner
|
|
662
|
-
//
|
|
663
|
-
// real items (header/footer/section-separator gaps unwrap to undefined). Mirrors the React/Vue
|
|
664
|
-
// entrySeparatorComponent wrap.
|
|
354
|
+
// The inner separator context carries flattened entries, unwrapped back to real items so the
|
|
355
|
+
// app's separator, typed on the item, never sees an envelope
|
|
665
356
|
itemSeparatorContextOf(
|
|
666
357
|
highlighted: unknown,
|
|
667
358
|
leadingItem: unknown,
|
|
@@ -679,8 +370,6 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
679
370
|
};
|
|
680
371
|
}
|
|
681
372
|
|
|
682
|
-
// ---- imperative handle (the shared IVirtualizedSectionListHandle surface) ----
|
|
683
|
-
|
|
684
373
|
scrollToLocation(params: {
|
|
685
374
|
sectionIndex: number;
|
|
686
375
|
itemIndex: number;
|