@symbiote-native/angular 0.1.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 (372) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +147 -0
  3. package/build/angular/components/activity-indicator/index.android.d.ts +12 -0
  4. package/build/angular/components/activity-indicator/index.android.js +21 -0
  5. package/build/angular/components/activity-indicator/index.android.js.map +1 -0
  6. package/build/angular/components/activity-indicator/index.d.ts +1 -0
  7. package/build/angular/components/activity-indicator/index.ios.d.ts +8 -0
  8. package/build/angular/components/activity-indicator/index.ios.js +21 -0
  9. package/build/angular/components/activity-indicator/index.ios.js.map +1 -0
  10. package/build/angular/components/activity-indicator/index.js +4 -0
  11. package/build/angular/components/activity-indicator/index.js.map +1 -0
  12. package/build/angular/components/activity-indicator/shared.d.ts +67 -0
  13. package/build/angular/components/activity-indicator/shared.js +260 -0
  14. package/build/angular/components/activity-indicator/shared.js.map +1 -0
  15. package/build/angular/components/button.d.ts +63 -0
  16. package/build/angular/components/button.js +332 -0
  17. package/build/angular/components/button.js.map +1 -0
  18. package/build/angular/components/drawer-layout-android/index.android.d.ts +34 -0
  19. package/build/angular/components/drawer-layout-android/index.android.js +291 -0
  20. package/build/angular/components/drawer-layout-android/index.android.js.map +1 -0
  21. package/build/angular/components/drawer-layout-android/index.d.ts +11 -0
  22. package/build/angular/components/drawer-layout-android/index.js +109 -0
  23. package/build/angular/components/drawer-layout-android/index.js.map +1 -0
  24. package/build/angular/components/drawer-layout-android/shared.d.ts +74 -0
  25. package/build/angular/components/drawer-layout-android/shared.js +138 -0
  26. package/build/angular/components/drawer-layout-android/shared.js.map +1 -0
  27. package/build/angular/components/flat-list/index.d.ts +122 -0
  28. package/build/angular/components/flat-list/index.js +689 -0
  29. package/build/angular/components/flat-list/index.js.map +1 -0
  30. package/build/angular/components/image/index.android.d.ts +10 -0
  31. package/build/angular/components/image/index.android.js +59 -0
  32. package/build/angular/components/image/index.android.js.map +1 -0
  33. package/build/angular/components/image/index.d.ts +1 -0
  34. package/build/angular/components/image/index.ios.d.ts +10 -0
  35. package/build/angular/components/image/index.ios.js +59 -0
  36. package/build/angular/components/image/index.ios.js.map +1 -0
  37. package/build/angular/components/image/index.js +3 -0
  38. package/build/angular/components/image/index.js.map +1 -0
  39. package/build/angular/components/image/shared.d.ts +101 -0
  40. package/build/angular/components/image/shared.js +408 -0
  41. package/build/angular/components/image/shared.js.map +1 -0
  42. package/build/angular/components/image-background.d.ts +81 -0
  43. package/build/angular/components/image-background.js +418 -0
  44. package/build/angular/components/image-background.js.map +1 -0
  45. package/build/angular/components/input-accessory-view.d.ts +59 -0
  46. package/build/angular/components/input-accessory-view.js +266 -0
  47. package/build/angular/components/input-accessory-view.js.map +1 -0
  48. package/build/angular/components/keyboard-avoiding-view.d.ts +82 -0
  49. package/build/angular/components/keyboard-avoiding-view.js +363 -0
  50. package/build/angular/components/keyboard-avoiding-view.js.map +1 -0
  51. package/build/angular/components/modal.d.ts +92 -0
  52. package/build/angular/components/modal.js +365 -0
  53. package/build/angular/components/modal.js.map +1 -0
  54. package/build/angular/components/pressable/index.d.ts +123 -0
  55. package/build/angular/components/pressable/index.js +421 -0
  56. package/build/angular/components/pressable/index.js.map +1 -0
  57. package/build/angular/components/refresh-control.d.ts +86 -0
  58. package/build/angular/components/refresh-control.js +347 -0
  59. package/build/angular/components/refresh-control.js.map +1 -0
  60. package/build/angular/components/safe-area-view.d.ts +57 -0
  61. package/build/angular/components/safe-area-view.js +253 -0
  62. package/build/angular/components/safe-area-view.js.map +1 -0
  63. package/build/angular/components/scroll-view/index.android.d.ts +21 -0
  64. package/build/angular/components/scroll-view/index.android.js +235 -0
  65. package/build/angular/components/scroll-view/index.android.js.map +1 -0
  66. package/build/angular/components/scroll-view/index.d.ts +3 -0
  67. package/build/angular/components/scroll-view/index.ios.d.ts +9 -0
  68. package/build/angular/components/scroll-view/index.ios.js +86 -0
  69. package/build/angular/components/scroll-view/index.ios.js.map +1 -0
  70. package/build/angular/components/scroll-view/index.js +6 -0
  71. package/build/angular/components/scroll-view/index.js.map +1 -0
  72. package/build/angular/components/scroll-view/projection.d.ts +32 -0
  73. package/build/angular/components/scroll-view/projection.js +312 -0
  74. package/build/angular/components/scroll-view/projection.js.map +1 -0
  75. package/build/angular/components/scroll-view/shared.d.ts +230 -0
  76. package/build/angular/components/scroll-view/shared.js +679 -0
  77. package/build/angular/components/scroll-view/shared.js.map +1 -0
  78. package/build/angular/components/scroll-view/sticky-header.d.ts +41 -0
  79. package/build/angular/components/scroll-view/sticky-header.js +208 -0
  80. package/build/angular/components/scroll-view/sticky-header.js.map +1 -0
  81. package/build/angular/components/section-list/index.d.ts +116 -0
  82. package/build/angular/components/section-list/index.js +641 -0
  83. package/build/angular/components/section-list/index.js.map +1 -0
  84. package/build/angular/components/switch/index.android.d.ts +20 -0
  85. package/build/angular/components/switch/index.android.js +70 -0
  86. package/build/angular/components/switch/index.android.js.map +1 -0
  87. package/build/angular/components/switch/index.d.ts +1 -0
  88. package/build/angular/components/switch/index.ios.d.ts +19 -0
  89. package/build/angular/components/switch/index.ios.js +69 -0
  90. package/build/angular/components/switch/index.ios.js.map +1 -0
  91. package/build/angular/components/switch/index.js +4 -0
  92. package/build/angular/components/switch/index.js.map +1 -0
  93. package/build/angular/components/switch/shared.d.ts +40 -0
  94. package/build/angular/components/switch/shared.js +127 -0
  95. package/build/angular/components/switch/shared.js.map +1 -0
  96. package/build/angular/components/text-input.d.ts +153 -0
  97. package/build/angular/components/text-input.js +604 -0
  98. package/build/angular/components/text-input.js.map +1 -0
  99. package/build/angular/components/touchable-native-feedback.d.ts +83 -0
  100. package/build/angular/components/touchable-native-feedback.js +376 -0
  101. package/build/angular/components/touchable-native-feedback.js.map +1 -0
  102. package/build/angular/components/touchable.d.ts +248 -0
  103. package/build/angular/components/touchable.js +1206 -0
  104. package/build/angular/components/touchable.js.map +1 -0
  105. package/build/angular/components/virtualized-list/directives.d.ts +54 -0
  106. package/build/angular/components/virtualized-list/directives.js +154 -0
  107. package/build/angular/components/virtualized-list/directives.js.map +1 -0
  108. package/build/angular/components/virtualized-list/index.d.ts +268 -0
  109. package/build/angular/components/virtualized-list/index.js +1162 -0
  110. package/build/angular/components/virtualized-list/index.js.map +1 -0
  111. package/build/angular/components/virtualized-section-list/directives.d.ts +37 -0
  112. package/build/angular/components/virtualized-section-list/directives.js +77 -0
  113. package/build/angular/components/virtualized-section-list/directives.js.map +1 -0
  114. package/build/angular/components/virtualized-section-list/index.d.ts +178 -0
  115. package/build/angular/components/virtualized-section-list/index.js +722 -0
  116. package/build/angular/components/virtualized-section-list/index.js.map +1 -0
  117. package/build/angular/components.d.ts +39 -0
  118. package/build/angular/components.js +38 -0
  119. package/build/angular/components.js.map +1 -0
  120. package/build/angular/create-portal.d.ts +22 -0
  121. package/build/angular/create-portal.js +74 -0
  122. package/build/angular/create-portal.js.map +1 -0
  123. package/build/angular/create-tunnel.d.ts +34 -0
  124. package/build/angular/create-tunnel.js +126 -0
  125. package/build/angular/create-tunnel.js.map +1 -0
  126. package/build/angular/descriptor-to-angular/index.d.ts +22 -0
  127. package/build/angular/descriptor-to-angular/index.js +142 -0
  128. package/build/angular/descriptor-to-angular/index.js.map +1 -0
  129. package/build/angular/host-instance/index.d.ts +2 -0
  130. package/build/angular/host-instance/index.js +37 -0
  131. package/build/angular/host-instance/index.js.map +1 -0
  132. package/build/angular/index.d.ts +21 -0
  133. package/build/angular/index.js +42 -0
  134. package/build/angular/index.js.map +1 -0
  135. package/build/angular/modules/animated/create-animated-component.d.ts +68 -0
  136. package/build/angular/modules/animated/create-animated-component.js +429 -0
  137. package/build/angular/modules/animated/create-animated-component.js.map +1 -0
  138. package/build/angular/modules/animated/index.d.ts +51 -0
  139. package/build/angular/modules/animated/index.js +59 -0
  140. package/build/angular/modules/animated/index.js.map +1 -0
  141. package/build/angular/modules/app-registry/index.d.ts +7 -0
  142. package/build/angular/modules/app-registry/index.js +23 -0
  143. package/build/angular/modules/app-registry/index.js.map +1 -0
  144. package/build/angular/modules/status-bar.d.ts +20 -0
  145. package/build/angular/modules/status-bar.js +59 -0
  146. package/build/angular/modules/status-bar.js.map +1 -0
  147. package/build/angular/primitives/index.d.ts +63 -0
  148. package/build/angular/primitives/index.js +189 -0
  149. package/build/angular/primitives/index.js.map +1 -0
  150. package/build/angular/primitives/shared.d.ts +89 -0
  151. package/build/angular/primitives/shared.js +172 -0
  152. package/build/angular/primitives/shared.js.map +1 -0
  153. package/build/angular/render.d.ts +11 -0
  154. package/build/angular/render.js +161 -0
  155. package/build/angular/render.js.map +1 -0
  156. package/build/angular/renderer.d.ts +38 -0
  157. package/build/angular/renderer.js +360 -0
  158. package/build/angular/renderer.js.map +1 -0
  159. package/build/angular/services/color-scheme.service.d.ts +16 -0
  160. package/build/angular/services/color-scheme.service.js +31 -0
  161. package/build/angular/services/color-scheme.service.js.map +1 -0
  162. package/build/angular/services/index.d.ts +2 -0
  163. package/build/angular/services/index.js +3 -0
  164. package/build/angular/services/index.js.map +1 -0
  165. package/build/angular/services/window-dimensions.service.d.ts +16 -0
  166. package/build/angular/services/window-dimensions.service.js +42 -0
  167. package/build/angular/services/window-dimensions.service.js.map +1 -0
  168. package/build/components/activity-indicator/index.android.d.ts +9 -0
  169. package/build/components/activity-indicator/index.android.js +64 -0
  170. package/build/components/activity-indicator/index.d.ts +1 -0
  171. package/build/components/activity-indicator/index.ios.d.ts +5 -0
  172. package/build/components/activity-indicator/index.ios.js +64 -0
  173. package/build/components/activity-indicator/index.js +3 -0
  174. package/build/components/activity-indicator/shared.d.ts +64 -0
  175. package/build/components/activity-indicator/shared.js +424 -0
  176. package/build/components/button.d.ts +60 -0
  177. package/build/components/button.js +456 -0
  178. package/build/components/drawer-layout-android/index.android.d.ts +29 -0
  179. package/build/components/drawer-layout-android/index.android.js +326 -0
  180. package/build/components/drawer-layout-android/index.d.ts +8 -0
  181. package/build/components/drawer-layout-android/index.js +145 -0
  182. package/build/components/drawer-layout-android/shared.d.ts +71 -0
  183. package/build/components/drawer-layout-android/shared.js +205 -0
  184. package/build/components/flat-list/index.d.ts +119 -0
  185. package/build/components/flat-list/index.js +692 -0
  186. package/build/components/image/index.android.d.ts +7 -0
  187. package/build/components/image/index.android.js +88 -0
  188. package/build/components/image/index.d.ts +1 -0
  189. package/build/components/image/index.ios.d.ts +7 -0
  190. package/build/components/image/index.ios.js +88 -0
  191. package/build/components/image/index.js +2 -0
  192. package/build/components/image/shared.d.ts +101 -0
  193. package/build/components/image/shared.js +407 -0
  194. package/build/components/image-background.d.ts +78 -0
  195. package/build/components/image-background.js +583 -0
  196. package/build/components/input-accessory-view.d.ts +56 -0
  197. package/build/components/input-accessory-view.js +407 -0
  198. package/build/components/keyboard-avoiding-view.d.ts +79 -0
  199. package/build/components/keyboard-avoiding-view.js +509 -0
  200. package/build/components/modal.d.ts +89 -0
  201. package/build/components/modal.js +534 -0
  202. package/build/components/pressable/index.d.ts +120 -0
  203. package/build/components/pressable/index.js +640 -0
  204. package/build/components/refresh-control.d.ts +83 -0
  205. package/build/components/refresh-control.js +514 -0
  206. package/build/components/safe-area-view.d.ts +54 -0
  207. package/build/components/safe-area-view.js +393 -0
  208. package/build/components/scroll-view/index.android.d.ts +16 -0
  209. package/build/components/scroll-view/index.android.js +228 -0
  210. package/build/components/scroll-view/index.d.ts +3 -0
  211. package/build/components/scroll-view/index.ios.d.ts +6 -0
  212. package/build/components/scroll-view/index.ios.js +113 -0
  213. package/build/components/scroll-view/index.js +5 -0
  214. package/build/components/scroll-view/projection.d.ts +32 -0
  215. package/build/components/scroll-view/projection.js +311 -0
  216. package/build/components/scroll-view/shared.d.ts +225 -0
  217. package/build/components/scroll-view/shared.js +757 -0
  218. package/build/components/scroll-view/sticky-header.d.ts +38 -0
  219. package/build/components/scroll-view/sticky-header.js +257 -0
  220. package/build/components/section-list/index.d.ts +113 -0
  221. package/build/components/section-list/index.js +768 -0
  222. package/build/components/switch/index.android.d.ts +17 -0
  223. package/build/components/switch/index.android.js +107 -0
  224. package/build/components/switch/index.d.ts +1 -0
  225. package/build/components/switch/index.ios.d.ts +16 -0
  226. package/build/components/switch/index.ios.js +106 -0
  227. package/build/components/switch/index.js +3 -0
  228. package/build/components/switch/shared.d.ts +37 -0
  229. package/build/components/switch/shared.js +176 -0
  230. package/build/components/text-input.d.ts +150 -0
  231. package/build/components/text-input.js +826 -0
  232. package/build/components/touchable-native-feedback.d.ts +80 -0
  233. package/build/components/touchable-native-feedback.js +550 -0
  234. package/build/components/touchable.d.ts +241 -0
  235. package/build/components/touchable.js +1672 -0
  236. package/build/components/virtualized-list/directives.d.ts +41 -0
  237. package/build/components/virtualized-list/directives.js +250 -0
  238. package/build/components/virtualized-list/index.d.ts +265 -0
  239. package/build/components/virtualized-list/index.js +1344 -0
  240. package/build/components/virtualized-section-list/directives.d.ts +28 -0
  241. package/build/components/virtualized-section-list/directives.js +149 -0
  242. package/build/components/virtualized-section-list/index.d.ts +175 -0
  243. package/build/components/virtualized-section-list/index.js +854 -0
  244. package/build/components.d.ts +39 -0
  245. package/build/components.js +37 -0
  246. package/build/create-portal.d.ts +17 -0
  247. package/build/create-portal.js +128 -0
  248. package/build/create-tunnel.d.ts +29 -0
  249. package/build/create-tunnel.js +181 -0
  250. package/build/descriptor-to-angular/index.d.ts +19 -0
  251. package/build/descriptor-to-angular/index.js +186 -0
  252. package/build/host-instance/index.d.ts +2 -0
  253. package/build/host-instance/index.js +36 -0
  254. package/build/index.d.ts +21 -0
  255. package/build/index.js +41 -0
  256. package/build/modules/animated/create-animated-component.d.ts +57 -0
  257. package/build/modules/animated/create-animated-component.js +490 -0
  258. package/build/modules/animated/index.d.ts +51 -0
  259. package/build/modules/animated/index.js +58 -0
  260. package/build/modules/app-registry/index.d.ts +7 -0
  261. package/build/modules/app-registry/index.js +22 -0
  262. package/build/modules/status-bar.d.ts +17 -0
  263. package/build/modules/status-bar.js +121 -0
  264. package/build/primitives/index.d.ts +32 -0
  265. package/build/primitives/index.js +386 -0
  266. package/build/primitives/shared.d.ts +84 -0
  267. package/build/primitives/shared.js +231 -0
  268. package/build/render.d.ts +11 -0
  269. package/build/render.js +160 -0
  270. package/build/renderer.d.ts +38 -0
  271. package/build/renderer.js +359 -0
  272. package/build/services/color-scheme.service.d.ts +13 -0
  273. package/build/services/color-scheme.service.js +72 -0
  274. package/build/services/index.d.ts +2 -0
  275. package/build/services/index.js +2 -0
  276. package/build/services/window-dimensions.service.d.ts +13 -0
  277. package/build/services/window-dimensions.service.js +83 -0
  278. package/metro-css-parser.cjs +11 -0
  279. package/package.json +57 -0
  280. package/src/__tests__/responder-change-detection.test.ts +102 -0
  281. package/src/__tests__/responder-nested-cd.test.ts +113 -0
  282. package/src/angular-gaps.test.ts +142 -0
  283. package/src/angular-imports.test.ts +100 -0
  284. package/src/components/activity-indicator/activity-indicator-class-style.test.ts +44 -0
  285. package/src/components/activity-indicator/activity-indicator.test.ts +131 -0
  286. package/src/components/activity-indicator/index.android.ts +16 -0
  287. package/src/components/activity-indicator/index.ios.ts +17 -0
  288. package/src/components/activity-indicator/index.ts +4 -0
  289. package/src/components/activity-indicator/shared.ts +206 -0
  290. package/src/components/button.ts +193 -0
  291. package/src/components/flat-list/column-wrapper-style-class.test.ts +116 -0
  292. package/src/components/flat-list/flat-list-array-style.test.ts +131 -0
  293. package/src/components/flat-list/flat-list-class-style.test.ts +74 -0
  294. package/src/components/flat-list/flat-list-scroll-containment.test.ts +107 -0
  295. package/src/components/flat-list/flat-list.test.ts +99 -0
  296. package/src/components/flat-list/index.ts +575 -0
  297. package/src/components/image/image-class-style.test.ts +46 -0
  298. package/src/components/image/index.android.ts +48 -0
  299. package/src/components/image/index.ios.ts +48 -0
  300. package/src/components/image/index.ts +3 -0
  301. package/src/components/image/shared.ts +478 -0
  302. package/src/components/image-background-class-style.test.ts +48 -0
  303. package/src/components/image-background-style-class.test.ts +79 -0
  304. package/src/components/image-background.ts +270 -0
  305. package/src/components/input-accessory-view.test.ts +43 -0
  306. package/src/components/input-accessory-view.ts +191 -0
  307. package/src/components/keyboard-avoiding-view.test.ts +54 -0
  308. package/src/components/keyboard-avoiding-view.ts +308 -0
  309. package/src/components/modal.test.ts +43 -0
  310. package/src/components/modal.ts +304 -0
  311. package/src/components/pressable/index.ts +371 -0
  312. package/src/components/pressable/pressable.test.ts +85 -0
  313. package/src/components/refresh-control.test.ts +41 -0
  314. package/src/components/refresh-control.ts +288 -0
  315. package/src/components/safe-area-view.test.ts +43 -0
  316. package/src/components/safe-area-view.ts +178 -0
  317. package/src/components/scroll-view/android-scroll-view-axis-projection.test.ts +123 -0
  318. package/src/components/scroll-view/content-container-style-class.test.ts +75 -0
  319. package/src/components/scroll-view/index.android.ts +190 -0
  320. package/src/components/scroll-view/index.ios.ts +79 -0
  321. package/src/components/scroll-view/index.ts +7 -0
  322. package/src/components/scroll-view/projection.ts +384 -0
  323. package/src/components/scroll-view/scroll-view-class-style.test.ts +134 -0
  324. package/src/components/scroll-view/scroll-view-projection.test.ts +194 -0
  325. package/src/components/scroll-view/shared.ts +836 -0
  326. package/src/components/scroll-view/sticky-header.ts +230 -0
  327. package/src/components/section-list/index.ts +445 -0
  328. package/src/components/switch/android-switch-class.test.ts +42 -0
  329. package/src/components/switch/index.android.ts +61 -0
  330. package/src/components/switch/index.ios.ts +60 -0
  331. package/src/components/switch/index.ts +4 -0
  332. package/src/components/switch/shared.ts +197 -0
  333. package/src/components/switch/switch.test.ts +92 -0
  334. package/src/components/text-input-class-style.test.ts +54 -0
  335. package/src/components/text-input.ts +536 -0
  336. package/src/components/touchable-native-feedback.test.ts +49 -0
  337. package/src/components/touchable-native-feedback.ts +260 -0
  338. package/src/components/touchable.test.ts +102 -0
  339. package/src/components/touchable.ts +643 -0
  340. package/src/components/virtualized-list/directives.ts +169 -0
  341. package/src/components/virtualized-list/index.ts +1204 -0
  342. package/src/components/virtualized-list/virtualized-list-class-style.test.ts +76 -0
  343. package/src/components/virtualized-section-list/directives.ts +91 -0
  344. package/src/components/virtualized-section-list/index.ts +598 -0
  345. package/src/components/virtualized-section-list/virtualized-section-list-class-style.test.ts +60 -0
  346. package/src/components.ts +149 -0
  347. package/src/create-portal.test.ts +90 -0
  348. package/src/create-portal.ts +74 -0
  349. package/src/create-tunnel.test.ts +120 -0
  350. package/src/create-tunnel.ts +136 -0
  351. package/src/descriptor-to-angular/descriptor-outlet.test.ts +94 -0
  352. package/src/descriptor-to-angular/index.ts +190 -0
  353. package/src/host-instance/host-instance.test.ts +49 -0
  354. package/src/host-instance/index.ts +36 -0
  355. package/src/index.ts +257 -0
  356. package/src/modules/animated/animated-scroll-view.test.ts +85 -0
  357. package/src/modules/animated/create-animated-component.ts +435 -0
  358. package/src/modules/animated/index.ts +105 -0
  359. package/src/modules/app-registry/app-registry.test.ts +106 -0
  360. package/src/modules/app-registry/index.ts +60 -0
  361. package/src/modules/status-bar.test.ts +50 -0
  362. package/src/modules/status-bar.ts +57 -0
  363. package/src/primitives/index.ts +119 -0
  364. package/src/primitives/shared.ts +191 -0
  365. package/src/render.test.ts +147 -0
  366. package/src/render.ts +224 -0
  367. package/src/renderer.test.ts +179 -0
  368. package/src/renderer.ts +407 -0
  369. package/src/services/color-scheme.service.ts +27 -0
  370. package/src/services/index.ts +2 -0
  371. package/src/services/services.test.ts +163 -0
  372. package/src/services/window-dimensions.service.ts +41 -0
@@ -0,0 +1,435 @@
1
+ // createAnimatedComponent for @symbiote-native/angular: the Angular twin of the React/Vue
2
+ // wrapper. React/Vue have a runtime HOC (`createAnimatedComponent(Component)` builds a
3
+ // fresh wrapped component on the fly). Angular has NO such idiom AND it cannot have one:
4
+ // the AOT-under-Metro build (angular-adapter skill §4) compiles every @Component at build
5
+ // time and ships NO JIT compiler to Hermes, so a runtime `Component({...})(class)` would
6
+ // throw. The idiomatic, AOT-safe equivalent is therefore an EXPLICIT set of standalone
7
+ // components — AnimatedView / AnimatedText / AnimatedImage / AnimatedScrollView — each a
8
+ // thin @Component over the matching host primitive, all sharing one abstract lifecycle
9
+ // base. The mechanism (build an AnimatedProps leaf, reduce animated props to current
10
+ // values for the first paint, bind the leaf to the committed host node, swap leaves on
11
+ // re-render, tear down on destroy) lives once in AnimatedComponentBase; only the per-host
12
+ // template differs.
13
+ //
14
+ // The framework-agnostic half (reduceProps / readPassthroughStyle / resolveHostNode /
15
+ // AnimatedProps / attachNativeEventHandler / isNativeAnimatedAvailable) comes from
16
+ // @symbiote-native/engine, shared verbatim with React and Vue (ADR 0016/0017). Angular supplies
17
+ // only the lifecycle wiring. The per-frame path NEVER goes through Angular change
18
+ // detection: value.setValue / animation -> flushValue -> AnimatedProps.update() ->
19
+ // setNativeProps(node), exactly as on the other adapters.
20
+
21
+ import {
22
+ ChangeDetectionStrategy,
23
+ Component,
24
+ CUSTOM_ELEMENTS_SCHEMA,
25
+ Directive,
26
+ ElementRef,
27
+ inject,
28
+ ViewChild,
29
+ type AfterViewInit,
30
+ type OnChanges,
31
+ type OnDestroy,
32
+ type Type,
33
+ } from '@angular/core';
34
+ import {
35
+ AnimatedProps,
36
+ attachNativeEventHandler,
37
+ dlog,
38
+ isNativeAnimatedAvailable,
39
+ isSymbioteNode,
40
+ reduceProps,
41
+ readPassthroughStyle,
42
+ resolveHostNode,
43
+ whenCommitted,
44
+ type ISymbioteNode,
45
+ } from '@symbiote-native/engine';
46
+ import { Image, ScrollView, Text, View } from '../../components';
47
+ import {
48
+ anchorHostStyle,
49
+ ViewHost,
50
+ TextHost,
51
+ ImageHost,
52
+ ScrollViewHost,
53
+ SymbioteHostPropsDirective,
54
+ } from '../../primitives';
55
+ import { FlatList } from '../../components/flat-list';
56
+ import {
57
+ IMAGE_INPUTS,
58
+ IMAGE_OUTPUTS,
59
+ ImageBase,
60
+ resolveImageProps,
61
+ } from '../../components/image/shared';
62
+ import { SectionList } from '../../components/section-list';
63
+
64
+ // RN's prop carrying explicit (already-rasterized) values that override the animated prop in
65
+ // the COMMITTED props (sticky-header passthrough). Named once so the directive input and the
66
+ // reconcile agree.
67
+ const PASSTHROUGH_PROP = 'passthroughAnimatedPropExplicitValues';
68
+
69
+ // The inputs every animated wrapper accepts. `style` is the (possibly animated) style — the
70
+ // common path (TouchableOpacity passes `[style, { opacity }]`). `animatedProps` is the generic
71
+ // escape hatch for any OTHER prop that may hold an AnimatedNode or an Animated.event handler,
72
+ // plus static host props to forward (the React/Vue `rest`). The passthrough drives native.
73
+ // Each concrete @Component re-lists these (Angular's inputs-on-base convention, mirroring
74
+ // Switch/Image), so they are inherited consistently.
75
+ export const ANIMATED_INPUTS = ['style', 'animatedProps', PASSTHROUGH_PROP];
76
+ export const ANIMATED_IMAGE_INPUTS = [...IMAGE_INPUTS, 'animatedProps', PASSTHROUGH_PROP];
77
+
78
+ // The shared lifecycle for every animated wrapper. Concrete subclasses add ONLY a @Component
79
+ // decorator (selector + the host-primitive template) — no behavior. Plain fields (no @Input
80
+ // here): the inputs are declared on each concrete via ANIMATED_INPUTS, the adapter convention.
81
+ // @Directive() (no selector) is the Angular-sanctioned decorator for an abstract base that
82
+ // declares lifecycle hooks — without it ngtsc rejects the inherited hooks (NG2007).
83
+ @Directive()
84
+ export abstract class AnimatedComponentBase implements AfterViewInit, OnChanges, OnDestroy {
85
+ style: unknown;
86
+ animatedProps: Record<string, unknown> | undefined;
87
+ passthroughAnimatedPropExplicitValues: unknown;
88
+
89
+ // This component's OWN host — every Animated* wrapper is a non-painting ANCHOR
90
+ // (ANCHOR_HOST_COMPONENTS in renderer.ts), so a `class="..."` at the use site resolves onto
91
+ // THIS element, never the real inner host primitive one level down (see anchorHostStyle's doc
92
+ // comment in primitives/shared.ts — the same reason ScrollView's own scrollProps merges it in).
93
+ private readonly elementRef = inject(ElementRef);
94
+
95
+ // The directive sitting on the inner host primitive; its `node` is the committed SymbioteNode
96
+ // the leaf binds to. Inherited by the decorated subclass (Angular collects base-class queries).
97
+ @ViewChild(SymbioteHostPropsDirective) private hostDirective?: SymbioteHostPropsDirective;
98
+
99
+ // The leaf currently wired into the value graph. Null until the first reconcile.
100
+ private attached: AnimatedProps | null = null;
101
+ // The whenCommitted waiter for the current leaf's node binding, cancelled before the next.
102
+ private cancelBind: (() => void) | undefined;
103
+ // Detachers for any Animated.event prop bound natively to the committed node (JS path: none).
104
+ private eventDetachers: Array<() => void> = [];
105
+ // Set once the view (and the inner host directive) exists; ngOnChanges before then is a no-op.
106
+ private viewReady = false;
107
+
108
+ // The concrete props for the host element each change-detection pass: animated entries reduced
109
+ // to their current value, then the passthrough style layered on top (last wins via the style
110
+ // array, which the commit layer flattens) so the ShadowTree carries the current transform.
111
+ get reducedProps(): Record<string, unknown> {
112
+ const reduced = reduceProps(this.mergedProps());
113
+ const passthroughStyle = readPassthroughStyle(this.passthroughAnimatedPropExplicitValues);
114
+ if (passthroughStyle !== undefined) {
115
+ reduced['style'] =
116
+ reduced['style'] === undefined ? passthroughStyle : [reduced['style'], passthroughStyle];
117
+ }
118
+ reduced['style'] = [anchorHostStyle(this.elementRef), reduced['style']];
119
+ return reduced;
120
+ }
121
+
122
+ ngAfterViewInit(): void {
123
+ this.viewReady = true;
124
+ this.reconcile();
125
+ }
126
+
127
+ ngOnChanges(): void {
128
+ this.reconcile();
129
+ }
130
+
131
+ ngOnDestroy(): void {
132
+ this.cancelBind?.();
133
+ this.cancelBind = undefined;
134
+ this.detachEvents();
135
+ if (this.attached !== null) {
136
+ this.attached.__detach();
137
+ this.attached = null;
138
+ }
139
+ }
140
+
141
+ // Build a fresh AnimatedProps leaf from the current props (the React/Vue per-render
142
+ // useMemo(rest)), wire it into the graph, and swap the previous one out. Attach the NEW leaf
143
+ // BEFORE detaching the OLD one: a shared Value self-detaches (dropping its native node) the
144
+ // instant its child count hits zero, so detaching first would kill a running native animation
145
+ // on any unrelated re-render (mirrors RN's AnimatedComponent._attachProps). Then bind the
146
+ // committed node, go native if wanted, and rebind native events.
147
+ private reconcile(): void {
148
+ if (!this.viewReady) return;
149
+ // A non-stable [animatedProps]/[style] input (a fresh object literal in the template)
150
+ // pushes a new reference on every change-detection pass of the HOST view, re-triggering
151
+ // this on every unrelated interaction elsewhere in the app — DEBUG=1 turns this into a
152
+ // visible tick count, so an unexpectedly high rate for a component nobody is animating
153
+ // is the tell (see AnimatedScrollView's stable-reference fix in examples/angular/App.ts).
154
+ dlog(`AnimatedComponentBase reconcile (${this.constructor.name})`);
155
+ const props = this.mergedProps();
156
+ const hasPassthroughAnimatedValues =
157
+ this.passthroughAnimatedPropExplicitValues !== null &&
158
+ this.passthroughAnimatedPropExplicitValues !== undefined;
159
+ const wantsNative = hasPassthroughAnimatedValues && isNativeAnimatedAvailable();
160
+
161
+ const newLeaf = new AnimatedProps(props);
162
+ newLeaf.__attach();
163
+ if (this.attached !== null && this.attached !== newLeaf) this.attached.__detach();
164
+ this.attached = newLeaf;
165
+
166
+ this.bindNode(newLeaf, props, wantsNative);
167
+ }
168
+
169
+ // Bind the leaf to the host's Fabric node THROUGH whenCommitted: under Angular's zoneless
170
+ // batched change detection the inner host's tag does not exist yet at ngAfterViewInit time
171
+ // (the same async-commit gotcha Vue documents), so binding eagerly would no-op. whenCommitted
172
+ // runs the action now if already committed, else after the commit that assigns the tag.
173
+ private bindNode(
174
+ leaf: AnimatedProps,
175
+ props: Record<string, unknown>,
176
+ wantsNative: boolean,
177
+ ): void {
178
+ this.cancelBind?.();
179
+ this.cancelBind = undefined;
180
+ const node = this.hostNode();
181
+ if (node === null) return;
182
+ this.cancelBind = whenCommitted(node, () => {
183
+ leaf.setNativeView(node);
184
+ if (wantsNative) leaf.__makeNative();
185
+ this.attachEvents(node, props);
186
+ });
187
+ }
188
+
189
+ // Native-attach any Animated.event prop (e.g. onScroll={Animated.event(…,{useNativeDriver:true})})
190
+ // to the committed node. attachNativeEventHandler no-ops (returns undefined) unless the prop is a
191
+ // native event handler with a committed tag, so the JS path stays the fallback. Rebound each
192
+ // reconcile so a new inline event re-attaches; detached first to avoid leaking the prior binding.
193
+ private attachEvents(node: ISymbioteNode, props: Record<string, unknown>): void {
194
+ this.detachEvents();
195
+ for (const key of Object.keys(props)) {
196
+ const attachment = attachNativeEventHandler(node, key, props[key]);
197
+ if (attachment !== undefined) this.eventDetachers.push(attachment.detach);
198
+ }
199
+ }
200
+
201
+ private detachEvents(): void {
202
+ for (const detach of this.eventDetachers) detach();
203
+ this.eventDetachers = [];
204
+ }
205
+
206
+ // Merge the dedicated `style` input over the generic `animatedProps` bag into one props map —
207
+ // the equivalent of React/Vue `rest`. `style` wins so `[style]` and `[animatedProps].style`
208
+ // never disagree.
209
+ private mergedProps(): Record<string, unknown> {
210
+ const base = this.animatedProps ?? {};
211
+ return this.style === undefined ? { ...base } : { ...base, style: this.style };
212
+ }
213
+
214
+ // The committed host node held by IDENTITY. resolveHostNode unwraps an imperative scroll
215
+ // handle to the underlying SymbioteNode (View / Text already hand back the node directly);
216
+ // the isSymbioteNode guard keeps us off a cast.
217
+ private hostNode(): ISymbioteNode | null {
218
+ const resolved = resolveHostNode(this.hostDirective?.node);
219
+ return isSymbioteNode(resolved) ? resolved : null;
220
+ }
221
+ }
222
+
223
+ @Component({
224
+ selector: 'AnimatedView, symbiote-animated-view',
225
+ standalone: true,
226
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
227
+ imports: [SymbioteHostPropsDirective, ViewHost],
228
+ inputs: ANIMATED_INPUTS,
229
+ template: `
230
+ <symbiote-view [symbioteHostProps]="reducedProps">
231
+ <ng-content></ng-content>
232
+ </symbiote-view>
233
+ `,
234
+ changeDetection: ChangeDetectionStrategy.OnPush,
235
+ })
236
+ export class AnimatedView extends AnimatedComponentBase {}
237
+
238
+ @Component({
239
+ selector: 'AnimatedText, symbiote-animated-text',
240
+ standalone: true,
241
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
242
+ imports: [SymbioteHostPropsDirective, TextHost],
243
+ inputs: ANIMATED_INPUTS,
244
+ template: `
245
+ <symbiote-text [symbioteHostProps]="reducedProps">
246
+ <ng-content></ng-content>
247
+ </symbiote-text>
248
+ `,
249
+ changeDetection: ChangeDetectionStrategy.OnPush,
250
+ })
251
+ export class AnimatedText extends AnimatedComponentBase {}
252
+
253
+ @Component({
254
+ selector: 'AnimatedImage, symbiote-animated-image',
255
+ standalone: true,
256
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
257
+ imports: [SymbioteHostPropsDirective, ImageHost],
258
+ inputs: ANIMATED_IMAGE_INPUTS,
259
+ outputs: IMAGE_OUTPUTS,
260
+ template: `
261
+ <symbiote-image
262
+ [symbioteHostProps]="animatedImageProps"
263
+ (accessibilityAction)="handleAccessibilityAction($event)"
264
+ (accessibilityTap)="handleAccessibilityTap($event)"
265
+ (magicTap)="handleMagicTap($event)"
266
+ (accessibilityEscape)="handleAccessibilityEscape($event)"
267
+ (loadStart)="handleLoadStart($event)"
268
+ (load)="handleLoad($event)"
269
+ (loadEnd)="handleLoadEnd($event)"
270
+ (error)="handleError($event)"
271
+ (progress)="handleProgress($event)"
272
+ (partialLoad)="handlePartialLoad($event)"
273
+ >
274
+ <ng-content></ng-content>
275
+ </symbiote-image>
276
+ `,
277
+ changeDetection: ChangeDetectionStrategy.OnPush,
278
+ })
279
+ export class AnimatedImage extends ImageBase implements AfterViewInit, OnChanges, OnDestroy {
280
+ animatedProps: Record<string, unknown> | undefined;
281
+ passthroughAnimatedPropExplicitValues: unknown;
282
+
283
+ // AnimatedImage is a non-painting ANCHOR too (ANCHOR_HOST_COMPONENTS) — see the matching
284
+ // comment on AnimatedComponentBase.elementRef.
285
+ private readonly elementRef = inject(ElementRef);
286
+
287
+ @ViewChild(SymbioteHostPropsDirective) private hostDirective?: SymbioteHostPropsDirective;
288
+
289
+ private attached: AnimatedProps | null = null;
290
+ private cancelBind: (() => void) | undefined;
291
+ private eventDetachers: Array<() => void> = [];
292
+ private viewReady = false;
293
+
294
+ get animatedImageProps(): Record<string, unknown> {
295
+ const reduced = reduceProps(this.mergedProps());
296
+ const passthroughStyle = readPassthroughStyle(this.passthroughAnimatedPropExplicitValues);
297
+ if (passthroughStyle !== undefined) {
298
+ reduced['style'] =
299
+ reduced['style'] === undefined ? passthroughStyle : [reduced['style'], passthroughStyle];
300
+ }
301
+ const resolved = resolveImageProps(reduced);
302
+ resolved['style'] = [anchorHostStyle(this.elementRef), resolved['style']];
303
+ return resolved;
304
+ }
305
+
306
+ ngAfterViewInit(): void {
307
+ this.viewReady = true;
308
+ this.reconcile();
309
+ }
310
+
311
+ ngOnChanges(): void {
312
+ this.reconcile();
313
+ }
314
+
315
+ ngOnDestroy(): void {
316
+ this.cancelBind?.();
317
+ this.cancelBind = undefined;
318
+ this.detachEvents();
319
+ if (this.attached !== null) {
320
+ this.attached.__detach();
321
+ this.attached = null;
322
+ }
323
+ }
324
+
325
+ private reconcile(): void {
326
+ if (!this.viewReady) return;
327
+ const props = this.mergedProps();
328
+ const hasPassthroughAnimatedValues =
329
+ this.passthroughAnimatedPropExplicitValues !== null &&
330
+ this.passthroughAnimatedPropExplicitValues !== undefined;
331
+ const wantsNative = hasPassthroughAnimatedValues && isNativeAnimatedAvailable();
332
+
333
+ const newLeaf = new AnimatedProps(props);
334
+ newLeaf.__attach();
335
+ if (this.attached !== null && this.attached !== newLeaf) this.attached.__detach();
336
+ this.attached = newLeaf;
337
+
338
+ this.bindNode(newLeaf, props, wantsNative);
339
+ }
340
+
341
+ private bindNode(
342
+ leaf: AnimatedProps,
343
+ props: Record<string, unknown>,
344
+ wantsNative: boolean,
345
+ ): void {
346
+ this.cancelBind?.();
347
+ this.cancelBind = undefined;
348
+ const node = this.hostNode();
349
+ if (node === null) return;
350
+ this.cancelBind = whenCommitted(node, () => {
351
+ leaf.setNativeView(node);
352
+ if (wantsNative) leaf.__makeNative();
353
+ this.attachEvents(node, props);
354
+ });
355
+ }
356
+
357
+ private attachEvents(node: ISymbioteNode, props: Record<string, unknown>): void {
358
+ this.detachEvents();
359
+ for (const key of Object.keys(props)) {
360
+ const attachment = attachNativeEventHandler(node, key, props[key]);
361
+ if (attachment !== undefined) this.eventDetachers.push(attachment.detach);
362
+ }
363
+ }
364
+
365
+ private detachEvents(): void {
366
+ for (const detach of this.eventDetachers) detach();
367
+ this.eventDetachers = [];
368
+ }
369
+
370
+ private mergedProps(): Record<string, unknown> {
371
+ const props: Record<string, unknown> = { ...(this.animatedProps ?? {}) };
372
+ for (const [key, value] of Object.entries(this.imageInputProps)) {
373
+ if (value !== undefined) props[key] = value;
374
+ }
375
+ return props;
376
+ }
377
+
378
+ private hostNode(): ISymbioteNode | null {
379
+ const resolved = resolveHostNode(this.hostDirective?.node);
380
+ return isSymbioteNode(resolved) ? resolved : null;
381
+ }
382
+ }
383
+
384
+ @Component({
385
+ selector: 'AnimatedScrollView, symbiote-animated-scroll-view',
386
+ standalone: true,
387
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
388
+ imports: [SymbioteHostPropsDirective, ScrollViewHost],
389
+ inputs: ANIMATED_INPUTS,
390
+ template: `
391
+ <symbiote-scroll-view [symbioteHostProps]="reducedProps">
392
+ <symbiote-scroll-content [collapsable]="false">
393
+ <ng-content></ng-content>
394
+ </symbiote-scroll-content>
395
+ </symbiote-scroll-view>
396
+ `,
397
+ changeDetection: ChangeDetectionStrategy.OnPush,
398
+ })
399
+ export class AnimatedScrollView extends AnimatedComponentBase {
400
+ // RN defaults nested scrolling ON (ScrollView.js `nestedScrollEnabled ?? true`) — Android
401
+ // needs it explicit or a ScrollView nested inside another scrollable container never
402
+ // receives touch (swallowed by the outer scroll view; iOS doesn't gate on this). The real
403
+ // ScrollView component already defaults this (scroll-view/shared.ts), but AnimatedScrollView
404
+ // talks to the raw primitive directly and has no such defaulting, so it must apply it too.
405
+ override get reducedProps(): Record<string, unknown> {
406
+ const reduced = super.reducedProps;
407
+ return reduced.nestedScrollEnabled === undefined
408
+ ? { ...reduced, nestedScrollEnabled: true }
409
+ : reduced;
410
+ }
411
+ }
412
+
413
+ // List components are already explicit AOT-compiled Angular components with their own full input
414
+ // surface and inner ScrollView composition. Expose them in the Animated namespace without runtime
415
+ // synthesis; app code passes animated style/onScroll through the existing list inputs.
416
+ export const AnimatedFlatList = FlatList;
417
+ export const AnimatedSectionList = SectionList;
418
+
419
+ // Surface-parity shim for the React/Vue `createAnimatedComponent(Component)`. Angular cannot
420
+ // synthesize a component at runtime (no JIT under AOT/Metro — see the file header), so this maps
421
+ // the built-in primitives to their pre-authored wrappers and refuses anything else with a
422
+ // pointer to the real Angular idiom: author a standalone @Component extending
423
+ // AnimatedComponentBase.
424
+ export function createAnimatedComponent(base: unknown): Type<unknown> {
425
+ if (base === View) return AnimatedView;
426
+ if (base === Text) return AnimatedText;
427
+ if (base === Image) return AnimatedImage;
428
+ if (base === ScrollView) return AnimatedScrollView;
429
+ throw new Error(
430
+ 'createAnimatedComponent: Angular cannot synthesize a component at runtime (no JIT compiler ' +
431
+ 'under AOT/Metro). Author an explicit standalone @Component extending AnimatedComponentBase ' +
432
+ 'instead. The built-in primitives View / Text / Image / ScrollView map to ' +
433
+ 'AnimatedView / AnimatedText / AnimatedImage / AnimatedScrollView.',
434
+ );
435
+ }
@@ -0,0 +1,105 @@
1
+ // The Animated namespace for @symbiote-native/angular: the Angular twin of adapters/vue/src/modules/
2
+ // animated/index.ts. The animated COMPONENTS (View / Text / Image / ScrollView) are explicit
3
+ // standalone components (Angular has no runtime HOC — see create-animated-component.ts); the
4
+ // value graph, easing and imperative drivers come from @symbiote-native/engine (framework-agnostic,
5
+ // JS-driven, ADR 0016), spread in verbatim. Both halves meet here so the familiar surface,
6
+ // `Animated.timing(new Animated.Value(0), …).start()`, works against the Angular-driven engine.
7
+
8
+ import {
9
+ AnimatedValue,
10
+ AnimatedValueXY,
11
+ AnimatedColor,
12
+ AnimatedMock,
13
+ Easing,
14
+ Platform,
15
+ timing,
16
+ spring,
17
+ decay,
18
+ parallel,
19
+ sequence,
20
+ stagger,
21
+ loop,
22
+ delay,
23
+ add,
24
+ subtract,
25
+ multiply,
26
+ divide,
27
+ modulo,
28
+ diffClamp,
29
+ event,
30
+ forkEvent,
31
+ unforkEvent,
32
+ } from '@symbiote-native/engine';
33
+ import {
34
+ AnimatedFlatList,
35
+ AnimatedImage,
36
+ AnimatedScrollView,
37
+ AnimatedSectionList,
38
+ AnimatedText,
39
+ AnimatedView,
40
+ createAnimatedComponent,
41
+ } from './create-animated-component';
42
+
43
+ export {
44
+ AnimatedComponentBase,
45
+ AnimatedFlatList,
46
+ AnimatedImage,
47
+ AnimatedScrollView,
48
+ AnimatedSectionList,
49
+ AnimatedText,
50
+ AnimatedView,
51
+ createAnimatedComponent,
52
+ } from './create-animated-component';
53
+
54
+ // ScrollView is exposed DIRECTLY, not behind the lazy getter the React/Vue modules use: that
55
+ // getter only exists to defer a RUNTIME createAnimatedComponent(ScrollView) past module init so
56
+ // it cannot read ScrollView inside its own TDZ during an import cycle. AnimatedScrollView here is
57
+ // a statically-declared component that never reads the ScrollView class at init (it targets the
58
+ // `symbiote-scroll-view` host by string), so there is no cycle to defer.
59
+ //
60
+ // FlatList / SectionList are exposed as explicit AOT-safe list entries now that the Angular list
61
+ // components exist. Angular still cannot synthesize arbitrary animated wrappers at runtime; custom
62
+ // animated components remain explicit standalone components over AnimatedComponentBase.
63
+
64
+ // The live, JS-driven driver namespace (real frames). RN's AnimatedImplementation.
65
+ const liveDrivers = {
66
+ Value: AnimatedValue,
67
+ ValueXY: AnimatedValueXY,
68
+ Color: AnimatedColor,
69
+ Easing,
70
+ timing,
71
+ spring,
72
+ decay,
73
+ parallel,
74
+ sequence,
75
+ stagger,
76
+ loop,
77
+ delay,
78
+ add,
79
+ subtract,
80
+ multiply,
81
+ divide,
82
+ modulo,
83
+ diffClamp,
84
+ event,
85
+ forkEvent,
86
+ unforkEvent,
87
+ };
88
+
89
+ // RN swaps the WHOLE driver namespace for the mock when the host reports isDisableAnimations
90
+ // (reduced motion / test env): the mock keeps the same surface but jumps each animation to its
91
+ // final value synchronously, no frames. The animated COMPONENTS are live in both branches; only
92
+ // the drivers/value/operators/events half is swapped, exactly like RN spreading `...Animated`
93
+ // (impl or mock) over the same components.
94
+ const drivers = Platform.isDisableAnimations ? AnimatedMock : liveDrivers;
95
+
96
+ export const Animated = {
97
+ View: AnimatedView,
98
+ Text: AnimatedText,
99
+ Image: AnimatedImage,
100
+ ScrollView: AnimatedScrollView,
101
+ FlatList: AnimatedFlatList,
102
+ SectionList: AnimatedSectionList,
103
+ createAnimatedComponent,
104
+ ...drivers,
105
+ };
@@ -0,0 +1,106 @@
1
+ // Co-located Angular-driven test (ADR 0025), Angular twin of adapters/react/src/modules/
2
+ // app-registry/app-registry.test.tsx. Proves the AppRegistry entry point:
3
+ // `registerComponent(appKey, () => App)` stores a runnable that calls `mount` (driving
4
+ // @symbiote-native/engine) AND bridges it to the host registrar (RN's own AppRegistry, injected via
5
+ // `setHostRegistrar`) so native can find it by key. Also proves the Angular-specific
6
+ // `setWrapperComponentProvider` seam: a pre-authored standalone wrapper receives the root's
7
+ // host node as projected `<ng-content>`, the AOT-safe twin of React's
8
+ // createElement(Wrapper, null, rootElement).
9
+
10
+ import '@angular/compiler';
11
+ import { Component, Input, type Type } from '@angular/core';
12
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
13
+ import { installFabric } from '@symbiote-native/test-utils';
14
+ import { AppRegistry, setHostRegistrar, type IAppParameters, type IRunnable } from '../..';
15
+ import { unmount } from '../../render';
16
+
17
+ const APP_KEY = 'canary';
18
+ const ROOT_TAG = 212;
19
+ const WRAPPED_APP_KEY = 'canary-wrapped';
20
+ const WRAPPED_ROOT_TAG = 213;
21
+
22
+ // Angular's mount() batches change detection on a microtask (the `angular-adapter` skill's
23
+ // whenCommitted-class gotcha), so assertions on the committed tree need one tick, same as Vue.
24
+ const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
25
+
26
+ class TestText {}
27
+ Component({
28
+ selector: 'symbiote-text',
29
+ standalone: true,
30
+ template: '<ng-content></ng-content>',
31
+ })(TestText);
32
+
33
+ class SmokeComponent {}
34
+ Component({
35
+ selector: 'symbiote-app-registry-smoke',
36
+ standalone: true,
37
+ imports: [TestText],
38
+ template: '<symbiote-text>hi</symbiote-text>',
39
+ })(SmokeComponent);
40
+
41
+ class WrapperComponent {
42
+ @Input() label = '';
43
+ }
44
+ Component({
45
+ selector: 'symbiote-app-registry-wrapper',
46
+ standalone: true,
47
+ imports: [TestText],
48
+ template: '<symbiote-text>{{ label }}</symbiote-text><ng-content></ng-content>',
49
+ })(WrapperComponent);
50
+
51
+ const fabric = installFabric();
52
+
53
+ // The host registrar the native side drives (RN's AppRegistry stand-in).
54
+ const hostRunnables = new Map<string, IRunnable>();
55
+
56
+ beforeEach(() => {
57
+ fabric.reset();
58
+ hostRunnables.clear();
59
+ setHostRegistrar({
60
+ registerRunnable: (appKey: string, run: IRunnable): string => {
61
+ hostRunnables.set(appKey, run);
62
+ return appKey;
63
+ },
64
+ });
65
+ AppRegistry.registerComponent(APP_KEY, () => SmokeComponent);
66
+ });
67
+ afterEach(() => {
68
+ unmount(ROOT_TAG);
69
+ unmount(WRAPPED_ROOT_TAG);
70
+ });
71
+
72
+ describe('AppRegistry', () => {
73
+ it('exposes the app key and bridges the runnable to the host registrar', () => {
74
+ expect(AppRegistry.getAppKeys()).toContain(APP_KEY);
75
+ expect(hostRunnables.get(APP_KEY)).toBeDefined();
76
+ });
77
+
78
+ it('mounts the tree when the host invokes the runnable with a rootTag', async () => {
79
+ const hostRun = hostRunnables.get(APP_KEY);
80
+ expect(hostRun).toBeDefined();
81
+
82
+ const nativeParams: IAppParameters = { rootTag: ROOT_TAG };
83
+ hostRun!(nativeParams);
84
+ await tick();
85
+
86
+ expect(fabric.find(n => n.viewName === 'RCTText')).toBeDefined();
87
+ });
88
+
89
+ it('runApplication drives the same runnable locally', async () => {
90
+ AppRegistry.runApplication(APP_KEY, { rootTag: ROOT_TAG });
91
+ await tick();
92
+
93
+ expect(fabric.find(n => n.viewName === 'RCTText')).toBeDefined();
94
+ });
95
+
96
+ it('projects the root component into a registered wrapper via <ng-content>', async () => {
97
+ AppRegistry.setWrapperComponentProvider(() => WrapperComponent as Type<unknown>);
98
+ AppRegistry.registerComponent(WRAPPED_APP_KEY, () => SmokeComponent);
99
+
100
+ AppRegistry.runApplication(WRAPPED_APP_KEY, { rootTag: WRAPPED_ROOT_TAG });
101
+ await tick();
102
+
103
+ const texts = fabric.appRoot().children.flatMap(n => fabric.serialize([n]));
104
+ expect(texts.join('')).toContain('hi');
105
+ });
106
+ });