@symbiote-native/angular 3.1.3 → 3.3.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 (165) hide show
  1. package/babel-register-composed.cjs +1 -0
  2. package/build/angular/accessibility-events.d.ts +12 -0
  3. package/build/angular/accessibility-events.js +28 -0
  4. package/build/angular/accessibility-events.js.map +1 -0
  5. package/build/angular/accessibility-inputs.d.ts +40 -0
  6. package/build/angular/accessibility-inputs.js +130 -0
  7. package/build/angular/accessibility-inputs.js.map +1 -0
  8. package/build/angular/bootstrap.d.ts +3 -1
  9. package/build/angular/bootstrap.js +4 -1
  10. package/build/angular/bootstrap.js.map +1 -1
  11. package/build/angular/components/checkbox-props.d.ts +2 -0
  12. package/build/angular/components/checkbox-props.js +2 -0
  13. package/build/angular/components/checkbox-props.js.map +1 -0
  14. package/build/angular/components/flat-list/flat-list-template.d.ts +1 -0
  15. package/build/angular/components/flat-list/flat-list-template.js +158 -0
  16. package/build/angular/components/flat-list/flat-list-template.js.map +1 -0
  17. package/build/angular/components/flat-list/index.d.ts +6 -61
  18. package/build/angular/components/flat-list/index.js +26 -463
  19. package/build/angular/components/flat-list/index.js.map +1 -1
  20. package/build/angular/components/keyboard-avoiding-view/index.d.ts +4 -40
  21. package/build/angular/components/keyboard-avoiding-view/index.js +7 -131
  22. package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
  23. package/build/angular/components/modal/index.d.ts +5 -41
  24. package/build/angular/components/modal/index.js +8 -133
  25. package/build/angular/components/modal/index.js.map +1 -1
  26. package/build/angular/components/section-list/index.d.ts +4 -51
  27. package/build/angular/components/section-list/index.js +18 -335
  28. package/build/angular/components/section-list/index.js.map +1 -1
  29. package/build/angular/components/virtualized-list/cell-registry.d.ts +35 -0
  30. package/build/angular/components/virtualized-list/cell-registry.js +133 -0
  31. package/build/angular/components/virtualized-list/cell-registry.js.map +1 -0
  32. package/build/angular/components/virtualized-list/index.d.ts +18 -253
  33. package/build/angular/components/virtualized-list/index.js +112 -1178
  34. package/build/angular/components/virtualized-list/index.js.map +1 -1
  35. package/build/angular/components/virtualized-list/list-a11y-forward.d.ts +1 -0
  36. package/build/angular/components/virtualized-list/list-a11y-forward.js +42 -0
  37. package/build/angular/components/virtualized-list/list-a11y-forward.js.map +1 -0
  38. package/build/angular/components/virtualized-list/list-bags.d.ts +32 -0
  39. package/build/angular/components/virtualized-list/list-bags.js +120 -0
  40. package/build/angular/components/virtualized-list/list-bags.js.map +1 -0
  41. package/build/angular/components/virtualized-list/list-effects.d.ts +31 -0
  42. package/build/angular/components/virtualized-list/list-effects.js +83 -0
  43. package/build/angular/components/virtualized-list/list-effects.js.map +1 -0
  44. package/build/angular/components/virtualized-list/list-events.d.ts +17 -0
  45. package/build/angular/components/virtualized-list/list-events.js +34 -0
  46. package/build/angular/components/virtualized-list/list-events.js.map +1 -0
  47. package/build/angular/components/virtualized-list/list-handle.d.ts +35 -0
  48. package/build/angular/components/virtualized-list/list-handle.js +61 -0
  49. package/build/angular/components/virtualized-list/list-handle.js.map +1 -0
  50. package/build/angular/components/virtualized-list/list-inputs.d.ts +78 -0
  51. package/build/angular/components/virtualized-list/list-inputs.js +150 -0
  52. package/build/angular/components/virtualized-list/list-inputs.js.map +1 -0
  53. package/build/angular/components/virtualized-list/list-props.d.ts +58 -0
  54. package/build/angular/components/virtualized-list/list-props.js +3 -0
  55. package/build/angular/components/virtualized-list/list-props.js.map +1 -0
  56. package/build/angular/components/virtualized-list/list-styles.d.ts +23 -0
  57. package/build/angular/components/virtualized-list/list-styles.js +26 -0
  58. package/build/angular/components/virtualized-list/list-styles.js.map +1 -0
  59. package/build/angular/components/virtualized-list/list-template.d.ts +1 -0
  60. package/build/angular/components/virtualized-list/list-template.js +176 -0
  61. package/build/angular/components/virtualized-list/list-template.js.map +1 -0
  62. package/build/angular/components/virtualized-section-list/index.d.ts +13 -70
  63. package/build/angular/components/virtualized-section-list/index.js +22 -455
  64. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  65. package/build/angular/components/virtualized-section-list/section-list-template.d.ts +1 -0
  66. package/build/angular/components/virtualized-section-list/section-list-template.js +107 -0
  67. package/build/angular/components/virtualized-section-list/section-list-template.js.map +1 -0
  68. package/build/angular/components.d.ts +1 -0
  69. package/build/angular/components.js.map +1 -1
  70. package/build/angular/descriptor-to-angular/descriptor-host.d.ts +8 -0
  71. package/build/angular/descriptor-to-angular/descriptor-host.js +38 -0
  72. package/build/angular/descriptor-to-angular/descriptor-host.js.map +1 -0
  73. package/build/angular/descriptor-to-angular/index.d.ts +1 -0
  74. package/build/angular/descriptor-to-angular/index.js +4 -0
  75. package/build/angular/descriptor-to-angular/index.js.map +1 -1
  76. package/build/angular/element-base.d.ts +153 -0
  77. package/build/angular/element-base.js +272 -0
  78. package/build/angular/element-base.js.map +1 -0
  79. package/build/angular/elements-controls.d.ts +165 -0
  80. package/build/angular/elements-controls.js +382 -0
  81. package/build/angular/elements-controls.js.map +1 -0
  82. package/build/angular/elements-layout.d.ts +122 -0
  83. package/build/angular/elements-layout.js +242 -0
  84. package/build/angular/elements-layout.js.map +1 -0
  85. package/build/angular/elements-press.d.ts +96 -0
  86. package/build/angular/elements-press.js +227 -0
  87. package/build/angular/elements-press.js.map +1 -0
  88. package/build/angular/elements.d.ts +6 -516
  89. package/build/angular/elements.js +8 -1091
  90. package/build/angular/elements.js.map +1 -1
  91. package/build/angular/finalization-registry.d.ts +4 -0
  92. package/build/angular/finalization-registry.js +17 -0
  93. package/build/angular/finalization-registry.js.map +1 -0
  94. package/build/angular/host-instance/index.d.ts +2 -0
  95. package/build/angular/host-instance/index.js +4 -4
  96. package/build/angular/host-instance/index.js.map +1 -1
  97. package/build/angular/index.d.ts +9 -4
  98. package/build/angular/index.js +8 -3
  99. package/build/angular/index.js.map +1 -1
  100. package/build/angular/native-view-base.d.ts +27 -0
  101. package/build/angular/native-view-base.js +69 -0
  102. package/build/angular/native-view-base.js.map +1 -0
  103. package/build/angular/render/index.d.ts +2 -1
  104. package/build/angular/render/index.js +46 -73
  105. package/build/angular/render/index.js.map +1 -1
  106. package/build/angular/services/connect-watched-signal.d.ts +2 -0
  107. package/build/angular/services/connect-watched-signal.js +9 -0
  108. package/build/angular/services/connect-watched-signal.js.map +1 -0
  109. package/build/angular/services/create-event-value-hook.d.ts +3 -0
  110. package/build/angular/services/create-event-value-hook.js +17 -0
  111. package/build/angular/services/create-event-value-hook.js.map +1 -0
  112. package/build/angular/services/create-resource-hook.d.ts +7 -0
  113. package/build/angular/services/create-resource-hook.js +20 -0
  114. package/build/angular/services/create-resource-hook.js.map +1 -0
  115. package/build/angular/services/index.d.ts +5 -0
  116. package/build/angular/services/index.js +5 -0
  117. package/build/angular/services/index.js.map +1 -1
  118. package/build/angular/services/inject-event.d.ts +6 -0
  119. package/build/angular/services/inject-event.js +24 -0
  120. package/build/angular/services/inject-event.js.map +1 -0
  121. package/build/angular/services/permissions-service-base.d.ts +14 -0
  122. package/build/angular/services/permissions-service-base.js +38 -0
  123. package/build/angular/services/permissions-service-base.js.map +1 -0
  124. package/package.json +6 -6
  125. package/src/accessibility-events.ts +13 -0
  126. package/src/accessibility-inputs.ts +89 -0
  127. package/src/bootstrap.ts +6 -2
  128. package/src/components/checkbox-props.ts +12 -0
  129. package/src/components/flat-list/flat-list-template.ts +159 -0
  130. package/src/components/flat-list/index.ts +30 -307
  131. package/src/components/keyboard-avoiding-view/index.ts +4 -78
  132. package/src/components/modal/index.ts +7 -80
  133. package/src/components/section-list/index.ts +21 -172
  134. package/src/components/virtualized-list/cell-registry.ts +199 -0
  135. package/src/components/virtualized-list/index.ts +145 -1181
  136. package/src/components/virtualized-list/list-a11y-forward.ts +42 -0
  137. package/src/components/virtualized-list/list-bags.ts +142 -0
  138. package/src/components/virtualized-list/list-effects.ts +116 -0
  139. package/src/components/virtualized-list/list-events.ts +31 -0
  140. package/src/components/virtualized-list/list-handle.ts +92 -0
  141. package/src/components/virtualized-list/list-inputs.ts +149 -0
  142. package/src/components/virtualized-list/list-props.ts +81 -0
  143. package/src/components/virtualized-list/list-styles.ts +62 -0
  144. package/src/components/virtualized-list/list-template.ts +175 -0
  145. package/src/components/virtualized-section-list/index.ts +40 -351
  146. package/src/components/virtualized-section-list/section-list-template.ts +108 -0
  147. package/src/components.ts +1 -0
  148. package/src/descriptor-to-angular/descriptor-host.ts +27 -0
  149. package/src/descriptor-to-angular/index.ts +5 -0
  150. package/src/element-base.ts +272 -0
  151. package/src/elements-controls.ts +282 -0
  152. package/src/elements-layout.ts +141 -0
  153. package/src/elements-press.ts +145 -0
  154. package/src/elements.ts +73 -788
  155. package/src/finalization-registry.ts +18 -0
  156. package/src/host-instance/index.ts +4 -4
  157. package/src/index.ts +18 -2
  158. package/src/native-view-base.ts +86 -0
  159. package/src/render/index.ts +76 -77
  160. package/src/services/connect-watched-signal.ts +15 -0
  161. package/src/services/create-event-value-hook.ts +24 -0
  162. package/src/services/create-resource-hook.ts +32 -0
  163. package/src/services/index.ts +5 -0
  164. package/src/services/inject-event.ts +52 -0
  165. package/src/services/permissions-service-base.ts +46 -0
@@ -1,46 +1,13 @@
1
- // FlatList, the Angular convenience surface over VirtualizedList. It takes a plain `data` array
2
- // and derives getItem/getItemCount; numColumns packs items into rows (each row a flex-row of N
3
- // columns), so the virtualized stream is rows, not items (RN's FlatList). Windowing / viewability /
4
- // batching / imperative scrolling are inherited from VirtualizedList; the data shaping
5
- // (chunkIntoRows / rowKeyExtractor / expandRowViewability / row-separator unwrap) is shared
6
- // verbatim from @symbiote-native/components, same as React/Vue's FlatLists.
7
- //
8
- // TEMPLATE FORWARDING — both column paths RE-STAMP; neither uses a bare `<ng-content>` passthrough.
9
- // Angular's @ContentChild does NOT resolve a directive across a SECOND `<ng-content>` re-projection
10
- // hop (only what's projected directly onto the querying component's own tag) — a bare
11
- // `<VirtualizedList ...><ng-content></ng-content></VirtualizedList>` left VirtualizedList's own
12
- // itemDir/headerDir/etc. undefined, rendering every cell empty (confirmed device bug, see
13
- // flat-list.test.ts). Fixed for both column modes:
14
- // * Single column (numColumns <= 1): FlatList captures the app's `<ng-template vListItem>` (and
15
- // vListHeader/vListFooter/vListEmpty/vListSeparator) with its OWN @ContentChild — a single,
16
- // direct projection hop, which always resolves. The per-cell item and separator templates go
17
- // straight in through VirtualizedList's `[itemTemplate]`/`[itemSeparatorTemplate]`, so a cell
18
- // is ONE outlet deep (a re-stamp doubled every cell's embedded views); the once-per-list
19
- // header/footer/empty slots are still re-stamped.
20
- // * Multi column (numColumns > 1): same re-stamp, but the app's vListItem is typed for ItemT
21
- // while the virtualized stream is rows (IRow<ItemT>), so a plain passthrough couldn't work
22
- // regardless. The row vListItem lays out the N columns side by side (each cell stamps the
23
- // app's item template via VListOutletDirective with context {item, index: row.startIndex +
24
- // column, separators}), the row vListSeparator unwraps the flanking rows to their last/first
25
- // item, and onViewableItemsChanged is wrapped with expandRowViewability so the caller still
26
- // sees per-item visibility — mirrors how Vue's FlatList intercepts renderItem with renderRow.
27
- //
28
- // The imperative handle (scrollToIndex / scrollToOffset / scrollToEnd / scrollToItem /
29
- // recordInteraction / flashScrollIndicators / getScroll* / getNativeScrollRef) is RN's FlatList
30
- // surface, delegated straight to the inner VirtualizedList (@ViewChild). The element-returning
31
- // props (renderItem / ItemSeparatorComponent / List{Header,Footer,Empty}Component) are templates
32
- // in Angular, so they're absent from IFlatListProps per the per-adapter children/render split;
33
- // everything else mirrors IVirtualizedListProps.
1
+ // FlatList, the convenience surface over VirtualizedList: a plain `data` array, and `numColumns`
2
+ // packing items into rows so the virtualized stream is rows, not items. The row shaping is shared
3
+ // with the React and Vue FlatLists, windowing and the scroll handle come from VirtualizedList
34
4
 
35
5
  import {
36
6
  CUSTOM_ELEMENTS_SCHEMA,
37
7
  ChangeDetectionStrategy,
38
8
  Component,
39
- ContentChild,
40
9
  ElementRef,
41
- EventEmitter,
42
10
  Input,
43
- Output,
44
11
  ViewChild,
45
12
  inject,
46
13
  type DoCheck,
@@ -83,11 +50,14 @@ import {
83
50
  type IVListSeparatorContext,
84
51
  } from '../virtualized-list';
85
52
  import { VListOutletDirective } from '../virtualized-list/directives';
53
+ import { ListInputsBase } from '../virtualized-list/list-inputs';
54
+ import { provideGateDemand } from '../../gate-demand';
86
55
  import {
87
56
  stableAnchorStyle,
88
57
  SymbioteStyleInputDirective,
89
58
  ViewHost,
90
59
  } from '../../primitives';
60
+ import { FLAT_LIST_TEMPLATE } from './flat-list-template';
91
61
 
92
62
  function isRecord(value: unknown): value is Record<string, unknown> {
93
63
  return typeof value === 'object' && value !== null;
@@ -106,16 +76,14 @@ function isSeparators(value: unknown): value is ISeparators {
106
76
  typeof value['unhighlight'] === 'function'
107
77
  );
108
78
  }
109
- // Used only as a type-safe fallback if a row's separators handle is ever absent; VirtualizedList
110
- // always supplies a real one, so in practice the live handle flows through.
79
+ // A fallback for a row whose separators handle is absent, `VirtualizedList` always supplies one
111
80
  const NOOP_SEPARATORS: ISeparators = {
112
81
  highlight: (): void => undefined,
113
82
  unhighlight: (): void => undefined,
114
83
  updateProps: (): void => undefined,
115
84
  };
116
85
 
117
- // Re-export the shared list types + the authoring directives so the app can import the cell/slot
118
- // directives alongside FlatList (mirrors how virtualized-list/index re-exports them).
86
+ // Re-exported so the app imports the cell and slot directives alongside FlatList
119
87
  export type {
120
88
  ISeparators,
121
89
  IViewableItemsChangedInfo,
@@ -134,27 +102,20 @@ export type {
134
102
  IVListSeparatorContext,
135
103
  } from '../virtualized-list';
136
104
 
137
- // FlatList's imperative handle is exactly VirtualizedList's.
138
105
  export type IFlatListHandle = IVirtualizedListHandle;
139
106
 
140
- // The Angular FlatList prop surface. Mirrors React/Vue's IFlatListProps: every agnostic
141
- // VirtualizedList prop EXCEPT data/getItem/getItemCount (FlatList derives those from a plain `data`
142
- // array), PLUS numColumns + columnWrapperStyle. The element-returning props are templates in
143
- // Angular, so they are absent here (they were already absent from IVirtualizedListProps).
107
+ // Every agnostic VirtualizedList prop except the data trio, plus `numColumns` and its row style
144
108
  export type IFlatListProps<ItemT> = Omit<
145
109
  IVirtualizedListProps<ItemT>,
146
110
  'data' | 'getItem' | 'getItemCount'
147
111
  > & {
148
112
  data: readonly ItemT[];
149
113
  numColumns?: number;
150
- // Style for the auto-generated row View when numColumns > 1 (RN's columnWrapperStyle). A bare
151
- // string resolves through the shared style registry.
114
+ // A bare string resolves through the shared style registry
152
115
  columnWrapperStyle?: IStyleProp<IViewStyle> | string;
153
116
  };
154
117
 
155
- // What the FlatList component itself takes as plain @Input()s: the full surface minus the events
156
- // it exposes as real @Output() EventEmitters instead (see the class below), mirroring how
157
- // pressable/index.ts derives IAngularPressableInputs from IAngularPressableProps.
118
+ // The plain inputs: the full surface minus the events exposed as real outputs
158
119
  export type IFlatListInputs<ItemT> = Omit<
159
120
  IFlatListProps<ItemT>,
160
121
  | 'onEndReached'
@@ -162,11 +123,16 @@ export type IFlatListInputs<ItemT> = Omit<
162
123
  | 'onRefresh'
163
124
  | 'onViewableItemsChanged'
164
125
  | 'onScrollToIndexFailed'
126
+ | 'onAccessibilityAction'
127
+ | 'onAccessibilityTap'
128
+ | 'onMagicTap'
129
+ | 'onAccessibilityEscape'
165
130
  >;
166
131
 
167
132
  @Component({
168
133
  selector: 'FlatList',
169
134
  standalone: true,
135
+ viewProviders: [provideGateDemand(() => FlatList)],
170
136
  hostDirectives: [
171
137
  { directive: SymbioteStyleInputDirective, inputs: ['style'] },
172
138
  ],
@@ -182,230 +148,17 @@ export type IFlatListInputs<ItemT> = Omit<
182
148
  ViewHost,
183
149
  ],
184
150
  changeDetection: ChangeDetectionStrategy.OnPush,
185
- template: `
186
- @if (isMultiColumn) {
187
- <VirtualizedList
188
- [data]="rows"
189
- [getItem]="getRow"
190
- [getItemCount]="getRowCount"
191
- [keyExtractor]="rowKey"
192
- [getItemLayout]="getItemLayout"
193
- [horizontal]="horizontal"
194
- [inverted]="inverted"
195
- [extraData]="extraData"
196
- (endReached)="endReached.emit($event)"
197
- [onEndReachedThreshold]="onEndReachedThreshold"
198
- (startReached)="startReached.emit($event)"
199
- [onStartReachedThreshold]="onStartReachedThreshold"
200
- (refresh)="refresh.emit()"
201
- [refreshRequested]="refresh.observed"
202
- [refreshing]="refreshing"
203
- [progressViewOffset]="progressViewOffset"
204
- (viewableItemsChanged)="rowViewableItemsChanged($event)"
205
- [viewabilityConfig]="viewabilityConfig"
206
- [viewabilityConfigCallbackPairs]="rowViewabilityPairs"
207
- (scrollToIndexFailed)="scrollToIndexFailed.emit($event)"
208
- [initialNumToRender]="initialNumToRender"
209
- [initialScrollIndex]="initialScrollIndex"
210
- [maxToRenderPerBatch]="maxToRenderPerBatch"
211
- [updateCellsBatchingPeriod]="updateCellsBatchingPeriod"
212
- [windowSize]="windowSize"
213
- [stickyHeaderIndices]="stickyHeaderIndices"
214
- [maintainVisibleContentPosition]="maintainVisibleContentPosition"
215
- [onScroll]="onScroll"
216
- [onScrollBeginDrag]="onScrollBeginDrag"
217
- [onScrollEndDrag]="onScrollEndDrag"
218
- [onMomentumScrollBegin]="onMomentumScrollBegin"
219
- [onMomentumScrollEnd]="onMomentumScrollEnd"
220
- [scrollEventThrottle]="scrollEventThrottle"
221
- [keyboardShouldPersistTaps]="keyboardShouldPersistTaps"
222
- [keyboardDismissMode]="keyboardDismissMode"
223
- [removeClippedSubviews]="resolvedRemoveClippedSubviews"
224
- [nestedScrollEnabled]="nestedScrollEnabled"
225
- [testID]="testID"
226
- [style]="resolvedStyle"
227
- [contentContainerStyle]="contentContainerStyle"
228
- >
229
- <ng-template vListItem let-row let-separators="separators">
230
- <view [style]="rowStyle">
231
- @for (cell of rowCells(row, separators); track cell.key) {
232
- <view [style]="columnCellStyle">
233
- <ng-container
234
- [vListOutlet]="itemDir?.templateRef"
235
- [vListOutletContext]="cell.context"
236
- ></ng-container>
237
- </view>
238
- }
239
- </view>
240
- </ng-template>
241
- @if (headerDir !== undefined) {
242
- <ng-template vListHeader>
243
- <ng-container [vListOutlet]="headerDir.templateRef"></ng-container>
244
- </ng-template>
245
- }
246
- @if (footerDir !== undefined) {
247
- <ng-template vListFooter>
248
- <ng-container [vListOutlet]="footerDir.templateRef"></ng-container>
249
- </ng-template>
250
- }
251
- @if (emptyDir !== undefined) {
252
- <ng-template vListEmpty>
253
- <ng-container [vListOutlet]="emptyDir.templateRef"></ng-container>
254
- </ng-template>
255
- }
256
- @if (separatorDir !== undefined) {
257
- <ng-template
258
- vListSeparator
259
- let-highlighted="highlighted"
260
- let-leadingItem="leadingItem"
261
- let-trailingItem="trailingItem"
262
- >
263
- <ng-container
264
- [vListOutlet]="separatorDir.templateRef"
265
- [vListOutletContext]="
266
- rowSeparatorContext(highlighted, leadingItem, trailingItem)
267
- "
268
- ></ng-container>
269
- </ng-template>
270
- }
271
- </VirtualizedList>
272
- } @else {
273
- <VirtualizedList
274
- [data]="data"
275
- [getItem]="getFlatItem"
276
- [getItemCount]="getFlatCount"
277
- [keyExtractor]="keyExtractor"
278
- [getItemLayout]="getItemLayout"
279
- [horizontal]="horizontal"
280
- [inverted]="inverted"
281
- [extraData]="extraData"
282
- (endReached)="endReached.emit($event)"
283
- [onEndReachedThreshold]="onEndReachedThreshold"
284
- (startReached)="startReached.emit($event)"
285
- [onStartReachedThreshold]="onStartReachedThreshold"
286
- (refresh)="refresh.emit()"
287
- [refreshRequested]="refresh.observed"
288
- [refreshing]="refreshing"
289
- [progressViewOffset]="progressViewOffset"
290
- (viewableItemsChanged)="viewableItemsChanged.emit($event)"
291
- [viewabilityConfig]="viewabilityConfig"
292
- [viewabilityConfigCallbackPairs]="viewabilityConfigCallbackPairs"
293
- (scrollToIndexFailed)="scrollToIndexFailed.emit($event)"
294
- [initialNumToRender]="initialNumToRender"
295
- [initialScrollIndex]="initialScrollIndex"
296
- [maxToRenderPerBatch]="maxToRenderPerBatch"
297
- [updateCellsBatchingPeriod]="updateCellsBatchingPeriod"
298
- [windowSize]="windowSize"
299
- [stickyHeaderIndices]="stickyHeaderIndices"
300
- [maintainVisibleContentPosition]="maintainVisibleContentPosition"
301
- [onScroll]="onScroll"
302
- [onScrollBeginDrag]="onScrollBeginDrag"
303
- [onScrollEndDrag]="onScrollEndDrag"
304
- [onMomentumScrollBegin]="onMomentumScrollBegin"
305
- [onMomentumScrollEnd]="onMomentumScrollEnd"
306
- [scrollEventThrottle]="scrollEventThrottle"
307
- [keyboardShouldPersistTaps]="keyboardShouldPersistTaps"
308
- [keyboardDismissMode]="keyboardDismissMode"
309
- [removeClippedSubviews]="resolvedRemoveClippedSubviews"
310
- [nestedScrollEnabled]="nestedScrollEnabled"
311
- [testID]="testID"
312
- [style]="resolvedStyle"
313
- [contentContainerStyle]="contentContainerStyle"
314
- [itemTemplate]="itemDir?.templateRef"
315
- [itemSeparatorTemplate]="separatorDir?.templateRef"
316
- >
317
- @if (headerDir !== undefined) {
318
- <ng-template vListHeader>
319
- <ng-container [vListOutlet]="headerDir.templateRef"></ng-container>
320
- </ng-template>
321
- }
322
- @if (footerDir !== undefined) {
323
- <ng-template vListFooter>
324
- <ng-container [vListOutlet]="footerDir.templateRef"></ng-container>
325
- </ng-template>
326
- }
327
- @if (emptyDir !== undefined) {
328
- <ng-template vListEmpty>
329
- <ng-container [vListOutlet]="emptyDir.templateRef"></ng-container>
330
- </ng-template>
331
- }
332
- </VirtualizedList>
333
- }
334
- `,
151
+ template: FLAT_LIST_TEMPLATE,
335
152
  })
336
153
  export class FlatList<ItemT = unknown>
154
+ extends ListInputsBase<ItemT>
337
155
  implements IFlatListInputs<ItemT>, IVirtualizedListHandle, DoCheck, OnChanges
338
156
  {
339
- // The list's edge/viewability/failure events as real Angular events: `(endReached)="…"`, not
340
- // `[onEndReached]="…"` — re-emitted straight from the inner VirtualizedList's own @Output()s (see
341
- // the template's `(endReached)="endReached.emit($event)"` style forwarding above).
342
- @Output() readonly endReached = new EventEmitter<{
343
- distanceFromEnd: number;
344
- }>();
345
- @Output() readonly startReached = new EventEmitter<{
346
- distanceFromStart: number;
347
- }>();
348
- @Output() readonly refresh = new EventEmitter<void>();
349
- @Output() readonly viewableItemsChanged = new EventEmitter<
350
- IViewableItemsChangedInfo<ItemT>
351
- >();
352
- @Output() readonly scrollToIndexFailed = new EventEmitter<{
353
- index: number;
354
- highestMeasuredFrameIndex: number;
355
- averageItemLength: number;
356
- }>();
357
157
  @Input({ required: true }) data!: readonly ItemT[];
358
- // RN's FlatList spreads its props onto the VirtualizedList it renders, so `testID` lands on the
359
- // scroll view. Angular has no spread, and this one was simply missing: `<FlatList testID="x">`
360
- // compiled (a static attribute on a component tag is never checked), reached the non-painting
361
- // anchor host, and committed nowhere — so the list was untargetable by a test or an e2e selector
362
- // while looking perfectly healthy on screen. VirtualizedList has always declared it.
363
- @Input() testID?: string;
364
158
  @Input() numColumns?: number;
365
159
  @Input() columnWrapperStyle?: IStyleProp<IViewStyle> | string;
366
- @Input() keyExtractor?: (item: ItemT, index: number) => string;
367
- @Input() getItemLayout?: (
368
- data: unknown,
369
- index: number,
370
- ) => { length: number; offset: number; index: number };
371
- @Input() horizontal?: boolean;
372
- @Input() inverted?: boolean;
373
- @Input() extraData?: unknown;
374
- @Input() onEndReachedThreshold?: number;
375
- @Input() onStartReachedThreshold?: number;
376
- @Input() refreshing?: boolean | null;
377
- @Input() progressViewOffset?: number;
378
- @Input()
379
- viewabilityConfig?: IVirtualizedListProps<ItemT>['viewabilityConfig'];
380
- @Input()
381
- viewabilityConfigCallbackPairs?: IViewabilityConfigCallbackPair<ItemT>[];
382
- @Input() initialNumToRender?: number;
383
- @Input() initialScrollIndex?: number;
384
- @Input() maxToRenderPerBatch?: number;
385
- @Input() updateCellsBatchingPeriod?: number;
386
- @Input() windowSize?: number;
387
- @Input() stickyHeaderIndices?: number[];
388
- @Input() maintainVisibleContentPosition?: {
389
- minIndexForVisible: number;
390
- autoscrollToTopThreshold?: number;
391
- };
392
- @Input() onScroll?: IVirtualizedListProps<ItemT>['onScroll'];
393
- @Input()
394
- onScrollBeginDrag?: IVirtualizedListProps<ItemT>['onScrollBeginDrag'];
395
- @Input() onScrollEndDrag?: IVirtualizedListProps<ItemT>['onScrollEndDrag'];
396
- @Input()
397
- onMomentumScrollBegin?: IVirtualizedListProps<ItemT>['onMomentumScrollBegin'];
398
- @Input()
399
- onMomentumScrollEnd?: IVirtualizedListProps<ItemT>['onMomentumScrollEnd'];
400
- @Input() scrollEventThrottle?: number;
401
- @Input() keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
402
- @Input() keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
403
- @Input() removeClippedSubviews?: boolean;
404
- @Input() nestedScrollEnabled?: boolean;
405
- @Input() style?: IStyleProp<IViewStyle>;
406
- @Input() contentContainerStyle?: IStyleProp<IViewStyle>;
407
160
 
408
- // FlatList.js always sends it, defaulted per platform.
161
+ // The list always gets a value here, defaulted per platform
409
162
  get resolvedRemoveClippedSubviews(): boolean {
410
163
  return removeClippedSubviewsOrDefault(
411
164
  this.removeClippedSubviews,
@@ -413,32 +166,14 @@ export class FlatList<ItemT = unknown>
413
166
  );
414
167
  }
415
168
 
416
- // The app's cell + slot templates, captured for the multi-column re-stamp path. In the
417
- // single-column path they are ALSO projected through <ng-content> to the inner list and these
418
- // captures stay unused (the inner list's own @ContentChild resolves them across the projection).
419
- @ContentChild(VListItemDirective) itemDir?: VListItemDirective<ItemT>;
420
- @ContentChild(VListHeaderDirective) headerDir?: VListHeaderDirective;
421
- @ContentChild(VListFooterDirective) footerDir?: VListFooterDirective;
422
- @ContentChild(VListEmptyDirective) emptyDir?: VListEmptyDirective;
423
- @ContentChild(VListSeparatorDirective)
424
- separatorDir?: VListSeparatorDirective<ItemT>;
425
-
426
- // The composed inner list (whichever numColumns branch rendered). Its instance IS the
427
- // IVirtualizedListHandle, so FlatList's handle delegates straight to it.
169
+ // The composed inner list, whichever branch rendered, its instance is the scroll handle
428
170
  @ViewChild(VirtualizedList) private listRef?: VirtualizedList;
429
171
 
430
- // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
431
- // onto (see anchorHostStyle's doc comment) — NOT `listRef` above, which targets the real inner
432
- // `<VirtualizedList>` one level down (itself its own separate anchor host).
172
+ // This component's own host, the anchor `class="..."` resolves onto, not the inner list's
433
173
  private readonly elementRef = inject(ElementRef);
434
174
 
435
- // --- derived view state (recomputed in ngOnChanges, stable identity across CD) ---
436
175
  rows: IRow<ItemT>[] = [];
437
- // Angular's [style]="…" binding compiles to the built-in ɵɵstyleMap instruction (NOT a
438
- // regular @Input() property write), which only understands a flat object — an array (RN's
439
- // own `style={[a, b]}` composition idiom) crashes deep inside Angular's styling engine. So
440
- // every style value this component stamps onto a template `[style]=` binding is flattened
441
- // via the engine's own flattenStyle first, here at the source rather than at each call site.
176
+ // `[style]` compiles to an instruction that takes a flat object only, so styles are flattened
442
177
  rowStyle: IViewStyle = flattenStyle([{ flexDirection: 'row' }]);
443
178
  rowViewabilityPairs?: IViewabilityConfigCallbackPair<IRow<ItemT>>[];
444
179
  readonly columnCellStyle: IViewStyle = { flex: 1 };
@@ -451,11 +186,8 @@ export class FlatList<ItemT = unknown>
451
186
  return this.columns > SINGLE_COLUMN;
452
187
  }
453
188
 
454
- // ngDoCheck, NOT ngOnChanges: a bare `class=` never becomes an @Input, so ngOnChanges does not
455
- // RUN for it and the merge froze at its creation value (a stranded tile on the ReactiveStyle
456
- // canary). stableAnchorStyle, not a bare flattenStyle, keeps `resolvedStyle`'s reference stable
457
- // across ticks that changed nothing - a fresh object every tick defeats VirtualizedList's own
458
- // dedup gate and free-runs CD (see stableAnchorStyle's doc comment).
189
+ // `ngDoCheck`, not `ngOnChanges`: a bare `class=` never becomes an input and would freeze the
190
+ // merge. `stableAnchorStyle` keeps the reference steady so the inner list's dedup gate holds
459
191
  ngDoCheck(): void {
460
192
  this.resolvedStyle = stableAnchorStyle(
461
193
  this.elementRef,
@@ -466,8 +198,7 @@ export class FlatList<ItemT = unknown>
466
198
 
467
199
  ngOnChanges(changes: SimpleChanges): void {
468
200
  if (changes['columnWrapperStyle'] !== undefined) {
469
- // A class-name string resolves through the shared registry before flattenStyle, which
470
- // only understands style objects/arrays.
201
+ // A class-name string resolves through the shared registry before `flattenStyle`
471
202
  const resolvedColumnWrapperStyle =
472
203
  typeof this.columnWrapperStyle === 'string'
473
204
  ? resolveClassName(this.columnWrapperStyle)
@@ -493,18 +224,16 @@ export class FlatList<ItemT = unknown>
493
224
  }
494
225
  }
495
226
 
496
- // ---- single-column data adaptation (plain array -> getItem/getItemCount) ----
497
227
  getFlatItem = (_data: unknown, index: number): ItemT => this.data[index];
498
228
  getFlatCount = (_data: unknown): number => this.data.length;
499
229
 
500
- // ---- multi-column data adaptation (the virtualized stream is rows) ----
230
+ // With several columns the virtualized stream is rows
501
231
  getRow = (_data: unknown, index: number): IRow<ItemT> => this.rows[index];
502
232
  getRowCount = (_data: unknown): number => this.rows.length;
503
233
  rowKey = (row: IRow<ItemT>, _index: number): string =>
504
234
  rowKeyExtractor(row, this.keyExtractor);
505
235
 
506
- // Viewability over rows expands back to per-item tokens, so the caller sees item-level
507
- // visibility, not row-level (shared expandRowViewability), matching Vue.
236
+ // Row viewability expands back to per-item tokens, so the caller sees items, not rows
508
237
  rowViewableItemsChanged = (
509
238
  info: IViewableItemsChangedInfo<IRow<ItemT>>,
510
239
  ): void => {
@@ -527,10 +256,8 @@ export class FlatList<ItemT = unknown>
527
256
  }));
528
257
  }
529
258
 
530
- // Lay out one row's N columns: every item shares the row's separators handle (the divider sits
531
- // between rows, not columns) and carries its absolute index (row.startIndex + column), like RN's
532
- // multi-column FlatList. Args arrive `unknown` from the template's `let` bindings (Angular cannot
533
- // type a generic structural directive's context), narrowed here — no `as`.
259
+ // Every item shares the row's separators handle and carries its absolute index. The arguments
260
+ // arrive `unknown` from the template's `let` bindings and are narrowed here
534
261
  rowCells(
535
262
  row: unknown,
536
263
  separators: unknown,
@@ -546,9 +273,7 @@ export class FlatList<ItemT = unknown>
546
273
  });
547
274
  }
548
275
 
549
- // The divider between rows shows real items (last of the row above, first of the row below), so the
550
- // app's separator template, typed on ItemT, sees items rather than the IRow wrapper. Args arrive
551
- // `unknown` from the template's `let` bindings, narrowed here.
276
+ // The divider between rows shows real items, so the app's separator template sees items
552
277
  rowSeparatorContext(
553
278
  highlighted: unknown,
554
279
  leadingRow: unknown,
@@ -567,8 +292,6 @@ export class FlatList<ItemT = unknown>
567
292
  };
568
293
  }
569
294
 
570
- // ---- imperative handle (RN FlatList surface) — delegates to the inner VirtualizedList ----
571
-
572
295
  scrollToOffset(params: { offset: number; animated?: boolean }): void {
573
296
  this.listRef?.scrollToOffset(params);
574
297
  }
@@ -36,7 +36,6 @@ import {
36
36
  resolveKeyboardAvoidingLayout,
37
37
  DEFAULT_VERTICAL_OFFSET,
38
38
  type IAccessibilityProps,
39
- type IAccessibilityStateValue,
40
39
  type IAriaProps,
41
40
  type IKeyboardAvoidingBehavior,
42
41
  type IKeyboardAvoidingLayout,
@@ -52,6 +51,7 @@ import {
52
51
  type ISymbioteEvent,
53
52
  type IViewStyle,
54
53
  } from '@symbiote-native/engine';
54
+ import { AccessibilityEventsBase } from '../../accessibility-events';
55
55
  import {
56
56
  anchorHostStyle,
57
57
  SymbioteHostPropsDirective,
@@ -117,6 +117,7 @@ export type IAngularKeyboardAvoidingViewInputs = Omit<
117
117
  `,
118
118
  })
119
119
  export class KeyboardAvoidingView
120
+ extends AccessibilityEventsBase
120
121
  implements IAngularKeyboardAvoidingViewInputs, OnInit, OnDestroy
121
122
  {
122
123
  @Input() behavior?: IKeyboardAvoidingBehavior;
@@ -129,47 +130,8 @@ export class KeyboardAvoidingView
129
130
  // (see the class's `handleLayout`) — the engine's bubble() treats ANCHOR_HOST_COMPONENTS as
130
131
  // transparent to listener lookup, so there is no double-fire.
131
132
  @Output() readonly layout = new EventEmitter<ISymbioteEvent>();
132
- @Output() readonly accessibilityAction = new EventEmitter<ISymbioteEvent>();
133
- @Output() readonly accessibilityTap = new EventEmitter<ISymbioteEvent>();
134
- @Output() readonly magicTap = new EventEmitter<ISymbioteEvent>();
135
- @Output() readonly accessibilityEscape = new EventEmitter<ISymbioteEvent>();
136
133
  @Input() testID?: string;
137
134
  @Input() nativeID?: string;
138
- @Input() accessible?: boolean;
139
- @Input() accessibilityLabel?: string;
140
- @Input() accessibilityHint?: string;
141
- @Input() accessibilityRole?: IAccessibilityProps['accessibilityRole'];
142
- @Input() accessibilityState?: IAccessibilityStateValue;
143
- @Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
144
- @Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
145
- @Input() accessibilityLabelledBy?: string | string[];
146
- @Input()
147
- importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
148
- @Input()
149
- accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
150
- @Input() screenReaderFocusable?: boolean;
151
- @Input() accessibilityViewIsModal?: boolean;
152
- @Input() accessibilityElementsHidden?: boolean;
153
- @Input() accessibilityIgnoresInvertColors?: boolean;
154
- @Input() accessibilityLanguage?: string;
155
- @Input() accessibilityRespondsToUserInteraction?: boolean;
156
- @Input() accessibilityShowsLargeContentViewer?: boolean;
157
- @Input() accessibilityLargeContentTitle?: string;
158
- @Input() role?: IAriaProps['role'];
159
- @Input('aria-label') ariaLabel?: string;
160
- @Input('aria-labelledby') ariaLabelledBy?: string;
161
- @Input('aria-live') ariaLive?: IAriaProps['aria-live'];
162
- @Input('aria-hidden') ariaHidden?: boolean;
163
- @Input('aria-busy') ariaBusy?: boolean;
164
- @Input('aria-checked') ariaChecked?: boolean | 'mixed';
165
- @Input('aria-disabled') ariaDisabled?: boolean;
166
- @Input('aria-expanded') ariaExpanded?: boolean;
167
- @Input('aria-selected') ariaSelected?: boolean;
168
- @Input('aria-modal') ariaModal?: boolean;
169
- @Input('aria-valuemax') ariaValueMax?: number;
170
- @Input('aria-valuemin') ariaValueMin?: number;
171
- @Input('aria-valuenow') ariaValueNow?: number;
172
- @Input('aria-valuetext') ariaValueText?: string;
173
135
 
174
136
  // How far the view must move so it no longer overlaps the keyboard. A plain field, not reactive:
175
137
  // OnPush + zoneless means a keyboard event mutates it and pulls the view via markForCheck.
@@ -325,44 +287,8 @@ export class KeyboardAvoidingView
325
287
  return emitter.observed ? event => this.emit(emitter, event) : undefined;
326
288
  }
327
289
 
328
- // Fold the web aria-*/role aliases into the canonical accessibility* props once per render, so the
329
- // host node never sees an aria-* key (native ignores them) — the shared transform every adapter runs.
290
+ // Folds the aria-*/role aliases into the canonical accessibility* props, native ignores aria-*
330
291
  get folded(): Partial<IAngularKeyboardAvoidingViewProps> {
331
- return resolveAccessibilityProps({
332
- accessibilityLabel: this.accessibilityLabel,
333
- accessibilityHint: this.accessibilityHint,
334
- accessibilityRole: this.accessibilityRole,
335
- accessibilityState: this.accessibilityState,
336
- accessibilityValue: this.accessibilityValue,
337
- accessibilityActions: this.accessibilityActions,
338
- accessibilityLabelledBy: this.accessibilityLabelledBy,
339
- importantForAccessibility: this.importantForAccessibility,
340
- accessibilityLiveRegion: this.accessibilityLiveRegion,
341
- screenReaderFocusable: this.screenReaderFocusable,
342
- accessibilityViewIsModal: this.accessibilityViewIsModal,
343
- accessibilityElementsHidden: this.accessibilityElementsHidden,
344
- accessibilityIgnoresInvertColors: this.accessibilityIgnoresInvertColors,
345
- accessibilityLanguage: this.accessibilityLanguage,
346
- accessibilityRespondsToUserInteraction:
347
- this.accessibilityRespondsToUserInteraction,
348
- accessibilityShowsLargeContentViewer:
349
- this.accessibilityShowsLargeContentViewer,
350
- accessibilityLargeContentTitle: this.accessibilityLargeContentTitle,
351
- role: this.role,
352
- 'aria-label': this.ariaLabel,
353
- 'aria-labelledby': this.ariaLabelledBy,
354
- 'aria-live': this.ariaLive,
355
- 'aria-hidden': this.ariaHidden,
356
- 'aria-busy': this.ariaBusy,
357
- 'aria-checked': this.ariaChecked,
358
- 'aria-disabled': this.ariaDisabled,
359
- 'aria-expanded': this.ariaExpanded,
360
- 'aria-selected': this.ariaSelected,
361
- 'aria-modal': this.ariaModal,
362
- 'aria-valuemax': this.ariaValueMax,
363
- 'aria-valuemin': this.ariaValueMin,
364
- 'aria-valuenow': this.ariaValueNow,
365
- 'aria-valuetext': this.ariaValueText,
366
- });
292
+ return resolveAccessibilityProps(this.accessibilityInputProps());
367
293
  }
368
294
  }