@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,206 @@
|
|
|
1
|
+
import { Directive, ElementRef, EventEmitter, inject, Input, Output } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
renderActivityIndicator,
|
|
4
|
+
resolveAccessibilityProps,
|
|
5
|
+
type IAccessibilityProps,
|
|
6
|
+
type IAccessibilityStateValue,
|
|
7
|
+
type IActivityIndicatorPlatform,
|
|
8
|
+
type IActivityIndicatorProps,
|
|
9
|
+
type IActivityIndicatorSize,
|
|
10
|
+
type IAriaProps,
|
|
11
|
+
} from '@symbiote-native/components';
|
|
12
|
+
import type { ISymbioteEvent } from '@symbiote-native/engine';
|
|
13
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
14
|
+
import { anchorHostStyle } from '../../primitives';
|
|
15
|
+
|
|
16
|
+
export type { IActivityIndicatorProps, IActivityIndicatorSize } from '@symbiote-native/components';
|
|
17
|
+
|
|
18
|
+
// Narrows anchorHostStyle's `unknown` (it reads an opaque engine prop bag) to the shape
|
|
19
|
+
// IActivityIndicatorProps['style'] actually declares, the same runtime guard image/shared.ts's
|
|
20
|
+
// asStyle() uses for the identical reason — a style value is structurally opaque at the type
|
|
21
|
+
// level, so this only rules out non-objects, never validates individual style keys.
|
|
22
|
+
function asStyle(value: unknown): IActivityIndicatorProps['style'] {
|
|
23
|
+
return typeof value === 'object' && value !== null ? value : undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// What the component itself takes as plain @Input()s: the full shared, cross-adapter
|
|
27
|
+
// IActivityIndicatorProps surface minus onLayout and the accessibility callbacks, which it
|
|
28
|
+
// exposes as real @Output() EventEmitters instead (see the class below), mirroring Pressable's
|
|
29
|
+
// IAngularPressableInputs split.
|
|
30
|
+
export type IActivityIndicatorInputs = Omit<
|
|
31
|
+
IActivityIndicatorProps,
|
|
32
|
+
| 'onLayout'
|
|
33
|
+
| 'onAccessibilityAction'
|
|
34
|
+
| 'onAccessibilityTap'
|
|
35
|
+
| 'onMagicTap'
|
|
36
|
+
| 'onAccessibilityEscape'
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
@Directive()
|
|
40
|
+
export abstract class ActivityIndicatorBase implements IActivityIndicatorInputs {
|
|
41
|
+
@Input() animating?: boolean;
|
|
42
|
+
@Input() color?: string;
|
|
43
|
+
@Input() hidesWhenStopped?: boolean;
|
|
44
|
+
@Input() nativeID?: string;
|
|
45
|
+
@Input() size?: IActivityIndicatorSize;
|
|
46
|
+
@Input() style?: IActivityIndicatorProps['style'];
|
|
47
|
+
@Input() testID?: string;
|
|
48
|
+
// Real @Output()s. This component renders through DescriptorOutlet (`symbiote-descriptor-
|
|
49
|
+
// outlet`), not a hand-written template: emitterHandler() below wraps each EventEmitter into a
|
|
50
|
+
// plain callback under the SAME onX key the shared, cross-adapter IActivityIndicatorProps
|
|
51
|
+
// expects, so the Descriptor's props bag still carries a function the engine's routeProp
|
|
52
|
+
// recognizes and routes to setEventListener — the outlet's renderer.setProperty call never
|
|
53
|
+
// sees an EventEmitter, only the wrapper.
|
|
54
|
+
@Output() readonly layout = new EventEmitter<ISymbioteEvent>();
|
|
55
|
+
|
|
56
|
+
@Input() accessible?: boolean;
|
|
57
|
+
@Input() accessibilityLabel?: string;
|
|
58
|
+
@Input() accessibilityHint?: string;
|
|
59
|
+
@Input() accessibilityRole?: IAccessibilityProps['accessibilityRole'];
|
|
60
|
+
@Input() accessibilityState?: IAccessibilityStateValue;
|
|
61
|
+
@Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
|
|
62
|
+
@Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
|
|
63
|
+
@Input() accessibilityLabelledBy?: string | string[];
|
|
64
|
+
@Input() importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
|
|
65
|
+
@Input() accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
|
|
66
|
+
@Input() screenReaderFocusable?: boolean;
|
|
67
|
+
@Input() accessibilityViewIsModal?: boolean;
|
|
68
|
+
@Input() accessibilityElementsHidden?: boolean;
|
|
69
|
+
@Input() accessibilityIgnoresInvertColors?: boolean;
|
|
70
|
+
@Input() accessibilityLanguage?: string;
|
|
71
|
+
@Input() accessibilityRespondsToUserInteraction?: boolean;
|
|
72
|
+
@Input() accessibilityShowsLargeContentViewer?: boolean;
|
|
73
|
+
@Input() accessibilityLargeContentTitle?: string;
|
|
74
|
+
@Output() readonly accessibilityAction = new EventEmitter<ISymbioteEvent>();
|
|
75
|
+
@Output() readonly accessibilityTap = new EventEmitter<ISymbioteEvent>();
|
|
76
|
+
@Output() readonly magicTap = new EventEmitter<ISymbioteEvent>();
|
|
77
|
+
@Output() readonly accessibilityEscape = new EventEmitter<ISymbioteEvent>();
|
|
78
|
+
|
|
79
|
+
@Input() role?: IAriaProps['role'];
|
|
80
|
+
@Input('aria-label') ariaLabel?: string;
|
|
81
|
+
@Input('aria-labelledby') ariaLabelledBy?: string;
|
|
82
|
+
@Input('aria-live') ariaLive?: IAriaProps['aria-live'];
|
|
83
|
+
@Input('aria-hidden') ariaHidden?: boolean;
|
|
84
|
+
@Input('aria-busy') ariaBusy?: boolean;
|
|
85
|
+
@Input('aria-checked') ariaChecked?: boolean | 'mixed';
|
|
86
|
+
@Input('aria-disabled') ariaDisabled?: boolean;
|
|
87
|
+
@Input('aria-expanded') ariaExpanded?: boolean;
|
|
88
|
+
@Input('aria-selected') ariaSelected?: boolean;
|
|
89
|
+
@Input('aria-modal') ariaModal?: boolean;
|
|
90
|
+
@Input('aria-valuemax') ariaValueMax?: number;
|
|
91
|
+
@Input('aria-valuemin') ariaValueMin?: number;
|
|
92
|
+
@Input('aria-valuenow') ariaValueNow?: number;
|
|
93
|
+
@Input('aria-valuetext') ariaValueText?: string;
|
|
94
|
+
|
|
95
|
+
protected abstract readonly defaultColor: string | null;
|
|
96
|
+
protected readonly nativeExtras: Readonly<Record<string, unknown>> = {};
|
|
97
|
+
|
|
98
|
+
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
99
|
+
// onto (see anchorHostStyle's doc comment) — NOT the descriptor-outlet-rendered wrapper the
|
|
100
|
+
// `descriptor` getter below builds. Merged FIRST so an explicit `style` @Input still wins
|
|
101
|
+
// (flattenStyle's later-wins collapse), mirroring every other composed component's anchor merge.
|
|
102
|
+
private readonly elementRef = inject(ElementRef);
|
|
103
|
+
|
|
104
|
+
// Stable bound wrappers (created ONCE, not per `descriptor` access) fed to emitterHandler below.
|
|
105
|
+
// jsonEqual (core/engine/src/commit.ts) falls through to Object.is for a function leaf, so a
|
|
106
|
+
// fresh closure built inside the `descriptor` getter would never equal the previous frame's
|
|
107
|
+
// closure even when nothing changed — every CD pass would read as "props changed" and force a
|
|
108
|
+
// real Fabric re-clone cascading up every ancestor to the root (the same hazard
|
|
109
|
+
// AnimatedComponentBase.reconcile() and ScrollViewStickyHeader's onHostLayout guard against).
|
|
110
|
+
private readonly onLayoutHandler = (event: ISymbioteEvent): void => this.layout.emit(event);
|
|
111
|
+
private readonly onAccessibilityActionHandler = (event: ISymbioteEvent): void =>
|
|
112
|
+
this.accessibilityAction.emit(event);
|
|
113
|
+
private readonly onAccessibilityTapHandler = (event: ISymbioteEvent): void =>
|
|
114
|
+
this.accessibilityTap.emit(event);
|
|
115
|
+
private readonly onMagicTapHandler = (event: ISymbioteEvent): void => this.magicTap.emit(event);
|
|
116
|
+
private readonly onAccessibilityEscapeHandler = (event: ISymbioteEvent): void =>
|
|
117
|
+
this.accessibilityEscape.emit(event);
|
|
118
|
+
|
|
119
|
+
get descriptor(): IDescriptor {
|
|
120
|
+
const props = resolveAccessibilityProps<IActivityIndicatorProps>({
|
|
121
|
+
animating: this.animating,
|
|
122
|
+
color: this.color,
|
|
123
|
+
hidesWhenStopped: this.hidesWhenStopped,
|
|
124
|
+
nativeID: this.nativeID,
|
|
125
|
+
size: this.size,
|
|
126
|
+
style: [asStyle(anchorHostStyle(this.elementRef)), this.style],
|
|
127
|
+
testID: this.testID,
|
|
128
|
+
onLayout: this.emitterHandler(this.layout, this.onLayoutHandler),
|
|
129
|
+
accessible: this.accessible,
|
|
130
|
+
accessibilityLabel: this.accessibilityLabel,
|
|
131
|
+
accessibilityHint: this.accessibilityHint,
|
|
132
|
+
accessibilityRole: this.accessibilityRole,
|
|
133
|
+
accessibilityState: this.accessibilityState,
|
|
134
|
+
accessibilityValue: this.accessibilityValue,
|
|
135
|
+
accessibilityActions: this.accessibilityActions,
|
|
136
|
+
accessibilityLabelledBy: this.accessibilityLabelledBy,
|
|
137
|
+
importantForAccessibility: this.importantForAccessibility,
|
|
138
|
+
accessibilityLiveRegion: this.accessibilityLiveRegion,
|
|
139
|
+
screenReaderFocusable: this.screenReaderFocusable,
|
|
140
|
+
accessibilityViewIsModal: this.accessibilityViewIsModal,
|
|
141
|
+
accessibilityElementsHidden: this.accessibilityElementsHidden,
|
|
142
|
+
accessibilityIgnoresInvertColors: this.accessibilityIgnoresInvertColors,
|
|
143
|
+
accessibilityLanguage: this.accessibilityLanguage,
|
|
144
|
+
accessibilityRespondsToUserInteraction: this.accessibilityRespondsToUserInteraction,
|
|
145
|
+
accessibilityShowsLargeContentViewer: this.accessibilityShowsLargeContentViewer,
|
|
146
|
+
accessibilityLargeContentTitle: this.accessibilityLargeContentTitle,
|
|
147
|
+
onAccessibilityAction: this.emitterHandler(
|
|
148
|
+
this.accessibilityAction,
|
|
149
|
+
this.onAccessibilityActionHandler,
|
|
150
|
+
),
|
|
151
|
+
onAccessibilityTap: this.emitterHandler(
|
|
152
|
+
this.accessibilityTap,
|
|
153
|
+
this.onAccessibilityTapHandler,
|
|
154
|
+
),
|
|
155
|
+
onMagicTap: this.emitterHandler(this.magicTap, this.onMagicTapHandler),
|
|
156
|
+
onAccessibilityEscape: this.emitterHandler(
|
|
157
|
+
this.accessibilityEscape,
|
|
158
|
+
this.onAccessibilityEscapeHandler,
|
|
159
|
+
),
|
|
160
|
+
role: this.role,
|
|
161
|
+
'aria-label': this.ariaLabel,
|
|
162
|
+
'aria-labelledby': this.ariaLabelledBy,
|
|
163
|
+
'aria-live': this.ariaLive,
|
|
164
|
+
'aria-hidden': this.ariaHidden,
|
|
165
|
+
'aria-busy': this.ariaBusy,
|
|
166
|
+
'aria-checked': this.ariaChecked,
|
|
167
|
+
'aria-disabled': this.ariaDisabled,
|
|
168
|
+
'aria-expanded': this.ariaExpanded,
|
|
169
|
+
'aria-selected': this.ariaSelected,
|
|
170
|
+
'aria-modal': this.ariaModal,
|
|
171
|
+
'aria-valuemax': this.ariaValueMax,
|
|
172
|
+
'aria-valuemin': this.ariaValueMin,
|
|
173
|
+
'aria-valuenow': this.ariaValueNow,
|
|
174
|
+
'aria-valuetext': this.ariaValueText,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const { animating, color, hidesWhenStopped, size, style, ...passthrough } = props;
|
|
178
|
+
return renderActivityIndicator(
|
|
179
|
+
{
|
|
180
|
+
animating: animating !== false,
|
|
181
|
+
color,
|
|
182
|
+
hidesWhenStopped: hidesWhenStopped !== false,
|
|
183
|
+
size: size ?? 'small',
|
|
184
|
+
style,
|
|
185
|
+
passthrough,
|
|
186
|
+
},
|
|
187
|
+
this.platform,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private get platform(): IActivityIndicatorPlatform {
|
|
192
|
+
return { defaultColor: this.defaultColor, nativeExtras: this.nativeExtras };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Gates a STABLE bound handler behind `observed`, so an unbound event still resolves to
|
|
196
|
+
// `undefined` in the descriptor's props bag — the same "undefined means nobody cares" contract
|
|
197
|
+
// the old @Input() callback had, letting resolveAccessibilityProps drop the key entirely instead
|
|
198
|
+
// of handing the engine a no-op function. `handler` must be one of the readonly bound fields
|
|
199
|
+
// above, never a closure built here — see their doc comment for why.
|
|
200
|
+
private emitterHandler(
|
|
201
|
+
emitter: EventEmitter<ISymbioteEvent>,
|
|
202
|
+
handler: (event: ISymbioteEvent) => void,
|
|
203
|
+
): ((event: ISymbioteEvent) => void) | undefined {
|
|
204
|
+
return emitter.observed ? handler : undefined;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Button for Angular. The minimal cross-platform button in RN's iOS shape (Button.js): a
|
|
2
|
+
// TouchableOpacity wrapping a Text. The base text style, the role constant, and the color fold are
|
|
3
|
+
// shared in @symbiote-native/components/view; here Angular only composes its TouchableOpacity + a
|
|
4
|
+
// symbiote-text child and re-maps the few Button-owned props. The Angular twin of the React/Vue
|
|
5
|
+
// adapter's Button. No JS-side platform branch, so this stays a flat single file (ADR 0026).
|
|
6
|
+
//
|
|
7
|
+
// RN's Button fixes accessibilityRole="button", marks the root accessible, and propagates `disabled`
|
|
8
|
+
// into the accessibility state; those three win over any caller value. `title` becomes the Text
|
|
9
|
+
// child; disabled forwards straight; touchSoundDisabled maps to the pressable's android_disableSound.
|
|
10
|
+
// Every OTHER field of the shared IButtonProps (title, color, disabled, touchSoundDisabled, testID,
|
|
11
|
+
// TV-focus, accessibility state) is agnostic and stays RE-EXPORTED from @symbiote-native/components verbatim
|
|
12
|
+
// (<prop_types_split_agnostic_vs_per_adapter>). onPress and the four accessibility callbacks are the
|
|
13
|
+
// exceptions: each is a real @Output() here (`press`, `accessibilityAction`, `accessibilityTap`,
|
|
14
|
+
// `magicTap`, `accessibilityEscape`), mirroring the Vue adapter's Button, which forks the SAME onPress
|
|
15
|
+
// field the same way (`Omit<ICoreButtonProps, 'onPress'>` + a `press` emit) — not a new precedent, the
|
|
16
|
+
// existing one extended to accessibility.
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
CUSTOM_ELEMENTS_SCHEMA,
|
|
20
|
+
ChangeDetectionStrategy,
|
|
21
|
+
Component,
|
|
22
|
+
ElementRef,
|
|
23
|
+
EventEmitter,
|
|
24
|
+
inject,
|
|
25
|
+
Input,
|
|
26
|
+
Output,
|
|
27
|
+
} from '@angular/core';
|
|
28
|
+
import {
|
|
29
|
+
BUTTON_ACCESSIBILITY_ROLE,
|
|
30
|
+
resolveButtonTextStyle,
|
|
31
|
+
type IAccessibilityProps,
|
|
32
|
+
type IAccessibilityStateValue,
|
|
33
|
+
type IAriaProps,
|
|
34
|
+
type IButtonProps as ICoreButtonProps,
|
|
35
|
+
} from '@symbiote-native/components';
|
|
36
|
+
import type { ISymbioteEvent, ITextStyle, IStyleProp, IViewStyle } from '@symbiote-native/engine';
|
|
37
|
+
import { anchorStyleProp, TextHost } from '../primitives';
|
|
38
|
+
import { TouchableOpacity } from './touchable';
|
|
39
|
+
|
|
40
|
+
export type IButtonProps = Omit<
|
|
41
|
+
ICoreButtonProps,
|
|
42
|
+
| 'onPress'
|
|
43
|
+
| 'onAccessibilityAction'
|
|
44
|
+
| 'onAccessibilityTap'
|
|
45
|
+
| 'onMagicTap'
|
|
46
|
+
| 'onAccessibilityEscape'
|
|
47
|
+
>;
|
|
48
|
+
|
|
49
|
+
@Component({
|
|
50
|
+
selector: 'Button',
|
|
51
|
+
standalone: true,
|
|
52
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
53
|
+
imports: [TouchableOpacity, TextHost],
|
|
54
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
55
|
+
template: `
|
|
56
|
+
<TouchableOpacity
|
|
57
|
+
[style]="anchorStyle"
|
|
58
|
+
(press)="press.emit($event)"
|
|
59
|
+
[disabled]="disabled"
|
|
60
|
+
[android_disableSound]="touchSoundDisabled"
|
|
61
|
+
[accessibilityRole]="buttonRole"
|
|
62
|
+
[accessible]="true"
|
|
63
|
+
[accessibilityState]="{ disabled }"
|
|
64
|
+
[testID]="testID"
|
|
65
|
+
[nativeID]="nativeID"
|
|
66
|
+
[hasTVPreferredFocus]="hasTVPreferredFocus"
|
|
67
|
+
[nextFocusDown]="nextFocusDown"
|
|
68
|
+
[nextFocusForward]="nextFocusForward"
|
|
69
|
+
[nextFocusLeft]="nextFocusLeft"
|
|
70
|
+
[nextFocusRight]="nextFocusRight"
|
|
71
|
+
[nextFocusUp]="nextFocusUp"
|
|
72
|
+
[accessibilityLabel]="accessibilityLabel"
|
|
73
|
+
[accessibilityHint]="accessibilityHint"
|
|
74
|
+
[accessibilityValue]="accessibilityValue"
|
|
75
|
+
[accessibilityActions]="accessibilityActions"
|
|
76
|
+
[accessibilityLabelledBy]="accessibilityLabelledBy"
|
|
77
|
+
[importantForAccessibility]="importantForAccessibility"
|
|
78
|
+
[accessibilityLiveRegion]="accessibilityLiveRegion"
|
|
79
|
+
[screenReaderFocusable]="screenReaderFocusable"
|
|
80
|
+
[accessibilityViewIsModal]="accessibilityViewIsModal"
|
|
81
|
+
[accessibilityElementsHidden]="accessibilityElementsHidden"
|
|
82
|
+
[accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
|
|
83
|
+
[accessibilityLanguage]="accessibilityLanguage"
|
|
84
|
+
[accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
|
|
85
|
+
[accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
|
|
86
|
+
[accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
|
|
87
|
+
(accessibilityAction)="accessibilityAction.emit($event)"
|
|
88
|
+
(accessibilityTap)="accessibilityTap.emit($event)"
|
|
89
|
+
(magicTap)="magicTap.emit($event)"
|
|
90
|
+
(accessibilityEscape)="accessibilityEscape.emit($event)"
|
|
91
|
+
[ariaLabel]="ariaLabel"
|
|
92
|
+
[ariaBusy]="ariaBusy"
|
|
93
|
+
[ariaChecked]="ariaChecked"
|
|
94
|
+
[ariaDisabled]="ariaDisabled"
|
|
95
|
+
[ariaExpanded]="ariaExpanded"
|
|
96
|
+
[ariaHidden]="ariaHidden"
|
|
97
|
+
[ariaLabelledBy]="ariaLabelledBy"
|
|
98
|
+
[ariaLive]="ariaLive"
|
|
99
|
+
[ariaSelected]="ariaSelected"
|
|
100
|
+
[ariaModal]="ariaModal"
|
|
101
|
+
[ariaValueMax]="ariaValueMax"
|
|
102
|
+
[ariaValueMin]="ariaValueMin"
|
|
103
|
+
[ariaValueNow]="ariaValueNow"
|
|
104
|
+
[ariaValueText]="ariaValueText"
|
|
105
|
+
[role]="role"
|
|
106
|
+
>
|
|
107
|
+
<symbiote-text [style]="textStyle">{{ title }}</symbiote-text>
|
|
108
|
+
</TouchableOpacity>
|
|
109
|
+
`,
|
|
110
|
+
})
|
|
111
|
+
export class Button implements IButtonProps {
|
|
112
|
+
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
113
|
+
// onto (see anchorHostStyle's doc comment in primitives/shared.ts) — NOT the inner
|
|
114
|
+
// TouchableOpacity/Pressable one level down. RN's real Button takes no `style` prop, so this
|
|
115
|
+
// is the only style source forwarded.
|
|
116
|
+
private readonly elementRef = inject(ElementRef);
|
|
117
|
+
|
|
118
|
+
@Output() readonly press = new EventEmitter<ISymbioteEvent>();
|
|
119
|
+
@Output() readonly accessibilityAction = new EventEmitter<ISymbioteEvent>();
|
|
120
|
+
@Output() readonly accessibilityTap = new EventEmitter<ISymbioteEvent>();
|
|
121
|
+
@Output() readonly magicTap = new EventEmitter<ISymbioteEvent>();
|
|
122
|
+
@Output() readonly accessibilityEscape = new EventEmitter<ISymbioteEvent>();
|
|
123
|
+
|
|
124
|
+
// Button-owned props: title is the Text child, color/disabled fold into the label style, and
|
|
125
|
+
// touchSoundDisabled re-maps onto TouchableOpacity.
|
|
126
|
+
@Input() title = '';
|
|
127
|
+
@Input() color?: string;
|
|
128
|
+
@Input() disabled?: boolean;
|
|
129
|
+
@Input() touchSoundDisabled?: boolean;
|
|
130
|
+
@Input() testID?: string;
|
|
131
|
+
|
|
132
|
+
// TV-focus props (Button.js): inert on a phone host, forwarded through TouchableOpacity.
|
|
133
|
+
@Input() hasTVPreferredFocus?: boolean;
|
|
134
|
+
@Input() nextFocusDown?: number;
|
|
135
|
+
@Input() nextFocusForward?: number;
|
|
136
|
+
@Input() nextFocusLeft?: number;
|
|
137
|
+
@Input() nextFocusRight?: number;
|
|
138
|
+
@Input() nextFocusUp?: number;
|
|
139
|
+
|
|
140
|
+
// Accessibility surface (IAccessibilityProps). accessibilityRole, accessible, and
|
|
141
|
+
// accessibilityState are declared for surface completeness but Button forces its own
|
|
142
|
+
// (button / true / { disabled }); the caller value is ignored, mirroring RN's Button.js.
|
|
143
|
+
@Input() nativeID?: string;
|
|
144
|
+
@Input() accessible?: boolean;
|
|
145
|
+
@Input() accessibilityLabel?: string;
|
|
146
|
+
@Input() accessibilityHint?: string;
|
|
147
|
+
@Input() accessibilityRole?: IAccessibilityProps['accessibilityRole'];
|
|
148
|
+
@Input() accessibilityState?: IAccessibilityStateValue;
|
|
149
|
+
@Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
|
|
150
|
+
@Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
|
|
151
|
+
@Input() accessibilityLabelledBy?: string | string[];
|
|
152
|
+
@Input() importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
|
|
153
|
+
@Input() accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
|
|
154
|
+
@Input() screenReaderFocusable?: boolean;
|
|
155
|
+
@Input() accessibilityViewIsModal?: boolean;
|
|
156
|
+
@Input() accessibilityElementsHidden?: boolean;
|
|
157
|
+
@Input() accessibilityIgnoresInvertColors?: boolean;
|
|
158
|
+
@Input() accessibilityLanguage?: string;
|
|
159
|
+
@Input() accessibilityRespondsToUserInteraction?: boolean;
|
|
160
|
+
@Input() accessibilityShowsLargeContentViewer?: boolean;
|
|
161
|
+
@Input() accessibilityLargeContentTitle?: string;
|
|
162
|
+
|
|
163
|
+
// Web-alias a11y surface (IAriaProps). External dashed aliases are exposed as Angular inputs and
|
|
164
|
+
// forwarded to TouchableOpacity's camelCase aria inputs.
|
|
165
|
+
@Input() role?: IAriaProps['role'];
|
|
166
|
+
@Input('aria-label') ariaLabel?: string;
|
|
167
|
+
@Input('aria-labelledby') ariaLabelledBy?: string;
|
|
168
|
+
@Input('aria-live') ariaLive?: IAriaProps['aria-live'];
|
|
169
|
+
@Input('aria-hidden') ariaHidden?: boolean;
|
|
170
|
+
@Input('aria-busy') ariaBusy?: boolean;
|
|
171
|
+
@Input('aria-checked') ariaChecked?: boolean | 'mixed';
|
|
172
|
+
@Input('aria-disabled') ariaDisabled?: boolean;
|
|
173
|
+
@Input('aria-expanded') ariaExpanded?: boolean;
|
|
174
|
+
@Input('aria-selected') ariaSelected?: boolean;
|
|
175
|
+
@Input('aria-modal') ariaModal?: boolean;
|
|
176
|
+
@Input('aria-valuemax') ariaValueMax?: number;
|
|
177
|
+
@Input('aria-valuemin') ariaValueMin?: number;
|
|
178
|
+
@Input('aria-valuenow') ariaValueNow?: number;
|
|
179
|
+
@Input('aria-valuetext') ariaValueText?: string;
|
|
180
|
+
|
|
181
|
+
// RN's Button is always accessibilityRole="button"; the shared role constant, not a literal.
|
|
182
|
+
readonly buttonRole = BUTTON_ACCESSIBILITY_ROLE;
|
|
183
|
+
|
|
184
|
+
// The label style with the caller color tinted in and `disabled` greying it out (disabled wins),
|
|
185
|
+
// computed by the shared fold so every adapter paints the identical button.
|
|
186
|
+
get textStyle(): ITextStyle {
|
|
187
|
+
return resolveButtonTextStyle(this.color, this.disabled);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
get anchorStyle(): IStyleProp<IViewStyle> | undefined {
|
|
191
|
+
return anchorStyleProp<IViewStyle>(this.elementRef);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Regression guard: columnWrapperStyle previously accepted ONLY a JS style object/array. It now
|
|
2
|
+
// also resolves a class-name string through the shared style registry, merged onto the same
|
|
3
|
+
// flex-row wrapper as an object/array value (see index.ts's ngOnChanges). Mirrors the Vue twin
|
|
4
|
+
// (column-wrapper-style-class.test.ts) and flat-list.test.ts's row-packing shape.
|
|
5
|
+
import '@angular/compiler';
|
|
6
|
+
import { Component } from '@angular/core';
|
|
7
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
8
|
+
import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
|
|
9
|
+
import { installFabric, type IFakeNode } from '@symbiote-native/test-utils';
|
|
10
|
+
|
|
11
|
+
import { mount, unmount } from '../../render';
|
|
12
|
+
import { FlatList } from './index';
|
|
13
|
+
import { VListItemDirective } from '../virtualized-list/directives';
|
|
14
|
+
|
|
15
|
+
const ROOT_TAG = 953;
|
|
16
|
+
const fabric = installFabric();
|
|
17
|
+
const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
|
|
18
|
+
|
|
19
|
+
interface IRow {
|
|
20
|
+
id: string;
|
|
21
|
+
label: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const rows: IRow[] = Array.from({ length: 4 }, (_unused, index) => ({
|
|
25
|
+
id: `r-${index}`,
|
|
26
|
+
label: `row-${index}`,
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
function walk(nodes: IFakeNode[], visit: (node: IFakeNode) => void): void {
|
|
30
|
+
for (const node of nodes) {
|
|
31
|
+
visit(node);
|
|
32
|
+
walk(node.children, visit);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function rowsWithFlexDirection(): IFakeNode[] {
|
|
37
|
+
const found: IFakeNode[] = [];
|
|
38
|
+
walk(fabric.committed, node => {
|
|
39
|
+
if (node.viewName === 'RCTView' && node.props.flexDirection === 'row') found.push(node);
|
|
40
|
+
});
|
|
41
|
+
return found;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@Component({
|
|
45
|
+
selector: 'symbiote-flatlist-column-style-class-host',
|
|
46
|
+
standalone: true,
|
|
47
|
+
imports: [FlatList, VListItemDirective],
|
|
48
|
+
template: `
|
|
49
|
+
<FlatList
|
|
50
|
+
[data]="rows"
|
|
51
|
+
[numColumns]="2"
|
|
52
|
+
[keyExtractor]="keyExtractor"
|
|
53
|
+
[columnWrapperStyle]="'gap8'"
|
|
54
|
+
>
|
|
55
|
+
<ng-template vListItem let-item>
|
|
56
|
+
<symbiote-text [testID]="item.id">{{ item.label }}</symbiote-text>
|
|
57
|
+
</ng-template>
|
|
58
|
+
</FlatList>
|
|
59
|
+
`,
|
|
60
|
+
})
|
|
61
|
+
class FlatListColumnStyleClassHost {
|
|
62
|
+
rows = rows;
|
|
63
|
+
keyExtractor = (item: IRow): string => item.id;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@Component({
|
|
67
|
+
selector: 'symbiote-flatlist-column-style-object-host',
|
|
68
|
+
standalone: true,
|
|
69
|
+
imports: [FlatList, VListItemDirective],
|
|
70
|
+
template: `
|
|
71
|
+
<FlatList
|
|
72
|
+
[data]="rows"
|
|
73
|
+
[numColumns]="2"
|
|
74
|
+
[keyExtractor]="keyExtractor"
|
|
75
|
+
[columnWrapperStyle]="{ gap: 4 }"
|
|
76
|
+
>
|
|
77
|
+
<ng-template vListItem let-item>
|
|
78
|
+
<symbiote-text [testID]="item.id">{{ item.label }}</symbiote-text>
|
|
79
|
+
</ng-template>
|
|
80
|
+
</FlatList>
|
|
81
|
+
`,
|
|
82
|
+
})
|
|
83
|
+
class FlatListColumnStyleObjectHost {
|
|
84
|
+
rows = rows;
|
|
85
|
+
keyExtractor = (item: IRow): string => item.id;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
beforeEach(() => {
|
|
89
|
+
fabric.reset();
|
|
90
|
+
registerStyles({ gap8: { gap: 8 } });
|
|
91
|
+
});
|
|
92
|
+
afterEach(() => {
|
|
93
|
+
unmount(ROOT_TAG);
|
|
94
|
+
clearGlobalStyles();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('FlatList columnWrapperStyle class-name support', () => {
|
|
98
|
+
it('resolves a class-name string onto the row wrapper alongside flexDirection', async () => {
|
|
99
|
+
mount(ROOT_TAG, FlatListColumnStyleClassHost);
|
|
100
|
+
await tick();
|
|
101
|
+
await tick();
|
|
102
|
+
|
|
103
|
+
const found = rowsWithFlexDirection();
|
|
104
|
+
expect(found.length, 'two flex-row rows for 4 items in 2 columns').toBe(2);
|
|
105
|
+
expect(found[0].props.gap).toBe(8);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('still accepts an ordinary style object unchanged', async () => {
|
|
109
|
+
mount(ROOT_TAG, FlatListColumnStyleObjectHost);
|
|
110
|
+
await tick();
|
|
111
|
+
await tick();
|
|
112
|
+
|
|
113
|
+
const found = rowsWithFlexDirection();
|
|
114
|
+
expect(found[0].props.gap).toBe(4);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import '@angular/compiler';
|
|
2
|
+
import { Component } from '@angular/core';
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
4
|
+
import { installFabric } from '@symbiote-native/test-utils';
|
|
5
|
+
import { flattenStyle } from '@symbiote-native/engine';
|
|
6
|
+
|
|
7
|
+
import { mount, unmount } from '../../render';
|
|
8
|
+
import { FlatList } from './index';
|
|
9
|
+
import { VListItemDirective } from '../virtualized-list/directives';
|
|
10
|
+
|
|
11
|
+
const ROOT_TAG = 905;
|
|
12
|
+
const fabric = installFabric();
|
|
13
|
+
|
|
14
|
+
interface IChip {
|
|
15
|
+
id: string;
|
|
16
|
+
n: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const chips: IChip[] = Array.from({ length: 24 }, (_unused, index) => ({
|
|
20
|
+
id: `c-${index}`,
|
|
21
|
+
n: index,
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
// Regression coverage for a real device bug: Angular compiles a literal `[style]="…"` binding to
|
|
25
|
+
// the built-in ɵɵstyleMap instruction (NOT a regular @Input() property write), regardless of the
|
|
26
|
+
// target's declared type — it only understands a flat style object, never an array. RN's own
|
|
27
|
+
// `style={[base, override]}` composition idiom (used by examples/angular/App.ts's "FlatList · 24
|
|
28
|
+
// chips" demo for the per-item computed backgroundColor) crashed deep inside Angular's own styling
|
|
29
|
+
// engine (`prop.indexOf is not a function`), and the crash landed inside a zoneless
|
|
30
|
+
// SymbioteChangeDetectionScheduler tick with no catch around it — so the retry kept re-firing
|
|
31
|
+
// forever (RAM climbing, constant re-render log spam on device) while the item never painted its
|
|
32
|
+
// style. Fixed by flattening any array-composed style with the engine's own `flattenStyle` before
|
|
33
|
+
// it reaches a `[style]=` binding — required of app authors (see App.ts) AND of every adapter
|
|
34
|
+
// component that forwards its own `style` @Input() onward (see the `resolvedStyle` getters/fields
|
|
35
|
+
// in virtualized-list, section-list, virtualized-section-list — flat-list's own `rowStyle` had the
|
|
36
|
+
// identical landmine, always assigning an array). See the angular-adapter skill for the full story.
|
|
37
|
+
@Component({
|
|
38
|
+
selector: 'symbiote-chip-list-host',
|
|
39
|
+
standalone: true,
|
|
40
|
+
imports: [FlatList, VListItemDirective],
|
|
41
|
+
template: `
|
|
42
|
+
<FlatList
|
|
43
|
+
testID="chips-list"
|
|
44
|
+
[data]="chips"
|
|
45
|
+
[horizontal]="true"
|
|
46
|
+
[keyExtractor]="keyExtractor"
|
|
47
|
+
[getItemLayout]="getItemLayout"
|
|
48
|
+
[style]="{ height: 84 }"
|
|
49
|
+
>
|
|
50
|
+
<ng-template vListItem let-item>
|
|
51
|
+
<symbiote-view
|
|
52
|
+
[testID]="'chip-' + item.n"
|
|
53
|
+
[style]="flattenStyle([{ height: 72, width: 64 }, { backgroundColor: chipColor(item) }])"
|
|
54
|
+
>
|
|
55
|
+
<symbiote-text>{{ item.n }}</symbiote-text>
|
|
56
|
+
</symbiote-view>
|
|
57
|
+
</ng-template>
|
|
58
|
+
</FlatList>
|
|
59
|
+
`,
|
|
60
|
+
})
|
|
61
|
+
class ChipListHost {
|
|
62
|
+
chips = chips;
|
|
63
|
+
flattenStyle = flattenStyle;
|
|
64
|
+
keyExtractor = (item: IChip): string => item.id;
|
|
65
|
+
getItemLayout = (
|
|
66
|
+
_data: unknown,
|
|
67
|
+
index: number,
|
|
68
|
+
): { length: number; offset: number; index: number } => ({
|
|
69
|
+
length: 64,
|
|
70
|
+
offset: 64 * index,
|
|
71
|
+
index,
|
|
72
|
+
});
|
|
73
|
+
chipColor(item: IChip): string {
|
|
74
|
+
return `hsl(${(item.n * 47) % 360}, 70%, 50%)`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
beforeEach(() => fabric.reset());
|
|
79
|
+
afterEach(() => unmount(ROOT_TAG));
|
|
80
|
+
|
|
81
|
+
function findCommitted(
|
|
82
|
+
nodes: typeof fabric.committed,
|
|
83
|
+
predicate: (n: (typeof nodes)[number]) => boolean,
|
|
84
|
+
): (typeof nodes)[number] | undefined {
|
|
85
|
+
for (const node of nodes) {
|
|
86
|
+
if (predicate(node)) return node;
|
|
87
|
+
const found = findCommitted(node.children, predicate);
|
|
88
|
+
if (found !== undefined) return found;
|
|
89
|
+
}
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
describe('FlatList array-composed item style', () => {
|
|
94
|
+
it('flattens to a plain object instead of crashing ɵɵstyleMap, and commits it', async () => {
|
|
95
|
+
mount(ROOT_TAG, ChipListHost);
|
|
96
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
97
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
98
|
+
|
|
99
|
+
const chip0 = findCommitted(fabric.committed, node => node.props.testID === 'chip-0');
|
|
100
|
+
expect(chip0?.props).toMatchObject({
|
|
101
|
+
height: 72,
|
|
102
|
+
width: 64,
|
|
103
|
+
backgroundColor: 'hsl(0, 70%, 50%)',
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('does not free-run change detection once the window settles', async () => {
|
|
108
|
+
mount(ROOT_TAG, ChipListHost);
|
|
109
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
110
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
111
|
+
|
|
112
|
+
const scroll = fabric.find(node => node.viewName === 'RCTScrollView');
|
|
113
|
+
if (scroll !== undefined) {
|
|
114
|
+
fabric.fireEvent(scroll.instanceHandle, 'topLayout', {
|
|
115
|
+
layout: { x: 0, y: 0, width: 360, height: 84 },
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
119
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
120
|
+
|
|
121
|
+
let previous = fabric.counts.completeRoot;
|
|
122
|
+
let stillGrowing = false;
|
|
123
|
+
for (let tick = 0; tick < 10; tick += 1) {
|
|
124
|
+
await new Promise<void>(resolve => setTimeout(resolve, 0));
|
|
125
|
+
const current = fabric.counts.completeRoot;
|
|
126
|
+
if (current > previous) stillGrowing = true;
|
|
127
|
+
previous = current;
|
|
128
|
+
}
|
|
129
|
+
expect(stillGrowing).toBe(false);
|
|
130
|
+
});
|
|
131
|
+
});
|