@symbiote-native/angular 0.6.0 → 0.6.2

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.
Files changed (193) hide show
  1. package/README.md +1 -1
  2. package/babel-register-composed.cjs +11 -3
  3. package/build/angular/anchor-host-registry.d.ts +2 -0
  4. package/build/angular/anchor-host-registry.js +84 -0
  5. package/build/angular/anchor-host-registry.js.map +1 -0
  6. package/build/angular/components/input-accessory-view/index.d.ts +2 -1
  7. package/build/angular/components/input-accessory-view/index.js +28 -39
  8. package/build/angular/components/input-accessory-view/index.js.map +1 -1
  9. package/build/angular/components/scroll-view/projection.js +70 -48
  10. package/build/angular/components/scroll-view/projection.js.map +1 -1
  11. package/build/angular/components/scroll-view/shared.js +28 -25
  12. package/build/angular/components/scroll-view/shared.js.map +1 -1
  13. package/build/angular/components/scroll-view/sticky-header.d.ts +6 -7
  14. package/build/angular/components/scroll-view/sticky-header.js +82 -65
  15. package/build/angular/components/scroll-view/sticky-header.js.map +1 -1
  16. package/build/angular/components/touchable/index.d.ts +2 -5
  17. package/build/angular/components/touchable/index.js +36 -56
  18. package/build/angular/components/touchable/index.js.map +1 -1
  19. package/build/angular/components/virtualized-list/index.d.ts +5 -20
  20. package/build/angular/components/virtualized-list/index.js +145 -275
  21. package/build/angular/components/virtualized-list/index.js.map +1 -1
  22. package/build/angular/components/virtualized-section-list/index.js +2 -4
  23. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  24. package/build/angular/index.d.ts +2 -1
  25. package/build/angular/index.js +6 -1
  26. package/build/angular/index.js.map +1 -1
  27. package/build/angular/renderer/index.d.ts +0 -1
  28. package/build/angular/renderer/index.js +5 -60
  29. package/build/angular/renderer/index.js.map +1 -1
  30. package/package.json +8 -4
  31. package/src/anchor-host-registry.ts +88 -0
  32. package/src/components/input-accessory-view/index.ts +30 -39
  33. package/src/components/scroll-view/projection.ts +76 -46
  34. package/src/components/scroll-view/shared.ts +27 -19
  35. package/src/components/scroll-view/sticky-header.ts +89 -64
  36. package/src/components/touchable/index.ts +52 -66
  37. package/src/components/virtualized-list/index.ts +157 -368
  38. package/src/components/virtualized-section-list/index.ts +6 -3
  39. package/src/index.ts +6 -1
  40. package/src/renderer/index.ts +5 -63
  41. package/build/bootstrap.d.ts +0 -7
  42. package/build/bootstrap.js +0 -14
  43. package/build/components/activity-indicator/index.android.d.ts +0 -9
  44. package/build/components/activity-indicator/index.android.js +0 -64
  45. package/build/components/activity-indicator/index.d.ts +0 -1
  46. package/build/components/activity-indicator/index.ios.d.ts +0 -5
  47. package/build/components/activity-indicator/index.ios.js +0 -64
  48. package/build/components/activity-indicator/index.js +0 -3
  49. package/build/components/activity-indicator/shared.d.ts +0 -64
  50. package/build/components/activity-indicator/shared.js +0 -424
  51. package/build/components/button.d.ts +0 -60
  52. package/build/components/button.js +0 -456
  53. package/build/components/flat-list/index.d.ts +0 -119
  54. package/build/components/flat-list/index.js +0 -691
  55. package/build/components/image/index.android.d.ts +0 -7
  56. package/build/components/image/index.android.js +0 -88
  57. package/build/components/image/index.d.ts +0 -1
  58. package/build/components/image/index.ios.d.ts +0 -7
  59. package/build/components/image/index.ios.js +0 -88
  60. package/build/components/image/index.js +0 -2
  61. package/build/components/image/shared.d.ts +0 -101
  62. package/build/components/image/shared.js +0 -405
  63. package/build/components/image-background.d.ts +0 -78
  64. package/build/components/image-background.js +0 -583
  65. package/build/components/input-accessory-view/index.d.ts +0 -56
  66. package/build/components/input-accessory-view/index.js +0 -403
  67. package/build/components/keyboard-avoiding-view/index.d.ts +0 -79
  68. package/build/components/keyboard-avoiding-view/index.js +0 -504
  69. package/build/components/modal/index.d.ts +0 -89
  70. package/build/components/modal/index.js +0 -529
  71. package/build/components/pressable/index.d.ts +0 -120
  72. package/build/components/pressable/index.js +0 -639
  73. package/build/components/refresh-control/index.d.ts +0 -83
  74. package/build/components/refresh-control/index.js +0 -509
  75. package/build/components/safe-area-view/index.d.ts +0 -54
  76. package/build/components/safe-area-view/index.js +0 -388
  77. package/build/components/scroll-view/index.android.d.ts +0 -16
  78. package/build/components/scroll-view/index.android.js +0 -228
  79. package/build/components/scroll-view/index.d.ts +0 -3
  80. package/build/components/scroll-view/index.ios.d.ts +0 -6
  81. package/build/components/scroll-view/index.ios.js +0 -113
  82. package/build/components/scroll-view/index.js +0 -5
  83. package/build/components/scroll-view/projection.d.ts +0 -32
  84. package/build/components/scroll-view/projection.js +0 -311
  85. package/build/components/scroll-view/shared.d.ts +0 -225
  86. package/build/components/scroll-view/shared.js +0 -757
  87. package/build/components/scroll-view/sticky-header.d.ts +0 -38
  88. package/build/components/scroll-view/sticky-header.js +0 -257
  89. package/build/components/section-list/index.d.ts +0 -113
  90. package/build/components/section-list/index.js +0 -768
  91. package/build/components/switch/index.android.d.ts +0 -17
  92. package/build/components/switch/index.android.js +0 -107
  93. package/build/components/switch/index.d.ts +0 -1
  94. package/build/components/switch/index.ios.d.ts +0 -16
  95. package/build/components/switch/index.ios.js +0 -106
  96. package/build/components/switch/index.js +0 -3
  97. package/build/components/switch/shared.d.ts +0 -37
  98. package/build/components/switch/shared.js +0 -176
  99. package/build/components/text-input.d.ts +0 -150
  100. package/build/components/text-input.js +0 -821
  101. package/build/components/touchable/index.d.ts +0 -241
  102. package/build/components/touchable/index.js +0 -1672
  103. package/build/components/touchable-native-feedback/index.d.ts +0 -80
  104. package/build/components/touchable-native-feedback/index.js +0 -545
  105. package/build/components/virtualized-list/directives.d.ts +0 -41
  106. package/build/components/virtualized-list/directives.js +0 -249
  107. package/build/components/virtualized-list/index.d.ts +0 -265
  108. package/build/components/virtualized-list/index.js +0 -1343
  109. package/build/components/virtualized-section-list/directives.d.ts +0 -28
  110. package/build/components/virtualized-section-list/directives.js +0 -148
  111. package/build/components/virtualized-section-list/index.d.ts +0 -175
  112. package/build/components/virtualized-section-list/index.js +0 -854
  113. package/build/components.d.ts +0 -39
  114. package/build/components.js +0 -37
  115. package/build/create-portal/index.d.ts +0 -17
  116. package/build/create-portal/index.js +0 -128
  117. package/build/create-tunnel/index.d.ts +0 -29
  118. package/build/create-tunnel/index.js +0 -181
  119. package/build/descriptor-to-angular/index.d.ts +0 -19
  120. package/build/descriptor-to-angular/index.js +0 -186
  121. package/build/host-instance/index.d.ts +0 -2
  122. package/build/host-instance/index.js +0 -36
  123. package/build/index.d.ts +0 -21
  124. package/build/index.js +0 -40
  125. package/build/modules/animated/animated-leaf-binder/index.d.ts +0 -14
  126. package/build/modules/animated/animated-leaf-binder/index.js +0 -90
  127. package/build/modules/animated/animated-leaf-binder.d.ts +0 -14
  128. package/build/modules/animated/animated-leaf-binder.js +0 -90
  129. package/build/modules/animated/create-animated-component.d.ts +0 -48
  130. package/build/modules/animated/create-animated-component.js +0 -425
  131. package/build/modules/animated/index.d.ts +0 -51
  132. package/build/modules/animated/index.js +0 -58
  133. package/build/modules/app-registry/index.d.ts +0 -7
  134. package/build/modules/app-registry/index.js +0 -22
  135. package/build/modules/status-bar/index.d.ts +0 -17
  136. package/build/modules/status-bar/index.js +0 -121
  137. package/build/primitives/index.d.ts +0 -32
  138. package/build/primitives/index.js +0 -386
  139. package/build/primitives/shared.d.ts +0 -83
  140. package/build/primitives/shared.js +0 -230
  141. package/build/render/index.d.ts +0 -11
  142. package/build/render/index.js +0 -170
  143. package/build/renderer/index.d.ts +0 -38
  144. package/build/renderer/index.js +0 -355
  145. package/build/services/color-scheme.service.d.ts +0 -13
  146. package/build/services/color-scheme.service.js +0 -72
  147. package/build/services/index.d.ts +0 -2
  148. package/build/services/index.js +0 -2
  149. package/build/services/window-dimensions.service.d.ts +0 -13
  150. package/build/services/window-dimensions.service.js +0 -83
  151. package/src/__tests__/responder-change-detection.test.ts +0 -102
  152. package/src/__tests__/responder-nested-cd.test.ts +0 -113
  153. package/src/angular-gaps.test.ts +0 -142
  154. package/src/angular-imports.test.ts +0 -100
  155. package/src/components/activity-indicator/activity-indicator-class-style.test.ts +0 -44
  156. package/src/components/activity-indicator/activity-indicator.test.ts +0 -131
  157. package/src/components/flat-list/column-wrapper-style-class.test.ts +0 -116
  158. package/src/components/flat-list/flat-list-array-style.test.ts +0 -131
  159. package/src/components/flat-list/flat-list-class-style.test.ts +0 -74
  160. package/src/components/flat-list/flat-list-scroll-containment.test.ts +0 -107
  161. package/src/components/flat-list/flat-list.test.ts +0 -99
  162. package/src/components/image/image-class-style.test.ts +0 -46
  163. package/src/components/image-background-class-style.test.ts +0 -48
  164. package/src/components/image-background-style-class.test.ts +0 -79
  165. package/src/components/input-accessory-view/input-accessory-view.test.ts +0 -43
  166. package/src/components/keyboard-avoiding-view/keyboard-avoiding-view.test.ts +0 -54
  167. package/src/components/modal/modal.test.ts +0 -43
  168. package/src/components/pressable/pressable.test.ts +0 -85
  169. package/src/components/refresh-control/refresh-control.test.ts +0 -41
  170. package/src/components/safe-area-view/safe-area-view.test.ts +0 -43
  171. package/src/components/scroll-view/android-scroll-view-axis-projection.test.ts +0 -123
  172. package/src/components/scroll-view/content-container-style-class.test.ts +0 -75
  173. package/src/components/scroll-view/scroll-view-class-style.test.ts +0 -134
  174. package/src/components/scroll-view/scroll-view-projection.test.ts +0 -194
  175. package/src/components/switch/android-switch-class.test.ts +0 -42
  176. package/src/components/switch/switch.test.ts +0 -92
  177. package/src/components/text-input-class-style.test.ts +0 -54
  178. package/src/components/touchable/touchable.test.ts +0 -102
  179. package/src/components/touchable-native-feedback/touchable-native-feedback.test.ts +0 -49
  180. package/src/components/virtualized-list/virtualized-list-class-style.test.ts +0 -76
  181. package/src/components/virtualized-section-list/virtualized-section-list-class-style.test.ts +0 -60
  182. package/src/create-portal/create-portal.test.ts +0 -90
  183. package/src/create-tunnel/create-tunnel.test.ts +0 -120
  184. package/src/descriptor-to-angular/descriptor-outlet.test.ts +0 -94
  185. package/src/host-instance/host-instance.test.ts +0 -49
  186. package/src/modules/animated/animated-leaf-binder/animated-leaf-binder.test.ts +0 -116
  187. package/src/modules/animated/animated-leaf-binder.test.ts +0 -116
  188. package/src/modules/animated/animated-scroll-view.test.ts +0 -102
  189. package/src/modules/app-registry/app-registry.test.ts +0 -106
  190. package/src/modules/status-bar/status-bar.test.ts +0 -50
  191. package/src/render/render.test.ts +0 -147
  192. package/src/renderer/renderer.test.ts +0 -202
  193. package/src/services/services.test.ts +0 -163
@@ -181,22 +181,12 @@ export declare class VirtualizedList<ItemT = unknown> implements IVirtualizedLis
181
181
  x: number;
182
182
  y: number;
183
183
  } | undefined;
184
- private scrollOffset;
185
- private viewportLength;
186
- private measureVersion;
187
- private metricsCore;
188
- private readonly measured;
184
+ private readonly listState;
185
+ private renderVersion;
189
186
  private readonly cellMeasures;
190
187
  private readonly separatorOverrides;
191
- private committedWindow;
192
- private sentEndForContentLength;
193
- private sentStartForContentLength;
194
- private lastViewable;
195
188
  private viewableTimer;
196
189
  private batchTimer;
197
- private hasInteracted;
198
- private appliedInitialScroll;
199
- private firstVisibleKey;
200
190
  private lastEffectSignature;
201
191
  private lastRecompute;
202
192
  private readonly cdr;
@@ -219,10 +209,12 @@ export declare class VirtualizedList<ItemT = unknown> implements IVirtualizedLis
219
209
  magicTapTick: (event: ISymbioteEvent) => void;
220
210
  accessibilityEscapeTick: (event: ISymbioteEvent) => void;
221
211
  private keyFor;
212
+ private buildInputs;
213
+ private dispatch;
214
+ private runEffects;
222
215
  ngDoCheck(): void;
223
216
  ngAfterViewChecked(): void;
224
217
  ngOnDestroy(): void;
225
- private recomputeMetrics;
226
218
  private recomputeView;
227
219
  private buildSeparatorContext;
228
220
  private spacerStyle;
@@ -256,13 +248,6 @@ export declare class VirtualizedList<ItemT = unknown> implements IVirtualizedLis
256
248
  getScrollNode(): ISymbioteNode | null;
257
249
  recordInteraction(): void;
258
250
  private scrollToPixel;
259
- private offsetForIndexLocal;
260
- private effectBatchFill;
261
- private effectEndReached;
262
- private effectStartReached;
263
- private effectViewability;
264
- private effectInitialScroll;
265
- private effectMaintainVisibleContentPosition;
266
251
  static ɵfac: i0.ɵɵFactoryDeclaration<VirtualizedList<any>, never>;
267
252
  static ɵcmp: i0.ɵɵComponentDeclaration<VirtualizedList<any>, "VirtualizedList", never, { "data": { "alias": "data"; "required": true; }; "getItem": { "alias": "getItem"; "required": true; }; "getItemCount": { "alias": "getItemCount"; "required": true; }; "keyExtractor": { "alias": "keyExtractor"; "required": false; }; "getItemLayout": { "alias": "getItemLayout"; "required": false; }; "horizontal": { "alias": "horizontal"; "required": false; }; "inverted": { "alias": "inverted"; "required": false; }; "extraData": { "alias": "extraData"; "required": false; }; "onEndReachedThreshold": { "alias": "onEndReachedThreshold"; "required": false; }; "onStartReachedThreshold": { "alias": "onStartReachedThreshold"; "required": false; }; "refreshing": { "alias": "refreshing"; "required": false; }; "progressViewOffset": { "alias": "progressViewOffset"; "required": false; }; "refreshRequested": { "alias": "refreshRequested"; "required": false; }; "viewabilityConfig": { "alias": "viewabilityConfig"; "required": false; }; "viewabilityConfigCallbackPairs": { "alias": "viewabilityConfigCallbackPairs"; "required": false; }; "initialNumToRender": { "alias": "initialNumToRender"; "required": false; }; "initialScrollIndex": { "alias": "initialScrollIndex"; "required": false; }; "maxToRenderPerBatch": { "alias": "maxToRenderPerBatch"; "required": false; }; "updateCellsBatchingPeriod": { "alias": "updateCellsBatchingPeriod"; "required": false; }; "windowSize": { "alias": "windowSize"; "required": false; }; "stickyHeaderIndices": { "alias": "stickyHeaderIndices"; "required": false; }; "maintainVisibleContentPosition": { "alias": "maintainVisibleContentPosition"; "required": false; }; "onScroll": { "alias": "onScroll"; "required": false; }; "onScrollBeginDrag": { "alias": "onScrollBeginDrag"; "required": false; }; "onScrollEndDrag": { "alias": "onScrollEndDrag"; "required": false; }; "onMomentumScrollBegin": { "alias": "onMomentumScrollBegin"; "required": false; }; "onMomentumScrollEnd": { "alias": "onMomentumScrollEnd"; "required": false; }; "scrollEventThrottle": { "alias": "scrollEventThrottle"; "required": false; }; "keyboardShouldPersistTaps": { "alias": "keyboardShouldPersistTaps"; "required": false; }; "keyboardDismissMode": { "alias": "keyboardDismissMode"; "required": false; }; "style": { "alias": "style"; "required": false; }; "contentContainerStyle": { "alias": "contentContainerStyle"; "required": false; }; "testID": { "alias": "testID"; "required": false; }; "nativeID": { "alias": "nativeID"; "required": false; }; "accessible": { "alias": "accessible"; "required": false; }; "accessibilityLabel": { "alias": "accessibilityLabel"; "required": false; }; "accessibilityHint": { "alias": "accessibilityHint"; "required": false; }; "accessibilityRole": { "alias": "accessibilityRole"; "required": false; }; "accessibilityState": { "alias": "accessibilityState"; "required": false; }; "accessibilityValue": { "alias": "accessibilityValue"; "required": false; }; "accessibilityActions": { "alias": "accessibilityActions"; "required": false; }; "accessibilityLabelledBy": { "alias": "accessibilityLabelledBy"; "required": false; }; "importantForAccessibility": { "alias": "importantForAccessibility"; "required": false; }; "accessibilityLiveRegion": { "alias": "accessibilityLiveRegion"; "required": false; }; "screenReaderFocusable": { "alias": "screenReaderFocusable"; "required": false; }; "accessibilityViewIsModal": { "alias": "accessibilityViewIsModal"; "required": false; }; "accessibilityElementsHidden": { "alias": "accessibilityElementsHidden"; "required": false; }; "accessibilityIgnoresInvertColors": { "alias": "accessibilityIgnoresInvertColors"; "required": false; }; "accessibilityLanguage": { "alias": "accessibilityLanguage"; "required": false; }; "accessibilityRespondsToUserInteraction": { "alias": "accessibilityRespondsToUserInteraction"; "required": false; }; "accessibilityShowsLargeContentViewer": { "alias": "accessibilityShowsLargeContentViewer"; "required": false; }; "accessibilityLargeContentTitle": { "alias": "accessibilityLargeContentTitle"; "required": false; }; "role": { "alias": "role"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "ariaLabelledBy": { "alias": "ariaLabelledBy"; "required": false; }; "ariaLive": { "alias": "ariaLive"; "required": false; }; "ariaHidden": { "alias": "ariaHidden"; "required": false; }; "ariaBusy": { "alias": "ariaBusy"; "required": false; }; "ariaChecked": { "alias": "ariaChecked"; "required": false; }; "ariaDisabled": { "alias": "ariaDisabled"; "required": false; }; "ariaExpanded": { "alias": "ariaExpanded"; "required": false; }; "ariaSelected": { "alias": "ariaSelected"; "required": false; }; "ariaModal": { "alias": "ariaModal"; "required": false; }; "ariaValueMax": { "alias": "ariaValueMax"; "required": false; }; "ariaValueMin": { "alias": "ariaValueMin"; "required": false; }; "ariaValueNow": { "alias": "ariaValueNow"; "required": false; }; "ariaValueText": { "alias": "ariaValueText"; "required": false; }; }, { "endReached": "endReached"; "startReached": "startReached"; "refresh": "refresh"; "viewableItemsChanged": "viewableItemsChanged"; "scrollToIndexFailed": "scrollToIndexFailed"; "accessibilityAction": "accessibilityAction"; "accessibilityTap": "accessibilityTap"; "magicTap": "magicTap"; "accessibilityEscape": "accessibilityEscape"; }, ["itemDir", "headerDir", "footerDir", "emptyDir", "separatorDir"], never, true, never>;
268
253
  }
@@ -24,7 +24,7 @@
24
24
  // Lists have no Descriptor render fn — the cell content is the framework's own children.
25
25
  // Cells/spacers are plain symbiote-view host elements.
26
26
  import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, Input, Output, ViewChild, inject, } from '@angular/core';
27
- import { DEFAULT_END_REACHED_THRESHOLD, DEFAULT_INITIAL_NUM_TO_RENDER, DEFAULT_MAX_TO_RENDER_PER_BATCH, DEFAULT_START_REACHED_THRESHOLD, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD, DEFAULT_WINDOW_SIZE, EMPTY_OFFSET, FIRST_INDEX, INVERTED_X_STYLE, INVERTED_Y_STYLE, NO_CONTENT_LENGTH_SENT, averageMeasuredLength, buildListPlan, buildOffsets, buildViewabilityPairs, computeEndReached, computeStartReached, computeViewableSet, computeWindow, diffViewable, highestMeasuredIndex, maxMinimumViewTime, offsetForIndex, readLayoutLength, readScrollOffset, resolveAccessibilityProps, throttleWindow, } from '@symbiote-native/components';
27
+ import { DEFAULT_END_REACHED_THRESHOLD, DEFAULT_INITIAL_NUM_TO_RENDER, DEFAULT_MAX_TO_RENDER_PER_BATCH, DEFAULT_START_REACHED_THRESHOLD, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD, DEFAULT_WINDOW_SIZE, EMPTY_OFFSET, FIRST_INDEX, INVERTED_X_STYLE, INVERTED_Y_STYLE, buildListPlan, buildViewabilityPairs, createInitialListState, isSeparatorGapInRange, listEffectSignature, readLayoutLength, readScrollOffset, reduceList, resolveAccessibilityProps, resolveItemKey, } from '@symbiote-native/components';
28
28
  import { dlog, flattenStyle, } from '@symbiote-native/engine';
29
29
  import { ScrollView } from '../scroll-view';
30
30
  import { RefreshControl } from '../refresh-control';
@@ -148,34 +148,18 @@ export class VirtualizedList {
148
148
  // The offset we are imperatively driving native to before the scroll handle attaches (rides down
149
149
  // as contentOffset). A fresh object identity each push so the commit re-applies a repeated value.
150
150
  commandedOffset = undefined;
151
- // --- reactive scalars (mutated by the native callbacks; markForCheck re-runs the CD) ---
152
- scrollOffset = EMPTY_OFFSET;
153
- viewportLength = EMPTY_OFFSET;
154
- measureVersion = EMPTY_OFFSET;
155
- // --- non-render state (the Angular twin of refs that never trigger a render) ---
156
- metricsCore = {
157
- count: EMPTY_OFFSET,
158
- offsets: [],
159
- lengths: [],
160
- total: EMPTY_OFFSET,
161
- first: FIRST_INDEX,
162
- last: -1,
163
- target: { first: FIRST_INDEX, last: -1 },
164
- averageLength: EMPTY_OFFSET,
165
- };
166
- measured = new Map();
151
+ // The one folded state cell (the Angular twin of React's stateRef): scroll offset, viewport,
152
+ // measured lengths, committed window, edge/viewability dedup, MVCP anchor — all in IListState,
153
+ // driven by the shared reduceList. `renderVersion` bumps whenever a transition changes render
154
+ // state, so ngDoCheck's recompute-dedup can detect it (listState is a plain object, not tracked).
155
+ listState = createInitialListState();
156
+ renderVersion = EMPTY_OFFSET;
167
157
  cellMeasures = new Map();
168
158
  separatorOverrides = new Map();
169
- // The previously committed window, grown by at most maxToRenderPerBatch per tick (no snap).
170
- committedWindow = { first: FIRST_INDEX, last: -1 };
171
- sentEndForContentLength = NO_CONTENT_LENGTH_SENT;
172
- sentStartForContentLength = NO_CONTENT_LENGTH_SENT;
173
- lastViewable = new Map();
159
+ // The adapter-owned debounce (minimumViewTime) and incremental-fill timers; the reducer only
160
+ // hands back a delay.
174
161
  viewableTimer = null;
175
162
  batchTimer = null;
176
- hasInteracted = false;
177
- appliedInitialScroll = false;
178
- firstVisibleKey = null;
179
163
  // Dedupes the after-commit effects: they run only when the windowing signature changed.
180
164
  lastEffectSignature = '';
181
165
  // Dedupes ngDoCheck's own recompute. WITHOUT this, recomputeView() unconditionally rebuilds
@@ -269,22 +253,18 @@ export class VirtualizedList {
269
253
  if (offset === undefined)
270
254
  return;
271
255
  dlog(`Angular VirtualizedList onScroll offset=${offset}`);
272
- // First scroll is the interaction that ungates waitForInteraction configs.
273
- this.hasInteracted = true;
274
- this.scrollOffset = offset;
275
256
  // A real native scroll supersedes any pending commanded offset.
276
257
  this.commandedOffset = undefined;
258
+ this.dispatch({ kind: 'scroll', offset });
277
259
  // Compose, don't clobber: internal windowing ran first, now the user's onScroll.
278
260
  this.onScroll?.(event);
279
- this.cdr.markForCheck();
280
261
  };
281
262
  onLayoutTick = (event) => {
282
263
  const length = readLayoutLength(event, this.isHorizontal);
283
264
  if (length === undefined)
284
265
  return;
285
266
  dlog(`Angular VirtualizedList onLayout viewport=${length}`);
286
- this.viewportLength = length;
287
- this.cdr.markForCheck();
267
+ this.dispatch({ kind: 'layout', length });
288
268
  };
289
269
  // RefreshControl's refresh and ScrollView's accessibility events are real @Output()s now, bound
290
270
  // via (refresh)="handleRefresh()" / (accessibilityAction)="accessibilityActionTick($event)" etc.
@@ -306,13 +286,105 @@ export class VirtualizedList {
306
286
  };
307
287
  keyFor = (index) => {
308
288
  const item = this.getItem(this.data, index);
309
- return this.keyExtractor ? this.keyExtractor(item, index) : String(index);
289
+ return resolveItemKey(item, index, this.keyExtractor);
310
290
  };
291
+ // The reducer inputs, folded off the @Input()s each call. The edge/viewability listeners map to
292
+ // `.observed` (Angular's "is anyone bound to this @Output()"), so the reducer emits only when the
293
+ // consumer listens — the same on-demand gating the prop-callback era had.
294
+ buildInputs() {
295
+ return {
296
+ data: this.data,
297
+ getItem: this.getItem,
298
+ getItemCount: this.getItemCount,
299
+ keyExtractor: this.keyExtractor,
300
+ getItemLayout: this.getItemLayout,
301
+ horizontal: this.isHorizontal,
302
+ windowSize: this.windowSizeValue,
303
+ initialNumToRender: this.initialNumToRenderValue,
304
+ maxToRenderPerBatch: this.maxToRenderPerBatchValue,
305
+ updateCellsBatchingPeriod: this.updateCellsBatchingPeriodValue,
306
+ onEndReachedThreshold: this.onEndReachedThresholdValue,
307
+ onStartReachedThreshold: this.onStartReachedThresholdValue,
308
+ onEndReachedActive: this.endReached.observed,
309
+ onStartReachedActive: this.startReached.observed,
310
+ viewabilityPairs: buildViewabilityPairs(this.viewableItemsChanged.observed
311
+ ? (info) => this.viewableItemsChanged.emit(info)
312
+ : undefined, this.viewabilityConfig, this.viewabilityConfigCallbackPairs),
313
+ maintainVisibleContentPosition: this.maintainVisibleContentPosition,
314
+ initialScrollIndex: this.initialScrollIndex,
315
+ };
316
+ }
317
+ // Map a native event / imperative call to an action, run the returned effects, and mark the view
318
+ // dirty when render state changed (the native callbacks fire outside Angular's own bindings).
319
+ dispatch(action) {
320
+ const inputs = this.buildInputs();
321
+ const result = reduceList(this.listState, action, inputs);
322
+ this.runEffects(result.effects, inputs);
323
+ if (result.changed) {
324
+ this.renderVersion += 1;
325
+ this.cdr.markForCheck();
326
+ }
327
+ }
328
+ runEffects(effects, inputs) {
329
+ for (const effect of effects) {
330
+ switch (effect.kind) {
331
+ case 'scroll-to':
332
+ this.scrollToPixel(effect.offset, effect.animated);
333
+ break;
334
+ case 'fire-end-reached':
335
+ this.endReached.emit({ distanceFromEnd: effect.distanceFromEnd });
336
+ break;
337
+ case 'fire-start-reached':
338
+ this.startReached.emit({ distanceFromStart: effect.distanceFromStart });
339
+ break;
340
+ case 'fire-scroll-to-index-failed':
341
+ this.scrollToIndexFailed.emit({
342
+ index: effect.index,
343
+ highestMeasuredFrameIndex: effect.highestMeasuredFrameIndex,
344
+ averageItemLength: effect.averageItemLength,
345
+ });
346
+ break;
347
+ case 'schedule-refill': {
348
+ if (this.batchTimer !== null)
349
+ clearTimeout(this.batchTimer);
350
+ this.batchTimer = setTimeout(() => {
351
+ this.batchTimer = null;
352
+ this.dispatch({ kind: 'batch-tick' });
353
+ }, effect.delay);
354
+ break;
355
+ }
356
+ case 'fire-viewable': {
357
+ const pairs = inputs.viewabilityPairs;
358
+ const info = effect.info;
359
+ const map = effect.map;
360
+ const fire = () => {
361
+ for (const pair of pairs)
362
+ pair.onViewableItemsChanged(info);
363
+ this.dispatch({ kind: 'viewable-fired', map });
364
+ };
365
+ if (this.viewableTimer !== null) {
366
+ clearTimeout(this.viewableTimer);
367
+ this.viewableTimer = null;
368
+ }
369
+ if (effect.delay > EMPTY_OFFSET) {
370
+ this.viewableTimer = setTimeout(() => {
371
+ this.viewableTimer = null;
372
+ fire();
373
+ }, effect.delay);
374
+ }
375
+ else {
376
+ fire();
377
+ }
378
+ break;
379
+ }
380
+ }
381
+ }
382
+ }
311
383
  // Once-per-CD recompute, BEFORE the template bindings are read (so the freshly computed
312
384
  // template-bound fields render this pass — computing them in ngAfterContentChecked instead would
313
- // trip ExpressionChangedAfterItHasBeenChecked). recomputeMetrics owns the controlled committedWindow
314
- // throttle (the side effect React runs during render); ngDoCheck is its single evaluation point, so
315
- // the window grows exactly one step per CD. The projected templates (ContentChild) are resolved
385
+ // trip ExpressionChangedAfterItHasBeenChecked). The dedup guard runs refresh-metrics (which owns
386
+ // the controlled committedWindow throttle) only when something relevant changed, so the window
387
+ // grows exactly one step per meaningful CD. The projected templates (ContentChild) are resolved
316
388
  // from the second CD on; the first paint (count/viewport still 0) corrects on the layout-driven CD.
317
389
  ngDoCheck() {
318
390
  const recomputeInputs = [
@@ -329,9 +401,8 @@ export class VirtualizedList {
329
401
  this.maintainVisibleContentPosition,
330
402
  this.style,
331
403
  this.contentContainerStyle,
332
- this.scrollOffset,
333
- this.viewportLength,
334
- this.measureVersion,
404
+ // Folds scroll / layout / measure / batch-tick: dispatch bumps renderVersion on any change.
405
+ this.renderVersion,
335
406
  this.headerDir !== undefined,
336
407
  this.footerDir !== undefined,
337
408
  this.emptyDir !== undefined,
@@ -344,21 +415,18 @@ export class VirtualizedList {
344
415
  previous.every((value, index) => value === recomputeInputs[index])) {
345
416
  return;
346
417
  }
347
- this.recomputeMetrics();
418
+ // The single derive-per-CD: recompute the window off the current state before the view reads it.
419
+ reduceList(this.listState, { kind: 'refresh-metrics' }, this.buildInputs());
348
420
  this.recomputeView();
349
421
  }
350
422
  ngAfterViewChecked() {
351
- const m = this.metricsCore;
352
- const signature = `${this.scrollOffset}|${this.viewportLength}|${m.first}|${m.last}|${m.count}|${m.total}|${this.measureVersion}`;
423
+ const signature = listEffectSignature(this.listState);
353
424
  if (signature === this.lastEffectSignature)
354
425
  return;
355
426
  this.lastEffectSignature = signature;
356
- this.effectBatchFill();
357
- this.effectEndReached();
358
- this.effectStartReached();
359
- this.effectViewability();
360
- this.effectInitialScroll();
361
- this.effectMaintainVisibleContentPosition();
427
+ const inputs = this.buildInputs();
428
+ const result = reduceList(this.listState, { kind: 'commit' }, inputs);
429
+ this.runEffects(result.effects, inputs);
362
430
  }
363
431
  ngOnDestroy() {
364
432
  if (this.viewableTimer !== null)
@@ -366,38 +434,8 @@ export class VirtualizedList {
366
434
  if (this.batchTimer !== null)
367
435
  clearTimeout(this.batchTimer);
368
436
  }
369
- recomputeMetrics() {
370
- const count = this.getItemCount(this.data);
371
- const gil = this.getItemLayout;
372
- const data = this.data;
373
- const fixedLayout = gil !== undefined
374
- ? (index) => {
375
- const layout = gil(data, index);
376
- return { length: layout.length, offset: layout.offset };
377
- }
378
- : undefined;
379
- const averageLength = fixedLayout !== undefined
380
- ? count > FIRST_INDEX
381
- ? fixedLayout(FIRST_INDEX).length
382
- : EMPTY_OFFSET
383
- : averageMeasuredLength(this.measured);
384
- const { offsets, lengths, total } = buildOffsets(count, this.measured, fixedLayout, averageLength);
385
- const target = computeWindow(count, offsets, lengths, this.scrollOffset, this.viewportLength, this.windowSizeValue, this.initialNumToRenderValue);
386
- const throttled = throttleWindow(target, this.committedWindow, this.maxToRenderPerBatchValue);
387
- this.committedWindow = throttled;
388
- this.metricsCore = {
389
- count,
390
- offsets,
391
- lengths,
392
- total,
393
- first: throttled.first,
394
- last: throttled.last,
395
- target,
396
- averageLength,
397
- };
398
- }
399
437
  recomputeView() {
400
- const m = this.metricsCore;
438
+ const m = this.listState.metrics;
401
439
  this.itemCount = m.count;
402
440
  const hasHeader = this.headerDir !== undefined;
403
441
  const hasSeparators = this.separatorDir !== undefined;
@@ -428,7 +466,7 @@ export class VirtualizedList {
428
466
  this.leadingSpacerStyle = null;
429
467
  this.trailingSpacerStyle = null;
430
468
  this.renderedStickyIndices = undefined;
431
- dlog(`Angular VirtualizedList empty (viewport=${this.viewportLength})`);
469
+ dlog(`Angular VirtualizedList empty (viewport=${this.listState.viewportLength})`);
432
470
  return;
433
471
  }
434
472
  const plan = buildListPlan({
@@ -473,7 +511,7 @@ export class VirtualizedList {
473
511
  }
474
512
  this.windowCells = cells;
475
513
  dlog(`Angular VirtualizedList window [${m.first}, ${m.last}] of ${m.count} ` +
476
- `(offset=${this.scrollOffset}, viewport=${this.viewportLength}, rendered=${cells.length})`);
514
+ `(offset=${this.listState.scrollOffset}, viewport=${this.listState.viewportLength}, rendered=${cells.length})`);
477
515
  }
478
516
  buildSeparatorContext(index, item) {
479
517
  const overrides = this.separatorOverrides.get(index);
@@ -503,17 +541,13 @@ export class VirtualizedList {
503
541
  if (existing !== undefined)
504
542
  return existing;
505
543
  const measure = (event) => {
506
- if (this.getItemLayout !== undefined)
507
- return;
508
544
  const length = readLayoutLength(event, this.isHorizontal);
509
545
  if (length === undefined)
510
546
  return;
511
- if (this.measured.get(index) === length)
512
- return;
513
- this.measured.set(index, length);
514
547
  dlog(`Angular VirtualizedList cell ${index} measured length=${length}`);
515
- this.measureVersion += 1;
516
- this.cdr.markForCheck();
548
+ // The reducer guards a fixed getItemLayout and a repeated length; a no-op leaves state and the
549
+ // view untouched (dispatch marks for check only when something changed).
550
+ this.dispatch({ kind: 'measure', index, length });
517
551
  };
518
552
  this.cellMeasures.set(index, measure);
519
553
  return measure;
@@ -528,8 +562,8 @@ export class VirtualizedList {
528
562
  return typeof value === 'object' && value !== null && 'nativeEvent' in value;
529
563
  }
530
564
  mergeSeparator(gapIndex, patch) {
531
- const count = this.metricsCore.count;
532
- if (gapIndex < FIRST_INDEX || gapIndex > count - 2)
565
+ const count = this.listState.metrics.count;
566
+ if (!isSeparatorGapInRange(gapIndex, count))
533
567
  return;
534
568
  this.separatorOverrides.set(gapIndex, { ...this.separatorOverrides.get(gapIndex), ...patch });
535
569
  this.cdr.markForCheck();
@@ -552,37 +586,34 @@ export class VirtualizedList {
552
586
  };
553
587
  }
554
588
  // ---- imperative handle (the shared IVirtualizedListHandle surface) ----
589
+ // Each scroll resolves to an offset (or a scroll-to-index failure) inside the reducer, then rides
590
+ // the scroll-to effect through scrollToPixel.
555
591
  scrollToOffset(params) {
556
- this.scrollToPixel(params.offset, params.animated ?? true);
592
+ this.dispatch({
593
+ kind: 'scroll-to-offset',
594
+ offset: params.offset,
595
+ animated: params.animated ?? true,
596
+ });
557
597
  }
558
598
  scrollToIndex(params) {
559
- const m = this.metricsCore;
560
- // No getItemLayout AND the target is past the last measured cell: report the failure instead of
561
- // scrolling to a fabricated estimate (RN VirtualizedList.js).
562
- if (this.getItemLayout === undefined && params.index > highestMeasuredIndex(this.measured)) {
563
- dlog(`Angular VirtualizedList onScrollToIndexFailed index=${params.index} ` +
564
- `highestMeasured=${highestMeasuredIndex(this.measured)} (no getItemLayout)`);
565
- this.scrollToIndexFailed.emit({
566
- index: params.index,
567
- highestMeasuredFrameIndex: highestMeasuredIndex(this.measured),
568
- averageItemLength: m.averageLength,
569
- });
570
- return;
571
- }
572
- this.scrollToPixel(this.offsetForIndexLocal(params.index, params.viewPosition ?? FIRST_INDEX, params.viewOffset ?? EMPTY_OFFSET), params.animated ?? true);
599
+ this.dispatch({
600
+ kind: 'scroll-to-index',
601
+ index: params.index,
602
+ animated: params.animated ?? true,
603
+ viewPosition: params.viewPosition ?? FIRST_INDEX,
604
+ viewOffset: params.viewOffset ?? EMPTY_OFFSET,
605
+ });
573
606
  }
574
607
  scrollToItem(params) {
575
- const count = this.metricsCore.count;
576
- for (let index = FIRST_INDEX; index < count; index += 1) {
577
- if (this.getItem(this.data, index) === params.item) {
578
- this.scrollToPixel(this.offsetForIndexLocal(index, params.viewPosition ?? FIRST_INDEX, EMPTY_OFFSET), params.animated ?? true);
579
- return;
580
- }
581
- }
582
- dlog('Angular VirtualizedList scrollToItem: item not found');
608
+ this.dispatch({
609
+ kind: 'scroll-to-item',
610
+ item: params.item,
611
+ animated: params.animated ?? true,
612
+ viewPosition: params.viewPosition ?? FIRST_INDEX,
613
+ });
583
614
  }
584
615
  scrollToEnd(params) {
585
- this.scrollToPixel(Math.max(EMPTY_OFFSET, this.metricsCore.total - this.viewportLength), params?.animated ?? true);
616
+ this.dispatch({ kind: 'scroll-to-end', animated: params?.animated ?? true });
586
617
  }
587
618
  flashScrollIndicators() {
588
619
  this.scrollView?.flashScrollIndicators();
@@ -600,7 +631,7 @@ export class VirtualizedList {
600
631
  return this.scrollView?.getScrollNode() ?? null;
601
632
  }
602
633
  recordInteraction() {
603
- this.hasInteracted = true;
634
+ this.dispatch({ kind: 'record-interaction' });
604
635
  }
605
636
  scrollToPixel(offset, animated) {
606
637
  const clamped = Math.max(EMPTY_OFFSET, offset);
@@ -616,167 +647,6 @@ export class VirtualizedList {
616
647
  this.commandedOffset = target;
617
648
  this.cdr.markForCheck();
618
649
  }
619
- offsetForIndexLocal(index, viewPosition, viewOffset) {
620
- const m = this.metricsCore;
621
- return offsetForIndex(index, viewPosition, viewOffset, m.count, m.offsets, m.lengths, this.viewportLength);
622
- }
623
- // ---- after-commit effects (run in ngAfterViewChecked, the post-render seam) ----
624
- // Batch fill: when the throttled window has not reached the target, schedule a re-render so the
625
- // window keeps filling toward target over successive ticks (RN's incremental fill).
626
- effectBatchFill() {
627
- const m = this.metricsCore;
628
- if (this.batchTimer !== null) {
629
- clearTimeout(this.batchTimer);
630
- this.batchTimer = null;
631
- }
632
- if (m.first <= m.target.first && m.last >= m.target.last)
633
- return;
634
- this.batchTimer = setTimeout(() => {
635
- this.batchTimer = null;
636
- this.measureVersion += 1;
637
- this.cdr.markForCheck();
638
- }, this.updateCellsBatchingPeriodValue);
639
- }
640
- // onEndReached: fire only when the actual last cell is rendered AND within threshold; dedup by
641
- // content length; re-arm on scroll away from the end (RN _maybeCallOnEdgeReached).
642
- effectEndReached() {
643
- if (!this.endReached.observed || this.viewportLength <= EMPTY_OFFSET)
644
- return;
645
- const m = this.metricsCore;
646
- const { distanceFromEnd, withinThreshold } = computeEndReached(m.total, this.scrollOffset, this.viewportLength, this.onEndReachedThresholdValue);
647
- const lastCellRendered = m.last === m.count - 1;
648
- if (withinThreshold && lastCellRendered && this.sentEndForContentLength !== m.total) {
649
- this.sentEndForContentLength = m.total;
650
- dlog(`Angular VirtualizedList endReached distanceFromEnd=${distanceFromEnd} ` +
651
- `(last=${m.last} of ${m.count}, contentLength=${m.total})`);
652
- this.endReached.emit({ distanceFromEnd });
653
- }
654
- if (!withinThreshold)
655
- this.sentEndForContentLength = NO_CONTENT_LENGTH_SENT;
656
- }
657
- // startReached: the top-edge twin of endReached.
658
- effectStartReached() {
659
- if (!this.startReached.observed || this.viewportLength <= EMPTY_OFFSET)
660
- return;
661
- const m = this.metricsCore;
662
- const { distanceFromStart, withinThreshold } = computeStartReached(this.scrollOffset, this.viewportLength, this.onStartReachedThresholdValue);
663
- const firstCellRendered = m.first === FIRST_INDEX;
664
- if (withinThreshold && firstCellRendered && this.sentStartForContentLength !== m.total) {
665
- this.sentStartForContentLength = m.total;
666
- dlog(`Angular VirtualizedList startReached distanceFromStart=${distanceFromStart} ` +
667
- `(first=${m.first}, contentLength=${m.total})`);
668
- this.startReached.emit({ distanceFromStart });
669
- }
670
- if (!withinThreshold)
671
- this.sentStartForContentLength = NO_CONTENT_LENGTH_SENT;
672
- }
673
- // Viewability: recompute which rendered cells clear the threshold and, if the viewable set
674
- // changed, fire viewableItemsChanged + every config/callback pair, honoring minimumViewTime.
675
- effectViewability() {
676
- const m = this.metricsCore;
677
- const pairs = buildViewabilityPairs(this.viewableItemsChanged.observed
678
- ? (info) => this.viewableItemsChanged.emit(info)
679
- : undefined, this.viewabilityConfig, this.viewabilityConfigCallbackPairs);
680
- if (pairs.length === EMPTY_OFFSET || this.viewportLength <= EMPTY_OFFSET)
681
- return;
682
- if (m.count === FIRST_INDEX)
683
- return;
684
- const { tokens, map } = computeViewableSet({
685
- first: m.first,
686
- last: m.last,
687
- count: m.count,
688
- offsets: m.offsets,
689
- lengths: m.lengths,
690
- scrollOffset: this.scrollOffset,
691
- viewportLength: this.viewportLength,
692
- data: this.data,
693
- getItem: this.getItem,
694
- keyExtractor: this.keyExtractor,
695
- pairs,
696
- hasInteracted: this.hasInteracted,
697
- });
698
- const diff = diffViewable(this.lastViewable, map, tokens);
699
- if (!diff.hasChanged)
700
- return;
701
- const commitAndFire = () => {
702
- this.lastViewable = map;
703
- dlog(`Angular VirtualizedList viewable=${tokens.length} changed=${diff.changed.length} ` +
704
- `(window [${m.first}, ${m.last}])`);
705
- const info = {
706
- viewableItems: tokens,
707
- changed: diff.changed,
708
- };
709
- for (const pair of pairs)
710
- pair.onViewableItemsChanged(info);
711
- };
712
- const minimumViewTime = maxMinimumViewTime(pairs);
713
- if (this.viewableTimer !== null) {
714
- clearTimeout(this.viewableTimer);
715
- this.viewableTimer = null;
716
- }
717
- if (minimumViewTime > EMPTY_OFFSET) {
718
- dlog(`Angular VirtualizedList viewability debounce ${minimumViewTime}ms (window [${m.first}, ${m.last}])`);
719
- this.viewableTimer = setTimeout(() => {
720
- this.viewableTimer = null;
721
- commitAndFire();
722
- }, minimumViewTime);
723
- return;
724
- }
725
- commitAndFire();
726
- }
727
- // initialScrollIndex: once the first viewport is known, jump to that index a single time.
728
- effectInitialScroll() {
729
- if (this.initialScrollIndex === undefined || this.appliedInitialScroll)
730
- return;
731
- if (this.viewportLength <= EMPTY_OFFSET || this.metricsCore.count === FIRST_INDEX)
732
- return;
733
- this.appliedInitialScroll = true;
734
- // The initial jump is instant (RN does not animate initialScrollIndex).
735
- this.scrollToPixel(this.offsetForIndexLocal(this.initialScrollIndex, FIRST_INDEX, EMPTY_OFFSET), false);
736
- }
737
- // maintainVisibleContentPosition JS anchor adjustment: track the key of the item at
738
- // minIndexForVisible; when a prepend moves it down, add the inserted extent in the leading SPACER
739
- // (the off-window items native MVCP cannot see) to scrollOffset so the anchored item does not jump
740
- // (RN getDerivedStateFromProps).
741
- effectMaintainVisibleContentPosition() {
742
- const m = this.metricsCore;
743
- if (this.maintainVisibleContentPosition === undefined || m.count === FIRST_INDEX) {
744
- this.firstVisibleKey = null;
745
- return;
746
- }
747
- const minIndexForVisible = this.maintainVisibleContentPosition.minIndexForVisible;
748
- const newFirstVisibleKey = m.count > minIndexForVisible ? this.keyFor(minIndexForVisible) : null;
749
- const prevKey = this.firstVisibleKey;
750
- if (prevKey !== null && newFirstVisibleKey !== null && prevKey !== newFirstVisibleKey) {
751
- let anchorIndex = -1;
752
- for (let index = minIndexForVisible; index < m.count; index += 1) {
753
- if (this.keyFor(index) === prevKey) {
754
- anchorIndex = index;
755
- break;
756
- }
757
- }
758
- if (anchorIndex > minIndexForVisible) {
759
- const spacerEnd = Math.min(anchorIndex, this.committedWindow.first);
760
- const insertedExtent = spacerEnd > minIndexForVisible
761
- ? m.offsets[spacerEnd] - m.offsets[minIndexForVisible]
762
- : EMPTY_OFFSET;
763
- if (insertedExtent > EMPTY_OFFSET) {
764
- const autoThreshold = this.maintainVisibleContentPosition.autoscrollToTopThreshold;
765
- const anchoredNearTop = autoThreshold !== undefined && this.scrollOffset <= autoThreshold;
766
- if (anchoredNearTop) {
767
- dlog(`Angular VirtualizedList MVCP autoscroll-to-top (offset=${this.scrollOffset} <= ${autoThreshold})`);
768
- this.scrollToPixel(EMPTY_OFFSET, true);
769
- }
770
- else {
771
- dlog(`Angular VirtualizedList MVCP adjust +${insertedExtent}px ` +
772
- `(anchor "${prevKey}" moved ${minIndexForVisible}->${anchorIndex})`);
773
- this.scrollToPixel(this.scrollOffset + insertedExtent, false);
774
- }
775
- }
776
- }
777
- }
778
- this.firstVisibleKey = newFirstVisibleKey;
779
- }
780
650
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: VirtualizedList, deps: [], target: i0.ɵɵFactoryTarget.Component });
781
651
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: VirtualizedList, isStandalone: true, selector: "VirtualizedList", inputs: { data: "data", getItem: "getItem", getItemCount: "getItemCount", keyExtractor: "keyExtractor", getItemLayout: "getItemLayout", horizontal: "horizontal", inverted: "inverted", extraData: "extraData", onEndReachedThreshold: "onEndReachedThreshold", onStartReachedThreshold: "onStartReachedThreshold", refreshing: "refreshing", progressViewOffset: "progressViewOffset", refreshRequested: "refreshRequested", viewabilityConfig: "viewabilityConfig", viewabilityConfigCallbackPairs: "viewabilityConfigCallbackPairs", initialNumToRender: "initialNumToRender", initialScrollIndex: "initialScrollIndex", maxToRenderPerBatch: "maxToRenderPerBatch", updateCellsBatchingPeriod: "updateCellsBatchingPeriod", windowSize: "windowSize", stickyHeaderIndices: "stickyHeaderIndices", maintainVisibleContentPosition: "maintainVisibleContentPosition", onScroll: "onScroll", onScrollBeginDrag: "onScrollBeginDrag", onScrollEndDrag: "onScrollEndDrag", onMomentumScrollBegin: "onMomentumScrollBegin", onMomentumScrollEnd: "onMomentumScrollEnd", scrollEventThrottle: "scrollEventThrottle", keyboardShouldPersistTaps: "keyboardShouldPersistTaps", keyboardDismissMode: "keyboardDismissMode", style: "style", contentContainerStyle: "contentContainerStyle", testID: "testID", nativeID: "nativeID", accessible: "accessible", accessibilityLabel: "accessibilityLabel", accessibilityHint: "accessibilityHint", accessibilityRole: "accessibilityRole", accessibilityState: "accessibilityState", accessibilityValue: "accessibilityValue", accessibilityActions: "accessibilityActions", accessibilityLabelledBy: "accessibilityLabelledBy", importantForAccessibility: "importantForAccessibility", accessibilityLiveRegion: "accessibilityLiveRegion", screenReaderFocusable: "screenReaderFocusable", accessibilityViewIsModal: "accessibilityViewIsModal", accessibilityElementsHidden: "accessibilityElementsHidden", accessibilityIgnoresInvertColors: "accessibilityIgnoresInvertColors", accessibilityLanguage: "accessibilityLanguage", accessibilityRespondsToUserInteraction: "accessibilityRespondsToUserInteraction", accessibilityShowsLargeContentViewer: "accessibilityShowsLargeContentViewer", accessibilityLargeContentTitle: "accessibilityLargeContentTitle", role: "role", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", ariaLive: "ariaLive", ariaHidden: "ariaHidden", ariaBusy: "ariaBusy", ariaChecked: "ariaChecked", ariaDisabled: "ariaDisabled", ariaExpanded: "ariaExpanded", ariaSelected: "ariaSelected", ariaModal: "ariaModal", ariaValueMax: "ariaValueMax", ariaValueMin: "ariaValueMin", ariaValueNow: "ariaValueNow", ariaValueText: "ariaValueText" }, outputs: { endReached: "endReached", startReached: "startReached", refresh: "refresh", viewableItemsChanged: "viewableItemsChanged", scrollToIndexFailed: "scrollToIndexFailed", accessibilityAction: "accessibilityAction", accessibilityTap: "accessibilityTap", magicTap: "magicTap", accessibilityEscape: "accessibilityEscape" }, queries: [{ propertyName: "itemDir", first: true, predicate: VListItemDirective, descendants: true }, { propertyName: "headerDir", first: true, predicate: VListHeaderDirective, descendants: true }, { propertyName: "footerDir", first: true, predicate: VListFooterDirective, descendants: true }, { propertyName: "emptyDir", first: true, predicate: VListEmptyDirective, descendants: true }, { propertyName: "separatorDir", first: true, predicate: VListSeparatorDirective, descendants: true }], viewQueries: [{ propertyName: "scrollView", first: true, predicate: ScrollView, descendants: true }], ngImport: i0, template: `
782
652
  <ScrollView