@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.
Files changed (191) hide show
  1. package/README.md +3 -3
  2. package/bin/symbiote-angular-dev.cjs +20 -19
  3. package/build/angular/anchor-host-registry.js +2 -2
  4. package/build/angular/anchor-host-registry.js.map +1 -1
  5. package/build/angular/bootstrap.js +1 -1
  6. package/build/angular/bootstrap.js.map +1 -1
  7. package/build/angular/components/activity-indicator/index.android.d.ts +2 -1
  8. package/build/angular/components/activity-indicator/index.android.js +12 -4
  9. package/build/angular/components/activity-indicator/index.android.js.map +1 -1
  10. package/build/angular/components/activity-indicator/index.ios.d.ts +2 -1
  11. package/build/angular/components/activity-indicator/index.ios.js +8 -3
  12. package/build/angular/components/activity-indicator/index.ios.js.map +1 -1
  13. package/build/angular/components/activity-indicator/shared.d.ts +1 -1
  14. package/build/angular/components/activity-indicator/shared.js +4 -4
  15. package/build/angular/components/activity-indicator/shared.js.map +1 -1
  16. package/build/angular/components/button.d.ts +4 -2
  17. package/build/angular/components/button.js +41 -22
  18. package/build/angular/components/button.js.map +1 -1
  19. package/build/angular/components/flat-list/index.d.ts +6 -4
  20. package/build/angular/components/flat-list/index.js +80 -50
  21. package/build/angular/components/flat-list/index.js.map +1 -1
  22. package/build/angular/components/image/index.android.d.ts +8 -3
  23. package/build/angular/components/image/index.android.js +42 -10
  24. package/build/angular/components/image/index.android.js.map +1 -1
  25. package/build/angular/components/image/index.ios.d.ts +8 -3
  26. package/build/angular/components/image/index.ios.js +42 -10
  27. package/build/angular/components/image/index.ios.js.map +1 -1
  28. package/build/angular/components/image/shared.d.ts +4 -1
  29. package/build/angular/components/image/shared.js +51 -8
  30. package/build/angular/components/image/shared.js.map +1 -1
  31. package/build/angular/components/image-background.d.ts +2 -1
  32. package/build/angular/components/image-background.js +26 -10
  33. package/build/angular/components/image-background.js.map +1 -1
  34. package/build/angular/components/input-accessory-view/index.d.ts +9 -4
  35. package/build/angular/components/input-accessory-view/index.js +49 -10
  36. package/build/angular/components/input-accessory-view/index.js.map +1 -1
  37. package/build/angular/components/keyboard-avoiding-view/index.d.ts +3 -1
  38. package/build/angular/components/keyboard-avoiding-view/index.js +44 -12
  39. package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
  40. package/build/angular/components/modal/index.d.ts +11 -8
  41. package/build/angular/components/modal/index.js +51 -29
  42. package/build/angular/components/modal/index.js.map +1 -1
  43. package/build/angular/components/pressable/index.d.ts +12 -6
  44. package/build/angular/components/pressable/index.js +66 -13
  45. package/build/angular/components/pressable/index.js.map +1 -1
  46. package/build/angular/components/refresh-control/index.d.ts +8 -4
  47. package/build/angular/components/refresh-control/index.js +54 -16
  48. package/build/angular/components/refresh-control/index.js.map +1 -1
  49. package/build/angular/components/safe-area-view/index.d.ts +9 -4
  50. package/build/angular/components/safe-area-view/index.js +48 -9
  51. package/build/angular/components/safe-area-view/index.js.map +1 -1
  52. package/build/angular/components/scroll-view/index.android.d.ts +2 -3
  53. package/build/angular/components/scroll-view/index.android.js +88 -61
  54. package/build/angular/components/scroll-view/index.android.js.map +1 -1
  55. package/build/angular/components/scroll-view/index.ios.d.ts +2 -3
  56. package/build/angular/components/scroll-view/index.ios.js +24 -18
  57. package/build/angular/components/scroll-view/index.ios.js.map +1 -1
  58. package/build/angular/components/scroll-view/projection.d.ts +35 -0
  59. package/build/angular/components/scroll-view/projection.js +279 -53
  60. package/build/angular/components/scroll-view/projection.js.map +1 -1
  61. package/build/angular/components/scroll-view/shared.d.ts +14 -5
  62. package/build/angular/components/scroll-view/shared.js +225 -75
  63. package/build/angular/components/scroll-view/shared.js.map +1 -1
  64. package/build/angular/components/scroll-view/sticky-header.js +21 -22
  65. package/build/angular/components/scroll-view/sticky-header.js.map +1 -1
  66. package/build/angular/components/section-list/index.d.ts +7 -1
  67. package/build/angular/components/section-list/index.js +91 -54
  68. package/build/angular/components/section-list/index.js.map +1 -1
  69. package/build/angular/components/switch/index.android.d.ts +7 -3
  70. package/build/angular/components/switch/index.android.js +52 -10
  71. package/build/angular/components/switch/index.android.js.map +1 -1
  72. package/build/angular/components/switch/index.ios.d.ts +7 -3
  73. package/build/angular/components/switch/index.ios.js +52 -10
  74. package/build/angular/components/switch/index.ios.js.map +1 -1
  75. package/build/angular/components/switch/shared.d.ts +13 -4
  76. package/build/angular/components/switch/shared.js +71 -7
  77. package/build/angular/components/switch/shared.js.map +1 -1
  78. package/build/angular/components/text-input.d.ts +11 -3
  79. package/build/angular/components/text-input.js +68 -8
  80. package/build/angular/components/text-input.js.map +1 -1
  81. package/build/angular/components/touchable/index.d.ts +40 -9
  82. package/build/angular/components/touchable/index.js +303 -67
  83. package/build/angular/components/touchable/index.js.map +1 -1
  84. package/build/angular/components/touchable-native-feedback/index.d.ts +6 -3
  85. package/build/angular/components/touchable-native-feedback/index.js +63 -27
  86. package/build/angular/components/touchable-native-feedback/index.js.map +1 -1
  87. package/build/angular/components/virtualized-list/directives.js +22 -18
  88. package/build/angular/components/virtualized-list/directives.js.map +1 -1
  89. package/build/angular/components/virtualized-list/index.d.ts +15 -4
  90. package/build/angular/components/virtualized-list/index.js +326 -94
  91. package/build/angular/components/virtualized-list/index.js.map +1 -1
  92. package/build/angular/components/virtualized-section-list/directives.js +12 -12
  93. package/build/angular/components/virtualized-section-list/directives.js.map +1 -1
  94. package/build/angular/components/virtualized-section-list/index.d.ts +19 -1
  95. package/build/angular/components/virtualized-section-list/index.js +93 -22
  96. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  97. package/build/angular/components.d.ts +2 -2
  98. package/build/angular/components.js +5 -0
  99. package/build/angular/components.js.map +1 -1
  100. package/build/angular/create-portal/index.js +34 -36
  101. package/build/angular/create-portal/index.js.map +1 -1
  102. package/build/angular/create-tunnel/index.js +19 -22
  103. package/build/angular/create-tunnel/index.js.map +1 -1
  104. package/build/angular/descriptor-to-angular/index.js +6 -4
  105. package/build/angular/descriptor-to-angular/index.js.map +1 -1
  106. package/build/angular/diagnostics.d.ts +33 -0
  107. package/build/angular/diagnostics.js +82 -0
  108. package/build/angular/diagnostics.js.map +1 -0
  109. package/build/angular/host-instance/index.js +1 -1
  110. package/build/angular/host-instance/index.js.map +1 -1
  111. package/build/angular/index.d.ts +9 -4
  112. package/build/angular/index.js +17 -3
  113. package/build/angular/index.js.map +1 -1
  114. package/build/angular/modules/animated/animated-leaf-binder.d.ts +1 -7
  115. package/build/angular/modules/animated/animated-leaf-binder.js +22 -72
  116. package/build/angular/modules/animated/animated-leaf-binder.js.map +1 -1
  117. package/build/angular/modules/animated/create-animated-component.d.ts +11 -6
  118. package/build/angular/modules/animated/create-animated-component.js +106 -55
  119. package/build/angular/modules/animated/create-animated-component.js.map +1 -1
  120. package/build/angular/modules/status-bar/index.js +4 -4
  121. package/build/angular/modules/status-bar/index.js.map +1 -1
  122. package/build/angular/primitives/index.d.ts +20 -3
  123. package/build/angular/primitives/index.js +84 -48
  124. package/build/angular/primitives/index.js.map +1 -1
  125. package/build/angular/primitives/shared.d.ts +48 -2
  126. package/build/angular/primitives/shared.js +158 -11
  127. package/build/angular/primitives/shared.js.map +1 -1
  128. package/build/angular/render/index.js +69 -38
  129. package/build/angular/render/index.js.map +1 -1
  130. package/build/angular/renderer/index.d.ts +1 -0
  131. package/build/angular/renderer/index.js +37 -2
  132. package/build/angular/renderer/index.js.map +1 -1
  133. package/build/angular/services/color-scheme.service.js +3 -3
  134. package/build/angular/services/color-scheme.service.js.map +1 -1
  135. package/build/angular/services/window-dimensions.service.js +4 -4
  136. package/build/angular/services/window-dimensions.service.js.map +1 -1
  137. package/package.json +10 -8
  138. package/src/anchor-host-registry.ts +2 -2
  139. package/src/bootstrap.ts +4 -1
  140. package/src/components/activity-indicator/index.android.ts +8 -1
  141. package/src/components/activity-indicator/index.ios.ts +4 -0
  142. package/src/components/activity-indicator/shared.ts +32 -13
  143. package/src/components/button.ts +46 -19
  144. package/src/components/flat-list/index.ts +122 -62
  145. package/src/components/image/index.android.ts +58 -7
  146. package/src/components/image/index.ios.ts +58 -7
  147. package/src/components/image/shared.ts +92 -21
  148. package/src/components/image-background.ts +29 -9
  149. package/src/components/input-accessory-view/index.ts +67 -12
  150. package/src/components/keyboard-avoiding-view/index.ts +61 -15
  151. package/src/components/modal/index.ts +72 -33
  152. package/src/components/pressable/index.ts +117 -28
  153. package/src/components/refresh-control/index.ts +74 -18
  154. package/src/components/safe-area-view/index.ts +64 -10
  155. package/src/components/scroll-view/index.android.ts +62 -47
  156. package/src/components/scroll-view/index.ios.ts +19 -17
  157. package/src/components/scroll-view/projection.ts +363 -64
  158. package/src/components/scroll-view/shared.ts +312 -90
  159. package/src/components/scroll-view/sticky-header.ts +36 -24
  160. package/src/components/section-list/index.ts +86 -53
  161. package/src/components/switch/index.android.ts +60 -8
  162. package/src/components/switch/index.ios.ts +60 -8
  163. package/src/components/switch/shared.ts +93 -6
  164. package/src/components/text-input.ts +95 -13
  165. package/src/components/touchable/index.ts +348 -64
  166. package/src/components/touchable-native-feedback/index.ts +94 -31
  167. package/src/components/virtualized-list/directives.ts +19 -5
  168. package/src/components/virtualized-list/index.ts +380 -85
  169. package/src/components/virtualized-section-list/directives.ts +6 -3
  170. package/src/components/virtualized-section-list/index.ts +146 -33
  171. package/src/components.ts +9 -1
  172. package/src/create-portal/index.ts +31 -31
  173. package/src/create-tunnel/index.ts +16 -17
  174. package/src/descriptor-to-angular/index.ts +29 -8
  175. package/src/diagnostics.ts +138 -0
  176. package/src/host-instance/index.ts +9 -3
  177. package/src/index.ts +61 -3
  178. package/src/modules/animated/animated-leaf-binder.ts +28 -77
  179. package/src/modules/animated/create-animated-component.ts +115 -47
  180. package/src/modules/app-registry/index.ts +9 -9
  181. package/src/modules/status-bar/index.ts +13 -4
  182. package/src/primitives/index.ts +47 -2
  183. package/src/primitives/shared.ts +170 -10
  184. package/src/render/index.ts +77 -39
  185. package/src/renderer/index.ts +76 -14
  186. package/src/services/color-scheme.service.ts +3 -1
  187. package/src/services/window-dimensions.service.ts +11 -4
  188. package/build/angular/modules/animated/animated-leaf-binder/index.d.ts +0 -14
  189. package/build/angular/modules/animated/animated-leaf-binder/index.js +0 -91
  190. package/build/angular/modules/animated/animated-leaf-binder/index.js.map +0 -1
  191. package/src/modules/animated/animated-leaf-binder/index.ts +0 -101
@@ -1,22 +1,19 @@
1
1
  // TouchableNativeFeedback: the Angular lifecycle half. Android's ripple / state-drawable
2
- // touchable, built on Pressable like the rest of the family (the Angular twin of the React/Vue
3
- // adapter). RN realizes its feedback by cloning the child into an RCTView carrying native ripple
4
- // props; we instead nest the child under a feedback <symbiote-view> that carries those props
5
- // (nativeBackgroundAndroid / nativeForegroundAndroid), inside a <Pressable> that owns the press
6
- // wiring. The native props are read by Android's ReactViewManager; on iOS they are inert props,
7
- // so the child still renders with working press wiring. The static factories + background mapping
8
- // are shared in @symbiote-native/components and reused verbatim Angular only attaches them onto the
9
- // component class and nests the feedback view. No JS-side platform branch (one Fabric path both
10
- // platforms), so this stays a flat single file, mirroring React/Vue.
2
+ // touchable, built on Pressable like the rest of the family. RN realizes its feedback by cloning
3
+ // the child into an RCTView carrying native ripple props; we instead nest the child under a
4
+ // feedback <symbiote-view> that carries those props (nativeBackgroundAndroid /
5
+ // nativeForegroundAndroid), inside a <Pressable> that owns the press wiring. The native props are
6
+ // read by Android's ReactViewManager; on iOS they are inert, so the child still renders with
7
+ // working press wiring. The static factories + background mapping are shared in
8
+ // @symbiote-native/components and reused verbatim. One Fabric path both platforms, so this stays
9
+ // a flat single file, mirroring React/Vue.
11
10
  //
12
11
  // This component's own press/hover events are real @Output() EventEmitters too, matching
13
- // Pressable (which it wraps) — `(press)="press.emit($event)"`, never `[onPress]="onPress"`.
14
- // Non-event config (delayLongPress, hitSlop, ...) still rides down as plain @Input() bindings. The
15
- // a11y identity bag + the four a11y events live on the feedback view — the one host intrinsic here —
16
- // folded through the shared resolveAccessibilityProps and routed through emit() on the (event)
17
- // channel (Angular blocks [onX] property bindings on host elements; events flow through (event)
18
- // only). disabled folds into the a11y state via resolveDisabledAccessibilityState, exactly as
19
- // Pressable does for its own host.
12
+ // Pressable (which it wraps) — `(press)="press.emit($event)"`, never `[onPress]="onPress"`. The
13
+ // a11y identity bag + the four a11y events live on the feedback view — the one host intrinsic here
14
+ // folded through the shared resolveAccessibilityProps and routed through emit() on the (event)
15
+ // channel (Angular blocks [onX] property bindings on host elements). disabled folds into the a11y
16
+ // state via resolveDisabledAccessibilityState, exactly as Pressable does for its own host.
20
17
 
21
18
  import {
22
19
  CUSTOM_ELEMENTS_SCHEMA,
@@ -24,9 +21,12 @@ import {
24
21
  Component,
25
22
  ElementRef,
26
23
  EventEmitter,
24
+ computed,
27
25
  inject,
28
26
  Input,
29
27
  Output,
28
+ signal,
29
+ type DoCheck,
30
30
  type OnChanges,
31
31
  } from '@angular/core';
32
32
  import {
@@ -44,8 +44,16 @@ import {
44
44
  type IPressableAndroidRippleConfig,
45
45
  type IRectOffset,
46
46
  } from '@symbiote-native/components';
47
- import { dlog, isSymbioteEvent, type ISymbioteEvent } from '@symbiote-native/engine';
48
- import { anchorHostStyle, SymbioteHostPropsDirective, ViewHost } from '../../primitives';
47
+ import {
48
+ dlog,
49
+ isSymbioteEvent,
50
+ type ISymbioteEvent,
51
+ } from '@symbiote-native/engine';
52
+ import {
53
+ anchorHostStyle,
54
+ SymbioteHostPropsDirective,
55
+ ViewHost,
56
+ } from '../../primitives';
49
57
  import { Pressable, type IAngularPressableInputs } from '../pressable';
50
58
 
51
59
  export type {
@@ -58,7 +66,10 @@ export type {
58
66
  // feedback config) minus children (Angular takes children via <ng-content>) and minus the press/
59
67
  // hover events (declared as this component's OWN @Output()s below). Declared per-adapter over the
60
68
  // shared Pressable INPUT surface.
61
- export type IAngularTouchableNativeFeedbackProps = Omit<IAngularPressableInputs, 'style'> & {
69
+ export type IAngularTouchableNativeFeedbackProps = Omit<
70
+ IAngularPressableInputs,
71
+ 'style'
72
+ > & {
62
73
  background?: INativeFeedbackBackground;
63
74
  useForeground?: boolean;
64
75
  };
@@ -90,7 +101,7 @@ export type IAngularTouchableNativeFeedbackProps = Omit<IAngularPressableInputs,
90
101
  [android_disableSound]="android_disableSound"
91
102
  >
92
103
  <symbiote-view
93
- [symbioteHostProps]="hostProps"
104
+ [symbioteHostProps]="hostProps()"
94
105
  (accessibilityAction)="emit(accessibilityAction, $event)"
95
106
  (accessibilityTap)="emit(accessibilityTap, $event)"
96
107
  (magicTap)="emit(magicTap, $event)"
@@ -101,11 +112,14 @@ export type IAngularTouchableNativeFeedbackProps = Omit<IAngularPressableInputs,
101
112
  </Pressable>
102
113
  `,
103
114
  })
104
- export class TouchableNativeFeedback implements IAngularTouchableNativeFeedbackProps, OnChanges {
115
+ export class TouchableNativeFeedback
116
+ implements IAngularTouchableNativeFeedbackProps, OnChanges, DoCheck
117
+ {
105
118
  // The static helpers are pure config-dict producers; they live as members on the component class
106
119
  // so callers reach them as `TouchableNativeFeedback.Ripple(...)`, exactly like RN.
107
120
  static readonly SelectableBackground = selectableBackground;
108
- static readonly SelectableBackgroundBorderless = selectableBackgroundBorderless;
121
+ static readonly SelectableBackgroundBorderless =
122
+ selectableBackgroundBorderless;
109
123
  static readonly Ripple = rippleBackground;
110
124
  static readonly canUseNativeForeground = canUseNativeForeground;
111
125
 
@@ -142,8 +156,10 @@ export class TouchableNativeFeedback implements IAngularTouchableNativeFeedbackP
142
156
  @Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
143
157
  @Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
144
158
  @Input() accessibilityLabelledBy?: string | string[];
145
- @Input() importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
146
- @Input() accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
159
+ @Input()
160
+ importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
161
+ @Input()
162
+ accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
147
163
  @Input() screenReaderFocusable?: boolean;
148
164
  @Input() accessibilityViewIsModal?: boolean;
149
165
  @Input() accessibilityElementsHidden?: boolean;
@@ -175,7 +191,37 @@ export class TouchableNativeFeedback implements IAngularTouchableNativeFeedbackP
175
191
  // anchor's class-derived style is the ONLY style source for hostProps.style below.
176
192
  private readonly elementRef = inject(ElementRef);
177
193
 
194
+ // Bridges the non-reactive @Input fields above into the reactive graph, so the computed() bag
195
+ // below can memoize a value derived from them. Signal inputs would make this unnecessary, but
196
+ // `input()` is visible only to the AOT compiler and this package's unit suite runs on JIT - see
197
+ // the `angular-adapter-change-detection` skill, §6. Mirrors ScrollView's identical bridge
198
+ // (components/scroll-view/shared.ts), including its constraint: ONLY safe for a bag whose every
199
+ // dependency is an @Input or carries its own signal, never for plain internal mutable state.
200
+ private readonly inputsRevision = signal(0);
201
+
202
+ // The anchor's class-derived style is hostProps' one dependency that is NOT an @Input:
203
+ // `class="..."`/`[class.x]`/`[ngClass]` at the use site resolves through the renderer's
204
+ // addClass/removeClass onto the anchor node (anchorHostStyle's doc comment), so it never appears
205
+ // in SimpleChanges and ngOnChanges cannot cover it. The engine's commitClassStyle allocates a
206
+ // fresh [classStyle, explicitStyle] array on exactly the passes where a class token actually
207
+ // moved, so signal.set's own Object.is check makes an unchanged poll a no-op that dirties nothing.
208
+ private readonly anchorStyle = signal<unknown>(undefined);
209
+
210
+ // ngDoCheck is the only hook that observes the anchor AFTER the parent wrote it. Angular flushes
211
+ // a node's pre-order hooks at the next `advance` PAST it (hooks.ts callHooks runs "until that
212
+ // node index exclusive") or in refreshView's post-template flush - both strictly after the
213
+ // parent's classProp on this element, and strictly before this component's own view refreshes.
214
+ // Angular also nulls the active consumer around lifecycle hooks (render3/hooks.ts), so this
215
+ // write registers no dependency on the caller's view and cannot throw NG0600.
216
+ ngDoCheck(): void {
217
+ this.anchorStyle.set(anchorHostStyle(this.elementRef));
218
+ }
219
+
178
220
  ngOnChanges(): void {
221
+ // Tells the computed bag below that an @Input moved - plain class fields are not reactive on
222
+ // their own. Must stay in ngOnChanges: that is the single moment Angular has finished writing
223
+ // every changed input for this pass.
224
+ this.inputsRevision.update(revision => revision + 1);
179
225
  dlog(
180
226
  `TouchableNativeFeedback render ${this.resolvedBackground.type} useForeground ${this.useForeground === true}`,
181
227
  );
@@ -190,22 +236,34 @@ export class TouchableNativeFeedback implements IAngularTouchableNativeFeedbackP
190
236
  // backgroundProps picks the foreground slot only where the platform supports it, else the
191
237
  // background slot (canUseNativeForeground) — shared with React/Vue. One side is always undefined.
192
238
  get feedback(): Record<string, INativeFeedbackBackground> {
193
- return backgroundProps(this.resolvedBackground, this.useForeground === true);
239
+ return backgroundProps(
240
+ this.resolvedBackground,
241
+ this.useForeground === true,
242
+ );
194
243
  }
195
244
 
196
245
  // Assembles the SAME resolved values the template used to bind one-by-one into a single
197
246
  // flat bag for `[symbioteHostProps]` (Renderer2.setProperty per key) — see primitives/shared.ts.
198
- get hostProps(): Record<string, unknown> {
247
+ //
248
+ // MEASURED 2026-08-16: as a getter this rebuilt the bag on every refresh of this view, and a
249
+ // press dirties this very view (SymbioteHostPropsDirective wraps each flat-bag onX with
250
+ // markForCheck), so `[symbioteHostProps]`'s reference check failed every time and re-pushed
251
+ // every key through Renderer2.setProperty -> routeProp for an identical bag. Memoized, an
252
+ // unchanged bag costs one reference compare. Every dependency below is either an @Input (covered
253
+ // by inputsRevision) or the anchor style (covered by its own signal) - nothing here reads plain
254
+ // internal mutable state, which is what makes memoizing this one safe.
255
+ readonly hostProps = computed<Record<string, unknown>>(() => {
256
+ this.inputsRevision();
199
257
  return {
200
258
  nativeBackgroundAndroid: this.feedback['nativeBackgroundAndroid'],
201
259
  nativeForegroundAndroid: this.feedback['nativeForegroundAndroid'],
202
- style: anchorHostStyle(this.elementRef),
260
+ style: this.anchorStyle(),
203
261
  testID: this.testID,
204
262
  nativeID: this.nativeID,
205
263
  accessible: this.accessible,
206
264
  ...this.folded,
207
265
  };
208
- }
266
+ });
209
267
 
210
268
  // Forward an engine event to the matching @Output(), narrowing the template's untyped $event.
211
269
  emit(emitter: EventEmitter<ISymbioteEvent>, event: unknown): void {
@@ -220,7 +278,10 @@ export class TouchableNativeFeedback implements IAngularTouchableNativeFeedbackP
220
278
  accessibilityLabel: this.accessibilityLabel,
221
279
  accessibilityHint: this.accessibilityHint,
222
280
  accessibilityRole: this.accessibilityRole,
223
- accessibilityState: resolveDisabledAccessibilityState(this.accessibilityState, this.disabled),
281
+ accessibilityState: resolveDisabledAccessibilityState(
282
+ this.accessibilityState,
283
+ this.disabled,
284
+ ),
224
285
  accessibilityValue: this.accessibilityValue,
225
286
  accessibilityActions: this.accessibilityActions,
226
287
  accessibilityLabelledBy: this.accessibilityLabelledBy,
@@ -231,8 +292,10 @@ export class TouchableNativeFeedback implements IAngularTouchableNativeFeedbackP
231
292
  accessibilityElementsHidden: this.accessibilityElementsHidden,
232
293
  accessibilityIgnoresInvertColors: this.accessibilityIgnoresInvertColors,
233
294
  accessibilityLanguage: this.accessibilityLanguage,
234
- accessibilityRespondsToUserInteraction: this.accessibilityRespondsToUserInteraction,
235
- accessibilityShowsLargeContentViewer: this.accessibilityShowsLargeContentViewer,
295
+ accessibilityRespondsToUserInteraction:
296
+ this.accessibilityRespondsToUserInteraction,
297
+ accessibilityShowsLargeContentViewer:
298
+ this.accessibilityShowsLargeContentViewer,
236
299
  accessibilityLargeContentTitle: this.accessibilityLargeContentTitle,
237
300
  role: this.role,
238
301
  'aria-label': this.ariaLabel,
@@ -36,6 +36,7 @@ import {
36
36
  type SimpleChanges,
37
37
  } from '@angular/core';
38
38
  import { dlog } from '@symbiote-native/engine';
39
+ import { countAngular } from '../../diagnostics';
39
40
  import type { ISeparators } from '@symbiote-native/components';
40
41
 
41
42
  let vListOutletInstanceCounter = 0;
@@ -68,7 +69,8 @@ function isRecord(value: unknown): value is Record<string, unknown> {
68
69
  // typed at the call site (let-item: ItemT, let-index: number, let-separators: ISeparators).
69
70
  @Directive({ selector: '[vListItem]', standalone: true })
70
71
  export class VListItemDirective<ItemT = unknown> {
71
- readonly templateRef = inject<TemplateRef<IVListItemContext<ItemT>>>(TemplateRef);
72
+ readonly templateRef =
73
+ inject<TemplateRef<IVListItemContext<ItemT>>>(TemplateRef);
72
74
 
73
75
  static ngTemplateContextGuard<T>(
74
76
  _dir: VListItemDirective<T>,
@@ -101,7 +103,8 @@ export class VListEmptyDirective {
101
103
  // types the `let-` bindings against the separator props.
102
104
  @Directive({ selector: '[vListSeparator]', standalone: true })
103
105
  export class VListSeparatorDirective<ItemT = unknown> {
104
- readonly templateRef = inject<TemplateRef<IVListSeparatorContext<ItemT>>>(TemplateRef);
106
+ readonly templateRef =
107
+ inject<TemplateRef<IVListSeparatorContext<ItemT>>>(TemplateRef);
105
108
 
106
109
  static ngTemplateContextGuard<T>(
107
110
  _dir: VListSeparatorDirective<T>,
@@ -130,20 +133,28 @@ export class VListOutletDirective<C = unknown> implements OnChanges, OnDestroy {
130
133
  `Angular VListOutlet#${this.instanceId} templateRef CHANGED (was=${changes['templateRef'].previousValue !== undefined} now=${this.templateRef !== undefined}) -> clear + recreate`,
131
134
  );
132
135
  this.viewContainer.clear();
136
+ countAngular('outletCreates');
133
137
  this.viewRef =
134
138
  this.templateRef === undefined
135
139
  ? null
136
- : this.viewContainer.createEmbeddedView(this.templateRef, this.context);
140
+ : this.viewContainer.createEmbeddedView(
141
+ this.templateRef,
142
+ this.context,
143
+ );
137
144
  return;
138
145
  }
139
146
  if (this.viewRef !== null && this.context !== undefined) {
140
- dlog(`Angular VListOutlet#${this.instanceId} context updated, markForCheck`);
147
+ countAngular('outletUpdates');
148
+ dlog(
149
+ `Angular VListOutlet#${this.instanceId} context updated, markForCheck`,
150
+ );
141
151
  this.updateContext(this.viewRef.context, this.context);
142
152
  this.viewRef.markForCheck();
143
153
  }
144
154
  }
145
155
 
146
156
  ngOnDestroy(): void {
157
+ countAngular('outletDestroys');
147
158
  dlog(`Angular VListOutlet#${this.instanceId} destroyed`);
148
159
  this.viewContainer.clear();
149
160
  }
@@ -158,7 +169,10 @@ export class VListOutletDirective<C = unknown> implements OnChanges, OnDestroy {
158
169
  }
159
170
  }
160
171
 
161
- function copyContextFields(target: Record<string, unknown>, source: Record<string, unknown>): void {
172
+ function copyContextFields(
173
+ target: Record<string, unknown>,
174
+ source: Record<string, unknown>,
175
+ ): void {
162
176
  for (const key of Object.keys(target)) {
163
177
  if (!(key in source)) delete target[key];
164
178
  }