react-native-tvos 0.69.6-3 → 0.69.8-0rc
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/Libraries/Components/TV/TVFocusGuideView.js +72 -61
- package/Libraries/Components/View/ViewNativeComponent.js +1 -1
- package/Libraries/Core/ReactNativeVersion.js +2 -2
- package/Libraries/Lists/VirtualizedList.js +25 -10
- package/README.md +2 -1
- package/React/Base/RCTVersion.m +2 -2
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +66 -29
- package/React/Views/RCTTVView.h +6 -1
- package/React/Views/RCTTVView.m +65 -7
- package/React/Views/RCTViewManager.m +5 -1
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +7 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactAndroidHWInputDeviceHelper.java +44 -14
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +25 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java +60 -11
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java +40 -4
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/react/renderer/components/view/ViewProps.cpp +80 -16
- package/ReactCommon/react/renderer/components/view/ViewProps.h +8 -0
- package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-debug-javadoc.jar → 0.69.8-0rc/hermes-engine-0.69.8-0rc-debug-javadoc.jar} +0 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-debug-javadoc.jar.md5 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-debug-javadoc.jar.sha1 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-debug-javadoc.jar.sha256 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-debug-javadoc.jar.sha512 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-debug.aar +0 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-debug.aar.md5 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-debug.aar.sha1 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-debug.aar.sha256 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-debug.aar.sha512 +1 -0
- package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-release-javadoc.jar → 0.69.8-0rc/hermes-engine-0.69.8-0rc-release-javadoc.jar} +0 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-release-javadoc.jar.md5 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-release-javadoc.jar.sha1 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-release-javadoc.jar.sha256 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-release-javadoc.jar.sha512 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-release.aar +0 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-release.aar.md5 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-release.aar.sha1 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-release.aar.sha256 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc-release.aar.sha512 +1 -0
- package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3.module → 0.69.8-0rc/hermes-engine-0.69.8-0rc.module} +47 -47
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc.module.md5 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc.module.sha1 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc.module.sha256 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc.module.sha512 +1 -0
- package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3.pom → 0.69.8-0rc/hermes-engine-0.69.8-0rc.pom} +1 -1
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc.pom.md5 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc.pom.sha1 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc.pom.sha256 +1 -0
- package/android/com/facebook/react/hermes-engine/0.69.8-0rc/hermes-engine-0.69.8-0rc.pom.sha512 +1 -0
- package/android/com/facebook/react/hermes-engine/maven-metadata.xml +4 -4
- package/android/com/facebook/react/hermes-engine/maven-metadata.xml.md5 +1 -1
- package/android/com/facebook/react/hermes-engine/maven-metadata.xml.sha1 +1 -1
- package/android/com/facebook/react/hermes-engine/maven-metadata.xml.sha256 +1 -1
- package/android/com/facebook/react/hermes-engine/maven-metadata.xml.sha512 +1 -1
- package/android/com/facebook/react/react-native/{0.69.6-3/react-native-0.69.6-3-debug-javadoc.jar → 0.69.8-0rc/react-native-0.69.8-0rc-debug-javadoc.jar} +0 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug-javadoc.jar.md5 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug-javadoc.jar.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug-javadoc.jar.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug-javadoc.jar.sha512 +1 -0
- package/android/com/facebook/react/react-native/{0.69.6-3/react-native-0.69.6-3-debug-sources.jar → 0.69.8-0rc/react-native-0.69.8-0rc-debug-sources.jar} +0 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug-sources.jar.md5 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug-sources.jar.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug-sources.jar.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug-sources.jar.sha512 +1 -0
- package/android/com/facebook/react/react-native/{0.69.6-3/react-native-0.69.6-3-debug.aar → 0.69.8-0rc/react-native-0.69.8-0rc-debug.aar} +0 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug.aar.md5 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug.aar.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug.aar.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-debug.aar.sha512 +1 -0
- package/android/com/facebook/react/react-native/{0.69.6-3/react-native-0.69.6-3-release-javadoc.jar → 0.69.8-0rc/react-native-0.69.8-0rc-release-javadoc.jar} +0 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release-javadoc.jar.md5 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release-javadoc.jar.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release-javadoc.jar.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release-javadoc.jar.sha512 +1 -0
- package/android/com/facebook/react/react-native/{0.69.6-3/react-native-0.69.6-3-release-sources.jar → 0.69.8-0rc/react-native-0.69.8-0rc-release-sources.jar} +0 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release-sources.jar.md5 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release-sources.jar.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release-sources.jar.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release-sources.jar.sha512 +1 -0
- package/android/com/facebook/react/react-native/{0.69.6-3/react-native-0.69.6-3-release.aar → 0.69.8-0rc/react-native-0.69.8-0rc-release.aar} +0 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release.aar.md5 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release.aar.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release.aar.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc-release.aar.sha512 +1 -0
- package/android/com/facebook/react/react-native/{0.69.6-3/react-native-0.69.6-3.module → 0.69.8-0rc/react-native-0.69.8-0rc.module} +57 -57
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc.module.md5 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc.module.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc.module.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc.module.sha512 +1 -0
- package/android/com/facebook/react/react-native/{0.69.6-3/react-native-0.69.6-3.pom → 0.69.8-0rc/react-native-0.69.8-0rc.pom} +1 -1
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc.pom.md5 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc.pom.sha1 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc.pom.sha256 +1 -0
- package/android/com/facebook/react/react-native/0.69.8-0rc/react-native-0.69.8-0rc.pom.sha512 +1 -0
- package/android/com/facebook/react/react-native/maven-metadata.xml +4 -4
- package/android/com/facebook/react/react-native/maven-metadata.xml.md5 +1 -1
- package/android/com/facebook/react/react-native/maven-metadata.xml.sha1 +1 -1
- package/android/com/facebook/react/react-native/maven-metadata.xml.sha256 +1 -1
- package/android/com/facebook/react/react-native/maven-metadata.xml.sha512 +1 -1
- package/package.json +2 -2
- package/sdks/hermesc/linux64-bin/hermesc +0 -0
- package/sdks/hermesc/osx-bin/hermesc +0 -0
- package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
- package/template/package.json +1 -1
- package/tvos-types.d.ts +28 -5
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-debug-javadoc.jar.md5 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-debug-javadoc.jar.sha1 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-debug-javadoc.jar.sha256 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-debug-javadoc.jar.sha512 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-debug.aar +0 -0
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-debug.aar.md5 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-debug.aar.sha1 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-debug.aar.sha256 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-debug.aar.sha512 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-release-javadoc.jar.md5 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-release-javadoc.jar.sha1 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-release-javadoc.jar.sha256 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-release-javadoc.jar.sha512 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-release.aar +0 -0
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-release.aar.md5 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-release.aar.sha1 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-release.aar.sha256 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3-release.aar.sha512 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3.module.md5 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3.module.sha1 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3.module.sha256 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3.module.sha512 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3.pom.md5 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3.pom.sha1 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3.pom.sha256 +0 -1
- package/android/com/facebook/react/hermes-engine/0.69.6-3/hermes-engine-0.69.6-3.pom.sha512 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug-javadoc.jar.md5 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug-javadoc.jar.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug-javadoc.jar.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug-javadoc.jar.sha512 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug-sources.jar.md5 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug-sources.jar.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug-sources.jar.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug-sources.jar.sha512 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug.aar.md5 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug.aar.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug.aar.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-debug.aar.sha512 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release-javadoc.jar.md5 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release-javadoc.jar.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release-javadoc.jar.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release-javadoc.jar.sha512 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release-sources.jar.md5 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release-sources.jar.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release-sources.jar.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release-sources.jar.sha512 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release.aar.md5 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release.aar.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release.aar.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3-release.aar.sha512 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3.module.md5 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3.module.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3.module.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3.module.sha512 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3.pom.md5 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3.pom.sha1 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3.pom.sha256 +0 -1
- package/android/com/facebook/react/react-native/0.69.6-3/react-native-0.69.6-3.pom.sha512 +0 -1
- /package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-debug-sources.jar → 0.69.8-0rc/hermes-engine-0.69.8-0rc-debug-sources.jar} +0 -0
- /package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-debug-sources.jar.md5 → 0.69.8-0rc/hermes-engine-0.69.8-0rc-debug-sources.jar.md5} +0 -0
- /package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-debug-sources.jar.sha1 → 0.69.8-0rc/hermes-engine-0.69.8-0rc-debug-sources.jar.sha1} +0 -0
- /package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-debug-sources.jar.sha256 → 0.69.8-0rc/hermes-engine-0.69.8-0rc-debug-sources.jar.sha256} +0 -0
- /package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-debug-sources.jar.sha512 → 0.69.8-0rc/hermes-engine-0.69.8-0rc-debug-sources.jar.sha512} +0 -0
- /package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-release-sources.jar → 0.69.8-0rc/hermes-engine-0.69.8-0rc-release-sources.jar} +0 -0
- /package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-release-sources.jar.md5 → 0.69.8-0rc/hermes-engine-0.69.8-0rc-release-sources.jar.md5} +0 -0
- /package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-release-sources.jar.sha1 → 0.69.8-0rc/hermes-engine-0.69.8-0rc-release-sources.jar.sha1} +0 -0
- /package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-release-sources.jar.sha256 → 0.69.8-0rc/hermes-engine-0.69.8-0rc-release-sources.jar.sha256} +0 -0
- /package/android/com/facebook/react/hermes-engine/{0.69.6-3/hermes-engine-0.69.6-3-release-sources.jar.sha512 → 0.69.8-0rc/hermes-engine-0.69.8-0rc-release-sources.jar.sha512} +0 -0
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
|
|
11
11
|
const React = require('react');
|
|
12
12
|
const ReactNative = require('react-native');
|
|
13
|
-
|
|
14
|
-
const Platform = require('../../Utilities/Platform');
|
|
13
|
+
|
|
15
14
|
import {Commands} from '../View/ViewNativeComponent';
|
|
16
15
|
import type {ViewProps} from '../View/ViewPropTypes';
|
|
16
|
+
import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes';
|
|
17
|
+
import setAndForwardRef from '../../Utilities/setAndForwardRef';
|
|
17
18
|
|
|
18
19
|
type TVFocusGuideViewProps = $ReadOnly<{
|
|
19
20
|
...ViewProps,
|
|
@@ -28,7 +29,7 @@ type TVFocusGuideViewProps = $ReadOnly<{
|
|
|
28
29
|
/**
|
|
29
30
|
* The views the focus should go to
|
|
30
31
|
*/
|
|
31
|
-
destinations?: ?
|
|
32
|
+
destinations?: (?React.ElementRef<HostComponent<mixed>>)[],
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* @deprecated Don't use it, no longer necessary.
|
|
@@ -36,79 +37,83 @@ type TVFocusGuideViewProps = $ReadOnly<{
|
|
|
36
37
|
safePadding?: 'vertical' | 'horizontal' | 'both' | null,
|
|
37
38
|
|
|
38
39
|
autoFocus?: boolean,
|
|
39
|
-
}>;
|
|
40
|
-
|
|
41
|
-
const TVFocusGuideView = ({
|
|
42
|
-
enabled = true,
|
|
43
|
-
safePadding,
|
|
44
|
-
...props
|
|
45
|
-
}: TVFocusGuideViewProps): React.Node => {
|
|
46
|
-
const enabledStyle = {display: enabled ? 'flex' : 'none'};
|
|
47
|
-
const style = [styles.container, props.style, enabledStyle];
|
|
48
|
-
|
|
49
|
-
// `autoFocus` and `destinations` props shouldn't be used together.
|
|
50
|
-
// Otherwise they can conflict with each other. So if `destinations` is
|
|
51
|
-
// provided, we set `autoFocus` prop to false to avoid that conflict.
|
|
52
|
-
const autoFocus = props.destinations?.length ? false : props.autoFocus;
|
|
53
40
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
41
|
+
trapFocusUp?: boolean,
|
|
42
|
+
trapFocusDown?: boolean,
|
|
43
|
+
trapFocusLeft?: boolean,
|
|
44
|
+
trapFocusRight?: boolean,
|
|
45
|
+
}>;
|
|
59
46
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
47
|
+
export type TVFocusGuideViewImperativeMethods = $ReadOnly<{
|
|
48
|
+
setDestinations: (
|
|
49
|
+
destinations: (?React.ElementRef<HostComponent<mixed>>)[],
|
|
50
|
+
) => void,
|
|
51
|
+
}>;
|
|
65
52
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
53
|
+
function TVFocusGuideView(
|
|
54
|
+
{
|
|
55
|
+
enabled = true,
|
|
56
|
+
safePadding,
|
|
57
|
+
destinations: destinationsProp,
|
|
58
|
+
...props
|
|
59
|
+
}: TVFocusGuideViewProps,
|
|
60
|
+
forwardedRef,
|
|
61
|
+
): React.Node {
|
|
62
|
+
const focusGuideRef = React.useRef<React.ElementRef<
|
|
63
|
+
typeof ReactNative.View,
|
|
64
|
+
> | null>(null);
|
|
65
|
+
|
|
66
|
+
const setDestinations = React.useCallback(
|
|
67
|
+
(destinations: (?React.ElementRef<HostComponent<mixed>>)[]) => {
|
|
68
|
+
const dests: number[] = (destinations || [])
|
|
69
|
+
.map(ReactNative.findNodeHandle)
|
|
70
|
+
.filter(Boolean);
|
|
71
|
+
|
|
72
|
+
if (focusGuideRef.current != null) {
|
|
73
|
+
Commands.setDestinations(focusGuideRef.current, dests);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
[],
|
|
77
|
+
);
|
|
69
78
|
|
|
70
|
-
const
|
|
71
|
-
|
|
79
|
+
const _setNativeRef = setAndForwardRef({
|
|
80
|
+
getForwardedRef: () => forwardedRef,
|
|
81
|
+
setLocalRef: ref => {
|
|
82
|
+
focusGuideRef.current = ref;
|
|
83
|
+
|
|
84
|
+
// This is a hack. Ideally we would forwardRef to the underlying
|
|
85
|
+
// host component. However, since TVFocusGuide has it's own methods that can be
|
|
86
|
+
// called as well, if we used the standard forwardRef then these
|
|
87
|
+
// methods wouldn't be accessible
|
|
88
|
+
//
|
|
89
|
+
// Here we mutate the ref, so that the user can use the standart native
|
|
90
|
+
// methods like `focus()`, `blur()`, etc. and while also having access to
|
|
91
|
+
// imperative methods of this component like `setDestinations()`.
|
|
92
|
+
if (ref) {
|
|
93
|
+
ref.setDestinations = setDestinations;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
});
|
|
72
97
|
|
|
73
98
|
React.useEffect(() => {
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
.map(d => ReactNative.findNodeHandle(d))
|
|
77
|
-
.filter(c => c !== 0 && c !== null && c !== undefined);
|
|
78
|
-
const hostComponentRef = ReactNativeShims.findHostInstance_DEPRECATED(
|
|
79
|
-
focusGuideRef?.current,
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
hostComponentRef &&
|
|
83
|
-
Commands.setDestinations(hostComponentRef, nativeDestinations);
|
|
99
|
+
if (destinationsProp != null) {
|
|
100
|
+
setDestinations(destinationsProp);
|
|
84
101
|
}
|
|
85
|
-
}, [
|
|
102
|
+
}, [setDestinations, destinationsProp]);
|
|
86
103
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
<ReactNative.View ref={focusGuideRef} {...props} collapsable={false} />
|
|
90
|
-
);
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const FocusGuideViewAndroidTV = (props: TVFocusGuideViewProps) => {
|
|
94
|
-
const nativeDestinations = React.useMemo(
|
|
95
|
-
() =>
|
|
96
|
-
(props.destinations || [])
|
|
97
|
-
.map(d => ReactNative.findNodeHandle(d))
|
|
98
|
-
.filter(c => c !== 0 && c !== null && c !== undefined),
|
|
99
|
-
[props.destinations],
|
|
100
|
-
);
|
|
104
|
+
const enabledStyle = {display: enabled ? 'flex' : 'none'};
|
|
105
|
+
const style = [styles.container, props.style, enabledStyle];
|
|
101
106
|
|
|
102
107
|
return (
|
|
103
108
|
// $FlowFixMe[prop-missing]
|
|
104
109
|
<ReactNative.View
|
|
105
110
|
{...props}
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
style={style}
|
|
112
|
+
ref={_setNativeRef}
|
|
108
113
|
collapsable={false}
|
|
109
114
|
/>
|
|
110
115
|
);
|
|
111
|
-
}
|
|
116
|
+
}
|
|
112
117
|
|
|
113
118
|
const styles = ReactNative.StyleSheet.create({
|
|
114
119
|
container: {
|
|
@@ -117,4 +122,10 @@ const styles = ReactNative.StyleSheet.create({
|
|
|
117
122
|
},
|
|
118
123
|
});
|
|
119
124
|
|
|
120
|
-
|
|
125
|
+
const ForwardedTVFocusGuideView: React.AbstractComponent<
|
|
126
|
+
TVFocusGuideViewProps,
|
|
127
|
+
React.ElementRef<HostComponent<mixed>> & TVFocusGuideViewImperativeMethods,
|
|
128
|
+
> = React.forwardRef(TVFocusGuideView);
|
|
129
|
+
ForwardedTVFocusGuideView.displayName = 'TVFocusGuideView';
|
|
130
|
+
|
|
131
|
+
module.exports = ForwardedTVFocusGuideView;
|
|
@@ -96,7 +96,7 @@ interface NativeCommands {
|
|
|
96
96
|
// Apple TV focus guide API
|
|
97
97
|
+setDestinations: (
|
|
98
98
|
viewRef: React.ElementRef<HostComponent<mixed>>,
|
|
99
|
-
destinations: Array<
|
|
99
|
+
destinations: Array<number>, // Node handles are basically integers
|
|
100
100
|
) => void;
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
type ChildListState,
|
|
43
43
|
type ListDebugInfo,
|
|
44
44
|
} from './VirtualizedListContext.js';
|
|
45
|
+
import TVFocusGuideView from '../Components/TV/TVFocusGuideView';
|
|
45
46
|
|
|
46
47
|
type Item = any;
|
|
47
48
|
|
|
@@ -1116,16 +1117,30 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|
|
1116
1117
|
unregisterAsNestedChild: this._unregisterAsNestedChild,
|
|
1117
1118
|
debugInfo: this._getDebugInfo(),
|
|
1118
1119
|
}}>
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
this.props.
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1120
|
+
<TVFocusGuideView
|
|
1121
|
+
trapFocusLeft={
|
|
1122
|
+
horizontalOrDefault(this.props.horizontal) && this.state.first > 0
|
|
1123
|
+
}
|
|
1124
|
+
trapFocusRight={
|
|
1125
|
+
horizontalOrDefault(this.props.horizontal) && this._hasMore
|
|
1126
|
+
}
|
|
1127
|
+
trapFocusUp={
|
|
1128
|
+
!horizontalOrDefault(this.props.horizontal) && this.state.first > 0
|
|
1129
|
+
}
|
|
1130
|
+
trapFocusDown={
|
|
1131
|
+
!horizontalOrDefault(this.props.horizontal) && this._hasMore
|
|
1132
|
+
}>
|
|
1133
|
+
{React.cloneElement(
|
|
1134
|
+
(
|
|
1135
|
+
this.props.renderScrollComponent ||
|
|
1136
|
+
this._defaultRenderScrollComponent
|
|
1137
|
+
)(scrollProps),
|
|
1138
|
+
{
|
|
1139
|
+
ref: this._captureScrollRef,
|
|
1140
|
+
},
|
|
1141
|
+
cells,
|
|
1142
|
+
)}
|
|
1143
|
+
</TVFocusGuideView>
|
|
1129
1144
|
</VirtualizedListContextProvider>
|
|
1130
1145
|
);
|
|
1131
1146
|
let ret: React.Node = innerRet;
|
package/README.md
CHANGED
|
@@ -207,7 +207,8 @@ class Game2048 extends React.Component {
|
|
|
207
207
|
| Prop | Value | Description |
|
|
208
208
|
|---|---|---|
|
|
209
209
|
| destinations | any[]? | Array of `Component`s to register as destinations of the FocusGuideView |
|
|
210
|
-
| autoFocus | boolean? | If true, `TVFocusGuide` will automatically manage focus for you. It will redirect the focus to the first focusable child on the first visit. It also remembers the last focused child and redirects the focus to it on the subsequent visits. |
|
|
210
|
+
| autoFocus | boolean? | If true, `TVFocusGuide` will automatically manage focus for you. It will redirect the focus to the first focusable child on the first visit. It also remembers the last focused child and redirects the focus to it on the subsequent visits. `destinations` prop takes precedence over this prop when used together. |
|
|
211
|
+
| trapFocus* (Up, Down, Left, Right) | Prevents focus escaping from the container for the given directions. |
|
|
211
212
|
|
|
212
213
|
- _Next Focus Direction_: the props `nextFocus*` on `View` should work as expected on iOS too (previously android only). One caveat is that if there is no focusable in the `nextFocusable*` direction next to the starting view, iOS doesn't check if we want to override the destination.
|
|
213
214
|
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -23,8 +23,8 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
|
|
23
23
|
__rnVersion = @{
|
|
24
24
|
RCTVersionMajor: @(0),
|
|
25
25
|
RCTVersionMinor: @(69),
|
|
26
|
-
RCTVersionPatch: @(
|
|
27
|
-
RCTVersionPrerelease: @"
|
|
26
|
+
RCTVersionPatch: @(8),
|
|
27
|
+
RCTVersionPrerelease: @"0rc",
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
return __rnVersion;
|
|
@@ -53,6 +53,12 @@ using namespace facebook::react;
|
|
|
53
53
|
UIView *_nextFocusRight;
|
|
54
54
|
UIView *_nextFocusActiveTarget;
|
|
55
55
|
BOOL _autoFocus;
|
|
56
|
+
BOOL _trapFocusUp;
|
|
57
|
+
BOOL _trapFocusDown;
|
|
58
|
+
BOOL _trapFocusLeft;
|
|
59
|
+
BOOL _trapFocusRight;
|
|
60
|
+
NSArray* _focusDestinations;
|
|
61
|
+
id<UIFocusItem> _previouslyFocusedItem;
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
@synthesize removeClippedSubviews = _removeClippedSubviews;
|
|
@@ -132,7 +138,7 @@ using namespace facebook::react;
|
|
|
132
138
|
return (RCTRootComponentView *)rootview;
|
|
133
139
|
}
|
|
134
140
|
|
|
135
|
-
- (void)addFocusGuide {
|
|
141
|
+
- (void)addFocusGuide:(NSArray*)destinations {
|
|
136
142
|
if (self.focusGuide == nil) {
|
|
137
143
|
self.focusGuide = [UIFocusGuide new];
|
|
138
144
|
[self addLayoutGuide:self.focusGuide];
|
|
@@ -142,18 +148,47 @@ using namespace facebook::react;
|
|
|
142
148
|
[self.focusGuide.widthAnchor constraintEqualToAnchor:self.widthAnchor].active = YES;
|
|
143
149
|
[self.focusGuide.heightAnchor constraintEqualToAnchor:self.heightAnchor].active = YES;
|
|
144
150
|
}
|
|
151
|
+
|
|
152
|
+
self.focusGuide.preferredFocusEnvironments = destinations;
|
|
145
153
|
}
|
|
146
154
|
|
|
147
155
|
- (void)removeFocusGuide {
|
|
148
156
|
if (self.focusGuide != nil) {
|
|
157
|
+
_focusDestinations = nil;
|
|
158
|
+
_previouslyFocusedItem = nil;
|
|
159
|
+
|
|
149
160
|
[self removeLayoutGuide:self.focusGuide];
|
|
150
161
|
self.focusGuide = nil;
|
|
151
162
|
}
|
|
152
163
|
}
|
|
153
164
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
165
|
+
/// Responsible of determining what focusGuide's next state should be based on the active properties of the component.
|
|
166
|
+
- (void)handleFocusGuide
|
|
167
|
+
{
|
|
168
|
+
// `destinations` should always be favored against `autoFocus` feature, if provided.
|
|
169
|
+
if (_focusDestinations != nil) {
|
|
170
|
+
[self addFocusGuide:_focusDestinations];
|
|
171
|
+
} else if (_autoFocus && _previouslyFocusedItem != nil) {
|
|
172
|
+
// We also add `self` as the second option in case `previouslyFocusedItem` becomes unreachable (e.g gets detached).
|
|
173
|
+
// `self` helps redirecting focus to the first focusable element in that case.
|
|
174
|
+
[self addFocusGuide:@[_previouslyFocusedItem, self]];
|
|
175
|
+
} else if (_autoFocus) {
|
|
176
|
+
[self addFocusGuide:@[self]];
|
|
177
|
+
} else {
|
|
178
|
+
// Then there's no need to have `focusGuide`, remove it to prevent potential bugs.
|
|
179
|
+
[self removeFocusGuide];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
- (void)setFocusDestinations:(NSArray*)destinations
|
|
184
|
+
{
|
|
185
|
+
if(destinations.count == 0) {
|
|
186
|
+
_focusDestinations = nil;
|
|
187
|
+
} else {
|
|
188
|
+
_focusDestinations = destinations;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
[self handleFocusGuide];
|
|
157
192
|
}
|
|
158
193
|
|
|
159
194
|
- (void)sendFocusNotification:(__unused UIFocusUpdateContext *)context
|
|
@@ -422,6 +457,23 @@ using namespace facebook::react;
|
|
|
422
457
|
}
|
|
423
458
|
}
|
|
424
459
|
|
|
460
|
+
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
|
|
461
|
+
{
|
|
462
|
+
// This is the `trapFocus*` logic that prevents the focus updates if
|
|
463
|
+
// focus should be trapped and `nextFocusedItem` is not a child FocusEnv.
|
|
464
|
+
if ((_trapFocusUp && context.focusHeading == UIFocusHeadingUp)
|
|
465
|
+
|| (_trapFocusDown && context.focusHeading == UIFocusHeadingDown)
|
|
466
|
+
|| (_trapFocusLeft && context.focusHeading == UIFocusHeadingLeft)
|
|
467
|
+
|| (_trapFocusRight && context.focusHeading == UIFocusHeadingRight)) {
|
|
468
|
+
|
|
469
|
+
// Checks if `nextFocusedItem` is a child `FocusEnvironment`.
|
|
470
|
+
// If not, it returns false thus it keeps the focus inside.
|
|
471
|
+
return [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem];
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return [super shouldUpdateFocusInContext:context];
|
|
475
|
+
}
|
|
476
|
+
|
|
425
477
|
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
|
|
426
478
|
{
|
|
427
479
|
if (context.previouslyFocusedView == context.nextFocusedView) {
|
|
@@ -433,9 +485,8 @@ using namespace facebook::react;
|
|
|
433
485
|
// So, `previouslyFocusedItem` is always the last focused child of `TVFocusGuide`.
|
|
434
486
|
// We should update `preferredFocusEnvironments` in this case to make sure `FocusGuide` remembers
|
|
435
487
|
// the last focused element and redirects the focus to it whenever focus comes back.
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
self.focusGuide.preferredFocusEnvironments = @[context.previouslyFocusedItem, self];
|
|
488
|
+
_previouslyFocusedItem = context.previouslyFocusedItem;
|
|
489
|
+
[self handleFocusGuide];
|
|
439
490
|
}
|
|
440
491
|
|
|
441
492
|
if (context.nextFocusedView == self && self.isUserInteractionEnabled ) {
|
|
@@ -481,7 +532,7 @@ using namespace facebook::react;
|
|
|
481
532
|
[destinations addObject:view];
|
|
482
533
|
}
|
|
483
534
|
}
|
|
484
|
-
[self
|
|
535
|
+
[self setFocusDestinations:destinations];
|
|
485
536
|
return;
|
|
486
537
|
#endif
|
|
487
538
|
}
|
|
@@ -851,12 +902,13 @@ using namespace facebook::react;
|
|
|
851
902
|
// `autoFocus`
|
|
852
903
|
if (oldViewProps.autoFocus != newViewProps.autoFocus) {
|
|
853
904
|
_autoFocus = newViewProps.autoFocus;
|
|
854
|
-
|
|
855
|
-
[self addFocusGuide];
|
|
856
|
-
} else {
|
|
857
|
-
[self removeFocusGuide];
|
|
858
|
-
}
|
|
905
|
+
[self handleFocusGuide];
|
|
859
906
|
}
|
|
907
|
+
|
|
908
|
+
_trapFocusUp = newViewProps.trapFocusUp;
|
|
909
|
+
_trapFocusDown = newViewProps.trapFocusDown;
|
|
910
|
+
_trapFocusLeft = newViewProps.trapFocusLeft;
|
|
911
|
+
_trapFocusRight = newViewProps.trapFocusRight;
|
|
860
912
|
#endif
|
|
861
913
|
|
|
862
914
|
|
|
@@ -943,22 +995,7 @@ using namespace facebook::react;
|
|
|
943
995
|
self.layer.opacity = (float)props.opacity;
|
|
944
996
|
}
|
|
945
997
|
|
|
946
|
-
|
|
947
|
-
// Resetting it also introduces a bug but it prevents much worse ones.
|
|
948
|
-
// The destination `focusEnvironment` reference could be recycled and used in another place so we might
|
|
949
|
-
// be holding a reference and redirecting the focus to the wrong view.
|
|
950
|
-
// To make sure that's not the case, we reset the destination to `self` which will
|
|
951
|
-
// redirect the focus to the first focusable child.
|
|
952
|
-
if (self.focusGuide != nil) {
|
|
953
|
-
self.focusGuide.preferredFocusEnvironments = @[self];
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
// If `autoFocus` is enabled, addition/removal process of `UIFocusGuide` is managed
|
|
957
|
-
// inside `updateProps` method. Removing `UIFocusGuide` here for that case would cause
|
|
958
|
-
// weird bugs and state loss.
|
|
959
|
-
if (!_autoFocus) {
|
|
960
|
-
[self removeFocusGuide];
|
|
961
|
-
}
|
|
998
|
+
[self removeFocusGuide];
|
|
962
999
|
|
|
963
1000
|
_propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN = nil;
|
|
964
1001
|
_eventEmitter.reset();
|
package/React/Views/RCTTVView.h
CHANGED
|
@@ -47,6 +47,11 @@
|
|
|
47
47
|
*/
|
|
48
48
|
@property (nonatomic, assign) BOOL autoFocus;
|
|
49
49
|
|
|
50
|
+
@property (nonatomic, assign) BOOL trapFocusUp;
|
|
51
|
+
@property (nonatomic, assign) BOOL trapFocusDown;
|
|
52
|
+
@property (nonatomic, assign) BOOL trapFocusLeft;
|
|
53
|
+
@property (nonatomic, assign) BOOL trapFocusRight;
|
|
54
|
+
|
|
50
55
|
- (instancetype)initWithBridge:(RCTBridge *)bridge;
|
|
51
56
|
|
|
52
57
|
/**
|
|
@@ -75,7 +80,7 @@
|
|
|
75
80
|
- (void)removeParallaxMotionEffects;
|
|
76
81
|
|
|
77
82
|
|
|
78
|
-
- (void)
|
|
83
|
+
- (void)setFocusDestinations:(NSArray*)destinations;
|
|
79
84
|
|
|
80
85
|
@property (nonatomic, strong) UIFocusGuide * focusGuide;
|
|
81
86
|
|
package/React/Views/RCTTVView.m
CHANGED
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
__weak RCTBridge *_bridge;
|
|
24
24
|
UITapGestureRecognizer *_selectRecognizer;
|
|
25
25
|
BOOL motionEffectsAdded;
|
|
26
|
+
NSArray* focusDestinations;
|
|
27
|
+
id<UIFocusItem> previouslyFocusedItem;
|
|
28
|
+
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
- (instancetype)initWithBridge:(RCTBridge *)bridge {
|
|
@@ -255,6 +258,23 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
|
|
|
255
258
|
motionEffectsAdded = NO;
|
|
256
259
|
}
|
|
257
260
|
|
|
261
|
+
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
|
|
262
|
+
{
|
|
263
|
+
// This is the `trapFocus*` logic that prevents the focus updates if
|
|
264
|
+
// focus should be trapped and `nextFocusedItem` is not a child FocusEnv.
|
|
265
|
+
if ((_trapFocusUp && context.focusHeading == UIFocusHeadingUp)
|
|
266
|
+
|| (_trapFocusDown && context.focusHeading == UIFocusHeadingDown)
|
|
267
|
+
|| (_trapFocusLeft && context.focusHeading == UIFocusHeadingLeft)
|
|
268
|
+
|| (_trapFocusRight && context.focusHeading == UIFocusHeadingRight)) {
|
|
269
|
+
|
|
270
|
+
// Checks if `nextFocusedItem` is a child `FocusEnvironment`.
|
|
271
|
+
// If not, it returns false thus it keeps the focus inside.
|
|
272
|
+
return [UIFocusSystem environment:self containsEnvironment:context.nextFocusedItem];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return [super shouldUpdateFocusInContext:context];
|
|
276
|
+
}
|
|
277
|
+
|
|
258
278
|
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context
|
|
259
279
|
withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
|
|
260
280
|
{
|
|
@@ -267,9 +287,8 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
|
|
|
267
287
|
// So, `previouslyFocusedItem` is always the last focused child of `TVFocusGuide`.
|
|
268
288
|
// We should update `preferredFocusEnvironments` in this case to make sure `FocusGuide` remembers
|
|
269
289
|
// the last focused element and redirects the focus to it whenever focus comes back.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
self.focusGuide.preferredFocusEnvironments = @[context.previouslyFocusedItem, self];
|
|
290
|
+
previouslyFocusedItem = context.previouslyFocusedItem;
|
|
291
|
+
[self handleFocusGuide];
|
|
273
292
|
}
|
|
274
293
|
|
|
275
294
|
if (context.nextFocusedView == self && self.isTVSelectable ) {
|
|
@@ -445,10 +464,10 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
|
|
|
445
464
|
|
|
446
465
|
- (void)setAutoFocus:(BOOL)autoFocus
|
|
447
466
|
{
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
467
|
+
if (_autoFocus != autoFocus) {
|
|
468
|
+
_autoFocus = autoFocus;
|
|
469
|
+
[self handleFocusGuide];
|
|
470
|
+
}
|
|
452
471
|
}
|
|
453
472
|
|
|
454
473
|
- (void)addFocusGuide:(NSArray*)destinations {
|
|
@@ -465,4 +484,43 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
|
|
|
465
484
|
self.focusGuide.preferredFocusEnvironments = destinations;
|
|
466
485
|
}
|
|
467
486
|
|
|
487
|
+
- (void)removeFocusGuide {
|
|
488
|
+
if (self.focusGuide != nil) {
|
|
489
|
+
focusDestinations = nil;
|
|
490
|
+
previouslyFocusedItem = nil;
|
|
491
|
+
|
|
492
|
+
[self removeLayoutGuide:self.focusGuide];
|
|
493
|
+
self.focusGuide = nil;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/// Responsible of determining what focusGuide's next state should be based on the active properties of the component.
|
|
498
|
+
- (void)handleFocusGuide
|
|
499
|
+
{
|
|
500
|
+
// `destinations` should always be favored against `autoFocus` feature, if provided.
|
|
501
|
+
if (focusDestinations != nil) {
|
|
502
|
+
[self addFocusGuide:focusDestinations];
|
|
503
|
+
} else if (_autoFocus && previouslyFocusedItem != nil) {
|
|
504
|
+
// We also add `self` as the second option in case `previouslyFocusedItem` becomes unreachable (e.g gets detached).
|
|
505
|
+
// `self` helps redirecting focus to the first focusable element in that case.
|
|
506
|
+
[self addFocusGuide:@[previouslyFocusedItem, self]];
|
|
507
|
+
} else if (_autoFocus) {
|
|
508
|
+
[self addFocusGuide:@[self]];
|
|
509
|
+
} else {
|
|
510
|
+
// Then there's no need to have `focusGuide`, remove it to prevent potential bugs.
|
|
511
|
+
[self removeFocusGuide];
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
- (void)setFocusDestinations:(NSArray*)destinations
|
|
516
|
+
{
|
|
517
|
+
if(destinations.count == 0) {
|
|
518
|
+
focusDestinations = nil;
|
|
519
|
+
} else {
|
|
520
|
+
focusDestinations = destinations;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
[self handleFocusGuide];
|
|
524
|
+
}
|
|
525
|
+
|
|
468
526
|
@end
|
|
@@ -138,6 +138,10 @@ RCT_EXPORT_VIEW_PROPERTY(nextFocusDown, NSNumber)
|
|
|
138
138
|
RCT_EXPORT_VIEW_PROPERTY(nextFocusLeft, NSNumber)
|
|
139
139
|
RCT_EXPORT_VIEW_PROPERTY(nextFocusRight, NSNumber)
|
|
140
140
|
RCT_EXPORT_VIEW_PROPERTY(autoFocus, BOOL)
|
|
141
|
+
RCT_EXPORT_VIEW_PROPERTY(trapFocusUp, BOOL)
|
|
142
|
+
RCT_EXPORT_VIEW_PROPERTY(trapFocusDown, BOOL)
|
|
143
|
+
RCT_EXPORT_VIEW_PROPERTY(trapFocusLeft, BOOL)
|
|
144
|
+
RCT_EXPORT_VIEW_PROPERTY(trapFocusRight, BOOL)
|
|
141
145
|
#endif
|
|
142
146
|
|
|
143
147
|
// Accessibility related properties
|
|
@@ -452,7 +456,7 @@ RCT_EXPORT_METHOD(setDestinations : (nonnull NSNumber *)viewTag reactTags : (NSA
|
|
|
452
456
|
[destinations addObject:destination];
|
|
453
457
|
}
|
|
454
458
|
}
|
|
455
|
-
[view
|
|
459
|
+
[view setFocusDestinations:destinations];
|
|
456
460
|
}];
|
|
457
461
|
}
|
|
458
462
|
#endif
|
|
@@ -105,7 +105,13 @@ public class ReactFeatureFlags {
|
|
|
105
105
|
public static boolean enableDelayedViewStateDeletion = false;
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
|
-
* Send key down events as well as key up events
|
|
108
|
+
* Android TV: Send key down events as well as key up events.
|
|
109
|
+
* Enabling this flag will result in two 'select' TVRemoteEventHandler events
|
|
110
|
+
* (one with key action 0 and one with key action 1) for each press of the center
|
|
111
|
+
* DPad button. (Similarly for arrow keys.)
|
|
112
|
+
* Note: If you enable this flag, long presses of the select or center button will
|
|
113
|
+
* result in an initial 'select' with eventKeyAction = 0 (ACTION_DOWN), before
|
|
114
|
+
* the expected 'longSelect' events are fired. (Similarly for arrow keys.)
|
|
109
115
|
*/
|
|
110
116
|
public static boolean enableKeyDownEvents = false;
|
|
111
117
|
|