@symbiote-native/angular 0.8.0 → 2.0.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 (256) hide show
  1. package/README.md +13 -10
  2. package/babel-register-composed.cjs +58 -18
  3. package/bin/symbiote-angular-dev.cjs +16 -4
  4. package/build/angular/anchor-host-registry.js +1 -15
  5. package/build/angular/anchor-host-registry.js.map +1 -1
  6. package/build/angular/change-detection-flush.d.ts +31 -0
  7. package/build/angular/change-detection-flush.js +110 -0
  8. package/build/angular/change-detection-flush.js.map +1 -0
  9. package/build/angular/components/activity-indicator-props.d.ts +2 -0
  10. package/build/angular/components/activity-indicator-props.js +2 -0
  11. package/build/angular/components/activity-indicator-props.js.map +1 -0
  12. package/build/angular/components/button-props.d.ts +2 -0
  13. package/build/angular/components/button-props.js +2 -0
  14. package/build/angular/components/button-props.js.map +1 -0
  15. package/build/angular/components/flat-list/index.d.ts +2 -1
  16. package/build/angular/components/flat-list/index.js +22 -10
  17. package/build/angular/components/flat-list/index.js.map +1 -1
  18. package/build/angular/components/image-background-props.d.ts +6 -0
  19. package/build/angular/components/image-background-props.js +2 -0
  20. package/build/angular/components/image-background-props.js.map +1 -0
  21. package/build/angular/components/{image/shared.d.ts → image-shared.d.ts} +4 -4
  22. package/build/angular/components/{image/shared.js → image-shared.js} +39 -28
  23. package/build/angular/components/image-shared.js.map +1 -0
  24. package/build/angular/components/input-accessory-view-props.d.ts +7 -0
  25. package/build/angular/components/input-accessory-view-props.js +9 -0
  26. package/build/angular/components/input-accessory-view-props.js.map +1 -0
  27. package/build/angular/components/keyboard-avoiding-view/index.d.ts +2 -1
  28. package/build/angular/components/keyboard-avoiding-view/index.js +28 -27
  29. package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
  30. package/build/angular/components/modal/index.d.ts +2 -0
  31. package/build/angular/components/modal/index.js +33 -20
  32. package/build/angular/components/modal/index.js.map +1 -1
  33. package/build/angular/components/pressable-props.d.ts +32 -0
  34. package/build/angular/components/pressable-props.js +11 -0
  35. package/build/angular/components/pressable-props.js.map +1 -0
  36. package/build/angular/components/refresh-control-props.d.ts +16 -0
  37. package/build/angular/components/refresh-control-props.js +14 -0
  38. package/build/angular/components/refresh-control-props.js.map +1 -0
  39. package/build/angular/components/safe-area-view-props.d.ts +7 -0
  40. package/build/angular/components/safe-area-view-props.js +11 -0
  41. package/build/angular/components/safe-area-view-props.js.map +1 -0
  42. package/build/angular/components/scroll-view-props.d.ts +76 -0
  43. package/build/angular/components/scroll-view-props.js +18 -0
  44. package/build/angular/components/scroll-view-props.js.map +1 -0
  45. package/build/angular/components/section-list/index.d.ts +3 -0
  46. package/build/angular/components/section-list/index.js +10 -1
  47. package/build/angular/components/section-list/index.js.map +1 -1
  48. package/build/angular/components/text-input-props.d.ts +45 -0
  49. package/build/angular/components/text-input-props.js +18 -0
  50. package/build/angular/components/text-input-props.js.map +1 -0
  51. package/build/angular/components/touchable-native-feedback/touchable-native-feedback-props.d.ts +6 -0
  52. package/build/angular/components/touchable-native-feedback/touchable-native-feedback-props.js +2 -0
  53. package/build/angular/components/touchable-native-feedback/touchable-native-feedback-props.js.map +1 -0
  54. package/build/angular/components/touchable-props.d.ts +14 -0
  55. package/build/angular/components/touchable-props.js +13 -0
  56. package/build/angular/components/touchable-props.js.map +1 -0
  57. package/build/angular/components/touchable-without-feedback/touchable-without-feedback-props.d.ts +3 -0
  58. package/build/angular/components/touchable-without-feedback/touchable-without-feedback-props.js +2 -0
  59. package/build/angular/components/touchable-without-feedback/touchable-without-feedback-props.js.map +1 -0
  60. package/build/angular/components/virtualized-list/index.d.ts +8 -1
  61. package/build/angular/components/virtualized-list/index.js +373 -278
  62. package/build/angular/components/virtualized-list/index.js.map +1 -1
  63. package/build/angular/components/virtualized-section-list/index.d.ts +3 -0
  64. package/build/angular/components/virtualized-section-list/index.js +10 -1
  65. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  66. package/build/angular/components.d.ts +21 -27
  67. package/build/angular/components.js +13 -15
  68. package/build/angular/components.js.map +1 -1
  69. package/build/angular/create-portal/index.d.ts +11 -2
  70. package/build/angular/create-portal/index.js +37 -11
  71. package/build/angular/create-portal/index.js.map +1 -1
  72. package/build/angular/create-tunnel/index.js +1 -1
  73. package/build/angular/element-props.d.ts +53 -0
  74. package/build/angular/element-props.js +2 -0
  75. package/build/angular/element-props.js.map +1 -0
  76. package/build/angular/elements.d.ts +528 -0
  77. package/build/angular/elements.js +1444 -0
  78. package/build/angular/elements.js.map +1 -0
  79. package/build/angular/gate-demand.d.ts +37 -0
  80. package/build/angular/gate-demand.js +84 -0
  81. package/build/angular/gate-demand.js.map +1 -0
  82. package/build/angular/host-instance/index.js +1 -1
  83. package/build/angular/index.d.ts +5 -2
  84. package/build/angular/index.js +16 -1
  85. package/build/angular/index.js.map +1 -1
  86. package/build/angular/modules/animated/create-animated-component.d.ts +6 -6
  87. package/build/angular/modules/animated/create-animated-component.js +73 -81
  88. package/build/angular/modules/animated/create-animated-component.js.map +1 -1
  89. package/build/angular/modules/animated/index.js +1 -1
  90. package/build/angular/modules/animated/index.js.map +1 -1
  91. package/build/angular/modules/image/index.d.ts +3 -0
  92. package/build/angular/modules/image/index.js +16 -0
  93. package/build/angular/modules/image/index.js.map +1 -0
  94. package/build/angular/primitives/index.d.ts +28 -16
  95. package/build/angular/primitives/index.js +77 -31
  96. package/build/angular/primitives/index.js.map +1 -1
  97. package/build/angular/primitives/shared.d.ts +2 -3
  98. package/build/angular/primitives/shared.js +8 -53
  99. package/build/angular/primitives/shared.js.map +1 -1
  100. package/build/angular/register.d.ts +1 -0
  101. package/build/angular/register.js +16 -0
  102. package/build/angular/register.js.map +1 -0
  103. package/build/angular/render/index.js +4 -2
  104. package/build/angular/render/index.js.map +1 -1
  105. package/build/angular/renderer/index.js +207 -60
  106. package/build/angular/renderer/index.js.map +1 -1
  107. package/build/angular/renderer/value-change.d.ts +2 -0
  108. package/build/angular/renderer/value-change.js +9 -0
  109. package/build/angular/renderer/value-change.js.map +1 -0
  110. package/metro-config.cjs +23 -5
  111. package/metro-css-parser.cjs +2 -1
  112. package/package.json +17 -7
  113. package/src/anchor-host-registry.ts +1 -15
  114. package/src/change-detection-flush.ts +120 -0
  115. package/src/components/activity-indicator-props.ts +21 -0
  116. package/src/components/button-props.ts +26 -0
  117. package/src/components/flat-list/index.ts +12 -4
  118. package/src/components/image-background-props.ts +24 -0
  119. package/src/components/{image/shared.ts → image-shared.ts} +57 -26
  120. package/src/components/input-accessory-view-props.ts +21 -0
  121. package/src/components/keyboard-avoiding-view/index.ts +27 -16
  122. package/src/components/modal/index.ts +32 -11
  123. package/src/components/pressable-props.ts +73 -0
  124. package/src/components/refresh-control-props.ts +43 -0
  125. package/src/components/safe-area-view-props.ts +28 -0
  126. package/src/components/scroll-view-props.ts +109 -0
  127. package/src/components/section-list/index.ts +18 -0
  128. package/src/components/text-input-props.ts +72 -0
  129. package/src/components/touchable-native-feedback/touchable-native-feedback-props.ts +23 -0
  130. package/src/components/touchable-props.ts +30 -0
  131. package/src/components/touchable-without-feedback/touchable-without-feedback-props.ts +21 -0
  132. package/src/components/virtualized-list/index.ts +254 -153
  133. package/src/components/virtualized-section-list/index.ts +18 -0
  134. package/src/components.ts +86 -35
  135. package/src/create-portal/index.ts +39 -9
  136. package/src/create-tunnel/index.ts +1 -1
  137. package/src/diagnostics.ts +1 -1
  138. package/src/element-props.ts +90 -0
  139. package/src/elements.ts +919 -0
  140. package/src/gate-demand.ts +109 -0
  141. package/src/host-instance/index.ts +1 -1
  142. package/src/index.ts +54 -15
  143. package/src/modules/animated/create-animated-component.ts +73 -59
  144. package/src/modules/animated/index.ts +1 -1
  145. package/src/modules/image/index.ts +18 -0
  146. package/src/primitives/index.ts +47 -16
  147. package/src/primitives/shared.ts +11 -44
  148. package/src/register.ts +15 -0
  149. package/src/render/index.ts +4 -2
  150. package/src/renderer/index.ts +239 -80
  151. package/src/renderer/value-change.ts +8 -0
  152. package/build/angular/components/activity-indicator/index.android.d.ts +0 -13
  153. package/build/angular/components/activity-indicator/index.android.js +0 -29
  154. package/build/angular/components/activity-indicator/index.android.js.map +0 -1
  155. package/build/angular/components/activity-indicator/index.d.ts +0 -1
  156. package/build/angular/components/activity-indicator/index.ios.d.ts +0 -9
  157. package/build/angular/components/activity-indicator/index.ios.js +0 -26
  158. package/build/angular/components/activity-indicator/index.ios.js.map +0 -1
  159. package/build/angular/components/activity-indicator/index.js +0 -4
  160. package/build/angular/components/activity-indicator/index.js.map +0 -1
  161. package/build/angular/components/activity-indicator/shared.d.ts +0 -67
  162. package/build/angular/components/activity-indicator/shared.js +0 -260
  163. package/build/angular/components/activity-indicator/shared.js.map +0 -1
  164. package/build/angular/components/button.d.ts +0 -65
  165. package/build/angular/components/button.js +0 -351
  166. package/build/angular/components/button.js.map +0 -1
  167. package/build/angular/components/image/index.android.d.ts +0 -15
  168. package/build/angular/components/image/index.android.js +0 -91
  169. package/build/angular/components/image/index.android.js.map +0 -1
  170. package/build/angular/components/image/index.d.ts +0 -1
  171. package/build/angular/components/image/index.ios.d.ts +0 -15
  172. package/build/angular/components/image/index.ios.js +0 -91
  173. package/build/angular/components/image/index.ios.js.map +0 -1
  174. package/build/angular/components/image/index.js +0 -3
  175. package/build/angular/components/image/index.js.map +0 -1
  176. package/build/angular/components/image/shared.js.map +0 -1
  177. package/build/angular/components/image-background.d.ts +0 -82
  178. package/build/angular/components/image-background.js +0 -434
  179. package/build/angular/components/image-background.js.map +0 -1
  180. package/build/angular/components/input-accessory-view/index.d.ts +0 -65
  181. package/build/angular/components/input-accessory-view/index.js +0 -290
  182. package/build/angular/components/input-accessory-view/index.js.map +0 -1
  183. package/build/angular/components/pressable/index.d.ts +0 -129
  184. package/build/angular/components/pressable/index.js +0 -473
  185. package/build/angular/components/pressable/index.js.map +0 -1
  186. package/build/angular/components/refresh-control/index.d.ts +0 -90
  187. package/build/angular/components/refresh-control/index.js +0 -380
  188. package/build/angular/components/refresh-control/index.js.map +0 -1
  189. package/build/angular/components/safe-area-view/index.d.ts +0 -62
  190. package/build/angular/components/safe-area-view/index.js +0 -287
  191. package/build/angular/components/safe-area-view/index.js.map +0 -1
  192. package/build/angular/components/scroll-view/index.android.d.ts +0 -20
  193. package/build/angular/components/scroll-view/index.android.js +0 -262
  194. package/build/angular/components/scroll-view/index.android.js.map +0 -1
  195. package/build/angular/components/scroll-view/index.d.ts +0 -3
  196. package/build/angular/components/scroll-view/index.ios.d.ts +0 -8
  197. package/build/angular/components/scroll-view/index.ios.js +0 -92
  198. package/build/angular/components/scroll-view/index.ios.js.map +0 -1
  199. package/build/angular/components/scroll-view/index.js +0 -6
  200. package/build/angular/components/scroll-view/index.js.map +0 -1
  201. package/build/angular/components/scroll-view/projection.d.ts +0 -67
  202. package/build/angular/components/scroll-view/projection.js +0 -560
  203. package/build/angular/components/scroll-view/projection.js.map +0 -1
  204. package/build/angular/components/scroll-view/shared.d.ts +0 -239
  205. package/build/angular/components/scroll-view/shared.js +0 -832
  206. package/build/angular/components/scroll-view/shared.js.map +0 -1
  207. package/build/angular/components/scroll-view/sticky-header.d.ts +0 -40
  208. package/build/angular/components/scroll-view/sticky-header.js +0 -224
  209. package/build/angular/components/scroll-view/sticky-header.js.map +0 -1
  210. package/build/angular/components/switch/index.android.d.ts +0 -24
  211. package/build/angular/components/switch/index.android.js +0 -112
  212. package/build/angular/components/switch/index.android.js.map +0 -1
  213. package/build/angular/components/switch/index.d.ts +0 -1
  214. package/build/angular/components/switch/index.ios.d.ts +0 -23
  215. package/build/angular/components/switch/index.ios.js +0 -111
  216. package/build/angular/components/switch/index.ios.js.map +0 -1
  217. package/build/angular/components/switch/index.js +0 -4
  218. package/build/angular/components/switch/index.js.map +0 -1
  219. package/build/angular/components/switch/shared.d.ts +0 -49
  220. package/build/angular/components/switch/shared.js +0 -191
  221. package/build/angular/components/switch/shared.js.map +0 -1
  222. package/build/angular/components/text-input.d.ts +0 -161
  223. package/build/angular/components/text-input.js +0 -659
  224. package/build/angular/components/text-input.js.map +0 -1
  225. package/build/angular/components/touchable/index.d.ts +0 -276
  226. package/build/angular/components/touchable/index.js +0 -1422
  227. package/build/angular/components/touchable/index.js.map +0 -1
  228. package/build/angular/components/touchable-native-feedback/index.d.ts +0 -86
  229. package/build/angular/components/touchable-native-feedback/index.js +0 -407
  230. package/build/angular/components/touchable-native-feedback/index.js.map +0 -1
  231. package/src/components/activity-indicator/index.android.ts +0 -23
  232. package/src/components/activity-indicator/index.ios.ts +0 -21
  233. package/src/components/activity-indicator/index.ts +0 -4
  234. package/src/components/activity-indicator/shared.ts +0 -225
  235. package/src/components/button.ts +0 -220
  236. package/src/components/image/index.android.ts +0 -99
  237. package/src/components/image/index.ios.ts +0 -99
  238. package/src/components/image/index.ts +0 -3
  239. package/src/components/image-background.ts +0 -290
  240. package/src/components/input-accessory-view/index.ts +0 -240
  241. package/src/components/pressable/index.ts +0 -462
  242. package/src/components/refresh-control/index.ts +0 -340
  243. package/src/components/safe-area-view/index.ts +0 -231
  244. package/src/components/scroll-view/index.android.ts +0 -205
  245. package/src/components/scroll-view/index.ios.ts +0 -81
  246. package/src/components/scroll-view/index.ts +0 -7
  247. package/src/components/scroll-view/projection.ts +0 -713
  248. package/src/components/scroll-view/shared.ts +0 -1066
  249. package/src/components/scroll-view/sticky-header.ts +0 -267
  250. package/src/components/switch/index.android.ts +0 -113
  251. package/src/components/switch/index.ios.ts +0 -112
  252. package/src/components/switch/index.ts +0 -4
  253. package/src/components/switch/shared.ts +0 -284
  254. package/src/components/text-input.ts +0 -613
  255. package/src/components/touchable/index.ts +0 -913
  256. package/src/components/touchable-native-feedback/index.ts +0 -317
@@ -10,6 +10,7 @@ import {
10
10
  type SimpleChanges,
11
11
  } from '@angular/core';
12
12
  import { countAngular } from '../diagnostics';
13
+ import { createCallbackWrapper } from '../change-detection-flush';
13
14
  import {
14
15
  flattenStyle,
15
16
  isSymbioteNode,
@@ -108,18 +109,6 @@ export function stableAnchorStyle(
108
109
  : next;
109
110
  }
110
111
 
111
- const ON_PREFIX = /^on[A-Z]/;
112
-
113
- // The one `onX` that fires per FRAME rather than per gesture, and with sticky headers RN pins
114
- // `scrollEventThrottle` to 1 (ScrollView.js), so 60 times a second. Since markForCheck walks
115
- // RefreshView|Dirty to the ROOT, wrapping it cost one full ancestor-screen template execution per
116
- // frame - the canary's ~37fps scroll (components/virtualized-list/scroll-cost.test.ts).
117
- //
118
- // Nothing lost its refresh: VirtualizedList marks itself when the window moves, sticky rides the
119
- // native driver, and a caller's own handler is typically an Animated.event touching no Angular
120
- // state. Drag/momentum begin/end stay wrapped - once per gesture is not a hot path.
121
- const PER_FRAME_CALLBACK = 'onScroll';
122
-
123
112
  /**
124
113
  * Restores the OnPush dirty-marking Angular skips for a `[style]` binding that a directive
125
114
  * declares as an input. Attach it to any component declaring a `style` input:
@@ -194,7 +183,7 @@ function isAnchorStyleUnchanged(previous: unknown, next: unknown): boolean {
194
183
  }
195
184
 
196
185
  /**
197
- * Base for all Angular primitive host components (`symbiote-view`, `symbiote-text`, ...).
186
+ * Base for all Angular primitive host components (`view`, `text`, ...).
198
187
  * RN's `StyleProp` can be an object, an array, nested arrays, falsy entries, and Animated
199
188
  * values. Angular's raw `[style]` binding on a custom element routes through the CSS style
200
189
  * engine (`setStyle` per key), which crashes on numeric array keys. By declaring `style` as
@@ -265,20 +254,15 @@ export class SymbioteHostPropsDirective {
265
254
  // The directive lives in its HOST component's template, so its injected ChangeDetectorRef IS
266
255
  // that component's own view detector — the one thing that can refresh it (see wrapCallback).
267
256
  private readonly cdr = inject(ChangeDetectorRef);
268
- // One wrapper per ORIGINAL handler, for the lifetime of this directive. Without it every push
269
- // of the props bag allocated a brand-new closure for every `onX` key, and the engine stored it
270
- // as a new listener (`setEventListener` allocates its own closure on top) - per key, per push,
271
- // on a path a scroll frame reaches 60 times a second. The wrapper body closes over nothing but
272
- // `value` and this instance's `cdr`, so the handler alone is a complete cache key; `key` is
273
- // read only by the ON_PREFIX guard above and never enters the wrapper.
274
- //
275
- // Reference stability is the point, not just the allocation: a fresh function on every push
276
- // defeats every downstream identity check on the bag, so nothing upstream could ever conclude
277
- // "this bag is unchanged" while a callback prop was in it.
278
- private readonly wrappers = new WeakMap<
279
- object,
280
- (...args: unknown[]) => unknown
281
- >();
257
+ // A flat-bag `onX` callback (responder negotiation, onLongPress, …) is invoked by the engine's
258
+ // event dispatch a plain JS call, entirely outside Angular so nothing dirties the view that
259
+ // binds its result: the "pan does nothing" bug. Shared with the TAG path's `SymbioteElement`,
260
+ // which has the identical deficit; the mechanism, the `onScroll` exemption and why the wrapper
261
+ // is cached per original handler live in `createCallbackWrapper`.
262
+ private readonly wrapCallback = createCallbackWrapper(
263
+ this.cdr,
264
+ this.elementRef.nativeElement,
265
+ );
282
266
 
283
267
  // Values pushed by the previous bag, so a push writes only what actually moved. Copied rather
284
268
  // than aliased: a component is free to hand back the same object with mutated fields.
@@ -330,21 +314,4 @@ export class SymbioteHostPropsDirective {
330
314
  // (`_cdRefInjectingView`, i.e. the host component), unlike `detectChanges()` which acts on a
331
315
  // resolved `_lView` that is NOT the host component here. The Angular twin of what React/Vue get
332
316
  // for free (setState / proxy reactivity).
333
- private wrapCallback(key: string, value: unknown): unknown {
334
- if (!ON_PREFIX.test(key) || typeof value !== 'function') return value;
335
- if (key === PER_FRAME_CALLBACK) return value;
336
- const cached = this.wrappers.get(value);
337
- if (cached !== undefined) return cached;
338
- // Reflect.apply rather than calling a cast-to-signature local: `typeof value === 'function'`
339
- // narrows to `Function`, which has no call signature TypeScript will accept, and this repo
340
- // does not use `as` to paper over that. `undefined` as the receiver preserves the previous
341
- // unbound call.
342
- const wrapper = (...args: unknown[]): unknown => {
343
- const result: unknown = Reflect.apply(value, undefined, args);
344
- this.cdr.markForCheck();
345
- return result;
346
- };
347
- this.wrappers.set(value, wrapper);
348
- return wrapper;
349
- }
350
317
  }
@@ -0,0 +1,15 @@
1
+ // Side-effect ONLY. Exports nothing, and must never be re-exported from the barrel.
2
+ //
3
+ // The fourteen calls live once, in `@symbiote-native/components/register` — they were identical in
4
+ // all five adapters, and each copy carried a migration ledger justifying a call against a wrapper
5
+ // that no longer exists. What is per-adapter is only the SPELLING of the import below: every
6
+ // `*-tag.test.*` here reaches the registry through `import './register';`, and this adapter's own
7
+ // barrel guard pins that line.
8
+ //
9
+ // WHY A SIDE-EFFECT SUBPATH AND NOT A BARREL EXPORT. Metro turns on `inlineRequires` for PRODUCTION
10
+ // only: it moves a `require` down to the first place its binding is used as a VALUE, and
11
+ // `export { X } from './x'` compiles to a lazy getter. A registration reached that way never
12
+ // evaluates in a Release build — invisible to tsc, to vitest, and to grepping the bundle. A bare
13
+ // `import` placed NEXT TO a re-export of the same specifier does not help either: Babel merges the
14
+ // two into one dependency and the merged dependency stays lazy.
15
+ import '@symbiote-native/components/register';
@@ -54,7 +54,7 @@ function asAngularHost(hostNode: SymbioteSurface | ISymbioteNode): Element {
54
54
  return hostNode as unknown as Element;
55
55
  }
56
56
 
57
- // A bare `symbiote-view` node, created directly through the engine (bypassing Angular's own
57
+ // A bare `view` node, created directly through the engine (bypassing Angular's own
58
58
  // createElement, which only resolves KNOWN symbiote primitives, never an arbitrary component's
59
59
  // selector — see SymbioteRenderer.createElement). Used as the AppRegistry root's host when a
60
60
  // wrapperComponentProvider is set: Angular has no hostElement-less bootstrap for our renderer
@@ -62,7 +62,9 @@ function asAngularHost(hostNode: SymbioteSurface | ISymbioteNode): Element {
62
62
  // that isn't one of our primitives), so the root needs an explicit host too, one we then hand
63
63
  // to the wrapper as projectable content.
64
64
  function createDetachedViewHost(): ISymbioteNode {
65
- const descriptor = descriptorFor('View');
65
+ // 'view', not 'View': the public name is not a Fabric view name, and until
66
+ // makeDescriptorFor learned to reject one it fell through to a view literally named `View`.
67
+ const descriptor = descriptorFor('view');
66
68
  return toPublicInstance(
67
69
  createEngineElement(descriptor.component, descriptor.isText),
68
70
  );
@@ -14,17 +14,23 @@ import {
14
14
  getExplicitStyle,
15
15
  insertBefore,
16
16
  isDebug,
17
+ isSymbioteEvent,
17
18
  isSymbioteNode,
18
19
  removeChild,
19
20
  routeProp,
20
21
  setEventListener,
22
+ setProp,
21
23
  setText,
22
24
  toPublicInstance,
23
25
  RAW_TEXT_COMPONENT,
24
26
  SymbioteSurface,
25
27
  type ISymbioteNode,
26
28
  } from '@symbiote-native/engine';
27
- import { descriptorFor } from '@symbiote-native/components';
29
+ import {
30
+ COMPONENT_DESCRIPTORS,
31
+ descriptorFor,
32
+ } from '@symbiote-native/components';
33
+ import { foldHostBag } from '@symbiote-native/components/fold-host-bag';
28
34
  import type { Renderer2, RendererFactory2, RendererType2 } from '@angular/core';
29
35
  import { isAnchorHostComponent } from '../anchor-host-registry';
30
36
  import {
@@ -32,12 +38,6 @@ import {
32
38
  noteAngularCreate,
33
39
  noteAngularWrite,
34
40
  } from '../diagnostics';
35
- import {
36
- flushScrollViewProjections,
37
- getScrollViewProjection,
38
- removeScrollViewProjectedChild,
39
- } from '../components/scroll-view/projection';
40
-
41
41
  // Angular host nodes are all SymbioteNode (elements, raw text, anchors). The mount
42
42
  // container is the surface, so a parent can be either a node or the surface root.
43
43
  type IHostNode = ISymbioteNode;
@@ -55,6 +55,89 @@ function isRecord(value: unknown): value is Record<string, unknown> {
55
55
  return typeof value === 'object' && value !== null;
56
56
  }
57
57
 
58
+ // RN's Text.js applies two defaults on the way to native (core/components/host-primitives.cjs's
59
+ // `Text.defaults`; the authority on what they MEAN is core/components/src/text-props.ts's
60
+ // resolveTextProps, which the composed `Text` @Component already calls). That component's own
61
+ // host paints directly (Text is not anchor-hosted — see the top-level "View/Text's own component
62
+ // doesn't have this split" reasoning elsewhere in this file), so createElement runs for its INNER
63
+ // text node too; seeding here therefore covers both the composed Text and any bare
64
+ // `text` a future lowering emits, uniformly. Found missing 2026-08-31 (a cross-adapter
65
+ // key-count diff against Vue's real BenchmarkRow.vue) — without this a lowered Text's
66
+ // `numberOfLines` clips with no ellipsis, silently, on device only. Vue's renderer already does
67
+ // this (`adapters/vue/src/renderer/index.ts`'s `seedTextDefaults`); Angular's simply never did.
68
+ //
69
+ // Sourced from `foldHostBag` (`@symbiote-native/components/fold-host-bag`, driven by
70
+ // `HOST_PRIMITIVES.Text.defaults`) rather than a second hardcoded copy — React and Svelte call the
71
+ // same function directly; this used to be a THIRD, independent restatement of the same two
72
+ // defaults, with nothing to catch it drifting from the spec if a default's value ever changed.
73
+ // `foldHostBag('text', {})` on an EMPTY bag folds every default with no authored value to
74
+ // override it (the alias loop has nothing to fold — `id` is only rewritten when present), which is
75
+ // exactly the seed this function needs.
76
+ function seedTextDefaults(node: ISymbioteNode): void {
77
+ const seeded = foldHostBag('text', {});
78
+ for (const [key, value] of Object.entries(seeded)) setProp(node, key, value);
79
+ }
80
+
81
+ // An explicit `undefined` must NOT clear one of those defaults — RN treats a missing prop and an
82
+ // explicit undefined alike, and only a literal `false` opts allowFontScaling out. Reached only
83
+ // when a later write clears a key back to undefined, so it costs nothing on the common path.
84
+ // `foldHostBag` folds every Text default when called this way (not just `key`), because its
85
+ // contract is "fold a whole bag" — the extra key computed alongside `key` is simply unread here.
86
+ function textDefaultFor(el: IHostElement, key: string): unknown {
87
+ if (isSurface(el) || !el.isText) return undefined;
88
+ return foldHostBag('text', { [key]: undefined })[key];
89
+ }
90
+
91
+ // RN's `id` is the modern W3C-named alias for `nativeID` (core/components/host-primitives.cjs's
92
+ // `ID_ALIAS`) — View.js/Text.js copy it over unconditionally, so the two name ONE native prop.
93
+ // React/Solid/Svelte fold it in a wrapper or transform; Angular had it nowhere, so `<view
94
+ // id="x">`/`[id]="x"` reached Fabric with an unknown `id` key and no `nativeID` — silently, on
95
+ // device only. Lives in the renderer (mirroring Vue's `PROP_ALIASES`) so it covers every path
96
+ // that can set a prop — `setAttribute`, `setProperty`, and (should a future lowering emit one) a
97
+ // hand-built call — not just the composed component's own `id` @Input.
98
+ // `symbioteStyle` is what the lowering transform emits in place of `[style]`: Angular routes a
99
+ // `style` binding to its own CSS styling engine, which cannot represent an RN StyleProp (an array
100
+ // throws inside change detection). Under any other name it is an ordinary property binding and
101
+ // arrives here.
102
+ // Angular's two-way sugar `[(value)]` compiles to a `(valueChange)` binding; the engine knows the
103
+ // same fold as the function prop `onValueChange`. See `listen()`. The two names live in a leaf
104
+ // module so `elements.ts`'s ControlValueAccessor can name them without importing this cyclic file.
105
+ import { VALUE_CHANGE_EVENT, VALUE_CHANGE_PROP } from './value-change';
106
+ import { flushViewFor } from '../change-detection-flush';
107
+
108
+ const PROP_ALIASES: ReadonlyMap<string, string> = new Map([
109
+ ['id', 'nativeID'],
110
+ ['symbioteStyle', 'style'],
111
+ ]);
112
+
113
+ function aliasedPropName(name: string): string {
114
+ return PROP_ALIASES.get(name) ?? name;
115
+ }
116
+
117
+ // The app callbacks an engine behavior READS BACK inside the same microtask turn, as an Angular
118
+ // `(event)` binding — `valueChange` is handled in `listen` on its own, since it also needs the field
119
+ // unwrapped. Zoneless change detection is a macrotask, so without a flush the behavior reads the
120
+ // PRE-event value; `../change-detection-flush` holds the whole mechanism, the three behaviors, and
121
+ // why this is scoped rather than wired to the engine's event-dispatch seam.
122
+ //
123
+ // The other spelling — the `[onRefresh]` flat-bag PROP — is not here: an `on*` function prop is
124
+ // wrapped by `SymbioteElement` itself, which reaches every one of them rather than a named three,
125
+ // and adds the `markForCheck` a prop callback needs and an event binding gets from Angular.
126
+ const READ_BACK_EVENTS: ReadonlySet<string> = new Set(['refresh']);
127
+
128
+ type IReadBackListener = (event: unknown) => unknown;
129
+
130
+ function withChangeDetection(
131
+ node: IHostElement,
132
+ listener: IReadBackListener,
133
+ ): IReadBackListener {
134
+ return (event: unknown): unknown => {
135
+ const result = listener(event);
136
+ flushViewFor(node);
137
+ return result;
138
+ };
139
+ }
140
+
58
141
  // Diagnostic-only: tags each anchor with a sequential id so log lines can tell distinct
59
142
  // anchors apart (they all otherwise print the same generic '#anchor' component name).
60
143
  // Gated behind isDebug() so a production build pays zero cost (no WeakMap writes).
@@ -79,23 +162,51 @@ function describeHost(node: IHostElement | null | undefined): string {
79
162
  : node.component;
80
163
  }
81
164
 
165
+ // A hand-written tag ngtsc accepts must contain a HYPHEN, so the six dashless intrinsics
166
+ // (`view`/`text`/`pressable`/`image`/`switch`/`modal`) need a second spelling that has one.
167
+ // `hasElement`/`hasProperty` gate the CUSTOM_ELEMENTS_SCHEMA branch behind
168
+ // `normalizedTag.includes('-')` (compiler/src/schema/dom_element_schema_registry.ts), so a dashless
169
+ // tag is NG8001 under every schema but NO_ERRORS_SCHEMA — which switches off element checking
170
+ // entirely. Dropping the `symbiote-` prefix from the tag alphabet is what took the dash away.
171
+ //
172
+ // A per-tag directive is the other repair, and it is the one an app should reach for now that
173
+ // `SYMBIOTE_ELEMENTS` exists (`../elements.ts`). Matching a directive does turn every bound prop
174
+ // into an input lookup — the sentence that used to end this paragraph — but that is a repair
175
+ // rather than a dead end: declare the input and the lookup succeeds, with a real TYPE, which no
176
+ // schema gives. This alias map stays for the `symbiote-*` spelling and for an app that has not
177
+ // imported the directives.
178
+ //
179
+ // Derived, so a future dashless intrinsic joins by existing; when the alphabet regains its dashes
180
+ // upstream every entry becomes identity and the map can go. See `bare-intrinsic-tag-aot.test.ts`.
181
+ const HYPHEN_PREFIX = 'symbiote-';
182
+
183
+ function hyphenatedIntrinsicAliases(): Record<string, string> {
184
+ const aliases: Record<string, string> = {};
185
+ for (const tag of Object.keys(COMPONENT_DESCRIPTORS)) {
186
+ if (tag.includes('-')) continue;
187
+ aliases[`${HYPHEN_PREFIX}${tag}`] = tag;
188
+ }
189
+ return aliases;
190
+ }
191
+
82
192
  const PRIMITIVE_SELECTOR_ALIAS: Record<string, string> = {
83
193
  // Public ergonomic selectors map directly to the engine primitive descriptors.
84
- View: 'symbiote-view',
85
- Text: 'symbiote-text',
194
+ View: 'view',
195
+ Text: 'text',
196
+ ...hyphenatedIntrinsicAliases(),
86
197
  };
87
198
 
88
199
  // The ANCHOR_HOST_COMPONENTS Set and registerComposedComponent now live in the dependency-free
89
200
  // leaf module ../anchor-host-registry (imported above as isAnchorHostComponent) — see its header
90
201
  // for why the registry must NOT sit in this require-cyclic renderer module.
91
202
 
92
- // Inserting a bare raw-text node anywhere but inside a <Text> is invalid in Fabric (a
93
- // stray RCTRawText would paint). Angular's ɵɵtext only ever lands text inside a <Text>,
203
+ // Inserting a bare raw-text node anywhere but inside a <text> is invalid in Fabric (a
204
+ // stray RCTRawText would paint). Angular's ɵɵtext only ever lands text inside a <text>,
94
205
  // but guard anyway for parity with the Vue adapter and to fail loudly on a bad template.
95
206
  function assertTextPlacement(child: ISymbioteNode, parent: IHostElement): void {
96
207
  if (isRawText(child) && (isSurface(parent) || !parent.isText)) {
97
208
  throw new Error(
98
- `Text string "${String(child.props.text)}" must be rendered inside a <Text>`,
209
+ `Text string "${String(child.props.text)}" must be rendered inside a <text>`,
99
210
  );
100
211
  }
101
212
  }
@@ -114,27 +225,55 @@ export class SymbioteRenderer implements Renderer2 {
114
225
  destroy(): void {}
115
226
 
116
227
  createElement(name: string): IHostNode {
117
- // `name` is the component's host tag — a symbiote intrinsic (`symbiote-view`,
118
- // `symbiote-text`, …), a public ergonomic alias (`View`, `Text`), or a raw Fabric view
228
+ // `name` is the component's host tag — a symbiote intrinsic (`view`,
229
+ // `text`, …), a public ergonomic alias (`View`, `Text`), or a raw Fabric view
119
230
  // name for a native leaf. Public aliases are normalized to their engine primitive name
120
231
  // before descriptor lookup. descriptorFor resolves it; an unknown `symbiote-*` is a typo,
121
232
  // any other string flows through as a raw Fabric name (events/processors derived from its
122
- // ViewConfig). toPublicInstance grafts the imperative API (measure / setNativeProps /
123
- // focus) onto the raw node in place, returning the SAME identity the commit mirror keys on.
233
+ // ViewConfig). The imperative API (measure / setNativeProps / focus) is on the node's
234
+ // prototype, so toPublicInstance hands back the SAME identity the commit mirror keys on.
124
235
  countAngular('nodesCreated');
125
236
  noteAngularCreate(name);
126
237
  const engineName = PRIMITIVE_SELECTOR_ALIAS[name] ?? name;
127
- if (isAnchorHostComponent(engineName)) {
238
+
239
+ // An INTRINSIC is never an anchor, and the check has to come first now that the tags carry no
240
+ // prefix. The anchor registry is keyed on lowercased selectors — Angular lowercases a
241
+ // dynamically-mounted component's selector at runtime, so it must be — and the composed
242
+ // wrappers are named after the primitives they render: `Text`.toLowerCase() IS the tag `text`.
243
+ // While both layers exist, every `<text>` would anchor instead of painting.
244
+ //
245
+ // Derived from the descriptor table rather than an exclusion list, so it cannot go stale; and
246
+ // it disappears on its own when the wrappers do, which is what this migration is for. The
247
+ // collision is exactly the single-word names — `TextInput` lowercases to `textinput`, which is
248
+ // no tag of ours.
249
+ if (
250
+ COMPONENT_DESCRIPTORS[engineName] === undefined &&
251
+ isAnchorHostComponent(engineName)
252
+ ) {
128
253
  const anchor = tagAnchorForDebug(createAnchor());
129
- dlog(
130
- `angular createElement ${name} -> anchor host ${describeHost(anchor)}`,
131
- );
254
+ if (isDebug()) {
255
+ dlog(
256
+ `angular createElement ${name} -> anchor host ${describeHost(anchor)}`,
257
+ );
258
+ }
132
259
  return anchor;
133
260
  }
134
261
 
135
262
  const descriptor = descriptorFor(engineName);
136
- const node = createElement(descriptor.component, descriptor.isText);
137
- dlog(`angular createElement ${name} -> ${descriptor.component}`);
263
+ // The tag, not just the resolved Fabric name: the host-behavior registry is keyed by the
264
+ // INTRINSIC tag (host-behavior.ts's own comment), and a node only ever carries the resolved
265
+ // name afterward. Omitting this argument means attachHostBehavior looks up the WRONG key
266
+ // (e.g. 'RCTView') and any registered behavior silently never attaches — Vue's renderer
267
+ // already passes this correctly (`createElement(descriptor.component, descriptor.isText, type)`).
268
+ const node = createElement(
269
+ descriptor.component,
270
+ descriptor.isText,
271
+ engineName,
272
+ );
273
+ if (descriptor.isText) seedTextDefaults(node);
274
+ if (isDebug()) {
275
+ dlog(`angular createElement ${name} -> ${descriptor.component}`);
276
+ }
138
277
  return toPublicInstance(node);
139
278
  }
140
279
 
@@ -144,7 +283,9 @@ export class SymbioteRenderer implements Renderer2 {
144
283
  // Vue createComment path.
145
284
  countAngular('nodesCreated');
146
285
  const anchor = tagAnchorForDebug(createAnchor());
147
- dlog(`Angular renderer createComment -> ${describeHost(anchor)}`);
286
+ if (isDebug()) {
287
+ dlog(`Angular renderer createComment -> ${describeHost(anchor)}`);
288
+ }
148
289
  return anchor;
149
290
  }
150
291
 
@@ -161,22 +302,22 @@ export class SymbioteRenderer implements Renderer2 {
161
302
  countAngular('nodesInserted');
162
303
  assertTextPlacement(newChild, parent);
163
304
  if (isSurface(parent)) {
164
- dlog(
165
- `Angular renderer appendChild parent=surface child=${describeHost(newChild)}`,
166
- );
305
+ if (isDebug()) {
306
+ dlog(
307
+ `Angular renderer appendChild parent=surface child=${describeHost(newChild)}`,
308
+ );
309
+ }
167
310
  parent.appendChild(newChild);
168
311
  } else {
169
- const projection = getScrollViewProjection(parent);
170
- dlog(
171
- `Angular renderer appendChild parent=${describeHost(parent)} child=${describeHost(newChild)} projection=${projection !== undefined}`,
172
- );
173
- if (projection !== undefined) {
174
- projection.appendProjectedChild(parent, newChild, (target, child) =>
175
- appendChild(target, child),
312
+ // The engine's own `appendChild` already redirects through `parent.childHost` when the
313
+ // primitive's behavior builds one (ScrollView's content node, e.g.) — the adapter-side
314
+ // projection bridge this used to route through is gone with the ScrollView component.
315
+ if (isDebug()) {
316
+ dlog(
317
+ `Angular renderer appendChild parent=${describeHost(parent)} child=${describeHost(newChild)}`,
176
318
  );
177
- } else {
178
- appendChild(parent, newChild);
179
319
  }
320
+ appendChild(parent, newChild);
180
321
  }
181
322
  this.surface.requestCommit();
182
323
  }
@@ -190,31 +331,21 @@ export class SymbioteRenderer implements Renderer2 {
190
331
  countAngular('nodesInserted');
191
332
  assertTextPlacement(newChild, parent);
192
333
  if (isSurface(parent)) {
193
- dlog(
194
- `Angular renderer insertBefore parent=surface child=${describeHost(newChild)} ref=${refChild ? describeHost(refChild) : 'null'}`,
195
- );
334
+ if (isDebug()) {
335
+ dlog(
336
+ `Angular renderer insertBefore parent=surface child=${describeHost(newChild)} ref=${refChild ? describeHost(refChild) : 'null'}`,
337
+ );
338
+ }
196
339
  if (refChild) parent.insertBefore(newChild, refChild);
197
340
  else parent.appendChild(newChild);
198
341
  } else {
199
- const projection = getScrollViewProjection(parent);
200
- dlog(
201
- `Angular renderer insertBefore parent=${describeHost(parent)} child=${describeHost(newChild)} ref=${refChild ? describeHost(refChild) : 'null'} projection=${projection !== undefined}`,
202
- );
203
- if (projection !== undefined) {
204
- projection.insertProjectedChild(
205
- parent,
206
- newChild,
207
- refChild,
208
- (target, child, before) => {
209
- if (before === undefined) appendChild(target, child);
210
- else insertBefore(target, child, before);
211
- },
342
+ if (isDebug()) {
343
+ dlog(
344
+ `Angular renderer insertBefore parent=${describeHost(parent)} child=${describeHost(newChild)} ref=${refChild ? describeHost(refChild) : 'null'}`,
212
345
  );
213
- } else if (refChild) {
214
- insertBefore(parent, newChild, refChild);
215
- } else {
216
- appendChild(parent, newChild);
217
346
  }
347
+ if (refChild) insertBefore(parent, newChild, refChild);
348
+ else appendChild(parent, newChild);
218
349
  }
219
350
  this.surface.requestCommit();
220
351
  }
@@ -224,21 +355,17 @@ export class SymbioteRenderer implements Renderer2 {
224
355
  // surface.children with no parent). Angular's `parent` arg is ignored in favor of the
225
356
  // authoritative link, mirroring the Vue adapter's remove.
226
357
  countAngular('nodesRemoved');
227
- const angularParent = _parent !== null ? describeHost(_parent) : 'null';
228
- const retainedParent =
229
- oldChild.parent !== undefined ? describeHost(oldChild.parent) : 'none';
230
- const wasProjected = removeScrollViewProjectedChild(
231
- oldChild,
232
- (parent, child) => removeChild(parent, child),
233
- );
234
- dlog(
235
- `Angular renderer removeChild angularParent=${angularParent} retainedParent=${retainedParent} child=${describeHost(oldChild)} viaProjection=${wasProjected}`,
236
- );
237
- if (!wasProjected) {
238
- const parent = oldChild.parent;
239
- if (parent !== undefined) removeChild(parent, oldChild);
240
- else this.surface.removeChild(oldChild);
358
+ if (isDebug()) {
359
+ const angularParent = _parent !== null ? describeHost(_parent) : 'null';
360
+ const retainedParent =
361
+ oldChild.parent !== undefined ? describeHost(oldChild.parent) : 'none';
362
+ dlog(
363
+ `Angular renderer removeChild angularParent=${angularParent} retainedParent=${retainedParent} child=${describeHost(oldChild)}`,
364
+ );
241
365
  }
366
+ const parent = oldChild.parent;
367
+ if (parent !== undefined) removeChild(parent, oldChild);
368
+ else this.surface.removeChild(oldChild);
242
369
  this.surface.requestCommit();
243
370
  }
244
371
 
@@ -278,7 +405,7 @@ export class SymbioteRenderer implements Renderer2 {
278
405
  if (isSurface(el)) return;
279
406
  countAngular('rendererWrites');
280
407
  noteAngularWrite(name);
281
- routeProp(el, name, value);
408
+ routeProp(el, aliasedPropName(name), value);
282
409
  this.surface.requestCommit();
283
410
  }
284
411
 
@@ -286,7 +413,8 @@ export class SymbioteRenderer implements Renderer2 {
286
413
  if (isSurface(el)) return;
287
414
  countAngular('rendererWrites');
288
415
  noteAngularWrite(name);
289
- routeProp(el, name, undefined);
416
+ const aliased = aliasedPropName(name);
417
+ routeProp(el, aliased, textDefaultFor(el, aliased));
290
418
  this.surface.requestCommit();
291
419
  }
292
420
 
@@ -353,7 +481,12 @@ export class SymbioteRenderer implements Renderer2 {
353
481
  if (isSurface(el)) return;
354
482
  countAngular('rendererWrites');
355
483
  noteAngularWrite(name);
356
- routeProp(el, name, value);
484
+ const aliased = aliasedPropName(name);
485
+ routeProp(
486
+ el,
487
+ aliased,
488
+ value === undefined ? textDefaultFor(el, aliased) : value,
489
+ );
357
490
  this.surface.requestCommit();
358
491
  }
359
492
 
@@ -362,7 +495,9 @@ export class SymbioteRenderer implements Renderer2 {
362
495
  noteAngularWrite('#text');
363
496
  // A useful permanent seam: text mutations are low-frequency and the one place a stale
364
497
  // `{{binding}}` (a change-detection gap) shows up as "the setValue never fired".
365
- dlog(`Angular renderer setValue "${value}" on ${describeHost(node)}`);
498
+ if (isDebug()) {
499
+ dlog(`Angular renderer setValue "${value}" on ${describeHost(node)}`);
500
+ }
366
501
  setText(node, value);
367
502
  this.surface.requestCommit();
368
503
  }
@@ -377,7 +512,34 @@ export class SymbioteRenderer implements Renderer2 {
377
512
  callback: (event: unknown) => boolean | void,
378
513
  ): () => void {
379
514
  if (!isSymbioteNode(target)) return () => {};
380
- setEventListener(target, eventName, callback);
515
+ // `[(value)]` desugars to `(valueChange)`, which is the spelling every Angular template writes
516
+ // for a Switch or a TextInput. On the COMPONENT path it is an `@Output()` the wrapper derives
517
+ // from the raw `change` payload; on a LOWERED element there is no component, and registering
518
+ // `valueChange` as an engine event would wait forever for a Fabric event of that name.
519
+ //
520
+ // The lowered path already carries the same fold under RN's own spelling: both behaviors call
521
+ // `node.props.onValueChange(event)` — a plain function PROP, not an event
522
+ // (`behaviors/switch.ts`, `behaviors/text-input.ts`), with `text`/`value` carried as a FIELD on
523
+ // the event object rather than a second argument (Svelte forces every individual `on*` prop
524
+ // through a native listener that calls with exactly one argument, always a real object). So
525
+ // Angular's own `[(value)]` sugar needs one extra step its React/Vue/Solid counterparts do not:
526
+ // unwrap that field back to a bare value before handing it to Angular's callback, or `text =
527
+ // $event` would assign the whole event object instead of the typed string/boolean.
528
+ if (eventName === VALUE_CHANGE_EVENT) {
529
+ const forwardValue = withChangeDetection(target, (event: unknown) => {
530
+ if (isSymbioteEvent(event)) {
531
+ if ('text' in event) return callback(event.text);
532
+ if ('value' in event) return callback(event.value);
533
+ }
534
+ return callback(event);
535
+ });
536
+ routeProp(target, VALUE_CHANGE_PROP, forwardValue);
537
+ return () => routeProp(target, VALUE_CHANGE_PROP, undefined);
538
+ }
539
+ const listener = READ_BACK_EVENTS.has(eventName)
540
+ ? withChangeDetection(target, callback)
541
+ : callback;
542
+ setEventListener(target, eventName, listener);
381
543
  return () => setEventListener(target, eventName, undefined);
382
544
  }
383
545
  }
@@ -397,13 +559,10 @@ export class SymbioteRendererFactory implements RendererFactory2 {
397
559
  return (this.renderer ??= new SymbioteRenderer(this.surface));
398
560
  }
399
561
 
400
- // Not commit coalescing (requestCommit owns that) — this is the one moment where a ScrollView's
401
- // two input channels are known to be consistent: Angular has finished writing every `@Input` AND
402
- // the renderer has finished every projected insert/remove for this pass, while the surface's
403
- // commit is still only queued. Sticky projection reconciles are batched to here for both reasons;
404
- // see flushScrollViewProjections.
562
+ // Not commit coalescing (requestCommit owns that) — a per-CD-pass counter only, now that the
563
+ // ScrollView projection bridge this used to also flush is gone (`../register.ts`'s
564
+ // `registerScrollViewBehavior` owns the content node and the sticky seam for every adapter).
405
565
  end(): void {
406
566
  countAngular('cdPasses');
407
- flushScrollViewProjections();
408
567
  }
409
568
  }
@@ -0,0 +1,8 @@
1
+ // The two names Angular's `[(value)]` sugar rides on, in a dependency-free LEAF so `elements.ts`
2
+ // can name the event without importing the require-cyclic `renderer/index.ts` (same reasoning as
3
+ // `anchor-host-registry.ts`).
4
+ //
5
+ // `[(value)]` desugars to a `(valueChange)` binding, which is no Fabric event — the renderer
6
+ // translates it to the `onValueChange` PROP both behaviors already call.
7
+ export const VALUE_CHANGE_EVENT = 'valueChange';
8
+ export const VALUE_CHANGE_PROP = 'onValueChange';
@@ -1,13 +0,0 @@
1
- import { ActivityIndicatorBase } from './shared';
2
- import * as i0 from "@angular/core";
3
- import * as i1 from "../../primitives/shared";
4
- export type { IActivityIndicatorProps } from './shared';
5
- export declare class ActivityIndicator extends ActivityIndicatorBase {
6
- protected readonly defaultColor: null;
7
- protected readonly nativeExtras: {
8
- styleAttr: string;
9
- indeterminate: boolean;
10
- };
11
- static ɵfac: i0.ɵɵFactoryDeclaration<ActivityIndicator, never>;
12
- static ɵcmp: i0.ɵɵComponentDeclaration<ActivityIndicator, "ActivityIndicator", never, {}, {}, never, never, true, [{ directive: typeof i1.SymbioteStyleInputDirective; inputs: { "style": "style"; }; outputs: {}; }]>;
13
- }
@@ -1,29 +0,0 @@
1
- import { ChangeDetectionStrategy, Component } from '@angular/core';
2
- import { DescriptorOutlet } from '../../descriptor-to-angular';
3
- import { ActivityIndicatorBase } from './shared';
4
- import { SymbioteStyleInputDirective } from '../../primitives';
5
- import * as i0 from "@angular/core";
6
- import * as i1 from "../../primitives/shared";
7
- export class ActivityIndicator extends ActivityIndicatorBase {
8
- defaultColor = null;
9
- nativeExtras = {
10
- styleAttr: 'Normal',
11
- indeterminate: true,
12
- };
13
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ActivityIndicator, deps: null, target: i0.ɵɵFactoryTarget.Component });
14
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.8", type: ActivityIndicator, isStandalone: true, selector: "ActivityIndicator", usesInheritance: true, hostDirectives: [{ directive: i1.SymbioteStyleInputDirective, inputs: ["style", "style"] }], ngImport: i0, template: `<symbiote-descriptor-outlet [node]="descriptor" />`, isInline: true, dependencies: [{ kind: "component", type: DescriptorOutlet, selector: "symbiote-descriptor-outlet", inputs: ["node"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
15
- }
16
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ActivityIndicator, decorators: [{
17
- type: Component,
18
- args: [{
19
- selector: 'ActivityIndicator',
20
- standalone: true,
21
- hostDirectives: [
22
- { directive: SymbioteStyleInputDirective, inputs: ['style'] },
23
- ],
24
- imports: [DescriptorOutlet],
25
- changeDetection: ChangeDetectionStrategy.OnPush,
26
- template: `<symbiote-descriptor-outlet [node]="descriptor" />`,
27
- }]
28
- }] });
29
- //# sourceMappingURL=index.android.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.android.js","sourceRoot":"","sources":["../../../../src/components/activity-indicator/index.android.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;;;AAa/D,MAAM,OAAO,iBAAkB,SAAQ,qBAAqB;IACvC,YAAY,GAAG,IAAI,CAAC;IACX,YAAY,GAAG;QACzC,SAAS,EAAE,QAAQ;QACnB,aAAa,EAAE,IAAI;KACpB,CAAC;uGALS,iBAAiB;2FAAjB,iBAAiB,iMAFlB,oDAAoD,4DAFpD,gBAAgB;;2FAIf,iBAAiB;kBAV7B,SAAS;mBAAC;oBACT,QAAQ,EAAE,mBAAmB;oBAC7B,UAAU,EAAE,IAAI;oBAChB,cAAc,EAAE;wBACd,EAAE,SAAS,EAAE,2BAA2B,EAAE,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE;qBAC9D;oBACD,OAAO,EAAE,CAAC,gBAAgB,CAAC;oBAC3B,eAAe,EAAE,uBAAuB,CAAC,MAAM;oBAC/C,QAAQ,EAAE,oDAAoD;iBAC/D"}