@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,270 @@
|
|
|
1
|
+
// ImageBackground: the Angular lifecycle half. ImageBackground has NO native host of its own —
|
|
2
|
+
// it composes an outer View, an absolute-fill Image behind the user children, and the children
|
|
3
|
+
// on top. The composition math (the absolute-fill, the wrapper-dimension proxy onto the inner
|
|
4
|
+
// image, the imageStyle merge) lives framework-agnostic in @symbiote-native/components/renderImageBackground
|
|
5
|
+
// and is shared verbatim with React/Vue. React/Vue bridge the Descriptor it returns; Angular has
|
|
6
|
+
// no hyperscript bridge, so it composes with a TEMPLATE instead and reuses renderImageBackground
|
|
7
|
+
// ONLY to compute the inner image's merged style (read off the tree it returns) — the math stays
|
|
8
|
+
// shared, never reimplemented. The inner <Image> is the adapter's own Image component, which owns
|
|
9
|
+
// source resolution / a11y folding / event emission; ImageBackground forwards every Image prop onto
|
|
10
|
+
// it. `style` is the WRAPPER View style; `imageStyle` targets the inner image. Children paint AFTER
|
|
11
|
+
// the image (on top) via <ng-content>. The Angular twin of the React/Vue ImageBackground.
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
15
|
+
ChangeDetectionStrategy,
|
|
16
|
+
Component,
|
|
17
|
+
ElementRef,
|
|
18
|
+
EventEmitter,
|
|
19
|
+
inject,
|
|
20
|
+
Input,
|
|
21
|
+
Output,
|
|
22
|
+
} from '@angular/core';
|
|
23
|
+
import {
|
|
24
|
+
renderImageBackground,
|
|
25
|
+
resolveAccessibilityProps,
|
|
26
|
+
type IAccessibilityProps,
|
|
27
|
+
type IAccessibilityStateValue,
|
|
28
|
+
type IAriaProps,
|
|
29
|
+
type IImageProps,
|
|
30
|
+
type IImageSourceProp,
|
|
31
|
+
type IResizeMode,
|
|
32
|
+
} from '@symbiote-native/components';
|
|
33
|
+
import {
|
|
34
|
+
resolveClassName,
|
|
35
|
+
type IStyleProp,
|
|
36
|
+
type ISymbioteEvent,
|
|
37
|
+
type IViewStyle,
|
|
38
|
+
} from '@symbiote-native/engine';
|
|
39
|
+
import { Image } from './image';
|
|
40
|
+
import { anchorHostStyle, ViewHost } from '../primitives';
|
|
41
|
+
|
|
42
|
+
// Mirrors React's IImageBackgroundProps minus children (Angular takes children via <ng-content>):
|
|
43
|
+
// every forwarding Image prop flows onto the inner image; `style` is the WRAPPER View style and
|
|
44
|
+
// `imageStyle` the inner image's, per <prop_types_split_agnostic_vs_per_adapter>.
|
|
45
|
+
export interface IAngularImageBackgroundProps extends Omit<IImageProps, 'style'> {
|
|
46
|
+
style?: IStyleProp<IViewStyle>;
|
|
47
|
+
// A bare string resolves through the shared style registry, like `class` on the wrapper.
|
|
48
|
+
imageStyle?: IStyleProp<IViewStyle> | string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// What the ImageBackground component itself takes as plain @Input()s: the full surface minus the
|
|
52
|
+
// inner Image's callback-shaped events, which it exposes as real @Output() EventEmitters instead
|
|
53
|
+
// (re-emitting the inner <Image>'s own already-converted outputs — see the template below).
|
|
54
|
+
export type IAngularImageBackgroundInputs = Omit<
|
|
55
|
+
IAngularImageBackgroundProps,
|
|
56
|
+
| 'onAccessibilityAction'
|
|
57
|
+
| 'onAccessibilityTap'
|
|
58
|
+
| 'onMagicTap'
|
|
59
|
+
| 'onAccessibilityEscape'
|
|
60
|
+
| 'onLoadStart'
|
|
61
|
+
| 'onLoad'
|
|
62
|
+
| 'onLoadEnd'
|
|
63
|
+
| 'onError'
|
|
64
|
+
| 'onProgress'
|
|
65
|
+
| 'onPartialLoad'
|
|
66
|
+
>;
|
|
67
|
+
|
|
68
|
+
@Component({
|
|
69
|
+
selector: 'ImageBackground',
|
|
70
|
+
standalone: true,
|
|
71
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
72
|
+
imports: [Image, ViewHost],
|
|
73
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
74
|
+
template: `
|
|
75
|
+
<symbiote-view [style]="wrapperStyle">
|
|
76
|
+
<Image
|
|
77
|
+
[source]="source"
|
|
78
|
+
[defaultSource]="defaultSource"
|
|
79
|
+
[loadingIndicatorSource]="loadingIndicatorSource"
|
|
80
|
+
[style]="imageStyle"
|
|
81
|
+
[resizeMode]="resizeMode"
|
|
82
|
+
[resizeMethod]="resizeMethod"
|
|
83
|
+
[tintColor]="tintColor"
|
|
84
|
+
[blurRadius]="blurRadius"
|
|
85
|
+
[capInsets]="capInsets"
|
|
86
|
+
[fadeDuration]="fadeDuration"
|
|
87
|
+
[progressiveRenderingEnabled]="progressiveRenderingEnabled"
|
|
88
|
+
[src]="src"
|
|
89
|
+
[srcSet]="srcSet"
|
|
90
|
+
[alt]="alt"
|
|
91
|
+
[width]="width"
|
|
92
|
+
[height]="height"
|
|
93
|
+
[crossOrigin]="crossOrigin"
|
|
94
|
+
[referrerPolicy]="referrerPolicy"
|
|
95
|
+
[testID]="testID"
|
|
96
|
+
[nativeID]="nativeID"
|
|
97
|
+
[accessible]="accessible"
|
|
98
|
+
[accessibilityLabel]="folded.accessibilityLabel"
|
|
99
|
+
[accessibilityHint]="folded.accessibilityHint"
|
|
100
|
+
[accessibilityRole]="folded.accessibilityRole"
|
|
101
|
+
[accessibilityState]="folded.accessibilityState"
|
|
102
|
+
[accessibilityValue]="folded.accessibilityValue"
|
|
103
|
+
[accessibilityActions]="folded.accessibilityActions"
|
|
104
|
+
[accessibilityLabelledBy]="folded.accessibilityLabelledBy"
|
|
105
|
+
[importantForAccessibility]="folded.importantForAccessibility"
|
|
106
|
+
[accessibilityLiveRegion]="folded.accessibilityLiveRegion"
|
|
107
|
+
[screenReaderFocusable]="folded.screenReaderFocusable"
|
|
108
|
+
[accessibilityViewIsModal]="folded.accessibilityViewIsModal"
|
|
109
|
+
[accessibilityElementsHidden]="folded.accessibilityElementsHidden"
|
|
110
|
+
[accessibilityIgnoresInvertColors]="folded.accessibilityIgnoresInvertColors"
|
|
111
|
+
[accessibilityLanguage]="folded.accessibilityLanguage"
|
|
112
|
+
[accessibilityRespondsToUserInteraction]="folded.accessibilityRespondsToUserInteraction"
|
|
113
|
+
[accessibilityShowsLargeContentViewer]="folded.accessibilityShowsLargeContentViewer"
|
|
114
|
+
[accessibilityLargeContentTitle]="folded.accessibilityLargeContentTitle"
|
|
115
|
+
(loadStart)="loadStart.emit($event)"
|
|
116
|
+
(load)="load.emit($event)"
|
|
117
|
+
(loadEnd)="loadEnd.emit($event)"
|
|
118
|
+
(error)="error.emit($event)"
|
|
119
|
+
(progress)="progress.emit($event)"
|
|
120
|
+
(partialLoad)="partialLoad.emit($event)"
|
|
121
|
+
(accessibilityAction)="accessibilityAction.emit($event)"
|
|
122
|
+
(accessibilityTap)="accessibilityTap.emit($event)"
|
|
123
|
+
(magicTap)="magicTap.emit($event)"
|
|
124
|
+
(accessibilityEscape)="accessibilityEscape.emit($event)"
|
|
125
|
+
/>
|
|
126
|
+
<ng-content></ng-content>
|
|
127
|
+
</symbiote-view>
|
|
128
|
+
`,
|
|
129
|
+
})
|
|
130
|
+
export class ImageBackground implements IAngularImageBackgroundInputs {
|
|
131
|
+
// The inner <Image>'s events as real Angular events, re-emitted verbatim through
|
|
132
|
+
// ImageBackground's own outputs: `(load)="load.emit($event)"`, not `[onLoad]="onLoad"`.
|
|
133
|
+
@Output() readonly accessibilityAction = new EventEmitter<ISymbioteEvent>();
|
|
134
|
+
@Output() readonly accessibilityTap = new EventEmitter<ISymbioteEvent>();
|
|
135
|
+
@Output() readonly magicTap = new EventEmitter<ISymbioteEvent>();
|
|
136
|
+
@Output() readonly accessibilityEscape = new EventEmitter<ISymbioteEvent>();
|
|
137
|
+
@Output() readonly loadStart = new EventEmitter<ISymbioteEvent>();
|
|
138
|
+
@Output() readonly load = new EventEmitter<ISymbioteEvent>();
|
|
139
|
+
@Output() readonly loadEnd = new EventEmitter<ISymbioteEvent>();
|
|
140
|
+
@Output() readonly error = new EventEmitter<ISymbioteEvent>();
|
|
141
|
+
@Output() readonly progress = new EventEmitter<ISymbioteEvent>();
|
|
142
|
+
@Output() readonly partialLoad = new EventEmitter<ISymbioteEvent>();
|
|
143
|
+
@Input() source?: IImageSourceProp;
|
|
144
|
+
@Input() defaultSource?: IImageSourceProp;
|
|
145
|
+
@Input() loadingIndicatorSource?: IImageSourceProp;
|
|
146
|
+
@Input() style?: IStyleProp<IViewStyle>;
|
|
147
|
+
@Input('imageStyle') imageStyleValue?: IStyleProp<IViewStyle> | string;
|
|
148
|
+
@Input() resizeMode?: IResizeMode;
|
|
149
|
+
@Input() resizeMethod?: IImageProps['resizeMethod'];
|
|
150
|
+
@Input() tintColor?: string;
|
|
151
|
+
@Input() blurRadius?: number;
|
|
152
|
+
@Input() capInsets?: IImageProps['capInsets'];
|
|
153
|
+
@Input() fadeDuration?: number;
|
|
154
|
+
@Input() progressiveRenderingEnabled?: boolean;
|
|
155
|
+
@Input() src?: string;
|
|
156
|
+
@Input() srcSet?: string;
|
|
157
|
+
@Input() alt?: string;
|
|
158
|
+
@Input() width?: number;
|
|
159
|
+
@Input() height?: number;
|
|
160
|
+
@Input() crossOrigin?: 'anonymous' | 'use-credentials';
|
|
161
|
+
@Input() referrerPolicy?: string;
|
|
162
|
+
@Input() testID?: string;
|
|
163
|
+
@Input() nativeID?: string;
|
|
164
|
+
@Input() accessible?: boolean;
|
|
165
|
+
@Input() accessibilityLabel?: string;
|
|
166
|
+
@Input() accessibilityHint?: string;
|
|
167
|
+
@Input() accessibilityRole?: IAccessibilityProps['accessibilityRole'];
|
|
168
|
+
@Input() accessibilityState?: IAccessibilityStateValue;
|
|
169
|
+
@Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
|
|
170
|
+
@Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
|
|
171
|
+
@Input() accessibilityLabelledBy?: string | string[];
|
|
172
|
+
@Input() importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
|
|
173
|
+
@Input() accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
|
|
174
|
+
@Input() screenReaderFocusable?: boolean;
|
|
175
|
+
@Input() accessibilityViewIsModal?: boolean;
|
|
176
|
+
@Input() accessibilityElementsHidden?: boolean;
|
|
177
|
+
@Input() accessibilityIgnoresInvertColors?: boolean;
|
|
178
|
+
@Input() accessibilityLanguage?: string;
|
|
179
|
+
@Input() accessibilityRespondsToUserInteraction?: boolean;
|
|
180
|
+
@Input() accessibilityShowsLargeContentViewer?: boolean;
|
|
181
|
+
@Input() accessibilityLargeContentTitle?: string;
|
|
182
|
+
@Input() role?: IAriaProps['role'];
|
|
183
|
+
@Input('aria-label') ariaLabel?: string;
|
|
184
|
+
@Input('aria-labelledby') ariaLabelledBy?: string;
|
|
185
|
+
@Input('aria-live') ariaLive?: IAriaProps['aria-live'];
|
|
186
|
+
@Input('aria-hidden') ariaHidden?: boolean;
|
|
187
|
+
@Input('aria-busy') ariaBusy?: boolean;
|
|
188
|
+
@Input('aria-checked') ariaChecked?: boolean | 'mixed';
|
|
189
|
+
@Input('aria-disabled') ariaDisabled?: boolean;
|
|
190
|
+
@Input('aria-expanded') ariaExpanded?: boolean;
|
|
191
|
+
@Input('aria-selected') ariaSelected?: boolean;
|
|
192
|
+
@Input('aria-modal') ariaModal?: boolean;
|
|
193
|
+
@Input('aria-valuemax') ariaValueMax?: number;
|
|
194
|
+
@Input('aria-valuemin') ariaValueMin?: number;
|
|
195
|
+
@Input('aria-valuenow') ariaValueNow?: number;
|
|
196
|
+
@Input('aria-valuetext') ariaValueText?: string;
|
|
197
|
+
|
|
198
|
+
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
199
|
+
// onto (see anchorHostStyle's doc comment) — NOT the inner `symbiote-view [style]="wrapperStyle"`
|
|
200
|
+
// one level down. Merged FIRST so the explicit `style` @Input still wins (flattenStyle's
|
|
201
|
+
// later-wins collapse), mirroring every other composed component's anchor merge. `imageStyle`
|
|
202
|
+
// below stays untouched per the ImageBackground-specific nuance: it targets the inner image, not
|
|
203
|
+
// this component's own root.
|
|
204
|
+
private readonly elementRef = inject(ElementRef);
|
|
205
|
+
|
|
206
|
+
get wrapperStyle(): unknown {
|
|
207
|
+
return [anchorHostStyle(this.elementRef), this.style];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// renderImageBackground owns the absolute-fill + wrapper-dimension-proxy + imageStyle merge
|
|
211
|
+
// (shared verbatim with React/Vue); read the inner image Descriptor's style off the tree it
|
|
212
|
+
// returns rather than reimplementing it. Only style/imageStyle drive that merge, so the image
|
|
213
|
+
// bag is empty here — the inner <Image> below resolves source / a11y / events on its own.
|
|
214
|
+
get imageStyle(): IStyleProp<IViewStyle> | undefined {
|
|
215
|
+
// imageStyle targets the INNER image (renderImageBackground's own field); resolve a
|
|
216
|
+
// class-name string here, before it flows into the merge.
|
|
217
|
+
const resolvedImageStyleValue =
|
|
218
|
+
typeof this.imageStyleValue === 'string'
|
|
219
|
+
? resolveClassName(this.imageStyleValue)
|
|
220
|
+
: this.imageStyleValue;
|
|
221
|
+
const inner = renderImageBackground({
|
|
222
|
+
style: this.style,
|
|
223
|
+
imageStyle: resolvedImageStyleValue,
|
|
224
|
+
image: { passthrough: {} },
|
|
225
|
+
}).children[0];
|
|
226
|
+
return typeof inner === 'string'
|
|
227
|
+
? undefined
|
|
228
|
+
: (inner.props.style as IStyleProp<IViewStyle> | undefined);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Fold the web aria-*/role aliases into the canonical accessibility* props once per render, so the
|
|
232
|
+
// inner image never sees an aria-* key (native ignores them) — the shared transform every adapter
|
|
233
|
+
// runs. The inner <Image> re-runs the same fold idempotently over the already-folded props.
|
|
234
|
+
get folded(): Partial<IAngularImageBackgroundProps> {
|
|
235
|
+
return resolveAccessibilityProps({
|
|
236
|
+
accessibilityLabel: this.accessibilityLabel,
|
|
237
|
+
accessibilityHint: this.accessibilityHint,
|
|
238
|
+
accessibilityRole: this.accessibilityRole,
|
|
239
|
+
accessibilityState: this.accessibilityState,
|
|
240
|
+
accessibilityValue: this.accessibilityValue,
|
|
241
|
+
accessibilityActions: this.accessibilityActions,
|
|
242
|
+
accessibilityLabelledBy: this.accessibilityLabelledBy,
|
|
243
|
+
importantForAccessibility: this.importantForAccessibility,
|
|
244
|
+
accessibilityLiveRegion: this.accessibilityLiveRegion,
|
|
245
|
+
screenReaderFocusable: this.screenReaderFocusable,
|
|
246
|
+
accessibilityViewIsModal: this.accessibilityViewIsModal,
|
|
247
|
+
accessibilityElementsHidden: this.accessibilityElementsHidden,
|
|
248
|
+
accessibilityIgnoresInvertColors: this.accessibilityIgnoresInvertColors,
|
|
249
|
+
accessibilityLanguage: this.accessibilityLanguage,
|
|
250
|
+
accessibilityRespondsToUserInteraction: this.accessibilityRespondsToUserInteraction,
|
|
251
|
+
accessibilityShowsLargeContentViewer: this.accessibilityShowsLargeContentViewer,
|
|
252
|
+
accessibilityLargeContentTitle: this.accessibilityLargeContentTitle,
|
|
253
|
+
role: this.role,
|
|
254
|
+
'aria-label': this.ariaLabel,
|
|
255
|
+
'aria-labelledby': this.ariaLabelledBy,
|
|
256
|
+
'aria-live': this.ariaLive,
|
|
257
|
+
'aria-hidden': this.ariaHidden,
|
|
258
|
+
'aria-busy': this.ariaBusy,
|
|
259
|
+
'aria-checked': this.ariaChecked,
|
|
260
|
+
'aria-disabled': this.ariaDisabled,
|
|
261
|
+
'aria-expanded': this.ariaExpanded,
|
|
262
|
+
'aria-selected': this.ariaSelected,
|
|
263
|
+
'aria-modal': this.ariaModal,
|
|
264
|
+
'aria-valuemax': this.ariaValueMax,
|
|
265
|
+
'aria-valuemin': this.ariaValueMin,
|
|
266
|
+
'aria-valuenow': this.ariaValueNow,
|
|
267
|
+
'aria-valuetext': this.ariaValueText,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import '@angular/compiler';
|
|
2
|
+
import { Component } from '@angular/core';
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
4
|
+
import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
|
|
5
|
+
import { installFabric } from '@symbiote-native/test-utils';
|
|
6
|
+
|
|
7
|
+
import { mount, unmount } from '../render';
|
|
8
|
+
import { InputAccessoryView } from './input-accessory-view';
|
|
9
|
+
|
|
10
|
+
const ROOT_TAG = 913;
|
|
11
|
+
const fabric = installFabric();
|
|
12
|
+
|
|
13
|
+
@Component({
|
|
14
|
+
selector: 'symbiote-iav-host',
|
|
15
|
+
standalone: true,
|
|
16
|
+
imports: [InputAccessoryView],
|
|
17
|
+
template: `
|
|
18
|
+
<InputAccessoryView [testID]="'iav'" class="toolbar">
|
|
19
|
+
<symbiote-text>Hello</symbiote-text>
|
|
20
|
+
</InputAccessoryView>
|
|
21
|
+
`,
|
|
22
|
+
})
|
|
23
|
+
class InputAccessoryViewHostFixture {}
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
fabric.reset();
|
|
27
|
+
});
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
unmount(ROOT_TAG);
|
|
30
|
+
clearGlobalStyles();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('InputAccessoryView', () => {
|
|
34
|
+
it('resolves a class= on the InputAccessoryView use site onto the real committed view, not the anchor', async () => {
|
|
35
|
+
registerStyles({ toolbar: { backgroundColor: 'orange' } });
|
|
36
|
+
|
|
37
|
+
mount(ROOT_TAG, InputAccessoryViewHostFixture);
|
|
38
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
39
|
+
|
|
40
|
+
const node = fabric.find(n => n.props.testID === 'iav');
|
|
41
|
+
expect(node?.props.backgroundColor).toBe('orange');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// InputAccessoryView, the Angular lifecycle half (iOS). A real Fabric host node
|
|
2
|
+
// (RCTInputAccessoryView) that docks its content above the keyboard; a TextInput points at it by
|
|
3
|
+
// nativeID through its inputAccessoryViewID. There is no JS-side translation — style / nativeID /
|
|
4
|
+
// backgroundColor map straight onto the intrinsic, children via <ng-content> — so this folds
|
|
5
|
+
// aria/role through the shared resolveAccessibilityProps and binds the rest onto the host. The
|
|
6
|
+
// Angular twin of the React/Vue InputAccessoryView. No platform branch, so this stays flat.
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
10
|
+
ChangeDetectionStrategy,
|
|
11
|
+
Component,
|
|
12
|
+
ElementRef,
|
|
13
|
+
EventEmitter,
|
|
14
|
+
inject,
|
|
15
|
+
Input,
|
|
16
|
+
Output,
|
|
17
|
+
} from '@angular/core';
|
|
18
|
+
import {
|
|
19
|
+
resolveAccessibilityProps,
|
|
20
|
+
type IAccessibilityProps,
|
|
21
|
+
type IAccessibilityStateValue,
|
|
22
|
+
type IAriaProps,
|
|
23
|
+
} from '@symbiote-native/components';
|
|
24
|
+
import type { IStyleProp, ISymbioteEvent, IViewStyle } from '@symbiote-native/engine';
|
|
25
|
+
import { anchorHostStyle, InputAccessoryViewHost, SymbioteHostPropsDirective } from '../primitives';
|
|
26
|
+
|
|
27
|
+
// Angular infers an `(event)` binding's $event as the DOM Event for a custom-schema element,
|
|
28
|
+
// so each handler enters as `unknown` and is narrowed here before reaching a typed callback.
|
|
29
|
+
function isSymbioteEvent(value: unknown): value is ISymbioteEvent {
|
|
30
|
+
return typeof value === 'object' && value !== null && 'nativeEvent' in value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Mirrors React's IInputAccessoryViewProps minus children (Angular takes children via
|
|
34
|
+
// <ng-content>), declared per-adapter over the shared a11y base.
|
|
35
|
+
export interface IAngularInputAccessoryViewProps extends IAccessibilityProps, IAriaProps {
|
|
36
|
+
// The id a TextInput's inputAccessoryViewID points at to dock above its keyboard.
|
|
37
|
+
nativeID?: string;
|
|
38
|
+
backgroundColor?: string;
|
|
39
|
+
style?: IStyleProp<IViewStyle>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// What the component itself takes as plain @Input()s: the full surface minus the accessibility
|
|
43
|
+
// callbacks, which it exposes as real @Output() EventEmitters instead (see the class below),
|
|
44
|
+
// mirroring Pressable's IAngularPressableInputs split.
|
|
45
|
+
export type IAngularInputAccessoryViewInputs = Omit<
|
|
46
|
+
IAngularInputAccessoryViewProps,
|
|
47
|
+
'onAccessibilityAction' | 'onAccessibilityTap' | 'onMagicTap' | 'onAccessibilityEscape'
|
|
48
|
+
>;
|
|
49
|
+
|
|
50
|
+
@Component({
|
|
51
|
+
selector: 'InputAccessoryView',
|
|
52
|
+
standalone: true,
|
|
53
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
54
|
+
imports: [InputAccessoryViewHost, SymbioteHostPropsDirective],
|
|
55
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
56
|
+
template: `
|
|
57
|
+
<symbiote-input-accessory-view
|
|
58
|
+
[symbioteHostProps]="hostProps"
|
|
59
|
+
(accessibilityAction)="emit(accessibilityAction, $event)"
|
|
60
|
+
(accessibilityTap)="emit(accessibilityTap, $event)"
|
|
61
|
+
(magicTap)="emit(magicTap, $event)"
|
|
62
|
+
(accessibilityEscape)="emit(accessibilityEscape, $event)"
|
|
63
|
+
>
|
|
64
|
+
<ng-content></ng-content>
|
|
65
|
+
</symbiote-input-accessory-view>
|
|
66
|
+
`,
|
|
67
|
+
})
|
|
68
|
+
export class InputAccessoryView implements IAngularInputAccessoryViewInputs {
|
|
69
|
+
@Input() nativeID?: string;
|
|
70
|
+
@Input() backgroundColor?: string;
|
|
71
|
+
@Input() style?: IStyleProp<IViewStyle>;
|
|
72
|
+
@Output() readonly accessibilityAction = new EventEmitter<ISymbioteEvent>();
|
|
73
|
+
@Output() readonly accessibilityTap = new EventEmitter<ISymbioteEvent>();
|
|
74
|
+
@Output() readonly magicTap = new EventEmitter<ISymbioteEvent>();
|
|
75
|
+
@Output() readonly accessibilityEscape = new EventEmitter<ISymbioteEvent>();
|
|
76
|
+
@Input() testID?: string;
|
|
77
|
+
@Input() accessible?: boolean;
|
|
78
|
+
@Input() accessibilityLabel?: string;
|
|
79
|
+
@Input() accessibilityHint?: string;
|
|
80
|
+
@Input() accessibilityRole?: IAccessibilityProps['accessibilityRole'];
|
|
81
|
+
@Input() accessibilityState?: IAccessibilityStateValue;
|
|
82
|
+
@Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
|
|
83
|
+
@Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
|
|
84
|
+
@Input() accessibilityLabelledBy?: string | string[];
|
|
85
|
+
@Input() importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
|
|
86
|
+
@Input() accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
|
|
87
|
+
@Input() screenReaderFocusable?: boolean;
|
|
88
|
+
@Input() accessibilityViewIsModal?: boolean;
|
|
89
|
+
@Input() accessibilityElementsHidden?: boolean;
|
|
90
|
+
@Input() accessibilityIgnoresInvertColors?: boolean;
|
|
91
|
+
@Input() accessibilityLanguage?: string;
|
|
92
|
+
@Input() accessibilityRespondsToUserInteraction?: boolean;
|
|
93
|
+
@Input() accessibilityShowsLargeContentViewer?: boolean;
|
|
94
|
+
@Input() accessibilityLargeContentTitle?: string;
|
|
95
|
+
@Input() role?: IAriaProps['role'];
|
|
96
|
+
@Input('aria-label') ariaLabel?: string;
|
|
97
|
+
@Input('aria-labelledby') ariaLabelledBy?: string;
|
|
98
|
+
@Input('aria-live') ariaLive?: IAriaProps['aria-live'];
|
|
99
|
+
@Input('aria-hidden') ariaHidden?: boolean;
|
|
100
|
+
@Input('aria-busy') ariaBusy?: boolean;
|
|
101
|
+
@Input('aria-checked') ariaChecked?: boolean | 'mixed';
|
|
102
|
+
@Input('aria-disabled') ariaDisabled?: boolean;
|
|
103
|
+
@Input('aria-expanded') ariaExpanded?: boolean;
|
|
104
|
+
@Input('aria-selected') ariaSelected?: boolean;
|
|
105
|
+
@Input('aria-modal') ariaModal?: boolean;
|
|
106
|
+
@Input('aria-valuemax') ariaValueMax?: number;
|
|
107
|
+
@Input('aria-valuemin') ariaValueMin?: number;
|
|
108
|
+
@Input('aria-valuenow') ariaValueNow?: number;
|
|
109
|
+
@Input('aria-valuetext') ariaValueText?: string;
|
|
110
|
+
|
|
111
|
+
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
112
|
+
// onto (see anchorHostStyle's doc comment). InputAccessoryView has no inner ViewChild, so this
|
|
113
|
+
// is the only ElementRef in the class.
|
|
114
|
+
private readonly elementRef = inject(ElementRef);
|
|
115
|
+
|
|
116
|
+
// Forward an engine event to the matching @Output(), narrowing the template's untyped $event.
|
|
117
|
+
emit(emitter: EventEmitter<ISymbioteEvent>, event: unknown): void {
|
|
118
|
+
if (isSymbioteEvent(event)) emitter.emit(event);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Folds every host-bound prop into one record for `symbioteHostProps` — the same fields the
|
|
122
|
+
// template used to bind one-by-one, assembled locally (no shared renderX for this component yet).
|
|
123
|
+
// The anchor's class-derived style goes FIRST, this component's own explicit `style` @Input
|
|
124
|
+
// SECOND — flattenStyle's later-wins collapse keeps an explicit [style] winning over its class.
|
|
125
|
+
get hostProps(): Record<string, unknown> {
|
|
126
|
+
const folded = this.folded;
|
|
127
|
+
return {
|
|
128
|
+
style: [anchorHostStyle(this.elementRef), this.style],
|
|
129
|
+
nativeID: this.nativeID,
|
|
130
|
+
backgroundColor: this.backgroundColor,
|
|
131
|
+
testID: this.testID,
|
|
132
|
+
accessible: this.accessible,
|
|
133
|
+
accessibilityLabel: folded.accessibilityLabel,
|
|
134
|
+
accessibilityHint: folded.accessibilityHint,
|
|
135
|
+
accessibilityRole: folded.accessibilityRole,
|
|
136
|
+
accessibilityState: folded.accessibilityState,
|
|
137
|
+
accessibilityValue: folded.accessibilityValue,
|
|
138
|
+
accessibilityActions: folded.accessibilityActions,
|
|
139
|
+
accessibilityLabelledBy: folded.accessibilityLabelledBy,
|
|
140
|
+
importantForAccessibility: folded.importantForAccessibility,
|
|
141
|
+
accessibilityLiveRegion: folded.accessibilityLiveRegion,
|
|
142
|
+
screenReaderFocusable: folded.screenReaderFocusable,
|
|
143
|
+
accessibilityViewIsModal: folded.accessibilityViewIsModal,
|
|
144
|
+
accessibilityElementsHidden: folded.accessibilityElementsHidden,
|
|
145
|
+
accessibilityIgnoresInvertColors: folded.accessibilityIgnoresInvertColors,
|
|
146
|
+
accessibilityLanguage: folded.accessibilityLanguage,
|
|
147
|
+
accessibilityRespondsToUserInteraction: folded.accessibilityRespondsToUserInteraction,
|
|
148
|
+
accessibilityShowsLargeContentViewer: folded.accessibilityShowsLargeContentViewer,
|
|
149
|
+
accessibilityLargeContentTitle: folded.accessibilityLargeContentTitle,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Fold the web aria-*/role aliases into the canonical accessibility* props once per render, so
|
|
154
|
+
// the host node never sees an aria-* key (native ignores them) — the shared transform.
|
|
155
|
+
get folded(): Partial<IAngularInputAccessoryViewProps> {
|
|
156
|
+
return resolveAccessibilityProps({
|
|
157
|
+
accessibilityLabel: this.accessibilityLabel,
|
|
158
|
+
accessibilityHint: this.accessibilityHint,
|
|
159
|
+
accessibilityRole: this.accessibilityRole,
|
|
160
|
+
accessibilityState: this.accessibilityState,
|
|
161
|
+
accessibilityValue: this.accessibilityValue,
|
|
162
|
+
accessibilityActions: this.accessibilityActions,
|
|
163
|
+
accessibilityLabelledBy: this.accessibilityLabelledBy,
|
|
164
|
+
importantForAccessibility: this.importantForAccessibility,
|
|
165
|
+
accessibilityLiveRegion: this.accessibilityLiveRegion,
|
|
166
|
+
screenReaderFocusable: this.screenReaderFocusable,
|
|
167
|
+
accessibilityViewIsModal: this.accessibilityViewIsModal,
|
|
168
|
+
accessibilityElementsHidden: this.accessibilityElementsHidden,
|
|
169
|
+
accessibilityIgnoresInvertColors: this.accessibilityIgnoresInvertColors,
|
|
170
|
+
accessibilityLanguage: this.accessibilityLanguage,
|
|
171
|
+
accessibilityRespondsToUserInteraction: this.accessibilityRespondsToUserInteraction,
|
|
172
|
+
accessibilityShowsLargeContentViewer: this.accessibilityShowsLargeContentViewer,
|
|
173
|
+
accessibilityLargeContentTitle: this.accessibilityLargeContentTitle,
|
|
174
|
+
role: this.role,
|
|
175
|
+
'aria-label': this.ariaLabel,
|
|
176
|
+
'aria-labelledby': this.ariaLabelledBy,
|
|
177
|
+
'aria-live': this.ariaLive,
|
|
178
|
+
'aria-hidden': this.ariaHidden,
|
|
179
|
+
'aria-busy': this.ariaBusy,
|
|
180
|
+
'aria-checked': this.ariaChecked,
|
|
181
|
+
'aria-disabled': this.ariaDisabled,
|
|
182
|
+
'aria-expanded': this.ariaExpanded,
|
|
183
|
+
'aria-selected': this.ariaSelected,
|
|
184
|
+
'aria-modal': this.ariaModal,
|
|
185
|
+
'aria-valuemax': this.ariaValueMax,
|
|
186
|
+
'aria-valuemin': this.ariaValueMin,
|
|
187
|
+
'aria-valuenow': this.ariaValueNow,
|
|
188
|
+
'aria-valuetext': this.ariaValueText,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import '@angular/compiler';
|
|
2
|
+
import { Component } from '@angular/core';
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
4
|
+
import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
|
|
5
|
+
import { installFabric } from '@symbiote-native/test-utils';
|
|
6
|
+
|
|
7
|
+
import { mount, unmount } from '../render';
|
|
8
|
+
import { KeyboardAvoidingView } from './keyboard-avoiding-view';
|
|
9
|
+
|
|
10
|
+
const ROOT_TAG = 911;
|
|
11
|
+
const fabric = installFabric();
|
|
12
|
+
|
|
13
|
+
// KeyboardAvoidingView's ngOnInit subscribes to the Keyboard module, which installs the
|
|
14
|
+
// bridgeless device-event hub on first use — needs a fake RN$registerCallableModule so
|
|
15
|
+
// installDeviceEventHub() doesn't throw (core/engine/src/native-events.ts). No native event is
|
|
16
|
+
// actually emitted in this test, only the subscribe/unsubscribe lifecycle runs.
|
|
17
|
+
Object.assign(globalThis, {
|
|
18
|
+
RN$registerCallableModule: (
|
|
19
|
+
_name: string,
|
|
20
|
+
_factory: () => { emit: (eventType: string, ...args: unknown[]) => void },
|
|
21
|
+
): void => {},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
@Component({
|
|
25
|
+
selector: 'symbiote-kav-host',
|
|
26
|
+
standalone: true,
|
|
27
|
+
imports: [KeyboardAvoidingView],
|
|
28
|
+
template: `
|
|
29
|
+
<KeyboardAvoidingView [testID]="'kav'" class="panel">
|
|
30
|
+
<symbiote-text>Hello</symbiote-text>
|
|
31
|
+
</KeyboardAvoidingView>
|
|
32
|
+
`,
|
|
33
|
+
})
|
|
34
|
+
class KeyboardAvoidingViewHostFixture {}
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
fabric.reset();
|
|
38
|
+
});
|
|
39
|
+
afterEach(() => {
|
|
40
|
+
unmount(ROOT_TAG);
|
|
41
|
+
clearGlobalStyles();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('KeyboardAvoidingView', () => {
|
|
45
|
+
it('resolves a class= on the KeyboardAvoidingView use site onto the real committed view, not the anchor', async () => {
|
|
46
|
+
registerStyles({ panel: { backgroundColor: 'teal' } });
|
|
47
|
+
|
|
48
|
+
mount(ROOT_TAG, KeyboardAvoidingViewHostFixture);
|
|
49
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
50
|
+
|
|
51
|
+
const node = fabric.find(n => n.props.testID === 'kav');
|
|
52
|
+
expect(node?.props.backgroundColor).toBe('teal');
|
|
53
|
+
});
|
|
54
|
+
});
|