@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.
Files changed (121) hide show
  1. package/build/angular/accessibility-events.d.ts +12 -0
  2. package/build/angular/accessibility-events.js +28 -0
  3. package/build/angular/accessibility-events.js.map +1 -0
  4. package/build/angular/accessibility-inputs.d.ts +40 -0
  5. package/build/angular/accessibility-inputs.js +130 -0
  6. package/build/angular/accessibility-inputs.js.map +1 -0
  7. package/build/angular/bootstrap.d.ts +3 -1
  8. package/build/angular/bootstrap.js +4 -1
  9. package/build/angular/bootstrap.js.map +1 -1
  10. package/build/angular/components/flat-list/flat-list-template.d.ts +1 -0
  11. package/build/angular/components/flat-list/flat-list-template.js +158 -0
  12. package/build/angular/components/flat-list/flat-list-template.js.map +1 -0
  13. package/build/angular/components/flat-list/index.d.ts +6 -61
  14. package/build/angular/components/flat-list/index.js +26 -463
  15. package/build/angular/components/flat-list/index.js.map +1 -1
  16. package/build/angular/components/keyboard-avoiding-view/index.d.ts +4 -40
  17. package/build/angular/components/keyboard-avoiding-view/index.js +7 -131
  18. package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
  19. package/build/angular/components/modal/index.d.ts +5 -41
  20. package/build/angular/components/modal/index.js +8 -133
  21. package/build/angular/components/modal/index.js.map +1 -1
  22. package/build/angular/components/section-list/index.d.ts +4 -51
  23. package/build/angular/components/section-list/index.js +18 -335
  24. package/build/angular/components/section-list/index.js.map +1 -1
  25. package/build/angular/components/virtualized-list/cell-registry.d.ts +35 -0
  26. package/build/angular/components/virtualized-list/cell-registry.js +133 -0
  27. package/build/angular/components/virtualized-list/cell-registry.js.map +1 -0
  28. package/build/angular/components/virtualized-list/index.d.ts +18 -253
  29. package/build/angular/components/virtualized-list/index.js +112 -1178
  30. package/build/angular/components/virtualized-list/index.js.map +1 -1
  31. package/build/angular/components/virtualized-list/list-a11y-forward.d.ts +1 -0
  32. package/build/angular/components/virtualized-list/list-a11y-forward.js +42 -0
  33. package/build/angular/components/virtualized-list/list-a11y-forward.js.map +1 -0
  34. package/build/angular/components/virtualized-list/list-bags.d.ts +32 -0
  35. package/build/angular/components/virtualized-list/list-bags.js +120 -0
  36. package/build/angular/components/virtualized-list/list-bags.js.map +1 -0
  37. package/build/angular/components/virtualized-list/list-effects.d.ts +31 -0
  38. package/build/angular/components/virtualized-list/list-effects.js +83 -0
  39. package/build/angular/components/virtualized-list/list-effects.js.map +1 -0
  40. package/build/angular/components/virtualized-list/list-events.d.ts +17 -0
  41. package/build/angular/components/virtualized-list/list-events.js +34 -0
  42. package/build/angular/components/virtualized-list/list-events.js.map +1 -0
  43. package/build/angular/components/virtualized-list/list-handle.d.ts +35 -0
  44. package/build/angular/components/virtualized-list/list-handle.js +61 -0
  45. package/build/angular/components/virtualized-list/list-handle.js.map +1 -0
  46. package/build/angular/components/virtualized-list/list-inputs.d.ts +78 -0
  47. package/build/angular/components/virtualized-list/list-inputs.js +150 -0
  48. package/build/angular/components/virtualized-list/list-inputs.js.map +1 -0
  49. package/build/angular/components/virtualized-list/list-props.d.ts +58 -0
  50. package/build/angular/components/virtualized-list/list-props.js +3 -0
  51. package/build/angular/components/virtualized-list/list-props.js.map +1 -0
  52. package/build/angular/components/virtualized-list/list-styles.d.ts +23 -0
  53. package/build/angular/components/virtualized-list/list-styles.js +26 -0
  54. package/build/angular/components/virtualized-list/list-styles.js.map +1 -0
  55. package/build/angular/components/virtualized-list/list-template.d.ts +1 -0
  56. package/build/angular/components/virtualized-list/list-template.js +176 -0
  57. package/build/angular/components/virtualized-list/list-template.js.map +1 -0
  58. package/build/angular/components/virtualized-section-list/index.d.ts +13 -70
  59. package/build/angular/components/virtualized-section-list/index.js +22 -455
  60. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  61. package/build/angular/components/virtualized-section-list/section-list-template.d.ts +1 -0
  62. package/build/angular/components/virtualized-section-list/section-list-template.js +107 -0
  63. package/build/angular/components/virtualized-section-list/section-list-template.js.map +1 -0
  64. package/build/angular/finalization-registry.d.ts +4 -0
  65. package/build/angular/finalization-registry.js +17 -0
  66. package/build/angular/finalization-registry.js.map +1 -0
  67. package/build/angular/index.d.ts +5 -1
  68. package/build/angular/index.js +5 -1
  69. package/build/angular/index.js.map +1 -1
  70. package/build/angular/native-view-base.d.ts +19 -0
  71. package/build/angular/native-view-base.js +48 -0
  72. package/build/angular/native-view-base.js.map +1 -0
  73. package/build/angular/render/index.d.ts +2 -1
  74. package/build/angular/render/index.js +46 -73
  75. package/build/angular/render/index.js.map +1 -1
  76. package/build/angular/services/connect-watched-signal.d.ts +2 -0
  77. package/build/angular/services/connect-watched-signal.js +9 -0
  78. package/build/angular/services/connect-watched-signal.js.map +1 -0
  79. package/build/angular/services/create-event-value-hook.d.ts +3 -0
  80. package/build/angular/services/create-event-value-hook.js +17 -0
  81. package/build/angular/services/create-event-value-hook.js.map +1 -0
  82. package/build/angular/services/create-resource-hook.d.ts +7 -0
  83. package/build/angular/services/create-resource-hook.js +20 -0
  84. package/build/angular/services/create-resource-hook.js.map +1 -0
  85. package/build/angular/services/index.d.ts +4 -0
  86. package/build/angular/services/index.js +4 -0
  87. package/build/angular/services/index.js.map +1 -1
  88. package/build/angular/services/permissions-service-base.d.ts +14 -0
  89. package/build/angular/services/permissions-service-base.js +38 -0
  90. package/build/angular/services/permissions-service-base.js.map +1 -0
  91. package/package.json +6 -6
  92. package/src/accessibility-events.ts +13 -0
  93. package/src/accessibility-inputs.ts +89 -0
  94. package/src/bootstrap.ts +6 -2
  95. package/src/components/flat-list/flat-list-template.ts +159 -0
  96. package/src/components/flat-list/index.ts +30 -307
  97. package/src/components/keyboard-avoiding-view/index.ts +4 -78
  98. package/src/components/modal/index.ts +7 -80
  99. package/src/components/section-list/index.ts +21 -172
  100. package/src/components/virtualized-list/cell-registry.ts +199 -0
  101. package/src/components/virtualized-list/index.ts +145 -1181
  102. package/src/components/virtualized-list/list-a11y-forward.ts +42 -0
  103. package/src/components/virtualized-list/list-bags.ts +142 -0
  104. package/src/components/virtualized-list/list-effects.ts +116 -0
  105. package/src/components/virtualized-list/list-events.ts +31 -0
  106. package/src/components/virtualized-list/list-handle.ts +92 -0
  107. package/src/components/virtualized-list/list-inputs.ts +149 -0
  108. package/src/components/virtualized-list/list-props.ts +81 -0
  109. package/src/components/virtualized-list/list-styles.ts +62 -0
  110. package/src/components/virtualized-list/list-template.ts +175 -0
  111. package/src/components/virtualized-section-list/index.ts +40 -351
  112. package/src/components/virtualized-section-list/section-list-template.ts +108 -0
  113. package/src/finalization-registry.ts +18 -0
  114. package/src/index.ts +12 -1
  115. package/src/native-view-base.ts +51 -0
  116. package/src/render/index.ts +76 -77
  117. package/src/services/connect-watched-signal.ts +15 -0
  118. package/src/services/create-event-value-hook.ts +24 -0
  119. package/src/services/create-resource-hook.ts +32 -0
  120. package/src/services/index.ts +4 -0
  121. package/src/services/permissions-service-base.ts +46 -0
@@ -1,22 +1,6 @@
1
- // VirtualizedSectionList, the Angular wrapper that flattens sections into one virtualized stream
2
- // over VirtualizedList. Each section contributes a header row, its item rows, then a footer row
3
- // (RN counts 2 per section); the flattened tagged sequence is fed to VirtualizedList as one list,
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
- // The Angular VirtualizedSectionList prop surface. Mirrors React/Vue's IVirtualizedSectionListProps
100
- // MINUS the element-returning props (renderItem, renderSectionHeader/Footer, the *Component slots):
101
- // those are the per-adapter children/render fields and become `<ng-template>` directives in Angular.
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
- // Fixed-layout fast path, FLAT like RN's: the SECTIONS array plus a flat entry index, where every
109
- // section contributes two rows beyond its items (header, footer) and the caller accounts for them.
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
- ) => { length: number; offset: number; index: number };
118
- // Stick each section header to the top as the next section scrolls up. Routed to the inner
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
- // What the VirtualizedSectionList component itself takes as plain @Input()s: the full surface
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
- ) => { length: number; offset: number; index: number };
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
- // See VirtualizedList's own refreshRequested doc comment: `(refresh)="resolvedOnRefresh?.()"`
359
- // above always subscribes to the inner VirtualizedList's refresh output (to re-forward it),
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
- // Bound to the template's `[style]="resolvedStyle"`, which Angular compiles to the built-in
389
- // ɵɵstyleMap instruction — it only understands a flat object, never an array (RN's own
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
- @Input() role?: IAriaProps['role'];
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
- // list-level slots reuse VirtualizedList's own directives; VSL forwards them to the inner list.
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 composed inner VirtualizedList. Its instance IS an IVirtualizedListHandle, so the section
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 OWN host — the non-painting anchor `class="..."` at the use site resolves
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
- // headerIndices are the flat positions of every section header; scrollToLocation maps a
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 so flattenSections does not re-run on every CD (the inner list marks for check on
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; Android does not unless asked.
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
- // The derived flat-stream accessors handed to the inner VirtualizedList. Stable arrow fields so
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
- // Hand the callback `sections`, not the entries: RN's inner VirtualizedList gets
543
- // `data={this.props.sections}` (VirtualizedSectionList.js:216) while ours streams the FLATTENED
544
- // entries, so the same user code would otherwise see a different argument here than on RN.
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
- // Adapts each @Output() into the plain callback VirtualizedList's own @Input() still wants,
582
- // gated on `.observed` so an unlistened event forwards `undefined` — the same "nobody cares"
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
- get resolvedOnAccessibilityAction():
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 list's separator context carries the flattened ENTRY as leading/trailing; unwrap each
662
- // back to its ItemT (shared unwrapEntryItem) so the app's item separator, typed on ItemT, sees
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;