From fd0923e7296fe0e982f18311a6837f01bf9a6bd3 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Thu, 13 Oct 2022 14:16:20 +0200 Subject: [PATCH 01/24] adding accessibilityTitle prop to ReactAndroid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "mHostView.addView adds the react views to the modal. The modal is a wrapper around react views. They are added to the modal. mDialog.setTitle does not display the title. The react-native implementation must have changed the functionality. Commenting addTitle creates issues. Try to call setTitle on the Activity (the Dialog is included in a Custom Activity) Investigate PhoneWindow.setTitle in particular onWindowTitleChanged and dispatchWindowAttributesChanged UPDATE: The method is WindowManager.setTitle" "https://github.com/fabriziobertoglio1987/react-native/blob/62f83a9fad027ef0ed808f7e34973bb01cdf10e9/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java#L114 https://github.com/aosp-mirror/platform_frameworks_base/blob/e648d3cb91f9a0156c729ca18ec27e71f59f9ce2/core/java/android/view/WindowManager.java#L3794" "Read TalkBack logic around dialog and title. Research for string associated with the Dialog role Research for logic related to the title attribute" Read logic mDialog https://github.com/fabriziobertoglio1987/react-native/blob/62f83a9fad027ef0ed808f7e34973bb01cdf10e9/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java#L285 Read logic from AOSP Dialog, Window and WindowManager https://github.com/aosp-mirror/platform_frameworks_base/blob/e648d3cb91f9a0156c729ca18ec27e71f59f9ce2/core/java/android/app/Dialog.java#L641 https://github.com/aosp-mirror/platform_frameworks_base/blob/e648d3cb91f9a0156c729ca18ec27e71f59f9ce2/core/java/android/view/Window.java#L1444 https://github.com/aosp-mirror/platform_frameworks_base/blob/e648d3cb91f9a0156c729ca18ec27e71f59f9ce2/core/java/android/view/WindowManager.java#L3801 "Quickly test the following solution: Implement prop accessibilityTitle Implement method DialogManager accessibilityTitle Call mDialog.setTitle(“my title”) The setter method setAccessibilityTitle is not called" "The setter method setAccessibilityTitle is not called, while the other props are called: Read other files in the same folder Read cpp fabric files Add fabric configurations Read reactnative.dev codegen instructions" "Troubleshoot codegen generation of the accessibilityTitle prop. The prop is not added to jave codegen files generated in ReactAndroid/generated/codegen/Modal. Make sure the prop is added and test the outcome: Read instructions on reactnative.dev on codegen types to use for this prop (optional) Codegen does not include accessibilityTitle prop. Make sure codegen adds the title.   Try testing on Paper. If the issue does not reproduce on Paper, it is caused by a missing CPP prop configuration" https://reactnative.dev/docs/the-new-architecture/pillars-codegen --- Libraries/Modal/Modal.js | 2 ++ Libraries/Modal/RCTModalHostViewNativeComponent.js | 1 + .../react/views/modal/ReactModalHostManager.java | 5 +++++ .../facebook/react/views/modal/ReactModalHostView.java | 10 ++++++++++ 4 files changed, 18 insertions(+) diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index b41ec143d633d3..a6e6a860362369 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -94,6 +94,7 @@ export type Props = $ReadOnly<{| * See https://reactnative.dev/docs/modal#transparent */ statusBarTranslucent?: ?boolean, + accessibilityTitle?: ?string, /** * The `hardwareAccelerated` prop controls whether to force hardware @@ -264,6 +265,7 @@ class Modal extends React.Component { // $FlowFixMe[method-unbinding] added when improving typing for this parameters onStartShouldSetResponder={this._shouldSetResponder} supportedOrientations={this.props.supportedOrientations} + accessibilityTitle={this.props.accessibilityTitle} onOrientationChange={this.props.onOrientationChange} testID={this.props.testID}> diff --git a/Libraries/Modal/RCTModalHostViewNativeComponent.js b/Libraries/Modal/RCTModalHostViewNativeComponent.js index a21af54ae4fe72..549388b466c84e 100644 --- a/Libraries/Modal/RCTModalHostViewNativeComponent.js +++ b/Libraries/Modal/RCTModalHostViewNativeComponent.js @@ -131,6 +131,7 @@ type NativeProps = $ReadOnly<{| * The `identifier` is the unique number for identifying Modal components. */ identifier?: WithDefault, + accessibilityTitle?: WithDefault, |}>; export default (codegenNativeComponent('ModalHostView', { diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java index 15ce94cb0ad66c..5e4f021733294e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java @@ -87,6 +87,11 @@ public void setStatusBarTranslucent(ReactModalHostView view, boolean statusBarTr } @Override + @ReactProp(name = "accessibilityTitle") + public void setAccessibilityTitle(ReactModalHostView view, String accessibilityTitle) { + view.setAccessibilityTitle(accessibilityTitle); + } + @ReactProp(name = "hardwareAccelerated") public void setHardwareAccelerated(ReactModalHostView view, boolean hardwareAccelerated) { view.setHardwareAccelerated(hardwareAccelerated); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java index 82be75a4377fc9..49265dfd773f93 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java @@ -79,6 +79,7 @@ public interface OnRequestCloseListener { private boolean mTransparent; private boolean mStatusBarTranslucent; private String mAnimationType; + private String mAccessibilityTitle; private boolean mHardwareAccelerated; // Set this flag to true if changing a particular property on the view requires a new Dialog to // be created. For instance, animation does since it affects Dialog creation through the theme @@ -203,6 +204,11 @@ protected void setAnimationType(String animationType) { mPropertyRequiresNewDialog = true; } + protected void setAccessibilityTitle(String accessibilityTitle) { + mAccessibilityTitle = accessibilityTitle; + mPropertyRequiresNewDialog = true; + } + protected void setHardwareAccelerated(boolean hardwareAccelerated) { mHardwareAccelerated = hardwareAccelerated; mPropertyRequiresNewDialog = true; @@ -324,6 +330,10 @@ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (mHardwareAccelerated) { mDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); } + if (mAccessibilityTitle != null) { + mDialog.setTitle(mAccessibilityTitle); + } + if (currentActivity != null && !currentActivity.isFinishing()) { mDialog.show(); if (context instanceof Activity) { From accbbfc01af57eda34374ce3b13e36b6e7c12a93 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Mon, 17 Oct 2022 22:20:46 +0200 Subject: [PATCH 02/24] improve types in java and js - use Stringish instead of string (internal type used in react-native) - add Nullable to Java setAccessibilityTitle, we use setTitle(null) to clear and previous value --- Libraries/Modal/Modal.js | 8 +++++++- Libraries/Modal/RCTModalHostViewNativeComponent.js | 8 +++++++- .../facebook/react/views/modal/ReactModalHostManager.java | 2 +- .../facebook/react/views/modal/ReactModalHostView.java | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index a6e6a860362369..4bb80f1fbd93fd 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -60,6 +60,13 @@ type OrientationChangeEvent = $ReadOnly<{| export type Props = $ReadOnly<{| ...ViewProps, + /** + * The `accessibilityTitle` prop controls the title announced with the TalkBack screen reader. + * + * See https://reactnative.dev/docs/modal# + */ + accessibilityTitle?: ?Stringish, + /** * The `animationType` prop controls how the modal animates. * @@ -94,7 +101,6 @@ export type Props = $ReadOnly<{| * See https://reactnative.dev/docs/modal#transparent */ statusBarTranslucent?: ?boolean, - accessibilityTitle?: ?string, /** * The `hardwareAccelerated` prop controls whether to force hardware diff --git a/Libraries/Modal/RCTModalHostViewNativeComponent.js b/Libraries/Modal/RCTModalHostViewNativeComponent.js index 549388b466c84e..58bae5849c29bb 100644 --- a/Libraries/Modal/RCTModalHostViewNativeComponent.js +++ b/Libraries/Modal/RCTModalHostViewNativeComponent.js @@ -25,6 +25,13 @@ type OrientationChangeEvent = $ReadOnly<{| type NativeProps = $ReadOnly<{| ...ViewProps, + /** + * The `accessibilityTitle` prop controls the title announced with the TalkBack screen reader. + * + * See https://reactnative.dev/docs/modal# + */ + accessibilityTitle?: WithDefault, + /** * The `animationType` prop controls how the modal animates. * @@ -131,7 +138,6 @@ type NativeProps = $ReadOnly<{| * The `identifier` is the unique number for identifying Modal components. */ identifier?: WithDefault, - accessibilityTitle?: WithDefault, |}>; export default (codegenNativeComponent('ModalHostView', { diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java index 5e4f021733294e..8a75afbc202347 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java @@ -88,7 +88,7 @@ public void setStatusBarTranslucent(ReactModalHostView view, boolean statusBarTr @Override @ReactProp(name = "accessibilityTitle") - public void setAccessibilityTitle(ReactModalHostView view, String accessibilityTitle) { + public void setAccessibilityTitle(ReactModalHostView view, @Nullable String accessibilityTitle) { view.setAccessibilityTitle(accessibilityTitle); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java index 49265dfd773f93..e16e23cd9d5023 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java @@ -79,7 +79,7 @@ public interface OnRequestCloseListener { private boolean mTransparent; private boolean mStatusBarTranslucent; private String mAnimationType; - private String mAccessibilityTitle; + private @Nullable String mAccessibilityTitle; private boolean mHardwareAccelerated; // Set this flag to true if changing a particular property on the view requires a new Dialog to // be created. For instance, animation does since it affects Dialog creation through the theme From 17d78273dbfffd68c66cd5bab82f4a68e236c3dc Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Mon, 24 Oct 2022 12:47:44 +0200 Subject: [PATCH 03/24] implementing alternative solution for iOS/Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit changes discussed in https://github.com/facebook/react-native/pull/34969#issuecomment-1281549634 which consist in: - Modal accepts prop TitleComponent which is a React.Element or Component and represents the title of the modal. The solution is taken from ListHeaderComponent in VirtList - AccessibilityInfo.sendAccessibilityEvent is triggered to focus on the Title when the modal opens - sendAccessibilityEvent needs to set a timeout of 1s (see https://github.com/facebook/react-native/issues/30097 and https://stackoverflow.com/questions/28472985/android-set-talkback-accessibility-focus-to-a-specific-view) - TitleComponent Styling and positioning is defined outside of reactnative This has to be reviewed as ListHeaderComponent uses ListHeaderComponentStyle Notes: "Improvements: Trigger focus on components using Fabric API (findNodeHandle is deprecated, setAccessibilityFocus). setAccessibilityFocus has several issues (stackoverflow), and I can not set a ref on a modal. componentDidMount seems to trigger before rendering the Modal children, the lifecycle does not work correctly with a modal on Fabric. You need to use forwardRef to call sendAccessibilityEvent Need to change the way you create the title component so that you create a forwardRef and then use this to send the accessibility event" "https://reactnative.dev/docs/new-architecture-library-intro#preparing-your-javascript-codebase-for-the-new-react-native-renderer-fabric https://reactnative.dev/docs/accessibilityinfo#setaccessibilityfocus https://reactnative.dev/docs/new-architecture-library-intro#preparing-your-javascript-codebase-for-the-new-react-native-renderer-fabric" "Test Text component solution without using getNativeRef, as the problem could be caused by timeout and not ref. Check the keys and try to use the _nativeRef Implement getNativeRef for the Text component and use it in Modal to call setAccessibilityFocus" https://github.com/fabriziobertoglio1987/react-native/blob/accbbfc01af57eda34374ce3b13e36b6e7c12a93/Libraries/Components/TextInput/TextInput.js#L1213 "Adding setTimeout with a wait of 1-second fixes issues with setAccessibilityFocus does not onLoad The reason is triggered focus on other elements, so we need to use an API to wait for the focus to display on that element Try to use runAfterInteraction" "https://github.com/facebook/react-native/issues/30097 https://reactnative.dev/docs/next/interactionmanager#runafterinteractions" "Review meeting notes and Brett suggestion Consider removing the sendAccessibilityEvent as violates WCAG 2.0 regulations, including 3.2.1 and 3.2.3" Test Android "- The title component displays under the Modal on Android. The title receives focus with the ModalPresentation example. The title does not receive focus in the ModalOnShow example. => In both examples, the titles displays under the modal => In ModalOnShow, the title does not receive focus Apply the same prop as in the ModalPresentation and see if the title receives focus Remove style Put the title directly in the ModalOnShow and trigger the focus Trigger the focus manually with a button instead of using useEffect( _ref ) Trigger focus manually with a button in the Modal.js" "setAccessibilityFocus correctly moves the focus when triggered with Button. The issue could be caused: ref is undefined read conversation #30097 alternative callback to _showModal (onLoad) TalkBack moves focus after calling sendAccessibilityEvent => increase timeout" https://github.com/facebook/react-native/issues/30097 "Test functionality on iOS: test functionality on iOS with Xcode build" "Improve solution and finalize diff before final commit: Fix issue with sendAccessibilityEvent based on stackoverflow solution or runAfterIteraction (setAccessibilityFocus does not onLoad) TitleComponent should move to rn-tester ModalPresentation and ModalOnShow
forwardRef may not work" "https://github.com/fabriziobertoglio1987/react-native/blob/accbbfc01af57eda34374ce3b13e36b6e7c12a93/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java#L968 https://stackoverflow.com/questions/28472985/android-set-talkback-accessibility-focus-to-a-specific-view https://github.com/facebook/react-native/issues/30097" --- Libraries/Modal/Modal.js | 25 ++++++++++++++++--- .../Modal/RCTModalHostViewNativeComponent.js | 7 ------ .../mounting/SurfaceMountingManager.java | 16 +++++++++++- .../views/modal/ReactModalHostManager.java | 6 ----- .../react/views/modal/ReactModalHostView.java | 9 ------- .../js/examples/Modal/ModalPresentation.js | 17 +++++++++++++ 6 files changed, 53 insertions(+), 27 deletions(-) diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index 4bb80f1fbd93fd..6c19116b9b87a5 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -18,6 +18,7 @@ import {type EventSubscription} from '../vendor/emitter/EventEmitter'; import ModalInjection from './ModalInjection'; import NativeModalManager from './NativeModalManager'; import RCTModalHostView from './RCTModalHostViewNativeComponent'; +import AccessibilityInfo from '../Components/AccessibilityInfo/AccessibilityInfo'; const ScrollView = require('../Components/ScrollView/ScrollView'); const View = require('../Components/View/View'); @@ -61,14 +62,15 @@ export type Props = $ReadOnly<{| ...ViewProps, /** - * The `accessibilityTitle` prop controls the title announced with the TalkBack screen reader. + * The `TitleComponent` represents the title of the Modal. + * The title is announced with TalkBack/VoiceOver screenreaders. * * See https://reactnative.dev/docs/modal# */ - accessibilityTitle?: ?Stringish, + TitleComponent?: ?(React.ComponentType | React.Element), /** - * The `animationType` prop controls how the modal animates. + The `animationType` prop controls how the modal animates. * * See https://reactnative.dev/docs/modal#animationtype */ @@ -213,6 +215,13 @@ class Modal extends React.Component { } } + _captureRef = ref => { + if (ref) { + this._ref = ref; + AccessibilityInfo.sendAccessibilityEvent(ref, 'focus'); + } + }; + componentWillUnmount() { if (this._eventSubscription) { this._eventSubscription.remove(); @@ -226,6 +235,14 @@ class Modal extends React.Component { } render(): React.Node { + const {TitleComponent} = this.props; + const element = React.isValidElement(TitleComponent) ? ( + TitleComponent + ) : ( + // $FlowFixMe[not-a-component] + // $FlowFixMe[incompatible-type-arg] + + ); if (this.props.visible !== true) { return null; } @@ -271,7 +288,6 @@ class Modal extends React.Component { // $FlowFixMe[method-unbinding] added when improving typing for this parameters onStartShouldSetResponder={this._shouldSetResponder} supportedOrientations={this.props.supportedOrientations} - accessibilityTitle={this.props.accessibilityTitle} onOrientationChange={this.props.onOrientationChange} testID={this.props.testID}> @@ -280,6 +296,7 @@ class Modal extends React.Component { style={[styles.container, containerStyles]} collapsable={false}> {innerChildren} + diff --git a/Libraries/Modal/RCTModalHostViewNativeComponent.js b/Libraries/Modal/RCTModalHostViewNativeComponent.js index 58bae5849c29bb..a21af54ae4fe72 100644 --- a/Libraries/Modal/RCTModalHostViewNativeComponent.js +++ b/Libraries/Modal/RCTModalHostViewNativeComponent.js @@ -25,13 +25,6 @@ type OrientationChangeEvent = $ReadOnly<{| type NativeProps = $ReadOnly<{| ...ViewProps, - /** - * The `accessibilityTitle` prop controls the title announced with the TalkBack screen reader. - * - * See https://reactnative.dev/docs/modal# - */ - accessibilityTitle?: WithDefault, - /** * The `animationType` prop controls how the modal animates. * diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java index 90096f4ada13b2..eb629379b2e445 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java @@ -57,6 +57,9 @@ import java.util.Stack; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; public class SurfaceMountingManager { @@ -963,7 +966,18 @@ public void sendAccessibilityEvent(int reactTag, int eventType) { "Unable to find viewState view for tag " + reactTag); } - viewState.mView.sendAccessibilityEvent(eventType); + Runnable task = + new Runnable() { + + @Override + public void run() { + viewState.mView.sendAccessibilityEvent(eventType); + } + }; + + final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor(); + + worker.schedule(task, 1000, TimeUnit.MILLISECONDS); } @UiThread diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java index 8a75afbc202347..3001eeb2f29e69 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java @@ -86,12 +86,6 @@ public void setStatusBarTranslucent(ReactModalHostView view, boolean statusBarTr view.setStatusBarTranslucent(statusBarTranslucent); } - @Override - @ReactProp(name = "accessibilityTitle") - public void setAccessibilityTitle(ReactModalHostView view, @Nullable String accessibilityTitle) { - view.setAccessibilityTitle(accessibilityTitle); - } - @ReactProp(name = "hardwareAccelerated") public void setHardwareAccelerated(ReactModalHostView view, boolean hardwareAccelerated) { view.setHardwareAccelerated(hardwareAccelerated); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java index e16e23cd9d5023..73608abe2494fb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java @@ -79,7 +79,6 @@ public interface OnRequestCloseListener { private boolean mTransparent; private boolean mStatusBarTranslucent; private String mAnimationType; - private @Nullable String mAccessibilityTitle; private boolean mHardwareAccelerated; // Set this flag to true if changing a particular property on the view requires a new Dialog to // be created. For instance, animation does since it affects Dialog creation through the theme @@ -204,11 +203,6 @@ protected void setAnimationType(String animationType) { mPropertyRequiresNewDialog = true; } - protected void setAccessibilityTitle(String accessibilityTitle) { - mAccessibilityTitle = accessibilityTitle; - mPropertyRequiresNewDialog = true; - } - protected void setHardwareAccelerated(boolean hardwareAccelerated) { mHardwareAccelerated = hardwareAccelerated; mPropertyRequiresNewDialog = true; @@ -330,9 +324,6 @@ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (mHardwareAccelerated) { mDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); } - if (mAccessibilityTitle != null) { - mDialog.setTitle(mAccessibilityTitle); - } if (currentActivity != null && !currentActivity.isFinishing()) { mDialog.show(); diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index b2b2aab6bb67e3..f85a7f9f0446e8 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -55,6 +55,22 @@ function ModalPresentation() { } }; + const TitleComponent = React.forwardRef((props, forwardedRef) => { + return ( + + My custom title + + ); + }); const onShow = () => { if (action === 'onShow') { alert('onShow'); @@ -76,6 +92,7 @@ function ModalPresentation() { Show Modal Date: Tue, 25 Oct 2022 16:26:15 +0200 Subject: [PATCH 04/24] moving Title logic to modal rn-tester example --- Libraries/Modal/Modal.js | 24 --------------- .../mounting/SurfaceMountingManager.java | 16 +--------- .../views/modal/ReactModalHostManager.java | 1 + .../react/views/modal/ReactModalHostView.java | 1 - .../js/examples/Modal/ModalPresentation.js | 30 +++++++++++++++++-- 5 files changed, 30 insertions(+), 42 deletions(-) diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index 6c19116b9b87a5..9f1ee8cad5b9dd 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -61,14 +61,6 @@ type OrientationChangeEvent = $ReadOnly<{| export type Props = $ReadOnly<{| ...ViewProps, - /** - * The `TitleComponent` represents the title of the Modal. - * The title is announced with TalkBack/VoiceOver screenreaders. - * - * See https://reactnative.dev/docs/modal# - */ - TitleComponent?: ?(React.ComponentType | React.Element), - /** The `animationType` prop controls how the modal animates. * @@ -215,13 +207,6 @@ class Modal extends React.Component { } } - _captureRef = ref => { - if (ref) { - this._ref = ref; - AccessibilityInfo.sendAccessibilityEvent(ref, 'focus'); - } - }; - componentWillUnmount() { if (this._eventSubscription) { this._eventSubscription.remove(); @@ -235,14 +220,6 @@ class Modal extends React.Component { } render(): React.Node { - const {TitleComponent} = this.props; - const element = React.isValidElement(TitleComponent) ? ( - TitleComponent - ) : ( - // $FlowFixMe[not-a-component] - // $FlowFixMe[incompatible-type-arg] - - ); if (this.props.visible !== true) { return null; } @@ -296,7 +273,6 @@ class Modal extends React.Component { style={[styles.container, containerStyles]} collapsable={false}> {innerChildren} - diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java index 6c67a9d195bd03..804a77ade78c1d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java @@ -57,9 +57,6 @@ import java.util.Stack; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; public class SurfaceMountingManager { @@ -951,18 +948,7 @@ public void sendAccessibilityEvent(int reactTag, int eventType) { "Unable to find viewState view for tag " + reactTag); } - Runnable task = - new Runnable() { - - @Override - public void run() { - viewState.mView.sendAccessibilityEvent(eventType); - } - }; - - final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor(); - - worker.schedule(task, 1000, TimeUnit.MILLISECONDS); + viewState.mView.sendAccessibilityEvent(eventType); } @UiThread diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java index 3001eeb2f29e69..15ce94cb0ad66c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java @@ -86,6 +86,7 @@ public void setStatusBarTranslucent(ReactModalHostView view, boolean statusBarTr view.setStatusBarTranslucent(statusBarTranslucent); } + @Override @ReactProp(name = "hardwareAccelerated") public void setHardwareAccelerated(ReactModalHostView view, boolean hardwareAccelerated) { view.setHardwareAccelerated(hardwareAccelerated); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java index 73608abe2494fb..82be75a4377fc9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java @@ -324,7 +324,6 @@ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (mHardwareAccelerated) { mDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); } - if (currentActivity != null && !currentActivity.isFinishing()) { mDialog.show(); if (context instanceof Activity) { diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index f85a7f9f0446e8..05b2557c6a7dc9 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -11,7 +11,16 @@ /* eslint-disable no-alert */ import * as React from 'react'; -import {Modal, Platform, StyleSheet, Switch, Text, View} from 'react-native'; +import { + NativeMethods, + AccessibilityInfo, + Modal, + Platform, + StyleSheet, + Switch, + Text, + View, +} from 'react-native'; import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; import RNTOption from '../../components/RNTOption'; const RNTesterButton = require('../../components/RNTesterButton'); @@ -47,6 +56,7 @@ function ModalPresentation() { React.useState('Portrait'); const [currentOrientation, setCurrentOrientation] = React.useState('unknown'); const [action, setAction] = React.useState('None'); + const ref = React.useRef(null); const actions = Platform.OS === 'ios' ? iOSActions : noniOSActions; const onDismiss = () => { setVisible(false); @@ -71,11 +81,27 @@ function ModalPresentation() { ); }); + const onShow = () => { if (action === 'onShow') { alert('onShow'); } }; + + const _captureRef = (ref: NativeMethods | null) => { + if (ref != null) { + this._ref = ref; + setTimeout( + (AccessibilityInfo, ref) => { + AccessibilityInfo.sendAccessibilityEvent(ref, 'focus'); + }, + 1000, + AccessibilityInfo, + ref, + ); + } + }; + /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's * LTI update could not be added via codemod */ const onOrientationChange = event => @@ -92,7 +118,6 @@ function ModalPresentation() { Show Modal + {TitleComponent != null && } Date: Tue, 25 Oct 2022 16:35:19 +0200 Subject: [PATCH 05/24] removing changes from Modal --- Libraries/Modal/Modal.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index 9f1ee8cad5b9dd..b41ec143d633d3 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -18,7 +18,6 @@ import {type EventSubscription} from '../vendor/emitter/EventEmitter'; import ModalInjection from './ModalInjection'; import NativeModalManager from './NativeModalManager'; import RCTModalHostView from './RCTModalHostViewNativeComponent'; -import AccessibilityInfo from '../Components/AccessibilityInfo/AccessibilityInfo'; const ScrollView = require('../Components/ScrollView/ScrollView'); const View = require('../Components/View/View'); @@ -62,7 +61,7 @@ export type Props = $ReadOnly<{| ...ViewProps, /** - The `animationType` prop controls how the modal animates. + * The `animationType` prop controls how the modal animates. * * See https://reactnative.dev/docs/modal#animationtype */ From 98b4a944c871313a92de6ee03ec7e3624a19ecb7 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Tue, 25 Oct 2022 17:00:50 +0200 Subject: [PATCH 06/24] fix issues with sendAccessibilityEvent --- .../js/examples/Modal/ModalPresentation.js | 57 +++++++++++-------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 05b2557c6a7dc9..61edfa5df161f5 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -44,6 +44,23 @@ const presentationStyles = [ const iOSActions = ['None', 'On Dismiss', 'On Show']; const noniOSActions = ['None', 'On Show']; +const TitleComponent = React.forwardRef((props, forwardedRef) => { + return ( + + My custom title + + ); +}); + function ModalPresentation() { const [animationType, setAnimationType] = React.useState('none'); const [transparent, setTransparent] = React.useState(false); @@ -56,8 +73,9 @@ function ModalPresentation() { React.useState('Portrait'); const [currentOrientation, setCurrentOrientation] = React.useState('unknown'); const [action, setAction] = React.useState('None'); - const ref = React.useRef(null); + let ref = React.useRef(null); const actions = Platform.OS === 'ios' ? iOSActions : noniOSActions; + let accessibilityEventTimeout; const onDismiss = () => { setVisible(false); if (action === 'onDismiss') { @@ -65,43 +83,32 @@ function ModalPresentation() { } }; - const TitleComponent = React.forwardRef((props, forwardedRef) => { - return ( - - My custom title - - ); - }); - const onShow = () => { if (action === 'onShow') { alert('onShow'); } }; - const _captureRef = (ref: NativeMethods | null) => { + const _captureRef = (localRef: NativeMethods | null) => { if (ref != null) { - this._ref = ref; - setTimeout( - (AccessibilityInfo, ref) => { - AccessibilityInfo.sendAccessibilityEvent(ref, 'focus'); + ref = localRef; + accessibilityEventTimeout = setTimeout( + (AI, elementRef) => { + AI.sendAccessibilityEvent(elementRef, 'focus'); }, 1000, AccessibilityInfo, - ref, + localRef, ); } }; + React.useEffect(() => { + if (accessibilityEventTimeout) { + clearTimeout(accessibilityEventTimeout); + } + }, []); + /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's * LTI update could not be added via codemod */ const onOrientationChange = event => @@ -129,7 +136,7 @@ function ModalPresentation() { onOrientationChange={onOrientationChange} onDismiss={onDismiss} onShow={onShow}> - {TitleComponent != null && } + {TitleComponent != null && } Date: Tue, 25 Oct 2022 17:31:21 +0200 Subject: [PATCH 07/24] refactor useTimer with useEffect --- .../js/examples/Modal/ModalPresentation.js | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 61edfa5df161f5..07305ff7930e69 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -71,6 +71,7 @@ function ModalPresentation() { React.useState('fullScreen'); const [supportedOrientationKey, setSupportedOrientationKey] = React.useState('Portrait'); + const [modalOpened, setModalOpened] = React.useState(null); const [currentOrientation, setCurrentOrientation] = React.useState('unknown'); const [action, setAction] = React.useState('None'); let ref = React.useRef(null); @@ -78,6 +79,7 @@ function ModalPresentation() { let accessibilityEventTimeout; const onDismiss = () => { setVisible(false); + setModalOpened(false); if (action === 'onDismiss') { alert('onDismiss'); } @@ -87,27 +89,34 @@ function ModalPresentation() { if (action === 'onShow') { alert('onShow'); } + if (ref != null) { + setModalOpened(true); + } }; const _captureRef = (localRef: NativeMethods | null) => { if (ref != null) { ref = localRef; - accessibilityEventTimeout = setTimeout( + } + }; + + React.useEffect(() => { + let timer; + if (ref != null && modalOpened) { + timer = setTimeout( (AI, elementRef) => { AI.sendAccessibilityEvent(elementRef, 'focus'); }, 1000, AccessibilityInfo, - localRef, + ref, ); } - }; - React.useEffect(() => { - if (accessibilityEventTimeout) { - clearTimeout(accessibilityEventTimeout); - } - }, []); + return () => { + if (timer) clearTimeout(timer); + }; + }, [modalOpened]); /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's * LTI update could not be added via codemod */ From 4213491e25f67377f3d6146273783ad84fb3144d Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Tue, 25 Oct 2022 17:40:20 +0200 Subject: [PATCH 08/24] minor fix to example --- packages/rn-tester/js/examples/Modal/ModalPresentation.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 07305ff7930e69..02d8b5389ba347 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -76,7 +76,6 @@ function ModalPresentation() { const [action, setAction] = React.useState('None'); let ref = React.useRef(null); const actions = Platform.OS === 'ios' ? iOSActions : noniOSActions; - let accessibilityEventTimeout; const onDismiss = () => { setVisible(false); setModalOpened(false); @@ -114,7 +113,9 @@ function ModalPresentation() { } return () => { - if (timer) clearTimeout(timer); + if (timer) { + clearTimeout(timer); + } }; }, [modalOpened]); From f89a01ff48d4c42d895797b3ee49b76f2957a857 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Wed, 26 Oct 2022 11:34:44 +0200 Subject: [PATCH 09/24] fix ref flow type in example --- .../js/examples/Modal/ModalPresentation.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 02d8b5389ba347..d1c0e9880b08dd 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -4,15 +4,15 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict-local + * @flow * @format */ /* eslint-disable no-alert */ import * as React from 'react'; +import type {ElementRef} from 'react'; import { - NativeMethods, AccessibilityInfo, Modal, Platform, @@ -21,6 +21,7 @@ import { Text, View, } from 'react-native'; +import type {HostComponent} from 'react-native'; import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; import RNTOption from '../../components/RNTOption'; const RNTesterButton = require('../../components/RNTesterButton'); @@ -74,7 +75,7 @@ function ModalPresentation() { const [modalOpened, setModalOpened] = React.useState(null); const [currentOrientation, setCurrentOrientation] = React.useState('unknown'); const [action, setAction] = React.useState('None'); - let ref = React.useRef(null); + let ref = React.useRef>(null); const actions = Platform.OS === 'ios' ? iOSActions : noniOSActions; const onDismiss = () => { setVisible(false); @@ -93,18 +94,20 @@ function ModalPresentation() { } }; - const _captureRef = (localRef: NativeMethods | null) => { - if (ref != null) { + const _captureRef = (localRef: typeof ref) => { + if (ref != null && localRef != null) { ref = localRef; } }; React.useEffect(() => { let timer; - if (ref != null && modalOpened) { + if (ref != null && ref.current != null && modalOpened === true) { timer = setTimeout( (AI, elementRef) => { - AI.sendAccessibilityEvent(elementRef, 'focus'); + if (elementRef != null && elementRef.current != null) { + AI.sendAccessibilityEvent(elementRef.current, 'focus'); + } }, 1000, AccessibilityInfo, @@ -146,7 +149,7 @@ function ModalPresentation() { onOrientationChange={onOrientationChange} onDismiss={onDismiss} onShow={onShow}> - {TitleComponent != null && } + {TitleComponent != null && } Date: Wed, 26 Oct 2022 12:40:49 +0200 Subject: [PATCH 10/24] eslint fix check --- .../rn-tester/js/examples/Modal/ModalPresentation.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index d1c0e9880b08dd..2e838b25599721 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -11,7 +11,6 @@ /* eslint-disable no-alert */ import * as React from 'react'; -import type {ElementRef} from 'react'; import { AccessibilityInfo, Modal, @@ -21,8 +20,6 @@ import { Text, View, } from 'react-native'; -import type {HostComponent} from 'react-native'; -import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; import RNTOption from '../../components/RNTOption'; const RNTesterButton = require('../../components/RNTesterButton'); @@ -94,12 +91,6 @@ function ModalPresentation() { } }; - const _captureRef = (localRef: typeof ref) => { - if (ref != null && localRef != null) { - ref = localRef; - } - }; - React.useEffect(() => { let timer; if (ref != null && ref.current != null && modalOpened === true) { From 129d152e7ffb5b1075eca63bcfa1e26b1778b30b Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Wed, 26 Oct 2022 12:50:54 +0200 Subject: [PATCH 11/24] minor change --- packages/rn-tester/js/examples/Modal/ModalPresentation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 2e838b25599721..268d77913aa2b2 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -93,10 +93,10 @@ function ModalPresentation() { React.useEffect(() => { let timer; - if (ref != null && ref.current != null && modalOpened === true) { + if (ref != null && modalOpened === true) { timer = setTimeout( (AI, elementRef) => { - if (elementRef != null && elementRef.current != null) { + if (elementRef.current != null) { AI.sendAccessibilityEvent(elementRef.current, 'focus'); } }, From 8a25a6fda7a99edeace892402e59100b7f7289af Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Wed, 26 Oct 2022 14:30:21 +0200 Subject: [PATCH 12/24] minor change --- build.gradle.kts | 2 +- packages/rn-tester/js/examples/Modal/ModalPresentation.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9d7ebb8e964aa1..f70907493b49d2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ plugins { id("io.github.gradle-nexus.publish-plugin") version "1.1.0" } val reactAndroidProperties = java.util.Properties() -File("./ReactAndroid/gradle.properties").inputStream().use { reactAndroidProperties.load(it) } +File("$rootDir/ReactAndroid/gradle.properties").inputStream().use { reactAndroidProperties.load(it) } version = if (project.hasProperty("isNightly") && diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 268d77913aa2b2..b49eba70aa5c00 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -20,6 +20,7 @@ import { Text, View, } from 'react-native'; +import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; import RNTOption from '../../components/RNTOption'; const RNTesterButton = require('../../components/RNTesterButton'); From dbd01c61046c73a95d06dc04c9893ca0cb5a7a6e Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Wed, 26 Oct 2022 14:32:46 +0200 Subject: [PATCH 13/24] minor change --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index f70907493b49d2..9d7ebb8e964aa1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ plugins { id("io.github.gradle-nexus.publish-plugin") version "1.1.0" } val reactAndroidProperties = java.util.Properties() -File("$rootDir/ReactAndroid/gradle.properties").inputStream().use { reactAndroidProperties.load(it) } +File("./ReactAndroid/gradle.properties").inputStream().use { reactAndroidProperties.load(it) } version = if (project.hasProperty("isNightly") && From 3c0f53194ed6fe5c8874a6f92978d8805a17b403 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Wed, 26 Oct 2022 14:41:05 +0200 Subject: [PATCH 14/24] avoid passing vars to setTimeout --- .../js/examples/Modal/ModalPresentation.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index b49eba70aa5c00..d69d9ec910ec83 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -95,16 +95,11 @@ function ModalPresentation() { React.useEffect(() => { let timer; if (ref != null && modalOpened === true) { - timer = setTimeout( - (AI, elementRef) => { - if (elementRef.current != null) { - AI.sendAccessibilityEvent(elementRef.current, 'focus'); - } - }, - 1000, - AccessibilityInfo, - ref, - ); + timer = setTimeout(() => { + if (ref.current != null) { + AccessibilityInfo.sendAccessibilityEvent(ref.current, 'focus'); + } + }, 1000); } return () => { From 43e2ffa317dbdac93f300989bea44d1450fd2e48 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Fri, 18 Nov 2022 17:18:56 +0100 Subject: [PATCH 15/24] remove sendAccessibilityEvent setTimeout as not required on iOS iOS does not have issues with sendAccessibilityEvent (https://github.com/facebook/react-native/issues/30097#issuecomment-1285927266), for this reason setTimeout is not required test on iOS https://www.icloud.com/iclouddrive/00cgfwQLkaoFQHvxh-Dj89zUA#ios_modal_title --- .../js/examples/Modal/ModalPresentation.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index d69d9ec910ec83..44b9cf2cd4ca98 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -95,11 +95,16 @@ function ModalPresentation() { React.useEffect(() => { let timer; if (ref != null && modalOpened === true) { - timer = setTimeout(() => { - if (ref.current != null) { - AccessibilityInfo.sendAccessibilityEvent(ref.current, 'focus'); - } - }, 1000); + if (Platform.OS === 'ios') { + AccessibilityInfo.sendAccessibilityEvent(ref.current, 'focus'); + } else { + // see https://github.com/facebook/react-native/issues/30097#issuecomment-1285927266 + timer = setTimeout(() => { + if (ref.current != null) { + AccessibilityInfo.sendAccessibilityEvent(ref.current, 'focus'); + } + }, 1000); + } } return () => { From 8f2e0f00ad9e7db302c246bbc0d509507043975a Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Fri, 18 Nov 2022 17:41:37 +0100 Subject: [PATCH 16/24] adding flowfixme --- packages/rn-tester/js/examples/Modal/ModalPresentation.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 44b9cf2cd4ca98..6e99514fb634cd 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -96,6 +96,7 @@ function ModalPresentation() { let timer; if (ref != null && modalOpened === true) { if (Platform.OS === 'ios') { + // $FlowFixMe AccessibilityInfo.sendAccessibilityEvent(ref.current, 'focus'); } else { // see https://github.com/facebook/react-native/issues/30097#issuecomment-1285927266 From 3126e49a9209c46971919bf49d68ed0a2e9c8d56 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Mon, 28 Nov 2022 18:53:34 +0100 Subject: [PATCH 17/24] Add viewHoverEnter to sendAccessibilityEventFromJS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED)Replace setTimeout with sendAccessibilityEvent eventID 32App fails with runtime facebook::jni::JniException: java.lang.IllegalArgumentException: sendAccessibilityEventFromJS: invalid eventType 32' -- Trigger sendAccessibilityEvent TYPE_WINDOW_STATE_CHANGED in Java.Calling sendAccessibilityEvent(ref.current, ’windowDidChange’) does not fix the issue. The method calls MountingManager.sendAccessibilityEvent which triggers sendAccessibilityEvent on the instance of ReactTextView.The method is triggered in SurfaceMountingManager sendAccessibilityEvent, which retrieves the ReactTextView using ref.current Read stackoverflow discussion Try to use ViewHoverEnter Add viewHoverEnter to sendAccessibilityEventFromJS (android docs) "Test [sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED)](https://github.com/facebook/react-native/pull/34969#discussion_r1030806866) Replace [setTimeout](https://github.com/fabriziobertoglio1987/react-native/blob/8f2e0f00ad9e7db302c246bbc0d509507043975a/packages/rn-tester/js/examples/Modal/ModalPresentation.js#L103) with [sendAccessibilityEvent](https://github.com/fabriziobertoglio1987/react-native/blob/8f2e0f00ad9e7db302c246bbc0d509507043975a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js#L359) eventID [32](https://developer.android.com/reference/android/view/accessibility/AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED)
App fails with runtime facebook::jni::JniException: java.lang.IllegalArgumentException: sendAccessibilityEventFromJS: invalid eventType 32'" "Trigger sendAccessibilityEvent TYPE_WINDOW_STATE_CHANGED in Java.
Calling sendAccessibilityEvent(ref.current, ’windowDidChange’) does not fix the issue. The method calls [MountingManager.sendAccessibilityEvent](https://github.com/fabriziobertoglio1987/react-native/blob/8f2e0f00ad9e7db302c246bbc0d509507043975a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java#L293-L301) which triggers sendAccessibilityEvent on the instance of ReactTextView. The method is triggered in SurfaceMountingManager [sendAccessibilityEvent](https://github.com/fabriziobertoglio1987/react-native/blob/8f2e0f00ad9e7db302c246bbc0d509507043975a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java#L934-L952), which retrieves the ReactTextView using ref.current " Read [stackoverflow](https://stackoverflow.com/questions/28472985/android-set-talkback-accessibility-focus-to-a-specific-view/28481095#28481095) discussion Try to use [ViewHoverEnter](https://github.com/xamarin/xamarin-android/issues/4322) Add viewHoverEnter to [sendAccessibilityEventFromJS](https://github.com/fabriziobertoglio1987/react-native/blob/8f2e0f00ad9e7db302c246bbc0d509507043975a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java#L1083) ([android docs](https://developer.android.com/reference/android/view/accessibility/AccessibilityEvent#TYPE_VIEW_HOVER_ENTER)) --- .../AccessibilityInfo/AccessibilityInfo.d.ts | 2 +- .../AccessibilityInfo/AccessibilityInfo.flow.js | 2 +- .../facebook/react/fabric/FabricUIManager.java | 2 ++ .../js/examples/Modal/ModalPresentation.js | 17 +++-------------- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts index 749d44e36717d0..8f0a23e080b185 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts @@ -37,7 +37,7 @@ type AccessibilityAnnouncementFinishedEventHandler = ( event: AccessibilityAnnouncementFinishedEvent, ) => void; -type AccessibilityEventTypes = 'click' | 'focus'; +type AccessibilityEventTypes = 'click' | 'focus' | 'viewHoverEnter'; /** * @see https://reactnative.dev/docs/accessibilityinfo diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js index b40fd0230eefe2..076ee3e2b859e4 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js @@ -34,7 +34,7 @@ type AccessibilityEventDefinitions = { screenReaderChanged: [boolean], }; -type AccessibilityEventTypes = 'click' | 'focus'; +type AccessibilityEventTypes = 'click' | 'focus' | 'viewHoverEnter'; /** * Sometimes it's useful to know whether or not the device has a screen reader * that is currently active. The `AccessibilityInfo` API is designed for this diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index e0947264fd959a..4f00fb3bd25003 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -1088,6 +1088,8 @@ public void sendAccessibilityEventFromJS(int surfaceId, int reactTag, String eve eventType = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; } else if ("click".equals(eventTypeJS)) { eventType = AccessibilityEvent.TYPE_VIEW_CLICKED; + } else if ("viewHoverEnter".equals(eventTypeJS)) { + eventType = AccessibilityEvent.TYPE_VIEW_HOVER_ENTER; } else { throw new IllegalArgumentException( "sendAccessibilityEventFromJS: invalid eventType " + eventTypeJS); diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 6e99514fb634cd..e62603e9cffe83 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -93,26 +93,15 @@ function ModalPresentation() { }; React.useEffect(() => { - let timer; if (ref != null && modalOpened === true) { if (Platform.OS === 'ios') { // $FlowFixMe AccessibilityInfo.sendAccessibilityEvent(ref.current, 'focus'); } else { - // see https://github.com/facebook/react-native/issues/30097#issuecomment-1285927266 - timer = setTimeout(() => { - if (ref.current != null) { - AccessibilityInfo.sendAccessibilityEvent(ref.current, 'focus'); - } - }, 1000); + // $FlowFixMe + AccessibilityInfo.sendAccessibilityEvent(ref.current, 'viewHoverEnter'); } } - - return () => { - if (timer) { - clearTimeout(timer); - } - }; }, [modalOpened]); /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's @@ -142,7 +131,7 @@ function ModalPresentation() { onOrientationChange={onOrientationChange} onDismiss={onDismiss} onShow={onShow}> - {TitleComponent != null && } + Date: Mon, 28 Nov 2022 18:59:34 +0100 Subject: [PATCH 18/24] remove state modalOpened --- .../rn-tester/js/examples/Modal/ModalPresentation.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index e62603e9cffe83..eb0bcc20badf95 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -87,13 +87,7 @@ function ModalPresentation() { if (action === 'onShow') { alert('onShow'); } - if (ref != null) { - setModalOpened(true); - } - }; - - React.useEffect(() => { - if (ref != null && modalOpened === true) { + if (ref != null && visible === true) { if (Platform.OS === 'ios') { // $FlowFixMe AccessibilityInfo.sendAccessibilityEvent(ref.current, 'focus'); @@ -102,7 +96,7 @@ function ModalPresentation() { AccessibilityInfo.sendAccessibilityEvent(ref.current, 'viewHoverEnter'); } } - }, [modalOpened]); + }; /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's * LTI update could not be added via codemod */ From 4cf1605e1abd72f7e521e13a0bee291c35cf2a4a Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Mon, 28 Nov 2022 19:01:35 +0100 Subject: [PATCH 19/24] remove state modalOpened --- packages/rn-tester/js/examples/Modal/ModalPresentation.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index eb0bcc20badf95..26ee5c126c47d0 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -70,14 +70,12 @@ function ModalPresentation() { React.useState('fullScreen'); const [supportedOrientationKey, setSupportedOrientationKey] = React.useState('Portrait'); - const [modalOpened, setModalOpened] = React.useState(null); const [currentOrientation, setCurrentOrientation] = React.useState('unknown'); const [action, setAction] = React.useState('None'); let ref = React.useRef>(null); const actions = Platform.OS === 'ios' ? iOSActions : noniOSActions; const onDismiss = () => { setVisible(false); - setModalOpened(false); if (action === 'onDismiss') { alert('onDismiss'); } From e7f0023b9fca4270b683513ef4b943c3206ba4f7 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Mon, 28 Nov 2022 19:32:12 +0100 Subject: [PATCH 20/24] adding viewHoverInfo to AccessiblityInfo --- Libraries/Components/AccessibilityInfo/AccessibilityInfo.js | 2 +- packages/rn-tester/js/examples/Modal/ModalPresentation.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js index 195fe7476367a3..20d9192968a1b4 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js @@ -42,7 +42,7 @@ type AccessibilityEventDefinitions = { screenReaderChanged: [boolean], }; -type AccessibilityEventTypes = 'click' | 'focus'; +type AccessibilityEventTypes = 'click' | 'focus' | 'viewHoverEnter'; // Mapping of public event names to platform-specific event names. const EventNames: Map< diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 26ee5c126c47d0..11651b9b4bfffd 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -85,11 +85,12 @@ function ModalPresentation() { if (action === 'onShow') { alert('onShow'); } - if (ref != null && visible === true) { + if (ref != null && ref.current != null && visible === true) { if (Platform.OS === 'ios') { // $FlowFixMe AccessibilityInfo.sendAccessibilityEvent(ref.current, 'focus'); } else { + // see https://github.com/facebook/react-native/issues/30097#issuecomment-1285927266 // $FlowFixMe AccessibilityInfo.sendAccessibilityEvent(ref.current, 'viewHoverEnter'); } From fd152d2c27e6401717227dba1b68f6ecbbe9efed Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Mon, 28 Nov 2022 21:42:03 +0100 Subject: [PATCH 21/24] minor change --- .../rn-tester/js/examples/Modal/ModalPresentation.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 11651b9b4bfffd..ab68e37e619b21 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -86,14 +86,10 @@ function ModalPresentation() { alert('onShow'); } if (ref != null && ref.current != null && visible === true) { - if (Platform.OS === 'ios') { - // $FlowFixMe - AccessibilityInfo.sendAccessibilityEvent(ref.current, 'focus'); - } else { - // see https://github.com/facebook/react-native/issues/30097#issuecomment-1285927266 - // $FlowFixMe - AccessibilityInfo.sendAccessibilityEvent(ref.current, 'viewHoverEnter'); - } + // see https://github.com/facebook/react-native/issues/30097#issuecomment-1285927266 + const focusEvent = Platform.OS === 'ios' ? 'focus' : 'viewHoverEnter'; + // $FlowFixMe + AccessibilityInfo.sendAccessibilityEvent(ref.current, focusEvent); } }; From bf37a34c38b39a14de8194520d07de0b9f8c0bf7 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Mon, 28 Nov 2022 22:05:52 +0100 Subject: [PATCH 22/24] using correct flow type --- packages/rn-tester/js/examples/Modal/ModalPresentation.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index ab68e37e619b21..78e0dec7e7f168 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -72,7 +72,7 @@ function ModalPresentation() { React.useState('Portrait'); const [currentOrientation, setCurrentOrientation] = React.useState('unknown'); const [action, setAction] = React.useState('None'); - let ref = React.useRef>(null); + let ref = React.useRef>(null); const actions = Platform.OS === 'ios' ? iOSActions : noniOSActions; const onDismiss = () => { setVisible(false); @@ -88,7 +88,6 @@ function ModalPresentation() { if (ref != null && ref.current != null && visible === true) { // see https://github.com/facebook/react-native/issues/30097#issuecomment-1285927266 const focusEvent = Platform.OS === 'ios' ? 'focus' : 'viewHoverEnter'; - // $FlowFixMe AccessibilityInfo.sendAccessibilityEvent(ref.current, focusEvent); } }; From dc4c54ec1b7b7f7cd37c7402b1eac5292cb4996a Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Tue, 29 Nov 2022 11:45:29 +0100 Subject: [PATCH 23/24] remove example --- .../js/examples/Modal/ModalPresentation.js | 37 +------------------ 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/packages/rn-tester/js/examples/Modal/ModalPresentation.js b/packages/rn-tester/js/examples/Modal/ModalPresentation.js index 78e0dec7e7f168..b2b2aab6bb67e3 100644 --- a/packages/rn-tester/js/examples/Modal/ModalPresentation.js +++ b/packages/rn-tester/js/examples/Modal/ModalPresentation.js @@ -4,22 +4,14 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow + * @flow strict-local * @format */ /* eslint-disable no-alert */ import * as React from 'react'; -import { - AccessibilityInfo, - Modal, - Platform, - StyleSheet, - Switch, - Text, - View, -} from 'react-native'; +import {Modal, Platform, StyleSheet, Switch, Text, View} from 'react-native'; import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; import RNTOption from '../../components/RNTOption'; const RNTesterButton = require('../../components/RNTesterButton'); @@ -43,23 +35,6 @@ const presentationStyles = [ const iOSActions = ['None', 'On Dismiss', 'On Show']; const noniOSActions = ['None', 'On Show']; -const TitleComponent = React.forwardRef((props, forwardedRef) => { - return ( - - My custom title - - ); -}); - function ModalPresentation() { const [animationType, setAnimationType] = React.useState('none'); const [transparent, setTransparent] = React.useState(false); @@ -72,7 +47,6 @@ function ModalPresentation() { React.useState('Portrait'); const [currentOrientation, setCurrentOrientation] = React.useState('unknown'); const [action, setAction] = React.useState('None'); - let ref = React.useRef>(null); const actions = Platform.OS === 'ios' ? iOSActions : noniOSActions; const onDismiss = () => { setVisible(false); @@ -85,13 +59,7 @@ function ModalPresentation() { if (action === 'onShow') { alert('onShow'); } - if (ref != null && ref.current != null && visible === true) { - // see https://github.com/facebook/react-native/issues/30097#issuecomment-1285927266 - const focusEvent = Platform.OS === 'ios' ? 'focus' : 'viewHoverEnter'; - AccessibilityInfo.sendAccessibilityEvent(ref.current, focusEvent); - } }; - /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's * LTI update could not be added via codemod */ const onOrientationChange = event => @@ -119,7 +87,6 @@ function ModalPresentation() { onOrientationChange={onOrientationChange} onDismiss={onDismiss} onShow={onShow}> - Date: Mon, 13 Feb 2023 11:53:58 +0100 Subject: [PATCH 24/24] remove AccInfo.flow.js --- .../AccessibilityInfo.flow.js | 208 ------------------ 1 file changed, 208 deletions(-) delete mode 100644 Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js deleted file mode 100644 index 076ee3e2b859e4..00000000000000 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ - -import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; -import type {EventSubscription} from '../../vendor/emitter/EventEmitter'; -import type {ElementRef} from 'react'; - -// Events that are only supported on Android. -type AccessibilityEventDefinitionsAndroid = { - accessibilityServiceChanged: [boolean], -}; - -// Events that are only supported on iOS. -type AccessibilityEventDefinitionsIOS = { - announcementFinished: [{announcement: string, success: boolean}], - boldTextChanged: [boolean], - grayscaleChanged: [boolean], - invertColorsChanged: [boolean], - reduceTransparencyChanged: [boolean], -}; - -type AccessibilityEventDefinitions = { - ...AccessibilityEventDefinitionsAndroid, - ...AccessibilityEventDefinitionsIOS, - change: [boolean], // screenReaderChanged - reduceMotionChanged: [boolean], - screenReaderChanged: [boolean], -}; - -type AccessibilityEventTypes = 'click' | 'focus' | 'viewHoverEnter'; -/** - * Sometimes it's useful to know whether or not the device has a screen reader - * that is currently active. The `AccessibilityInfo` API is designed for this - * purpose. You can use it to query the current state of the screen reader as - * well as to register to be notified when the state of the screen reader - * changes. - * - * See https://reactnative.dev/docs/accessibilityinfo - */ -export type AccessibilityInfoType = { - /** - * Query whether bold text is currently enabled. - * - * Returns a promise which resolves to a boolean. - * The result is `true` when bold text is enabled and `false` otherwise. - * - * See https://reactnative.dev/docs/accessibilityinfo#isBoldTextEnabled - */ - isBoldTextEnabled: () => Promise, - - /** - * Query whether grayscale is currently enabled. - * - * Returns a promise which resolves to a boolean. - * The result is `true` when grayscale is enabled and `false` otherwise. - * - * See https://reactnative.dev/docs/accessibilityinfo#isGrayscaleEnabled - */ - isGrayscaleEnabled: () => Promise, - - /** - * Query whether inverted colors are currently enabled. - * - * Returns a promise which resolves to a boolean. - * The result is `true` when invert color is enabled and `false` otherwise. - * - * See https://reactnative.dev/docs/accessibilityinfo#isInvertColorsEnabled - */ - isInvertColorsEnabled: () => Promise, - - /** - * Query whether reduced motion is currently enabled. - * - * Returns a promise which resolves to a boolean. - * The result is `true` when a reduce motion is enabled and `false` otherwise. - * - * See https://reactnative.dev/docs/accessibilityinfo#isReduceMotionEnabled - */ - isReduceMotionEnabled: () => Promise, - - /** - * Query whether reduce motion and prefer cross-fade transitions settings are currently enabled. - * - * Returns a promise which resolves to a boolean. - * The result is `true` when prefer cross-fade transitions is enabled and `false` otherwise. - * - * See https://reactnative.dev/docs/accessibilityinfo#prefersCrossFadeTransitions - */ - prefersCrossFadeTransitions: () => Promise, - - /** - * Query whether reduced transparency is currently enabled. - * - * Returns a promise which resolves to a boolean. - * The result is `true` when a reduce transparency is enabled and `false` otherwise. - * - * See https://reactnative.dev/docs/accessibilityinfo#isReduceTransparencyEnabled - */ - isReduceTransparencyEnabled: () => Promise, - - /** - * Query whether a screen reader is currently enabled. - * - * Returns a promise which resolves to a boolean. - * The result is `true` when a screen reader is enabled and `false` otherwise. - * - * See https://reactnative.dev/docs/accessibilityinfo#isScreenReaderEnabled - */ - isScreenReaderEnabled: () => Promise, - - /** - * Query whether Accessibility Service is currently enabled. - * - * Returns a promise which resolves to a boolean. - * The result is `true` when any service is enabled and `false` otherwise. - * - * @platform android - * - * See https://reactnative.dev/docs/accessibilityinfo/#isaccessibilityserviceenabled-android - */ - isAccessibilityServiceEnabled: () => Promise, - - /** - * Add an event handler. Supported events: - * - * - `reduceMotionChanged`: Fires when the state of the reduce motion toggle changes. - * The argument to the event handler is a boolean. The boolean is `true` when a reduce - * motion is enabled (or when "Transition Animation Scale" in "Developer options" is - * "Animation off") and `false` otherwise. - * - `screenReaderChanged`: Fires when the state of the screen reader changes. The argument - * to the event handler is a boolean. The boolean is `true` when a screen - * reader is enabled and `false` otherwise. - * - * These events are only supported on iOS: - * - * - `boldTextChanged`: iOS-only event. Fires when the state of the bold text toggle changes. - * The argument to the event handler is a boolean. The boolean is `true` when a bold text - * is enabled and `false` otherwise. - * - `grayscaleChanged`: iOS-only event. Fires when the state of the gray scale toggle changes. - * The argument to the event handler is a boolean. The boolean is `true` when a gray scale - * is enabled and `false` otherwise. - * - `invertColorsChanged`: iOS-only event. Fires when the state of the invert colors toggle - * changes. The argument to the event handler is a boolean. The boolean is `true` when a invert - * colors is enabled and `false` otherwise. - * - `reduceTransparencyChanged`: iOS-only event. Fires when the state of the reduce transparency - * toggle changes. The argument to the event handler is a boolean. The boolean is `true` - * when a reduce transparency is enabled and `false` otherwise. - * - `announcementFinished`: iOS-only event. Fires when the screen reader has - * finished making an announcement. The argument to the event handler is a - * dictionary with these keys: - * - `announcement`: The string announced by the screen reader. - * - `success`: A boolean indicating whether the announcement was - * successfully made. - * - * See https://reactnative.dev/docs/accessibilityinfo#addeventlistener - */ - addEventListener>( - eventName: K, - handler: (...$ElementType) => void, - ): EventSubscription, - - /** - * Set accessibility focus to a React component. - * - * See https://reactnative.dev/docs/accessibilityinfo#setaccessibilityfocus - */ - setAccessibilityFocus: (reactTag: number) => void, - - /** - * Send a named accessibility event to a HostComponent. - */ - sendAccessibilityEvent: ( - handle: ElementRef>, - eventType: AccessibilityEventTypes, - ) => void, - - /** - * Post a string to be announced by the screen reader. - * - * See https://reactnative.dev/docs/accessibilityinfo#announceforaccessibility - */ - announceForAccessibility: (announcement: string) => void, - - /** - * Post a string to be announced by the screen reader. - * - `announcement`: The string announced by the screen reader. - * - `options`: An object that configures the reading options. - * - `queue`: The announcement will be queued behind existing announcements. iOS only. - */ - announceForAccessibilityWithOptions: ( - announcement: string, - options: {queue?: boolean}, - ) => void, - - /** - * Get the recommended timeout for changes to the UI needed by this user. - * - * See https://reactnative.dev/docs/accessibilityinfo#getrecommendedtimeoutmillis - */ - getRecommendedTimeoutMillis: (originalTimeout: number) => Promise, -};