@symbiote-native/angular 0.6.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/bin/symbiote-angular-dev.cjs +20 -19
- package/build/angular/anchor-host-registry.js +2 -2
- package/build/angular/anchor-host-registry.js.map +1 -1
- package/build/angular/bootstrap.js +1 -1
- package/build/angular/bootstrap.js.map +1 -1
- package/build/angular/components/activity-indicator/index.android.d.ts +2 -1
- package/build/angular/components/activity-indicator/index.android.js +12 -4
- package/build/angular/components/activity-indicator/index.android.js.map +1 -1
- package/build/angular/components/activity-indicator/index.ios.d.ts +2 -1
- package/build/angular/components/activity-indicator/index.ios.js +8 -3
- package/build/angular/components/activity-indicator/index.ios.js.map +1 -1
- package/build/angular/components/activity-indicator/shared.d.ts +1 -1
- package/build/angular/components/activity-indicator/shared.js +4 -4
- package/build/angular/components/activity-indicator/shared.js.map +1 -1
- package/build/angular/components/button.d.ts +4 -2
- package/build/angular/components/button.js +41 -22
- package/build/angular/components/button.js.map +1 -1
- package/build/angular/components/flat-list/index.d.ts +6 -4
- package/build/angular/components/flat-list/index.js +80 -50
- package/build/angular/components/flat-list/index.js.map +1 -1
- package/build/angular/components/image/index.android.d.ts +8 -3
- package/build/angular/components/image/index.android.js +42 -10
- package/build/angular/components/image/index.android.js.map +1 -1
- package/build/angular/components/image/index.ios.d.ts +8 -3
- package/build/angular/components/image/index.ios.js +42 -10
- package/build/angular/components/image/index.ios.js.map +1 -1
- package/build/angular/components/image/shared.d.ts +4 -1
- package/build/angular/components/image/shared.js +51 -8
- package/build/angular/components/image/shared.js.map +1 -1
- package/build/angular/components/image-background.d.ts +2 -1
- package/build/angular/components/image-background.js +26 -10
- package/build/angular/components/image-background.js.map +1 -1
- package/build/angular/components/input-accessory-view/index.d.ts +9 -4
- package/build/angular/components/input-accessory-view/index.js +49 -10
- package/build/angular/components/input-accessory-view/index.js.map +1 -1
- package/build/angular/components/keyboard-avoiding-view/index.d.ts +3 -1
- package/build/angular/components/keyboard-avoiding-view/index.js +44 -12
- package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
- package/build/angular/components/modal/index.d.ts +11 -8
- package/build/angular/components/modal/index.js +51 -29
- package/build/angular/components/modal/index.js.map +1 -1
- package/build/angular/components/pressable/index.d.ts +12 -6
- package/build/angular/components/pressable/index.js +66 -13
- package/build/angular/components/pressable/index.js.map +1 -1
- package/build/angular/components/refresh-control/index.d.ts +8 -4
- package/build/angular/components/refresh-control/index.js +54 -16
- package/build/angular/components/refresh-control/index.js.map +1 -1
- package/build/angular/components/safe-area-view/index.d.ts +9 -4
- package/build/angular/components/safe-area-view/index.js +48 -9
- package/build/angular/components/safe-area-view/index.js.map +1 -1
- package/build/angular/components/scroll-view/index.android.d.ts +2 -3
- package/build/angular/components/scroll-view/index.android.js +88 -61
- package/build/angular/components/scroll-view/index.android.js.map +1 -1
- package/build/angular/components/scroll-view/index.ios.d.ts +2 -3
- package/build/angular/components/scroll-view/index.ios.js +24 -18
- package/build/angular/components/scroll-view/index.ios.js.map +1 -1
- package/build/angular/components/scroll-view/projection.d.ts +35 -0
- package/build/angular/components/scroll-view/projection.js +279 -53
- package/build/angular/components/scroll-view/projection.js.map +1 -1
- package/build/angular/components/scroll-view/shared.d.ts +14 -5
- package/build/angular/components/scroll-view/shared.js +225 -75
- package/build/angular/components/scroll-view/shared.js.map +1 -1
- package/build/angular/components/scroll-view/sticky-header.js +21 -22
- package/build/angular/components/scroll-view/sticky-header.js.map +1 -1
- package/build/angular/components/section-list/index.d.ts +7 -1
- package/build/angular/components/section-list/index.js +91 -54
- package/build/angular/components/section-list/index.js.map +1 -1
- package/build/angular/components/switch/index.android.d.ts +7 -3
- package/build/angular/components/switch/index.android.js +52 -10
- package/build/angular/components/switch/index.android.js.map +1 -1
- package/build/angular/components/switch/index.ios.d.ts +7 -3
- package/build/angular/components/switch/index.ios.js +52 -10
- package/build/angular/components/switch/index.ios.js.map +1 -1
- package/build/angular/components/switch/shared.d.ts +13 -4
- package/build/angular/components/switch/shared.js +71 -7
- package/build/angular/components/switch/shared.js.map +1 -1
- package/build/angular/components/text-input.d.ts +11 -3
- package/build/angular/components/text-input.js +68 -8
- package/build/angular/components/text-input.js.map +1 -1
- package/build/angular/components/touchable/index.d.ts +40 -9
- package/build/angular/components/touchable/index.js +303 -67
- package/build/angular/components/touchable/index.js.map +1 -1
- package/build/angular/components/touchable-native-feedback/index.d.ts +6 -3
- package/build/angular/components/touchable-native-feedback/index.js +63 -27
- package/build/angular/components/touchable-native-feedback/index.js.map +1 -1
- package/build/angular/components/virtualized-list/directives.js +22 -18
- package/build/angular/components/virtualized-list/directives.js.map +1 -1
- package/build/angular/components/virtualized-list/index.d.ts +15 -4
- package/build/angular/components/virtualized-list/index.js +326 -94
- package/build/angular/components/virtualized-list/index.js.map +1 -1
- package/build/angular/components/virtualized-section-list/directives.js +12 -12
- package/build/angular/components/virtualized-section-list/directives.js.map +1 -1
- package/build/angular/components/virtualized-section-list/index.d.ts +19 -1
- package/build/angular/components/virtualized-section-list/index.js +93 -22
- package/build/angular/components/virtualized-section-list/index.js.map +1 -1
- package/build/angular/components.d.ts +2 -2
- package/build/angular/components.js +5 -0
- package/build/angular/components.js.map +1 -1
- package/build/angular/create-portal/index.js +34 -36
- package/build/angular/create-portal/index.js.map +1 -1
- package/build/angular/create-tunnel/index.js +19 -22
- package/build/angular/create-tunnel/index.js.map +1 -1
- package/build/angular/descriptor-to-angular/index.js +6 -4
- package/build/angular/descriptor-to-angular/index.js.map +1 -1
- package/build/angular/diagnostics.d.ts +33 -0
- package/build/angular/diagnostics.js +82 -0
- package/build/angular/diagnostics.js.map +1 -0
- package/build/angular/host-instance/index.js +1 -1
- package/build/angular/host-instance/index.js.map +1 -1
- package/build/angular/index.d.ts +9 -4
- package/build/angular/index.js +17 -3
- package/build/angular/index.js.map +1 -1
- package/build/angular/modules/animated/animated-leaf-binder.d.ts +1 -7
- package/build/angular/modules/animated/animated-leaf-binder.js +22 -72
- package/build/angular/modules/animated/animated-leaf-binder.js.map +1 -1
- package/build/angular/modules/animated/create-animated-component.d.ts +11 -6
- package/build/angular/modules/animated/create-animated-component.js +106 -55
- package/build/angular/modules/animated/create-animated-component.js.map +1 -1
- package/build/angular/modules/status-bar/index.js +4 -4
- package/build/angular/modules/status-bar/index.js.map +1 -1
- package/build/angular/primitives/index.d.ts +20 -3
- package/build/angular/primitives/index.js +84 -48
- package/build/angular/primitives/index.js.map +1 -1
- package/build/angular/primitives/shared.d.ts +48 -2
- package/build/angular/primitives/shared.js +158 -11
- package/build/angular/primitives/shared.js.map +1 -1
- package/build/angular/render/index.js +69 -38
- package/build/angular/render/index.js.map +1 -1
- package/build/angular/renderer/index.d.ts +1 -0
- package/build/angular/renderer/index.js +37 -2
- package/build/angular/renderer/index.js.map +1 -1
- package/build/angular/services/color-scheme.service.js +3 -3
- package/build/angular/services/color-scheme.service.js.map +1 -1
- package/build/angular/services/window-dimensions.service.js +4 -4
- package/build/angular/services/window-dimensions.service.js.map +1 -1
- package/package.json +10 -8
- package/src/anchor-host-registry.ts +2 -2
- package/src/bootstrap.ts +4 -1
- package/src/components/activity-indicator/index.android.ts +8 -1
- package/src/components/activity-indicator/index.ios.ts +4 -0
- package/src/components/activity-indicator/shared.ts +32 -13
- package/src/components/button.ts +46 -19
- package/src/components/flat-list/index.ts +122 -62
- package/src/components/image/index.android.ts +58 -7
- package/src/components/image/index.ios.ts +58 -7
- package/src/components/image/shared.ts +92 -21
- package/src/components/image-background.ts +29 -9
- package/src/components/input-accessory-view/index.ts +67 -12
- package/src/components/keyboard-avoiding-view/index.ts +61 -15
- package/src/components/modal/index.ts +72 -33
- package/src/components/pressable/index.ts +117 -28
- package/src/components/refresh-control/index.ts +74 -18
- package/src/components/safe-area-view/index.ts +64 -10
- package/src/components/scroll-view/index.android.ts +62 -47
- package/src/components/scroll-view/index.ios.ts +19 -17
- package/src/components/scroll-view/projection.ts +363 -64
- package/src/components/scroll-view/shared.ts +312 -90
- package/src/components/scroll-view/sticky-header.ts +36 -24
- package/src/components/section-list/index.ts +86 -53
- package/src/components/switch/index.android.ts +60 -8
- package/src/components/switch/index.ios.ts +60 -8
- package/src/components/switch/shared.ts +93 -6
- package/src/components/text-input.ts +95 -13
- package/src/components/touchable/index.ts +348 -64
- package/src/components/touchable-native-feedback/index.ts +94 -31
- package/src/components/virtualized-list/directives.ts +19 -5
- package/src/components/virtualized-list/index.ts +380 -85
- package/src/components/virtualized-section-list/directives.ts +6 -3
- package/src/components/virtualized-section-list/index.ts +146 -33
- package/src/components.ts +9 -1
- package/src/create-portal/index.ts +31 -31
- package/src/create-tunnel/index.ts +16 -17
- package/src/descriptor-to-angular/index.ts +29 -8
- package/src/diagnostics.ts +138 -0
- package/src/host-instance/index.ts +9 -3
- package/src/index.ts +61 -3
- package/src/modules/animated/animated-leaf-binder.ts +28 -77
- package/src/modules/animated/create-animated-component.ts +115 -47
- package/src/modules/app-registry/index.ts +9 -9
- package/src/modules/status-bar/index.ts +13 -4
- package/src/primitives/index.ts +47 -2
- package/src/primitives/shared.ts +170 -10
- package/src/render/index.ts +77 -39
- package/src/renderer/index.ts +76 -14
- package/src/services/color-scheme.service.ts +3 -1
- package/src/services/window-dimensions.service.ts +11 -4
- package/build/angular/modules/animated/animated-leaf-binder/index.d.ts +0 -14
- package/build/angular/modules/animated/animated-leaf-binder/index.js +0 -91
- package/build/angular/modules/animated/animated-leaf-binder/index.js.map +0 -1
- package/src/modules/animated/animated-leaf-binder/index.ts +0 -101
|
@@ -1,37 +1,35 @@
|
|
|
1
1
|
// FlatList, the Angular convenience surface over VirtualizedList. It takes a plain `data` array
|
|
2
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).
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// verbatim from @symbiote-native/components,
|
|
7
|
-
// Angular twin of adapters/vue/src/components/flat-list/index.ts.
|
|
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.
|
|
8
7
|
//
|
|
9
|
-
// TEMPLATE FORWARDING — both paths RE-STAMP; neither uses a bare `<ng-content>` passthrough.
|
|
8
|
+
// TEMPLATE FORWARDING — both column paths RE-STAMP; neither uses a bare `<ng-content>` passthrough.
|
|
10
9
|
// Angular's @ContentChild does NOT resolve a directive across a SECOND `<ng-content>` re-projection
|
|
11
|
-
// hop (
|
|
12
|
-
// `<VirtualizedList ...><ng-content></ng-content></VirtualizedList>`
|
|
13
|
-
// itemDir/headerDir/etc. undefined,
|
|
14
|
-
// flat-list.test.ts). Fixed for both column modes
|
|
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:
|
|
15
14
|
// * Single column (numColumns <= 1): FlatList captures the app's `<ng-template vListItem>` (and
|
|
16
15
|
// vListHeader/vListFooter/vListEmpty/vListSeparator) with its OWN @ContentChild — a single,
|
|
17
16
|
// direct projection hop, which always resolves — then re-authors equivalent `<ng-template>`s on
|
|
18
|
-
// `<VirtualizedList>`,
|
|
17
|
+
// `<VirtualizedList>`, forwarding the captured templateRef + context through
|
|
19
18
|
// VListOutletDirective. Item/index/separators pass through 1:1 (no row wrapping).
|
|
20
|
-
// * Multi column (numColumns > 1):
|
|
21
|
-
// while the virtualized stream is rows (IRow<ItemT>), so a plain passthrough couldn't work
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
// renderItem with renderRow.
|
|
19
|
+
// * Multi column (numColumns > 1): same re-stamp, but the app's vListItem is typed for ItemT
|
|
20
|
+
// while the virtualized stream is rows (IRow<ItemT>), so a plain passthrough couldn't work
|
|
21
|
+
// regardless. The row vListItem lays out the N columns side by side (each cell stamps the
|
|
22
|
+
// app's item template via VListOutletDirective with context {item, index: row.startIndex +
|
|
23
|
+
// column, separators}), the row vListSeparator unwraps the flanking rows to their last/first
|
|
24
|
+
// item, and onViewableItemsChanged is wrapped with expandRowViewability so the caller still
|
|
25
|
+
// sees per-item visibility — mirrors how Vue's FlatList intercepts renderItem with renderRow.
|
|
28
26
|
//
|
|
29
27
|
// The imperative handle (scrollToIndex / scrollToOffset / scrollToEnd / scrollToItem /
|
|
30
28
|
// recordInteraction / flashScrollIndicators / getScroll* / getNativeScrollRef) is RN's FlatList
|
|
31
|
-
// surface
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
29
|
+
// surface, delegated straight to the inner VirtualizedList (@ViewChild). The element-returning
|
|
30
|
+
// props (renderItem / ItemSeparatorComponent / List{Header,Footer,Empty}Component) are templates
|
|
31
|
+
// in Angular, so they're absent from IFlatListProps per the per-adapter children/render split;
|
|
32
|
+
// everything else mirrors IVirtualizedListProps.
|
|
35
33
|
|
|
36
34
|
import {
|
|
37
35
|
CUSTOM_ELEMENTS_SCHEMA,
|
|
@@ -44,6 +42,7 @@ import {
|
|
|
44
42
|
Output,
|
|
45
43
|
ViewChild,
|
|
46
44
|
inject,
|
|
45
|
+
type DoCheck,
|
|
47
46
|
type OnChanges,
|
|
48
47
|
type SimpleChanges,
|
|
49
48
|
} from '@angular/core';
|
|
@@ -81,14 +80,20 @@ import {
|
|
|
81
80
|
type IVListSeparatorContext,
|
|
82
81
|
} from '../virtualized-list';
|
|
83
82
|
import { VListOutletDirective } from '../virtualized-list/directives';
|
|
84
|
-
import {
|
|
83
|
+
import {
|
|
84
|
+
stableAnchorStyle,
|
|
85
|
+
SymbioteStyleInputDirective,
|
|
86
|
+
ViewHost,
|
|
87
|
+
} from '../../primitives';
|
|
85
88
|
|
|
86
89
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
87
90
|
return typeof value === 'object' && value !== null;
|
|
88
91
|
}
|
|
89
92
|
function isRow<ItemT>(value: unknown): value is IRow<ItemT> {
|
|
90
93
|
return (
|
|
91
|
-
isRecord(value) &&
|
|
94
|
+
isRecord(value) &&
|
|
95
|
+
Array.isArray(value['items']) &&
|
|
96
|
+
typeof value['startIndex'] === 'number'
|
|
92
97
|
);
|
|
93
98
|
}
|
|
94
99
|
function isSeparators(value: unknown): value is ISeparators {
|
|
@@ -130,7 +135,10 @@ export {
|
|
|
130
135
|
VListItemDirective,
|
|
131
136
|
VListSeparatorDirective,
|
|
132
137
|
} from '../virtualized-list';
|
|
133
|
-
export type {
|
|
138
|
+
export type {
|
|
139
|
+
IVListItemContext,
|
|
140
|
+
IVListSeparatorContext,
|
|
141
|
+
} from '../virtualized-list';
|
|
134
142
|
|
|
135
143
|
// FlatList's imperative handle is exactly VirtualizedList's.
|
|
136
144
|
export type IFlatListHandle = IVirtualizedListHandle;
|
|
@@ -165,6 +173,9 @@ export type IFlatListInputs<ItemT> = Omit<
|
|
|
165
173
|
@Component({
|
|
166
174
|
selector: 'FlatList',
|
|
167
175
|
standalone: true,
|
|
176
|
+
hostDirectives: [
|
|
177
|
+
{ directive: SymbioteStyleInputDirective, inputs: ['style'] },
|
|
178
|
+
],
|
|
168
179
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
169
180
|
imports: [
|
|
170
181
|
VirtualizedList,
|
|
@@ -254,7 +265,9 @@ export type IFlatListInputs<ItemT> = Omit<
|
|
|
254
265
|
>
|
|
255
266
|
<ng-container
|
|
256
267
|
[vListOutlet]="separatorDir.templateRef"
|
|
257
|
-
[vListOutletContext]="
|
|
268
|
+
[vListOutletContext]="
|
|
269
|
+
rowSeparatorContext(highlighted, leadingItem, trailingItem)
|
|
270
|
+
"
|
|
258
271
|
></ng-container>
|
|
259
272
|
</ng-template>
|
|
260
273
|
}
|
|
@@ -299,7 +312,12 @@ export type IFlatListInputs<ItemT> = Omit<
|
|
|
299
312
|
[style]="resolvedStyle"
|
|
300
313
|
[contentContainerStyle]="contentContainerStyle"
|
|
301
314
|
>
|
|
302
|
-
<ng-template
|
|
315
|
+
<ng-template
|
|
316
|
+
vListItem
|
|
317
|
+
let-item
|
|
318
|
+
let-index="index"
|
|
319
|
+
let-separators="separators"
|
|
320
|
+
>
|
|
303
321
|
<ng-container
|
|
304
322
|
[vListOutlet]="itemDir?.templateRef"
|
|
305
323
|
[vListOutletContext]="{ $implicit: item, index, separators }"
|
|
@@ -329,7 +347,9 @@ export type IFlatListInputs<ItemT> = Omit<
|
|
|
329
347
|
>
|
|
330
348
|
<ng-container
|
|
331
349
|
[vListOutlet]="separatorDir.templateRef"
|
|
332
|
-
[vListOutletContext]="
|
|
350
|
+
[vListOutletContext]="
|
|
351
|
+
itemSeparatorContext(highlighted, leadingItem, trailingItem)
|
|
352
|
+
"
|
|
333
353
|
></ng-container>
|
|
334
354
|
</ng-template>
|
|
335
355
|
}
|
|
@@ -338,15 +358,21 @@ export type IFlatListInputs<ItemT> = Omit<
|
|
|
338
358
|
`,
|
|
339
359
|
})
|
|
340
360
|
export class FlatList<ItemT = unknown>
|
|
341
|
-
implements IFlatListInputs<ItemT>, IVirtualizedListHandle, OnChanges
|
|
361
|
+
implements IFlatListInputs<ItemT>, IVirtualizedListHandle, DoCheck, OnChanges
|
|
342
362
|
{
|
|
343
363
|
// The list's edge/viewability/failure events as real Angular events: `(endReached)="…"`, not
|
|
344
364
|
// `[onEndReached]="…"` — re-emitted straight from the inner VirtualizedList's own @Output()s (see
|
|
345
365
|
// the template's `(endReached)="endReached.emit($event)"` style forwarding above).
|
|
346
|
-
@Output() readonly endReached = new EventEmitter<{
|
|
347
|
-
|
|
366
|
+
@Output() readonly endReached = new EventEmitter<{
|
|
367
|
+
distanceFromEnd: number;
|
|
368
|
+
}>();
|
|
369
|
+
@Output() readonly startReached = new EventEmitter<{
|
|
370
|
+
distanceFromStart: number;
|
|
371
|
+
}>();
|
|
348
372
|
@Output() readonly refresh = new EventEmitter<void>();
|
|
349
|
-
@Output() readonly viewableItemsChanged = new EventEmitter<
|
|
373
|
+
@Output() readonly viewableItemsChanged = new EventEmitter<
|
|
374
|
+
IViewableItemsChangedInfo<ItemT>
|
|
375
|
+
>();
|
|
350
376
|
@Output() readonly scrollToIndexFailed = new EventEmitter<{
|
|
351
377
|
index: number;
|
|
352
378
|
highestMeasuredFrameIndex: number;
|
|
@@ -367,8 +393,10 @@ export class FlatList<ItemT = unknown>
|
|
|
367
393
|
@Input() onStartReachedThreshold?: number;
|
|
368
394
|
@Input() refreshing?: boolean | null;
|
|
369
395
|
@Input() progressViewOffset?: number;
|
|
370
|
-
@Input()
|
|
371
|
-
|
|
396
|
+
@Input()
|
|
397
|
+
viewabilityConfig?: IVirtualizedListProps<ItemT>['viewabilityConfig'];
|
|
398
|
+
@Input()
|
|
399
|
+
viewabilityConfigCallbackPairs?: IViewabilityConfigCallbackPair<ItemT>[];
|
|
372
400
|
@Input() initialNumToRender?: number;
|
|
373
401
|
@Input() initialScrollIndex?: number;
|
|
374
402
|
@Input() maxToRenderPerBatch?: number;
|
|
@@ -380,10 +408,13 @@ export class FlatList<ItemT = unknown>
|
|
|
380
408
|
autoscrollToTopThreshold?: number;
|
|
381
409
|
};
|
|
382
410
|
@Input() onScroll?: IVirtualizedListProps<ItemT>['onScroll'];
|
|
383
|
-
@Input()
|
|
411
|
+
@Input()
|
|
412
|
+
onScrollBeginDrag?: IVirtualizedListProps<ItemT>['onScrollBeginDrag'];
|
|
384
413
|
@Input() onScrollEndDrag?: IVirtualizedListProps<ItemT>['onScrollEndDrag'];
|
|
385
|
-
@Input()
|
|
386
|
-
|
|
414
|
+
@Input()
|
|
415
|
+
onMomentumScrollBegin?: IVirtualizedListProps<ItemT>['onMomentumScrollBegin'];
|
|
416
|
+
@Input()
|
|
417
|
+
onMomentumScrollEnd?: IVirtualizedListProps<ItemT>['onMomentumScrollEnd'];
|
|
387
418
|
@Input() scrollEventThrottle?: number;
|
|
388
419
|
@Input() keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
|
|
389
420
|
@Input() keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
|
|
@@ -397,7 +428,8 @@ export class FlatList<ItemT = unknown>
|
|
|
397
428
|
@ContentChild(VListHeaderDirective) headerDir?: VListHeaderDirective;
|
|
398
429
|
@ContentChild(VListFooterDirective) footerDir?: VListFooterDirective;
|
|
399
430
|
@ContentChild(VListEmptyDirective) emptyDir?: VListEmptyDirective;
|
|
400
|
-
@ContentChild(VListSeparatorDirective)
|
|
431
|
+
@ContentChild(VListSeparatorDirective)
|
|
432
|
+
separatorDir?: VListSeparatorDirective<ItemT>;
|
|
401
433
|
|
|
402
434
|
// The composed inner list (whichever numColumns branch rendered). Its instance IS the
|
|
403
435
|
// IVirtualizedListHandle, so FlatList's handle delegates straight to it.
|
|
@@ -427,18 +459,20 @@ export class FlatList<ItemT = unknown>
|
|
|
427
459
|
return this.columns > SINGLE_COLUMN;
|
|
428
460
|
}
|
|
429
461
|
|
|
462
|
+
// ngDoCheck, NOT ngOnChanges: a bare `class=` never becomes an @Input, so ngOnChanges does not
|
|
463
|
+
// RUN for it and the merge froze at its creation value (a stranded tile on the ReactiveStyle
|
|
464
|
+
// canary). stableAnchorStyle, not a bare flattenStyle, keeps `resolvedStyle`'s reference stable
|
|
465
|
+
// across ticks that changed nothing - a fresh object every tick defeats VirtualizedList's own
|
|
466
|
+
// dedup gate and free-runs CD (see stableAnchorStyle's doc comment).
|
|
467
|
+
ngDoCheck(): void {
|
|
468
|
+
this.resolvedStyle = stableAnchorStyle(
|
|
469
|
+
this.elementRef,
|
|
470
|
+
this.style,
|
|
471
|
+
this.resolvedStyle,
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
|
|
430
475
|
ngOnChanges(changes: SimpleChanges): void {
|
|
431
|
-
// Recomputed on EVERY ngOnChanges call, not gated on `changes['style']`: a class= on the
|
|
432
|
-
// FlatList use site (no matching [style] binding at all) never appears in `changes`, so a
|
|
433
|
-
// guard here would permanently skip picking up anchorHostStyle for that (the actual bug-report
|
|
434
|
-
// shape) — ngOnChanges still fires at least once at mount via the required `data` @Input(), and
|
|
435
|
-
// by then the anchor's class-derived style is already resolved synchronously (routeProp runs
|
|
436
|
-
// inline from Renderer2.addClass, before this component's own lifecycle hooks). stableAnchorStyle
|
|
437
|
-
// (not a bare flattenStyle) keeps `resolvedStyle`'s REFERENCE stable across ticks where nothing
|
|
438
|
-
// actually changed — `[style]="resolvedStyle"` binds onto VirtualizedList's own `@Input() style`,
|
|
439
|
-
// which feeds its `ngDoCheck` dedup gate; a fresh object every tick would defeat that gate and
|
|
440
|
-
// free-run change detection forever (see stableAnchorStyle's doc comment).
|
|
441
|
-
this.resolvedStyle = stableAnchorStyle(this.elementRef, this.style, this.resolvedStyle);
|
|
442
476
|
if (changes['columnWrapperStyle'] !== undefined) {
|
|
443
477
|
// A class-name string resolves through the shared registry before flattenStyle, which
|
|
444
478
|
// only understands style objects/arrays.
|
|
@@ -446,11 +480,18 @@ export class FlatList<ItemT = unknown>
|
|
|
446
480
|
typeof this.columnWrapperStyle === 'string'
|
|
447
481
|
? resolveClassName(this.columnWrapperStyle)
|
|
448
482
|
: this.columnWrapperStyle;
|
|
449
|
-
this.rowStyle = flattenStyle([
|
|
483
|
+
this.rowStyle = flattenStyle([
|
|
484
|
+
{ flexDirection: 'row' },
|
|
485
|
+
resolvedColumnWrapperStyle,
|
|
486
|
+
]);
|
|
450
487
|
}
|
|
451
488
|
if (changes['data'] !== undefined || changes['numColumns'] !== undefined) {
|
|
452
|
-
this.rows = this.isMultiColumn
|
|
453
|
-
|
|
489
|
+
this.rows = this.isMultiColumn
|
|
490
|
+
? chunkIntoRows(this.data, this.columns)
|
|
491
|
+
: [];
|
|
492
|
+
dlog(
|
|
493
|
+
`Angular FlatList over ${this.data?.length ?? 0} items, ${this.columns} column(s)`,
|
|
494
|
+
);
|
|
454
495
|
}
|
|
455
496
|
if (
|
|
456
497
|
changes['viewabilityConfigCallbackPairs'] !== undefined ||
|
|
@@ -471,15 +512,24 @@ export class FlatList<ItemT = unknown>
|
|
|
471
512
|
|
|
472
513
|
// Viewability over rows expands back to per-item tokens, so the caller sees item-level
|
|
473
514
|
// visibility, not row-level (shared expandRowViewability), matching Vue.
|
|
474
|
-
rowViewableItemsChanged = (
|
|
475
|
-
|
|
515
|
+
rowViewableItemsChanged = (
|
|
516
|
+
info: IViewableItemsChangedInfo<IRow<ItemT>>,
|
|
517
|
+
): void => {
|
|
518
|
+
this.viewableItemsChanged.emit(
|
|
519
|
+
expandRowViewability(info, this.keyExtractor),
|
|
520
|
+
);
|
|
476
521
|
};
|
|
477
522
|
|
|
478
|
-
private buildRowViewabilityPairs():
|
|
523
|
+
private buildRowViewabilityPairs():
|
|
524
|
+
IViewabilityConfigCallbackPair<IRow<ItemT>>[] | undefined {
|
|
479
525
|
return this.viewabilityConfigCallbackPairs?.map(pair => ({
|
|
480
526
|
viewabilityConfig: pair.viewabilityConfig,
|
|
481
|
-
onViewableItemsChanged: (
|
|
482
|
-
|
|
527
|
+
onViewableItemsChanged: (
|
|
528
|
+
rowInfo: IViewableItemsChangedInfo<IRow<ItemT>>,
|
|
529
|
+
): void => {
|
|
530
|
+
pair.onViewableItemsChanged?.(
|
|
531
|
+
expandRowViewability(rowInfo, this.keyExtractor),
|
|
532
|
+
);
|
|
483
533
|
},
|
|
484
534
|
}));
|
|
485
535
|
}
|
|
@@ -496,7 +546,9 @@ export class FlatList<ItemT = unknown>
|
|
|
496
546
|
const handle = isSeparators(separators) ? separators : NOOP_SEPARATORS;
|
|
497
547
|
return row.items.map((item, column) => {
|
|
498
548
|
const index = row.startIndex + column;
|
|
499
|
-
const key = this.keyExtractor
|
|
549
|
+
const key = this.keyExtractor
|
|
550
|
+
? this.keyExtractor(item, index)
|
|
551
|
+
: String(index);
|
|
500
552
|
return { key, context: { $implicit: item, index, separators: handle } };
|
|
501
553
|
});
|
|
502
554
|
}
|
|
@@ -513,8 +565,12 @@ export class FlatList<ItemT = unknown>
|
|
|
513
565
|
return {
|
|
514
566
|
$implicit: isHighlighted,
|
|
515
567
|
highlighted: isHighlighted,
|
|
516
|
-
leadingItem: isRow<ItemT>(leadingRow)
|
|
517
|
-
|
|
568
|
+
leadingItem: isRow<ItemT>(leadingRow)
|
|
569
|
+
? lastItemOfRow(leadingRow)
|
|
570
|
+
: undefined,
|
|
571
|
+
trailingItem: isRow<ItemT>(trailingRow)
|
|
572
|
+
? firstItemOfRow(trailingRow)
|
|
573
|
+
: undefined,
|
|
518
574
|
};
|
|
519
575
|
}
|
|
520
576
|
|
|
@@ -547,7 +603,11 @@ export class FlatList<ItemT = unknown>
|
|
|
547
603
|
}): void {
|
|
548
604
|
this.listRef?.scrollToIndex(params);
|
|
549
605
|
}
|
|
550
|
-
scrollToItem(params: {
|
|
606
|
+
scrollToItem(params: {
|
|
607
|
+
item: unknown;
|
|
608
|
+
animated?: boolean;
|
|
609
|
+
viewPosition?: number;
|
|
610
|
+
}): void {
|
|
551
611
|
this.listRef?.scrollToItem(params);
|
|
552
612
|
}
|
|
553
613
|
scrollToEnd(params?: { animated?: boolean }): void {
|
|
@@ -1,6 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
3
|
+
Component,
|
|
4
|
+
ElementRef,
|
|
5
|
+
inject,
|
|
6
|
+
signal,
|
|
7
|
+
type DoCheck,
|
|
8
|
+
type OnChanges,
|
|
9
|
+
} from '@angular/core';
|
|
10
|
+
import {
|
|
11
|
+
anchorHostStyle,
|
|
12
|
+
ImageHost,
|
|
13
|
+
SymbioteHostPropsDirective,
|
|
14
|
+
SymbioteStyleInputDirective,
|
|
15
|
+
} from '../../primitives';
|
|
16
|
+
import {
|
|
17
|
+
IMAGE_INPUTS,
|
|
18
|
+
IMAGE_OUTPUTS,
|
|
19
|
+
ImageBase,
|
|
20
|
+
resolveImageProps,
|
|
21
|
+
} from './shared';
|
|
4
22
|
export { setImageSourceResolver } from './shared';
|
|
5
23
|
export type {
|
|
6
24
|
IImageProps,
|
|
@@ -14,13 +32,16 @@ export type {
|
|
|
14
32
|
@Component({
|
|
15
33
|
selector: 'Image',
|
|
16
34
|
standalone: true,
|
|
35
|
+
hostDirectives: [
|
|
36
|
+
{ directive: SymbioteStyleInputDirective, inputs: ['style'] },
|
|
37
|
+
],
|
|
17
38
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
18
39
|
imports: [ImageHost, SymbioteHostPropsDirective],
|
|
19
40
|
inputs: IMAGE_INPUTS,
|
|
20
41
|
outputs: IMAGE_OUTPUTS,
|
|
21
42
|
template: `
|
|
22
43
|
<symbiote-image
|
|
23
|
-
[symbioteHostProps]="imageProps"
|
|
44
|
+
[symbioteHostProps]="imageProps()"
|
|
24
45
|
(accessibilityAction)="handleAccessibilityAction($event)"
|
|
25
46
|
(accessibilityTap)="handleAccessibilityTap($event)"
|
|
26
47
|
(magicTap)="handleMagicTap($event)"
|
|
@@ -34,15 +55,45 @@ export type {
|
|
|
34
55
|
/>
|
|
35
56
|
`,
|
|
36
57
|
})
|
|
37
|
-
export class Image extends ImageBase {
|
|
58
|
+
export class Image extends ImageBase implements OnChanges, DoCheck {
|
|
38
59
|
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
39
60
|
// onto (see anchorHostStyle's doc comment) — NOT the inner `symbiote-image` one level down.
|
|
40
61
|
private readonly elementRef = inject(ElementRef);
|
|
41
62
|
|
|
42
|
-
|
|
63
|
+
// The anchor's class-derived style is written by the renderer's addClass/removeClass and never
|
|
64
|
+
// reaches Angular's input pipeline (a bare `class="x"` never appears in SimpleChanges — see
|
|
65
|
+
// anchorHostStyle's doc comment), so ImageBase's inputsRevision cannot see it. Hence its own
|
|
66
|
+
// signal: a plain field read inside a computed() would be untracked and the bag would go stale
|
|
67
|
+
// the moment a `[class.x]`/`[ngClass]` toggled.
|
|
68
|
+
//
|
|
69
|
+
// ngDoCheck is the right cadence: render3's callHooks flushes a node's pre-order hooks at the
|
|
70
|
+
// next `ɵɵadvance` past it (or in refreshView's post-template flush), i.e. AFTER the declaring
|
|
71
|
+
// template's ɵɵclassProp wrote the class onto this element and BEFORE this component's own view
|
|
72
|
+
// refreshes — the exact window a class poll needs. callHooks also runs under
|
|
73
|
+
// setActiveConsumer(null), so the write registers no dependency on the caller's view (no NG0600).
|
|
74
|
+
// commitClassStyle allocates a fresh style array only when a token actually moved, so signal.set's
|
|
75
|
+
// own Object.is check makes an unchanged poll a no-op that dirties nothing.
|
|
76
|
+
//
|
|
77
|
+
// Known gap, shared with every other component polling this way (Pressable, SafeAreaView,
|
|
78
|
+
// TouchableNativeFeedback): `[ngClass]` applies its tokens from NgClass's OWN ngDoCheck, and a
|
|
79
|
+
// node's hooks flush in registration order with the component's first, so an [ngClass] flip lands
|
|
80
|
+
// one pass after this poll reads it. `class=` and `[class.x]` are written by the declaring
|
|
81
|
+
// template's styling instructions and so are always current here.
|
|
82
|
+
private readonly anchorStyle = signal<unknown>(undefined);
|
|
83
|
+
|
|
84
|
+
// ImageBase is undecorated, so the input bump is declared here rather than inherited.
|
|
85
|
+
ngOnChanges(): void {
|
|
86
|
+
this.bumpInputsRevision();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
ngDoCheck(): void {
|
|
90
|
+
this.anchorStyle.set(anchorHostStyle(this.elementRef));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
protected override buildImageProps(): Record<string, unknown> {
|
|
43
94
|
return resolveImageProps({
|
|
44
95
|
...this.imageInputProps,
|
|
45
|
-
style: [
|
|
96
|
+
style: [this.anchorStyle(), this.style],
|
|
46
97
|
});
|
|
47
98
|
}
|
|
48
99
|
}
|
|
@@ -1,6 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
3
|
+
Component,
|
|
4
|
+
ElementRef,
|
|
5
|
+
inject,
|
|
6
|
+
signal,
|
|
7
|
+
type DoCheck,
|
|
8
|
+
type OnChanges,
|
|
9
|
+
} from '@angular/core';
|
|
10
|
+
import {
|
|
11
|
+
anchorHostStyle,
|
|
12
|
+
ImageHost,
|
|
13
|
+
SymbioteHostPropsDirective,
|
|
14
|
+
SymbioteStyleInputDirective,
|
|
15
|
+
} from '../../primitives';
|
|
16
|
+
import {
|
|
17
|
+
IMAGE_INPUTS,
|
|
18
|
+
IMAGE_OUTPUTS,
|
|
19
|
+
ImageBase,
|
|
20
|
+
resolveImageProps,
|
|
21
|
+
} from './shared';
|
|
4
22
|
export { setImageSourceResolver } from './shared';
|
|
5
23
|
export type {
|
|
6
24
|
IImageProps,
|
|
@@ -14,13 +32,16 @@ export type {
|
|
|
14
32
|
@Component({
|
|
15
33
|
selector: 'Image',
|
|
16
34
|
standalone: true,
|
|
35
|
+
hostDirectives: [
|
|
36
|
+
{ directive: SymbioteStyleInputDirective, inputs: ['style'] },
|
|
37
|
+
],
|
|
17
38
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
18
39
|
imports: [ImageHost, SymbioteHostPropsDirective],
|
|
19
40
|
inputs: IMAGE_INPUTS,
|
|
20
41
|
outputs: IMAGE_OUTPUTS,
|
|
21
42
|
template: `
|
|
22
43
|
<symbiote-image
|
|
23
|
-
[symbioteHostProps]="imageProps"
|
|
44
|
+
[symbioteHostProps]="imageProps()"
|
|
24
45
|
(accessibilityAction)="handleAccessibilityAction($event)"
|
|
25
46
|
(accessibilityTap)="handleAccessibilityTap($event)"
|
|
26
47
|
(magicTap)="handleMagicTap($event)"
|
|
@@ -34,15 +55,45 @@ export type {
|
|
|
34
55
|
/>
|
|
35
56
|
`,
|
|
36
57
|
})
|
|
37
|
-
export class Image extends ImageBase {
|
|
58
|
+
export class Image extends ImageBase implements OnChanges, DoCheck {
|
|
38
59
|
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
39
60
|
// onto (see anchorHostStyle's doc comment) — NOT the inner `symbiote-image` one level down.
|
|
40
61
|
private readonly elementRef = inject(ElementRef);
|
|
41
62
|
|
|
42
|
-
|
|
63
|
+
// The anchor's class-derived style is written by the renderer's addClass/removeClass and never
|
|
64
|
+
// reaches Angular's input pipeline (a bare `class="x"` never appears in SimpleChanges — see
|
|
65
|
+
// anchorHostStyle's doc comment), so ImageBase's inputsRevision cannot see it. Hence its own
|
|
66
|
+
// signal: a plain field read inside a computed() would be untracked and the bag would go stale
|
|
67
|
+
// the moment a `[class.x]`/`[ngClass]` toggled.
|
|
68
|
+
//
|
|
69
|
+
// ngDoCheck is the right cadence: render3's callHooks flushes a node's pre-order hooks at the
|
|
70
|
+
// next `ɵɵadvance` past it (or in refreshView's post-template flush), i.e. AFTER the declaring
|
|
71
|
+
// template's ɵɵclassProp wrote the class onto this element and BEFORE this component's own view
|
|
72
|
+
// refreshes — the exact window a class poll needs. callHooks also runs under
|
|
73
|
+
// setActiveConsumer(null), so the write registers no dependency on the caller's view (no NG0600).
|
|
74
|
+
// commitClassStyle allocates a fresh style array only when a token actually moved, so signal.set's
|
|
75
|
+
// own Object.is check makes an unchanged poll a no-op that dirties nothing.
|
|
76
|
+
//
|
|
77
|
+
// Known gap, shared with every other component polling this way (Pressable, SafeAreaView,
|
|
78
|
+
// TouchableNativeFeedback): `[ngClass]` applies its tokens from NgClass's OWN ngDoCheck, and a
|
|
79
|
+
// node's hooks flush in registration order with the component's first, so an [ngClass] flip lands
|
|
80
|
+
// one pass after this poll reads it. `class=` and `[class.x]` are written by the declaring
|
|
81
|
+
// template's styling instructions and so are always current here.
|
|
82
|
+
private readonly anchorStyle = signal<unknown>(undefined);
|
|
83
|
+
|
|
84
|
+
// ImageBase is undecorated, so the input bump is declared here rather than inherited.
|
|
85
|
+
ngOnChanges(): void {
|
|
86
|
+
this.bumpInputsRevision();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
ngDoCheck(): void {
|
|
90
|
+
this.anchorStyle.set(anchorHostStyle(this.elementRef));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
protected override buildImageProps(): Record<string, unknown> {
|
|
43
94
|
return resolveImageProps({
|
|
44
95
|
...this.imageInputProps,
|
|
45
|
-
style: [
|
|
96
|
+
style: [this.anchorStyle(), this.style],
|
|
46
97
|
});
|
|
47
98
|
}
|
|
48
99
|
}
|