@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.
- package/LICENSE +21 -0
- package/README.md +147 -0
- package/build/angular/components/activity-indicator/index.android.d.ts +12 -0
- package/build/angular/components/activity-indicator/index.android.js +21 -0
- package/build/angular/components/activity-indicator/index.android.js.map +1 -0
- package/build/angular/components/activity-indicator/index.d.ts +1 -0
- package/build/angular/components/activity-indicator/index.ios.d.ts +8 -0
- package/build/angular/components/activity-indicator/index.ios.js +21 -0
- package/build/angular/components/activity-indicator/index.ios.js.map +1 -0
- package/build/angular/components/activity-indicator/index.js +4 -0
- package/build/angular/components/activity-indicator/index.js.map +1 -0
- package/build/angular/components/activity-indicator/shared.d.ts +67 -0
- package/build/angular/components/activity-indicator/shared.js +260 -0
- package/build/angular/components/activity-indicator/shared.js.map +1 -0
- package/build/angular/components/button.d.ts +63 -0
- package/build/angular/components/button.js +332 -0
- package/build/angular/components/button.js.map +1 -0
- package/build/angular/components/drawer-layout-android/index.android.d.ts +34 -0
- package/build/angular/components/drawer-layout-android/index.android.js +291 -0
- package/build/angular/components/drawer-layout-android/index.android.js.map +1 -0
- package/build/angular/components/drawer-layout-android/index.d.ts +11 -0
- package/build/angular/components/drawer-layout-android/index.js +109 -0
- package/build/angular/components/drawer-layout-android/index.js.map +1 -0
- package/build/angular/components/drawer-layout-android/shared.d.ts +74 -0
- package/build/angular/components/drawer-layout-android/shared.js +138 -0
- package/build/angular/components/drawer-layout-android/shared.js.map +1 -0
- package/build/angular/components/flat-list/index.d.ts +122 -0
- package/build/angular/components/flat-list/index.js +689 -0
- package/build/angular/components/flat-list/index.js.map +1 -0
- package/build/angular/components/image/index.android.d.ts +10 -0
- package/build/angular/components/image/index.android.js +59 -0
- package/build/angular/components/image/index.android.js.map +1 -0
- package/build/angular/components/image/index.d.ts +1 -0
- package/build/angular/components/image/index.ios.d.ts +10 -0
- package/build/angular/components/image/index.ios.js +59 -0
- package/build/angular/components/image/index.ios.js.map +1 -0
- package/build/angular/components/image/index.js +3 -0
- package/build/angular/components/image/index.js.map +1 -0
- package/build/angular/components/image/shared.d.ts +101 -0
- package/build/angular/components/image/shared.js +408 -0
- package/build/angular/components/image/shared.js.map +1 -0
- package/build/angular/components/image-background.d.ts +81 -0
- package/build/angular/components/image-background.js +418 -0
- package/build/angular/components/image-background.js.map +1 -0
- package/build/angular/components/input-accessory-view.d.ts +59 -0
- package/build/angular/components/input-accessory-view.js +266 -0
- package/build/angular/components/input-accessory-view.js.map +1 -0
- package/build/angular/components/keyboard-avoiding-view.d.ts +82 -0
- package/build/angular/components/keyboard-avoiding-view.js +363 -0
- package/build/angular/components/keyboard-avoiding-view.js.map +1 -0
- package/build/angular/components/modal.d.ts +92 -0
- package/build/angular/components/modal.js +365 -0
- package/build/angular/components/modal.js.map +1 -0
- package/build/angular/components/pressable/index.d.ts +123 -0
- package/build/angular/components/pressable/index.js +421 -0
- package/build/angular/components/pressable/index.js.map +1 -0
- package/build/angular/components/refresh-control.d.ts +86 -0
- package/build/angular/components/refresh-control.js +347 -0
- package/build/angular/components/refresh-control.js.map +1 -0
- package/build/angular/components/safe-area-view.d.ts +57 -0
- package/build/angular/components/safe-area-view.js +253 -0
- package/build/angular/components/safe-area-view.js.map +1 -0
- package/build/angular/components/scroll-view/index.android.d.ts +21 -0
- package/build/angular/components/scroll-view/index.android.js +235 -0
- package/build/angular/components/scroll-view/index.android.js.map +1 -0
- package/build/angular/components/scroll-view/index.d.ts +3 -0
- package/build/angular/components/scroll-view/index.ios.d.ts +9 -0
- package/build/angular/components/scroll-view/index.ios.js +86 -0
- package/build/angular/components/scroll-view/index.ios.js.map +1 -0
- package/build/angular/components/scroll-view/index.js +6 -0
- package/build/angular/components/scroll-view/index.js.map +1 -0
- package/build/angular/components/scroll-view/projection.d.ts +32 -0
- package/build/angular/components/scroll-view/projection.js +312 -0
- package/build/angular/components/scroll-view/projection.js.map +1 -0
- package/build/angular/components/scroll-view/shared.d.ts +230 -0
- package/build/angular/components/scroll-view/shared.js +679 -0
- package/build/angular/components/scroll-view/shared.js.map +1 -0
- package/build/angular/components/scroll-view/sticky-header.d.ts +41 -0
- package/build/angular/components/scroll-view/sticky-header.js +208 -0
- package/build/angular/components/scroll-view/sticky-header.js.map +1 -0
- package/build/angular/components/section-list/index.d.ts +116 -0
- package/build/angular/components/section-list/index.js +641 -0
- package/build/angular/components/section-list/index.js.map +1 -0
- package/build/angular/components/switch/index.android.d.ts +20 -0
- package/build/angular/components/switch/index.android.js +70 -0
- package/build/angular/components/switch/index.android.js.map +1 -0
- package/build/angular/components/switch/index.d.ts +1 -0
- package/build/angular/components/switch/index.ios.d.ts +19 -0
- package/build/angular/components/switch/index.ios.js +69 -0
- package/build/angular/components/switch/index.ios.js.map +1 -0
- package/build/angular/components/switch/index.js +4 -0
- package/build/angular/components/switch/index.js.map +1 -0
- package/build/angular/components/switch/shared.d.ts +40 -0
- package/build/angular/components/switch/shared.js +127 -0
- package/build/angular/components/switch/shared.js.map +1 -0
- package/build/angular/components/text-input.d.ts +153 -0
- package/build/angular/components/text-input.js +604 -0
- package/build/angular/components/text-input.js.map +1 -0
- package/build/angular/components/touchable-native-feedback.d.ts +83 -0
- package/build/angular/components/touchable-native-feedback.js +376 -0
- package/build/angular/components/touchable-native-feedback.js.map +1 -0
- package/build/angular/components/touchable.d.ts +248 -0
- package/build/angular/components/touchable.js +1206 -0
- package/build/angular/components/touchable.js.map +1 -0
- package/build/angular/components/virtualized-list/directives.d.ts +54 -0
- package/build/angular/components/virtualized-list/directives.js +154 -0
- package/build/angular/components/virtualized-list/directives.js.map +1 -0
- package/build/angular/components/virtualized-list/index.d.ts +268 -0
- package/build/angular/components/virtualized-list/index.js +1162 -0
- package/build/angular/components/virtualized-list/index.js.map +1 -0
- package/build/angular/components/virtualized-section-list/directives.d.ts +37 -0
- package/build/angular/components/virtualized-section-list/directives.js +77 -0
- package/build/angular/components/virtualized-section-list/directives.js.map +1 -0
- package/build/angular/components/virtualized-section-list/index.d.ts +178 -0
- package/build/angular/components/virtualized-section-list/index.js +722 -0
- package/build/angular/components/virtualized-section-list/index.js.map +1 -0
- package/build/angular/components.d.ts +39 -0
- package/build/angular/components.js +38 -0
- package/build/angular/components.js.map +1 -0
- package/build/angular/create-portal.d.ts +22 -0
- package/build/angular/create-portal.js +74 -0
- package/build/angular/create-portal.js.map +1 -0
- package/build/angular/create-tunnel.d.ts +34 -0
- package/build/angular/create-tunnel.js +126 -0
- package/build/angular/create-tunnel.js.map +1 -0
- package/build/angular/descriptor-to-angular/index.d.ts +22 -0
- package/build/angular/descriptor-to-angular/index.js +142 -0
- package/build/angular/descriptor-to-angular/index.js.map +1 -0
- package/build/angular/host-instance/index.d.ts +2 -0
- package/build/angular/host-instance/index.js +37 -0
- package/build/angular/host-instance/index.js.map +1 -0
- package/build/angular/index.d.ts +21 -0
- package/build/angular/index.js +42 -0
- package/build/angular/index.js.map +1 -0
- package/build/angular/modules/animated/create-animated-component.d.ts +68 -0
- package/build/angular/modules/animated/create-animated-component.js +429 -0
- package/build/angular/modules/animated/create-animated-component.js.map +1 -0
- package/build/angular/modules/animated/index.d.ts +51 -0
- package/build/angular/modules/animated/index.js +59 -0
- package/build/angular/modules/animated/index.js.map +1 -0
- package/build/angular/modules/app-registry/index.d.ts +7 -0
- package/build/angular/modules/app-registry/index.js +23 -0
- package/build/angular/modules/app-registry/index.js.map +1 -0
- package/build/angular/modules/status-bar.d.ts +20 -0
- package/build/angular/modules/status-bar.js +59 -0
- package/build/angular/modules/status-bar.js.map +1 -0
- package/build/angular/primitives/index.d.ts +63 -0
- package/build/angular/primitives/index.js +189 -0
- package/build/angular/primitives/index.js.map +1 -0
- package/build/angular/primitives/shared.d.ts +89 -0
- package/build/angular/primitives/shared.js +172 -0
- package/build/angular/primitives/shared.js.map +1 -0
- package/build/angular/render.d.ts +11 -0
- package/build/angular/render.js +161 -0
- package/build/angular/render.js.map +1 -0
- package/build/angular/renderer.d.ts +38 -0
- package/build/angular/renderer.js +360 -0
- package/build/angular/renderer.js.map +1 -0
- package/build/angular/services/color-scheme.service.d.ts +16 -0
- package/build/angular/services/color-scheme.service.js +31 -0
- package/build/angular/services/color-scheme.service.js.map +1 -0
- package/build/angular/services/index.d.ts +2 -0
- package/build/angular/services/index.js +3 -0
- package/build/angular/services/index.js.map +1 -0
- package/build/angular/services/window-dimensions.service.d.ts +16 -0
- package/build/angular/services/window-dimensions.service.js +42 -0
- package/build/angular/services/window-dimensions.service.js.map +1 -0
- package/build/components/activity-indicator/index.android.d.ts +9 -0
- package/build/components/activity-indicator/index.android.js +64 -0
- package/build/components/activity-indicator/index.d.ts +1 -0
- package/build/components/activity-indicator/index.ios.d.ts +5 -0
- package/build/components/activity-indicator/index.ios.js +64 -0
- package/build/components/activity-indicator/index.js +3 -0
- package/build/components/activity-indicator/shared.d.ts +64 -0
- package/build/components/activity-indicator/shared.js +424 -0
- package/build/components/button.d.ts +60 -0
- package/build/components/button.js +456 -0
- package/build/components/drawer-layout-android/index.android.d.ts +29 -0
- package/build/components/drawer-layout-android/index.android.js +326 -0
- package/build/components/drawer-layout-android/index.d.ts +8 -0
- package/build/components/drawer-layout-android/index.js +145 -0
- package/build/components/drawer-layout-android/shared.d.ts +71 -0
- package/build/components/drawer-layout-android/shared.js +205 -0
- package/build/components/flat-list/index.d.ts +119 -0
- package/build/components/flat-list/index.js +692 -0
- package/build/components/image/index.android.d.ts +7 -0
- package/build/components/image/index.android.js +88 -0
- package/build/components/image/index.d.ts +1 -0
- package/build/components/image/index.ios.d.ts +7 -0
- package/build/components/image/index.ios.js +88 -0
- package/build/components/image/index.js +2 -0
- package/build/components/image/shared.d.ts +101 -0
- package/build/components/image/shared.js +407 -0
- package/build/components/image-background.d.ts +78 -0
- package/build/components/image-background.js +583 -0
- package/build/components/input-accessory-view.d.ts +56 -0
- package/build/components/input-accessory-view.js +407 -0
- package/build/components/keyboard-avoiding-view.d.ts +79 -0
- package/build/components/keyboard-avoiding-view.js +509 -0
- package/build/components/modal.d.ts +89 -0
- package/build/components/modal.js +534 -0
- package/build/components/pressable/index.d.ts +120 -0
- package/build/components/pressable/index.js +640 -0
- package/build/components/refresh-control.d.ts +83 -0
- package/build/components/refresh-control.js +514 -0
- package/build/components/safe-area-view.d.ts +54 -0
- package/build/components/safe-area-view.js +393 -0
- package/build/components/scroll-view/index.android.d.ts +16 -0
- package/build/components/scroll-view/index.android.js +228 -0
- package/build/components/scroll-view/index.d.ts +3 -0
- package/build/components/scroll-view/index.ios.d.ts +6 -0
- package/build/components/scroll-view/index.ios.js +113 -0
- package/build/components/scroll-view/index.js +5 -0
- package/build/components/scroll-view/projection.d.ts +32 -0
- package/build/components/scroll-view/projection.js +311 -0
- package/build/components/scroll-view/shared.d.ts +225 -0
- package/build/components/scroll-view/shared.js +757 -0
- package/build/components/scroll-view/sticky-header.d.ts +38 -0
- package/build/components/scroll-view/sticky-header.js +257 -0
- package/build/components/section-list/index.d.ts +113 -0
- package/build/components/section-list/index.js +768 -0
- package/build/components/switch/index.android.d.ts +17 -0
- package/build/components/switch/index.android.js +107 -0
- package/build/components/switch/index.d.ts +1 -0
- package/build/components/switch/index.ios.d.ts +16 -0
- package/build/components/switch/index.ios.js +106 -0
- package/build/components/switch/index.js +3 -0
- package/build/components/switch/shared.d.ts +37 -0
- package/build/components/switch/shared.js +176 -0
- package/build/components/text-input.d.ts +150 -0
- package/build/components/text-input.js +826 -0
- package/build/components/touchable-native-feedback.d.ts +80 -0
- package/build/components/touchable-native-feedback.js +550 -0
- package/build/components/touchable.d.ts +241 -0
- package/build/components/touchable.js +1672 -0
- package/build/components/virtualized-list/directives.d.ts +41 -0
- package/build/components/virtualized-list/directives.js +250 -0
- package/build/components/virtualized-list/index.d.ts +265 -0
- package/build/components/virtualized-list/index.js +1344 -0
- package/build/components/virtualized-section-list/directives.d.ts +28 -0
- package/build/components/virtualized-section-list/directives.js +149 -0
- package/build/components/virtualized-section-list/index.d.ts +175 -0
- package/build/components/virtualized-section-list/index.js +854 -0
- package/build/components.d.ts +39 -0
- package/build/components.js +37 -0
- package/build/create-portal.d.ts +17 -0
- package/build/create-portal.js +128 -0
- package/build/create-tunnel.d.ts +29 -0
- package/build/create-tunnel.js +181 -0
- package/build/descriptor-to-angular/index.d.ts +19 -0
- package/build/descriptor-to-angular/index.js +186 -0
- package/build/host-instance/index.d.ts +2 -0
- package/build/host-instance/index.js +36 -0
- package/build/index.d.ts +21 -0
- package/build/index.js +41 -0
- package/build/modules/animated/create-animated-component.d.ts +57 -0
- package/build/modules/animated/create-animated-component.js +490 -0
- package/build/modules/animated/index.d.ts +51 -0
- package/build/modules/animated/index.js +58 -0
- package/build/modules/app-registry/index.d.ts +7 -0
- package/build/modules/app-registry/index.js +22 -0
- package/build/modules/status-bar.d.ts +17 -0
- package/build/modules/status-bar.js +121 -0
- package/build/primitives/index.d.ts +32 -0
- package/build/primitives/index.js +386 -0
- package/build/primitives/shared.d.ts +84 -0
- package/build/primitives/shared.js +231 -0
- package/build/render.d.ts +11 -0
- package/build/render.js +160 -0
- package/build/renderer.d.ts +38 -0
- package/build/renderer.js +359 -0
- package/build/services/color-scheme.service.d.ts +13 -0
- package/build/services/color-scheme.service.js +72 -0
- package/build/services/index.d.ts +2 -0
- package/build/services/index.js +2 -0
- package/build/services/window-dimensions.service.d.ts +13 -0
- package/build/services/window-dimensions.service.js +83 -0
- package/metro-css-parser.cjs +11 -0
- package/package.json +57 -0
- package/src/__tests__/responder-change-detection.test.ts +102 -0
- package/src/__tests__/responder-nested-cd.test.ts +113 -0
- package/src/angular-gaps.test.ts +142 -0
- package/src/angular-imports.test.ts +100 -0
- package/src/components/activity-indicator/activity-indicator-class-style.test.ts +44 -0
- package/src/components/activity-indicator/activity-indicator.test.ts +131 -0
- package/src/components/activity-indicator/index.android.ts +16 -0
- package/src/components/activity-indicator/index.ios.ts +17 -0
- package/src/components/activity-indicator/index.ts +4 -0
- package/src/components/activity-indicator/shared.ts +206 -0
- package/src/components/button.ts +193 -0
- package/src/components/flat-list/column-wrapper-style-class.test.ts +116 -0
- package/src/components/flat-list/flat-list-array-style.test.ts +131 -0
- package/src/components/flat-list/flat-list-class-style.test.ts +74 -0
- package/src/components/flat-list/flat-list-scroll-containment.test.ts +107 -0
- package/src/components/flat-list/flat-list.test.ts +99 -0
- package/src/components/flat-list/index.ts +575 -0
- package/src/components/image/image-class-style.test.ts +46 -0
- package/src/components/image/index.android.ts +48 -0
- package/src/components/image/index.ios.ts +48 -0
- package/src/components/image/index.ts +3 -0
- package/src/components/image/shared.ts +478 -0
- package/src/components/image-background-class-style.test.ts +48 -0
- package/src/components/image-background-style-class.test.ts +79 -0
- package/src/components/image-background.ts +270 -0
- package/src/components/input-accessory-view.test.ts +43 -0
- package/src/components/input-accessory-view.ts +191 -0
- package/src/components/keyboard-avoiding-view.test.ts +54 -0
- package/src/components/keyboard-avoiding-view.ts +308 -0
- package/src/components/modal.test.ts +43 -0
- package/src/components/modal.ts +304 -0
- package/src/components/pressable/index.ts +371 -0
- package/src/components/pressable/pressable.test.ts +85 -0
- package/src/components/refresh-control.test.ts +41 -0
- package/src/components/refresh-control.ts +288 -0
- package/src/components/safe-area-view.test.ts +43 -0
- package/src/components/safe-area-view.ts +178 -0
- package/src/components/scroll-view/android-scroll-view-axis-projection.test.ts +123 -0
- package/src/components/scroll-view/content-container-style-class.test.ts +75 -0
- package/src/components/scroll-view/index.android.ts +190 -0
- package/src/components/scroll-view/index.ios.ts +79 -0
- package/src/components/scroll-view/index.ts +7 -0
- package/src/components/scroll-view/projection.ts +384 -0
- package/src/components/scroll-view/scroll-view-class-style.test.ts +134 -0
- package/src/components/scroll-view/scroll-view-projection.test.ts +194 -0
- package/src/components/scroll-view/shared.ts +836 -0
- package/src/components/scroll-view/sticky-header.ts +230 -0
- package/src/components/section-list/index.ts +445 -0
- package/src/components/switch/android-switch-class.test.ts +42 -0
- package/src/components/switch/index.android.ts +61 -0
- package/src/components/switch/index.ios.ts +60 -0
- package/src/components/switch/index.ts +4 -0
- package/src/components/switch/shared.ts +197 -0
- package/src/components/switch/switch.test.ts +92 -0
- package/src/components/text-input-class-style.test.ts +54 -0
- package/src/components/text-input.ts +536 -0
- package/src/components/touchable-native-feedback.test.ts +49 -0
- package/src/components/touchable-native-feedback.ts +260 -0
- package/src/components/touchable.test.ts +102 -0
- package/src/components/touchable.ts +643 -0
- package/src/components/virtualized-list/directives.ts +169 -0
- package/src/components/virtualized-list/index.ts +1204 -0
- package/src/components/virtualized-list/virtualized-list-class-style.test.ts +76 -0
- package/src/components/virtualized-section-list/directives.ts +91 -0
- package/src/components/virtualized-section-list/index.ts +598 -0
- package/src/components/virtualized-section-list/virtualized-section-list-class-style.test.ts +60 -0
- package/src/components.ts +149 -0
- package/src/create-portal.test.ts +90 -0
- package/src/create-portal.ts +74 -0
- package/src/create-tunnel.test.ts +120 -0
- package/src/create-tunnel.ts +136 -0
- package/src/descriptor-to-angular/descriptor-outlet.test.ts +94 -0
- package/src/descriptor-to-angular/index.ts +190 -0
- package/src/host-instance/host-instance.test.ts +49 -0
- package/src/host-instance/index.ts +36 -0
- package/src/index.ts +257 -0
- package/src/modules/animated/animated-scroll-view.test.ts +85 -0
- package/src/modules/animated/create-animated-component.ts +435 -0
- package/src/modules/animated/index.ts +105 -0
- package/src/modules/app-registry/app-registry.test.ts +106 -0
- package/src/modules/app-registry/index.ts +60 -0
- package/src/modules/status-bar.test.ts +50 -0
- package/src/modules/status-bar.ts +57 -0
- package/src/primitives/index.ts +119 -0
- package/src/primitives/shared.ts +191 -0
- package/src/render.test.ts +147 -0
- package/src/render.ts +224 -0
- package/src/renderer.test.ts +179 -0
- package/src/renderer.ts +407 -0
- package/src/services/color-scheme.service.ts +27 -0
- package/src/services/index.ts +2 -0
- package/src/services/services.test.ts +163 -0
- package/src/services/window-dimensions.service.ts +41 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// Angular descriptor outlet. The React/Vue bridges can return framework elements directly
|
|
2
|
+
// (`descriptorToReact` / `descriptorToVue`); Angular needs a tiny standalone component that
|
|
3
|
+
// consumes a Descriptor tree and drives Renderer2 imperatively. This mirrors wolf-tui's
|
|
4
|
+
// WNodeOutlet, but patches same type/key nodes instead of clearing and recreating the subtree so
|
|
5
|
+
// Symbiote keeps retained-node identity and Fabric stays on the clone-on-write path.
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
ChangeDetectionStrategy,
|
|
9
|
+
Component,
|
|
10
|
+
ElementRef,
|
|
11
|
+
inject,
|
|
12
|
+
Input,
|
|
13
|
+
Renderer2,
|
|
14
|
+
type OnChanges,
|
|
15
|
+
type OnDestroy,
|
|
16
|
+
type SimpleChanges,
|
|
17
|
+
} from '@angular/core';
|
|
18
|
+
import type { IDescriptor, IDescriptorChild } from '@symbiote-native/components';
|
|
19
|
+
|
|
20
|
+
type IRenderedChild = IRenderedElement | IRenderedText;
|
|
21
|
+
|
|
22
|
+
type IRenderedElement = {
|
|
23
|
+
kind: 'element';
|
|
24
|
+
node: unknown;
|
|
25
|
+
descriptor: IDescriptor;
|
|
26
|
+
props: Record<string, unknown>;
|
|
27
|
+
children: IRenderedChild[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type IRenderedText = {
|
|
31
|
+
kind: 'text';
|
|
32
|
+
node: unknown;
|
|
33
|
+
value: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
@Component({
|
|
37
|
+
selector: 'symbiote-descriptor-outlet',
|
|
38
|
+
standalone: true,
|
|
39
|
+
template: '',
|
|
40
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
41
|
+
})
|
|
42
|
+
export class DescriptorOutlet implements OnChanges, OnDestroy {
|
|
43
|
+
@Input({ required: true }) node!: IDescriptor;
|
|
44
|
+
|
|
45
|
+
private readonly renderer = inject(Renderer2);
|
|
46
|
+
private readonly hostNode = inject<ElementRef<unknown>>(ElementRef).nativeElement;
|
|
47
|
+
private rendered: IRenderedElement | undefined;
|
|
48
|
+
|
|
49
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
50
|
+
if (!('node' in changes) || this.node === undefined) return;
|
|
51
|
+
this.rendered = this.patchRoot(this.rendered, this.node);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
ngOnDestroy(): void {
|
|
55
|
+
if (this.rendered === undefined) return;
|
|
56
|
+
this.renderer.removeChild(this.hostNode, this.rendered.node);
|
|
57
|
+
this.rendered = undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private patchRoot(rendered: IRenderedElement | undefined, next: IDescriptor): IRenderedElement {
|
|
61
|
+
if (rendered === undefined) {
|
|
62
|
+
const created = this.createElement(next);
|
|
63
|
+
this.renderer.appendChild(this.hostNode, created.node);
|
|
64
|
+
return created;
|
|
65
|
+
}
|
|
66
|
+
return this.patchElement(this.hostNode, rendered, next);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private createChild(child: IDescriptorChild): IRenderedChild {
|
|
70
|
+
return typeof child === 'string' ? this.createText(child) : this.createElement(child);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private createText(value: string): IRenderedText {
|
|
74
|
+
return { kind: 'text', node: this.renderer.createText(value), value };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private createElement(descriptor: IDescriptor): IRenderedElement {
|
|
78
|
+
const node = this.renderer.createElement(descriptor.type);
|
|
79
|
+
const props = { ...descriptor.props };
|
|
80
|
+
for (const [key, value] of Object.entries(props)) {
|
|
81
|
+
this.renderer.setProperty(node, key, value);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const children = descriptor.children.map(child => this.createChild(child));
|
|
85
|
+
for (const child of children) {
|
|
86
|
+
this.renderer.appendChild(node, child.node);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { kind: 'element', node, descriptor, props, children };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private patchChild(
|
|
93
|
+
parent: unknown,
|
|
94
|
+
rendered: IRenderedChild,
|
|
95
|
+
next: IDescriptorChild,
|
|
96
|
+
): IRenderedChild {
|
|
97
|
+
if (typeof next === 'string') {
|
|
98
|
+
if (rendered.kind === 'text') {
|
|
99
|
+
if (rendered.value !== next) {
|
|
100
|
+
this.renderer.setValue(rendered.node, next);
|
|
101
|
+
rendered.value = next;
|
|
102
|
+
}
|
|
103
|
+
return rendered;
|
|
104
|
+
}
|
|
105
|
+
const replacement = this.createText(next);
|
|
106
|
+
this.replaceChild(parent, rendered.node, replacement.node);
|
|
107
|
+
return replacement;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (rendered.kind === 'element') {
|
|
111
|
+
return this.patchElement(parent, rendered, next);
|
|
112
|
+
}
|
|
113
|
+
const replacement = this.createElement(next);
|
|
114
|
+
this.replaceChild(parent, rendered.node, replacement.node);
|
|
115
|
+
return replacement;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private patchElement(
|
|
119
|
+
parent: unknown,
|
|
120
|
+
rendered: IRenderedElement,
|
|
121
|
+
next: IDescriptor,
|
|
122
|
+
): IRenderedElement {
|
|
123
|
+
if (!sameElement(rendered.descriptor, next)) {
|
|
124
|
+
const replacement = this.createElement(next);
|
|
125
|
+
this.replaceChild(parent, rendered.node, replacement.node);
|
|
126
|
+
return replacement;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
this.patchProps(rendered, next.props);
|
|
130
|
+
rendered.children = this.patchChildren(rendered.node, rendered.children, next.children);
|
|
131
|
+
rendered.descriptor = next;
|
|
132
|
+
return rendered;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private patchProps(rendered: IRenderedElement, nextProps: Record<string, unknown>): void {
|
|
136
|
+
const prevProps = rendered.props;
|
|
137
|
+
for (const key of Object.keys(prevProps)) {
|
|
138
|
+
if (!(key in nextProps)) {
|
|
139
|
+
this.renderer.setProperty(rendered.node, key, undefined);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
for (const [key, value] of Object.entries(nextProps)) {
|
|
143
|
+
if (!Object.is(prevProps[key], value)) {
|
|
144
|
+
this.renderer.setProperty(rendered.node, key, value);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
rendered.props = { ...nextProps };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private patchChildren(
|
|
151
|
+
parent: unknown,
|
|
152
|
+
renderedChildren: IRenderedChild[],
|
|
153
|
+
nextChildren: IDescriptorChild[],
|
|
154
|
+
): IRenderedChild[] {
|
|
155
|
+
const nextRendered: IRenderedChild[] = [];
|
|
156
|
+
const common = Math.min(renderedChildren.length, nextChildren.length);
|
|
157
|
+
|
|
158
|
+
for (let i = 0; i < common; i++) {
|
|
159
|
+
const rendered = renderedChildren[i];
|
|
160
|
+
const next = nextChildren[i];
|
|
161
|
+
if (rendered !== undefined && next !== undefined) {
|
|
162
|
+
nextRendered.push(this.patchChild(parent, rendered, next));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (let i = common; i < nextChildren.length; i++) {
|
|
167
|
+
const next = nextChildren[i];
|
|
168
|
+
if (next === undefined) continue;
|
|
169
|
+
const child = this.createChild(next);
|
|
170
|
+
this.renderer.appendChild(parent, child.node);
|
|
171
|
+
nextRendered.push(child);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
for (let i = common; i < renderedChildren.length; i++) {
|
|
175
|
+
const rendered = renderedChildren[i];
|
|
176
|
+
if (rendered !== undefined) this.renderer.removeChild(parent, rendered.node);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return nextRendered;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private replaceChild(parent: unknown, oldChild: unknown, newChild: unknown): void {
|
|
183
|
+
this.renderer.insertBefore(parent, newChild, oldChild);
|
|
184
|
+
this.renderer.removeChild(parent, oldChild);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function sameElement(prev: IDescriptor, next: IDescriptor): boolean {
|
|
189
|
+
return prev.type === next.type && prev.key === next.key;
|
|
190
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Co-located test for findNodeHandle (ADR 0025), the Angular twin of adapters/vue/src/host-instance/host-instance.test.ts.
|
|
2
|
+
// Proves the Angular adapter can resolve a raw engine node, an engine public instance, a bare
|
|
3
|
+
// reactTag, and null/undefined to a native tag using the engine's getNativeTag.
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
6
|
+
import { createElement, createSurface, getNativeTag } from '@symbiote-native/engine';
|
|
7
|
+
import { installFabric } from '@symbiote-native/test-utils';
|
|
8
|
+
import { findNodeHandle } from './index';
|
|
9
|
+
|
|
10
|
+
installFabric();
|
|
11
|
+
const ROOT_TAG = 708;
|
|
12
|
+
|
|
13
|
+
describe('Angular findNodeHandle on the engine', () => {
|
|
14
|
+
it('returns the committed tag for a raw engine node', async () => {
|
|
15
|
+
const surface = createSurface(ROOT_TAG);
|
|
16
|
+
const node = createElement('RCTView');
|
|
17
|
+
surface.appendChild(node);
|
|
18
|
+
surface.commit();
|
|
19
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
20
|
+
|
|
21
|
+
const tag = getNativeTag(node);
|
|
22
|
+
expect(tag).toBeGreaterThan(0);
|
|
23
|
+
expect(findNodeHandle(node)).toBe(tag);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('returns the committed tag for a public instance (toPublicInstance graft)', async () => {
|
|
27
|
+
const surface = createSurface(ROOT_TAG + 1);
|
|
28
|
+
const node = createElement('RCTView');
|
|
29
|
+
surface.appendChild(node);
|
|
30
|
+
surface.commit();
|
|
31
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
32
|
+
|
|
33
|
+
const tag = getNativeTag(node);
|
|
34
|
+
// The public instance is the same identity as the engine node; findNodeHandle accepts it.
|
|
35
|
+
const publicInstance = node;
|
|
36
|
+
expect(findNodeHandle(publicInstance)).toBe(tag);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('passes a bare number through idempotently', () => {
|
|
40
|
+
expect(findNodeHandle(42)).toBe(42);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('returns null for null, undefined, and unknown inputs', () => {
|
|
44
|
+
expect(findNodeHandle(null)).toBeNull();
|
|
45
|
+
expect(findNodeHandle(undefined)).toBeNull();
|
|
46
|
+
expect(findNodeHandle('not-a-node' as any)).toBeNull();
|
|
47
|
+
expect(findNodeHandle({} as any)).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// findNodeHandle, the Angular twin of adapters/react/src/host-instance.ts and
|
|
2
|
+
// adapters/vue/src/host-instance/index.ts. RN's "ref/instance -> native reactTag" lookup,
|
|
3
|
+
// the seam imperative-interop libraries reach through.
|
|
4
|
+
//
|
|
5
|
+
// Angular template refs on a primitive host (`<View #myView>`) receive the component instance,
|
|
6
|
+
// not the raw engine node. SymbiotePrimitiveHost exposes `nativeElement`, which holds the
|
|
7
|
+
// engine host node that `getNativeTag` is keyed on. This adapter accepts:
|
|
8
|
+
// - a bare number (idempotent)
|
|
9
|
+
// - an engine host node / public instance
|
|
10
|
+
// - an Angular ElementRef wrapping the host node
|
|
11
|
+
// - a SymbiotePrimitiveHost component instance (via its public `nativeElement` getter)
|
|
12
|
+
// - null/undefined -> null
|
|
13
|
+
// An uncommitted or unknown input surfaces as null.
|
|
14
|
+
|
|
15
|
+
import { ElementRef } from '@angular/core';
|
|
16
|
+
import { getNativeTag, isSymbioteNode, type ISymbioteNode } from '@symbiote-native/engine';
|
|
17
|
+
|
|
18
|
+
export type { IHostInstance } from '@symbiote-native/engine';
|
|
19
|
+
|
|
20
|
+
function resolveHostNode(candidate: unknown): ISymbioteNode | null {
|
|
21
|
+
if (candidate === null || candidate === undefined) return null;
|
|
22
|
+
if (isSymbioteNode(candidate)) return candidate;
|
|
23
|
+
if (candidate instanceof ElementRef) return resolveHostNode(candidate.nativeElement);
|
|
24
|
+
const maybeHost = candidate as { nativeElement?: unknown };
|
|
25
|
+
if (typeof maybeHost.nativeElement !== 'undefined') {
|
|
26
|
+
return resolveHostNode(maybeHost.nativeElement);
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function findNodeHandle(componentOrHandle: unknown): number | null {
|
|
32
|
+
if (componentOrHandle === null || componentOrHandle === undefined) return null;
|
|
33
|
+
if (typeof componentOrHandle === 'number') return componentOrHandle;
|
|
34
|
+
const node = resolveHostNode(componentOrHandle);
|
|
35
|
+
return node ? (getNativeTag(node) ?? null) : null;
|
|
36
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// @symbiote-native/angular: a thin Angular reconciler over @symbiote-native/engine. A custom Renderer2 +
|
|
2
|
+
// RendererFactory2 map each node op onto the engine's mutation API; all Fabric clone-on-write
|
|
3
|
+
// lives in the engine, shared with every other adapter. App code names only @symbiote-native/angular.
|
|
4
|
+
//
|
|
5
|
+
// SEAM SCAFFOLD: mount/unmount + the renderer seam + host intrinsic selectors. Full RN-like
|
|
6
|
+
// composed components still flow through the shared @symbiote-native/components bridge — see the
|
|
7
|
+
// `angular-adapter` skill (§6 descriptorToAngular, the layered milestones).
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
ActivityIndicator,
|
|
11
|
+
anchorHostStyle,
|
|
12
|
+
Button,
|
|
13
|
+
FlatList,
|
|
14
|
+
HorizontalScrollContentView,
|
|
15
|
+
HorizontalScrollView,
|
|
16
|
+
Image,
|
|
17
|
+
ImageBackground,
|
|
18
|
+
InputAccessoryView,
|
|
19
|
+
KeyboardAvoidingView,
|
|
20
|
+
Modal,
|
|
21
|
+
Pressable,
|
|
22
|
+
RefreshControl,
|
|
23
|
+
SafeAreaView,
|
|
24
|
+
ScrollContentView,
|
|
25
|
+
ScrollView,
|
|
26
|
+
ScrollViewStickyHeader,
|
|
27
|
+
SectionList,
|
|
28
|
+
stableAnchorStyle,
|
|
29
|
+
Switch,
|
|
30
|
+
SymbioteHostPropsDirective,
|
|
31
|
+
Text,
|
|
32
|
+
TextInput,
|
|
33
|
+
TouchableHighlight,
|
|
34
|
+
TouchableNativeFeedback,
|
|
35
|
+
TouchableOpacity,
|
|
36
|
+
TouchableWithoutFeedback,
|
|
37
|
+
View,
|
|
38
|
+
VirtualizedList,
|
|
39
|
+
VirtualizedSectionList,
|
|
40
|
+
VListEmptyDirective,
|
|
41
|
+
VListFooterDirective,
|
|
42
|
+
VListHeaderDirective,
|
|
43
|
+
VListItemDirective,
|
|
44
|
+
VListSeparatorDirective,
|
|
45
|
+
VSectionFooterDirective,
|
|
46
|
+
VSectionHeaderDirective,
|
|
47
|
+
VSectionItemDirective,
|
|
48
|
+
VSectionSeparatorDirective,
|
|
49
|
+
} from './components';
|
|
50
|
+
export { Animated } from './modules/animated';
|
|
51
|
+
// Also exposed as named top-level symbols (not just Animated.View/.Text/...): ngtsc's partial-mode
|
|
52
|
+
// static evaluator (real AOT, see angular-adapter skill §4) can't trace a component class through
|
|
53
|
+
// property access on an external namespace object, only through a direct named import binding —
|
|
54
|
+
// so `<AnimatedView>` in a template requires `import { AnimatedView } from '@symbiote-native/angular'`,
|
|
55
|
+
// not `const AnimatedView = Animated.View`. Plain tsc/vitest don't catch this; only a real ngc run does.
|
|
56
|
+
export {
|
|
57
|
+
AnimatedFlatList,
|
|
58
|
+
AnimatedImage,
|
|
59
|
+
AnimatedScrollView,
|
|
60
|
+
AnimatedSectionList,
|
|
61
|
+
AnimatedText,
|
|
62
|
+
AnimatedView,
|
|
63
|
+
} from './modules/animated';
|
|
64
|
+
export type {
|
|
65
|
+
IActivityIndicatorProps,
|
|
66
|
+
IAngularImageBackgroundProps,
|
|
67
|
+
IAngularInputAccessoryViewProps,
|
|
68
|
+
IAngularKeyboardAvoidingViewProps,
|
|
69
|
+
IAngularModalProps,
|
|
70
|
+
IAngularPressableProps,
|
|
71
|
+
IAngularRefreshControlProps,
|
|
72
|
+
IAngularSafeAreaViewProps,
|
|
73
|
+
IAngularScrollViewProps,
|
|
74
|
+
IAngularTextInputProps,
|
|
75
|
+
IAngularTouchableHighlightProps,
|
|
76
|
+
IAngularTouchableNativeFeedbackProps,
|
|
77
|
+
IAngularTouchableOpacityProps,
|
|
78
|
+
IAngularTouchableWithoutFeedbackProps,
|
|
79
|
+
IButtonProps,
|
|
80
|
+
ICellLayout,
|
|
81
|
+
IFlatListHandle,
|
|
82
|
+
IFlatListProps,
|
|
83
|
+
IEnterKeyHint,
|
|
84
|
+
IImageCacheStatus,
|
|
85
|
+
IImageProps,
|
|
86
|
+
IImageSize,
|
|
87
|
+
IImageSource,
|
|
88
|
+
IImageSourceProp,
|
|
89
|
+
IInputMode,
|
|
90
|
+
IKeyboardAvoidingBehavior,
|
|
91
|
+
IModalAnimationType,
|
|
92
|
+
IModalOrientation,
|
|
93
|
+
IModalOrientationChangeEvent,
|
|
94
|
+
IModalPresentationStyle,
|
|
95
|
+
INativeFeedbackBackground,
|
|
96
|
+
IResizeMode,
|
|
97
|
+
IRippleBackground,
|
|
98
|
+
IScrollViewHandle,
|
|
99
|
+
ISectionListHandle,
|
|
100
|
+
ISectionListProps,
|
|
101
|
+
ISeparatorProps,
|
|
102
|
+
ISeparators,
|
|
103
|
+
IStickyHeaderComponentType,
|
|
104
|
+
ISubmitBehavior,
|
|
105
|
+
IThemeAttrBackground,
|
|
106
|
+
IViewabilityConfig,
|
|
107
|
+
IViewabilityConfigCallbackPair,
|
|
108
|
+
IViewableItemsChangedInfo,
|
|
109
|
+
IViewToken,
|
|
110
|
+
IVirtualizedListHandle,
|
|
111
|
+
IVirtualizedListProps,
|
|
112
|
+
IVirtualizedSectionListHandle,
|
|
113
|
+
IVirtualizedSectionListProps,
|
|
114
|
+
IVListItemContext,
|
|
115
|
+
IVListSeparatorContext,
|
|
116
|
+
IVSectionContext,
|
|
117
|
+
IVSectionItemContext,
|
|
118
|
+
ISection,
|
|
119
|
+
ISwitchProps,
|
|
120
|
+
ISwitchTrackColor,
|
|
121
|
+
ITextInputHandle,
|
|
122
|
+
ITextInputSelection,
|
|
123
|
+
} from './components';
|
|
124
|
+
export { setImageSourceResolver } from './components';
|
|
125
|
+
export { mount, unmount } from './render';
|
|
126
|
+
// The generic Descriptor→Angular bridge (§6 of the angular-adapter skill), the twin of
|
|
127
|
+
// descriptorToReact/descriptorToVue. Exported so a component defined OUTSIDE this package (e.g.
|
|
128
|
+
// @symbiote-native/slider) can render a shared @symbiote-native/components/@symbiote-native/slider Descriptor tree
|
|
129
|
+
// without hand-writing its own Renderer2 walker.
|
|
130
|
+
export { DescriptorOutlet } from './descriptor-to-angular';
|
|
131
|
+
// createPortal (same-surface only — see the file header) and createTunnel (cross-surface,
|
|
132
|
+
// see its file header) are the Angular twins of the React/Vue portal/tunnel primitives.
|
|
133
|
+
// Angular can't synthesize components at runtime (no JIT under Metro/Hermes), so both are
|
|
134
|
+
// static, pre-authored structural directives (`*portal`/`*tunnelIn`, the `*ngIf`/`*ngFor`
|
|
135
|
+
// idiom) parameterized by an `@Input()`, rather than a factory returning fresh components per
|
|
136
|
+
// call — see the react-adapter-portal / angular-adapter skills.
|
|
137
|
+
export { PortalDirective, PortalOutletDirective } from './create-portal';
|
|
138
|
+
export { createTunnel, TunnelInDirective, TunnelOut, type ITunnelStore } from './create-tunnel';
|
|
139
|
+
export { SymbioteRenderer, SymbioteRendererFactory } from './renderer';
|
|
140
|
+
export { findNodeHandle } from './host-instance';
|
|
141
|
+
export type { IHostInstance } from './host-instance';
|
|
142
|
+
export { StatusBar } from './modules/status-bar';
|
|
143
|
+
export type { IStatusBarProps, IStatusBarStyle } from './modules/status-bar';
|
|
144
|
+
// AppRegistry: RN's app entry point over `mount`. setHostRegistrar wires RN's own
|
|
145
|
+
// registrar so the native Fabric host finds our runnable by app key.
|
|
146
|
+
export { AppRegistry, setHostRegistrar } from './modules/app-registry';
|
|
147
|
+
export type {
|
|
148
|
+
IComponentProvider,
|
|
149
|
+
IAppParameters,
|
|
150
|
+
IRunnable,
|
|
151
|
+
IHostRegistrar,
|
|
152
|
+
IWrapperComponentProvider,
|
|
153
|
+
IRegistry,
|
|
154
|
+
IHeadlessTask,
|
|
155
|
+
ITaskProvider,
|
|
156
|
+
ITaskCanceller,
|
|
157
|
+
ITaskCancelProvider,
|
|
158
|
+
} from './modules/app-registry';
|
|
159
|
+
export { ColorSchemeService, WindowDimensionsService } from './services';
|
|
160
|
+
|
|
161
|
+
// Framework-agnostic runtime modules from @symbiote-native/engine. Every adapter re-exports them so
|
|
162
|
+
// app code names only @symbiote-native/angular.
|
|
163
|
+
export {
|
|
164
|
+
Alert,
|
|
165
|
+
Share,
|
|
166
|
+
ActionSheetIOS,
|
|
167
|
+
Linking,
|
|
168
|
+
Vibration,
|
|
169
|
+
ToastAndroid,
|
|
170
|
+
Settings,
|
|
171
|
+
I18nManager,
|
|
172
|
+
Dimensions,
|
|
173
|
+
Appearance,
|
|
174
|
+
AppState,
|
|
175
|
+
Keyboard,
|
|
176
|
+
KEYBOARD_EVENT,
|
|
177
|
+
BackHandler,
|
|
178
|
+
PermissionsAndroid,
|
|
179
|
+
PERMISSIONS,
|
|
180
|
+
RESULTS,
|
|
181
|
+
AccessibilityInfo,
|
|
182
|
+
LayoutAnimation,
|
|
183
|
+
InteractionManager,
|
|
184
|
+
PanResponder,
|
|
185
|
+
PixelRatio,
|
|
186
|
+
PlatformColor,
|
|
187
|
+
DynamicColorIOS,
|
|
188
|
+
} from '@symbiote-native/engine';
|
|
189
|
+
export type {
|
|
190
|
+
IAlertType,
|
|
191
|
+
IAlertButtonStyle,
|
|
192
|
+
IAlertButton,
|
|
193
|
+
IAlertButtons,
|
|
194
|
+
IAlertOptions,
|
|
195
|
+
IShareContent,
|
|
196
|
+
IShareOptions,
|
|
197
|
+
IShareAction,
|
|
198
|
+
IActionSheetIOSOptions,
|
|
199
|
+
IShareActionSheetIOSOptions,
|
|
200
|
+
IShareActionSheetError,
|
|
201
|
+
IUrlEvent,
|
|
202
|
+
II18nManagerConstants,
|
|
203
|
+
IDisplayMetrics,
|
|
204
|
+
IDisplayMetricsAndroid,
|
|
205
|
+
IDimensionsPayload,
|
|
206
|
+
IDimensionsSet,
|
|
207
|
+
IDimensionsKey,
|
|
208
|
+
IDimensionsChangeListener,
|
|
209
|
+
IDimensionsStatic,
|
|
210
|
+
IColorSchemeName,
|
|
211
|
+
IColorSchemePreference,
|
|
212
|
+
IAppStateStatus,
|
|
213
|
+
IAppStateEvent,
|
|
214
|
+
IKeyboardEventName,
|
|
215
|
+
IKeyboardEvent,
|
|
216
|
+
IKeyboardMetrics,
|
|
217
|
+
IBackPressEventName,
|
|
218
|
+
IBackPressHandler,
|
|
219
|
+
IPermission,
|
|
220
|
+
IPermissionStatus,
|
|
221
|
+
IRationale,
|
|
222
|
+
IAccessibilityChangeEvent,
|
|
223
|
+
IAccessibilityChangeEventName,
|
|
224
|
+
IAccessibilityChangeEventHandler,
|
|
225
|
+
IAccessibilityAnnouncementFinishedEvent,
|
|
226
|
+
IAnnounceForAccessibilityOptions,
|
|
227
|
+
IAccessibilityEventType,
|
|
228
|
+
ILayoutAnimationType,
|
|
229
|
+
ILayoutAnimationProperty,
|
|
230
|
+
ILayoutAnimationConfig,
|
|
231
|
+
ILayoutAnimationAnim,
|
|
232
|
+
IInteractionEvent,
|
|
233
|
+
ISimpleTask,
|
|
234
|
+
IPromiseTask,
|
|
235
|
+
ITask,
|
|
236
|
+
IHandle,
|
|
237
|
+
IPanResponderGestureState,
|
|
238
|
+
IPanResponderCallbacks,
|
|
239
|
+
IGestureResponderHandlers,
|
|
240
|
+
IPanResponderInstance,
|
|
241
|
+
IPixelRatioStatic,
|
|
242
|
+
IColorValue,
|
|
243
|
+
IOpaqueColorValue,
|
|
244
|
+
IDynamicColorIOSTuple,
|
|
245
|
+
} from '@symbiote-native/engine';
|
|
246
|
+
export {
|
|
247
|
+
dlog,
|
|
248
|
+
flattenStyle,
|
|
249
|
+
isDebug,
|
|
250
|
+
Platform,
|
|
251
|
+
processColor,
|
|
252
|
+
setColorProcessor,
|
|
253
|
+
setDeviceEventSource,
|
|
254
|
+
setNativeViewConfigSource,
|
|
255
|
+
StyleSheet,
|
|
256
|
+
} from '@symbiote-native/engine';
|
|
257
|
+
export type { IRootTag, ISymbioteEvent, ISymbioteNode } from '@symbiote-native/engine';
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Regression tests for two Android-only bugs AnimatedScrollView's bespoke template hit because
|
|
2
|
+
// it talks to the raw symbiote-scroll-view primitive directly instead of reusing the real
|
|
3
|
+
// ScrollView component (which already has both fixes — see scroll-view/shared.ts):
|
|
4
|
+
//
|
|
5
|
+
// 1. It projected <ng-content> straight into symbiote-scroll-view with no content wrapper. On
|
|
6
|
+
// Android, symbiote-scroll-content resolves to a plain RCTView, which Fabric view-flattens
|
|
7
|
+
// away unless collapsable:false pins it — so multiple projected children were hoisted up as
|
|
8
|
+
// direct children of the scroll view, which natively hosts exactly one ("ScrollView can
|
|
9
|
+
// host only one direct child" -> addViewAt crash).
|
|
10
|
+
// 2. It never defaulted nestedScrollEnabled. RN defaults nested scrolling ON (ScrollView.js
|
|
11
|
+
// `nestedScrollEnabled ?? true`), but Android needs it explicit or a ScrollView nested
|
|
12
|
+
// inside another scrollable container (this canary's own nested demo) never receives touch
|
|
13
|
+
// — it renders fine but is static, the outer ScrollView swallows the gesture.
|
|
14
|
+
//
|
|
15
|
+
// The fake Fabric harness doesn't simulate Android's real view-flattening or touch dispatch, so
|
|
16
|
+
// these tests only prove the structural/prop invariants that prevent both bugs, not the
|
|
17
|
+
// on-device symptoms themselves — those still need a real Android host.
|
|
18
|
+
import '@angular/compiler';
|
|
19
|
+
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
20
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
21
|
+
import { installFabric } from '@symbiote-native/test-utils';
|
|
22
|
+
import { mount, unmount } from '../../render';
|
|
23
|
+
import { AnimatedScrollView } from './create-animated-component';
|
|
24
|
+
|
|
25
|
+
const ROOT_TAG = 927;
|
|
26
|
+
const OVERRIDE_ROOT_TAG = 928;
|
|
27
|
+
const fabric = installFabric();
|
|
28
|
+
const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
|
|
29
|
+
|
|
30
|
+
class AnimatedScrollViewApp {}
|
|
31
|
+
Component({
|
|
32
|
+
selector: 'animated-scroll-view-test',
|
|
33
|
+
standalone: true,
|
|
34
|
+
imports: [AnimatedScrollView],
|
|
35
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
36
|
+
template: `
|
|
37
|
+
<AnimatedScrollView>
|
|
38
|
+
<symbiote-view testID="a"></symbiote-view>
|
|
39
|
+
<symbiote-view testID="b"></symbiote-view>
|
|
40
|
+
</AnimatedScrollView>
|
|
41
|
+
`,
|
|
42
|
+
})(AnimatedScrollViewApp);
|
|
43
|
+
|
|
44
|
+
class AnimatedScrollViewOverrideApp {}
|
|
45
|
+
Component({
|
|
46
|
+
selector: 'animated-scroll-view-override-test',
|
|
47
|
+
standalone: true,
|
|
48
|
+
imports: [AnimatedScrollView],
|
|
49
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
50
|
+
template: `
|
|
51
|
+
<AnimatedScrollView [animatedProps]="{ nestedScrollEnabled: false }">
|
|
52
|
+
<symbiote-view testID="a"></symbiote-view>
|
|
53
|
+
</AnimatedScrollView>
|
|
54
|
+
`,
|
|
55
|
+
})(AnimatedScrollViewOverrideApp);
|
|
56
|
+
|
|
57
|
+
beforeEach(() => fabric.reset());
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
unmount(ROOT_TAG);
|
|
60
|
+
unmount(OVERRIDE_ROOT_TAG);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('AnimatedScrollView', () => {
|
|
64
|
+
it('wraps multiple projected children in a single non-collapsable content view', async () => {
|
|
65
|
+
mount(ROOT_TAG, AnimatedScrollViewApp);
|
|
66
|
+
await tick();
|
|
67
|
+
|
|
68
|
+
const scrollView = fabric.find(node => node.viewName === 'RCTScrollView');
|
|
69
|
+
expect(scrollView?.children).toHaveLength(1);
|
|
70
|
+
expect(scrollView?.props.nestedScrollEnabled).toBe(true);
|
|
71
|
+
|
|
72
|
+
const content = scrollView?.children[0];
|
|
73
|
+
expect(content?.viewName).toBe('RCTScrollContentView');
|
|
74
|
+
expect(content?.props.collapsable).toBe(false);
|
|
75
|
+
expect(content?.children.map(child => child.props.testID)).toEqual(['a', 'b']);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('lets an explicit nestedScrollEnabled in animatedProps override the default', async () => {
|
|
79
|
+
mount(OVERRIDE_ROOT_TAG, AnimatedScrollViewOverrideApp);
|
|
80
|
+
await tick();
|
|
81
|
+
|
|
82
|
+
const scrollView = fabric.find(node => node.viewName === 'RCTScrollView');
|
|
83
|
+
expect(scrollView?.props.nestedScrollEnabled).toBe(false);
|
|
84
|
+
});
|
|
85
|
+
});
|