@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,12 +1,12 @@
|
|
|
1
1
|
// RefreshControl, the Angular lifecycle half. On iOS this is the PullToRefreshView Fabric node that
|
|
2
2
|
// lives INSIDE a ScrollView (a childless sibling before the content container); on Android it is
|
|
3
|
-
// AndroidSwipeRefreshLayout and WRAPS the scroll view, receiving it through <ng-content>.
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
3
|
+
// AndroidSwipeRefreshLayout and WRAPS the scroll view, receiving it through <ng-content>. There is
|
|
4
|
+
// no JS-side platform renaming and no shared render fn — every prop forwards straight to the
|
|
5
|
+
// native node, which reads what it understands and ignores the rest, so Android-only and iOS-only
|
|
6
|
+
// prop families ride down harmlessly on both. This folds aria/role through the shared
|
|
7
|
+
// resolveAccessibilityProps and maps the native props + a11y + onRefresh onto the
|
|
8
|
+
// symbiote-refresh-control host, children via <ng-content>. One composed component covers both
|
|
9
|
+
// platforms, so this stays a flat single file.
|
|
10
10
|
//
|
|
11
11
|
// `refreshing` is a controlled prop: the parent owns it and pushes it down each commit; native
|
|
12
12
|
// reports the gesture via the direct `topRefresh` event, which the engine routes to the host's
|
|
@@ -16,13 +16,16 @@ import {
|
|
|
16
16
|
CUSTOM_ELEMENTS_SCHEMA,
|
|
17
17
|
ChangeDetectionStrategy,
|
|
18
18
|
Component,
|
|
19
|
+
computed,
|
|
19
20
|
ElementRef,
|
|
20
21
|
EventEmitter,
|
|
21
22
|
inject,
|
|
22
23
|
Input,
|
|
23
24
|
Output,
|
|
25
|
+
signal,
|
|
24
26
|
ViewChild,
|
|
25
27
|
type AfterViewInit,
|
|
28
|
+
type DoCheck,
|
|
26
29
|
type OnChanges,
|
|
27
30
|
type OnInit,
|
|
28
31
|
type SimpleChanges,
|
|
@@ -42,7 +45,12 @@ import {
|
|
|
42
45
|
type ISymbioteEvent,
|
|
43
46
|
type IViewStyle,
|
|
44
47
|
} from '@symbiote-native/engine';
|
|
45
|
-
import {
|
|
48
|
+
import {
|
|
49
|
+
anchorHostStyle,
|
|
50
|
+
RefreshControlHost,
|
|
51
|
+
SymbioteHostPropsDirective,
|
|
52
|
+
SymbioteStyleInputDirective,
|
|
53
|
+
} from '../../primitives';
|
|
46
54
|
|
|
47
55
|
// Record<string, unknown> already tolerates `style` holding the [anchorHostStyle, this.style]
|
|
48
56
|
// array anchorHostStyle's merge produces (see hostProps below) — no widening needed.
|
|
@@ -52,7 +60,8 @@ type IHostProps = Record<string, unknown>;
|
|
|
52
60
|
// via <ng-content>), declared per-adapter over the shared accessibility base since the framework-specific
|
|
53
61
|
// children slot keeps it from being fully shared across adapters. Read the React reference for the
|
|
54
62
|
// native prop names.
|
|
55
|
-
export interface IAngularRefreshControlProps
|
|
63
|
+
export interface IAngularRefreshControlProps
|
|
64
|
+
extends IAccessibilityProps, IAriaProps {
|
|
56
65
|
refreshing: boolean;
|
|
57
66
|
// RN's onRefresh is `() => void | Promise<void>`, the handler may be async; the promise is
|
|
58
67
|
// fire-and-forget (native already starts refreshing on the gesture).
|
|
@@ -89,13 +98,16 @@ export type IAngularRefreshControlInputs = Omit<
|
|
|
89
98
|
@Component({
|
|
90
99
|
selector: 'RefreshControl',
|
|
91
100
|
standalone: true,
|
|
101
|
+
hostDirectives: [
|
|
102
|
+
{ directive: SymbioteStyleInputDirective, inputs: ['style'] },
|
|
103
|
+
],
|
|
92
104
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
93
105
|
imports: [RefreshControlHost, SymbioteHostPropsDirective],
|
|
94
106
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
95
107
|
template: `
|
|
96
108
|
<symbiote-refresh-control
|
|
97
109
|
#host
|
|
98
|
-
[symbioteHostProps]="hostProps"
|
|
110
|
+
[symbioteHostProps]="hostProps()"
|
|
99
111
|
(refresh)="handleRefresh()"
|
|
100
112
|
(accessibilityAction)="emit(accessibilityAction, $event)"
|
|
101
113
|
(accessibilityTap)="emit(accessibilityTap, $event)"
|
|
@@ -107,7 +119,12 @@ export type IAngularRefreshControlInputs = Omit<
|
|
|
107
119
|
`,
|
|
108
120
|
})
|
|
109
121
|
export class RefreshControl
|
|
110
|
-
implements
|
|
122
|
+
implements
|
|
123
|
+
IAngularRefreshControlInputs,
|
|
124
|
+
OnInit,
|
|
125
|
+
OnChanges,
|
|
126
|
+
DoCheck,
|
|
127
|
+
AfterViewInit
|
|
111
128
|
{
|
|
112
129
|
// Controlled prop the parent owns; required to match the React reference surface.
|
|
113
130
|
@Input({ required: true }) refreshing!: boolean;
|
|
@@ -133,8 +150,10 @@ export class RefreshControl
|
|
|
133
150
|
@Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
|
|
134
151
|
@Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
|
|
135
152
|
@Input() accessibilityLabelledBy?: string | string[];
|
|
136
|
-
@Input()
|
|
137
|
-
|
|
153
|
+
@Input()
|
|
154
|
+
importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
|
|
155
|
+
@Input()
|
|
156
|
+
accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
|
|
138
157
|
@Input() screenReaderFocusable?: boolean;
|
|
139
158
|
@Input() accessibilityViewIsModal?: boolean;
|
|
140
159
|
@Input() accessibilityElementsHidden?: boolean;
|
|
@@ -175,6 +194,18 @@ export class RefreshControl
|
|
|
175
194
|
private lastNativeRefreshing = false;
|
|
176
195
|
private refreshNativeNode: unknown;
|
|
177
196
|
|
|
197
|
+
// Bridges the non-reactive @Input fields `hostProps` reads into the reactive graph, so it can
|
|
198
|
+
// memoize. Plain fields read inside a computed() are UNTRACKED - something must signal "a
|
|
199
|
+
// dependency changed" or the bag goes stale. Signal inputs would do this natively, but `input()`
|
|
200
|
+
// is visible only to the AOT compiler and this package's unit suite runs on JIT (see the
|
|
201
|
+
// `angular-adapter-change-detection` skill, §6); `signal()`/`computed()` are plain runtime APIs.
|
|
202
|
+
// Safe here because `refreshing` is a CONTROLLED @Input - the parent owns it, nothing in this
|
|
203
|
+
// class assigns it. The internal `lastNativeRefreshing` / `refreshNativeNode` fields drive the
|
|
204
|
+
// native handshake only; neither is read by the bag, so neither may bump this.
|
|
205
|
+
private readonly hostPropsRevision = signal(0);
|
|
206
|
+
// What the anchor's class-derived style was when the bag was last built (identity, not value).
|
|
207
|
+
private lastAnchorStyle: unknown;
|
|
208
|
+
|
|
178
209
|
ngOnInit(): void {
|
|
179
210
|
dlog('RefreshControl -> PullToRefreshView');
|
|
180
211
|
dlog(`RefreshControl refreshing=${String(this.refreshing)}`);
|
|
@@ -188,13 +219,18 @@ export class RefreshControl
|
|
|
188
219
|
}
|
|
189
220
|
|
|
190
221
|
ngOnChanges(changes: SimpleChanges): void {
|
|
222
|
+
// Before the `refreshing`-only early-return below: this is the single moment Angular has
|
|
223
|
+
// finished writing every changed @Input, and `hostProps` depends on the whole input surface.
|
|
224
|
+
this.hostPropsRevision.update(revision => revision + 1);
|
|
191
225
|
const refreshing = changes.refreshing;
|
|
192
226
|
if (refreshing === undefined) return;
|
|
193
227
|
if (refreshing.firstChange) {
|
|
194
228
|
this.lastNativeRefreshing = this.refreshing;
|
|
195
229
|
return;
|
|
196
230
|
}
|
|
197
|
-
this.syncNativeRefreshing(
|
|
231
|
+
this.syncNativeRefreshing(
|
|
232
|
+
this.refreshNativeNode ?? this.host?.nativeElement,
|
|
233
|
+
);
|
|
198
234
|
}
|
|
199
235
|
|
|
200
236
|
// Native starts the spinner before JS runs. Mirror RN's RefreshControl controlled-component
|
|
@@ -220,11 +256,29 @@ export class RefreshControl
|
|
|
220
256
|
if (isSymbioteEvent(event)) emitter.emit(event);
|
|
221
257
|
}
|
|
222
258
|
|
|
259
|
+
// The anchor's class-derived style is NOT an @Input: `class="..."`/`[ngClass]` at the use site
|
|
260
|
+
// resolves through the renderer's addClass onto this component's anchor host (see
|
|
261
|
+
// anchorHostStyle's doc comment), so it never shows up in SimpleChanges and ngOnChanges alone
|
|
262
|
+
// would leave a later class toggle stranded. ngDoCheck runs at exactly the cadence the old
|
|
263
|
+
// getter was re-read, and bumps only on a real identity change.
|
|
264
|
+
ngDoCheck(): void {
|
|
265
|
+
const anchorStyle = anchorHostStyle(this.elementRef);
|
|
266
|
+
if (anchorStyle === this.lastAnchorStyle) return;
|
|
267
|
+
this.lastAnchorStyle = anchorStyle;
|
|
268
|
+
this.hostPropsRevision.update(revision => revision + 1);
|
|
269
|
+
}
|
|
270
|
+
|
|
223
271
|
// The full native + a11y prop bag applied onto the host in one shot via
|
|
224
272
|
// [symbioteHostProps], instead of enumerating each key as its own template binding. The
|
|
225
273
|
// anchor's class-derived style goes FIRST, this component's own explicit `style` @Input SECOND
|
|
226
274
|
// — flattenStyle's later-wins collapse keeps an explicit [style] winning over its ambient class.
|
|
227
|
-
|
|
275
|
+
//
|
|
276
|
+
// A computed(), not a getter: Angular re-reads a template getter on every refresh of this view
|
|
277
|
+
// and `[symbioteHostProps]` compares by REFERENCE, so a freshly rebuilt (but identical) bag
|
|
278
|
+
// re-pushes every key through renderer.setProperty -> the engine's prop routing. A pull gesture
|
|
279
|
+
// dirties this view through its own `(refresh)` binding, which is exactly when that waste hit.
|
|
280
|
+
readonly hostProps = computed<IHostProps>(() => {
|
|
281
|
+
this.hostPropsRevision();
|
|
228
282
|
return {
|
|
229
283
|
refreshing: this.refreshing,
|
|
230
284
|
tintColor: this.tintColor,
|
|
@@ -241,7 +295,7 @@ export class RefreshControl
|
|
|
241
295
|
accessible: this.accessible,
|
|
242
296
|
...this.folded,
|
|
243
297
|
};
|
|
244
|
-
}
|
|
298
|
+
});
|
|
245
299
|
|
|
246
300
|
// Fold the web aria-*/role aliases into the canonical accessibility* props once per render, so the
|
|
247
301
|
// host node never sees an aria-* key (native ignores them) — the shared transform every adapter runs.
|
|
@@ -261,8 +315,10 @@ export class RefreshControl
|
|
|
261
315
|
accessibilityElementsHidden: this.accessibilityElementsHidden,
|
|
262
316
|
accessibilityIgnoresInvertColors: this.accessibilityIgnoresInvertColors,
|
|
263
317
|
accessibilityLanguage: this.accessibilityLanguage,
|
|
264
|
-
accessibilityRespondsToUserInteraction:
|
|
265
|
-
|
|
318
|
+
accessibilityRespondsToUserInteraction:
|
|
319
|
+
this.accessibilityRespondsToUserInteraction,
|
|
320
|
+
accessibilityShowsLargeContentViewer:
|
|
321
|
+
this.accessibilityShowsLargeContentViewer,
|
|
266
322
|
accessibilityLargeContentTitle: this.accessibilityLargeContentTitle,
|
|
267
323
|
role: this.role,
|
|
268
324
|
'aria-label': this.ariaLabel,
|
|
@@ -10,11 +10,15 @@ import {
|
|
|
10
10
|
CUSTOM_ELEMENTS_SCHEMA,
|
|
11
11
|
ChangeDetectionStrategy,
|
|
12
12
|
Component,
|
|
13
|
+
computed,
|
|
13
14
|
ElementRef,
|
|
14
15
|
EventEmitter,
|
|
15
16
|
inject,
|
|
16
17
|
Input,
|
|
17
18
|
Output,
|
|
19
|
+
signal,
|
|
20
|
+
type DoCheck,
|
|
21
|
+
type OnChanges,
|
|
18
22
|
} from '@angular/core';
|
|
19
23
|
import {
|
|
20
24
|
resolveAccessibilityProps,
|
|
@@ -28,12 +32,18 @@ import {
|
|
|
28
32
|
type ISymbioteEvent,
|
|
29
33
|
type IViewStyle,
|
|
30
34
|
} from '@symbiote-native/engine';
|
|
31
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
anchorHostStyle,
|
|
37
|
+
SafeAreaViewHost,
|
|
38
|
+
SymbioteHostPropsDirective,
|
|
39
|
+
SymbioteStyleInputDirective,
|
|
40
|
+
} from '../../primitives';
|
|
32
41
|
|
|
33
42
|
// Mirrors React's ISafeAreaViewProps minus children (Angular takes children via <ng-content>),
|
|
34
43
|
// declared per-adapter over the shared accessibility base since the framework-specific children
|
|
35
44
|
// slot keeps it from being fully shared across adapters.
|
|
36
|
-
export interface IAngularSafeAreaViewProps
|
|
45
|
+
export interface IAngularSafeAreaViewProps
|
|
46
|
+
extends IAccessibilityProps, IAriaProps {
|
|
37
47
|
style?: IStyleProp<IViewStyle>;
|
|
38
48
|
onLayout?: (event: ISymbioteEvent) => void;
|
|
39
49
|
}
|
|
@@ -53,12 +63,15 @@ export type IAngularSafeAreaViewInputs = Omit<
|
|
|
53
63
|
@Component({
|
|
54
64
|
selector: 'SafeAreaView',
|
|
55
65
|
standalone: true,
|
|
66
|
+
hostDirectives: [
|
|
67
|
+
{ directive: SymbioteStyleInputDirective, inputs: ['style'] },
|
|
68
|
+
],
|
|
56
69
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
57
70
|
imports: [SafeAreaViewHost, SymbioteHostPropsDirective],
|
|
58
71
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
59
72
|
template: `
|
|
60
73
|
<symbiote-safe-area-view
|
|
61
|
-
[symbioteHostProps]="hostProps"
|
|
74
|
+
[symbioteHostProps]="hostProps()"
|
|
62
75
|
(accessibilityAction)="emit(accessibilityAction, $event)"
|
|
63
76
|
(accessibilityTap)="emit(accessibilityTap, $event)"
|
|
64
77
|
(magicTap)="emit(magicTap, $event)"
|
|
@@ -69,7 +82,9 @@ export type IAngularSafeAreaViewInputs = Omit<
|
|
|
69
82
|
</symbiote-safe-area-view>
|
|
70
83
|
`,
|
|
71
84
|
})
|
|
72
|
-
export class SafeAreaView
|
|
85
|
+
export class SafeAreaView
|
|
86
|
+
implements IAngularSafeAreaViewInputs, OnChanges, DoCheck
|
|
87
|
+
{
|
|
73
88
|
@Input() style?: IStyleProp<IViewStyle>;
|
|
74
89
|
// Real @Output()s, not `[onX]="…"` callbacks. Safe to name `layout` the same as the native
|
|
75
90
|
// `layout` event fired inside this component's own template — the engine's bubble() treats
|
|
@@ -89,8 +104,10 @@ export class SafeAreaView implements IAngularSafeAreaViewInputs {
|
|
|
89
104
|
@Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
|
|
90
105
|
@Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
|
|
91
106
|
@Input() accessibilityLabelledBy?: string | string[];
|
|
92
|
-
@Input()
|
|
93
|
-
|
|
107
|
+
@Input()
|
|
108
|
+
importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
|
|
109
|
+
@Input()
|
|
110
|
+
accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
|
|
94
111
|
@Input() screenReaderFocusable?: boolean;
|
|
95
112
|
@Input() accessibilityViewIsModal?: boolean;
|
|
96
113
|
@Input() accessibilityElementsHidden?: boolean;
|
|
@@ -127,6 +144,35 @@ export class SafeAreaView implements IAngularSafeAreaViewInputs {
|
|
|
127
144
|
if (isSymbioteEvent(event)) emitter.emit(event);
|
|
128
145
|
}
|
|
129
146
|
|
|
147
|
+
// Bridges the non-reactive fields `hostProps` reads into the reactive graph, so it can memoize.
|
|
148
|
+
// Plain fields read inside a computed() are UNTRACKED - something must signal "a dependency
|
|
149
|
+
// changed" or the bag goes stale. Signal inputs would do this natively, but `input()` is visible
|
|
150
|
+
// only to the AOT compiler and this package's unit suite runs on JIT (see the
|
|
151
|
+
// `angular-adapter-change-detection` skill, §6); `signal()`/`computed()` are plain runtime APIs.
|
|
152
|
+
// TWO bump sites, both required - see ngOnChanges and ngDoCheck below.
|
|
153
|
+
private readonly hostPropsRevision = signal(0);
|
|
154
|
+
// What the anchor's class-derived style was when the bag was last built (identity, not value).
|
|
155
|
+
private lastAnchorStyle: unknown;
|
|
156
|
+
|
|
157
|
+
ngOnChanges(): void {
|
|
158
|
+
// The single moment Angular has finished writing every changed @Input for this pass.
|
|
159
|
+
this.hostPropsRevision.update(revision => revision + 1);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// The anchor's class-derived style is NOT an @Input: `class="..."`/`[ngClass]` at the use site
|
|
163
|
+
// resolves through the renderer's addClass onto this component's anchor host (see
|
|
164
|
+
// anchorHostStyle's doc comment), so it never shows up in SimpleChanges - ngOnChanges alone
|
|
165
|
+
// would strand a class toggled after mount (regression-covered by safe-area-view.test.ts's
|
|
166
|
+
// class-toggle case, which fails the moment this hook stops bumping). ngDoCheck runs at exactly
|
|
167
|
+
// the cadence the old getter was re-read, and bumps only on a real identity change, so an
|
|
168
|
+
// unchanged anchor still costs nothing.
|
|
169
|
+
ngDoCheck(): void {
|
|
170
|
+
const anchorStyle = anchorHostStyle(this.elementRef);
|
|
171
|
+
if (anchorStyle === this.lastAnchorStyle) return;
|
|
172
|
+
this.lastAnchorStyle = anchorStyle;
|
|
173
|
+
this.hostPropsRevision.update(revision => revision + 1);
|
|
174
|
+
}
|
|
175
|
+
|
|
130
176
|
// Folds style/testID/nativeID/accessible alongside the accessibility*/aria-*/role surface into
|
|
131
177
|
// one bag for [symbioteHostProps] — resolveAccessibilityProps takes the whole props object (not
|
|
132
178
|
// just the accessibility slice) and returns it with aria-*/role folded into accessibility*, so
|
|
@@ -134,7 +180,13 @@ export class SafeAreaView implements IAngularSafeAreaViewInputs {
|
|
|
134
180
|
// SafeAreaView runs over its whole `rawProps`. The anchor's class-derived style goes FIRST, this
|
|
135
181
|
// component's own explicit `style` @Input SECOND — flattenStyle's later-wins collapse keeps an
|
|
136
182
|
// explicit [style] winning over its ambient class.
|
|
137
|
-
|
|
183
|
+
//
|
|
184
|
+
// A computed(), not a getter: Angular re-reads a template getter on every refresh of this view
|
|
185
|
+
// and `[symbioteHostProps]` compares by REFERENCE, so a freshly rebuilt (but identical) bag
|
|
186
|
+
// re-pushes every key through renderer.setProperty -> the engine's prop routing. Memoized, an
|
|
187
|
+
// a11y/layout event that only dirties this view costs nothing.
|
|
188
|
+
readonly hostProps = computed<Record<string, unknown>>(() => {
|
|
189
|
+
this.hostPropsRevision();
|
|
138
190
|
return resolveAccessibilityProps({
|
|
139
191
|
style: [anchorHostStyle(this.elementRef), this.style],
|
|
140
192
|
testID: this.testID,
|
|
@@ -154,8 +206,10 @@ export class SafeAreaView implements IAngularSafeAreaViewInputs {
|
|
|
154
206
|
accessibilityElementsHidden: this.accessibilityElementsHidden,
|
|
155
207
|
accessibilityIgnoresInvertColors: this.accessibilityIgnoresInvertColors,
|
|
156
208
|
accessibilityLanguage: this.accessibilityLanguage,
|
|
157
|
-
accessibilityRespondsToUserInteraction:
|
|
158
|
-
|
|
209
|
+
accessibilityRespondsToUserInteraction:
|
|
210
|
+
this.accessibilityRespondsToUserInteraction,
|
|
211
|
+
accessibilityShowsLargeContentViewer:
|
|
212
|
+
this.accessibilityShowsLargeContentViewer,
|
|
159
213
|
accessibilityLargeContentTitle: this.accessibilityLargeContentTitle,
|
|
160
214
|
role: this.role,
|
|
161
215
|
'aria-label': this.ariaLabel,
|
|
@@ -173,5 +227,5 @@ export class SafeAreaView implements IAngularSafeAreaViewInputs {
|
|
|
173
227
|
'aria-valuenow': this.ariaValueNow,
|
|
174
228
|
'aria-valuetext': this.ariaValueText,
|
|
175
229
|
});
|
|
176
|
-
}
|
|
230
|
+
});
|
|
177
231
|
}
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
// ScrollView on Android. An Android ScrollView accepts only ONE child, so a
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
1
|
+
// ScrollView on Android. An Android ScrollView accepts only ONE child, so a RefreshControl can't
|
|
2
|
+
// be a sibling of the content the way iOS allows ("addViewAt: failed to insert view ... at index
|
|
3
|
+
// 1"). RN solves this by having the RefreshControl (AndroidSwipeRefreshLayout) WRAP the scroll
|
|
4
|
+
// view (cloneElement(refreshControl, {style}, scrollView)). Angular mirrors that shape by querying
|
|
5
|
+
// a projected <RefreshControl>, re-rendering its native prop surface as the outer wrapper, and
|
|
6
|
+
// projecting every non-RefreshControl child into the inner scroll content.
|
|
7
7
|
//
|
|
8
|
-
// Android
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// four axis x refresh combos, plus a runtime axis switch) and `flat-list-scroll-containment.test.ts`.
|
|
8
|
+
// Android needs a different Fabric view per axis for both the outer scroll container
|
|
9
|
+
// (RCTScrollView is vertical-only; AndroidHorizontalScrollView is a dedicated ViewManager) and the
|
|
10
|
+
// inner content view (horizontal content is AndroidHorizontalScrollContentView, with its own
|
|
11
|
+
// ShadowNode::layout() override) — but Angular only reliably projects into a component's
|
|
12
|
+
// LAST-declared <ng-content> when 2+ DISTINCT declarations exist (angular/angular#22972), which an
|
|
13
|
+
// earlier 4-call-site template (one <ng-content> per axis x refresh-control branch) tripped. Fix:
|
|
14
|
+
// exactly ONE `<ng-content>` textually, inside a single top-level `<ng-template>`, re-instantiated
|
|
15
|
+
// into whichever branch is active via a local template-outlet directive
|
|
16
|
+
// (SymbioteTemplateOutletDirective below, `@angular/common`-free per this adapter's dependency
|
|
17
|
+
// policy — see package.json). Only one branch is ever live, so the declaration count stays at one
|
|
18
|
+
// and the "last one wins" limitation never triggers. Covered by
|
|
19
|
+
// `android-scroll-view-axis-projection.test.ts` and `flat-list-scroll-containment.test.ts`.
|
|
21
20
|
//
|
|
22
21
|
// Metro picks this on an Android host; no Platform.OS read.
|
|
23
22
|
|
|
@@ -26,7 +25,6 @@ import {
|
|
|
26
25
|
ChangeDetectionStrategy,
|
|
27
26
|
Component,
|
|
28
27
|
Directive,
|
|
29
|
-
ElementRef,
|
|
30
28
|
Input,
|
|
31
29
|
TemplateRef,
|
|
32
30
|
ViewContainerRef,
|
|
@@ -37,15 +35,19 @@ import {
|
|
|
37
35
|
} from '@angular/core';
|
|
38
36
|
import type { IStyleProp, IViewStyle } from '@symbiote-native/engine';
|
|
39
37
|
import {
|
|
40
|
-
anchorHostStyle,
|
|
41
|
-
HorizontalScrollView,
|
|
42
38
|
HorizontalScrollContentView,
|
|
39
|
+
HorizontalScrollView,
|
|
43
40
|
RefreshControlHost,
|
|
44
41
|
ScrollContentView,
|
|
45
42
|
ScrollViewHost,
|
|
46
43
|
SymbioteHostPropsDirective,
|
|
44
|
+
SymbioteStyleInputDirective,
|
|
47
45
|
} from '../../primitives';
|
|
48
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
ScrollViewBase,
|
|
48
|
+
ScrollViewProjectionDirective,
|
|
49
|
+
SCROLL_VIEW_INPUTS,
|
|
50
|
+
} from './shared';
|
|
49
51
|
export type { IAngularScrollViewProps, IScrollViewHandle } from './shared';
|
|
50
52
|
|
|
51
53
|
// Minimal local twin of `@angular/common`'s NgTemplateOutlet (this adapter deliberately has no
|
|
@@ -68,7 +70,9 @@ export class SymbioteTemplateOutletDirective implements OnChanges, OnDestroy {
|
|
|
68
70
|
this.viewRef = undefined;
|
|
69
71
|
}
|
|
70
72
|
if (this.symbioteTemplateOutlet !== null) {
|
|
71
|
-
this.viewRef = this.viewContainerRef.createEmbeddedView(
|
|
73
|
+
this.viewRef = this.viewContainerRef.createEmbeddedView(
|
|
74
|
+
this.symbioteTemplateOutlet,
|
|
75
|
+
);
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
78
|
|
|
@@ -89,6 +93,9 @@ function asStyle(value: unknown): IStyleProp<IViewStyle> | undefined {
|
|
|
89
93
|
@Component({
|
|
90
94
|
selector: 'ScrollView',
|
|
91
95
|
standalone: true,
|
|
96
|
+
hostDirectives: [
|
|
97
|
+
{ directive: SymbioteStyleInputDirective, inputs: ['style'] },
|
|
98
|
+
],
|
|
92
99
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
93
100
|
imports: [
|
|
94
101
|
ScrollViewHost,
|
|
@@ -115,23 +122,30 @@ function asStyle(value: unknown): IStyleProp<IViewStyle> | undefined {
|
|
|
115
122
|
>
|
|
116
123
|
<symbiote-horizontal-scroll-view
|
|
117
124
|
#host="symbioteHost"
|
|
118
|
-
[symbioteHostProps]="androidWrappedScrollProps"
|
|
125
|
+
[symbioteHostProps]="androidWrappedScrollProps()"
|
|
119
126
|
>
|
|
120
127
|
<symbiote-horizontal-scroll-content
|
|
121
|
-
[symbioteHostProps]="contentProps"
|
|
128
|
+
[symbioteHostProps]="contentProps()"
|
|
122
129
|
[symbioteScrollViewProjection]="projectionController"
|
|
123
130
|
>
|
|
124
|
-
<ng-container
|
|
131
|
+
<ng-container
|
|
132
|
+
[symbioteTemplateOutlet]="sharedContent"
|
|
133
|
+
></ng-container>
|
|
125
134
|
</symbiote-horizontal-scroll-content>
|
|
126
135
|
</symbiote-horizontal-scroll-view>
|
|
127
136
|
</symbiote-refresh-control>
|
|
128
137
|
} @else {
|
|
129
|
-
<symbiote-horizontal-scroll-view
|
|
138
|
+
<symbiote-horizontal-scroll-view
|
|
139
|
+
#host="symbioteHost"
|
|
140
|
+
[symbioteHostProps]="scrollProps()"
|
|
141
|
+
>
|
|
130
142
|
<symbiote-horizontal-scroll-content
|
|
131
|
-
[symbioteHostProps]="contentProps"
|
|
143
|
+
[symbioteHostProps]="contentProps()"
|
|
132
144
|
[symbioteScrollViewProjection]="projectionController"
|
|
133
145
|
>
|
|
134
|
-
<ng-container
|
|
146
|
+
<ng-container
|
|
147
|
+
[symbioteTemplateOutlet]="sharedContent"
|
|
148
|
+
></ng-container>
|
|
135
149
|
</symbiote-horizontal-scroll-content>
|
|
136
150
|
</symbiote-horizontal-scroll-view>
|
|
137
151
|
}
|
|
@@ -144,23 +158,30 @@ function asStyle(value: unknown): IStyleProp<IViewStyle> | undefined {
|
|
|
144
158
|
>
|
|
145
159
|
<symbiote-scroll-view
|
|
146
160
|
#host="symbioteHost"
|
|
147
|
-
[symbioteHostProps]="androidWrappedScrollProps"
|
|
161
|
+
[symbioteHostProps]="androidWrappedScrollProps()"
|
|
148
162
|
>
|
|
149
163
|
<symbiote-scroll-content
|
|
150
|
-
[symbioteHostProps]="contentProps"
|
|
164
|
+
[symbioteHostProps]="contentProps()"
|
|
151
165
|
[symbioteScrollViewProjection]="projectionController"
|
|
152
166
|
>
|
|
153
|
-
<ng-container
|
|
167
|
+
<ng-container
|
|
168
|
+
[symbioteTemplateOutlet]="sharedContent"
|
|
169
|
+
></ng-container>
|
|
154
170
|
</symbiote-scroll-content>
|
|
155
171
|
</symbiote-scroll-view>
|
|
156
172
|
</symbiote-refresh-control>
|
|
157
173
|
} @else {
|
|
158
|
-
<symbiote-scroll-view
|
|
174
|
+
<symbiote-scroll-view
|
|
175
|
+
#host="symbioteHost"
|
|
176
|
+
[symbioteHostProps]="scrollProps()"
|
|
177
|
+
>
|
|
159
178
|
<symbiote-scroll-content
|
|
160
|
-
[symbioteHostProps]="contentProps"
|
|
179
|
+
[symbioteHostProps]="contentProps()"
|
|
161
180
|
[symbioteScrollViewProjection]="projectionController"
|
|
162
181
|
>
|
|
163
|
-
<ng-container
|
|
182
|
+
<ng-container
|
|
183
|
+
[symbioteTemplateOutlet]="sharedContent"
|
|
184
|
+
></ng-container>
|
|
164
185
|
</symbiote-scroll-content>
|
|
165
186
|
</symbiote-scroll-view>
|
|
166
187
|
}
|
|
@@ -168,23 +189,17 @@ function asStyle(value: unknown): IStyleProp<IViewStyle> | undefined {
|
|
|
168
189
|
`,
|
|
169
190
|
})
|
|
170
191
|
export class ScrollView extends ScrollViewBase {
|
|
171
|
-
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
172
|
-
// onto (see anchorHostStyle's doc comment) — NOT `#host` in the template above, which targets
|
|
173
|
-
// the real inner `symbiote-scroll-view`/`symbiote-horizontal-scroll-view` one level down.
|
|
174
|
-
private readonly elementRef = inject(ElementRef);
|
|
175
|
-
|
|
176
|
-
override get scrollProps(): Record<string, unknown> {
|
|
177
|
-
const props = super.scrollProps;
|
|
178
|
-
return { ...props, style: [anchorHostStyle(this.elementRef), props.style] };
|
|
179
|
-
}
|
|
180
|
-
|
|
181
192
|
// Feeds the anchor's class-derived style INTO the base class's own `splitLayoutProps` call
|
|
182
193
|
// (shared.ts's `androidWrappedScrollProps`/`androidRefreshControlProps`), not tacked on after —
|
|
183
194
|
// a class-only layout style (flex/height/gap/…) must be visible to the split itself, or the
|
|
184
195
|
// Android outer refresh-control wrapper never receives its share and collapses to zero size
|
|
185
196
|
// (a real device bug: the whole ScrollView renders nothing). See layoutSplitStyle's doc comment
|
|
186
197
|
// in shared.ts and the identical fix already shipped in the Vue adapter's scroll-view.
|
|
198
|
+
//
|
|
199
|
+
// Reads the base's `anchorStyle` SIGNAL rather than calling anchorHostStyle() directly: this
|
|
200
|
+
// getter is evaluated inside the `androidWrappedScrollProps` computed, where a plain read would
|
|
201
|
+
// be untracked and leave the memoized bag holding a stale class.
|
|
187
202
|
protected override get layoutSplitStyle(): IStyleProp<IViewStyle> {
|
|
188
|
-
return [asStyle(
|
|
203
|
+
return [asStyle(this.anchorStyle()), this.style];
|
|
189
204
|
}
|
|
190
205
|
}
|
|
@@ -20,17 +20,19 @@ import {
|
|
|
20
20
|
CUSTOM_ELEMENTS_SCHEMA,
|
|
21
21
|
ChangeDetectionStrategy,
|
|
22
22
|
Component,
|
|
23
|
-
ElementRef,
|
|
24
|
-
inject,
|
|
25
23
|
} from '@angular/core';
|
|
26
24
|
import {
|
|
27
|
-
anchorHostStyle,
|
|
28
25
|
RefreshControlHost,
|
|
29
26
|
ScrollContentView,
|
|
30
27
|
ScrollViewHost,
|
|
31
28
|
SymbioteHostPropsDirective,
|
|
29
|
+
SymbioteStyleInputDirective,
|
|
32
30
|
} from '../../primitives';
|
|
33
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
ScrollViewBase,
|
|
33
|
+
ScrollViewProjectionDirective,
|
|
34
|
+
SCROLL_VIEW_INPUTS,
|
|
35
|
+
} from './shared';
|
|
34
36
|
export type { IAngularScrollViewProps, IScrollViewHandle } from './shared';
|
|
35
37
|
|
|
36
38
|
// The symbiote-* host elements are imported as standalone components; the props directive is
|
|
@@ -38,6 +40,9 @@ export type { IAngularScrollViewProps, IScrollViewHandle } from './shared';
|
|
|
38
40
|
@Component({
|
|
39
41
|
selector: 'ScrollView',
|
|
40
42
|
standalone: true,
|
|
43
|
+
hostDirectives: [
|
|
44
|
+
{ directive: SymbioteStyleInputDirective, inputs: ['style'] },
|
|
45
|
+
],
|
|
41
46
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
42
47
|
imports: [
|
|
43
48
|
ScrollViewHost,
|
|
@@ -49,7 +54,10 @@ export type { IAngularScrollViewProps, IScrollViewHandle } from './shared';
|
|
|
49
54
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
50
55
|
inputs: SCROLL_VIEW_INPUTS,
|
|
51
56
|
template: `
|
|
52
|
-
<symbiote-scroll-view
|
|
57
|
+
<symbiote-scroll-view
|
|
58
|
+
#host="symbioteHost"
|
|
59
|
+
[symbioteHostProps]="scrollProps()"
|
|
60
|
+
>
|
|
53
61
|
@if (hasProjectedRefreshControl) {
|
|
54
62
|
<symbiote-refresh-control
|
|
55
63
|
#refreshHost="symbioteHost"
|
|
@@ -58,7 +66,7 @@ export type { IAngularScrollViewProps, IScrollViewHandle } from './shared';
|
|
|
58
66
|
></symbiote-refresh-control>
|
|
59
67
|
}
|
|
60
68
|
<symbiote-scroll-content
|
|
61
|
-
[symbioteHostProps]="contentProps"
|
|
69
|
+
[symbioteHostProps]="contentProps()"
|
|
62
70
|
[symbioteScrollViewProjection]="projectionController"
|
|
63
71
|
>
|
|
64
72
|
<ng-content></ng-content>
|
|
@@ -66,14 +74,8 @@ export type { IAngularScrollViewProps, IScrollViewHandle } from './shared';
|
|
|
66
74
|
</symbiote-scroll-view>
|
|
67
75
|
`,
|
|
68
76
|
})
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
override get scrollProps(): Record<string, unknown> {
|
|
76
|
-
const props = super.scrollProps;
|
|
77
|
-
return { ...props, style: [anchorHostStyle(this.elementRef), props.style] };
|
|
78
|
-
}
|
|
79
|
-
}
|
|
77
|
+
// Behavior lives entirely in ScrollViewBase; this class exists for the decorator + iOS template.
|
|
78
|
+
// The anchor-style merge that used to be a `scrollProps` override here moved into the base's
|
|
79
|
+
// `scrollProps` computed - a subclass getter cannot override a field, and both platforms merged it
|
|
80
|
+
// identically anyway (see that computed's comment).
|
|
81
|
+
export class ScrollView extends ScrollViewBase {}
|