@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
|
@@ -46,7 +46,8 @@ export interface IVSectionContext<ItemT> {
|
|
|
46
46
|
// `<ng-template vSectionItem>` — one section item row. The static guard types the `let-` bindings.
|
|
47
47
|
@Directive({ selector: '[vSectionItem]', standalone: true })
|
|
48
48
|
export class VSectionItemDirective<ItemT = unknown> {
|
|
49
|
-
readonly templateRef =
|
|
49
|
+
readonly templateRef =
|
|
50
|
+
inject<TemplateRef<IVSectionItemContext<ItemT>>>(TemplateRef);
|
|
50
51
|
|
|
51
52
|
static ngTemplateContextGuard<T>(
|
|
52
53
|
_dir: VSectionItemDirective<T>,
|
|
@@ -59,7 +60,8 @@ export class VSectionItemDirective<ItemT = unknown> {
|
|
|
59
60
|
// `<ng-template vSectionHeader>` — rendered above each section's items (RN renderSectionHeader).
|
|
60
61
|
@Directive({ selector: '[vSectionHeader]', standalone: true })
|
|
61
62
|
export class VSectionHeaderDirective<ItemT = unknown> {
|
|
62
|
-
readonly templateRef =
|
|
63
|
+
readonly templateRef =
|
|
64
|
+
inject<TemplateRef<IVSectionContext<ItemT>>>(TemplateRef);
|
|
63
65
|
|
|
64
66
|
static ngTemplateContextGuard<T>(
|
|
65
67
|
_dir: VSectionHeaderDirective<T>,
|
|
@@ -72,7 +74,8 @@ export class VSectionHeaderDirective<ItemT = unknown> {
|
|
|
72
74
|
// `<ng-template vSectionFooter>` — rendered below each section's items (RN renderSectionFooter).
|
|
73
75
|
@Directive({ selector: '[vSectionFooter]', standalone: true })
|
|
74
76
|
export class VSectionFooterDirective<ItemT = unknown> {
|
|
75
|
-
readonly templateRef =
|
|
77
|
+
readonly templateRef =
|
|
78
|
+
inject<TemplateRef<IVSectionContext<ItemT>>>(TemplateRef);
|
|
76
79
|
|
|
77
80
|
static ngTemplateContextGuard<T>(
|
|
78
81
|
_dir: VSectionFooterDirective<T>,
|
|
@@ -64,7 +64,10 @@ import {
|
|
|
64
64
|
type IVListSeparatorContext,
|
|
65
65
|
} from '../virtualized-list';
|
|
66
66
|
import { VListOutletDirective } from '../virtualized-list/directives';
|
|
67
|
-
import {
|
|
67
|
+
import {
|
|
68
|
+
stableAnchorStyle,
|
|
69
|
+
SymbioteStyleInputDirective,
|
|
70
|
+
} from '../../primitives';
|
|
68
71
|
import {
|
|
69
72
|
VSectionFooterDirective,
|
|
70
73
|
VSectionHeaderDirective,
|
|
@@ -92,9 +95,20 @@ export type { IVSectionContext, IVSectionItemContext } from './directives';
|
|
|
92
95
|
// those are the per-adapter children/render fields and become `<ng-template>` directives in Angular.
|
|
93
96
|
// Everything agnostic is the SAME surface as the
|
|
94
97
|
// React/Vue adapters, including the a11y/aria prop family forwarded through VirtualizedList.
|
|
95
|
-
export interface IVirtualizedSectionListProps<ItemT>
|
|
98
|
+
export interface IVirtualizedSectionListProps<ItemT>
|
|
99
|
+
extends IAccessibilityProps, IAriaProps {
|
|
96
100
|
sections: ReadonlyArray<ISection<ItemT>>;
|
|
97
101
|
keyExtractor?: (item: ItemT, index: number) => string;
|
|
102
|
+
// Fixed-layout fast path, FLAT like RN's: the SECTIONS array plus a flat entry index, where every
|
|
103
|
+
// section contributes two rows beyond its items (header, footer) and the caller accounts for them.
|
|
104
|
+
// A `({ section, index })` form would be our invention, not parity - `VirtualizedSectionList.js`
|
|
105
|
+
// has no getItemLayout code at all, the prop rides through `passThroughProps`; that shape is the
|
|
106
|
+
// community react-native-section-list-get-item-layout, layered on top. Without it a fast scroll
|
|
107
|
+
// outruns measurement and leaves blank windows.
|
|
108
|
+
getItemLayout?: (
|
|
109
|
+
data: ReadonlyArray<ISection<ItemT>> | null,
|
|
110
|
+
index: number,
|
|
111
|
+
) => { length: number; offset: number; index: number };
|
|
98
112
|
// Stick each section header to the top as the next section scrolls up. Routed to the inner
|
|
99
113
|
// VirtualizedList's stickyHeaderIndices. Defaults to `Platform.OS === 'ios'`; Android does not
|
|
100
114
|
// stick by default. Pass true/false to override.
|
|
@@ -146,6 +160,9 @@ export type IVirtualizedSectionListInputs<ItemT> = Omit<
|
|
|
146
160
|
@Component({
|
|
147
161
|
selector: 'VirtualizedSectionList',
|
|
148
162
|
standalone: true,
|
|
163
|
+
hostDirectives: [
|
|
164
|
+
{ directive: SymbioteStyleInputDirective, inputs: ['style'] },
|
|
165
|
+
],
|
|
149
166
|
imports: [
|
|
150
167
|
VirtualizedList,
|
|
151
168
|
VListItemDirective,
|
|
@@ -162,6 +179,7 @@ export type IVirtualizedSectionListInputs<ItemT> = Omit<
|
|
|
162
179
|
[getItem]="getEntry"
|
|
163
180
|
[getItemCount]="getEntryCount"
|
|
164
181
|
[keyExtractor]="entryKeyExtractor"
|
|
182
|
+
[getItemLayout]="entryItemLayout"
|
|
165
183
|
[stickyHeaderIndices]="stickyHeaderIndices"
|
|
166
184
|
[extraData]="extraData"
|
|
167
185
|
[inverted]="inverted"
|
|
@@ -206,8 +224,12 @@ export type IVirtualizedSectionListInputs<ItemT> = Omit<
|
|
|
206
224
|
[accessibilityElementsHidden]="accessibilityElementsHidden"
|
|
207
225
|
[accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
|
|
208
226
|
[accessibilityLanguage]="accessibilityLanguage"
|
|
209
|
-
[accessibilityRespondsToUserInteraction]="
|
|
210
|
-
|
|
227
|
+
[accessibilityRespondsToUserInteraction]="
|
|
228
|
+
accessibilityRespondsToUserInteraction
|
|
229
|
+
"
|
|
230
|
+
[accessibilityShowsLargeContentViewer]="
|
|
231
|
+
accessibilityShowsLargeContentViewer
|
|
232
|
+
"
|
|
211
233
|
[accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
|
|
212
234
|
(accessibilityAction)="resolvedOnAccessibilityAction?.($event)"
|
|
213
235
|
(accessibilityTap)="resolvedOnAccessibilityTap?.($event)"
|
|
@@ -245,7 +267,9 @@ export type IVirtualizedSectionListInputs<ItemT> = Omit<
|
|
|
245
267
|
></ng-container>
|
|
246
268
|
}
|
|
247
269
|
@case ('section-separator') {
|
|
248
|
-
<ng-container
|
|
270
|
+
<ng-container
|
|
271
|
+
[vListOutlet]="sectionSeparatorDir?.templateRef"
|
|
272
|
+
></ng-container>
|
|
249
273
|
}
|
|
250
274
|
@case ('item') {
|
|
251
275
|
<ng-container
|
|
@@ -259,12 +283,16 @@ export type IVirtualizedSectionListInputs<ItemT> = Omit<
|
|
|
259
283
|
<!-- list-level slots: forward the app's VirtualizedList directives to the inner list. -->
|
|
260
284
|
@if (listHeaderDir !== undefined) {
|
|
261
285
|
<ng-template vListHeader>
|
|
262
|
-
<ng-container
|
|
286
|
+
<ng-container
|
|
287
|
+
[vListOutlet]="listHeaderDir.templateRef"
|
|
288
|
+
></ng-container>
|
|
263
289
|
</ng-template>
|
|
264
290
|
}
|
|
265
291
|
@if (listFooterDir !== undefined) {
|
|
266
292
|
<ng-template vListFooter>
|
|
267
|
-
<ng-container
|
|
293
|
+
<ng-container
|
|
294
|
+
[vListOutlet]="listFooterDir.templateRef"
|
|
295
|
+
></ng-container>
|
|
268
296
|
</ng-template>
|
|
269
297
|
}
|
|
270
298
|
@if (listEmptyDir !== undefined) {
|
|
@@ -282,7 +310,9 @@ export type IVirtualizedSectionListInputs<ItemT> = Omit<
|
|
|
282
310
|
>
|
|
283
311
|
<ng-container
|
|
284
312
|
[vListOutlet]="itemSeparatorDir.templateRef"
|
|
285
|
-
[vListOutletContext]="
|
|
313
|
+
[vListOutletContext]="
|
|
314
|
+
itemSeparatorContextOf(highlighted, leadingItem, trailingItem)
|
|
315
|
+
"
|
|
286
316
|
></ng-container>
|
|
287
317
|
</ng-template>
|
|
288
318
|
}
|
|
@@ -290,15 +320,26 @@ export type IVirtualizedSectionListInputs<ItemT> = Omit<
|
|
|
290
320
|
`,
|
|
291
321
|
})
|
|
292
322
|
export class VirtualizedSectionList<ItemT = unknown>
|
|
293
|
-
implements
|
|
323
|
+
implements
|
|
324
|
+
IVirtualizedSectionListInputs<ItemT>,
|
|
325
|
+
IVirtualizedSectionListHandle,
|
|
326
|
+
DoCheck
|
|
294
327
|
{
|
|
295
328
|
@Input({ required: true }) sections!: ReadonlyArray<ISection<ItemT>>;
|
|
296
329
|
@Input() keyExtractor?: (item: ItemT, index: number) => string;
|
|
330
|
+
@Input() getItemLayout?: (
|
|
331
|
+
data: ReadonlyArray<ISection<ItemT>> | null,
|
|
332
|
+
index: number,
|
|
333
|
+
) => { length: number; offset: number; index: number };
|
|
297
334
|
@Input() stickySectionHeadersEnabled?: boolean;
|
|
298
335
|
@Input() extraData?: unknown;
|
|
299
|
-
@Output() readonly endReached = new EventEmitter<{
|
|
336
|
+
@Output() readonly endReached = new EventEmitter<{
|
|
337
|
+
distanceFromEnd: number;
|
|
338
|
+
}>();
|
|
300
339
|
@Input() onEndReachedThreshold?: number;
|
|
301
|
-
@Output() readonly startReached = new EventEmitter<{
|
|
340
|
+
@Output() readonly startReached = new EventEmitter<{
|
|
341
|
+
distanceFromStart: number;
|
|
342
|
+
}>();
|
|
302
343
|
@Input() onStartReachedThreshold?: number;
|
|
303
344
|
@Output() readonly refresh = new EventEmitter<void>();
|
|
304
345
|
@Input() refreshing?: boolean | null;
|
|
@@ -359,8 +400,10 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
359
400
|
@Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
|
|
360
401
|
@Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
|
|
361
402
|
@Input() accessibilityLabelledBy?: string | string[];
|
|
362
|
-
@Input()
|
|
363
|
-
|
|
403
|
+
@Input()
|
|
404
|
+
importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
|
|
405
|
+
@Input()
|
|
406
|
+
accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
|
|
364
407
|
@Input() screenReaderFocusable?: boolean;
|
|
365
408
|
@Input() accessibilityViewIsModal?: boolean;
|
|
366
409
|
@Input() accessibilityElementsHidden?: boolean;
|
|
@@ -392,20 +435,27 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
392
435
|
// The section cell templates the app authors (the Angular twin of renderItem /
|
|
393
436
|
// renderSectionHeader / renderSectionFooter / SectionSeparatorComponent), captured from projected
|
|
394
437
|
// <ng-template> content and stamped by the synthesized vListItem dispatch.
|
|
395
|
-
@ContentChild(VSectionItemDirective)
|
|
396
|
-
|
|
397
|
-
@ContentChild(
|
|
398
|
-
|
|
438
|
+
@ContentChild(VSectionItemDirective)
|
|
439
|
+
sectionItemDir?: VSectionItemDirective<ItemT>;
|
|
440
|
+
@ContentChild(VSectionHeaderDirective)
|
|
441
|
+
sectionHeaderDir?: VSectionHeaderDirective<ItemT>;
|
|
442
|
+
@ContentChild(VSectionFooterDirective)
|
|
443
|
+
sectionFooterDir?: VSectionFooterDirective<ItemT>;
|
|
444
|
+
@ContentChild(VSectionSeparatorDirective)
|
|
445
|
+
sectionSeparatorDir?: VSectionSeparatorDirective;
|
|
399
446
|
|
|
400
447
|
// list-level slots reuse VirtualizedList's own directives; VSL forwards them to the inner list.
|
|
401
448
|
@ContentChild(VListHeaderDirective) listHeaderDir?: VListHeaderDirective;
|
|
402
449
|
@ContentChild(VListFooterDirective) listFooterDir?: VListFooterDirective;
|
|
403
450
|
@ContentChild(VListEmptyDirective) listEmptyDir?: VListEmptyDirective;
|
|
404
|
-
@ContentChild(VListSeparatorDirective)
|
|
451
|
+
@ContentChild(VListSeparatorDirective)
|
|
452
|
+
itemSeparatorDir?: VListSeparatorDirective<ItemT>;
|
|
405
453
|
|
|
406
454
|
// The composed inner VirtualizedList. Its instance IS an IVirtualizedListHandle, so the section
|
|
407
455
|
// handle delegates straight to it. Available from ngAfterViewInit; reads lazily, no-ops pre-commit.
|
|
408
|
-
@ViewChild(VirtualizedList) private list?: VirtualizedList<
|
|
456
|
+
@ViewChild(VirtualizedList) private list?: VirtualizedList<
|
|
457
|
+
ISectionEntry<ItemT>
|
|
458
|
+
>;
|
|
409
459
|
|
|
410
460
|
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
411
461
|
// onto (see anchorHostStyle's doc comment) — NOT `list` above, which targets the real inner
|
|
@@ -438,7 +488,10 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
438
488
|
this.lastHasSectionSeparator = hasSectionSeparator;
|
|
439
489
|
|
|
440
490
|
const sections = this.sections ?? [];
|
|
441
|
-
const { entries, headerIndices } = flattenSections(
|
|
491
|
+
const { entries, headerIndices } = flattenSections(
|
|
492
|
+
sections,
|
|
493
|
+
hasSectionSeparator,
|
|
494
|
+
);
|
|
442
495
|
this.flatEntries = entries;
|
|
443
496
|
this.headerIndices = headerIndices;
|
|
444
497
|
|
|
@@ -457,42 +510,95 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
457
510
|
|
|
458
511
|
// The derived flat-stream accessors handed to the inner VirtualizedList. Stable arrow fields so
|
|
459
512
|
// the bindings keep a constant identity; they read the live flatEntries.
|
|
460
|
-
getEntry = (_source: unknown, index: number): ISectionEntry<ItemT> =>
|
|
513
|
+
getEntry = (_source: unknown, index: number): ISectionEntry<ItemT> =>
|
|
514
|
+
this.flatEntries[index];
|
|
461
515
|
getEntryCount = (): number => this.flatEntries.length;
|
|
462
516
|
entryKeyExtractor = (entry: ISectionEntry<ItemT>, index: number): string =>
|
|
463
517
|
sectionEntryKey(entry, index, this.keyExtractor);
|
|
464
518
|
|
|
519
|
+
// Hand the callback `sections`, not the entries: RN's inner VirtualizedList gets
|
|
520
|
+
// `data={this.props.sections}` (VirtualizedSectionList.js:216) while ours streams the FLATTENED
|
|
521
|
+
// entries, so the same user code would otherwise see a different argument here than on RN.
|
|
522
|
+
//
|
|
523
|
+
// UPSTREAM-DIVERGENCE(react-native): the flat INDEX matches RN's (two rows per section, header
|
|
524
|
+
// and footer) only while the vSectionSeparator template is unset. With it, flattenSections emits
|
|
525
|
+
// an extra 'section-separator' row per boundary that RN renders inside the neighbouring cell, so
|
|
526
|
+
// indices shift by one per boundary from the second section on. Deliberate - that row is how this
|
|
527
|
+
// adapter paints the separator; a caller combining the two must account for it.
|
|
528
|
+
//
|
|
529
|
+
// Cached on the input's own identity, like resolvedStyle above: the inner VirtualizedList folds
|
|
530
|
+
// getItemLayout into its ngDoCheck dedup array, so a wrapper allocated per getter read would
|
|
531
|
+
// re-run its whole recompute every CD.
|
|
532
|
+
private cachedEntryItemLayout?: (
|
|
533
|
+
data: unknown,
|
|
534
|
+
index: number,
|
|
535
|
+
) => { length: number; offset: number; index: number };
|
|
536
|
+
private lastGetItemLayout?: IVirtualizedSectionListProps<ItemT>['getItemLayout'];
|
|
537
|
+
get entryItemLayout():
|
|
538
|
+
| ((
|
|
539
|
+
data: unknown,
|
|
540
|
+
index: number,
|
|
541
|
+
) => { length: number; offset: number; index: number })
|
|
542
|
+
| undefined {
|
|
543
|
+
if (this.getItemLayout !== this.lastGetItemLayout) {
|
|
544
|
+
const getItemLayout = this.getItemLayout;
|
|
545
|
+
this.lastGetItemLayout = getItemLayout;
|
|
546
|
+
this.cachedEntryItemLayout =
|
|
547
|
+
getItemLayout === undefined
|
|
548
|
+
? undefined
|
|
549
|
+
: (
|
|
550
|
+
_entries: unknown,
|
|
551
|
+
index: number,
|
|
552
|
+
): { length: number; offset: number; index: number } =>
|
|
553
|
+
getItemLayout(this.sections, index);
|
|
554
|
+
}
|
|
555
|
+
return this.cachedEntryItemLayout;
|
|
556
|
+
}
|
|
557
|
+
|
|
465
558
|
// Adapts each @Output() into the plain callback VirtualizedList's own @Input() still wants,
|
|
466
559
|
// gated on `.observed` so an unlistened event forwards `undefined` — the same "nobody cares"
|
|
467
560
|
// contract the old @Input() callback passthrough had (e.g. onRefresh presence gates whether a
|
|
468
561
|
// RefreshControl is built downstream; see the Vue twin's `listens('onRefresh')` gate).
|
|
469
|
-
get resolvedOnEndReached():
|
|
470
|
-
|
|
562
|
+
get resolvedOnEndReached():
|
|
563
|
+
((info: { distanceFromEnd: number }) => void) | undefined {
|
|
564
|
+
return this.endReached.observed
|
|
565
|
+
? info => this.endReached.emit(info)
|
|
566
|
+
: undefined;
|
|
471
567
|
}
|
|
472
568
|
|
|
473
|
-
get resolvedOnStartReached():
|
|
474
|
-
|
|
569
|
+
get resolvedOnStartReached():
|
|
570
|
+
((info: { distanceFromStart: number }) => void) | undefined {
|
|
571
|
+
return this.startReached.observed
|
|
572
|
+
? info => this.startReached.emit(info)
|
|
573
|
+
: undefined;
|
|
475
574
|
}
|
|
476
575
|
|
|
477
576
|
get resolvedOnRefresh(): (() => void) | undefined {
|
|
478
577
|
return this.refresh.observed ? () => this.refresh.emit() : undefined;
|
|
479
578
|
}
|
|
480
579
|
|
|
481
|
-
get resolvedOnAccessibilityAction():
|
|
580
|
+
get resolvedOnAccessibilityAction():
|
|
581
|
+
((event: ISymbioteEvent) => void) | undefined {
|
|
482
582
|
return this.accessibilityAction.observed
|
|
483
583
|
? event => this.accessibilityAction.emit(event)
|
|
484
584
|
: undefined;
|
|
485
585
|
}
|
|
486
586
|
|
|
487
|
-
get resolvedOnAccessibilityTap():
|
|
488
|
-
|
|
587
|
+
get resolvedOnAccessibilityTap():
|
|
588
|
+
((event: ISymbioteEvent) => void) | undefined {
|
|
589
|
+
return this.accessibilityTap.observed
|
|
590
|
+
? event => this.accessibilityTap.emit(event)
|
|
591
|
+
: undefined;
|
|
489
592
|
}
|
|
490
593
|
|
|
491
594
|
get resolvedOnMagicTap(): ((event: ISymbioteEvent) => void) | undefined {
|
|
492
|
-
return this.magicTap.observed
|
|
595
|
+
return this.magicTap.observed
|
|
596
|
+
? event => this.magicTap.emit(event)
|
|
597
|
+
: undefined;
|
|
493
598
|
}
|
|
494
599
|
|
|
495
|
-
get resolvedOnAccessibilityEscape():
|
|
600
|
+
get resolvedOnAccessibilityEscape():
|
|
601
|
+
((event: ISymbioteEvent) => void) | undefined {
|
|
496
602
|
return this.accessibilityEscape.observed
|
|
497
603
|
? event => this.accessibilityEscape.emit(event)
|
|
498
604
|
: undefined;
|
|
@@ -515,7 +621,10 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
515
621
|
return { $implicit: value.section, section: value.section };
|
|
516
622
|
}
|
|
517
623
|
|
|
518
|
-
itemContextOf(
|
|
624
|
+
itemContextOf(
|
|
625
|
+
value: unknown,
|
|
626
|
+
separators: ISeparators,
|
|
627
|
+
): IVSectionItemContext<ItemT> | undefined {
|
|
519
628
|
if (!this.isEntry(value) || value.kind !== 'item') return undefined;
|
|
520
629
|
return {
|
|
521
630
|
$implicit: value.item,
|
|
@@ -538,8 +647,12 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
538
647
|
return {
|
|
539
648
|
$implicit: highlighted === true,
|
|
540
649
|
highlighted: highlighted === true,
|
|
541
|
-
leadingItem: this.isEntry(leadingItem)
|
|
542
|
-
|
|
650
|
+
leadingItem: this.isEntry(leadingItem)
|
|
651
|
+
? unwrapEntryItem(leadingItem)
|
|
652
|
+
: undefined,
|
|
653
|
+
trailingItem: this.isEntry(trailingItem)
|
|
654
|
+
? unwrapEntryItem(trailingItem)
|
|
655
|
+
: undefined,
|
|
543
656
|
};
|
|
544
657
|
}
|
|
545
658
|
|
package/src/components.ts
CHANGED
|
@@ -112,7 +112,10 @@ export type {
|
|
|
112
112
|
IVSectionItemContext,
|
|
113
113
|
} from './components/virtualized-section-list';
|
|
114
114
|
export { SectionList } from './components/section-list';
|
|
115
|
-
export type {
|
|
115
|
+
export type {
|
|
116
|
+
ISectionListHandle,
|
|
117
|
+
ISectionListProps,
|
|
118
|
+
} from './components/section-list';
|
|
116
119
|
|
|
117
120
|
// Re-export primitive hosts so composed components can import them from the public barrel too.
|
|
118
121
|
export {
|
|
@@ -134,6 +137,11 @@ export {
|
|
|
134
137
|
RefreshControlHost,
|
|
135
138
|
InputAccessoryViewHost,
|
|
136
139
|
SymbioteHostPropsDirective,
|
|
140
|
+
// Public even though no app names it: it rides `hostDirectives` on every component declaring a
|
|
141
|
+
// `style` input, so ngtsc writes it into their public type metadata and a consuming app's AOT
|
|
142
|
+
// build fails with NG3004 without it. Invisible to tsc and vitest; only a consumer's ngc catches
|
|
143
|
+
// it.
|
|
144
|
+
SymbioteStyleInputDirective,
|
|
137
145
|
// Exported so an OUT-OF-PACKAGE composed component (e.g. @symbiote-native/slider's Angular wrapper,
|
|
138
146
|
// itself listed in ANCHOR_HOST_COMPONENTS) can merge its own anchor host's class-derived style
|
|
139
147
|
// the same way every in-package composed component does — see anchorHostStyle's doc comment.
|
|
@@ -1,38 +1,32 @@
|
|
|
1
1
|
// createPortal for @symbiote-native/angular — the Angular twin of the React/Vue same-surface portal
|
|
2
|
-
// (create-portal.ts / Teleport in runtime-helpers.ts). Scope is identical: the target must be
|
|
3
|
-
//
|
|
4
|
-
// across independently-mounted surfaces has no safe host-level primitive
|
|
5
|
-
//
|
|
2
|
+
// (create-portal.ts / Teleport in runtime-helpers.ts). Scope is identical: the target must be an
|
|
3
|
+
// already-mounted location WITHIN THE SAME SURFACE as the portal's call site — moving content
|
|
4
|
+
// across independently-mounted surfaces has no safe host-level primitive, so createTunnel
|
|
5
|
+
// (create-tunnel.ts) covers that cross-surface case instead.
|
|
6
6
|
//
|
|
7
|
-
// React/Vue implement this as a thin validating wrapper around a mechanism the
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// point), not from wherever a node was manually moved to afterwards, so a raw Renderer2 move
|
|
15
|
-
// would desync Angular's internals from the retained tree.
|
|
7
|
+
// React/Vue implement this as a thin validating wrapper around a mechanism the framework itself
|
|
8
|
+
// already has (react-reconciler's Fiber-level HostPortal, Vue's own <Teleport>). Angular has no
|
|
9
|
+
// such built-in (no `@angular/cdk` dependency here, core-only — see package.json), and physically
|
|
10
|
+
// moving an EmbeddedView's already-created root nodes via Renderer2 after the fact is NOT safe —
|
|
11
|
+
// Angular's own view-destroy path removes a view's nodes from wherever ITS OWN bookkeeping thinks
|
|
12
|
+
// they live, not from wherever a node was manually moved to, so a raw Renderer2 move would desync
|
|
13
|
+
// Angular's internals from the retained tree.
|
|
16
14
|
//
|
|
17
|
-
// PortalDirective is a STRUCTURAL directive (`*portal="overlayHost"`), not a component
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// injects that template's own TemplateRef into the directive automatically.
|
|
15
|
+
// PortalDirective is a STRUCTURAL directive (`*portal="overlayHost"`), not a component taking a
|
|
16
|
+
// separate `<ng-template>` + `[content]` binding — that two-step reads as foreign next to
|
|
17
|
+
// `*ngIf`/`*ngFor`/`*ngTemplateOutlet`. `*portal="x"` desugars the same way `*ngIf` does: Angular
|
|
18
|
+
// wraps the host element in an `<ng-template>` and injects that template's own TemplateRef into
|
|
19
|
+
// the directive automatically.
|
|
23
20
|
//
|
|
24
21
|
// The safe, fully-public-API mechanism: create the embedded view DIRECTLY inside a
|
|
25
22
|
// ViewContainerRef anchored at the destination, so there is nothing to move at all. That
|
|
26
|
-
// ViewContainerRef
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
// `
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
// one is Angular's own template compiler resolving a template reference variable, so
|
|
34
|
-
// `strictTemplates` rejects anything else at compile time and there is nothing left to guard
|
|
35
|
-
// against at runtime.
|
|
23
|
+
// ViewContainerRef comes from `PortalOutletDirective`, a marker placed on the target host
|
|
24
|
+
// (`<View portalOutlet #overlayHost="portalOutlet">`) purely to expose its ViewContainerRef, the
|
|
25
|
+
// same export-as-template-variable idiom `#form="ngForm"` uses. This also replaces the
|
|
26
|
+
// `isSymbioteNode` runtime guard React/Vue need (there `to` is an arbitrary JS value until
|
|
27
|
+
// validated): here `to` is typed as `PortalOutletDirective` — the only way to construct one is
|
|
28
|
+
// Angular's own template compiler resolving a template reference variable, so `strictTemplates`
|
|
29
|
+
// rejects anything else at compile time and there is nothing left to guard at runtime.
|
|
36
30
|
|
|
37
31
|
import {
|
|
38
32
|
Directive,
|
|
@@ -48,7 +42,11 @@ import {
|
|
|
48
42
|
/** Marks the destination for `*portal` — place it on whichever already-mounted host should
|
|
49
43
|
* paint the portaled content (e.g. a persistent overlay-host View near the app root), then
|
|
50
44
|
* export it to a template variable and pass that variable as `*portal`'s target. */
|
|
51
|
-
@Directive({
|
|
45
|
+
@Directive({
|
|
46
|
+
selector: '[portalOutlet]',
|
|
47
|
+
standalone: true,
|
|
48
|
+
exportAs: 'portalOutlet',
|
|
49
|
+
})
|
|
52
50
|
export class PortalOutletDirective {
|
|
53
51
|
readonly viewContainerRef = inject(ViewContainerRef);
|
|
54
52
|
}
|
|
@@ -65,7 +63,9 @@ export class PortalDirective implements OnChanges, OnDestroy {
|
|
|
65
63
|
|
|
66
64
|
ngOnChanges(): void {
|
|
67
65
|
this.viewRef?.destroy();
|
|
68
|
-
this.viewRef = this.portal.viewContainerRef.createEmbeddedView(
|
|
66
|
+
this.viewRef = this.portal.viewContainerRef.createEmbeddedView(
|
|
67
|
+
this.templateRef,
|
|
68
|
+
);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
ngOnDestroy(): void {
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
// createTunnel for @symbiote-native/angular — the Angular twin of the React/Vue cross-surface tunnel
|
|
2
2
|
// (adapters/react/src/create-tunnel.tsx, adapters/vue/src/create-tunnel.ts — read their
|
|
3
|
-
// headers for the
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// share a surface or not.
|
|
3
|
+
// headers for the "why not just extend the portal across surfaces" rationale; same prior art:
|
|
4
|
+
// pmndrs/tunnel-rat, facebook/react#17147). `TunnelOut` lives in whichever component should PAINT
|
|
5
|
+
// the content; its own read of the shared store drives that surface's own normal render cycle —
|
|
6
|
+
// no cross-surface reach-in, works whether TunnelIn and TunnelOut share a surface or not.
|
|
8
7
|
//
|
|
9
|
-
// Angular cannot mirror React's/Vue's shape verbatim: both
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// Metro/Hermes (see modules/animated/create-animated-component.ts's header for the same
|
|
8
|
+
// Angular cannot mirror React's/Vue's shape verbatim: both build a FRESH `In`/`Out` pair per
|
|
9
|
+
// `createTunnel()` call, and Angular components can't be synthesized at runtime — no JIT compiler
|
|
10
|
+
// under Metro/Hermes (see modules/animated/create-animated-component.ts's header for the same
|
|
13
11
|
// constraint). So here `createTunnel()` returns only a plain reactive STORE (a signal);
|
|
14
12
|
// `TunnelInDirective` and `TunnelOut` are ONE static, pre-authored, AOT-compilable pair,
|
|
15
|
-
// parameterized by that store through an input —
|
|
16
|
-
//
|
|
13
|
+
// parameterized by that store through an input — the relationship `VListOutletDirective` has to
|
|
14
|
+
// the per-cell template it stamps, generalized to an open-ended, changing SET of templates.
|
|
17
15
|
//
|
|
18
|
-
// TunnelInDirective is a STRUCTURAL directive (`*tunnelIn="overlayTunnel"`),
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// same shape as Angular's own `<router-outlet>`, not content that needs a structural directive.
|
|
16
|
+
// TunnelInDirective is a STRUCTURAL directive (`*tunnelIn="overlayTunnel"`), matching `*portal`
|
|
17
|
+
// (see create-portal.ts's header for why that reads as native Angular). `TunnelOut` stays a plain
|
|
18
|
+
// component (`<tunnel-out>`) — a rendering SLOT, the same shape as Angular's own
|
|
19
|
+
// `<router-outlet>`, not content that needs a structural directive.
|
|
23
20
|
//
|
|
24
21
|
// App code stays fully declarative — no ViewContainerRef/imperative rendering — by putting
|
|
25
22
|
// `*tunnelIn` directly on the portable content, the same way `*ngIf` sits directly on an
|
|
@@ -112,7 +109,9 @@ export class TunnelOut implements OnInit, OnDestroy {
|
|
|
112
109
|
private stopEffect: (() => void) | undefined;
|
|
113
110
|
|
|
114
111
|
ngOnInit(): void {
|
|
115
|
-
const ref = effect(() => this.sync(this.tunnel.entries()), {
|
|
112
|
+
const ref = effect(() => this.sync(this.tunnel.entries()), {
|
|
113
|
+
injector: this.injector,
|
|
114
|
+
});
|
|
116
115
|
this.stopEffect = () => ref.destroy();
|
|
117
116
|
}
|
|
118
117
|
|
|
@@ -15,7 +15,10 @@ import {
|
|
|
15
15
|
type OnDestroy,
|
|
16
16
|
type SimpleChanges,
|
|
17
17
|
} from '@angular/core';
|
|
18
|
-
import type {
|
|
18
|
+
import type {
|
|
19
|
+
IDescriptor,
|
|
20
|
+
IDescriptorChild,
|
|
21
|
+
} from '@symbiote-native/components';
|
|
19
22
|
|
|
20
23
|
type IRenderedChild = IRenderedElement | IRenderedText;
|
|
21
24
|
|
|
@@ -43,7 +46,8 @@ export class DescriptorOutlet implements OnChanges, OnDestroy {
|
|
|
43
46
|
@Input({ required: true }) node!: IDescriptor;
|
|
44
47
|
|
|
45
48
|
private readonly renderer = inject(Renderer2);
|
|
46
|
-
private readonly hostNode =
|
|
49
|
+
private readonly hostNode =
|
|
50
|
+
inject<ElementRef<unknown>>(ElementRef).nativeElement;
|
|
47
51
|
private rendered: IRenderedElement | undefined;
|
|
48
52
|
|
|
49
53
|
ngOnChanges(changes: SimpleChanges): void {
|
|
@@ -57,7 +61,10 @@ export class DescriptorOutlet implements OnChanges, OnDestroy {
|
|
|
57
61
|
this.rendered = undefined;
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
private patchRoot(
|
|
64
|
+
private patchRoot(
|
|
65
|
+
rendered: IRenderedElement | undefined,
|
|
66
|
+
next: IDescriptor,
|
|
67
|
+
): IRenderedElement {
|
|
61
68
|
if (rendered === undefined) {
|
|
62
69
|
const created = this.createElement(next);
|
|
63
70
|
this.renderer.appendChild(this.hostNode, created.node);
|
|
@@ -67,7 +74,9 @@ export class DescriptorOutlet implements OnChanges, OnDestroy {
|
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
private createChild(child: IDescriptorChild): IRenderedChild {
|
|
70
|
-
return typeof child === 'string'
|
|
77
|
+
return typeof child === 'string'
|
|
78
|
+
? this.createText(child)
|
|
79
|
+
: this.createElement(child);
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
private createText(value: string): IRenderedText {
|
|
@@ -127,12 +136,19 @@ export class DescriptorOutlet implements OnChanges, OnDestroy {
|
|
|
127
136
|
}
|
|
128
137
|
|
|
129
138
|
this.patchProps(rendered, next.props);
|
|
130
|
-
rendered.children = this.patchChildren(
|
|
139
|
+
rendered.children = this.patchChildren(
|
|
140
|
+
rendered.node,
|
|
141
|
+
rendered.children,
|
|
142
|
+
next.children,
|
|
143
|
+
);
|
|
131
144
|
rendered.descriptor = next;
|
|
132
145
|
return rendered;
|
|
133
146
|
}
|
|
134
147
|
|
|
135
|
-
private patchProps(
|
|
148
|
+
private patchProps(
|
|
149
|
+
rendered: IRenderedElement,
|
|
150
|
+
nextProps: Record<string, unknown>,
|
|
151
|
+
): void {
|
|
136
152
|
const prevProps = rendered.props;
|
|
137
153
|
for (const key of Object.keys(prevProps)) {
|
|
138
154
|
if (!(key in nextProps)) {
|
|
@@ -173,13 +189,18 @@ export class DescriptorOutlet implements OnChanges, OnDestroy {
|
|
|
173
189
|
|
|
174
190
|
for (let i = common; i < renderedChildren.length; i++) {
|
|
175
191
|
const rendered = renderedChildren[i];
|
|
176
|
-
if (rendered !== undefined)
|
|
192
|
+
if (rendered !== undefined)
|
|
193
|
+
this.renderer.removeChild(parent, rendered.node);
|
|
177
194
|
}
|
|
178
195
|
|
|
179
196
|
return nextRendered;
|
|
180
197
|
}
|
|
181
198
|
|
|
182
|
-
private replaceChild(
|
|
199
|
+
private replaceChild(
|
|
200
|
+
parent: unknown,
|
|
201
|
+
oldChild: unknown,
|
|
202
|
+
newChild: unknown,
|
|
203
|
+
): void {
|
|
183
204
|
this.renderer.insertBefore(parent, newChild, oldChild);
|
|
184
205
|
this.renderer.removeChild(parent, oldChild);
|
|
185
206
|
}
|